[BACK]Return to sftp-int.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/Attic/sftp-int.c between version 1.46.2.3 and 1.47

version 1.46.2.3, 2003/04/03 22:35:17 version 1.47, 2002/06/23 09:30:14
Line 22 
Line 22 
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */   */
   
   /* XXX: globbed ls */
 /* XXX: recursive operations */  /* XXX: recursive operations */
   
 #include "includes.h"  #include "includes.h"
Line 49 
Line 50 
 /* Number of concurrent outstanding requests */  /* Number of concurrent outstanding requests */
 extern int num_requests;  extern int num_requests;
   
 /* This is set to 0 if the progressmeter is not desired. */  
 int showprogress = 1;  
   
 /* Seperators for interactive commands */  /* Seperators for interactive commands */
 #define WHITESPACE " \t\r\n"  #define WHITESPACE " \t\r\n"
   
Line 78 
Line 76 
 #define I_SHELL         20  #define I_SHELL         20
 #define I_SYMLINK       21  #define I_SYMLINK       21
 #define I_VERSION       22  #define I_VERSION       22
 #define I_PROGRESS      23  
   
 struct CMD {  struct CMD {
         const char *c;          const char *c;
         const int n;          const int n;
 };  };
   
 static const struct CMD cmds[] = {  const struct CMD cmds[] = {
         { "bye",        I_QUIT },          { "bye",        I_QUIT },
         { "cd",         I_CHDIR },          { "cd",         I_CHDIR },
         { "chdir",      I_CHDIR },          { "chdir",      I_CHDIR },
Line 106 
Line 103 
         { "ls",         I_LS },          { "ls",         I_LS },
         { "lumask",     I_LUMASK },          { "lumask",     I_LUMASK },
         { "mkdir",      I_MKDIR },          { "mkdir",      I_MKDIR },
         { "progress",   I_PROGRESS },  
         { "put",        I_PUT },          { "put",        I_PUT },
         { "mput",       I_PUT },          { "mput",       I_PUT },
         { "pwd",        I_PWD },          { "pwd",        I_PWD },
Line 139 
Line 135 
         printf("ls [path]                     Display remote directory listing\n");          printf("ls [path]                     Display remote directory listing\n");
         printf("lumask umask                  Set local umask to 'umask'\n");          printf("lumask umask                  Set local umask to 'umask'\n");
         printf("mkdir path                    Create remote directory\n");          printf("mkdir path                    Create remote directory\n");
         printf("progress                      Toggle display of progress meter\n");  
         printf("put local-path [remote-path]  Upload file\n");          printf("put local-path [remote-path]  Upload file\n");
         printf("pwd                           Display remote working directory\n");          printf("pwd                           Display remote working directory\n");
         printf("exit                          Quit sftp\n");          printf("exit                          Quit sftp\n");
Line 208 
Line 203 
         }          }
 }  }
   
 /* Strip one path (usually the pwd) from the start of another */  
 static char *  static char *
 path_strip(char *path, char *strip)  
 {  
         size_t len;  
   
         if (strip == NULL)  
                 return (xstrdup(path));  
   
         len = strlen(strip);  
         if (strip != NULL && strncmp(path, strip, len) == 0) {  
                 if (strip[len - 1] != '/' && path[len] == '/')  
                         len++;  
                 return (xstrdup(path + len));  
         }  
   
         return (xstrdup(path));  
 }  
   
 static char *  
 path_append(char *p1, char *p2)  path_append(char *p1, char *p2)
 {  {
         char *ret;          char *ret;
Line 235 
Line 211 
   
         ret = xmalloc(len);          ret = xmalloc(len);
         strlcpy(ret, p1, len);          strlcpy(ret, p1, len);
         if (p1[strlen(p1) - 1] != '/')          if (strcmp(p1, "/") != 0)
                 strlcat(ret, "/", len);                  strlcat(ret, "/", len);
         strlcat(ret, p2, len);          strlcat(ret, p2, len);
   
Line 300 
Line 276 
 }  }
   
 static int  static int
 parse_ls_flags(const char **cpp, int *lflag)  
 {  
         const char *cp = *cpp;  
   
         /* Check for flags */  
         if (cp++[0] == '-') {  
                 for(; strchr(WHITESPACE, *cp) == NULL; cp++) {  
                         switch (*cp) {  
                         case 'l':  
                                 *lflag = 1;  
                                 break;  
                         default:  
                                 error("Invalid flag -%c", *cp);  
                                 return(-1);  
                         }  
                 }  
                 *cpp = cp + strspn(cp, WHITESPACE);  
         }  
   
         return(0);  
 }  
   
 static int  
 get_pathname(const char **cpp, char **path)  get_pathname(const char **cpp, char **path)
 {  {
         const char *cp = *cpp, *end;          const char *cp = *cpp, *end;
Line 383 
Line 336 
 }  }
   
 static int  static int
 is_reg(char *path)  
 {  
         struct stat sb;  
   
         if (stat(path, &sb) == -1)  
                 fatal("stat %s: %s", path, strerror(errno));  
   
         return(S_ISREG(sb.st_mode));  
 }  
   
 static int  
 remote_is_dir(struct sftp_conn *conn, char *path)  remote_is_dir(struct sftp_conn *conn, char *path)
 {  {
         Attrib *a;          Attrib *a;
Line 444 
Line 386 
                         err = -1;                          err = -1;
                         goto out;                          goto out;
                 }                  }
                   printf("Fetching %s to %s\n", g.gl_pathv[0], abs_dst);
                 err = do_download(conn, g.gl_pathv[0], abs_dst, pflag);                  err = do_download(conn, g.gl_pathv[0], abs_dst, pflag);
                 goto out;                  goto out;
         }          }
