SSH with JSch for multiple commands with intermediate Output - java

I am very new to JSch. I am trying to run few commands on a server which I am getting as input from some other system.
What I am doing is taking those commands and passing them as a parameter to a java method.
For Eg:
public String readFileFromPath(String server, String path,
String fileName);
Here first we have to cd to 'path', then we need to read some particular content from the file present on the path.
To implement this I did following :
Session session = sshOperations.getSessionWithTimeout(USER,server,SSHPORT,1000);
Channel shellChannel = sshOperations.getShellChannel(session);
InputStream in = new PipedInputStream();
PipedOutputStream consoleInput = new PipedOutputStream((PipedInputStream) in);
OutputStream out = new PipedOutputStream();
BufferedReader consoleOutput = new BufferedReader(new InputStreamReader(new PipedInputStream((PipedOutputStream) out)));
shellChannel.setInputStream(in);
shellChannel.setOutputStream(out);
shellChannel.connect(1000);
consoleInput.write(("cd "+path).getBytes());
// first While
while ((line = consoleOutput.readLine()) != null)
{
System.out.println("check "+ line);
}
// execute second command
consoleInput.write("cat some.properties".getBytes());
// second While
while ((line = consoleOutput.readLine()) != null)
{
System.out.println("check "+ line);
}
Now what I know is whenever I connect to that server I get a welcome text :
"You are using <serverName> server.
Please contact admin for any issues"
So, after the first while loop my cd command ran and it prints the message mentioned above. But, after this it waits for more output from the output stream (it is stuck at this point )and the output stream can't product anything until I run another command.
Somehow I want to exit from the first while loop without writing the logic for consuming the 2 lines(fixed lines). As for the next command I will not know how many lines will come as output in stream.
Please suggest the logic to the get the desired output i.e. I ran a command and some logic consumes it and then I get get to run another command and so on until all the commands which came as parameter are executed.
Is there any other way to achive the same?
Thanks

Do not use "shell" channel. The "shell" channel is intended to implement an interactive session (hence the welcome message), not to automate command execution.
To automate command execution, use "exec" channel. See Multiple commands through JSch shell.
Though you actually do not need multiple commands. There's no need for cd. Just use a full path in the cat command
ChannelExec channel = (ChannelExec) session.openChannel("exec");
channel.setCommand("cat " + path + "/some.properties");
channel.connect();
Though actually, if you want to read contents of files, use SFTP, instead of running console commands like cat. SFTP is a standardized API to access files over SFTP.
See SFTP file transfer using Java JSch.

Related

how to run a bash program from windows in unix using java

I am trying to run a program which process a file from window using jcraft library in Unix. what i found after establishing the channel it always try to run the program in home directory but i need to run in a separate directory.please have a look what i tried so far and let me know what i am missing.
String strRemoteDir = "/home/process/input"
channel = session.openChannel("sftp");
channel.connect();
System.out.println("sftp channel opened and connected.");
channelSftp = (ChannelSftp) channel;
// Printing Home Directory in Unix Server
System.out.println(channelSftp.getHome());
channelSftp.cd(strRemoteDir);
System.out.println(channelSftp.pwd());
// for uploading a file where i need to run the program
File f = new File(fileName);
channelSftp.put(new FileInputStream(f), f.getName());
System.out.println("File transfered successfully to host.");
fileTransfer = true;
channel=session.openChannel("exec");
InputStream in=channel.getInputStream();
// it is printing the desired directory where i want to go
System.out.println(channelSftp.pwd());
((ChannelExec)channel).setCommand("sh process.ksh "a.txt");
channel.setInputStream(null);
((ChannelExec)channel).setErrStream(System.err);
channel.connect();
output : process.ksh not found
But through putty i was able to run the program. just to let you know process.ksh is not in the input directory, but has the capability to run from anywhere with arguments.
((ChannelExec)channel).setcommand("ls")
prints out all the files from home directory. i believe i am establishing a channel to home directory, i just don't know how to run bash program using jcraft in a desired location.Please let me know what i am missing or is it possible to make it happen.
Thanks in advance.
Nur
"sftp" channel are not made to execute shell command but sftp command only.
Channel channel = session.openChannel("shell");
cmdSend = channel.getOutputStream();
InputStream cmdRcv = channel.getInputStream();
// Start a Thread reading and displaying cmdRcv
channel.connect(3000);
Thread.sleep(1000);
cmdSend.write("cd /to/the/right/dir\n".getBytes());
cmdSend.flush();
cmdSend.write("sh process.ksh \"a.txt\"\n".getBytes());
cmdSend.flush();
Others have provided examples of how to set the working directory. However, a more defensive style of programming is to assume nothing and specify everything explicitly. So for specifying the command to execute, something like:
/bin/sh /path/to/bin/process.ksh /path/to/data/ "a.txt"
Notice that I have added a new first argument to your command, the directory you want to run it from.
Now, change your script so that it changes to this directory (given as parameter $1) before continuing.
This can be done by adding cd at the beginning, something like:
cd $1
shift
The shift command shifts all other arguments, so that $2 becomes $1 and so on, so that the rest of the script will find the arguments where it expects.

JCraft Jsch returns nothing while command works in a regular terminal

All I am trying to do with jsch is execute
stat -c %s /directory/file.ext
...and it does work as expected from the command line. Now I know all of my ssh/reader/jsch code works just fine because I use a series of commands using the exact same code to gather the directory and the files after searching out things with the proper .ext.
In fact we are using the JCraft stuff for various other things for another test tool we are building. I can do ls, cd, find, grep, echo, etc. No problem. However as soon as I started doing stat it popped up. Now I am using
String line = bufferedReader.readLine();
...so I thought maybe stat by default doesn't have a newline character for the readline, however, it is not being hung on the readline() method which would happen if no newline was present.
All the SSH connection stuff is working, no exceptions, no anything. It connects, executes the command, and just returns nothing.
cExec.setCommand(command);
InputStream commandOutput = channel.getInputStream();
cExec.connect( timeoutInSecs * 1000 );
BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(commandOutput, "UTF-8") );
String line = bufferedReader.readLine();
Where channel is a jcraft object that is part of its library.

