java sshd multiple command - java

If someone have an actual solution to this problem i would much appreciate it. So far all implementation that I have used close the session as soon as one of the channel is "connected" what ever that means. Like most i need to be able to script ssh interaction meaning that i need the result of my operation with a still alive channel I'm not looking for a command with "cmd1;cmd2;cmd3" type ..
The best example I can think of is if you were trying to browse trough a file system.
If each command is a new session you would be going going no where since at each new session you go back to square one.
In command line the ssh session remain open when you type an operation why all java implementation differ so much from this approach is beyond me. My next step if i cant find an answer is actually to use command shell from java and interacting from there instead of using java ssh libraries..

public void connect() {
Session session;
try {
session = createConnectedSession();
java.util.logging.Logger.getLogger("test").log(Level.INFO,"isConnected "+session.isConnected());
ByteArrayOutputStream output = new ByteArrayOutputStream();
Channel channel = session.openChannel("shell");
channel.setOutputStream(output);
PrintStream ps = new PrintStream(channel.getOutputStream(), true);
// InputStream is = new InputStream(channel.getInputStream());
channel.connect();
sleep();
java.util.logging.Logger.getLogger("test").log(Level.INFO,"isConnected "+session.isConnected());
Stack<String> mstack = getCommandStack();
//readChannel(channel);
while (!mstack.isEmpty()) {
String cmd = mstack.pop();
java.util.logging.Logger.getLogger("test").log(Level.INFO,"sending command "+cmd);
ps.println(cmd);
sleep();
System.out.println(output.toString());
java.util.logging.Logger.getLogger("test").log(Level.INFO,"command result"+output.toString());
sleep();
// System.out.println(output.toString());
ps.flush();
}
channel.disconnect();
session.disconnect();
} catch (JSchException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

Related

How to tell if an SFTP upload was successful using JSch

Unfortunately the getExitStatus() method always returns -1 so i can't use that to tell me whether or not a file upload worked. I tried to use the getInputStream() method of the Channel class but whenever i tried to read from the inputstream my code blocked forever as if the Channel instance was still open/connected (even though the isConnected and isClosed() were false and true respectively - suggesting that the Channel was indeed closed). The following code always blocks after i try to read a byte of data from the input stream:
public class Put {
public static void main(String[] args) throws IOException {
Session session = null;
Channel channel = null;
ChannelSftp channelSftp = null;
InputStream in = null;
JSch jsch = new JSch();
try {
jsch.setKnownHosts("known_hosts");
session = jsch.getSession("user", "host", 22);
session.setPassword("password");
session.connect();
channel = session.openChannel("sftp");
channel.setInputStream(null);
stdout = channel.getInputStream();
channel.connect();
channelSftp = (ChannelSftp)channel;
channelSftp.cd("/path/to/sftp");
channelSftp.put("/path/to/localfile", "/path/to/remotefile");
} catch (JSchException e) {
System.out.println(e.getMessage());
e.printStackTrace();
} catch (SftpException e) {
System.out.println(e.id);
System.out.println(e.getMessage());
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(channelSftp != null && channelSftp.isConnected())channelSftp.exit();
if(channel != null && channel.isConnected()) channel.disconnect();
if(session != null && session.isConnected()) session.disconnect();
}
System.out.println("Channel is connected? " + channel.isConnected()); // returns false as i would expect
System.out.println("Channel is closed? " + channel.isClosed()); // returns true as i would expect
System.out.println(stdout.available()); // returns 0
System.out.println(stdout.read()); // code blocks here
}
}
I suppose my questions are:
Why is my code blocking whenever i try to read from the input stream (even though the Channel is indeed closed)
What is the way to tell if a file upload worked or not. I guess if a SFTPException is thrown that's unsuccessful otherwise i can assume it was successful?
I guess if a SFTPException is thrown that's unsuccessful otherwise i can assume it was successful?
That is correct. The various ChannelSftp.put() functions will throw an exception if they fail for any reason. If you want to double-check, you could call ChannelSftp.stat() or ...lstat() on the remote filename afterwards to check it. But be aware that another process could hypothetically delete or move the remote file before you got a chance to check it.
You don't normally need to access the input or output streams of a ChannelSftp. getExitStatus() would tell you the exit status of the SFTP session as a whole, rather than the result of a particular operation.
JCraft has an example program illustrating how to do SFTP that you might find useful.

Trouble sending multiple values to an external process with apache commons-exec

I'm trying to write a little application that would automate the use of an external application which is cisco any connect mobility client. It provides a command line tools that you can use to connect to your VPN.
I want to run this command line tools from my java application using apache commons-exec library and be able to read his output to send needed information.
I already searched on the net to find "how to communicate" with an external application but the only post I found was this article : Trouble providing multiple input to a Command using Apache Commons Exec and extracting output where it just says "hey I found the solutions", but I don't understand how he did it.
When I start the process, I run a function that read the input like this :
Thread T = new Thread() {
public void run() {
String line;
try {
line = processOutput.readLine();
while (line != null) {
System.out.println(line);
if(line.contains("VPN-Password")){
sendMessage(processInput, "1");
}
if(line.contains("Please enter your username and password")){
sendMessage(processInput, "username");
}
line = processOutput.readLine();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
T.start();
the function send message just run a thread to write in the process inputstream then flush it.
Thread T = new Thread() {
public void run() {
try {
os.write((message+"\n").getBytes());
os.flush();
System.out.println("SENT : "+message);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
T.start();
As you can see I check the output to send a message to the process depending on it (basicly to answer questions). However, when it comes to the "Please enter...", I got this exception
java.io.IOException: Read end dead
My issue is that I can't find how to "communicate" with the process by reading his output and sending it messages depending on what it tells me.
Can you help me ?
Thanks for reading.

Android Ping command dies on unreachable server

I have been trying to attempt to insert a ping command thread into my Android application, and when the server is reachable the code works great. When the server is unreachable, the process hangs and I have no idea why.
This code works in the emulator, whether the host is resolvable or not, however on an actual device, the process.waitFor never returns, and no output is published from the input or output streams.
Any ideas?
protected double executePing(String ipAddress) {
List<String> commands = new ArrayList<String>();
commands.add("/system/bin/ping");
commands.add("-c");
commands.add("5");
commands.add("-w");
commands.add("5");
commands.add("128.128.128.128");
try {
this.doCommand(commands);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return laten;
}
private void doCommand(List<String> command) throws IOException{
ProcessBuilder pb = new ProcessBuilder(command);
Process process = pb.start();
// any error message?
StreamGobbler errorGobbler = new StreamGobbler(
process.getErrorStream(), "ERROR");
// any output?
OutputStreamGobbler outputGobbler = new OutputStreamGobbler(
process.getInputStream(), "OUTPUT");
// kick them off
errorGobbler.start();
outputGobbler.start();
// read the output from the command
try {
exitVal = process.waitFor();
//Sleep for 10 secs to try to clear the buffer
Thread.sleep(6000);
//pingVal = echo.toString();
if(exitVal == 0 && !pingVal.isEmpty()){
//System.out.println("PING STATS: "+pingVal);
try{
pingVal = pingVal.substring(pingVal.lastIndexOf("rtt min/avg/max/mdev"));
pingVal = pingVal.substring(23);
pingVal = pingVal.substring(pingVal.indexOf("/")+1);
laten = Double.parseDouble(pingVal.substring(0,pingVal.indexOf("/")));
}catch (IndexOutOfBoundsException ex){
System.out.println("PING VAL: "+ pingVal);
ex.printStackTrace();
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("ExitValue: " + exitVal);
}
One option would be to create a new thread to ping, and keep it open for a certain amount of time (call it a timeout). If you don't get the desired response, within the desired time, you can close the thread & try again; or, kill the process. This would give you the ability to check for specific response codes, along with the timeout.

how to pass the arguments to the shell command through java?

I am new to this kind of integration of java with Unix.
what i am trying to do is
String command="passwd";
Runtime rt=Runtime.getRuntime();
try {
Process pc=rt.exec(command);
try {
pc.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
BufferedReader buf = new BufferedReader(new InputStreamReader(pc.getInputStream()));
String line = "";
while ((line=buf.readLine())!=null) {
System.out.println(line);
}
BufferedReader buf1 = new BufferedReader(new InputStreamReader(pc.getErrorStream()));
String line1 = "";
while ((line1=buf1.readLine())!=null) {
System.out.println("Error--"+line1);
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
System.out.println("IOException---"+e1.getMessage());
}
now when i am trying to pass the "passwd" command the Unix environment goes to suspended mode.
I want to know how can i pass the old password ,new password and confirm new password to the shell using the java code.
You need to pass it in using the confusing named Process.getOutputStream(). From the doc:
Gets the output stream of the subprocess. Output to the stream is
piped into the standard input stream of the process represented by
this Process object
Note that you need to capture the processes stdout/err simultaneously to avoid blocking. See this answer for more details.
There is a utility called expect. If u installed u can pass argument for any thing. So construct as string execute by
String ConstructedCommand;
Process p=Runtime.getRuntime().exec(ConstructedCommand);
This link will be deserve your need. http://linux.die.net/man/1/expect

run interactive command with apache commons exec

I want to run an interactive command with apache commons exec. Everything works except that when my command is executed and waits for user input I don't see my input in the console until I press enter which makes it effectively unusable.
This is an example of an interactive program:
public static void main(String[] args) {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while (true) {
System.out.print("=> ");
try {
line = in.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(line);
}
}
Now I want to execute that with apache commons exec like this:
public static void main(String[] args) {
Executor ex = new DefaultExecutor();
ex.setStreamHandler(new PumpStreamHandler(System.out, System.err, System.in));
CommandLine cl = new CommandLine("java");
cl.addArguments("-cp target\\classes foo.bar.Main");
try {
ex.execute(cl);
} catch (ExecuteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
As I said, it basically works, I get the "=>" prompt but when I type something I don't see it until I hit enter. I'm doing this on windows 7 with a cmd prompt.
I'd appreciate any hint on how to achieve the desired behaviour.
Edit: It works as expected on linux. I guess this is an issue with the windows cmd prompt. I'd still like to make this work if at all possible, so I would appreciate any insight into this behaviour on windows.
Edit2: I also tested with msys shell and powershell, both exhibit the same problem.
Edit3: I worked around the issue by launching a seperate cmd prompt. This works, but I still like to understand why.
CommandLine cl = new CommandLine("cmd");
cl.addArguments("/C java -cp target\\classes foo.bar.Main");
thanks
Raoul
I'm not sure exactly what you were expecting to happen here; if the spawned process is designed to wait to read from its input, then it shouldn't be surprising when it does exactly that?
If that's the issue, and your question is "How can I make my program automatically send a newline character to the spawned process' input?", then you'll need to define an OutputStream to write the input to, and get hold of the ExecuteStreamHandler to attach it to the process. Something like the following:
Executor ex = new DefaultExecutor();
// Create an output stream and set it as the process' input
OutputStream out = new ByteArrayOutputStream();
ex.getStreamHandler().setProcessInputStream(out);
...
try
{
ex.execute(cl);
out.write("\n".getBytes()); // TODO use appropriate charset explicitly
...
Using Apache exec org.apache.commons.exec.DefaultExecuteResultHandler you can launch a non-blocking command. And then you can follow the steps #Andrzej mentioned.

Categories

Resources