]> andersk Git - gssapi-openssh.git/blobdiff - openssh/scp.c
openssh-4.2p1-hpn11-none.diff from
[gssapi-openssh.git] / openssh / scp.c
index fb4d3096c1a64ea01c1c2449ae858119eb0d1d25..bd0f6482ba0406b5f9a0bfc5990df3c93c67fbce 100644 (file)
  * 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.85 2001/10/01 08:06:28 markus Exp $");
+RCSID("$OpenBSD: scp.c,v 1.125 2005/07/27 10:39:03 dtucker 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
-/* alarm() interval for updating progress meter */
-#define PROGRESSTIME   1
-
-/* 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);
+void bwlimit(int);
 
 /* Struct for addargs */
 arglist args;
 
-/* Time a transfer started. */
-static struct timeval start;
-
-/* Number of bytes of current file transferred so far. */
-volatile off_t 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;
@@ -133,6 +102,22 @@ int showprogress = 1;
 /* This is the program to execute for the secured connection. ("ssh" or -S) */
 char *ssh_program = _PATH_SSH_PROGRAM;
 
+/* 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
  * given host.  This returns < 0 if execution fails, and >= 0 otherwise. This
@@ -166,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]);
@@ -185,17 +171,22 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
                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;
 
@@ -223,31 +214,32 @@ 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]);
+       __progname = ssh_get_progname(argv[0]);
 
        args.list = NULL;
-       addargs(&args, "ssh");          /* overwritten with ssh_program */
+       addargs(&args, "ssh");          /* overwritten with ssh_program */
        addargs(&args, "-x");
        addargs(&args, "-oForwardAgent no");
-       addargs(&args, "-oFallBackToRsh no");
        addargs(&args, "-oClearAllForwardings yes");
 
        fflag = tflag = 0;
-       while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:F:")) != -1)
+       while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q1246zS:o:F:w:")) != -1)
                switch (ch) {
                /* User-visible flags. */
+               case '1':
+               case '2':
                case '4':
                case '6':
                case 'C':
+               case 'z':       
                        addargs(&args, "-%c", ch);
                        break;
                case 'o':
@@ -262,6 +254,12 @@ main(argc, argv)
                case 'B':
                        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;
                        break;
@@ -276,6 +274,7 @@ main(argc, argv)
                        verbose_mode = 1;
                        break;
                case 'q':
+                       addargs(&args, "-q");
                        showprogress = 0;
                        break;
 
@@ -294,6 +293,9 @@ main(argc, argv)
                        setmode(0, O_BINARY);
 #endif
                        break;
+               case 'w':
+                 addargs(&args, "-w%s", optarg);
+                 break;
                default:
                        usage();
                }
@@ -301,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;
@@ -326,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" : "",
@@ -341,31 +344,44 @@ 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);
 }
 
 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;
        }
 
@@ -373,12 +389,11 @@ toremote(targ, argc, argv)
                src = colon(argv[i]);
                if (src) {      /* remote to remote */
                        static char *ssh_options =
-                           "-x -o'FallBackToRsh no' "
-                           "-o'ClearAllForwardings yes'";
+                           "-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) +
@@ -390,8 +405,14 @@ 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 %s -n "
                                    "-l %s %s %s %s '%s%s%s:%s'",
@@ -411,7 +432,8 @@ toremote(targ, argc, argv)
                        }
                        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) {
@@ -432,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;
@@ -457,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 {
@@ -465,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;
@@ -485,16 +503,15 @@ 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, amt, result;
-       int fd, haderr, indx;
-       char *last, *name, buf[2048];
+       off_t i, amt, statbytes;
+       size_t result;
+       int fd = -1, haderr, indx;
+       char *last, *name, buf[16384];
        int len;
 
        for (indx = 0; indx < argc; ++indx) {
@@ -540,37 +557,30 @@ 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)
-#ifdef HAVE_LONG_LONG_INT
                snprintf(buf, sizeof buf, "C%04o %lld %s\n",
                    (u_int) (stb.st_mode & FILEMODEMASK),
-                   (long long) stb.st_size, last);
-#else
-               /* XXX: Handle integer overflow? */
-               snprintf(buf, sizeof buf, "C%04o %lu %s\n",
-                   (u_int) (stb.st_mode & FILEMODEMASK),
-                   (u_long) stb.st_size, last);
-#endif
-
+                   (int64_t)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) {
+               /* this change decreases the number of read/write syscalls*/
+               /* when scp acts as data source. this is the critical change*/
+               /* buf can actually remain at 2k but increasing both to 16k*/
+               /* seemed to make sense*/
+               if ((bp = allocbuf(&buffer, fd, sizeof(buf))) == NULL) {
 next:                  (void) close(fd);
                        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;
@@ -579,24 +589,26 @@ 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 (!haderr)
-                       (void) atomicio(write, remout, "", 1);
+                       (void) atomicio(vwrite, remout, "", 1);
                else
                        run_err("%s: %s", name, strerror(haderr));
                (void) response();
@@ -604,9 +616,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;
@@ -625,7 +635,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;
@@ -635,7 +645,7 @@ 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;
@@ -654,14 +664,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;
@@ -669,16 +731,17 @@ 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];
+       char ch, *cp, *np, *targ, *why, *vect[1], buf[16384];
        struct timeval tv[2];
 
 #define        atime   tv[0]
 #define        mtime   tv[1]
-#define        SCREWUP(str)    do { why = str; goto screwup; } while (0)
+#define        SCREWUP(str)    { why = str; goto screwup; }
 
        setimes = targisdir = 0;
        mask = umask(0);
@@ -692,12 +755,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>");
@@ -707,10 +770,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);
@@ -718,7 +783,7 @@ sink(argc, argv)
                        continue;
                }
                if (buf[0] == 'E') {
-                       (void) atomicio(write, remout, "", 1);
+                       (void) atomicio(vwrite, remout, "", 1);
                        return;
                }
                if (ch == '\n')
