Java Process immediately exits - java

I am creating a Process as follows:
Process p = Runtime.getRuntime().exec("nohup /usr/bin/python " + filePath + " &");
Process q = Runtime.getRuntime().exec("/usr/bin/python -m -webbrowser " + url);
I am trying to run the p in the background so that q can run without a problem. Also, when the Java program ends, the python script is no longer running.

The command you ran is nohup, and it did exit immediately. nohup started a separate Python process, but that's not the process p is controlling.
Why are you using nohup and & if that isn't the functionality you want? If you simply want to execute a Python subprocess just call:
Process p = Runtime.getRuntime().exec("/usr/bin/python " + filePath);
Note that it's also safer to use the overload of exec that takes an array, so you don't have to do string-concatenation yourself (and therefore avoid a type of security exploit). The syntax changes slightly to:
Process p = Runtime.getRuntime().exec(new String[]{"/usr/bin/python", filePath});
Or with ProcessBuilder:
Process p = new ProcessBuilder("/usr/bin/python", filePath).start();

Take a look at the documentation for the & operator here. Your process is running in the background. As far as the Java program you're writing (and the shell, for that matter) are concerned, the call you made has already ended. It's most certainly still running in the background, but you're telling the shell (and by extension your Java program) to not pay attention to the output and move on.

As Sean Bright mentioned take the '&' character out of the end of the script that you are running. Basically on all *nix systems. If you call make a type a command and use the ampersand, it will run that process in the background. That's why the call to java process is returning finished.
It would probably be better to not execute the command in the background (no '&') and just call Process.isAlive() periodically to determine if the process is finished.

Related

Executing shell commands

