Sending commands to a background executable via Java ProcessBuilder in MATLAB - java

I am using Java ProcessBuilder in MATLAB to open an executable in the background. This executable does some automated tasks, then pauses, waiting for user to type in some text and press enter.
I am able to send "enter key" commands to the executable via ProcessBuilder, but I am unable to send text strings. Can someone help me in this? Here is my code so far that initiates the executable in the background:
% specify the executable to run
run_exe_file = {'my_executable_program.exe'};
% initialize the java ProcessBuilder, run the executable
processBuilder = java.lang.ProcessBuilder(run_exe_file);
myProcess = processBuilder.start();
% initialize the reader. notice the myProcess in myProcess.getInputStream
reader = ...
java.io.BufferedReader(...
java.io.InputStreamReader(...
myProcess.getInputStream() ...
) ...
);
% initialize the writer. notice the myProcess in myProcess.getOutputStream
writer = ...
java.io.BufferedWriter(...
java.io.OutputStreamWriter(...
myProcess.getOutputStream() ...
) ...
);
After running the code above, 'my_executable_program.exe' starts running in the background successfully. After the background program run some tasks, it waits for user input. If for example I want to send an "enter key" press to the program I type in MATLAB the following:
writer.newLine; writer.flush; reader.readLine;
Which successfully sends the enter key command. However if I want to send some text to the program, from my understanding I am supposed to use the following code:
writer.write("Here is some text I'm sending to the program"); writer.flush; reader.readLine;
However running the above code does not send the text string to the program in my testing. Can someone help me with what is the proper syntax to send the text?
Thank you

Related

how to pass the user and pwd via the runtime.exec() in java

I'm trying to run a simple command using java 1.8 and OS Solaris 11.
My program runs under a particular user and the command must run under SuperUser
here is the command:
Runtime.getRuntime().exec("su - root -c 'pargs -l 1111'");
if i run the command in shall its work fine and ask for password and wen i enter the password i will get the result.
the problem is wen i run it in java
here is my code
Process proc = Runtime.getRuntime().exec("su - root -c 'pargs -l 1111'");
PrintWriter out = new PrintWriter(new OutputStreamWriter(proc.getOutputStream()));
out.println(password);
out.flush();
int exitCode= proc.waitFor();
System.out.println(exitCode);//exitCode = 1
BufferedReader pArgs= new BufferedReader( new InputStreamReader(proc.getInputStream()));
if((line=pArgs.readLine()) != null)
{
//do something
}
else
{
//something not working = ERROR
}
i think that the line equal to null because something in the set of the password is not correct bat i'm not sure
what i'm doing wrong?
I might suggest a different way around this issue altogether. Instead of trying to run a shell command that dynamically asks for a password, make the command not require a password.
If its just asking for a password because it needs root, you can add a line in the sudoers file under root to say that your program user is allowed to execute that one specific command as if they were root: https://www.linux.com/blog/configuring-linux-sudoers-file.
This would be more secure too as you wouldn't have the password floating around code.
how to pass the user and pwd via the runtime.exec() in java
You can't under Solaris if you want to use su.
Solaris su uses the getpass() function to get the necessary password from the user.
From the Solaris getpass() man page:
Description
The getpass() function opens the process's controlling terminal, writes to that device the null-terminated string prompt, disables echoing, reads a string of characters up to the next newline character or EOF, restores the terminal state and closes the terminal.
...
Errors
The getpass() and getpassphrase() functions may fail if:
...
ENXIO
The process does not have a controlling terminal.
su will either get the password from the controlling terminal, or it will fail.
This is a deliberate design decision to make it almost impossible to perform insecure actions such as automated password entry.
Thank you very much for all the answers. But my solution was a little different.
It was decided to use an external file that could be written and read from both processes.
The whole goal was to do a handshake again in case the process running at the root will fall (watchdog).
So now there is no need to use the command
Runtime.getRuntime().exec("su - root -c 'pargs -l 1111'");
When the root process starts running, it records a time signature into a file.
and if the process of the user (who reads the file every X time) finds that the signature has changed, he will do a handshake again.

How to wait for multi-threaded shell script execution to finish called inside my web service?

