Java's waitFor() method seems to hang - c#

I have written a simple routine in .Net that I need to call from Java and check the exit value. For some reason when called from Java, waitFor never ends. This is in spite of the fact that when called from command prompt .Net routine ends quickly and when called from test.bat it properly returns -1. Anyone has any idea what the problem is?
Here is Java code:
public static int runOnceWait(String[] cmdarray) throws IOException, InterruptedException
{
Process p;
p = Runtime.getRuntime().exec(cmdarray);
int res = p.waitFor();
p.destroy();
return res;
}
/**
* #param args
* #throws InterruptedException
* #throws IOException
*/
public static void main(String[] args) throws IOException, InterruptedException
{
String [] cmd = new String[2];
cmd[0]=signer;
cmd[1]=fileLocation;
System.out.println ("\"" + cmd[0] + "\" \"" + cmd[1] + "\"");
System.out.println (runOnceWait(cmd));
}
Here's C# code:
static int Main(string[] args)
{
if (args.Length != 1 && args.Length != 2)
{
Console.WriteLine("Use: ");
Console.WriteLine("DocumentSigner.exe source");
Console.WriteLine(" or");
Console.WriteLine("DocumentSigner.exe source, destination");
return -100;
}
string destination = null;
try
{
if (args.Length == 1) destination = Sign(args[0]);
else destination = Sign(args[0], args[1]);
Console.WriteLine("Document signed and saved as " + destination);
}
catch (Exception e)
{
Console.WriteLine(e);
return -1;
}
return 0;
}
For testing purposes I even wrote a .bat file which behaves as expected, i.e. returns ERRORLEVEL of -1.
Here's .bat file:
#echo off
rem test.bat
"DocumentSigner.exe" "{5E3C1967-A26E-4FC5-A6A8-3F358F388A3D}.pdf"
#if "%ERRORLEVEL%" == "0" goto good
:fail
echo Execution Failed
echo return value = %ERRORLEVEL%
goto end
:good
echo Execution succeeded
echo Return value = %ERRORLEVEL%
goto end
:end

From the API reference of java.lang.Process (emphasis mine):
By default, the created subprocess does not have its own terminal or
console. All its standard I/O (i.e. stdin, stdout, stderr) operations
will be redirected to the parent process, where they can be accessed
via the streams obtained using the methods getOutputStream(),
getInputStream(), and getErrorStream(). The parent process uses these
streams to feed input to and get output from the subprocess. Because
some native platforms only provide limited buffer size for standard
input and output streams, failure to promptly write the input stream
or read the output stream of the subprocess may cause the subprocess
to block, or even deadlock.
I would try to read from java what your c# application is writing with Console.WriteLine(), e.g. doing something like this after your exec()
BufferedReader in = new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}

Related

How to handle "press enter to continue" to exit a program when running it from code?

I'm trying to run an external binary from a C# code using the ProcessEx.RunAsync command. However, this binary doesn't have a quiet mode and whenever it's done operating, it prompts "press enter to continue" in order to exit the program. How do I handle this so I won't get a timeout return?
The functionality you describe is similar to what expect tool provides in *nix world.
The program automates interactions with programs that expose a text terminal interface.
There are various options available for you to use and if you are interested in using an existing C# library then the dotnetexpect might solve it for you; note it is quite old.
If you are looking for all hand-coding, here is a PoC to explain the concept. As usual: don't use as-is this is just to demonstrate the concept.
namespace ToExpectOrNotToExpect
{
class Program
{
static void RunAndManage(string command,string args)
{
Process processHandle = new Process();
processHandle.StartInfo.FileName = command;
processHandle.StartInfo.Arguments = args;
processHandle.StartInfo.UseShellExecute = false;
processHandle.StartInfo.RedirectStandardOutput = true;
processHandle.StartInfo.RedirectStandardInput = true;
processHandle.StartInfo.CreateNoWindow = false;
processHandle.Start();
string data = "";
while (!processHandle.StandardOutput.EndOfStream)
{
// Cheap and cheeky buffer: improve
char[] buffer = new char[256];
int n = processHandle.StandardOutput.Read(buffer, 0, 100);
data += new string(buffer, 0, n);
Console.WriteLine("GOT: [[ " + data + "]]");
if (data.IndexOf("Press any key") >= 0)
{
processHandle.StandardInput.Write('\r');
// Keeping it simple and exiting for the PoC: improve this in your implementation
break;
}
}
}
static void Main(string[] args)
{
RunAndManage("cmd.exe", " /c echo This was fun && echo Really && echo Really && pause && echo Wowzer Pause Bypassed 1>&2 ");
}
}
}
Output would look something like this (notice that we sent CarriageReturn once we saw the pause text being emitted):
Detailed and expansive examples are plenty on this idea on Stackoverflow and elsewhere. Here is one.

