Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read JSch command output?

Tags:

java

ssh

jsch

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?

like image 571
Noel Yap Avatar asked Aug 01 '11 17:08

Noel Yap


People also ask

Is it possible to execute a list of commands in jsch?

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.

How do I use jsch in Linux?

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.

Is it possible to open a jsch channel in command mode?

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.

What is jsjsch?

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.


1 Answers

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.

like image 130
Martin Prikryl Avatar answered Oct 02 '22 13:10

Martin Prikryl