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

Diff for /src/usr.bin/ssh/scp.c between version 1.88 and 1.88.2.2

version 1.88, 2002/04/06 18:24:09 version 1.88.2.2, 2003/04/03 22:35:17
Line 82 
Line 82 
 #include "pathnames.h"  #include "pathnames.h"
 #include "log.h"  #include "log.h"
 #include "misc.h"  #include "misc.h"
   #include "progressmeter.h"
   
 /* For progressmeter() -- number of seconds before xfer considered "stalled" */  
 #define STALLTIME       5  
 /* alarm() interval for updating progress meter */  
 #define PROGRESSTIME    1  
   
 /* Visual statistics about files as they are transferred. */  
 void progressmeter(int);  
   
 /* Returns width of the terminal (for progress meter calculations). */  
 int getttywidth(void);  
 int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc);  int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc);
   
   void bwlimit(int);
   
 /* Struct for addargs */  /* Struct for addargs */
 arglist args;  arglist args;
   
 /* Time a transfer started. */  /* Bandwidth limit */
 static struct timeval start;  off_t limit = 0;
   
 /* Number of bytes of current file transferred so far. */  
 volatile off_t statbytes;  
   
 /* Total size of current file. */  
 off_t totalbytes = 0;  
   
 /* Name of current file being transferred. */  /* Name of current file being transferred. */
 char *curfile;  char *curfile;
   
Line 119 
Line 106 
 /* This is the program to execute for the secured connection. ("ssh" or -S) */  /* This is the program to execute for the secured connection. ("ssh" or -S) */
 char *ssh_program = _PATH_SSH_PROGRAM;  char *ssh_program = _PATH_SSH_PROGRAM;
   
   /* This is used to store the pid of ssh_program */
   pid_t do_cmd_pid;
   
 /*  /*
  * This function executes the given command as the specified user on the   * This function executes the given command as the specified user on the
  * given host.  This returns < 0 if execution fails, and >= 0 otherwise. This   * given host.  This returns < 0 if execution fails, and >= 0 otherwise. This
Line 153 
Line 143 
         close(reserved[1]);          close(reserved[1]);
   
         /* For a child to execute the command on the remote host using ssh. */          /* For a child to execute the command on the remote host using ssh. */
         if (fork() == 0)  {          do_cmd_pid = fork();
           if (do_cmd_pid == 0) {
                 /* Child. */                  /* Child. */
                 close(pin[1]);                  close(pin[1]);
                 close(pout[0]);                  close(pout[0]);
Line 171 
Line 162 
                 execvp(ssh_program, args.list);                  execvp(ssh_program, args.list);
                 perror(ssh_program);                  perror(ssh_program);
                 exit(1);                  exit(1);
           } else if (do_cmd_pid == -1) {
                   fatal("fork: %s", strerror(errno));
         }          }
         /* Parent.  Close the other side, and return the local side. */          /* Parent.  Close the other side, and return the local side. */
         close(pin[0]);          close(pin[0]);
Line 213 
Line 206 
         int argc;          int argc;
         char *argv[];          char *argv[];
 {  {
         int ch, fflag, tflag;          int ch, fflag, tflag, status;
         char *targ;          double speed;
           char *targ, *endp;
         extern char *optarg;          extern char *optarg;
         extern int optind;          extern int optind;
   
         args.list = NULL;          args.list = NULL;
         addargs(&args, "ssh");          /* overwritten with ssh_program */          addargs(&args, "ssh");          /* overwritten with ssh_program */
         addargs(&args, "-x");          addargs(&args, "-x");
         addargs(&args, "-oForwardAgent no");          addargs(&args, "-oForwardAgent no");
         addargs(&args, "-oFallBackToRsh no");  
         addargs(&args, "-oClearAllForwardings yes");          addargs(&args, "-oClearAllForwardings yes");
   
         fflag = tflag = 0;          fflag = tflag = 0;
         while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:F:")) != -1)          while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q1246S:o:F:")) != -1)
                 switch (ch) {                  switch (ch) {
                 /* User-visible flags. */                  /* User-visible flags. */
                   case '1':
                   case '2':
                 case '4':                  case '4':
                 case '6':                  case '6':
                 case 'C':                  case 'C':
Line 246 
Line 241 
                 case 'B':                  case 'B':
                         addargs(&args, "-oBatchmode yes");                          addargs(&args, "-oBatchmode yes");
                         break;                          break;
                   case 'l':
                           speed = strtod(optarg, &endp);
                           if (speed <= 0 || *endp != '\0')
                                   usage();
                           limit = speed * 1024;
                           break;
                 case 'p':                  case 'p':
                         pflag = 1;                          pflag = 1;
                         break;                          break;
Line 307 
Line 308 
                 targetshouldbedirectory = 1;                  targetshouldbedirectory = 1;
   
         remin = remout = -1;          remin = remout = -1;
           do_cmd_pid = -1;
         /* Command to be executed on remote system using "ssh". */          /* Command to be executed on remote system using "ssh". */
         (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",          (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",
             verbose_mode ? " -v" : "",              verbose_mode ? " -v" : "",
Line 322 
Line 324 
                 if (targetshouldbedirectory)                  if (targetshouldbedirectory)
                         verifydir(argv[argc - 1]);                          verifydir(argv[argc - 1]);
         }          }
           /*
            * Finally check the exit status of the ssh process, if one was forked
            * and no error has occured yet
            */
           if (do_cmd_pid != -1 && errs == 0) {
                   if (remin != -1)
                       (void) close(remin);
                   if (remout != -1)
                       (void) close(remout);
                   if (waitpid(do_cmd_pid, &status, 0) == -1)
                           errs = 1;
                   else {
                           if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
                                   errs = 1;
                   }
           }
         exit(errs != 0);          exit(errs != 0);
 }  }
   
