Java processbuilder and using environment variables - java

What I want to do is I want to run a process, however because this process itself relies on environment variables, directly calling it causes error within the process. For those who are wondering what this is, it's rake tool. For this reason I thought maybe it's better to use bash and using it through bash would eliminate the issue. However that doesn't seem to be the case.
Here is my code:
public static void runPB(String directory) throws IOException {
ProcessBuilder processBuilder = new ProcessBuilder(
"/bin/bash");
processBuilder.directory(new File(directory));
Process process = processBuilder.start();
OutputStreamWriter osw = new OutputStreamWriter(process.getOutputStream());
osw.write("rake routes");
osw.close();
printStream(process.getErrorStream());
printStream(process.getInputStream());
}
public static void printStream(InputStream is) throws IOException {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
I know it is environment related issue because the error that I am getting is described here cannot load such file -- bundler/setup (LoadError)
Further I checked processBuilder.environment() returns less environment variables than entering env. I went ahead and changed the osw.write() line and tried echo $GEM_HOME there, which doesn't print anything and if I do this on my OSs bash then I get the path, I also tried other common things like echo $SHELL and it prints the shell location in both Java code and in bash.
So my questions are:
1) Why is my operating system's environment variables are different than the ProcessBuilder.environment() method?
2) Does Process class consider using environment variables that were given out by ProcessBuilder.environment()? If so then how can we add the missing ones from the operating system's level?

1) The varaibles you see in your java process are those inheritd from the process you started the java process from. I.e. If you launch it from a shell it should have the same variables as the shell had. You need to investigate which variables are actually set before launching your Java application and why the ones you expect are not set in that context.
To answer part 2, yes, the process will be launched with the environment in ProcessBuilder.environment(). You can simply add things to the map returned by ProcessBuilder.environment(), that will extend the runtime environment:
ProcessBuilder pb = new ProcessBuilder("foo");
pb.environment().put("MY_VAR", "foobar");

Related

Command executed from terminal, failed from Java using ProcessBuilder

I'm trying to execute a command in my terminal. The problem is, when I execute the command in terminal, it succeed, but when I run the command from java, the command is executed but, I got an error message showing me that some python module is missing.
try{
String[] list = { "python3", "script.py" };
ProcessBuilder pb = new ProcessBuilder(list);
pb.directory(
new File("/home/script"));
System.out.println("" + pb.directory());
Process process = pb.start();
InputStream str = process.getErrorStream();
InputStreamReader isr = new InputStreamReader(str);
BufferedReader br = new BufferedReader(isr);
String line;
System.out.printf("Output of running %s is:", Arrays.toString(args));
while ((line = br.readLine()) != null) {
System.out.println(line);}
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String ret = in.readLine();
System.out.println("value is : "+ret);
process.waitFor();
process.destroy();
}catch (Exception ex) {
ex.printStackTrace();
}
The error message:
/home/script
Output of running [] is:Traceback (most recent call last):
File "scraper.py", line 8, in <module>
from selenium import webdriver
ModuleNotFoundError: No module named 'selenium'
value is : null
PS: When I execute the command directly from terminal, everything works good, I don't get the missing module error.
Similar to Java, python allows to import other stuff. That message tells you that your python script wants to use the module selenium, but can't find it.
Most likely you have some special ENV var setup when running commands manually in a shell/console. So check your .bashrc or .initrc or whatever defines your ENV variables. On a unix system, typing the command env might show you all settings, too. Simply check if the env var PYTHONPATH is setup.
As that call works from the command line, then for sure, the module is installed on your system. Your only problem is that python can't find it when you invoke that script through the Java ProcessBuilder!
One solution might be that you "manually" adjust the PYTHONPATH from within your script. Thus: figure the correct setup for PYTHONPATH, then update your script to "do the right thing".
For further details, see the python documentation!

Call from Java to run an executable as a different user