I have a java restful service method which executes a myscript.sh using processBuilder. My script takes one input (example - myscript.sh /path/to-a/folder).
Inside the script something like this
-> execute a command which is multithreaded i.e parallel processing
-> echo "my message"
Now when call my script from a linux command line it executes fine. First all the threads running finishes and then some text output from threaded command execution shown on terminal and then echo my message is shown.
But when I call the same script from java using processBuilder, the last echo message comes immidiately and execution ends.
Following the way I call my script from java
ProcessBuilder processBuilder = new ProcessBuilder("/bin/bash","/path/to/myscript.sh","/path/to/folder/data");
Process proc = processBuilder.start();
StringBuffer output = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = "";
while((line = reader.readLine()) != null){
output.append(line + "\n");
}
System.out.println("### " + output);
I don't know whats happening, how to debug also.
Can someone enlighten me on how to get the same behaviour from shell script when run from terminal or from java processBuilder?
Use ProcessBuilder.redirectErrorStream(boolean redirectErrorStream) with argument true to merge the errors into output. Alternatively, you could also use the shell command syntax cmd 2>&1 to merge the error with output.
These are some of the cases why you may be immediately getting the output of the last echo statement (instead of the script taking time to run and return proper results):
Missing environment variables
The launched bash needs to source .bashrc or some such recource file
The launched bash may not be running in right directory (you can set this in ProcessBuilder)
The launched bash may not be finding some script/executable in its PATH
The launched bash may not be finding proper libraries in the path for any of the executables
Once you merge error, you would be able to debug and see the errors for yourself.
In your context, separate processes may be spawned in two ways:
1) Bash
/path/to/executables/executable &
This will spawn a new executable executable and you need to wait for it to finish. Here's an answer that will help you.
2) Java
Process exec = Runtime.getRuntime().exec(command);
status = exec.waitFor();
Essentially, you need to wait for the process to end before you start reading its std/err streams.
If I understand the problem correctly, adding just this line to your code should suffice: status = exec.waitFor() (Before you obtain the streams)
Here's the JavaDoc for Process.waitFor() :
Causes the current thread to wait, if necessary, until the process represented by this Process object has terminated. This method returns immediately if the subprocess has already terminated. If the subprocess has not yet terminated, the calling thread will be blocked until the subprocess exits.
Returns:
the exit value of the subprocess represented by this Process object. By convention, the value 0 indicates normal termination.
Throws:
InterruptedException - if the current thread is interrupted by another thread while it is waiting, then the wait is ended and an InterruptedException is thrown

Process launched from Java code doesn't return

This is my code :
Process p1;
try {
p1 = Runtime.getRuntime().exec( "utils/a.out < utils/test_c2.txt > utils/result.txt" );
p1.waitFor();
} catch ( Exception e ) {
System.out.println("Something went bad!");
}
I've read that there should be a problem with the input buffer size, but in this case, all the output from the launched process is redirected to " utils/result.txt", so the launched process should not reach deadlock. When I run the same command from terminal it works. Maybe it would be helpful to describe what is "a.out". I obtained it from a flex file as follows:
$ flex rulex.lex
$ gcc lex.yy.c -lfl
Any help would be appreciated.
The subprocess is waiting to read data on stdin. Java does not launch the subprocess within a shell, so no pipes are available. You need to make your subprogram take files as arguments and open the files itself. Another option is to start a shell (like bash) and tell it to run the program, then the piping of files will work.

ffmpeg won't start until java exits

