]> andersk Git - openssh.git/blobdiff - scp.c
- fgsch@cvs.openbsd.org 2003/01/10 08:19:07
[openssh.git] / scp.c
diff --git a/scp.c b/scp.c
index 10b77af6d7e7349d7b19f0d793064493a47f996e..44b5b4582b204dc5e76769bce184ae79998b015a 100644 (file)
--- a/scp.c
+++ b/scp.c
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: scp.c,v 1.69 2001/05/03 23:09:53 mouring Exp $");
+RCSID("$OpenBSD: scp.c,v 1.97 2003/01/10 08:19:07 fgsch 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;
@@ -89,35 +90,8 @@ extern char *__progname;
 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)));
-
-/* 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;
+/* Struct for addargs */
+arglist args;
 
 /* Name of current file being transferred. */
 char *curfile;
@@ -131,12 +105,8 @@ 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;
 
 /*
  * This function executes the given command as the specified user on the
@@ -150,8 +120,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
@@ -170,7 +142,8 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
        close(reserved[1]);
 
        /* 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. */
                close(pin[1]);
                close(pout[0]);
@@ -181,13 +154,15 @@ 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]);
@@ -230,7 +205,7 @@ main(argc, argv)
        int argc;
        char *argv[];
 {
-       int ch, fflag, tflag;
+       int ch, fflag, tflag, status;
        char *targ;
        extern char *optarg;
        extern int optind;
@@ -238,29 +213,31 @@ main(argc, argv)
        __progname = 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, "-oClearAllForwardings yes");
 
        fflag = tflag = 0;
-       while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:")) != -1)
+       while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:F:")) != -1)
                switch (ch) {
                /* User-visible flags. */
                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 'p':
                        pflag = 1;
@@ -272,6 +249,7 @@ main(argc, argv)
                        ssh_program = xstrdup(optarg);
                        break;
                case 'v':
+                       addargs(&args, "-v");
                        verbose_mode = 1;
                        break;
                case 'q':
@@ -325,6 +303,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" : "",
@@ -340,6 +319,22 @@ 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);
 }
 
@@ -355,7 +350,7 @@ toremote(targ, argc, argv)
        if (*targ == 0)
                targ = ".";
 
-       if ((thost = strchr(argv[argc - 1], '@'))) {
+       if ((thost = strrchr(argv[argc - 1], '@'))) {
                /* user@host */
                *thost++ = 0;
                tuser = argv[argc - 1];
@@ -371,13 +366,16 @@ toremote(targ, argc, argv)
        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;
@@ -388,19 +386,19 @@ toremote(targ, argc, argv)
                                else if (!okname(suser))
                                        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);
                        }
@@ -452,7 +450,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 {
@@ -487,7 +485,7 @@ source(argc, argv)
        struct stat stb;
        static BUF buffer;
        BUF *bp;
-       off_t i, amt, result;
+       off_t i, amt, result, statbytes;
        int fd, haderr, indx;
        char *last, *name, buf[2048];
        int len;
@@ -498,6 +496,11 @@ source(argc, argv)
                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) {
@@ -538,17 +541,15 @@ syserr:                   run_err("%s: %s", name, strerror(errno));
 #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);
+                   (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
-
                if (verbose_mode) {
                        fprintf(stderr, "Sending file modes: %s", buf);
-                       fflush(stderr);
                }
                (void) atomicio(write, remout, buf, strlen(buf));
                if (response() < 0)
@@ -557,10 +558,8 @@ syserr:                    run_err("%s: %s", name, strerror(errno));
 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;
@@ -581,7 +580,7 @@ next:                       (void) close(fd);
                        }
                }
                if (showprogress)
-                       progressmeter(1);
+                       stop_progress_meter();
 
                if (close(fd) < 0 && !haderr)
                        haderr = errno;
@@ -661,14 +660,14 @@ sink(argc, argv)
        BUF *bp;
        off_t i, j;
        int amt, count, exists, first, mask, mode, ofd, omode;
-       off_t size;
+       off_t size, statbytes;
        int setimes, targisdir, wrerrno = 0;
        char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
        struct timeval tv[2];
 
 #define        atime   tv[0]
 #define        mtime   tv[1]
-#define        SCREWUP(str)    { why = str; goto screwup; }
+#define        SCREWUP(str)    do { why = str; goto screwup; } while (0)
 
        setimes = targisdir = 0;
        mask = umask(0);
@@ -773,7 +772,7 @@ sink(argc, argv)
                                cursize = need;
                        }
                        (void) snprintf(namebuf, need, "%s%s%s", targ,
-                           *targ ? "/" : "", cp);
+                           strcmp(targ, "/") ? "/" : "", cp);
                        np = namebuf;
                } else
                        np = targ;
@@ -811,7 +810,7 @@ sink(argc, argv)
                }
                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;
                }
@@ -823,11 +822,9 @@ 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)
@@ -835,7 +832,8 @@ bad:                        run_err("%s: %s", np, strerror(errno));
                        count += amt;
                        do {
                                j = read(remin, cp, amt);
-                               if (j == -1 && (errno == EINTR || errno == EAGAIN)) {
+                               if (j == -1 && (errno == EINTR ||
+                                   errno == EAGAIN)) {
                                        continue;
                                } else if (j <= 0) {
                                        run_err("%s", j ? strerror(errno) :
@@ -860,18 +858,16 @@ 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) {
                        wrerr = YES;
                        wrerrno = j >= 0 ? EIO : errno;
                }
-#if 0
                if (ftruncate(ofd, size)) {
                        run_err("%s: truncate: %s", np, strerror(errno));
                        wrerr = DISPLAYED;
                }
-#endif
                if (pflag) {
                        if (exists || omode != mode)
 #ifdef HAVE_FCHMOD
@@ -921,7 +917,7 @@ screwup:
 }
 
 int
-response()
+response(void)
 {
        char ch, *cp, resp, rbuf[2048];
 
@@ -954,11 +950,12 @@ response()
 }
 
 void
-usage()
+usage(void)
 {
-       (void) fprintf(stderr, "usage: scp "
-           "[-pqrvBC46] [-S ssh] [-P port] [-c cipher] [-i identity] f1 f2\n"
-           "   or: scp [options] f1 ... fn directory\n");
+       (void) fprintf(stderr,
+           "usage: scp [-pqrvBC46] [-F config] [-S program] [-P port]\n"
+           "           [-c cipher] [-i identity] [-o option]\n"
+           "           [[user@]host1:]file1 [...] [[user@]host2:]file2\n");
        exit(1);
 }
 
@@ -1011,11 +1008,11 @@ okname(cp0)
 
        cp = cp0;
        do {
-               c = *cp;
+               c = (int)*cp;
                if (c & 0200)
                        goto bad;
                if (!isalpha(c) && !isdigit(c) &&
-                   c != '_' && c != '-' && c != '.' && c != '+')
+                   c != '@' && c != '_' && c != '-' && c != '.' && c != '+')
                        goto bad;
        } while (*++cp);
        return (1);
@@ -1030,27 +1027,26 @@ allocbuf(bp, fd, blksize)
        int fd, 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);
 }
@@ -1060,177 +1056,9 @@ lostconn(signo)
        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.064935 seconds and 4 git commands to generate.