Question:
I have to call an exe file passing 2 string arguments. The call has to get executed as a different user
I referred few of the links that I got from hints. Couple of them were using powershell, few were using runas examples and so on.
But with powershell also, I am not sure if I will face the issue of "cannot be loaded because running scripts is disabled on this system".
Just because of this reason, I want to try something authentic.
Tried following approaches
Trying to do it through a call with RunAs command is making my life difficult. (called a batch file with RunAs command passing a separate pass.txt or savecred). savecred was ruled out by most people. Other one did not work as expected.
Powershell, has issues wherein, I always get a userid/password popup, even though I run through a Java file.
I also get an error in the command prompt as here below
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodExcept
ion
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.Power
Shell.Commands.NewObjectCommand
(Sample code attached below)
public class SamplePS {
public static void main(String[] args) throws IOException {
Runtime runtime = Runtime.getRuntime();
String command = "powershell C:\\Users\\Ramu\\Project\\SampleFile.ps1";
//String cmds[] = {"C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe", "\\c", "SampleFile.ps"};
System.out.println("1");
Process proc = runtime.exec(command);
InputStream is = proc.getErrorStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(isr);
String line;
while ((line = reader.readLine()) != null)
{
System.out.println(line);
}
System.out.println("2");
}
}
My ps1 file is as here below
$credential = New-Object System.Management.Automation.PSCredential <<domain>>\<<user id>>, <<password>>
start-process cmd.exe -arg "/k dir" -Credential $credential
What is the best way to handle this scenario?
Please suggest! I am not sure what approach to take.
Powershell or Perl or any other scripting.
Whatever it be, I have to make a call from Java file.
Please suggest!
Note: For time being, I dont mind the password being sent as a plain text.
The exe file is in Windows machine
Thanks!
Ram

How to set environment variable in java [duplicate]

This question already has answers here:
How do I set environment variables from Java?
(23 answers)
Closed 8 years ago.
I want to set environment variable in JAVA . For this , I have searched a lot in internet and got the following code .
void set_up_environment_var() throws IOException
{
ProcessBuilder pb = new ProcessBuilder("CMD.exe", "/C", "SET"); // SET prints out the environment variables
pb.redirectErrorStream(true);
Map<String,String> env = pb.environment();
String str1 = ";C:\\naved\\bin";
String path = env.get("Path") ;//+ ";C:\\naved\\bin";
System.out.println("ok , I am coming . "+path.toLowerCase().contains(str1.toLowerCase()));
env.put("Path", path.concat(str1));
Process process = pb.start();
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = in.readLine()) != null)
{
// System.out.println(line);
}
}
But after execution , the envorinment variable is not set in "PATH" varaible . Why ?
A process can only set environment variables of itself and for processes it will spawn in future. A process cannot set the environment variables of already running processes.
You might have already noticed that when you were setting environment variables manually, globally in the system. They will not affect instances of processes which are already running, like an already running cmd.exe or an already running bash. You might also have noticed, that if you set an environment variable that way, that whether or not a new process gets the new environment variable setting depends on how the new process is started. The default behavior is that a process is started with a copy of the environment of its parent process, which is the process that starts the new process.
As a simple explanation, you could say there are root processes and child processes. root processes get the environment settings from the global settings, child processes inherit the environment settings from their parent processes.
The question is what do you want to achieve with setting the environment? I could think of at least three different things that you could want to achieve:
Set the environment globally, as part of an installer.
Set the environment for the currently running JVM.
Set the environment for a process that you will be starting.
Set the environment for the calling process directly (not possible!).
Set the environment for the calling process indirectly.
Setting the environment globally, as part of an installer
This is highly system-specific.
On UNIX, this topic is actually avoided.
Programs would rather provide wrapper scripts that set the environment instead of setting global environment variables.
The philosophy in UNIX is that usually environment variables are only used in cases where the variable would be useful for more than just one process.
Examples for such varaibles are PATH and EDITOR.
On Windows, you would probably call regedit to modify the environment.
Setting the environment of the currently running JVM
There is no API for setting the environment of the currently running JVM, so you would have to use JNI for this. However, be advised, that the fact that there is no API for this is for good reasons, and part of these reasons might be that the JVM doesn't want its environment be arbitrarily changed by some Java code.
Setting the environment for a process that will be started
When you start a process using one of the Runtime.exec() methods, you can actually provide the environment that you like.
If you want to start a process with a modified environment, the best way would be to use ProcessBuilder. It provides a method environment() for modifying the environment for the new process.
Setting the environment for the calling process directly
If you want to implement the set command in Java, forget it, it is not possible. set is not a program, it's an internal command of the shell, i.e. cmd.exe. Because of the explanation above, it wouldn't work otherwise.
Setting the environment for the calling process indirectly
You can set the environment for the calling process indirectly - if the calling process cooperates. If your calling process is cmd.exe or sh, you could have your Java program generate a temporary batch file or shell script, and then have the calling cmd.exe or sh execute that batch file or shell script.
Simple example for how to set path with setx.exe in command line:
setx path "jdk bin path"
ex
setx path "C:\Program Files (x86)\Java\jdk1.7.0_04\bin"
try this on your code
like
try {
// using the Runtime exec method:
Process p = Runtime.getRuntime().exec("setx path C:\Program Files (x86)\Java\jdk1.7.0_04\bin");
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
// read the output from the command
System.out.println("Here is the standard output of the command:\n");
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);
}
System.exit(0);
}
catch (IOException e) {
System.out.println("exception happened - here's what I know: ");
e.printStackTrace();
System.exit(-1);
}

