]> andersk Git - openssh.git/blobdiff - scp.c
- jmc@cvs.openbsd.org 2006/01/30 13:37:49
[openssh.git] / scp.c
diff --git a/scp.c b/scp.c
index 3ca110b167f7222503e1182fa94885c65d539758..5dced6ce4aa008e3bef063711e7a54a5ac7dee99 100644 (file)
--- a/scp.c
+++ b/scp.c
@@ -14,8 +14,8 @@
  * called by a name other than "ssh" or "Secure Shell".
  */
 /*
- * Copyright (c) 1999 Theo de Raadt. All rights reserved.
- * Copyright (c) 1999 Aaron Campbell. All rights reserved.
+ * Copyright (c) 1999 Theo de Raadt.  All rights reserved.
+ * Copyright (c) 1999 Aaron Campbell.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: scp.c,v 1.58 2001/02/10 15:14:11 danh Exp $");
+RCSID("$OpenBSD: scp.c,v 1.128 2005/12/06 22:38:27 reyk Exp $");
 
 #include "xmalloc.h"
 #include "atomicio.h"
 #include "pathnames.h"
 #include "log.h"
 #include "misc.h"
+#include "progressmeter.h"
 
-#ifdef HAVE___PROGNAME
 extern char *__progname;
-#else
-char *__progname;
-#endif
-
-/* For progressmeter() -- number of seconds before xfer considered "stalled" */
-#define STALLTIME      5
-
-/* Progress meter bar */
-#define BAR \
-       "************************************************************"\
-       "************************************************************"\
-       "************************************************************"\
-       "************************************************************"
-#define MAX_BARLENGTH (sizeof(BAR) - 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);
 
-/* setup arguments for the call to ssh */
-void addargs(char *fmt, ...) __attribute__((format(printf, 1, 2)));
+void bwlimit(int);
 
-/* Time a transfer started. */
-static struct timeval start;
+/* Struct for addargs */
+arglist args;
 
-/* Number of bytes of current file transferred so far. */
-volatile u_long statbytes;
-
-/* Total size of current file. */
-off_t totalbytes = 0;
+/* Bandwidth limit */
+off_t limit_rate = 0;
 
 /* Name of current file being transferred. */
 char *curfile;
@@ -131,12 +102,21 @@ int showprogress = 1;
 /* This is the program to execute for the secured connection. ("ssh" or -S) */
 char *ssh_program = _PATH_SSH_PROGRAM;
 
-/* This is the list of arguments that scp passes to ssh */
-struct {
-       char    **list;
-       int     num;
-       int     nalloc;
-} args;
+/* This is used to store the pid of ssh_program */
+pid_t do_cmd_pid = -1;
+
+static void
+killchild(int signo)
+{
+       if (do_cmd_pid > 1) {
+               kill(do_cmd_pid, signo ? signo : SIGTERM);
+               waitpid(do_cmd_pid, NULL, 0);
+       }
+
+       if (signo)
+               _exit(1);
+       exit(1);
+}
 
 /*
  * This function executes the given command as the specified user on the
@@ -150,8 +130,10 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
        int pin[2], pout[2], reserved[2];
 
        if (verbose_mode)
-               fprintf(stderr, "Executing: program %s host %s, user %s, command %s\n",
-                   ssh_program, host, remuser ? remuser : "(unspecified)", cmd);
+               fprintf(stderr,
+                   "Executing: program %s host %s, user %s, command %s\n",
+                   ssh_program, host,
+                   remuser ? remuser : "(unspecified)", cmd);
 
        /*
         * Reserve two descriptors so that the real pipes won't get
@@ -169,8 +151,9 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
        close(reserved[0]);
        close(reserved[1]);
 
-       /* For a child to execute the command on the remote host using ssh. */
-       if (fork() == 0)  {
+       /* Fork a child to execute the command on the remote host using ssh. */
+       do_cmd_pid = fork();
+       if (do_cmd_pid == 0) {
                /* Child. */
                close(pin[1]);
                close(pout[0]);
@@ -181,31 +164,33 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
 
                args.list[0] = ssh_program;
                if (remuser != NULL)
-                       addargs("-l%s", remuser);
-               addargs("%s", host);
-               addargs("%s", cmd);
+                       addargs(&args, "-l%s", remuser);
+               addargs(&args, "%s", host);
+               addargs(&args, "%s", cmd);
 
                execvp(ssh_program, args.list);
                perror(ssh_program);
                exit(1);
+       } else if (do_cmd_pid == -1) {
+               fatal("fork: %s", strerror(errno));
        }
        /* Parent.  Close the other side, and return the local side. */
        close(pin[0]);
        *fdout = pin[1];
        close(pout[1]);
        *fdin = pout[0];
+       signal(SIGTERM, killchild);
+       signal(SIGINT, killchild);
+       signal(SIGHUP, killchild);
        return 0;
 }
 
 typedef struct {
-       int cnt;
+       size_t cnt;
        char *buf;
 } BUF;
 