Line 337 
Line 355 
         if (*targ == 0)          if (*targ == 0)
                 targ = ".";                  targ = ".";
   
         if ((thost = strchr(argv[argc - 1], '@'))) {          if ((thost = strrchr(argv[argc - 1], '@'))) {
                 /* user@host */                  /* user@host */
                 *thost++ = 0;                  *thost++ = 0;
                 tuser = argv[argc - 1];                  tuser = argv[argc - 1];
                 if (*tuser == '\0')                  if (*tuser == '\0')
                         tuser = NULL;                          tuser = NULL;
                 else if (!okname(tuser))  
                         exit(1);  
         } else {          } else {
                 thost = argv[argc - 1];                  thost = argv[argc - 1];
                 tuser = NULL;                  tuser = NULL;
Line 354 
Line 370 
                 src = colon(argv[i]);                  src = colon(argv[i]);
                 if (src) {      /* remote to remote */                  if (src) {      /* remote to remote */
                         static char *ssh_options =                          static char *ssh_options =
                             "-x -o'FallBackToRsh no' "                              "-x -o'ClearAllForwardings yes'";
                             "-o'ClearAllForwardings yes'";  
                         *src++ = 0;                          *src++ = 0;
                         if (*src == 0)                          if (*src == 0)
                                 src = ".";                                  src = ".";
                         host = strchr(argv[i], '@');                          host = strrchr(argv[i], '@');
                         len = strlen(ssh_program) + strlen(argv[i]) +                          len = strlen(ssh_program) + strlen(argv[i]) +
                             strlen(src) + (tuser ? strlen(tuser) : 0) +                              strlen(src) + (tuser ? strlen(tuser) : 0) +
                             strlen(thost) + strlen(targ) +                              strlen(thost) + strlen(targ) +
Line 371 
Line 386 
                                 suser = argv[i];                                  suser = argv[i];
                                 if (*suser == '\0')                                  if (*suser == '\0')
                                         suser = pwd->pw_name;                                          suser = pwd->pw_name;
                                 else if (!okname(suser))                                  else if (!okname(suser)) {
                                           xfree(bp);
                                         continue;                                          continue;
                                   }
                                   if (tuser && !okname(tuser)) {
                                           xfree(bp);
                                           continue;
                                   }
                                 snprintf(bp, len,                                  snprintf(bp, len,
                                     "%s%s %s -n "                                      "%s%s %s -n "
                                     "-l %s %s %s %s '%s%s%s:%s'",                                      "-l %s %s %s %s '%s%s%s:%s'",
Line 438 
Line 459 
                 *src++ = 0;                  *src++ = 0;
                 if (*src == 0)                  if (*src == 0)
                         src = ".";                          src = ".";
                 if ((host = strchr(argv[i], '@')) == NULL) {                  if ((host = strrchr(argv[i], '@')) == NULL) {
                         host = argv[i];                          host = argv[i];
                         suser = NULL;                          suser = NULL;
                 } else {                  } else {
Line 446 
Line 467 
                         suser = argv[i];                          suser = argv[i];
                         if (*suser == '\0')                          if (*suser == '\0')
                                 suser = pwd->pw_name;                                  suser = pwd->pw_name;
                         else if (!okname(suser))  
                                 continue;  
                 }                  }
                 host = cleanhostname(host);                  host = cleanhostname(host);
                 len = strlen(src) + CMDNEEDS + 20;                  len = strlen(src) + CMDNEEDS + 20;
Line 473 
Line 492 
         struct stat stb;          struct stat stb;
         static BUF buffer;          static BUF buffer;
         BUF *bp;          BUF *bp;
         off_t i, amt, result;          off_t i, amt, result, statbytes;
         int fd, haderr, indx;          int fd, haderr, indx;
         char *last, *name, buf[2048];          char *last, *name, buf[2048];
         int len;          int len;
Line 531 
Line 550 
                     (long long)stb.st_size, last);                      (long long)stb.st_size, last);
                 if (verbose_mode) {                  if (verbose_mode) {
                         fprintf(stderr, "Sending file modes: %s", buf);                          fprintf(stderr, "Sending file modes: %s", buf);
                         fflush(stderr);  
                 }                  }
                 (void) atomicio(write, remout, buf, strlen(buf));                  (void) atomicio(write, remout, buf, strlen(buf));
                 if (response() < 0)                  if (response() < 0)
Line 540 
Line 558 
 next:                   (void) close(fd);  next:                   (void) close(fd);
                         continue;                          continue;
                 }                  }
                 if (showprogress) {                  if (showprogress)
                         totalbytes = stb.st_size;                          start_progress_meter(curfile, stb.st_size, &statbytes);
                         progressmeter(-1);  
                 }  
                 /* Keep writing after an error so that we stay sync'd up. */                  /* Keep writing after an error so that we stay sync'd up. */
                 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {                  for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
                         amt = bp->cnt;                          amt = bp->cnt;
Line 562 
Line 578 
                                         haderr = result >= 0 ? EIO : errno;                                          haderr = result >= 0 ? EIO : errno;
                                 statbytes += result;                                  statbytes += result;
                         }                          }
                           if (limit)
                                   bwlimit(amt);
                 }                  }
                 if (showprogress)                  if (showprogress)
                         progressmeter(1);                          stop_progress_meter();
   
                 if (close(fd) < 0 && !haderr)                  if (close(fd) < 0 && !haderr)
                         haderr = errno;                          haderr = errno;