I'm having some trouble getting my app to execute that command, it asks for root access but does not run the kill $(pidof cameraserver) part.
If I run kill $(pidof cameraserver) from the terminal on my phone it works, but not when I hit the button on my app.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button action = findViewById(R.id.buttonAction);
action.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
Process process;
Process secondProcess;
process = Runtime.getRuntime().exec("su kill $pidof(cameraserver)");
BufferedReader in = new BufferedReader
(new InputStreamReader(process.getInputStream()));
}
catch (IOException e){
e.printStackTrace();
}
}
});
}
I doubt that $(pidof cameraserver) will be expanded by the exec() method. This is a shell feature. It works in the terminal, because that's a shell. You would have to exec pidof cameraserver first and use the result of that for a second call to exec.
I also believe, that you can not use the single argument overload of exec this way. You would rather have to provide a string array that contains the command and its parameter as separate array items.
You're confused. Your post title is Executing shell commands, and yet what you're doing is.. not that.
Runtime.exec does not run shell commands.
It runs executables, with its own extremely crappy shell-like behaviour you should not rely on.
Just su, in bash, will apply aliases, check if it's a bash built-in, and if none of those apply, scans the PATH. Runtime.exec does almost none of those things (it kinda scans PATH, but don't rely on that). bash will expand ${pid}, *, and many other things. Runtime.exec doesn't do any of these things.
For starters, take Runtime.getRuntime().exec and put it on your verboten list. You should never ever call this method. Let it join Thread.stop and all those silent char-to-byte conversion methods that don't include a charset.
The right way to do process control is to use ProcessBuilder. This makes a lot more clear what is happening:
Java will run the exact application you provide (so, don't do su, do /bin/su), and pass arguments verbatim with absolutely no parsing whatsoever. With the exec method you use, java will try to apply quote separation and otherwise treats spaces as separators, and does nothing more. This confusing mix of some bashisms (such as splitting your string on spaces and then treating each part as an argument) and lack of bashisms (not applying *.txt, or ${var} and friends, or supporting any of the built-ins) is just going to lead to a lot of confusion.
You have two general options:
Realize java just tells the OS to fire app A with argslist B with no processing whatsoever, and 'bash' is not built into the OS. There is simply no way to do any of these things directly, you have to program them. Whatever pidof does, you'd have to program it in java.
Start bash, not su. Then tell bash to run this command.
option 2 is possibly easier here:
ProcessBuilder pb = new ProcessBuilder();
pb.command("/bin/bash", "-c", "su kill $pidof(cameraserver)");
Process p = pb.start();
Then you're stuck trying to deal with the fact you're calling su, which goes out of its way to stop you from doing this. Having a script just casually pick up root rights is something that is just going to lead to a ton of security issues.
Find another way. For example, make a shell script that runs this command, then use some linux knowhow to give this shell SUID rights (so that it automatically and silently is run with the rights of the owner), then make it owned by root, and then use processbuilder to exec "/bin/bash", "-c", "/path/to/that/script". This has a chance of being safe: That shell can only be written to by root (make sure of that!), and thus you have now decided, as operator of the hardware you run this on, that this specific job is acceptable even for non-root users to run.
NB: If you've configured your su to just let this happen without asking for passwords, go back. Undo that mistake. Keep your system safe. root access is hidden behind a few doors for a reason. Stop replacing the locks on your safe with paper and sticks.
I finally fixed the issue, I have my phone rooted with Magisk so all i had to do was use their 'su' file, I'm new to Java and android development so i don't really know how to explain myself in proper terms but here's the code:
ProcessBuilder pb = new ProcessBuilder();
pb.command("/sbin/su", "-c","pkill cameraserver");
Process p = pb.start();
This limits the user to use Magisk, but since this is for personal use it wont matter much.
Thanks to EricSchaefer and rzwitserloot for their knowledge and help.

Executing Unix Script through plink from JAVA Runtime

I am using below code to trigger script of Unix through Java.I am not able to figure out why this command is not working.
String cmd="E:\\plink.exe -ssh -l user -pw p123 10.xxx.xx.xx \"sh /home/try.sh\"";
System.out.println(cmd);
Process process=Runtime.getRuntime().exec(cmd) ;
process.destroy();
Do i need to make some correction in it?
Runtime.exec only starts the specified program/process. You immediately destroy it before it has time to connect and send the commmand, as you want it to. At a minimum you should .waitFor() it to complete.
You don't say if the script produces (any) output. If it does and you want anything to happen with that output, like being displayed or saved someplace, you need to read from Process.getInputStream() and do your thing. Also if your script needs input (less common) you need to write it to .getOutputStream().

how to increase the performance of cmd command in window

I am using java to call arp -s command and waiting for the process to finish in order to complete function .
String command ="arp -s "+entryIpAddress+" ee-ee-ee-ee-ee-ee-ee";
Process p=Runtime.getRuntime().exec(command);
p.waitFor();
but the calling of this process is taking more than the usual time so, is there a way to increase the performance of this method. i cannot remove the p.waitFor() my next function depend on the added entry.
Your code doesn't show any sign of effort towards allowing the process to complete ever. You are not consuming its output, so its output buffer will soon fill up, blocking further progress.
To make this task easier on yourself, please use the ProcessBuilder.

In Java What is the exit value of a process which is killed in the background through Linux shell using process id

Using Java, I am executing a process in linux environment like below
Process startPingProcess = Runtime.getRuntime()().exec(ping -c 50 74.125.228.71);
we check whether process has completed its execution using startPingProcess.exitValue() in java, it will return 0 if completed normally.
Suppose if I'm killing the above started process in the middle by executing below code
Runtime.getRuntime()().exec(kill -2 processid); - where processid is process id of above started process
What is exitValue of startPingProcess object?
Your help is much appreciated! Thanks
This is not a Java specific question. The return code will be the same for all Unix systems here (at least I have never seen a Unix system not behaving this way): 128 + the number of the signal which caused the process to terminate. No idea for Windows...
Therefore, 130 in your case. In C, you'd check (after a call to waitpid() for instance) whether a process has been terminated by a signal using WIFSIGNALED(status).

Java process.waitFor() does not return

On Windows 7 64 bit, running 64 bit Java 1.7.0_17 , the p.waitFor() shown below never returns.
String move_command="cmd.exe /c xcopy /Y /E "+x86_release+" "+path+"\\";
Process p;
p = Runtime.getRuntime().exec(move_command);
p.waitFor();
If I use Windows Explorer, it looks like all the files are copied (same number, same size, etc.)
If I do the below, it waitFor() does return:
String move_command="cmd.exe /c move /Y "+x86_release+" "+path+"\\";
Process p;
p = Runtime.getRuntime().exec(move_command);
p.waitFor();
What could be so different between an xcopy and a move that keeps waitFor() from returning, or am I on the wrong track entirely?
xcopy probably just happens to produce more output than move, filling up the out-buffer and blocking until it is flushed. The default behavior in Java is to pipe the subprocess's stdout/stderr into InputStreams that you are then required to read programmatically lest the subprocess's buffers overflow.
If the latter is the case, the solution is simple, and in fact you should do that anyway: use ProcessBuilder to prepare the system call and call inheritIO on it. This will reuse your parent process`s stdin and stdout for the subprocess.
A side note, xcopy is a regular .exe file and doesn't need wrapping into cmd.exe /c.
I suspect you're not consuming the process standard out/err, and that's blocking the process. If your code doesn't consume this output, then the spawned process will hang (and you'll hang waiting for that process!). Why the difference in behaviour between the two commands ? Probably due to the quantity of data returned and the impact on the publishing buffers.
See this answer for more details.
I would also investigate Apache Commons FileUtils.copyDirectory() such that you don't have to spawn a whole new process to copy files.

Categories