Line 507 
Line 450 
   
         /* Only one match, dst may be file, directory or unspecified */          /* Only one match, dst may be file, directory or unspecified */
         if (g.gl_pathv[0] && g.gl_matchc == 1) {          if (g.gl_pathv[0] && g.gl_matchc == 1) {
                 if (!is_reg(g.gl_pathv[0])) {  
                         error("Can't upload %s: not a regular file",  
                             g.gl_pathv[0]);  
                         err = 1;  
                         goto out;  
                 }  
                 if (tmp_dst) {                  if (tmp_dst) {
                         /* If directory specified, append filename */                          /* If directory specified, append filename */
                         if (remote_is_dir(conn, tmp_dst)) {                          if (remote_is_dir(conn, tmp_dst)) {
Line 531 
Line 468 
                         }                          }
                         abs_dst = make_absolute(abs_dst, pwd);                          abs_dst = make_absolute(abs_dst, pwd);
                 }                  }
                   printf("Uploading %s to %s\n", g.gl_pathv[0], abs_dst);
                 err = do_upload(conn, g.gl_pathv[0], abs_dst, pflag);                  err = do_upload(conn, g.gl_pathv[0], abs_dst, pflag);
                 goto out;                  goto out;
         }          }
Line 544 
Line 482 
         }          }
   
         for (i = 0; g.gl_pathv[i]; i++) {          for (i = 0; g.gl_pathv[i]; i++) {
                 if (!is_reg(g.gl_pathv[i])) {  
                         error("skipping non-regular file %s",  
                             g.gl_pathv[i]);  
                         continue;  
                 }  
                 if (infer_path(g.gl_pathv[i], &tmp)) {                  if (infer_path(g.gl_pathv[i], &tmp)) {
                         err = -1;                          err = -1;
                         goto out;                          goto out;
Line 573 
Line 506 
 }  }
   
 static int  static int
 sdirent_comp(const void *aa, const void *bb)  parse_args(const char **cpp, int *pflag, unsigned long *n_arg,
       char **path1, char **path2)
 {  {
         SFTP_DIRENT *a = *(SFTP_DIRENT **)aa;  
         SFTP_DIRENT *b = *(SFTP_DIRENT **)bb;  
   
         return (strcmp(a->filename, b->filename));  
 }  
   
 /* sftp ls.1 replacement for directories */  
 static int  
 do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag)  
 {  
         int n;  
         SFTP_DIRENT **d;  
   
         if ((n = do_readdir(conn, path, &d)) != 0)  
                 return (n);  
   
         /* Count entries for sort */  
         for (n = 0; d[n] != NULL; n++)  
                 ;  
   
         qsort(d, n, sizeof(*d), sdirent_comp);  
   
         for (n = 0; d[n] != NULL; n++) {  
                 char *tmp, *fname;  
   
                 tmp = path_append(path, d[n]->filename);  
                 fname = path_strip(tmp, strip_path);  
                 xfree(tmp);  
   
                 if (lflag) {  
                         char *lname;  
                         struct stat sb;  
   
                         memset(&sb, 0, sizeof(sb));  
                         attrib_to_stat(&d[n]->a, &sb);  
                         lname = ls_file(fname, &sb, 1);  
                         printf("%s\n", lname);  
                         xfree(lname);  
                 } else {  
                         /* XXX - multicolumn display would be nice here */  
                         printf("%s\n", fname);  
                 }  
   
                 xfree(fname);  
         }  
   
         free_sftp_dirents(d);  
         return (0);  
 }  
   
 /* sftp ls.1 replacement which handles path globs */  
 static int  
 do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,  
     int lflag)  
 {  
         glob_t g;  
         int i;  
         Attrib *a;  
         struct stat sb;  
   
         memset(&g, 0, sizeof(g));  
   
         if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE,  
             NULL, &g)) {  
                 error("Can't ls: \"%s\" not found", path);  
                 return (-1);  
         }  
   
         /*  
          * If the glob returns a single match, which is the same as the  
          * input glob, and it is a directory, then just list its contents  
          */  
         if (g.gl_pathc == 1 &&  
             strncmp(path, g.gl_pathv[0], strlen(g.gl_pathv[0]) - 1) == 0) {  
                 if ((a = do_lstat(conn, path, 1)) == NULL) {  
                         globfree(&g);  
                         return (-1);  
                 }  
                 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&  
                     S_ISDIR(a->perm)) {  
                         globfree(&g);  
                         return (do_ls_dir(conn, path, strip_path, lflag));  
                 }  
         }  
   
         for (i = 0; g.gl_pathv[i]; i++) {  
                 char *fname, *lname;  
   
                 fname = path_strip(g.gl_pathv[i], strip_path);  
   
                 if (lflag) {  
                         /*  
                          * XXX: this is slow - 1 roundtrip per path  
                          * A solution to this is to fork glob() and  
                          * build a sftp specific version which keeps the  
                          * attribs (which currently get thrown away)  
                          * that the server returns as well as the filenames.  
                          */  
                         memset(&sb, 0, sizeof(sb));  
                         a = do_lstat(conn, g.gl_pathv[i], 1);  
                         if (a != NULL)  
                                 attrib_to_stat(a, &sb);  
                         lname = ls_file(fname, &sb, 1);  
                         printf("%s\n", lname);  
                         xfree(lname);  
                 } else {  
                         /* XXX - multicolumn display would be nice here */  
                         printf("%s\n", fname);  
                 }  
                 xfree(fname);  
         }  
   
         if (g.gl_pathc)  
                 globfree(&g);  
   
         return (0);  
 }  
   
 static int  
 parse_args(const char **cpp, int *pflag, int *lflag, int *iflag,  
     unsigned long *n_arg, char **path1, char **path2)  
 {  
         const char *cmd, *cp = *cpp;          const char *cmd, *cp = *cpp;
         char *cp2;          char *cp2;
         int base = 0;          int base = 0;
Line 706 
Line 518 
         /* Skip leading whitespace */          /* Skip leading whitespace */
         cp = cp + strspn(cp, WHITESPACE);          cp = cp + strspn(cp, WHITESPACE);
   
         /* Ignore blank lines and lines which begin with comment '#' char */          /* Ignore blank lines */
         if (*cp == '\0' || *cp == '#')          if (!*cp)
                 return (0);                  return(-1);
   
         /* Check for leading '-' (disable error processing) */  
         *iflag = 0;  
         if (*cp == '-') {  
                 *iflag = 1;  
                 cp++;  
         }  
   
         /* Figure out which command we have */          /* Figure out which command we have */
         for (i = 0; cmds[i].c; i++) {          for (i = 0; cmds[i].c; i++) {
                 int cmdlen = strlen(cmds[i].c);                  int cmdlen = strlen(cmds[i].c);
Line 738 
Line 543 
                 cmdnum = I_SHELL;                  cmdnum = I_SHELL;
         } else if (cmdnum == -1) {          } else if (cmdnum == -1) {
                 error("Invalid command.");                  error("Invalid command.");
                 return (-1);                  return(-1);
         }          }
   
         /* Get arguments and parse flags */          /* Get arguments and parse flags */
         *lflag = *pflag = *n_arg = 0;          *pflag = *n_arg = 0;
         *path1 = *path2 = NULL;          *path1 = *path2 = NULL;
         switch (cmdnum) {          switch (cmdnum) {
         case I_GET:          case I_GET:
Line 789 
Line 594 
                 }                  }
                 break;                  break;
         case I_LS:          case I_LS:
                 if (parse_ls_flags(&cp, lflag))  
                         return(-1);  
                 /* Path is optional */                  /* Path is optional */
                 if (get_pathname(&cp, path1))                  if (get_pathname(&cp, path1))
                         return(-1);                          return(-1);
Line 838 
Line 641 
         case I_LPWD:          case I_LPWD:
         case I_HELP:          case I_HELP:
         case I_VERSION:          case I_VERSION:
         case I_PROGRESS:  
                 break;                  break;
         default:          default:
                 fatal("Command not implemented");                  fatal("Command not implemented");
Line 849 
Line 651 
 }  }
   
 static int  static int
 parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,  parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd)
     int err_abort)  
 {  {
         char *path1, *path2, *tmp;          char *path1, *path2, *tmp;
         int pflag, lflag, iflag, cmdnum, i;          int pflag, cmdnum, i;
         unsigned long n_arg;          unsigned long n_arg;
         Attrib a, *aa;          Attrib a, *aa;
         char path_buf[MAXPATHLEN];          char path_buf[MAXPATHLEN];
Line 861 
Line 662 
         glob_t g;          glob_t g;
   
         path1 = path2 = NULL;          path1 = path2 = NULL;
         cmdnum = parse_args(&cmd, &pflag, &lflag, &iflag, &n_arg,          cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2);
             &path1, &path2);  
   
         if (iflag != 0)  
                 err_abort = 0;  
   
         memset(&g, 0, sizeof(g));          memset(&g, 0, sizeof(g));
   
         /* Perform command */          /* Perform command */
         switch (cmdnum) {          switch (cmdnum) {
         case 0:  
                 /* Blank line */  
                 break;  
         case -1:          case -1:
                 /* Unrecognized command */  
                 err = -1;  
                 break;                  break;
         case I_GET:          case I_GET:
                 err = process_get(conn, path1, path2, *pwd, pflag);                  err = process_get(conn, path1, path2, *pwd, pflag);
Line 898 
Line 690 
                 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);                  remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
                 for (i = 0; g.gl_pathv[i]; i++) {                  for (i = 0; g.gl_pathv[i]; i++) {
                         printf("Removing %s\n", g.gl_pathv[i]);                          printf("Removing %s\n", g.gl_pathv[i]);
                         err = do_rm(conn, g.gl_pathv[i]);                          if (do_rm(conn, g.gl_pathv[i]) == -1)
                         if (err != 0 && err_abort)                                  err = -1;
                                 break;  
                 }                  }
                 break;                  break;
         case I_MKDIR:          case I_MKDIR:
Line 943 
Line 734 
                 break;                  break;
         case I_LS:          case I_LS:
                 if (!path1) {                  if (!path1) {
                         do_globbed_ls(conn, *pwd, *pwd, lflag);                          do_ls(conn, *pwd);
                         break;                          break;
                 }                  }
   
                 /* Strip pwd off beginning of non-absolute paths */  
                 tmp = NULL;  
                 if (*path1 != '/')  
                         tmp = *pwd;  
   
                 path1 = make_absolute(path1, *pwd);                  path1 = make_absolute(path1, *pwd);
                 err = do_globbed_ls(conn, path1, tmp, lflag);                  if ((tmp = do_realpath(conn, path1)) == NULL)
                           break;
                   xfree(path1);
                   path1 = tmp;
                   if ((aa = do_stat(conn, path1, 0)) == NULL)
                           break;
                   if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
                       !S_ISDIR(aa->perm)) {
                           error("Can't ls: \"%s\" is not a directory", path1);
                           break;
                   }
                   do_ls(conn, path1);
                 break;                  break;
         case I_LCHDIR:          case I_LCHDIR:
                 if (chdir(path1) == -1) {                  if (chdir(path1) == -1) {
Line 987 
Line 783 
                 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);                  remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
                 for (i = 0; g.gl_pathv[i]; i++) {                  for (i = 0; g.gl_pathv[i]; i++) {
                         printf("Changing mode on %s\n", g.gl_pathv[i]);                          printf("Changing mode on %s\n", g.gl_pathv[i]);
                         err = do_setstat(conn, g.gl_pathv[i], &a);                          do_setstat(conn, g.gl_pathv[i], &a);
                         if (err != 0 && err_abort)  
                                 break;  
                 }                  }
                 break;                  break;
         case I_CHOWN:          case I_CHOWN:
         case I_CHGRP:  
                 path1 = make_absolute(path1, *pwd);                  path1 = make_absolute(path1, *pwd);
                 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);                  remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
                 for (i = 0; g.gl_pathv[i]; i++) {                  for (i = 0; g.gl_pathv[i]; i++) {
                         if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) {                          if (!(aa = do_stat(conn, g.gl_pathv[i], 0)))
                                 if (err != 0 && err_abort)                                  continue;
                                         break;  
                                 else  
                                         continue;  
                         }  
                         if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {                          if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
                                 error("Can't get current ownership of "                                  error("Can't get current ownership of "
                                     "remote file \"%s\"", g.gl_pathv[i]);                                      "remote file \"%s\"", g.gl_pathv[i]);
                                 if (err != 0 && err_abort)                                  continue;
                                         break;  
                                 else  
                                         continue;  
                         }                          }
                           printf("Changing owner on %s\n", g.gl_pathv[i]);
                         aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;                          aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
                         if (cmdnum == I_CHOWN) {                          aa->uid = n_arg;
                                 printf("Changing owner on %s\n", g.gl_pathv[i]);                          do_setstat(conn, g.gl_pathv[i], aa);
                                 aa->uid = n_arg;                  }
                         } else {                  break;
                                 printf("Changing group on %s\n", g.gl_pathv[i]);          case I_CHGRP:
                                 aa->gid = n_arg;                  path1 = make_absolute(path1, *pwd);
                   remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
                   for (i = 0; g.gl_pathv[i]; i++) {
                           if (!(aa = do_stat(conn, g.gl_pathv[i], 0)))
                                   continue;
                           if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
                                   error("Can't get current ownership of "
                                       "remote file \"%s\"", g.gl_pathv[i]);
                                   continue;
                         }                          }
                         err = do_setstat(conn, g.gl_pathv[i], aa);                          printf("Changing group on %s\n", g.gl_pathv[i]);
                         if (err != 0 && err_abort)                          aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
                                 break;                          aa->gid = n_arg;
                           do_setstat(conn, g.gl_pathv[i], aa);
                 }                  }
                 break;                  break;
         case I_PWD:          case I_PWD:
                 printf("Remote working directory: %s\n", *pwd);                  printf("Remote working directory: %s\n", *pwd);
                 break;                  break;
         case I_LPWD:          case I_LPWD:
                 if (!getcwd(path_buf, sizeof(path_buf))) {                  if (!getcwd(path_buf, sizeof(path_buf)))
                         error("Couldn't get local cwd: %s", strerror(errno));                          error("Couldn't get local cwd: %s",
                         err = -1;                              strerror(errno));
                         break;                  else
                 }                          printf("Local working directory: %s\n",
                 printf("Local working directory: %s\n", path_buf);                              path_buf);
                 break;                  break;
         case I_QUIT:          case I_QUIT:
                 /* Processed below */                  return(-1);
                 break;  
         case I_HELP:          case I_HELP:
                 help();                  help();
                 break;                  break;
         case I_VERSION:          case I_VERSION:
                 printf("SFTP protocol version %u\n", sftp_proto_version(conn));                  printf("SFTP protocol version %u\n", sftp_proto_version(conn));
                 break;                  break;
         case I_PROGRESS:  
                 showprogress = !showprogress;  
                 if (showprogress)  
                         printf("Progress meter enabled\n");  
                 else  
                         printf("Progress meter disabled\n");  
                 break;  
         default:          default:
                 fatal("%d is not implemented", cmdnum);                  fatal("%d is not implemented", cmdnum);
         }          }