How do I execute an executable file from within a java file on linux?

I am trying to execute an executable file and a perl script from within a java program. I have found many topics similar to this but most of them refer to windows. I know java is platform independent and it should work anyways but it doesn't. The solution I have tried already is the one based on the java Runtime and it's exec method. It works just fine on windows but since I'm porting my program on linux I need to adapt it. As I said I need to execute an executable file that I have compiled and was written in c++ which it looks like it's working but it finishes executing with an exit value of 1. I have no idea what it means but on windows it exits with 0 and that's how it should be on linux as well (?!?!). The pearl script on the other hand does not start at all. I use the command "perl script.pl" and it exits with a value of 255. Needless to say, it doesn't do what it's supposed to.
Does anybody know another way to execute these files? Or maybe where I am wrong with my implementation?
here's the code if you want to take a look at it:
This is the one for the perl script
public static void main(String[] args){
System.out.println("Starting");
try{
String[] cmd = {"perl", "cloc-1.53.pl"};
Process pr = Runtime.getRuntime().exec(cmd);
BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String line=null;
while((line=input.readLine()) != null) {
System.out.println(line);
}
int exitVal = pr.waitFor();
System.out.println("Exit code: " + exitVal);
} catch (Throwable t){
t.printStackTrace();
}
}
For the compiled file I change this:
String[] cmd = {"perl", "cloc-1.53.pl"};
with:
String cmd = "./UCC";
There should be no differece in starting processes on windows and linux.
Good article http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html
Its for the old way but gives good insight.
Article converting to the new way:
From Runtime.exec() to ProcessBuilder

running sipp from java

I am programming a Java interface for the sipp command line program. My current code is:
ProcessBuilder builder = new ProcessBuilder("sipp", "-sn uac",
"127.0.0.1");
Map<String, String> environment = builder.environment();
Process javap = builder.start();
InputStreamReader tempReader = new InputStreamReader(new BufferedInputStream(javap.getInputStream()));
BufferedReader reader = new BufferedReader(tempReader);
while (true){
String line = reader.readLine();
if (line == null)
break;
System.out.println(line);
}
This does not work for me thought, I have sipp environment variable set so this is not the problem. The standard output is sipp's help message. What am I doing wrong? Also I would like to know once I got sipp running is it possible to pass arguments to the processBuilder object associated with it so I can change the call rate? i.e. sipp let users change call rate by pressing + , - , * is this possible?
Try breaking up the -sn and uac parameters:
ProcessBuilder builder = new ProcessBuilder("sipp", "-sn", "uac", "127.0.0.1");
Also I would like to know once I got
sipp running is it possible to pass
arguments to the processBuilder object
associated with it so I can change the
call rate?
If sipp is expecting input from standard in, you should be able to grab an output stream (javap.getOutputStream()) to the process and write commands to it. I don't know anything about sipp to tell you whether that's how it works, though.

Categories

Resources