Single instance .NET Core App (or making crontab run only 1 instance of my app)

I would like to execute a .NET Core Application on a schedule in Linux using crontab. It's a long running operation and I don't want another instance to be run if a previous execution hasn't finished yet. In other words, I don't want crontab to execute more than one instance of my .NET Core App at a given time.
Is there any way to avoid it? I would prefer not to modify the code of my app. Maybe there is an option for crontab to avoid concurrency. I'm not a Linux expert (yet) :)
For those who want to check instances from code you may use named mutex like this
const string mutexName = #"Global\appName";
var mutex = new Mutex(true, mutexName, out var createdNew);
if (!createdNew)
{
Console.WriteLine(mutexName + " is already running! Exiting the application.");
return;
}
Be sure that your mutex name begins with "Global\".
I've finally used a little tool available for Raspbian: flock
In my crontab config file, I've put this:
flock -n /tmp/importer.lock dotnet ~/Desktop/Importer/Plugin.Clm.Importer.Console.dll
It seems that flock writes a lock file while it's running, and executes the command. It it's executed again, and the lock file is there, it just fails. When it finishes, it releases the file, allowing it to be called again.
In a few words: it acts as a semaphore :)
If you want to solve it in your program, you could loop through all processes in System.Diagnostics.Process.GetProcesses and check if any process executable path ends with your filename.
[System.STAThread]
static void Main(string[] args)
{
foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses())
{
if (p.MainModule.FileName.EndsWith("bla.exe", System.StringComparison.CurrentCultureIgnoreCase))
return;
}
[...]
}
Otherwise, have a script set a value in /var/run and check if that file exists. That file is to be deleted if your program exits in any way.
Also, address the long running time.
Programs should't normally take that long.
Looks to me like you're doing something wrong, unless you are indeed processing several gigabytes of data.
if MainModule returns dotnet, you could also readlink proc/pid/exe/ (Linux or BSD) or /proc/self/exe (linux only)
int pid = System.Diagnostics.Process.GetCurrentProcess().Id;
System.Text.StringBuilder sb = new System.Text.StringBuilder(System.Environment.SystemPageSize);
int ret = Mono.Unix.Native.Syscall.readlink($"/proc/{pid}/exe", sb);
string res = sb.ToString();
System.Console.WriteLine(res);
Alternatively, if that only yields dotnet too, you can read the command line arguments (/proc/pid/cmdline - linux only):
public static byte[] ReadReallyAllBytes(string filename)
{
byte[] retValue = null;
using (System.IO.FileStream fs = System.IO.File.OpenRead(filename))
{
byte[] buffer = new byte[System.Environment.SystemPageSize];
List<byte> byteList = new List<byte>();
int ct = 0;
while ((ct = fs.Read(buffer, 0, buffer.Length)) > 0)
{
for (int i = 0; i < ct; ++i)
{
byteList.Add(buffer[i]);
}
}
buffer = null;
retValue = byteList.ToArray();
byteList.Clear();
byteList = null;
}
return retValue;
}
public static List<string> GetCmdLineArgs(int pid)
{
List<string> ls = new List<string>();
byte[] buffer = ReadReallyAllBytes($"/proc/{pid}/cmdline");
int last = 0;
for (int i = 0; i < buffer.Length; ++i)
{
if (buffer[i] == 0)
{
string arg = System.Text.Encoding.UTF8.GetString(buffer, last, i-last);
last = i + 1;
ls.Add(arg);
} // End if (buffer[i] == 0)
} // Next i
// System.Console.WriteLine(ls);
return ls;
}
Now if MainModule is dotnet, check if the command line arguments list contains your dll/exe.
Also, if you do a release-build (standalone - no shared-framework), then it should work with MainModule.
Maybe put the duplicate check in the script, not in the program.
So check the output of 'ps -ef | grep myprogramname' before executing your program.

