# HG changeset patch # User Matt Johnston # Date 1141827624 0 # Node ID b72f98803e4672021c48fcd822735b482f0223ab # Parent 92cc938b59a23c27bdfa0ef441d86e855c10c5a6 Update to scp from OpenSSH portable 4.3p2 diff -r 92cc938b59a2 -r b72f98803e46 options.h --- a/options.h Wed Mar 08 13:48:05 2006 +0000 +++ b/options.h Wed Mar 08 14:20:24 2006 +0000 @@ -252,6 +252,8 @@ #define _PATH_TTY "/dev/tty" +#define _PATH_CP "/bin/cp" + /* Timeouts in seconds */ #define SELECT_TIMEOUT 20 diff -r 92cc938b59a2 -r b72f98803e46 progressmeter.c --- a/progressmeter.c Wed Mar 08 13:48:05 2006 +0000 +++ b/progressmeter.c Wed Mar 08 14:20:24 2006 +0000 @@ -24,7 +24,7 @@ */ #include "includes.h" -/*RCSID("OpenBSD: progressmeter.c,v 1.15 2003/08/31 12:14:22 markus Exp ");*/ +/*RCSID("$OpenBSD: progressmeter.c,v 1.24 2005/06/07 13:25:23 jaredy Exp $");*/ #include "progressmeter.h" #include "atomicio.h" @@ -43,21 +43,26 @@ static void format_size(char *, int, off_t); static void format_rate(char *, int, off_t); +/* window resizing */ +static void sig_winch(int); +static void setscreensize(void); + /* updates the progressmeter to reflect the current state of the transfer */ void refresh_progress_meter(void); /* signal handler for updating the progress meter */ static void update_progress_meter(int); -static time_t start; /* start progress */ -static time_t last_update; /* last progress update */ -static char *file; /* name of the file being transferred */ -static off_t end_pos; /* ending position of transfer */ -static off_t cur_pos; /* transfer position as of last refresh */ +static time_t start; /* start progress */ +static time_t last_update; /* last progress update */ +static char *file; /* name of the file being transferred */ +static off_t end_pos; /* ending position of transfer */ +static off_t cur_pos; /* transfer position as of last refresh */ static volatile off_t *counter; /* progress counter */ -static long stalled; /* how long we have been stalled */ -static int bytes_per_second; /* current speed in bytes per second */ -static int win_size; /* terminal window size */ +static long stalled; /* how long we have been stalled */ +static int bytes_per_second; /* current speed in bytes per second */ +static int win_size; /* terminal window size */ +static volatile sig_atomic_t win_resized; /* for window resizing */ /* units for format_size */ static const char unit[] = " KMGT"; @@ -81,8 +86,8 @@ bytes = (bytes + 512) / 1024; } snprintf(buf, size, "%3lld.%1lld%c%s", - (int64_t) bytes / 100, - (int64_t) (bytes + 5) / 10 % 10, + (long long) (bytes + 5) / 100, + (long long) (bytes + 5) / 10 % 10, unit[i], i ? "B" : " "); } @@ -95,7 +100,7 @@ for (i = 0; bytes >= 10000 && unit[i] != 'T'; i++) bytes = (bytes + 512) / 1024; snprintf(buf, size, "%4lld%c%s", - (int64_t) bytes, + (long long) bytes, unit[i], i ? "B" : " "); } @@ -108,7 +113,7 @@ off_t transferred; double elapsed; int percent; - int bytes_left; + off_t bytes_left; int cur_speed; int hours, minutes, seconds; int i, len; @@ -121,14 +126,18 @@ if (bytes_left > 0) elapsed = now - last_update; - else + else { elapsed = now - start; + /* Calculate true total speed when done */ + transferred = end_pos; + bytes_per_second = 0; + } /* calculate speed */ if (elapsed != 0) cur_speed = (transferred / elapsed); else - cur_speed = 0; + cur_speed = transferred; #define AGE_FACTOR 0.9 if (bytes_per_second != 0) { @@ -144,6 +153,8 @@ len = snprintf(buf, file_len + 1, "\r%s", file); if (len < 0) len = 0; + if (len >= file_len + 1) + len = file_len; for (i = len; i < file_len; i++ ) buf[i] = ' '; buf[file_len] = '\0'; @@ -164,7 +175,7 @@ /* bandwidth usage */ format_rate(buf + strlen(buf), win_size - strlen(buf), - bytes_per_second); + (off_t)bytes_per_second); strlcat(buf, "/s ", win_size); /* ETA */ @@ -201,7 +212,7 @@ strlcat(buf, " ", win_size); } - atomicio(vwrite, STDOUT_FILENO, buf, win_size); + atomicio(vwrite, STDOUT_FILENO, buf, win_size - 1); last_update = now; } @@ -212,6 +223,10 @@ save_errno = errno; + if (win_resized) { + setscreensize(); + win_resized = 0; + } if (can_output()) refresh_progress_meter(); @@ -221,32 +236,22 @@ } void -start_progress_meter(char *f, off_t filesize, off_t *stat) +start_progress_meter(char *f, off_t filesize, off_t *ctr) { - struct winsize winsize; - start = last_update = time(NULL); file = f; end_pos = filesize; cur_pos = 0; - counter = stat; + counter = ctr; stalled = 0; bytes_per_second = 0; - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) != -1 && - winsize.ws_col != 0) { - if (winsize.ws_col > MAX_WINSIZE) - win_size = MAX_WINSIZE; - else - win_size = winsize.ws_col; - } else - win_size = DEFAULT_WINSIZE; - win_size += 1; /* trailing \0 */ - + setscreensize(); if (can_output()) refresh_progress_meter(); signal(SIGALRM, update_progress_meter); + signal(SIGWINCH, sig_winch); alarm(UPDATE_INTERVAL); } @@ -264,4 +269,26 @@ atomicio(vwrite, STDOUT_FILENO, "\n", 1); } + +static void +sig_winch(int sig) +{ + win_resized = 1; +} + +static void +setscreensize(void) +{ + struct winsize winsize; + + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) != -1 && + winsize.ws_col != 0) { + if (winsize.ws_col > MAX_WINSIZE) + win_size = MAX_WINSIZE; + else + win_size = winsize.ws_col; + } else + win_size = DEFAULT_WINSIZE; + win_size += 1; /* trailing \0 */ +} #endif /* PROGRESS_METER */ diff -r 92cc938b59a2 -r b72f98803e46 scp.c --- a/scp.c Wed Mar 08 13:48:05 2006 +0000 +++ b/scp.c Wed Mar 08 14:20:24 2006 +0000 @@ -71,40 +71,20 @@ */ #include "includes.h" +/*RCSID("$OpenBSD: scp.c,v 1.130 2006/01/31 10:35:43 djm Exp $");*/ + #include "atomicio.h" #include "compat.h" #include "scpmisc.h" #include "progressmeter.h" -#define _PATH_CP "/bin/cp" - -#ifndef TIMEVAL_TO_TIMESPEC -#define TIMEVAL_TO_TIMESPEC(tv, ts) { \ - (ts)->tv_sec = (tv)->tv_sec; \ - (ts)->tv_nsec = (tv)->tv_usec * 1000; \ -} -#endif - -#ifndef timersub -#define timersub(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ - if ((vvp)->tv_usec < 0) { \ - (vvp)->tv_sec--; \ - (vvp)->tv_usec += 1000000; \ - } \ - } while (/* CONSTCOND */ 0) -#endif /* timersub */ - - void bwlimit(int); /* Struct for addargs */ arglist args; /* Bandwidth limit */ -off_t limitbw = 0; +off_t limit_rate = 0; /* Name of current file being transferred. */ char *curfile; @@ -112,10 +92,8 @@ /* This is set to non-zero to enable verbose mode. */ int verbose_mode = 0; -#ifdef PROGRESS_METER /* This is set to zero if the progressmeter is not desired. */ int showprogress = 1; -#endif /* This is the program to execute for the secured connection. ("ssh" or -S) */ char *ssh_program = _PATH_SSH_PROGRAM; @@ -126,10 +104,56 @@ static void killchild(int signo) { - if (do_cmd_pid > 1) - kill(do_cmd_pid, 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); +} + +static int +do_local_cmd(arglist *a) +{ + u_int i; + int status; + pid_t pid; + + if (a->num == 0) + fatal("do_local_cmd: no arguments"); - _exit(1); + if (verbose_mode) { + fprintf(stderr, "Executing:"); + for (i = 0; i < a->num; i++) + fprintf(stderr, " %s", a->list[i]); + fprintf(stderr, "\n"); + } + if ((pid = fork()) == -1) + fatal("do_local_cmd: fork: %s", strerror(errno)); + + if (pid == 0) { + execvp(a->list[0], a->list); + perror(a->list[0]); + exit(1); + } + + do_cmd_pid = pid; + signal(SIGTERM, killchild); + signal(SIGINT, killchild); + signal(SIGHUP, killchild); + + while (waitpid(pid, &status, 0) == -1) + if (errno != EINTR) + fatal("do_local_cmd: waitpid: %s", strerror(errno)); + + do_cmd_pid = -1; + + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + return (-1); + + return (0); } /* @@ -156,11 +180,10 @@ pipe(reserved); /* Create a socket pair for communicating with ssh. */ - if (pipe(pin) < 0 || pipe(pout) < 0) - { - fprintf(stderr, "Fatal error: pipe: %s\n", strerror(errno)); - exit(1); - } + if (pipe(pin) < 0) + fatal("pipe: %s", strerror(errno)); + if (pipe(pout) < 0) + fatal("pipe: %s", strerror(errno)); /* Free the reserved descriptors. */ close(reserved[0]); @@ -169,19 +192,20 @@ /* uClinux needs to build the args here before vforking, otherwise we do it later on. */ #ifdef __uClinux__ - args.list[0] = ssh_program; - if (remuser != NULL) - addargs(&args, "-l%s", remuser); - addargs(&args, "%s", host); - addargs(&args, "%s", cmd); + replacearg(&args, 0, "%s", ssh_program); + if (remuser != NULL) + addargs(&args, "-l%s", remuser); + addargs(&args, "%s", host); + addargs(&args, "%s", cmd); #endif /* __uClinux__ */ /* Fork a child to execute the command on the remote host using ssh. */ -#ifdef __uClinux__ +#ifndef __uClinux__ do_cmd_pid = vfork(); #else do_cmd_pid = fork(); #endif /* __uClinux__ */ + if (do_cmd_pid == 0) { /* Child. */ close(pin[1]); @@ -192,38 +216,39 @@ close(pout[1]); #ifndef __uClinux__ - args.list[0] = ssh_program; - if (remuser != NULL) { - addargs(&args, "-l"); - addargs(&args, "%s", remuser); - } + replacearg(&args, 0, "%s", ssh_program); + if (remuser != NULL) + addargs(&args, "-l%s", remuser); addargs(&args, "%s", host); addargs(&args, "%s", cmd); -#endif +#endif /* __uClinux__ */ execvp(ssh_program, args.list); perror(ssh_program); exit(1); } else if (do_cmd_pid == -1) { - fprintf(stderr, "Fatal error: fork: %s\n", strerror(errno)); - exit(1); + fatal("fork: %s", strerror(errno)); } + #ifdef __uClinux__ /* clean up command */ /* pop cmd */ - xfree(args->list[--args->num]); - args->list[args->num]=NULL; + xfree(args->list[args->num-1]); + args->list[args->num-1]=NULL; + args->num--; /* pop host */ - xfree(args->list[--args->num-1]); - args->list[args->num]=NULL; + xfree(args->list[args->num-1]); + args->list[args->num-1]=NULL; + args->num--; /* pop user */ if (remuser != NULL) { - xfree(args->list[--args->num-1]); - args->list[args->num]=NULL; + xfree(args->list[args->num-1]); + args->list[args->num-1]=NULL; + args->num--; } #endif /* __uClinux__ */ - + /* Parent. Close the other side, and return the local side. */ close(pin[0]); *fdout = pin[1]; @@ -236,7 +261,7 @@ } typedef struct { - int cnt; + size_t cnt; char *buf; } BUF; @@ -267,6 +292,7 @@ #if defined(DBMULTI_scp) && defined(DROPBEAR_MULTI) int scp_main(int argc, char **argv) #else +int main(int argc, char **argv) #endif { @@ -276,10 +302,15 @@ extern char *optarg; extern int optind; + /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ + sanitise_stdfd(); + + memset(&args, '\0', sizeof(args)); args.list = NULL; - addargs(&args, "ssh"); /* overwritten with ssh_program */ + addargs(&args, "%s", ssh_program); addargs(&args, "-x"); addargs(&args, "-oForwardAgent no"); + addargs(&args, "-oPermitLocalCommand no"); addargs(&args, "-oClearAllForwardings yes"); fflag = tflag = 0; @@ -309,7 +340,7 @@ speed = strtod(optarg, &endp); if (speed <= 0 || *endp != '\0') usage(); - limitbw = speed * 1024; + limit_rate = speed * 1024; break; case 'p': pflag = 1; @@ -326,6 +357,7 @@ break; #ifdef PROGRESS_METER case 'q': + addargs(&args, "-q"); showprogress = 0; break; #endif @@ -351,14 +383,11 @@ argc -= optind; argv += optind; - if ((pwd = getpwuid(userid = getuid())) == NULL) { - fprintf(stderr, "unknown user %u", (u_int) userid); - } + if ((pwd = getpwuid(userid = getuid())) == NULL) + fatal("unknown user %u", (u_int) userid); -#ifdef PROGRESS_METER if (!isatty(STDERR_FILENO)) showprogress = 0; -#endif remin = STDIN_FILENO; remout = STDOUT_FILENO; @@ -392,9 +421,9 @@ if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ toremote(targ, argc, argv); else { - tolocal(argc, argv); /* Dest is local host. */ if (targetshouldbedirectory) verifydir(argv[argc - 1]); + tolocal(argc, argv); /* Dest is local host. */ } /* * Finally check the exit status of the ssh process, if one was forked @@ -414,78 +443,76 @@ } exit(errs != 0); } -#endif /* DBMULTI stuff */ +#endif /* DBMULTI_scp stuff */ void 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; + arglist alist; + + memset(&alist, '\0', sizeof(alist)); + alist.list = NULL; *targ++ = 0; if (*targ == 0) targ = "."; - if ((thost = strrchr(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 { - thost = argv[argc - 1]; + thost = arg; tuser = NULL; } + if (tuser != NULL && !okname(tuser)) { + xfree(arg); + return; + } + for (i = 0; i < argc - 1; i++) { src = colon(argv[i]); if (src) { /* remote to remote */ - static char *ssh_options = - "-x -o'ClearAllForwardings yes'"; + freeargs(&alist); + addargs(&alist, "%s", ssh_program); + if (verbose_mode) + addargs(&alist, "-v"); + addargs(&alist, "-x"); + addargs(&alist, "-oClearAllForwardings yes"); + addargs(&alist, "-n"); + *src++ = 0; if (*src == 0) src = "."; host = strrchr(argv[i], '@'); - len = strlen(ssh_program) + strlen(argv[i]) + - strlen(src) + (tuser ? strlen(tuser) : 0) + - strlen(thost) + strlen(targ) + - strlen(ssh_options) + CMDNEEDS + 20; - bp = xmalloc(len); + if (host) { *host++ = 0; host = cleanhostname(host); suser = argv[i]; if (*suser == '\0') suser = pwd->pw_name; - else if (!okname(suser)) { - xfree(bp); - continue; - } - if (tuser && !okname(tuser)) { - xfree(bp); + else if (!okname(suser)) continue; - } - 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); + addargs(&alist, "-l"); + addargs(&alist, "%s", suser); } else { host = cleanhostname(argv[i]); - 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); - (void) system(bp); - (void) xfree(bp); + addargs(&alist, "%s", host); + addargs(&alist, "%s", cmd); + addargs(&alist, "%s", src); + addargs(&alist, "%s%s%s:%s", + tuser ? tuser : "", tuser ? "@" : "", + thost, targ); + if (do_local_cmd(&alist) != 0) + errs = 1; } else { /* local to remote */ if (remin == -1) { len = strlen(targ) + CMDNEEDS + 20; @@ -509,20 +536,23 @@ { int i, len; char *bp, *host, *src, *suser; + arglist alist; + + memset(&alist, '\0', sizeof(alist)); + alist.list = NULL; for (i = 0; i < argc - 1; i++) { if (!(src = colon(argv[i]))) { /* Local to local. */ - len = strlen(_PATH_CP) + strlen(argv[i]) + - strlen(argv[argc - 1]) + 20; - bp = xmalloc(len); - (void) snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, - iamrecursive ? " -r" : "", pflag ? " -p" : "", - argv[i], argv[argc - 1]); - if (verbose_mode) - fprintf(stderr, "Executing: %s\n", bp); - if (system(bp)) + freeargs(&alist); + addargs(&alist, "%s", _PATH_CP); + if (iamrecursive) + addargs(&alist, "-r"); + if (pflag) + addargs(&alist, "-p"); + addargs(&alist, "%s", argv[i]); + addargs(&alist, "%s", argv[argc-1]); + if (do_local_cmd(&alist)) ++errs; - (void) xfree(bp); continue; } *src++ = 0; @@ -559,8 +589,9 @@ struct stat stb; static BUF buffer; BUF *bp; - off_t i, amt, result, statbytes; - int fd, haderr, indx; + off_t i, amt, statbytes; + size_t result; + int fd = -1, haderr, indx; char *last, *name, buf[2048]; int len; @@ -614,7 +645,7 @@ #define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) snprintf(buf, sizeof buf, "C%04o %lld %s\n", (u_int) (stb.st_mode & FILEMODEMASK), - (int64_t)stb.st_size, last); + (long long)stb.st_size, last); if (verbose_mode) { fprintf(stderr, "Sending file modes: %s", buf); } @@ -622,10 +653,13 @@ 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; } -#ifdef PROGRESS_METER +#if PROGRESS_METER if (showprogress) start_progress_meter(curfile, stb.st_size, &statbytes); #endif @@ -637,17 +671,17 @@ if (!haderr) { result = atomicio(read, fd, bp->buf, amt); if (result != amt) - haderr = result >= 0 ? EIO : errno; + haderr = errno; } if (haderr) (void) atomicio(vwrite, remout, bp->buf, amt); else { result = atomicio(vwrite, remout, bp->buf, amt); if (result != amt) - haderr = result >= 0 ? EIO : errno; + haderr = errno; statbytes += result; } - if (limitbw) + if (limit_rate) bwlimit(amt); } #ifdef PROGRESS_METER @@ -655,8 +689,11 @@ stop_progress_meter(); #endif - if (close(fd) < 0 && !haderr) - haderr = errno; + if (fd != -1) { + if (close(fd) < 0 && !haderr) + haderr = errno; + fd = -1; + } if (!haderr) (void) atomicio(vwrite, remout, "", 1); else @@ -723,7 +760,7 @@ { static struct timeval bwstart, bwend; static int lamt, thresh = 16384; - uint64_t wait; + u_int64_t waitlen; struct timespec ts, rm; if (!timerisset(&bwstart)) { @@ -741,10 +778,10 @@ return; lamt *= 8; - wait = (double)1000000L * lamt / limitbw; + waitlen = (double)1000000L * lamt / limit_rate; - bwstart.tv_sec = wait / 1000000L; - bwstart.tv_usec = wait % 1000000L; + bwstart.tv_sec = waitlen / 1000000L; + bwstart.tv_usec = waitlen % 1000000L; if (timercmp(&bwstart, &bwend, >)) { timersub(&bwstart, &bwend, &bwend); @@ -781,8 +818,9 @@ YES, NO, DISPLAYED } wrerr; BUF *bp; - off_t i, j; - int amt, count, exists, first, mask, mode, ofd, omode; + 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]; @@ -790,7 +828,7 @@ #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); @@ -809,7 +847,7 @@ 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 "); @@ -819,6 +857,8 @@ *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) @@ -882,9 +922,13 @@ 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; @@ -903,6 +947,8 @@ 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; @@ -956,11 +1002,8 @@ 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); @@ -969,17 +1012,17 @@ cp += j; statbytes += j; } while (amt > 0); - - if (limitbw) + + if (limit_rate) bwlimit(4096); if (count == bp->cnt) { /* Keep reading so we stay sync'd up. */ if (wrerr == NO) { - j = atomicio(vwrite, 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; @@ -991,9 +1034,9 @@ stop_progress_meter(); #endif if (count != 0 && wrerr == NO && - (j = atomicio(vwrite, ofd, bp->buf, count)) != count) { + atomicio(vwrite, ofd, bp->buf, count) != count) { wrerr = YES; - wrerrno = j >= 0 ? EIO : errno; + wrerrno = errno; } if (wrerr == NO && ftruncate(ofd, size) != 0) { run_err("%s: truncate: %s", np, strerror(errno)); @@ -1002,21 +1045,25 @@ 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; @@ -1084,8 +1131,8 @@ usage(void) { (void) fprintf(stderr, - "usage: scp [-pqrvBC1246] [-F config] [-S program] [-P port]\n" - " [-c cipher] [-i identity] [-l limit] [-o option]\n" + "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); } @@ -1126,7 +1173,7 @@ errno = ENOTDIR; } run_err("%s: %s", cp, strerror(errno)); - exit(1); + killchild(0); } int diff -r 92cc938b59a2 -r b72f98803e46 scpmisc.c --- a/scpmisc.c Wed Mar 08 13:48:05 2006 +0000 +++ b/scpmisc.c Wed Mar 08 14:20:24 2006 +0000 @@ -140,12 +140,15 @@ addargs(arglist *args, char *fmt, ...) { va_list ap; - char buf[1024]; - int nalloc; + char *cp; + u_int nalloc; + int r; va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); + r = vasprintf(&cp, fmt, ap); va_end(ap); + if (r == -1) + fatal("addargs: argument too long"); nalloc = args->nalloc; if (args->list == NULL) { @@ -156,6 +159,90 @@ args->list = xrealloc(args->list, nalloc * sizeof(char *)); args->nalloc = nalloc; - args->list[args->num++] = xstrdup(buf); + args->list[args->num++] = cp; args->list[args->num] = NULL; } + +void +replacearg(arglist *args, u_int which, char *fmt, ...) +{ + va_list ap; + char *cp; + int r; + + va_start(ap, fmt); + r = vasprintf(&cp, fmt, ap); + va_end(ap); + if (r == -1) + fatal("replacearg: argument too long"); + + if (which >= args->num) + fatal("replacearg: tried to replace invalid arg %d >= %d", + which, args->num); + xfree(args->list[which]); + args->list[which] = cp; +} + +void +freeargs(arglist *args) +{ + u_int i; + + if (args->list != NULL) { + for (i = 0; i < args->num; i++) + xfree(args->list[i]); + xfree(args->list); + args->nalloc = args->num = 0; + args->list = NULL; + } +} + +/* + * NB. duplicate __progname in case it is an alias for argv[0] + * Otherwise it may get clobbered by setproctitle() + */ +char *ssh_get_progname(char *argv0) +{ + char *p; + + if (argv0 == NULL) + return ("unknown"); /* XXX */ + p = strrchr(argv0, '/'); + if (p == NULL) + p = argv0; + else + p++; + + return (xstrdup(p)); +} + +void fatal(char* fmt,...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + exit(255); +} + +void +sanitise_stdfd(void) +{ + int nullfd, dupfd; + + if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { + fprintf(stderr, "Couldn't open /dev/null: %s", strerror(errno)); + exit(1); + } + while (++dupfd <= 2) { + /* Only clobber closed fds */ + if (fcntl(dupfd, F_GETFL, 0) >= 0) + continue; + if (dup2(nullfd, dupfd) == -1) { + fprintf(stderr, "dup2: %s", strerror(errno)); + exit(1); + } + } + if (nullfd > 2) + close(nullfd); +} diff -r 92cc938b59a2 -r b72f98803e46 scpmisc.h --- a/scpmisc.h Wed Mar 08 13:48:05 2006 +0000 +++ b/scpmisc.h Wed Mar 08 14:20:24 2006 +0000 @@ -34,6 +34,8 @@ int nalloc; }; void addargs(arglist *, char *, ...); +void replacearg(arglist *, u_int, char *, ...); +void freeargs(arglist *); /* from xmalloc.h */ void *xmalloc(size_t); @@ -41,4 +43,6 @@ void xfree(void *); char *xstrdup(const char *); - +char *ssh_get_progname(char *); +void fatal(char* fmt,...); +void sanitise_stdfd(void);