java process builder add path to environment not working - java

I have a problem with adding a path to the environment of a process using processbuider. I have no clue why the process is ignoring the environment. Here is my example:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Map;
public class main {
public static void main(String [ ] args) {
try {
String s = null;
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", "fsl");
Map<String, String> env;
env = pb.environment();
env.put("FSLDIR", "/usr/local/fsl/bin/");
Process p = pb.start();
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
System.out.println("Process p:");
// read the output from the command
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
//////////*********\\\\\\\\\\\
ProcessBuilder pb2 = new ProcessBuilder("/usr/local/fsl/bin/fsl");
s = null;
Process p2 = pb2.start();
stdInput = new BufferedReader(new
InputStreamReader(p2.getInputStream()));
stdError = new BufferedReader(new
InputStreamReader(p2.getErrorStream()));
System.out.println("Process p2:");
// read the output from the command
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Output:
Process p:
/bin/bash: fsl: command not found
Process p2:
DISPLAY is not set. Please set your DISPLAY environment variable!
And you see FSL wants some more variables to be set. That is why p2 is not an option.

As Jdamian said, Bash searches the directories in the PATH environment variable to find binaries - Bash does not look for your FSLDIR variable, nor will it treat the values of arbitrary variables as executables.
The first thing you should always do when running into issues with a process library (e.g. ProcessBuilder in Java, subprocess in Python), is try to replicate the issue directly in the shell. If you run fsl or /bin/bash -c fsl in your shell you'll likely see the same error (if you don't you're not running your Java binary the same way as your shell) which confirms the issue is not related to Java.
Once you've confirmed that it's just a question of how to fix it. If you intend for fsl to be always available add its containing directory to your PATH in your ~/.bashrc file:
export PATH="$PATH:/usr/local/fsl/bin"
If you just want it available in your Java binary, modify the PATH in-process:
// notice there's no need for `bash -c`
ProcessBuilder pb = new ProcessBuilder("fsl");
pb.environment().put("PATH",
"/usr/local/fsl/bin" + File.pathSeparator + System.getenv("PATH"));
In practice however, your code will often be much more maintainable and easier to work with if you don't modify the PATH and instead simply always invoke external processes by their absolute path, like your second example:
ProcessBuilder pb = new ProcessBuilder("/usr/local/fsl/bin/fsl");
These two commands are (roughly) equivalent, but the latter is far more clear, and less likely to introduce confusing bugs.

Related

How does java Runtime.getRuntime().exec(...) search for executables on windows?

I'm trying to do a proof of concept exploit to show how changing the path variable can replace standard programs for malicious ends. I put a dummy program called "cmd.exe" in a directory "C:\path\to\fake_exe\" and changed the path to have that at the front.
Below is the function I'm using to demonstrate, but it runs normally (i.e., it passes the arguments to the correct cmd.exe instead of my fake one). I even passed "cmd" to the function, and it opened my dummy program! So the path variable is definitely set to find my fake cmd.exe correctly, but the exec(..) function is finding the proper cmd.exe regardless.
How does the exec(...) function find executables? Where is this documented?
static void unsafeExec(String cmd) throws IOException, InterruptedException {
String[] run = new String[3];
run[0] = "cmd.exe";
run[1] = "/C";
run[2] = cmd;
Process p = Runtime.getRuntime().exec(run);
BufferedReader stdIN = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdER = new BufferedReader(new InputStreamReader(p.getErrorStream()));
p.waitFor();
String s;
while ((s = stdIN.readLine()) != null) {
System.out.println(s);
}
while ((s = stdER.readLine()) != null) {
System.out.print(s);
}
}

When I am running java program manually from terminal it is working fine but it is not working when i am running from eclipse

My program is not running from eclipse but it is running through terminal in ubuntu.
Below is the shell script that i am running in java
#!/usr/bin/env bash
# Running sqoop commands
s="$(sqoop help)"
echo "$s"
Below is the java code
package flexibility;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Flex {
public static void main(String args[]) throws Exception {
String s = null;
String line = "";
String sqoopCommand = "sqoop help";
try {
Process p = Runtime.getRuntime().exec("/home/avinash/sqoop.sh");
p.waitFor();
StringBuffer output = new StringBuffer();
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((line = stdInput.readLine()) != null) {
output.append(line + "\n");
}
while ((line = stdError.readLine()) != null) {
output.append(line + "\n");
}
System.out.println("### " + output);
} catch (Throwable t) {
t.printStackTrace();
}
}
}
error message :
/home/avinash/sqoop.sh: line 5: sqoop: command not found
Try with the command "sh /home/avinash/sqoop.sh". I feel since the ubuntu isn't aware what kind of file it is,It's clearly throwing command not found error.
The error message is from your script. Not from Eclipse.
Eclipse (or the JVM to be more precise) does not know about the environment variables or working directory of the script. In contrast: If you run the script from command line environment variables (e.g. PATH) or working directory are known.
You can use method Runtime.exec(String command, String[] envp, File dir) to specify this in your Java code. So I guess this should work:
Process p =
Runtime.getRuntime().exec("/home/avinash/sqoop.sh", null, new File("/home/avinash/"));

Execute ntpdate with java and get the output value

I want to execute this command within my java program and check if it was successfully executed.
sudo ntpdate -u someserver.com
I create a bash with the command
#!/bin/sh
sudo ntpdate -u omeserver.com
and execute it with java
ProcessBuilder pb = new ProcessBuilder("/updateTime");
Process p = pb.start();
p.waitFor();
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
System.out.println(stdInput.readLine());
But I get no output, there are no lines in stdInput, how can I check if the command was correctly executed?
If I add for example Echo updated in the end of the bash file I get it in the stdInput, but it still don't mean that the time were updated
You'd probably get by easier when just calling sudo directly with ProcessBuilder instead of an external script. That's just redundant complexity for the task at hand.
You can feed ProcessBuilder with the whole command line, for example, like this:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class q39836547 {
private static String[] cmdl = { "/usr/bin/sudo",
"ntpdate",
"-u",
"some.ntp.server" };
public static void main(String[] as) throws IOException {
ProcessBuilder pb = new ProcessBuilder(cmdl);
Process p = pb.start();
BufferedReader stdin = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stderr = new BufferedReader(new InputStreamReader(p.getErrorStream()));
try { p.waitFor(); }
catch(InterruptedException e) { }
if(p.exitValue() != 0)
System.err.println("The process was not executed successfully.");
else
System.err.println("The process ran and exited cleanly.");
stdin.lines().forEach(s -> System.out.println("STDOUT: " + s));
stderr.lines().forEach(s -> System.out.println("STDERR: " + s));
}
}
You also have to waitFor() (as you properly did) the ntpdate to finish. Otherwise you might end up reading its standard input or standard error with getInputStream() or getErrorStream() before there is any output produced into either stream.
If you comment out the try-catch-block, you'll occasionally see how the process is still running while you're trying to read its input. That is likely to happen almost every time, actually.

java run bash script, command not found

I tried to use java to run some bash script and store the terminal output in a string. However, there are a lot of commands don't work in this way. It keeps showing command not found, but I can run those commands correctly in terminal, ex node --version, go --version. I guess is the path issue, but have no idea how to fix it.
Another question, when I run "python --version", it shows "Python 2.7.10" but it is in getErrorStream. Can anyone give me some hint?
public static void runscript() throws IOException {
Runtime rt = Runtime.getRuntime();
String[] commands = { "/bin/bash", "-c", "node --version" };
Process proc = null;
try {
proc = rt.exec(commands);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
// read the output from the command
System.out.println("Here is the standard output of the command:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
}
Reply #VishalKamat comment.
when I tried using the output of "which node" as my path, which is "/usr/local/bin/node". It works!!!
But, does that mean I have to change the path when I need to get different application version info?
I thought I can easily get the info just like I do in terminal.
I try to print $PATH by java in this way
String[] commands = { "/bin/bash","-c", "$PATH" };
The error msg is :
/bin/bash: /usr/bin:/bin:/usr/sbin:/sbin: No such file or directory

How to Execute Windows Commands Using Java - Change Network Settings

In Java, I want to be able to execute a Windows command.
The command in question is netsh. This will enable me to set/reset my IP address.
Note that I do not want to execute a batch file.
Instead of using a batch file, I want to execute such commands directly. Is this possible?
Here is my implemented Solution for Future Reference:
public class JavaRunCommand {
private static final String CMD =
"netsh int ip set address name = \"Local Area Connection\" source = static addr = 192.168.222.3 mask = 255.255.255.0";
public static void main(String args[]) {
try {
// Run "netsh" Windows command
Process process = Runtime.getRuntime().exec(CMD);
// Get input streams
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
// Read command standard output
String s;
System.out.println("Standard output: ");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
// Read command errors
System.out.println("Standard error: ");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
}
Runtime.getRuntime().exec("netsh");
See Runtime Javadoc.
EDIT: A later answer by leet suggests that this process is now deprecated. However, as per the comment by DJViking, this appears not to be the case: Java 8 documentation. The method is not deprecated.
Use ProcessBuilder
ProcessBuilder pb=new ProcessBuilder(command);
pb.redirectErrorStream(true);
Process process=pb.start();
BufferedReader inStreamReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
while(inStreamReader.readLine() != null){
//do something with commandline output.
}
You can run the command with Runtime.getRuntime().exec("<command>") (eg. Runtime.getRuntime().exec("tree")). But, this will only run executables found in path, not commands like echo, del, ... But only stuff like tree.com, netstat.com, ... To run regular commands, you will have to put cmd /c before the command (eg Runtime.getRuntime().exec("cmd /c echo echo"))
public static void main(String[] args) {
String command="netstat";
try {
Process process = Runtime.getRuntime().exec(command);
System.out.println("the output stream is "+process.getOutputStream());
BufferedReader reader=new BufferedReader( new InputStreamReader(process.getInputStream()));
String s;
while ((s = reader.readLine()) != null){
System.out.println("The inout stream is " + s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
This works.
Runtime#exec().

Categories

Resources