Unix Script not working in Java Process Runtime.exec() - java

I am developing an application in Spring Web MVC where i need to execute some of the linux script..
I am using tomcat version 5.5 for running my project in linux..
My code is looking like this :
Process proc = runtime.exec("sudo cp /var/tmp/mailserverfiles/editinterface.txt /etc/sysconfig/network-scripts/editinterface.txt");
InputStream inputstream = proc.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
String line;
while ((line = bufferedreader.readLine()) != null) {
System.out.println("\nOUTPUT = " + line);
}
System.out.print("\nbefore execute6");
try {
if (proc.waitFor() != 0) {
System.err.println("\nexit value = " + proc.exitValue());
}
} catch (InterruptedException e) {
System.err.println("\nERROR = " + e);
}
Here i want to cp a particular file from one location to another using linux script..
But when i am executing this part, i am getting
exit value = 1
as a output.. I have also tried to put this script into .sh file and try to execute that shell script here from Java Code, but i am getting same result..
Can anybody tell me, what should be the reason for this ?
Thanks in advance..

I would guess that sudo is expecting an interactive terminal in order to ask for a password. Since there is no interactive terminal, it prints an error message to stderr and exits with an exit code of 1. You are not reading the error stream, so you won't see any message that it might print.
You will definitely want to read the error stream in any case. Doing so now will help you diagnose what is going wrong at this point.

I assume the user that Tomcat is running under has unrestricted access to sudo? And that it's not being prompted for a password?

It is possible that your search path is weird and that "cp" and "sudo" are not found when you try to execute the command.
Here are some things you could try to track down your problem(s):
Try running the "cp" command without "sudo".
Try giving the full pathname of the command(s). This will avoid search path problems.
By default "sudo" logs failed commands using syslog(3). See if you can find traces in the corresponding logfiles.

Assuming you can run your command from a command line, logged in as the tomcat user - try
ProcessBuilder pb = new ProcessBuilder("/usr/bin/sudo", "cp",
"/var/tmp/mailserverfiles/editinterface.txt",
"/etc/sysconfig/network-scripts/editinterface.txt");
pb.redirectErrorStream(true);
Process proc = pb.start();
... rest of code as before
if things still fail, start debugging. strace should be helpful. e.g. run this shell script
from your java application, and figure out where things fail in the /tmp/trace.txt file:
#!/bin/sh
strace -f sudo cp /var/tmp/mailserverfiles/editinterface.txt /etc/sysconfig/network-scripts/editinterface.txt >/tmp/trace.txt 2>&1

Whilst not directly answering your question, the following will help. You need to read stdout and stderr (to capture all process output), and do this concurrently to prevent blocking of the spawned process. See this answer for more info.

Related

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

JavaFX + ProcessBuilder / Runtime.exec() starts process after JVM closes [duplicate]

