I have the following code:
JSch jsch = new JSch();
jsch.setKnownHosts(dotSshDir + "/known_hosts");
jsch.addIdentity(dotSshDir + "/id_rsa");
Session session = jsch.getSession(userName, hostname, 22);
session.connect();
ChannelExec channel = (ChannelExec) session.openChannel("exec");
channel.setCommand(command);
channel.setInputStream(null);
channel.setErrStream(System.err);
Reader reader = new InputStreamReader(channel.getInputStream());
char[] buf = new char[1024];
int numRead;
while ((numRead = reader.read(buf)) != -1) {
String readData = String.valueOf(buf, 0, numRead);
result.append(readData);
buf = new char[1024];
}
It's hanging trying to read from the reader. How do I fix this? How do I go about hunting down what's happening?
You generally should not use "shell" channel to automate a command execution. Use "exec" channel instead. See Execute a list of commands from an ArrayList using JSch exec in Java. If you use "shell" channel, you get into troubles sooner or later.
JSch example execution. Privileged access to your Linux system as root or via the sudo command. With the help of JSch, we’ll develop an application that will attempt to log in to localhost via ssh, using the username test and password test.
The same functionality is provided by JSch if you open the channel in command mode: This way you don’t need to handle closing the session with the exit shell command.
JSch is a project that implements the ssh protocol in Java. With it's help, you can build applications that are capable to connect to and interact with a remote or local SSH Server.
One has to read the output continuously, while waiting for the command to finish. Otherwise, if the command produces enough output to fill in an output buffer, the command will hang, waiting for the buffer to be consumed, what never happens. So you get a deadlock.
The following example reads both stdout and stderr continuously, while monitoring a command status. It is based on the official JSch exec.java
example (just adds a reading of stderr).
ChannelExec channel = (ChannelExec)session.openChannel("exec");
channel.setCommand(
"for((i=1;i<=10000;i+=2)); do echo \"Long output - $i\"; done ; " +
"echo error output >&2");
ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream();
ByteArrayOutputStream errorBuffer = new ByteArrayOutputStream();
InputStream in = channel.getInputStream();
InputStream err = channel.getExtInputStream();
channel.connect();
byte[] tmp = new byte[1024];
while (true) {
while (in.available() > 0) {
int i = in.read(tmp, 0, 1024);
if (i < 0) break;
outputBuffer.write(tmp, 0, i);
}
while (err.available() > 0) {
int i = err.read(tmp, 0, 1024);
if (i < 0) break;
errorBuffer.write(tmp, 0, i);
}
if (channel.isClosed()) {
if ((in.available() > 0) || (err.available() > 0)) continue;
System.out.println("exit-status: " + channel.getExitStatus());
break;
}
try {
Thread.sleep(1000);
} catch (Exception ee) {
}
}
System.out.println("output: " + outputBuffer.toString("UTF-8"));
System.out.println("error: " + errorBuffer.toString("UTF-8"));
channel.disconnect();
If you add while (!channel.isClosed()) {}
after the channel.connect();
, you will see that with a sufficiently large i
in the shell for
loop (10000 is enough with in my environment), the loop never finishes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With