-extern int iamremote;
-
 BUF *allocbuf(BUF *, int, int);
-char *colon(char *);
 void lostconn(int);
 void nospace(void);
 int okname(char *);
@@ -220,52 +205,63 @@ int pflag, iamremote, iamrecursive, targetshouldbedirectory;
 #define        CMDNEEDS        64
 char cmd[CMDNEEDS];            /* must hold "rcp -r -p -d\0" */
 
-int main(int, char *[]);
 int response(void);
 void rsource(char *, struct stat *);
 void sink(int, char *[]);
 void source(int, char *[]);
 void tolocal(int, char *[]);
-char *cleanhostname(char *);
 void toremote(char *, int, char *[]);
 void usage(void);
 
 int
-main(argc, argv)
-       int argc;
-       char *argv[];
+main(int argc, char **argv)
 {
-       int ch, fflag, tflag;
-       char *targ;
+       int ch, fflag, tflag, status;
+       double speed;
+       char *targ, *endp;
        extern char *optarg;
        extern int optind;
 
-       __progname = get_progname(argv[0]);
+       /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+       sanitise_stdfd();
+
+       __progname = ssh_get_progname(argv[0]);
 
        args.list = NULL;
-       addargs("ssh");         /* overwritten with ssh_program */
-       addargs("-x");
-       addargs("-oFallBackToRsh no");
+       addargs(&args, "ssh");          /* overwritten with ssh_program */
+       addargs(&args, "-x");
+       addargs(&args, "-oForwardAgent no");
+       addargs(&args, "-oPermitLocalCommand no");
+       addargs(&args, "-oClearAllForwardings yes");
 
        fflag = tflag = 0;
-       while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:")) != -1)
+       while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q1246S:o:F:")) != -1)
                switch (ch) {
                /* User-visible flags. */
+               case '1':
+               case '2':
                case '4':
                case '6':
                case 'C':
-                       addargs("-%c", ch);
+                       addargs(&args, "-%c", ch);
                        break;
                case 'o':
                case 'c':
                case 'i':
-                       addargs("-%c%s", ch, optarg);
+               case 'F':
+                       addargs(&args, "-%c%s", ch, optarg);
                        break;
                case 'P':
-                       addargs("-p%s", optarg);
+                       addargs(&args, "-p%s", optarg);
                        break;
                case 'B':
-                       addargs("-oBatchmode yes");
+                       addargs(&args, "-oBatchmode yes");
+                       break;
+               case 'l':
+                       speed = strtod(optarg, &endp);
+                       if (speed <= 0 || *endp != '\0')
+                               usage();
+                       limit_rate = speed * 1024;
                        break;
                case 'p':
                        pflag = 1;
@@ -277,9 +273,11 @@ main(argc, argv)
                        ssh_program = xstrdup(optarg);
                        break;
                case 'v':
+                       addargs(&args, "-v");
                        verbose_mode = 1;
                        break;
                case 'q':
+                       addargs(&args, "-q");
                        showprogress = 0;
                        break;
 
@@ -294,8 +292,10 @@ main(argc, argv)
                case 't':       /* "to" */
                        iamremote = 1;
                        tflag = 1;
+#ifdef HAVE_CYGWIN
+                       setmode(0, O_BINARY);
+#endif
                        break;
-               case '?':
                default:
                        usage();
                }
@@ -303,7 +303,7 @@ main(argc, argv)
        argv += optind;
 
        if ((pwd = getpwuid(userid = getuid())) == NULL)
-               fatal("unknown user %d", (int) userid);
+               fatal("unknown user %u", (u_int) userid);
 
        if (!isatty(STDERR_FILENO))
                showprogress = 0;
@@ -328,6 +328,7 @@ main(argc, argv)
                targetshouldbedirectory = 1;
 
        remin = remout = -1;
+       do_cmd_pid = -1;
        /* Command to be executed on remote system using "ssh". */
        (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",
            verbose_mode ? " -v" : "",
@@ -343,55 +344,60 @@ main(argc, argv)
                if (targetshouldbedirectory)
                        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);
 }
 
-char *
-cleanhostname(host)
-       char *host;
-{
-       if (*host == '[' && host[strlen(host) - 1] == ']') {
-               host[strlen(host) - 1] = '\0';
-               return (host + 1);
-       } else
-               return host;
-}
-
 void