Can't enter password using Java ProcessBuilder to interact with a CLI

I'm trying to interact with a CLI on a server from a web browser. On the server side, I'm using a Java Servlet running on JBoss AS 7.1.1.Final. The CLI is an ovirt-engine tool (ovirt-iso-uploader). In order to use it, you have to provide the REST API password when it requests it.
Therefore, here is the following code I'm using to interact with the CLI:
private String executeCommand(String command) {
System.out.println("Executing command: " + command);
String[] commands = new String[]{"/bin/sh","-c",command};
try {
ProcessBuilder builder = new ProcessBuilder(commands);
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
System.out.println(line);
if (line.contains("Please provide the REST API password")){
writer.write( "password\n" );
writer.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
However, whatever input command I'm using, I always have the same problem. (For this example I used the command ovirt-iso-uploader list to list all the ISO storage domains. You can find the documentation of the CLI here)
11:31:34,282 INFO [stdout] (http--0.0.0.0-8080-2) Executing command: ovirt-iso-uploader list
Please provide the REST API password for the admin#internal oVirt Engine user (CTRL+D to abort):
So the execution is blocked here as the CLI is waiting for the password and the Servlet can't see the line Please provide the REST API password for the admin#internal oVirt Engine user (CTRL+D to abort): as it is not send in [stdout]. However, it is working if I manually enter the password directly in the terminal.
Therefore, my question is how can I read the password request from the CLI and answer to it ?
Thank you for your time.
I would suggest that buffered reader is the wrong thing to use as it may be waiting for a newline at the end of the prompt which is not there and can not therefore return a line.
I think you will have to read the stream directly. Maybe character by character or byte by byte.
It may also not be necessary to wait for the prompt. In unix shell programming it is common to provide the standard input without reference to prompt like:
Command <!
Lineone
line two
!

Calling Python from Java (Tomcat6) as sub-process

I am trying to call a python script from a java/tomcat6 webapp. I am currently using the following code:
Process p = Runtime.getRuntime().exec("python <file.py>");
InputStream in = p.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader b = new BufferedReader(isr);
logger.info("PYTHON OUTPUT");
String line = null;
while ( (line = b.readLine()) != null){
logger.info(line);
}
p.waitFor();
logger.info("COMPLETE PYTHON OUTPUT");
logger.info("EXIT VALUE: "+p.exitValue());
I can't really see any output in the catalinia.out file from the python script and using an adapter library like jython is not possible as the script relies on several machine learning libraries that need python's Numpy module to work.
Help?
The explanation is probably one (or more) of following:
The command is failing and writing error messages to its "stderr" fd ... which you are not looking at.
The command is failing to launch because the command name is incorrect; e.g. it can't be found on $PATH.
The command is trying to read from its stdin fd ... but you haven't provided any input (yet).
It could be a problem with command-line splitting; e.g if you are using pathnames with embedded spaces, or other things that would normally be handled by the shell.
Also, since this is python, this could be a problem with python-specific environment variables, the current directory and/or the effective user that is executing the command.
How to proceed:
Determine if the python command is actually starting. For instance. "hack" the "" to write something to a temporary file on startup.
Change to using ProcessBuilder to create the Process object. This will give you more control over the streams and how they are handled.
Find out what is going to the child processes "stderr". (ProcessBuilder allows you to redirect it to "stdout" ...)

java servlet, run exe file in a server to the client

I have a java servlet running in a server, plus an 'exe file' located in the same server,
i want , in respond to the client passed parameters to the servlet , to run the exe file located on the server and show it to the client , even a screen shot,,
any ideas??!! please help
You can use Process and Runtime classes
Eg :
Runtime r = Runtime.getRuntime();
Process p = r.getRuntime().exec("C:\\newfolder\\run.exe");
For taking screenshot refer to how to take sc in java
This way you can save the image and then send this image to user.
For sending image to client refer to how to send file from sever to client
these are.the pieces , you need to put them together
UPDATE 1 : to kill the exe you can use p.destroy() ( not a good implementation though, as it forcefully kills the process)
UPDATE2 : to check if the process( which is executing your exe) hence to check if the exe is running or not, you can refer to how to check if a process is running
You can run an external command in Java by the following code:
Process p = Runtime.getRuntime().exec("your_external_program_here");
You can pass in parameters as well, simply amend the above line to include what parameters you want to pass into the program.
To retrieve the 'output' of the process you need to get the input stream for the process:
InputStream output = p.getInputStream();
Note the input stream is the piped output of the process. You can then view the contents (advisable to use a buffered reader) like this:
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(output));
while ((line = reader.readLine()) != null) { ... }
Or alternatively you can look at ProcessBuilder which is easier to use :)

Categories