Line 632 
Line 650 
 }  }
   
 void  void
   bwlimit(int amount)
   {
           static struct timeval bwstart, bwend;
           static int lamt, thresh = 16384;
           u_int64_t wait;
           struct timespec ts, rm;
   
           if (!timerisset(&bwstart)) {
                   gettimeofday(&bwstart, NULL);
                   return;
           }
   
           lamt += amount;
           if (lamt < thresh)
                   return;
   
           gettimeofday(&bwend, NULL);
           timersub(&bwend, &bwstart, &bwend);
           if (!timerisset(&bwend))
                   return;
   
           lamt *= 8;
           wait = (double)1000000L * lamt / limit;
   
           bwstart.tv_sec = wait / 1000000L;
           bwstart.tv_usec = wait % 1000000L;
   
           if (timercmp(&bwstart, &bwend, >)) {
                   timersub(&bwstart, &bwend, &bwend);
   
                   /* Adjust the wait time */
                   if (bwend.tv_sec) {
                           thresh /= 2;
                           if (thresh < 2048)
                                   thresh = 2048;
                   } else if (bwend.tv_usec < 100) {
                           thresh *= 2;
                           if (thresh > 32768)
                                   thresh = 32768;
                   }
   
                   TIMEVAL_TO_TIMESPEC(&bwend, &ts);
                   while (nanosleep(&ts, &rm) == -1) {
                           if (errno != EINTR)
                                   break;
                           ts = rm;
                   }
           }
   
           lamt = 0;
           gettimeofday(&bwstart, NULL);
   }
   
   void
 sink(argc, argv)  sink(argc, argv)
         int argc;          int argc;
         char *argv[];          char *argv[];
Line 644 
Line 716 
         BUF *bp;          BUF *bp;
         off_t i, j;          off_t i, j;
         int amt, count, exists, first, mask, mode, ofd, omode;          int amt, count, exists, first, mask, mode, ofd, omode;
         off_t size;          off_t size, statbytes;
         int setimes, targisdir, wrerrno = 0;          int setimes, targisdir, wrerrno = 0;
         char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];          char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
         struct timeval tv[2];          struct timeval tv[2];
