X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/188adeb23a3cbd4165c39be879a95161f7e16807..b65c3807cf26816238f1ddcd06979c059425e470:/scp.c diff --git a/scp.c b/scp.c index 72949d0e..44b5b458 100644 --- 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 @@ -75,74 +75,38 @@ */ #include "includes.h" -RCSID("$OpenBSD: scp.c,v 1.40 2000/09/21 11:11:42 markus Exp $"); +RCSID("$OpenBSD: scp.c,v 1.97 2003/01/10 08:19:07 fgsch Exp $"); -#include "ssh.h" #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 -#define _PATH_CP "cp" - -/* 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); - -/* Time a transfer started. */ -static struct timeval start; - -/* Number of bytes of current file transferred so far. */ -volatile unsigned long statbytes; - -/* Total size of current file. */ -off_t totalbytes = 0; +/* Struct for addargs */ +arglist args; /* Name of current file being transferred. */ char *curfile; -/* This is set to non-zero if IPv4 is desired. */ -int IPv4 = 0; - -/* This is set to non-zero if IPv6 is desired. */ -int IPv6 = 0; - /* This is set to non-zero to enable verbose mode. */ int verbose_mode = 0; -/* This is set to non-zero if compression is desired. */ -int compress_flag = 0; - /* This is set to zero if the progressmeter is not desired. */ int showprogress = 1; -/* This is set to non-zero if running in batch mode (that is, password - and passphrase queries are not allowed). */ -int batchmode = 0; - -/* This is set to the cipher type string if given on the command line. */ -char *cipher = NULL; - -/* This is set to the RSA authentication identity file name if given on - the command line. */ -char *identity = NULL; - -/* This is the port to use in contacting the remote site (is non-NULL). */ -char *port = NULL; - /* This is the program to execute for the secured connection. ("ssh" or -S) */ -char *ssh_program = SSH_PROGRAM; +char *ssh_program = _PATH_SSH_PROGRAM; + +/* This is used to store the pid of ssh_program */ +pid_t do_cmd_pid; /* * This function executes the given command as the specified user on the @@ -156,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: host %s, user %s, command %s\n", - 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 @@ -176,10 +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) { - char *args[100]; /* XXX careful */ - unsigned int i; - + do_cmd_pid = fork(); + if (do_cmd_pid == 0) { /* Child. */ close(pin[1]); close(pout[0]); @@ -188,43 +152,17 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc) close(pin[0]); close(pout[1]); - i = 0; - args[i++] = ssh_program; - args[i++] = "-x"; - args[i++] = "-oFallBackToRsh no"; - if (IPv4) - args[i++] = "-4"; - if (IPv6) - args[i++] = "-6"; - if (verbose_mode) - args[i++] = "-v"; - if (compress_flag) - args[i++] = "-C"; - if (batchmode) - args[i++] = "-oBatchMode yes"; - if (cipher != NULL) { - args[i++] = "-c"; - args[i++] = cipher; - } - if (identity != NULL) { - args[i++] = "-i"; - args[i++] = identity; - } - if (port != NULL) { - args[i++] = "-p"; - args[i++] = port; - } - if (remuser != NULL) { - args[i++] = "-l"; - args[i++] = remuser; - } - args[i++] = host; - args[i++] = cmd; - args[i++] = NULL; + args.list[0] = ssh_program; + if (remuser != NULL) + addargs(&args, "-l%s", remuser); + addargs(&args, "%s", host); + addargs(&args, "%s", cmd); - execvp(ssh_program, args); + 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]); @@ -234,28 +172,12 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc) return 0; } -void -fatal(const char *fmt,...) -{ - va_list ap; - char buf[1024]; - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - fprintf(stderr, "%s\n", buf); - exit(255); -} - typedef struct { int cnt; char *buf; } BUF; -extern int iamremote; - BUF *allocbuf(BUF *, int, int); -char *colon(char *); void lostconn(int); void nospace(void); int okname(char *); @@ -283,32 +205,55 @@ main(argc, argv) int argc; char *argv[]; { - int ch, fflag, tflag; + int ch, fflag, tflag, status; char *targ; extern char *optarg; extern int optind; + __progname = get_progname(argv[0]); + + args.list = NULL; + 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:")) != EOF) + while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:F:")) != -1) switch (ch) { /* User-visible flags. */ case '4': - IPv4 = 1; - break; case '6': - IPv6 = 1; + case 'C': + addargs(&args, "-%c", ch); break; - case 'p': - pflag = 1; + case 'o': + case 'c': + case 'i': + case 'F': + addargs(&args, "-%c%s", ch, optarg); break; case 'P': - port = optarg; + addargs(&args, "-p%s", optarg); + break; + case 'B': + addargs(&args, "-oBatchmode yes"); + break; + case 'p': + pflag = 1; break; case 'r': iamrecursive = 1; break; case 'S': - ssh_program = optarg; + ssh_program = xstrdup(optarg); + break; + case 'v': + addargs(&args, "-v"); + verbose_mode = 1; + break; + case 'q': + showprogress = 0; break; /* Server options. */ @@ -322,26 +267,10 @@ main(argc, argv) case 't': /* "to" */ iamremote = 1; tflag = 1; +#ifdef HAVE_CYGWIN + setmode(0, O_BINARY); +#endif break; - case 'c': - cipher = optarg; - break; - case 'i': - identity = optarg; - break; - case 'v': - verbose_mode = 1; - break; - case 'B': - batchmode = 1; - break; - case 'C': - compress_flag = 1; - break; - case 'q': - showprogress = 0; - break; - case '?': default: usage(); } @@ -357,7 +286,7 @@ main(argc, argv) remin = STDIN_FILENO; remout = STDOUT_FILENO; - if (fflag) { + if (fflag) { /* Follow "protocol", send data. */ (void) response(); source(argc, argv); @@ -374,8 +303,10 @@ main(argc, argv) targetshouldbedirectory = 1; remin = remout = -1; + do_cmd_pid = -1; /* Command to be executed on remote system using "ssh". */ - (void) sprintf(cmd, "scp%s%s%s%s", verbose_mode ? " -v" : "", + (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s", + verbose_mode ? " -v" : "", iamrecursive ? " -r" : "", pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); @@ -388,20 +319,25 @@ 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[]; @@ -414,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]; @@ -430,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; @@ -446,20 +385,22 @@ toremote(targ, argc, argv) suser = pwd->pw_name; else if (!okname(suser)) continue; - (void) sprintf(bp, - "%s%s -x -o'FallBackToRsh no' -n -l %s %s %s %s '%s%s%s:%s'", - ssh_program, verbose_mode ? " -v" : "", - suser, host, cmd, src, - tuser ? tuser : "", tuser ? "@" : "", - thost, targ); + snprintf(bp, len, + "%s%s %s -n " + "-l %s %s %s %s '%s%s%s:%s'", + ssh_program, verbose_mode ? " -v" : "", + ssh_options, suser, host, cmd, src, + tuser ? tuser : "", tuser ? "@" : "", + thost, targ); } else { host = cleanhostname(argv[i]); - (void) sprintf(bp, - "exec %s%s -x -o'FallBackToRsh no' -n %s %s %s '%s%s%s:%s'", - ssh_program, verbose_mode ? " -v" : "", - host, cmd, src, - tuser ? tuser : "", tuser ? "@" : "", - thost, targ); + snprintf(bp, len, + "exec %s%s %s -n %s " + "%s %s '%s%s%s:%s'", + ssh_program, verbose_mode ? " -v" : "", + ssh_options, host, cmd, src, + tuser ? tuser : "", tuser ? "@" : "", + thost, targ); } if (verbose_mode) fprintf(stderr, "Executing: %s\n", bp); @@ -469,7 +410,7 @@ toremote(targ, argc, argv) if (remin == -1) { len = strlen(targ) + CMDNEEDS + 20; bp = xmalloc(len); - (void) sprintf(bp, "%s -t %s", cmd, targ); + (void) snprintf(bp, len, "%s -t %s", cmd, targ); host = cleanhostname(thost); if (do_cmd(host, tuser, bp, &remin, &remout, argc) < 0) @@ -496,7 +437,7 @@ tolocal(argc, argv) len = strlen(_PATH_CP) + strlen(argv[i]) + strlen(argv[argc - 1]) + 20; bp = xmalloc(len); - (void) sprintf(bp, "exec %s%s%s %s %s", _PATH_CP, + (void) snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, iamrecursive ? " -r" : "", pflag ? " -p" : "", argv[i], argv[argc - 1]); if (verbose_mode) @@ -509,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 { @@ -523,7 +464,7 @@ tolocal(argc, argv) host = cleanhostname(host); len = strlen(src) + CMDNEEDS + 20; bp = xmalloc(len); - (void) sprintf(bp, "%s -f %s", cmd, src); + (void) snprintf(bp, len, "%s -f %s", cmd, src); if (do_cmd(host, suser, bp, &remin, &remout, argc) < 0) { (void) xfree(bp); ++errs; @@ -544,13 +485,22 @@ source(argc, argv) struct stat stb; static BUF buffer; BUF *bp; - off_t i; - int amt, fd, haderr, indx, result; + off_t i, amt, result, statbytes; + int fd, 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) { @@ -580,21 +530,26 @@ syserr: run_err("%s: %s", name, strerror(errno)); * Make it compatible with possible future * versions expecting microseconds. */ - (void) sprintf(buf, "T%lu 0 %lu 0\n", - (unsigned long) stb.st_mtime, - (unsigned long) stb.st_atime); + (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)); if (response() < 0) goto next; } #define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) - (void) sprintf(buf, "C%04o %lu %s\n", - (unsigned int) (stb.st_mode & FILEMODEMASK), - (unsigned long) stb.st_size, - last); +#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 if (verbose_mode) { fprintf(stderr, "Sending file modes: %s", buf); - fflush(stderr); } (void) atomicio(write, remout, buf, strlen(buf)); if (response() < 0) @@ -603,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; @@ -627,7 +580,7 @@ next: (void) close(fd); } } if (showprogress) - progressmeter(1); + stop_progress_meter(); if (close(fd) < 0 && !haderr) haderr = errno; @@ -658,17 +611,17 @@ rsource(name, statp) else last++; if (pflag) { - (void) sprintf(path, "T%lu 0 %lu 0\n", - (unsigned long) statp->st_mtime, - (unsigned long) statp->st_atime); + (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)); if (response() < 0) { closedir(dirp); return; } } - (void) sprintf(path, "D%04o %d %.1024s\n", - (unsigned int) (statp->st_mode & FILEMODEMASK), 0, last); + (void) snprintf(path, sizeof path, "D%04o %d %.1024s\n", + (u_int) (statp->st_mode & FILEMODEMASK), 0, last); if (verbose_mode) fprintf(stderr, "Entering directory: %s", path); (void) atomicio(write, remout, path, strlen(path)); @@ -676,7 +629,7 @@ rsource(name, statp) 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, "..")) @@ -685,7 +638,7 @@ rsource(name, statp) run_err("%s/%s: name too long", name, dp->d_name); continue; } - (void) sprintf(path, "%s/%s", name, dp->d_name); + (void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name); vect[0] = path; source(1, vect); } @@ -707,13 +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]; - int dummy_usec; struct timeval tv[2]; -#define SCREWUP(str) { why = str; goto screwup; } +#define atime tv[0] +#define mtime tv[1] +#define SCREWUP(str) do { why = str; goto screwup; } while (0) setimes = targisdir = 0; mask = umask(0); @@ -746,7 +700,7 @@ sink(argc, argv) if (buf[0] == '\01' || buf[0] == '\02') { if (iamremote == 0) (void) atomicio(write, STDERR_FILENO, - buf + 1, strlen(buf + 1)); + buf + 1, strlen(buf + 1)); if (buf[0] == '\02') exit(1); ++errs; @@ -759,25 +713,21 @@ sink(argc, argv) 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); continue; @@ -805,7 +755,7 @@ 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"); @@ -815,10 +765,14 @@ sink(argc, argv) size_t need; need = strlen(targ) + strlen(cp) + 250; - if (need > cursize) + if (need > cursize) { + if (namebuf) + xfree(namebuf); namebuf = xmalloc(need); - (void) sprintf(namebuf, "%s%s%s", targ, - *targ ? "/" : "", cp); + cursize = need; + } + (void) snprintf(namebuf, need, "%s%s%s", targ, + strcmp(targ, "/") ? "/" : "", cp); np = namebuf; } else np = targ; @@ -840,21 +794,23 @@ sink(argc, argv) if (mkdir(np, mode | S_IRWXU) < 0) goto bad; } - vect[0] = np; + vect[0] = xstrdup(np); sink(1, vect); 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; } @@ -866,21 +822,22 @@ 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 = atomicio(read, remin, cp, amt); - if (j <= 0) { + j = read(remin, cp, amt); + if (j == -1 && (errno == EINTR || + errno == EAGAIN)) { + continue; + } else if (j <= 0) { run_err("%s", j ? strerror(errno) : - "dropped connection"); + "dropped connection"); exit(1); } amt -= j; @@ -901,28 +858,34 @@ 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 if (fchmod(ofd, omode)) +#else /* HAVE_FCHMOD */ + if (chmod(np, omode)) +#endif /* HAVE_FCHMOD */ run_err("%s: set mode: %s", - np, strerror(errno)); + np, strerror(errno)); } else { if (!exists && omode != mode) +#ifdef HAVE_FCHMOD if (fchmod(ofd, omode & ~mask)) +#else /* HAVE_FCHMOD */ + if (chmod(np, omode & ~mask)) +#endif /* HAVE_FCHMOD */ run_err("%s: set mode: %s", - np, strerror(errno)); + np, strerror(errno)); } if (close(ofd) == -1) { wrerr = YES; @@ -933,7 +896,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; } } @@ -954,7 +917,7 @@ screwup: } int -response() +response(void) { char ch, *cp, resp, rbuf[2048]; @@ -987,11 +950,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 [-pqrvBC46] [-F config] [-S program] [-P port]\n" + " [-c cipher] [-i identity] [-o option]\n" + " [[user@]host1:]file1 [...] [[user@]host2:]file2\n"); exit(1); } @@ -1020,30 +984,6 @@ 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; @@ -1068,10 +1008,11 @@ okname(cp0) cp = cp0; do { - c = *cp; + c = (int)*cp; if (c & 0200) goto bad; - if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') + if (!isalpha(c) && !isdigit(c) && + c != '@' && c != '_' && c != '-' && c != '.' && c != '+') goto bad; } while (*++cp); return (1); @@ -1086,23 +1027,26 @@ allocbuf(bp, fd, blksize) int fd, blksize; { size_t size; +#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_STRUCT_STAT_ST_BLKSIZE */ + size = 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); } @@ -1112,164 +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() -{ - static pid_t pgrp = -1; - int ctty_pgrp; - - if (pgrp == -1) - pgrp = getpgrp(); - -#ifdef HAVE_CYGWIN - /* - * Cygwin only supports tcgetpgrp() for getting the controlling tty - * currently. - */ - 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), " %5d %c%c ", - (int) 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 (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) { - struct sigaction sa; - sa.sa_handler = updateprogressmeter; - sigemptyset((sigset_t *)&sa.sa_mask); -#ifdef SA_RESTART - sa.sa_flags = SA_RESTART; -#endif - sigaction(SIGALRM, &sa, NULL); - 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); + exit(1); }