I am trying to make a java program that automatically converts wtv files in an input folder to mpg files in output folder. The twist is that I make it run periodically, so it acts as a synchronizer.
The following code works for converting the .wtv to a .dvr-ms, which is required by ffmpeg since it cannot convert .wtv files directly.
Process p = Runtime.getRuntime().exec("C:\\Windows\\ehome\\WTVConverter C:\\Users\\Andrew\\Desktop\\test\\input\\input.wtv C:\\Users\\Andrew\\Desktop\\test\\output\\input.dvr-ms");
p.waitFor();
WTVConverter has no problems running from a java application. ffmpeg is a different story. Once the above line runs, I then run this...
Process p = Runtime.getRuntime().exec("ffmpeg\\bin\\ffmpeg -y -i \"C:\\Users\\Andrew\\Desktop\\test\\output\\input.dvr-ms'" -vcodec copy -acodec copy -f dvd \"C:\Users\Andrew\Desktop\test\output\input.mpg\"");
p.waitFor();
Suddenly, there is a problem... The application ffmpeg shows up in the task manager, but it's cpu usage is 0, and no mpeg files is being generated. If I force the java application to close, though, suddenly it starts working! Huh?
What reason would there be for a command line application to wait for its calling application to quit before it executes? I'm not incredibly command line savvy, so I don't really know how to diagnose this problem.
Bah, this always happens. I post a question, and THEN I figure it out on my own. Turns out, ffmpeg expects you to read in its text output before it loads each frame. If a calling program does not do this, it simply waits. If there is no calling program, I assume that it just outputs it nowhere. What I did is ran the program as usual, but also read in text from the process's input stream like so...
Process p = Runtime.getRuntime.exec(".....");
final Scanner in = new Scanner(p.getInputStream());
new Thread()
{
#Override
public void run()
{
System.out.println(in.nextLine());
}
}.start();
Lesson learned, I guess.

echo from csh script not showing up on terminal

I am currently executing a csh shell script from a GUI button. The script originally calls another sql script to select information from a database and output it to a log file in the tmp directory. I now need to CAT that file and display it on the xterm window. I use the java Runtime.exec() method to execute the command and I figured I have two options that I can use
Redirect the std output to show it on the xterm
Read from the log file using the csh script and ouytput to xterm
So I chose option 2 and I cannot even get the csh script to output a simple hello world which means I cannot out put anything to the screen when I run it from netbeans. When I try to run the script directly from the xterm it works . Here is the script code
#!/bin/csh -f
#set MYSQL=${MYSQL_HOME}/mysql
#set PSQL=${PSQL_HOME}/psql
echo "Hello World"
#set REPORT=${CLEADM_HOME}/Scripts/DataValidation/CLEADM_EarthOrientationParametersDataReport.sql
#${REPORT}
#${PSQL} ${CLEDBUSER}<${REPORT}
#Get the number of lines in the report file for scrollbar control
#set lc='wc -l /tmp/results.log'
#echo $lc
I commented everything out just to see if I could even print (echo) the results to the screen and that doesn't work. When I run it from the xterm directly (~/.mysqlconnection.csh) it seems to work and prints out "Hello World". I do not know what is wrong. So i tried to force the terminal to come up by adding this code at the top of my script
/usr/openwin/bin/XTERM \ this opens up the xterm but leaves it frozen for some reason? now i cant access anything on my computer
below is the code i use to exeucte the csh script from a java button. i call this method behond the button
public class RunShellScript {
public static void runShellScript (String unixCommand)
{
try {
Runtime runtime=Runtime.getRuntime();
Process process=runtime.exec(new String [] { "/bin/csh", "-c", unixCommand});
InputStream stderr=process.getErrorStream();
InputStreamReader isr=new InputStreamReader (stderr);
BufferedReader br=new BufferedReader (isr);
String line=null;
System.out.println("<ERROR>");
while((line=br.readLine())!=null)
System.out.println(line);
System.out.println(line);
int exitVal=process.waitFor();
System.out.println("Process exitValue:" + exitVal);
}
catch (Throwable t)
{
t.printStackTrace();
}
somewhere i need to redirect the output to an exterm and i am confused as to how to dop that using the streamreader
EDIT - I'm completely starting over with my answer since I badly misunderstood the requirements.
If you want a new window each time the user presses the button, then opening an xterm from the csh script should work; try this:
/usr/openwin/bin/xterm -e "bash -c 'cat /tmp/results.log; echo press a key to continue; read'" &
If you want one window that stays open forever, but keeps updating with new results each time the user presses the button, that's a little different. I would try spawning the other window from Java. You could either have a separate Java window/frame, or use another xterm. To use another xterm, try running a Process somehow, like this:
new ProcessBuilder("/usr/openwin/bin/xterm","-e","tail -f /tmp/results.log").start();
That will open up the tail -f command on the results.log file, and everything you add to the log file will show up in the xterm.

Categories