How to interact with data piped to console application similar to the LESS program [duplicate]

I know how to program Console application with parameters, example : myProgram.exe param1 param2.
My question is, how can I make my program works with |, example : echo "word" | myProgram.exe?
You need to use Console.Read() and Console.ReadLine() as if you were reading user input. Pipes replace user input transparently. You can't use both easily (although I'm sure it's quite possible...).
Edit:
A simple cat style program:
class Program
{
static void Main(string[] args)
{
string s;
while ((s = Console.ReadLine()) != null)
{
Console.WriteLine(s);
}
}
}
And when run, as expected, the output:
C:\...\ConsoleApplication1\bin\Debug>echo "Foo bar baz" | ConsoleApplication1.exe
"Foo bar baz"
C:\...\ConsoleApplication1\bin\Debug>
The following will not suspend the application for input and works when data is or is not piped. A bit of a hack; and due to the error catching, performance could lack when numerous piped calls are made but... easy.
public static void Main(String[] args)
{
String pipedText = "";
bool isKeyAvailable;
try
{
isKeyAvailable = System.Console.KeyAvailable;
}
catch (InvalidOperationException expected)
{
pipedText = System.Console.In.ReadToEnd();
}
//do something with pipedText or the args
}
in .NET 4.5 it's
if (Console.IsInputRedirected)
{
using(stream s = Console.OpenStandardInput())
{
...
This is the way to do it:
static void Main(string[] args)
{
Console.SetIn(new StreamReader(Console.OpenStandardInput(8192))); // This will allow input >256 chars
while (Console.In.Peek() != -1)
{
string input = Console.In.ReadLine();
Console.WriteLine("Data read was " + input);
}
}
This allows two usage methods. Read from standard input:
C:\test>myProgram.exe
hello
Data read was hello
or read from piped input:
C:\test>echo hello | myProgram.exe
Data read was hello
Here is another alternate solution that was put together from the other solutions plus a peek().
Without the Peek() I was experiencing that the app would not return without ctrl-c at the end when doing "type t.txt | prog.exe" where t.txt is a multi-line file. But just "prog.exe" or "echo hi | prog.exe" worked fine.
this code is meant to only process piped input.
static int Main(string[] args)
{
// if nothing is being piped in, then exit
if (!IsPipedInput())
return 0;
while (Console.In.Peek() != -1)
{
string input = Console.In.ReadLine();
Console.WriteLine(input);
}
return 0;
}
private static bool IsPipedInput()
{
try
{
bool isKey = Console.KeyAvailable;
return false;
}
catch
{
return true;
}
}
This will also work for
c:\MyApp.exe < input.txt
I had to use a StringBuilder to manipulate the inputs captured from Stdin:
public static void Main()
{
List<string> salesLines = new List<string>();
Console.InputEncoding = Encoding.UTF8;
using (StreamReader reader = new StreamReader(Console.OpenStandardInput(), Console.InputEncoding))
{
string stdin;
do
{
StringBuilder stdinBuilder = new StringBuilder();
stdin = reader.ReadLine();
stdinBuilder.Append(stdin);
var lineIn = stdin;
if (stdinBuilder.ToString().Trim() != "")
{
salesLines.Add(stdinBuilder.ToString().Trim());
}
} while (stdin != null);
}
}
Console.In is a reference to a TextReader wrapped around the standard input stream. When piping large amounts of data to your program, it might be easier to work with that way.
there is a problem with supplied example.
while ((s = Console.ReadLine()) != null)
will stuck waiting for input if program was launched without piped data. so user has to manually press any key to exit program.

running multiple threads with continous value returns (ping program)

good day
I have taken up a project that as a bases needs insernt a command into cmd "ping x.x.x.x -t" and the program needs to return the output until a specified parameter
I am considering threads as my unterstanding in multithreading is limited, I am unable to continue without guidance
my ping class which recieves a string ip, adds it to a precompiled command string, etc.
I am aware of the built in ping class for this use, but I would prefer the "longer" method since i would gain valueble information/experience from this
main object class: ping
class ping
{
Process proc;
ProcessStartInfo psi;
string ip_address;
bool bStop = false;
public ping(string ip)
{
ip_address = ip;
}
public void StartPing()
{
string cmdInput;
psi = new ProcessStartInfo(Environment.GetEnvironmentVariable("COMSPEC"));
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.UseShellExecute = false;
proc = Process.Start(psi);
proc.StandardInput.WriteLine("ping " + ip_address + " -t");
cmdInput = proc.StandardOutput.ReadLine();
cmdInput = proc.StandardOutput.ReadLine();
cmdInput = proc.StandardOutput.ReadLine();
cmdInput = proc.StandardOutput.ReadLine();
cmdInput = proc.StandardOutput.ReadLine();
cmdInput = proc.StandardOutput.ReadLine();
while (bStop == false)
{
cmdInput = proc.StandardOutput.ReadLine();
Console.WriteLine(returnPing(cmdInput));
}
proc.Close();
}
private string returnPing(string cmdInput)
{
int start, end;
string ping;
if (cmdInput.IndexOf("Reply") != -1 && cmdInput.IndexOf("time") != -1)
{
start = cmdInput.IndexOf("time=") + 5;
end = cmdInput.IndexOf("ms");
ping = cmdInput.Substring(start, end - start);
return ping;
}
else return "-1";
}
and thread_handler class, which manages mutliple instances of the ping method, please not the console.writeline is a temporary output which I will change in the future
class thread_handler
{
string[] ipList;
private IList<Thread> threadList;
public thread_handler(string[] ip)
{
ipList = ip;
threadList = new List<Thread>();
createThreads();
}
private void createThreads()
{
foreach (string item in ipList)
{
ping NewPing = new ping(item);
Thread newPingThread = new Thread(NewPing.StartPing);
newPingThread.IsBackground = true;
newPingThread.Name = string.Format("{0}", item);
threadList.Add(newPingThread);
}
startAllThreads();
}
private void startAllThreads()
{
foreach (Thread item in threadList)
{
item.Start();
}
}
}
Program
class Program
{
static string[] ipList;
static void Main(string[] args)
{
ipList = new String[3];
readData();
sendData();
}
private static void sendData()
{
thread_handler thIp = new thread_handler(ipList);
}
private static void readData()
{
//use sll with name defintions and ip address's with metadata
ipList[0] = "10.0.0.2";
ipList[1] = "telkom_exchange";
ipList[2] = "goo.gl";
}
The aim of this program is (with gui changes in future) for a simple console with respective dimensions to constantly ping certain ip address's (we have ban infrastructure, thus program is for informative purposes), constantly updating on every ping reply
I do not want anyone to finish this program, I simply require assistance with running multiple instances (or maybe "threads") of this pinging, thus
each thread as it runs the "StartPing()" method, it should return an output, e.g. simply output the ping into the console, but it doesnt...
Output:
The process tried to write to a nonexistent pipe.
The process tried to write to a nonexistent pipe.
then hangs
The way you read from the child process is not right. This is a surprisingly complicated task. I don't know why you are getting this specific error message but it sounds like it has to do with process standard output redirection. For example you have not redirected standard error.
I suggest you use one of the top voted snippets of stack overflow, to be found by: site:stackoverflow.com process RedirectStandardOutput. There are hundreds of such questions. Most solutions are subtly wrong.
This is a good checklist.
You should use the ping class to execute a ping. This class allows you to control many details.
The call to ping.exe with Process.Start() involves way too much overhead and complicates things (as you experienced in your try)
As simple as it is, redirecting standard input and output did it, with a tweak or two, voila

C# Console receive input with pipe

I know how to program Console application with parameters, example : myProgram.exe param1 param2.
My question is, how can I make my program works with |, example : echo "word" | myProgram.exe?
You need to use Console.Read() and Console.ReadLine() as if you were reading user input. Pipes replace user input transparently. You can't use both easily (although I'm sure it's quite possible...).
Edit:
A simple cat style program:
class Program
{
static void Main(string[] args)
{
string s;
while ((s = Console.ReadLine()) != null)
{
Console.WriteLine(s);
}
}
}
And when run, as expected, the output:
C:\...\ConsoleApplication1\bin\Debug>echo "Foo bar baz" | ConsoleApplication1.exe
"Foo bar baz"
C:\...\ConsoleApplication1\bin\Debug>
The following will not suspend the application for input and works when data is or is not piped. A bit of a hack; and due to the error catching, performance could lack when numerous piped calls are made but... easy.
public static void Main(String[] args)
{
String pipedText = "";
bool isKeyAvailable;
try
{
isKeyAvailable = System.Console.KeyAvailable;
}
catch (InvalidOperationException expected)
{
pipedText = System.Console.In.ReadToEnd();
}
//do something with pipedText or the args
}
in .NET 4.5 it's
if (Console.IsInputRedirected)
{
using(stream s = Console.OpenStandardInput())
{
...
This is the way to do it:
static void Main(string[] args)
{
Console.SetIn(new StreamReader(Console.OpenStandardInput(8192))); // This will allow input >256 chars
while (Console.In.Peek() != -1)
{
string input = Console.In.ReadLine();
Console.WriteLine("Data read was " + input);
}
}
This allows two usage methods. Read from standard input:
C:\test>myProgram.exe
hello
Data read was hello
or read from piped input:
C:\test>echo hello | myProgram.exe
Data read was hello
Here is another alternate solution that was put together from the other solutions plus a peek().
Without the Peek() I was experiencing that the app would not return without ctrl-c at the end when doing "type t.txt | prog.exe" where t.txt is a multi-line file. But just "prog.exe" or "echo hi | prog.exe" worked fine.
this code is meant to only process piped input.
static int Main(string[] args)
{
// if nothing is being piped in, then exit
if (!IsPipedInput())
return 0;
while (Console.In.Peek() != -1)
{
string input = Console.In.ReadLine();
Console.WriteLine(input);
}
return 0;
}
private static bool IsPipedInput()
{
try
{
bool isKey = Console.KeyAvailable;
return false;
}
catch
{
return true;
}
}
This will also work for
c:\MyApp.exe < input.txt
I had to use a StringBuilder to manipulate the inputs captured from Stdin:
public static void Main()
{
List<string> salesLines = new List<string>();
Console.InputEncoding = Encoding.UTF8;
using (StreamReader reader = new StreamReader(Console.OpenStandardInput(), Console.InputEncoding))
{
string stdin;
do
{
StringBuilder stdinBuilder = new StringBuilder();
stdin = reader.ReadLine();
stdinBuilder.Append(stdin);
var lineIn = stdin;
if (stdinBuilder.ToString().Trim() != "")
{
salesLines.Add(stdinBuilder.ToString().Trim());
}
} while (stdin != null);
}
}
Console.In is a reference to a TextReader wrapped around the standard input stream. When piping large amounts of data to your program, it might be easier to work with that way.
there is a problem with supplied example.
while ((s = Console.ReadLine()) != null)
will stuck waiting for input if program was launched without piped data. so user has to manually press any key to exit program.

Categories