title: JSch ChannelSftp exit status is always -1
body: <p>I use the JSch library to develop a SFTP client.</p>
  
  <p>The problem is both <code>get</code> and <code>put</code> methods' status is -1.</p>
  
  <p>Here is my code:</p>
  
  <pre><code>class SftpClient {
      private static final Logger LOG = Logger.getLogger(SftpClient.class);
  
      /** Connection port number */
      public static final int PORT = 22;
  
      /** SECURED protocol name */
      private static final String PROTOCOL = "sftp";
  
      /** Connection time out in milliseconds */
      public static final int TIME_OUT = 5000;
  
      /** This class serves as a central configuration point, and as a factory for Session objects configured with these settings */
      private JSch _client;
      /** A session represents a connection to a SSH server */
      private Session _session;
      /** Channel connected to a SECURED server (as a subsystem of the SSH server) */
      private ChannelSftp _channelSftp;
  
      /**
       * Value returned by the last executed command.
       */
      private int _exitValue;
  
      /**
       * Computer contains the url, the login and the password to connect.
       */
      private Computer _computer;
  
      /**
       * Initialize a SECURED client
       * @param target - Machine we want to connect to
       */
      public SftpClient(Computer target) {
          _client = new JSch();
          _computer = target;
      }
  
      protected void connect() throws Exception {
          try {
              if (_client == null) {
                  _client = new JSch();
              }
              if (_session == null) {
                  _session = _client.getSession(_computer.getLogin(), _computer.getUrl(), PORT);
                  Properties props = new Properties();
                  props.put("StrictHostKeyChecking", "no");
                  props.put("compression.s2c", "zlib,none");
                  props.put("compression.c2s", "zlib,none");
                  _session.setConfig(props);
                  _session.setPassword(_computer.getPassword());
                  if (LOG.isDebugEnabled()) {
                      LOG.debug("Connecting to "+_computer.getUrl()+" with login "+_computer.getLogin()+"...");
                  }
              }
              if (!_session.isConnected()) {
                  _session.connect(TIME_OUT);
              }
              // disconnect previous channel if it has not been killed properly
              if (_channelSftp != null &amp;&amp; _channelSftp.isConnected()) {
                  _channelSftp.disconnect();
              }
              _channelSftp = (ChannelSftp) _session.openChannel(PROTOCOL);
              _channelSftp.connect();
              if (LOG.isInfoEnabled()) {
                  LOG.info("Connected to "+_computer.getUrl()+" with login "+_computer.getLogin());
              }
          } catch(JSchException e) {
              LOG.error("Auth failed", e);
              throw e;
          }
      }
  
      protected void connect(String path) throws Exception {
          connect();
          if (_channelSftp != null &amp;&amp; _channelSftp.isConnected()) {
              _channelSftp.cd(path);
          }
      }
  
      public boolean get(final String remoteDirectory, final String remoteFile, final String localDirectory) throws Exception {
          boolean res = false;
          if (LOG.isInfoEnabled()) {
              LOG.info("Download file "+remoteDirectory+"/"+remoteFile+" from "+_computer+" in "+localDirectory);
          }
          if (remoteDirectory != null &amp;&amp; remoteFile != null &amp;&amp; !remoteFile.isEmpty() &amp;&amp; localDirectory != null) {
              try {
                  // connect to the server and change directory
                  connect(remoteDirectory);
                  // change local directory
                  _channelSftp.lcd(localDirectory);
                  // download the file, keeping the same name
                  _channelSftp.get(remoteFile, remoteFile);
                  // update exit value
                  _exitValue = _channelSftp.getExitStatus();
  
                  if (_exitValue == 0) {
                      res = true;
                  }
                  if (LOG.isDebugEnabled()) {
                      LOG.debug("Exit status is: "+_exitValue);
                  }
              } catch(SftpException e){
                  LOG.error("Auth failed", e);
                  throw e;
              } finally {
                  if (_channelSftp != null &amp;&amp; _channelSftp.isConnected()) {
                      _channelSftp.disconnect();
                      _channelSftp.exit();
                  }
              }
          } else {
              LOG.warn("Check remoteDirectory ('"+remoteDirectory+"') or remoteFile ('"+remoteFile+"') or localDirectory ('"+localDirectory+"').");
          }
          return res;
      }
  
      public void put(final File localFile, final String destPath) throws Exception {
          if (LOG.isInfoEnabled()) {
              LOG.info("Send file "+localFile+" to "+_computer+" in "+destPath);
          }
          if (localFile == null) {
              _exitValue = -1;
              LOG.error("The given local file is null. Aborting tranfer.");
              return;
          }
          if (!localFile.exists()) {
              _exitValue = -1;
              LOG.error("The given local file '"+localFile+"' does not exist. Aborting tranfer.");
              return;
          }
          final InputStream input = new FileInputStream(localFile);
          if (input == null || input.available() &lt;= 0) {
              _exitValue = -1;
              LOG.error("Cannot read file "+localFile);
              return;
          }
          try {
              connect(destPath);
              _channelSftp.put(input, localFile.getName());
              _exitValue = _channelSftp.getExitStatus();
              if (LOG.isDebugEnabled()) {
                  LOG.debug("Exit status is: "+_exitValue);
              }
          } catch(SftpException e){
              LOG.error("Auth failed", e);
              throw e;
          } finally {
              if (_channelSftp != null &amp;&amp; _channelSftp.isConnected()) {
                  _channelSftp.disconnect();
                  _channelSftp.exit();
              }
              IOUtils.closeQuietly(input);
          }
      }
  
      public void disconnect() {
          if (_channelSftp != null &amp;&amp; _channelSftp.isConnected()) {
              _channelSftp.disconnect();
              _channelSftp.exit();
          }
          if (_session != null &amp;&amp; _session.isConnected()) {
              _session.disconnect();
              if (LOG.isInfoEnabled()) {
                  LOG.info("SECURED FTP disconnected");
              }
          }
      }
  }
  </code></pre>
  
  <p>No exception is thrown.</p>
  
  <p>By the way, the files I want to upload and download are tar files. Does Jsch have a FTP binary mode?</p>
  
  <p>Files are well transferred. I can use them properly but I am worried about the exit status.</p>
  
  <p>I had a look to the <a href="http://epaul.github.com/jsch-documentation/javadoc/com/jcraft/jsch/Channel.html#getExitStatus%28%29" rel="nofollow">Jsch API</a> and it says:</p>
  
  <p><em><code>The exit status is only available for certain types of channels, and only after the channel was closed (more exactly, just before the channel is closed).</code></em></p>
  
  <p>How can I know if the exit status is available for <code>ChannelSftp</code>?</p>