@@ -740,7 +805,7 @@ sink(argc, argv)
                        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') {
@@ -770,9 +835,13 @@ sink(argc, argv)
                        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;
@@ -783,7 +852,7 @@ sink(argc, argv)
                                cursize = need;
                        }
                        (void) snprintf(namebuf, need, "%s%s%s", targ,
-                           *targ ? "/" : "", cp);
+                           strcmp(targ, "/") ? "/" : "", cp);
                        np = namebuf;
                } else
                        np = targ;
@@ -791,6 +860,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;
@@ -825,30 +896,25 @@ sink(argc, argv)
 bad:                   run_err("%s: %s", np, strerror(errno));
                        continue;
                }
-               (void) atomicio(write, remout, "", 1);
-               if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) {
+               (void) atomicio(vwrite, remout, "", 1);
+               if ((bp = allocbuf(&buffer, ofd, sizeof(buf))) == NULL) {
                        (void) close(ofd);
                        continue;
                }
                cp = bp->buf;
                wrerr = NO;
 
-               if (showprogress) {
-                       totalbytes = size;
-                       progressmeter(-1);
-               }
                statbytes = 0;
-               for (count = i = 0; i < size; i += 4096) {
-                       amt = 4096;
+               if (showprogress)
+                       start_progress_meter(curfile, size, &statbytes);
+               for (count = i = 0; i < size; i += sizeof(buf)) {
+                       amt = sizeof(buf);
                        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");
                                        exit(1);
@@ -857,13 +923,17 @@ bad:                      run_err("%s: %s", np, strerror(errno));
                                cp += j;
                                statbytes += j;
                        } while (amt > 0);
+
+                       if (limit_rate)
+                               bwlimit(sizeof(buf));
+
                        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;
@@ -871,34 +941,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 (ftruncate(ofd, size)) {
+               if (wrerr == NO && ftruncate(ofd, size) != 0) {
                        run_err("%s: truncate: %s", np, strerror(errno));
                        wrerr = DISPLAYED;
                }
                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));
+                                       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));
+                                       wrerr = DISPLAYED;
+                               }
                }
                if (close(ofd) == -1) {
                        wrerr = YES;
@@ -918,7 +992,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;
@@ -930,7 +1004,7 @@ screwup:
 }
 
 int
-response()
+response(void)
 {
        char ch, *cp, resp, rbuf[2048];
 
@@ -953,7 +1027,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);
@@ -963,12 +1037,12 @@ response()
 }
 
 void
-usage()
+usage(void)
 {
        (void) fprintf(stderr,
-           "usage: scp [-pqrvBC46] [-F config] [-S ssh] [-P port] [-c cipher] [-i identity]\n"
-           "           [-o option] f1 f2\n"
-           "   or: scp [options] f1 ... fn directory\n");
+           "usage: scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
+           "           [-l limit] [-o ssh_option] [-P port] [-w buffer size] [-S program]\n"
+           "           [[user@]host1:]file1 [...] [[user@]host2:]file2\n");
        exit(1);
 }
 
@@ -998,8 +1072,7 @@ run_err(const char *fmt,...)
 }
 
 void
-verifydir(cp)
-       char *cp;
+verifydir(char *cp)
 {
        struct stat stb;
 
@@ -1009,12 +1082,11 @@ 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;
@@ -1024,9 +1096,18 @@ okname(cp0)
                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);
 
@@ -1035,9 +1116,7 @@ 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_STRUCT_STAT_ST_BLKSIZE
@@ -1047,11 +1126,9 @@ allocbuf(bp, fd, blksize)
                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_STRUCT_STAT_ST_BLKSIZE */
        size = blksize;
 #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
@@ -1067,8 +1144,7 @@ allocbuf(bp, fd, blksize)
 }
 
 void
-lostconn(signo)
-       int signo;
+lostconn(int signo)
 {
        if (!iamremote)
                write(STDERR_FILENO, "lost connection\n", 16);
@@ -1077,142 +1153,3 @@ lostconn(signo)
        else
                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();
-
-#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);
-               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);
-}
This page took 0.206836 seconds and 4 git commands to generate.