-toremote(targ, argc, argv)
-       char *targ, *argv[];
-       int argc;
+toremote(char *targ, int argc, char **argv)
 {
        int i, len;
-       char *bp, *host, *src, *suser, *thost, *tuser;
+       char *bp, *host, *src, *suser, *thost, *tuser, *arg;
 
        *targ++ = 0;
        if (*targ == 0)
                targ = ".";
 
-       if ((thost = strchr(argv[argc - 1], '@'))) {
+       arg = xstrdup(argv[argc - 1]);
+       if ((thost = strrchr(arg, '@'))) {
                /* user@host */
                *thost++ = 0;
-               tuser = argv[argc - 1];
+               tuser = arg;
                if (*tuser == '\0')
                        tuser = NULL;
-               else if (!okname(tuser))
-                       exit(1);
        } else {
-               thost = argv[argc - 1];
+               thost = arg;
                tuser = NULL;
        }
 
        for (i = 0; i < argc - 1; i++) {
                src = colon(argv[i]);
                if (src) {      /* remote to remote */
+                       static char *ssh_options =
+                           "-x -o'ClearAllForwardings yes'";
                        *src++ = 0;
                        if (*src == 0)
                                src = ".";
-                       host = strchr(argv[i], '@');
+                       host = strrchr(argv[i], '@');
                        len = strlen(ssh_program) + strlen(argv[i]) +
                            strlen(src) + (tuser ? strlen(tuser) : 0) +
-                           strlen(thost) + strlen(targ) + CMDNEEDS + 32;
+                           strlen(thost) + strlen(targ) +
+                           strlen(ssh_options) + CMDNEEDS + 20;
                        bp = xmalloc(len);
                        if (host) {
                                *host++ = 0;
@@ -399,28 +405,35 @@ toremote(targ, argc, argv)
                                suser = argv[i];
                                if (*suser == '\0')
                                        suser = pwd->pw_name;
-                               else if (!okname(suser))
+                               else if (!okname(suser)) {
+                                       xfree(bp);
+                                       continue;
+                               }
+                               if (tuser && !okname(tuser)) {
+                                       xfree(bp);
                                        continue;
+                               }
                                snprintf(bp, len,
-                                   "%s%s -x -o'FallBackToRsh no' -n "
+                                   "%s%s %s -n "
                                    "-l %s %s %s %s '%s%s%s:%s'",
                                    ssh_program, verbose_mode ? " -v" : "",
-                                   suser, host, cmd, src,
+                                   ssh_options, suser, host, cmd, src,
                                    tuser ? tuser : "", tuser ? "@" : "",
                                    thost, targ);
                        } else {
                                host = cleanhostname(argv[i]);
                                snprintf(bp, len,
-                                   "exec %s%s -x -o'FallBackToRsh no' -n %s "
+                                   "exec %s%s %s -n %s "
                                    "%s %s '%s%s%s:%s'",
                                    ssh_program, verbose_mode ? " -v" : "",
-                                   host, cmd, src,
+                                   ssh_options, host, cmd, src,
                                    tuser ? tuser : "", tuser ? "@" : "",
                                    thost, targ);
                        }
                        if (verbose_mode)
                                fprintf(stderr, "Executing: %s\n", bp);
-                       (void) system(bp);
+                       if (system(bp) != 0)
+                               errs = 1;
                        (void) xfree(bp);
                } else {        /* local to remote */
                        if (remin == -1) {
@@ -441,9 +454,7 @@ toremote(targ, argc, argv)
 }
 
 void
-tolocal(argc, argv)
-       int argc;
-       char *argv[];
+tolocal(int argc, char **argv)
 {
        int i, len;
        char *bp, *host, *src, *suser;
@@ -466,7 +477,7 @@ tolocal(argc, argv)
                *src++ = 0;
                if (*src == 0)
                        src = ".";
-               if ((host = strchr(argv[i], '@')) == NULL) {
+               if ((host = strrchr(argv[i], '@')) == NULL) {
                        host = argv[i];
                        suser = NULL;
                } else {
@@ -474,8 +485,6 @@ tolocal(argc, argv)
                        suser = argv[i];
                        if (*suser == '\0')
                                suser = pwd->pw_name;
-                       else if (!okname(suser))
-                               continue;
                }
                host = cleanhostname(host);
                len = strlen(src) + CMDNEEDS + 20;
@@ -494,20 +503,28 @@ tolocal(argc, argv)
 }
 
 void
-source(argc, argv)
-       int argc;
-       char *argv[];
+source(int argc, char **argv)
 {
        struct stat stb;
        static BUF buffer;
        BUF *bp;
-       off_t i;
-       int amt, fd, haderr, indx, result;
+       off_t i, amt, statbytes;
+       size_t result;
+       int fd = -1, haderr, indx;
        char *last, *name, buf[2048];
+       int len;
 
        for (indx = 0; indx < argc; ++indx) {
                name = argv[indx];
                statbytes = 0;
+               len = strlen(name);
+               while (len > 1 && name[len-1] == '/')
+                       name[--len] = '\0';
+               if (strchr(name, '\n') != NULL) {
+                       run_err("%s: skipping, filename contains a newline",
+                           name);
+                       goto next;
+               }
                if ((fd = open(name, O_RDONLY, 0)) < 0)
                        goto syserr;
                if (fstat(fd, &stb) < 0) {
@@ -540,29 +557,29 @@ syserr:                   run_err("%s: %s", name, strerror(errno));
                        (void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n",
                            (u_long) stb.st_mtime,
                            (u_long) stb.st_atime);
-                       (void) atomicio(write, remout, buf, strlen(buf));
+                       (void) atomicio(vwrite, remout, buf, strlen(buf));
                        if (response() < 0)
                                goto next;
                }
 #define        FILEMODEMASK    (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
-               snprintf(buf, sizeof buf, "C%04o %lu %s\n",
+               snprintf(buf, sizeof buf, "C%04o %lld %s\n",
                    (u_int) (stb.st_mode & FILEMODEMASK),
-                   (u_long) stb.st_size, last);
+                   (long long)stb.st_size, last);
                if (verbose_mode) {
                        fprintf(stderr, "Sending file modes: %s", buf);
-                       fflush(stderr);
                }
-               (void) atomicio(write, remout, buf, strlen(buf));
+               (void) atomicio(vwrite, remout, buf, strlen(buf));
                if (response() < 0)
                        goto next;
                if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) {
-next:                  (void) close(fd);
+next:                  if (fd != -1) {
+                               (void) close(fd);
+                               fd = -1;
+                       }
                        continue;
                }
-               if (showprogress) {
-                       totalbytes = stb.st_size;
-                       progressmeter(-1);
-               }
+               if (showprogress)
+                       start_progress_meter(curfile, stb.st_size, &statbytes);
                /* Keep writing after an error so that we stay sync'd up. */
                for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
                        amt = bp->cnt;
@@ -571,24 +588,29 @@ next:                     (void) close(fd);
                        if (!haderr) {
                                result = atomicio(read, fd, bp->buf, amt);
                                if (result != amt)
-                                       haderr = result >= 0 ? EIO : errno;
+                                       haderr = errno;
                        }
                        if (haderr)
-                               (void) atomicio(write, remout, bp->buf, amt);
+                               (void) atomicio(vwrite, remout, bp->buf, amt);
                        else {
-                               result = atomicio(write, remout, bp->buf, amt);
+                               result = atomicio(vwrite, remout, bp->buf, amt);
                                if (result != amt)
-                                       haderr = result >= 0 ? EIO : errno;
+                                       haderr = errno;
                                statbytes += result;
                        }
+                       if (limit_rate)
+                               bwlimit(amt);
                }
                if (showprogress)
-                       progressmeter(1);
+                       stop_progress_meter();
 
-               if (close(fd) < 0 && !haderr)
-                       haderr = errno;
+               if (fd != -1) {
+                       if (close(fd) < 0 && !haderr)
+                               haderr = errno;
+                       fd = -1;
+               }
                if (!haderr)
-                       (void) atomicio(write, remout, "", 1);
+                       (void) atomicio(vwrite, remout, "", 1);
                else
                        run_err("%s: %s", name, strerror(haderr));
                (void) response();
@@ -596,9 +618,7 @@ next:                       (void) close(fd);
 }
 
 void
-rsource(name, statp)
-       char *name;
-       struct stat *statp;
+rsource(char *name, struct stat *statp)
 {
        DIR *dirp;
        struct dirent *dp;
@@ -617,7 +637,7 @@ rsource(name, statp)
                (void) snprintf(path, sizeof(path), "T%lu 0 %lu 0\n",
                    (u_long) statp->st_mtime,
                    (u_long) statp->st_atime);
-               (void) atomicio(write, remout, path, strlen(path));
+               (void) atomicio(vwrite, remout, path, strlen(path));
                if (response() < 0) {
                        closedir(dirp);
                        return;
@@ -627,12 +647,12 @@ rsource(name, statp)
            (u_int) (statp->st_mode & FILEMODEMASK), 0, last);
        if (verbose_mode)
                fprintf(stderr, "Entering directory: %s", path);
-       (void) atomicio(write, remout, path, strlen(path));
+       (void) atomicio(vwrite, remout, path, strlen(path));
        if (response() < 0) {
                closedir(dirp);
                return;
        }
-       while ((dp = readdir(dirp))) {
+       while ((dp = readdir(dirp)) != NULL) {
                if (dp->d_ino == 0)
                        continue;
                if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
@@ -646,14 +666,66 @@ rsource(name, statp)
                source(1, vect);
        }
        (void) closedir(dirp);
-       (void) atomicio(write, remout, "E\n", 2);
+       (void) atomicio(vwrite, remout, "E\n", 2);
        (void) response();
 }
 
 void
-sink(argc, argv)
-       int argc;
-       char *argv[];
+bwlimit(int amount)
+{
+       static struct timeval bwstart, bwend;
+       static int lamt, thresh = 16384;
+       u_int64_t waitlen;
+       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;
+       waitlen = (double)1000000L * lamt / limit_rate;
+
+       bwstart.tv_sec = waitlen / 1000000L;
+       bwstart.tv_usec = waitlen % 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(int argc, char **argv)
 {
        static BUF buffer;
        struct stat stb;
@@ -661,14 +733,16 @@ sink(argc, argv)
                YES, NO, DISPLAYED
        } wrerr;
        BUF *bp;
-       off_t i, j;
-       int amt, count, exists, first, mask, mode, ofd, omode;
-       off_t size;
+       off_t i;
+       size_t j, count;
+       int amt, exists, first, mask, mode, ofd, omode;
+       off_t size, statbytes;
        int setimes, targisdir, wrerrno = 0;
        char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
-       int dummy_usec;
        struct timeval tv[2];
 
+#define        atime   tv[0]
+#define        mtime   tv[1]
 #define        SCREWUP(str)    { why = str; goto screwup; }
 
        setimes = targisdir = 0;
@@ -683,12 +757,12 @@ sink(argc, argv)
        if (targetshouldbedirectory)
                verifydir(targ);
 
-       (void) atomicio(write, remout, "", 1);
+       (void) atomicio(vwrite, remout, "", 1);
        if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
                targisdir = 1;
        for (first = 1;; first = 0) {
                cp = buf;
-               if (atomicio(read, remin, cp, 1) <= 0)
+               if (atomicio(read, remin, cp, 1) != 1)
                        return;
                if (*cp++ == '\n')
                        SCREWUP("unexpected <newline>");
@@ -698,10 +772,12 @@ sink(argc, argv)
                        *cp++ = ch;
                } while (cp < &buf[sizeof(buf) - 1] && ch != '\n');
                *cp = 0;
+               if (verbose_mode)
+                       fprintf(stderr, "Sink: %s", buf);
 
                if (buf[0] == '\01' || buf[0] == '\02') {
                        if (iamremote == 0)
-                               (void) atomicio(write, STDERR_FILENO,
+                               (void) atomicio(vwrite, STDERR_FILENO,
                                    buf + 1, strlen(buf + 1));
                        if (buf[0] == '\02')
                                exit(1);
@@ -709,33 +785,29 @@ sink(argc, argv)
                        continue;
                }
                if (buf[0] == 'E') {
-                       (void) atomicio(write, remout, "", 1);
+                       (void) atomicio(vwrite, remout, "", 1);
                        return;
                }
                if (ch == '\n')
                        *--cp = 0;
 
-#define getnum(t) (t) = 0; \
-  while (*cp >= '0' && *cp <= '9') (t) = (t) * 10 + (*cp++ - '0');
                cp = buf;
                if (*cp == 'T') {
                        setimes++;
                        cp++;
-                       getnum(tv[1].tv_sec);
-                       if (*cp++ != ' ')
+                       mtime.tv_sec = strtol(cp, &cp, 10);
+                       if (!cp || *cp++ != ' ')
                                SCREWUP("mtime.sec not delimited");
-                       getnum(dummy_usec);
-                       tv[1].tv_usec = 0;
-                       if (*cp++ != ' ')
+                       mtime.tv_usec = strtol(cp, &cp, 10);
+                       if (!cp || *cp++ != ' ')
                                SCREWUP("mtime.usec not delimited");
-                       getnum(tv[0].tv_sec);
-                       if (*cp++ != ' ')
+                       atime.tv_sec = strtol(cp, &cp, 10);
+                       if (!cp || *cp++ != ' ')
                                SCREWUP("atime.sec not delimited");
-                       getnum(dummy_usec);
-                       tv[0].tv_usec = 0;
-                       if (*cp++ != '\0')
+                       atime.tv_usec = strtol(cp, &cp, 10);
+                       if (!cp || *cp++ != '\0')
                                SCREWUP("atime.usec not delimited");
-                       (void) atomicio(write, remout, "", 1);
+                       (void) atomicio(vwrite, remout, "", 1);
                        continue;
                }
                if (*cp != 'C' && *cp != 'D') {
@@ -761,13 +833,17 @@ sink(argc, argv)
                if (*cp++ != ' ')
                        SCREWUP("mode not delimited");
 
-               for (size = 0; *cp >= '0' && *cp <= '9';)
+               for (size = 0; isdigit(*cp);)
                        size = size * 10 + (*cp++ - '0');
                if (*cp++ != ' ')
                        SCREWUP("size not delimited");
+               if ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) {
+                       run_err("error: unexpected filename: %s", cp);
+                       exit(1);
+               }
                if (targisdir) {
                        static char *namebuf;
-                       static int cursize;
+                       static size_t cursize;
                        size_t need;
 
                        need = strlen(targ) + strlen(cp) + 250;
@@ -778,7 +854,7 @@ sink(argc, argv)
                                cursize = need;
                        }
                        (void) snprintf(namebuf, need, "%s%s%s", targ,
-                           *targ ? "/" : "", cp);
+                           strcmp(targ, "/") ? "/" : "", cp);
                        np = namebuf;
                } else
                        np = targ;
@@ -786,6 +862,8 @@ sink(argc, argv)
                exists = stat(np, &stb) == 0;
                if (buf[0] == 'D') {
                        int mod_flag = pflag;
+                       if (!iamrecursive)
+                               SCREWUP("received directory without -r");
                        if (exists) {
                                if (!S_ISDIR(stb.st_mode)) {
                                        errno = ENOTDIR;
@@ -802,25 +880,25 @@ sink(argc, argv)
                        }
                        vect[0] = xstrdup(np);
                        sink(1, vect);
-                       if (vect[0])
-                               xfree(vect[0]);
                        if (setimes) {
                                setimes = 0;
-                               if (utimes(np, tv) < 0)
+                               if (utimes(vect[0], tv) < 0)
                                        run_err("%s: set times: %s",
-                                               np, strerror(errno));
+                                           vect[0], strerror(errno));
                        }
                        if (mod_flag)
-                               (void) chmod(np, mode);
+                               (void) chmod(vect[0], mode);
+                       if (vect[0])
+                               xfree(vect[0]);
                        continue;
                }
                omode = mode;
                mode |= S_IWRITE;
-               if ((ofd = open(np, O_WRONLY | O_CREAT | O_TRUNC, mode)) < 0) {
+               if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
 bad:                   run_err("%s: %s", np, strerror(errno));
                        continue;
                }
-               (void) atomicio(write, remout, "", 1);
+               (void) atomicio(vwrite, remout, "", 1);
                if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) {
                        (void) close(ofd);
                        continue;
@@ -828,36 +906,36 @@ bad:                      run_err("%s: %s", np, strerror(errno));
                cp = bp->buf;
                wrerr = NO;
 
-               if (showprogress) {
-                       totalbytes = size;
-                       progressmeter(-1);
-               }
                statbytes = 0;
+               if (showprogress)
+                       start_progress_meter(curfile, size, &statbytes);
                for (count = i = 0; i < size; i += 4096) {
                        amt = 4096;
                        if (i + amt > size)
                                amt = size - i;
                        count += amt;
                        do {
-                               j = read(remin, cp, amt);
-                               if (j == -1 && (errno == EINTR || errno == EAGAIN)) {
-                                       continue;
-                               } else if (j <= 0) {
+                               j = atomicio(read, remin, cp, amt);
+                               if (j == 0) {
                                        run_err("%s", j ? strerror(errno) :
-                                               "dropped connection");
+                                           "dropped connection");
                                        exit(1);
                                }
                                amt -= j;
                                cp += j;
                                statbytes += j;
                        } while (amt > 0);
+
+                       if (limit_rate)
+                               bwlimit(4096);
+
                        if (count == bp->cnt) {
                                /* Keep reading so we stay sync'd up. */
                                if (wrerr == NO) {
-                                       j = atomicio(write, ofd, bp->buf, count);
-                                       if (j != count) {
+                                       if (atomicio(vwrite, ofd, bp->buf,
+                                           count) != count) {
                                                wrerr = YES;
-                                               wrerrno = j >= 0 ? EIO : errno;
+                                               wrerrno = errno;
                                        }
                                }
                                count = 0;
@@ -865,36 +943,38 @@ bad:                      run_err("%s: %s", np, strerror(errno));
                        }
                }
                if (showprogress)
-                       progressmeter(1);
+                       stop_progress_meter();
                if (count != 0 && wrerr == NO &&
-                   (j = atomicio(write, ofd, bp->buf, count)) != count) {
+                   atomicio(vwrite, ofd, bp->buf, count) != count) {
                        wrerr = YES;
-                       wrerrno = j >= 0 ? EIO : errno;
+                       wrerrno = errno;
                }
-#if 0
-               if (ftruncate(ofd, size)) {
+               if (wrerr == NO && ftruncate(ofd, size) != 0) {
                        run_err("%s: truncate: %s", np, strerror(errno));
                        wrerr = DISPLAYED;
                }
-#endif
                if (pflag) {
                        if (exists || omode != mode)
 #ifdef HAVE_FCHMOD
-                               if (fchmod(ofd, omode))
+                               if (fchmod(ofd, omode)) {
 #else /* HAVE_FCHMOD */
-                               if (chmod(np, omode))
+                               if (chmod(np, omode)) {
 #endif /* HAVE_FCHMOD */
                                        run_err("%s: set mode: %s",
-                                               np, strerror(errno));
+                                           np, strerror(errno));
+                                       wrerr = DISPLAYED;
+                               }
                } else {
                        if (!exists && omode != mode)
 #ifdef HAVE_FCHMOD
-                               if (fchmod(ofd, omode & ~mask))
+                               if (fchmod(ofd, omode & ~mask)) {
 #else /* HAVE_FCHMOD */
-                               if (chmod(np, omode & ~mask))
+                               if (chmod(np, omode & ~mask)) {
 #endif /* HAVE_FCHMOD */
                                        run_err("%s: set mode: %s",
-                                               np, strerror(errno));
+                                           np, strerror(errno));
+                                       wrerr = DISPLAYED;
+                               }
                }
                if (close(ofd) == -1) {
                        wrerr = YES;
@@ -905,7 +985,7 @@ bad:                        run_err("%s: %s", np, strerror(errno));
                        setimes = 0;
                        if (utimes(np, tv) < 0) {
                                run_err("%s: set times: %s",
-                                       np, strerror(errno));
+                                   np, strerror(errno));
                                wrerr = DISPLAYED;
                        }
                }
@@ -914,7 +994,7 @@ bad:                        run_err("%s: %s", np, strerror(errno));
                        run_err("%s: %s", np, strerror(wrerrno));
                        break;
                case NO:
-                       (void) atomicio(write, remout, "", 1);
+                       (void) atomicio(vwrite, remout, "", 1);
                        break;
                case DISPLAYED:
                        break;
@@ -926,7 +1006,7 @@ screwup:
 }
 
 int
-response()
+response(void)
 {
        char ch, *cp, resp, rbuf[2048];
 
@@ -949,7 +1029,7 @@ response()
                } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n');
 
                if (!iamremote)
-                       (void) atomicio(write, STDERR_FILENO, rbuf, cp - rbuf);
+                       (void) atomicio(vwrite, STDERR_FILENO, rbuf, cp - rbuf);
                ++errs;
                if (resp == 1)
                        return (-1);
@@ -959,11 +1039,12 @@ response()
 }
 
 void
-usage()
+usage(void)
 {
-       (void) fprintf(stderr, "usage: scp "
-           "[-pqrvC46] [-S ssh] [-P port] [-c cipher] [-i identity] f1 f2; or:\n"
-           "       scp [options] f1 ... fn directory\n");
+       (void) fprintf(stderr,
+           "usage: scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
+           "           [-l limit] [-o ssh_option] [-P port] [-S program]\n"
+           "           [[user@]host1:]file1 [...] [[user@]host2:]file2\n");
        exit(1);
 }
 
@@ -992,33 +1073,8 @@ run_err(const char *fmt,...)
        }
 }
 
-char *
-colon(cp)
-       char *cp;
-{
-       int flag = 0;
-
-       if (*cp == ':')         /* Leading colon is part of file name. */
-               return (0);
-       if (*cp == '[')
-               flag = 1;
-
-       for (; *cp; ++cp) {
-               if (*cp == '@' && *(cp+1) == '[')
-                       flag = 1;
-               if (*cp == ']' && *(cp+1) == ':' && flag)
-                       return (cp+1);
-               if (*cp == ':' && !flag)
-                       return (cp);
-               if (*cp == '/')
-                       return (0);
-       }
-       return (0);
-}
-
 void
-verifydir(cp)
-       char *cp;
+verifydir(char *cp)
 {
        struct stat stb;
 
@@ -1028,24 +1084,32 @@ verifydir(cp)
                errno = ENOTDIR;
        }
        run_err("%s: %s", cp, strerror(errno));
-       exit(1);
+       killchild(0);
 }
 
 int
-okname(cp0)
-       char *cp0;
+okname(char *cp0)
 {
        int c;
        char *cp;
 
        cp = cp0;
        do {
-               c = *cp;
+               c = (int)*cp;
                if (c & 0200)
                        goto bad;
-               if (!isalpha(c) && !isdigit(c) &&
-                   c != '_' && c != '-' && c != '.' && c != '+')
-                       goto bad;
+               if (!isalpha(c) && !isdigit(c)) {
+                       switch (c) {
+                       case '\'':
+                       case '"':
+                       case '`':
+                       case ' ':
+                       case '#':
+                               goto bad;
+                       default:
+                               break;
+                       }
+               }
        } while (*++cp);
        return (1);
 
@@ -1054,212 +1118,40 @@ bad:   fprintf(stderr, "%s: invalid user name\n", cp0);
 }
 
 BUF *
-allocbuf(bp, fd, blksize)
-       BUF *bp;
-       int fd, blksize;
+allocbuf(BUF *bp, int fd, int blksize)
 {
        size_t size;
-#ifdef HAVE_ST_BLKSIZE
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
        struct stat stb;
 
        if (fstat(fd, &stb) < 0) {
                run_err("fstat: %s", strerror(errno));
                return (0);
        }
-       if (stb.st_blksize == 0)
+       size = roundup(stb.st_blksize, blksize);
+       if (size == 0)
                size = blksize;
-       else
-               size = blksize + (stb.st_blksize - blksize % stb.st_blksize) %
-                   stb.st_blksize;
-#else /* HAVE_ST_BLKSIZE */
+#else /* HAVE_STRUCT_STAT_ST_BLKSIZE */
        size = blksize;
-#endif /* HAVE_ST_BLKSIZE */
+#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
        if (bp->cnt >= size)
                return (bp);
        if (bp->buf == NULL)
                bp->buf = xmalloc(size);
        else
                bp->buf = xrealloc(bp->buf, size);
+       memset(bp->buf, 0, size);
        bp->cnt = size;
        return (bp);
 }
 
 void
-lostconn(signo)
-       int signo;
+lostconn(int signo)
 {
        if (!iamremote)
-               fprintf(stderr, "lost connection\n");
-       exit(1);
-}
-
-
-void
-alarmtimer(int wait)
-{
-       struct itimerval itv;
-
-       itv.it_value.tv_sec = wait;
-       itv.it_value.tv_usec = 0;
-       itv.it_interval = itv.it_value;
-       setitimer(ITIMER_REAL, &itv, NULL);
-}
-
-void
-updateprogressmeter(int ignore)
-{
-       int save_errno = errno;
-
-       progressmeter(0);
-       errno = save_errno;
-}
-
-int
-foregroundproc(void)
-{
-       static pid_t pgrp = -1;
-       int ctty_pgrp;
-
-       if (pgrp == -1)
-               pgrp = getpgrp();
-
-#ifdef HAVE_TCGETPGRP
-       return ((ctty_pgrp = tcgetpgrp(STDOUT_FILENO)) != -1 &&
-               ctty_pgrp == pgrp);
-#else
-       return ((ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 &&
-                ctty_pgrp == pgrp));
-#endif
-}
-
-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[256];
-
-       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;
-       barlength = (barlength <= MAX_BARLENGTH)?barlength:MAX_BARLENGTH;
-       if (barlength > 0) {
-               i = barlength * ratio / 100;
-               snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-                        "|%.*s%*s|", i, BAR, barlength - i, "");
-       }
-       i = 0;
-       abbrevsize = cursize;
-       while (abbrevsize >= 100000 && i < sizeof(prefixes)) {
-               i++;
-               abbrevsize >>= 10;
-       }
-       snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5lu %c%c ",
-           (unsigned 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) {
-               mysignal(SIGALRM, updateprogressmeter);
-               alarmtimer(1);
-       } else if (flag == 1) {
-               alarmtimer(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);
+               write(STDERR_FILENO, "lost connection\n", 16);
+       if (signo)
+               _exit(1);
        else
-               return (80);
-}
-
-void
-addargs(char *fmt, ...)
-{
-       va_list ap;
-       char buf[1024];
-
-       va_start(ap, fmt);
-       vsnprintf(buf, sizeof(buf), fmt, ap);
-       va_end(ap);
-
-       if (args.list == NULL) {
-               args.nalloc = 32;
-               args.num = 0;
-               args.list = xmalloc(args.nalloc * sizeof(char *));
-       } else if (args.num+2 >= args.nalloc) {
-               args.nalloc *= 2;
-               args.list = xrealloc(args.list, args.nalloc * sizeof(char *));
-       }
-       args.list[args.num++] = xstrdup(buf);
-       args.list[args.num] = NULL;
+               exit(1);
 }
This page took 0.097459 seconds and 4 git commands to generate.