0

I am trying to execute some shell commands using JSch on a remote machine. However, when that command runs and returns quickly (like ls, my method returns, but when the command takes a while to run, and produces a lot of output (like service myservice stop; service myservice start, where service is the name of some of the services i need to restart), my method gets stuck in the outer while(true) loop, and I can't figure out why.

EDIT Turns out, it is not the time of the execution of the remote command, it is something else. I tried this method with a python script on the other end that just writes garbage for 10 minutes, and that returns normally.

Here is the code:

    private String execCommand(String command) throws JSchException, IOException {
        Channel channel = session.openChannel("exec");
        ((ChannelExec) channel).setCommand(command);
        channel.setInputStream(null);
        ((ChannelExec) channel).setErrStream(System.err);
        InputStream in = channel.getInputStream();
        channel.connect();
        byte[] tmp = new byte[1024];
        while (true) {
            while (in.available() > 0) {
                int i = in.read(tmp, 0, 1024);
                if (i < 0)
                    break;
                System.out.print(new String(tmp, 0, i));
            }
            if (channel.isClosed()) {
                System.out.println("exit-status: " + channel.getExitStatus());
                break;
            }
            try {
                Thread.sleep(1000);
            } catch (Exception ee) {
            }
        }
        channel.disconnect();
        return new String(tmp,Charset.forName("UTF-8"));
    }

I also tried using the .isEOF() to check whether the remote output has finished, but that doesn't work either.

My current thought is to use some sentinel, e.g. the MD5 of the command to run to determine that the remote end is done (that is, running the command + "; echo \"" + md5(command) + "\"", but that doesn't feel right.

Can anyone help me, please?

Ibolit
  • 9,218
  • 7
  • 52
  • 96
  • I always used separated thread for reading of output and error streams with JSch. Your code has no chance to get to if (channel.isClosed()) in case of timeout. – JosefN Dec 20 '13 at 06:11
  • I thought of that, and that will be my next step. But currently it seems there is nothing written into the error stream, because it is redirected to the System.err, and there was nothing there... – Ibolit Dec 20 '13 at 06:28
  • it is exactly the issue, when connection is broken nothing goes to error stream and output stream and your code waits forever :) – JosefN Dec 20 '13 at 06:31
  • But how do i do that? I added the "InputStream stderr = ((ChannelExec) channel).getErrStream();" and then I check whether there is anything available in it after each "while (in.available().." loop, but it is always empty. – Ibolit Dec 20 '13 at 17:53
  • 1
    @lbolit sorry for delay, I do not have example with Jsch now but I can point you to examples in Ganymed-ssh2. Please see http://code.google.com/p/ganymed-ssh-2/source/browse/trunk/examples/Basic.java . The stout is wrapped by the StreamGobler that consume stout in different thread and what is important, checks in different thread that channel is not closed. http://code.google.com/p/ganymed-ssh-2/source/browse/trunk/src/main/java/ch/ethz/ssh2/StreamGobbler.java I hope that it clarify the way how to solve your issue. Having said that I think that switch to Ganymed is actually a good idea :) – JosefN Dec 21 '13 at 08:43
  • See also [How to read JSch command output?](https://stackoverflow.com/q/6902386/850848) – Which shows how to *correctly* read both standard and error output simultaneously, to allow command to complete and to collect all output including the errors. – Martin Prikryl Nov 11 '20 at 16:24

1 Answers1

0

To all those who may follow my footsteps: I ended up using the Ganymed-SSH-2 library instead of JSch. The approach in that library seems more logical, and everything works. At least, I haven't come run into the problems I had with JSch.

OGHaza
  • 4,795
  • 7
  • 23
  • 29
Ibolit
  • 9,218
  • 7
  • 52
  • 96