Line 1062 
Line 850 
         if (path2)          if (path2)
                 xfree(path2);                  xfree(path2);
   
         /* If an unignored error occurs in batch mode we should abort. */          /* If an error occurs in batch mode we should abort. */
         if (err_abort && err != 0)          if (infile != stdin && err > 0)
                 return (-1);                  return -1;
         else if (cmdnum == I_QUIT)  
                 return (1);  
   
         return (0);          return(0);
 }  }
   
 int  void
 interactive_loop(int fd_in, int fd_out, char *file1, char *file2)  interactive_loop(int fd_in, int fd_out, char *file1, char *file2)
 {  {
         char *pwd;          char *pwd;
         char *dir = NULL;          char *dir = NULL;
         char cmd[2048];          char cmd[2048];
         struct sftp_conn *conn;          struct sftp_conn *conn;
         int err;  
   
         conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests);          conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests);
         if (conn == NULL)          if (conn == NULL)
Line 1095 
Line 880 
                 if (remote_is_dir(conn, dir) && file2 == NULL) {                  if (remote_is_dir(conn, dir) && file2 == NULL) {
                         printf("Changing to: %s\n", dir);                          printf("Changing to: %s\n", dir);
                         snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);                          snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
                         if (parse_dispatch_command(conn, cmd, &pwd, 1) != 0)                          parse_dispatch_command(conn, cmd, &pwd);
                                 return (-1);  
                 } else {                  } else {
                         if (file2 == NULL)                          if (file2 == NULL)
                                 snprintf(cmd, sizeof cmd, "get %s", dir);                                  snprintf(cmd, sizeof cmd, "get %s", dir);
Line 1104 
Line 888 
                                 snprintf(cmd, sizeof cmd, "get %s %s", dir,                                  snprintf(cmd, sizeof cmd, "get %s %s", dir,
                                     file2);                                      file2);
   
                         err = parse_dispatch_command(conn, cmd, &pwd, 1);                          parse_dispatch_command(conn, cmd, &pwd);
                         xfree(dir);                          xfree(dir);
                         xfree(pwd);                          return;
                         return (err);  
                 }                  }
                 xfree(dir);                  xfree(dir);
         }          }
   
         setvbuf(stdout, NULL, _IOLBF, 0);          setvbuf(stdout, NULL, _IOLBF, 0);
         setvbuf(infile, NULL, _IOLBF, 0);          setvbuf(infile, NULL, _IOLBF, 0);
   
         err = 0;  
         for (;;) {          for (;;) {
                 char *cp;                  char *cp;
   
Line 1132 
Line 913 
                 if (cp)                  if (cp)
                         *cp = '\0';                          *cp = '\0';
   
                 err = parse_dispatch_command(conn, cmd, &pwd, infile != stdin);                  if (parse_dispatch_command(conn, cmd, &pwd))
                 if (err != 0)  
                         break;                          break;
         }          }
         xfree(pwd);          xfree(pwd);
   
         /* err == 1 signifies normal "quit" exit */  
         return (err >= 0 ? 0 : -1);  
 }  }
   

Legend:
Removed from v.1.46.2.3  
changed lines
  Added in v.1.47