I've been trying to use Java's ProcessBuilder to launch an application in Linux that should run "long-term". The way this program runs is to launch a command (in this case, I am launching a media playback application), allow it to run, and check to ensure that it hasn't crashed. For instance, check to see if the PID is still active, and then relaunch the process, if it has died.
The problem I'm getting right now is that the PID remains alive in the system, but the GUI for the application hangs. I tried shifting the ProcessBuilder(cmd).start() into a separate thread, but that doesn't seem to be solving anything, as I hoped it would have.
Basically the result is that, to the user, the program APPEARS to have crashed, but killing the Java process that drives the ProcessBuilder.start() Process actually allows the created Process to resume its normal behavior. This means that something in the Java application is interfering with the spawned Process, but I have absolutely no idea what, at this point. (Hence why I tried separating it into another thread, which didn't seem to resolve anything)
If anyone has any input/thoughts, please let me know, as I can't for the life of me think of how to solve this problem.
Edit: I have no concern over the I/O stream created from the Process, and have thus taken no steps to deal with that--could this cause a hang in the Process itself?
If the process writes to stderr or stdout, and you're not reading it - it will just "hang" , blocking when writing to stdout/err. Either redirect stdout/err to /dev/null using a shell or merge stdout/err with redirectErrorStream(true) and spawn another thread that reads from stdout of the process
You want the trick?
Don't start your process from ProcessBuilder.start(). Don't try to mess with stream redirection/consumption from Java (especially if you give no s**t about it ; )
Use ProcessBuilder.start() to start a little shell script that gobbles all the input/output streams.
Something like that:
#!/bin/bash
nohup $1 >/dev/null 2>error.log &
That is: if you don't care about stdout and still want to log stderr (do you?) to a file (error.log here).
If you don't even care about stderr, just redirect it to stdout:
#!/bin/bash
nohup $1 >/dev/null 2>1 &
And you call that tiny script from Java, giving it as an argument the name of the process you want to run.
If a process running on Linux that is redirecting both stdout and stderr to /dev/null still produce anything then you've got a broken, non-compliant, Linux install ;)
In other word: the above Just Works [TM] and get rid of the problematic "you need to consume the streams in this and that order bla bla bla Java-specific non-sense".
The thread running the process may block if it does not handle the output. This can be done by spawning a new thread that reads the output of the process.
final ProcessBuilder builder = new ProcessBuilder("script")
.redirectErrorStream(true)
.directory(workDirectory);
final Process process = builder.start();
final StringWriter writer = new StringWriter();
new Thread(new Runnable() {
public void run() {
IOUtils.copy(process.getInputStream(), writer);
}
}).start();
final int exitValue = process.waitFor();
final String processOutput = writer.toString();
Just stumbled on this after I had a similar issue. Agreeing with nos, you need to handle the output. I had something like this:
ProcessBuilder myProc2 = new ProcessBuilder(command);
final Process process = myProc2.start();
and it was working great. The spawned process even did output some output but not much. When I started to output a lot more, it appeared my process wasn't even getting launched anymore. I updated to this:
ProcessBuilder myProc2 = new ProcessBuilder(command);
myProc2.redirectErrorStream(true);
final Process process = myProc2.start();
InputStream myIS = process.getInputStream();
String tempOut = convertStreamToStr(myIS);
and it started working again. (Refer to this link for convertStreamToStr() code)
Edit: I have no concern over the I/O stream created from the Process, and have thus taken no steps to deal with that--could this cause a hang in the Process itself?
If you don't read the output streams created by the process then it is possible that the application will block once the application's buffers are full. I've never seen this happen on Linux (although I'm not saying that it doesn't) but I have seen this exact problem on Windows. I think this is likely related.
JDK7 will have builtin support for subprocess I/O redirection:
http://download.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html
In the meantime, if you really want to discard stdout/stderr, it seems best (on Linux) to invoke ProcessBuilder on a command that looks like:
["/bin/bash", "-c", "exec YOUR_COMMAND_HERE >/dev/null 2>&1"]
Another solution is to start the process with Redirect.PIPE and close the InputStream like this:
ProcessBuilder builder = new ProcessBuilder(cmd);
builder.redirectOutput(Redirect.PIPE);
builder.redirectErrorStream(true); // redirect the SysErr to SysOut
Process proc = builder.start();
proc.getInputStream().close(); // this will close the pipe and the output will "flow"
proc.waitFor(); //wait
I tested this in Windows and Linux, and works!
In case you need to capture stdout and stderr and monitor the process then using Apache Commons Exec helped me a lot.
I believe the problem is the buffering pipe from Linux itself.
Try to use stdbuf with your executable
new ProcessBuilder().command("/usr/bin/stdbuf","-o0","*executable*","*arguments*");**
The -o0 says not to buffer the output.
The same goes to -i0 and -e0 if you want to unbuffer the input and error pipe.
you need to read the output before waiting to finish the cycle. You will not be notified If the output doesn't fill the buffer. If it does, it will wait until you read the output.
Suppose you have some errors or responses regarding your command which you are not reading. This would cause the application to stop and waitFor to wait forever. A simple way around is to re-direct the errors to the regular output.
I was spent 2 days on this issue.
public static void exeCuteCommand(String command) {
try {
boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
ProcessBuilder builder = new ProcessBuilder();
if (isWindows) {
builder.command("cmd.exe", "/c", command);
} else {
builder.command("sh", "-c", command);
}
Process process = builder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null)
System.out.println("Cmd Response: " + line);
process.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

Java getting error while executing Adb Commands using process builder

When Executing following line I am getting response error=> segmentation fault
String[] commands = {"cmd.exe","/c","adb shell","su","cd /data/app","ls com.mypack*"};
StringBuilder cmdReturnRsp = new StringBuilder();
try {
ProcessBuilder processBuilder = new ProcessBuilder(commands);
processBuilder.directory(fileADb);
Process process = processBuilder.start();
InputStream inputStream = process.getInputStream();
int c;
while ((c = inputStream.read()) != -1) {
cmdReturnRsp.append((char) c);
}
System.out.println("responce = "+ cmdReturnRsp);
}catch(Exception e){
}
but when above lines run in cmd prompt it is working fine, so How can make code work same as cmd
You have missunderstanding of process builder. I seems that you think that it works as a kind of script. This is wrong. Process builder just builds correct command line and executes it.
So, you can run cmd.exe, you can run cmd.exe /c adb shell, but I doubt you can run the rest of commands.
Take a look on description of adb. If it supports mode similar to cmd /c, i.e. gets commands in command line and then executes it you can probably do this.
BTW, why do you want to do this?
Check if device is rooted, usually when device is not rooted, It does not work.
/c is not understood I guess.
It should be cd c:/

error for Importing sql file to mysql database using java in windows

here is my code
try{
String logf = "mysql -p -h localhost ruralcdn<E:\\data\\DBServer\\"+FileName;
System.out.println("Command"+logf);
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(logf);
int lm = pr.waitFor();
System.out.println("lm"+lm);
System.out.println("!!Done!!");
}catch(Exception ex){
System.out.println("!!error!!");
}
when i compile the above code, it hangs for infinite period of time and no entry updated in my database.
when i tried using the method given below
Connection conn = dbConnectionSource.getConnection();
Statement stmt = conn.createStatement();
stmt.execute(FileUtils.readFileToString(new File("./some-sql-file")));
console displayed error:you have an error in your sql syntex
please help me so that i can do things correctly.
Thanks -A
Your command (in logf) includes a redirection of standard input. Unfortunately, you can't do it that way because the Process.exec(String) method doesn't understand how to do command redirection, quoting and sso on. It only understands how to execute a simple command with arguments separated by spaces.
You've got two choices:
You can open the file in Java, and write it to the process object's output stream so that it show up on the commands standard input.
You can tell Java to run the mysql command in a shell / command interpretter that can take care of the redirection and so on.
Your code should look something like this:
String[] command = new String{
"cmd",
"/c",
"mysql -p -h localhost ruralcdn < E:\\data\\DBServer\\" + fileName;
ProcessBuilder pb = new ProcessBuilder(command);
Process p = pb.start();
p.waitFor();
The other thing that your code should do is to read and display (or discard) the standard output / error from the command. If you don't read it:
you won't know if it contains any error messages, and
there is the possibility that the mysql command will block because it can't write any more to the pipe that you haven't reading.
console displayed error:you have an error in your sql syntex
It is probably telling the truth ...
By the way, the reason that the mysql command currently hangs for ever is that it is waiting for the Java process to send it data on its standard input. And that ain't going to happen because your Java code doesn't write anything to it.

In Java, send commands to another command-line program

I am using Java on Windows XP and want to be able to send commands to another program such as telnet.
I do not want to simply execute another program. I want to execute it, and then send it a sequence of commands once it's running.
Here's my code of what I want to do, but it does not work:
(If you uncomment and change the command to "cmd" it works as expected. Please help.)
This is a simplified example. In production there will be many more commands sent, so please don't suggest calling "telnet localhost".
try
{
Runtime rt = Runtime.getRuntime();
String command = "telnet";
//command = "cmd";
Process pr = rt.exec(command);
BufferedReader processOutput = new BufferedReader(new InputStreamReader(pr.getInputStream()));
BufferedWriter processInput = new BufferedWriter(new OutputStreamWriter(pr.getOutputStream()));
String commandToSend = "open localhost\n";
//commandToSend = "dir\n" + "exit\n";
processInput.write(commandToSend);
processInput.flush();
int lineCounter = 0;
while(true)
{
String line = processOutput.readLine();
if(line == null) break;
System.out.println(++lineCounter + ": " + line);
}
processInput.close();
processOutput.close();
pr.waitFor();
}
catch(Exception x)
{
x.printStackTrace();
}
That looks OK, as it won't be producing that much output, but you should really read and write in separate threads so it doesn't fill up the buffer and block waiting you to read before you reach the next step.
So if it's reaching the point where you flush the command you send to it, find out whether the Windows telnet client supports receiving commands from standard input rather than a console by piping the text you're sending to its standard input to it in a command prompt.
For example, echo dir c:\ | cmd causes cmd to run, list the c: drive contents and exit, much the same behaviour as if you typed dir c:\ into the console. But echo open localhost | telnet causes telnet to clear the screen then exit, rather than behaving the same way as if you typed it into the console. As telnet needs to mask user input for passwords, it's quite likely that it's using the console API rather than reading from standard input. It's help doesn't list any command arguments to tell it to read from standard input, so maybe you need to use a telnet implementation which is better suited to scripting.
It's not directly an answer to your question, but...
Instead of using Runtime.exec() you should use a ProcessBuilder and redirect stderr to stdout (ProcessBuilder.redirectErrorStream(true)). Otherwise your process could block if it writes something to stderr (Windows doesn't like it when the output of a process isn't read).
If you want to control a telnet session programatically from Java, you might be able to use this Java telnet library... you can do the same things (open connections, send username/password, send commands and receive results) but without actually spawning a separate process.
You may take a look at the Telnet Ant task you can call it directly in your code with out having to use a build.xml file.
You can also take a look at the source code and see how they do it.

Categories

Resources