Line 806 
Line 878 
                 cp = bp->buf;                  cp = bp->buf;
                 wrerr = NO;                  wrerr = NO;
   
                 if (showprogress) {  
                         totalbytes = size;  
                         progressmeter(-1);  
                 }  
                 statbytes = 0;                  statbytes = 0;
                   if (showprogress)
                           start_progress_meter(curfile, size, &statbytes);
                 for (count = i = 0; i < size; i += 4096) {                  for (count = i = 0; i < size; i += 4096) {
                         amt = 4096;                          amt = 4096;
                         if (i + amt > size)                          if (i + amt > size)
Line 830 
Line 900 
                                 cp += j;                                  cp += j;
                                 statbytes += j;                                  statbytes += j;
                         } while (amt > 0);                          } while (amt > 0);
   
                           if (limit)
                                   bwlimit(4096);
   
                         if (count == bp->cnt) {                          if (count == bp->cnt) {
                                 /* Keep reading so we stay sync'd up. */                                  /* Keep reading so we stay sync'd up. */
                                 if (wrerr == NO) {                                  if (wrerr == NO) {
Line 844 
Line 918 
                         }                          }
                 }                  }
                 if (showprogress)                  if (showprogress)
                         progressmeter(1);                          stop_progress_meter();
                 if (count != 0 && wrerr == NO &&                  if (count != 0 && wrerr == NO &&
                     (j = atomicio(write, ofd, bp->buf, count)) != count) {                      (j = atomicio(write, ofd, bp->buf, count)) != count) {
                         wrerr = YES;                          wrerr = YES;
                         wrerrno = j >= 0 ? EIO : errno;                          wrerrno = j >= 0 ? EIO : errno;
                 }                  }
                 if (ftruncate(ofd, size)) {                  if (wrerr == NO && ftruncate(ofd, size) != 0) {
                         run_err("%s: truncate: %s", np, strerror(errno));                          run_err("%s: truncate: %s", np, strerror(errno));
                         wrerr = DISPLAYED;                          wrerr = DISPLAYED;
                 }                  }
Line 931 
Line 1005 
 usage(void)  usage(void)
 {  {
         (void) fprintf(stderr,          (void) fprintf(stderr,
             "usage: scp [-pqrvBC46] [-F config] [-S ssh] [-P port] [-c cipher] [-i identity]\n"              "usage: scp [-pqrvBC1246] [-F config] [-S program] [-P port]\n"
             "           [-o option] f1 f2\n"              "           [-c cipher] [-i identity] [-l limit] [-o option]\n"
             "   or: scp [options] f1 ... fn directory\n");              "           [[user@]host1:]file1 [...] [[user@]host2:]file2\n");
         exit(1);          exit(1);
 }  }
   
Line 989 
Line 1063 
                 c = (int)*cp;                  c = (int)*cp;
                 if (c & 0200)                  if (c & 0200)
                         goto bad;                          goto bad;
                 if (!isalpha(c) && !isdigit(c) &&                  if (!isalpha(c) && !isdigit(c)) {
                     c != '_' && c != '-' && c != '.' && c != '+')                          switch (c) {
                         goto bad;                          case '\'':
                           case '"':
                           case '`':
                           case ' ':
                           case '#':
                                   goto bad;
                           default:
                                   break;
                           }
                   }
         } while (*++cp);          } while (*++cp);
         return (1);          return (1);
   
Line 1011 
Line 1094 
                 run_err("fstat: %s", strerror(errno));                  run_err("fstat: %s", strerror(errno));
                 return (0);                  return (0);
         }          }
         if (stb.st_blksize == 0)          size = roundup(stb.st_blksize, blksize);
           if (size == 0)
                 size = blksize;                  size = blksize;
         else  
                 size = blksize + (stb.st_blksize - blksize % stb.st_blksize) %  
                     stb.st_blksize;  
         if (bp->cnt >= size)          if (bp->cnt >= size)
                 return (bp);                  return (bp);
         if (bp->buf == NULL)          if (bp->buf == NULL)
Line 1037 
Line 1118 
                 _exit(1);                  _exit(1);
         else          else
                 exit(1);                  exit(1);
 }  
   
 static void  
 updateprogressmeter(int ignore)  
 {  
         int save_errno = errno;  
   
         progressmeter(0);  
         signal(SIGALRM, updateprogressmeter);  
         alarm(PROGRESSTIME);  
         errno = save_errno;  
 }  
   
 static int  
 foregroundproc(void)  
 {  
         static pid_t pgrp = -1;  
         int ctty_pgrp;  
   
         if (pgrp == -1)  
                 pgrp = getpgrp();  
   
         return ((ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 &&  
                  ctty_pgrp == pgrp));  
 }  
   
 void  
 progressmeter(int flag)  
 {  
         static const char prefixes[] = " KMGTP";  
         static struct timeval lastupdate;  
         static off_t lastsize;  
         struct timeval now, td, wait;  
         off_t cursize, abbrevsize;  
         double elapsed;  
         int ratio, barlength, i, remaining;  
         char buf[512];  
   
         if (flag == -1) {  
                 (void) gettimeofday(&start, (struct timezone *) 0);  
                 lastupdate = start;  
                 lastsize = 0;  
         }  
         if (foregroundproc() == 0)  
                 return;  
   
         (void) gettimeofday(&now, (struct timezone *) 0);  
         cursize = statbytes;  
         if (totalbytes != 0) {  
                 ratio = 100.0 * cursize / totalbytes;  
                 ratio = MAX(ratio, 0);  
                 ratio = MIN(ratio, 100);  
         } else  
                 ratio = 100;  
   
         snprintf(buf, sizeof(buf), "\r%-20.20s %3d%% ", curfile, ratio);  
   
         barlength = getttywidth() - 51;  
         if (barlength > 0) {  
                 i = barlength * ratio / 100;  
                 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),  
                     "|%.*s%*s|", i,  
                     "*******************************************************"  
                     "*******************************************************"  
                     "*******************************************************"  
                     "*******************************************************"  
                     "*******************************************************"  
                     "*******************************************************"  
                     "*******************************************************",  
                     barlength - i, "");  
         }  
         i = 0;  
         abbrevsize = cursize;  
         while (abbrevsize >= 100000 && i < sizeof(prefixes)) {  
                 i++;  
                 abbrevsize >>= 10;  
         }  
         snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5llu %c%c ",  
             (unsigned long long) abbrevsize, prefixes[i],  
             prefixes[i] == ' ' ? ' ' : 'B');  
   
         timersub(&now, &lastupdate, &wait);  
         if (cursize > lastsize) {  
                 lastupdate = now;  
                 lastsize = cursize;  
                 if (wait.tv_sec >= STALLTIME) {  
                         start.tv_sec += wait.tv_sec;  
                         start.tv_usec += wait.tv_usec;  
                 }  
                 wait.tv_sec = 0;  
         }  
         timersub(&now, &start, &td);  
         elapsed = td.tv_sec + (td.tv_usec / 1000000.0);  
   
         if (flag != 1 &&  
             (statbytes <= 0 || elapsed <= 0.0 || cursize > totalbytes)) {  
                 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),  
                     "   --:-- ETA");  
         } else if (wait.tv_sec >= STALLTIME) {  
                 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),  
                     " - stalled -");  
         } else {  
                 if (flag != 1)  
                         remaining = (int)(totalbytes / (statbytes / elapsed) -  
                             elapsed);  
                 else  
                         remaining = elapsed;  
   
                 i = remaining / 3600;  
                 if (i)  
                         snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),  
                             "%2d:", i);  
                 else  
                         snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),  
                             "   ");  
                 i = remaining % 3600;  
                 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),  
                     "%02d:%02d%s", i / 60, i % 60,  
                     (flag != 1) ? " ETA" : "    ");  
         }  
         atomicio(write, fileno(stdout), buf, strlen(buf));  
   
         if (flag == -1) {  
                 signal(SIGALRM, updateprogressmeter);  
                 alarm(PROGRESSTIME);  
         } else if (flag == 1) {  
                 alarm(0);  
                 atomicio(write, fileno(stdout), "\n", 1);  
                 statbytes = 0;  
         }  
 }  
   
 int  
 getttywidth(void)  
 {  
         struct winsize winsize;  
   
         if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1)  
                 return (winsize.ws_col ? winsize.ws_col : 80);  
         else  
                 return (80);  
 }  }

Legend:
Removed from v.1.88  
changed lines
  Added in v.1.88.2.2