Update to scp from OpenSSH portable 4.3p2

--HG--
extra : convert_revision : e2bccdd6ba49edd575b1d0272c7dfee5f9f7acf6
This commit is contained in:
Matt Johnston 2006-03-08 14:20:24 +00:00
parent a7a5365af2
commit 3a5c4b68bb
5 changed files with 351 additions and 184 deletions

View File

@ -252,6 +252,8 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */
#define _PATH_TTY "/dev/tty" #define _PATH_TTY "/dev/tty"
#define _PATH_CP "/bin/cp"
/* Timeouts in seconds */ /* Timeouts in seconds */
#define SELECT_TIMEOUT 20 #define SELECT_TIMEOUT 20

View File

@ -24,7 +24,7 @@
*/ */
#include "includes.h" #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 "progressmeter.h"
#include "atomicio.h" #include "atomicio.h"
@ -43,21 +43,26 @@ static int can_output(void);
static void format_size(char *, int, off_t); static void format_size(char *, int, off_t);
static void format_rate(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 */ /* updates the progressmeter to reflect the current state of the transfer */
void refresh_progress_meter(void); void refresh_progress_meter(void);
/* signal handler for updating the progress meter */ /* signal handler for updating the progress meter */
static void update_progress_meter(int); static void update_progress_meter(int);
static time_t start; /* start progress */ static time_t start; /* start progress */
static time_t last_update; /* last progress update */ static time_t last_update; /* last progress update */
static char *file; /* name of the file being transferred */ static char *file; /* name of the file being transferred */
static off_t end_pos; /* ending position of transfer */ static off_t end_pos; /* ending position of transfer */
static off_t cur_pos; /* transfer position as of last refresh */ static off_t cur_pos; /* transfer position as of last refresh */
static volatile off_t *counter; /* progress counter */ static volatile off_t *counter; /* progress counter */
static long stalled; /* how long we have been stalled */ static long stalled; /* how long we have been stalled */
static int bytes_per_second; /* current speed in bytes per second */ static int bytes_per_second; /* current speed in bytes per second */
static int win_size; /* terminal window size */ static int win_size; /* terminal window size */
static volatile sig_atomic_t win_resized; /* for window resizing */
/* units for format_size */ /* units for format_size */
static const char unit[] = " KMGT"; static const char unit[] = " KMGT";
@ -81,8 +86,8 @@ format_rate(char *buf, int size, off_t bytes)
bytes = (bytes + 512) / 1024; bytes = (bytes + 512) / 1024;
} }
snprintf(buf, size, "%3lld.%1lld%c%s", snprintf(buf, size, "%3lld.%1lld%c%s",
(int64_t) bytes / 100, (long long) (bytes + 5) / 100,
(int64_t) (bytes + 5) / 10 % 10, (long long) (bytes + 5) / 10 % 10,
unit[i], unit[i],
i ? "B" : " "); i ? "B" : " ");
} }
@ -95,7 +100,7 @@ format_size(char *buf, int size, off_t bytes)
for (i = 0; bytes >= 10000 && unit[i] != 'T'; i++) for (i = 0; bytes >= 10000 && unit[i] != 'T'; i++)
bytes = (bytes + 512) / 1024; bytes = (bytes + 512) / 1024;
snprintf(buf, size, "%4lld%c%s", snprintf(buf, size, "%4lld%c%s",
(int64_t) bytes, (long long) bytes,
unit[i], unit[i],
i ? "B" : " "); i ? "B" : " ");
} }
@ -108,7 +113,7 @@ refresh_progress_meter(void)
off_t transferred; off_t transferred;
double elapsed; double elapsed;
int percent; int percent;
int bytes_left; off_t bytes_left;
int cur_speed; int cur_speed;
int hours, minutes, seconds; int hours, minutes, seconds;
int i, len; int i, len;
@ -121,14 +126,18 @@ refresh_progress_meter(void)
if (bytes_left > 0) if (bytes_left > 0)
elapsed = now - last_update; elapsed = now - last_update;
else else {
elapsed = now - start; elapsed = now - start;
/* Calculate true total speed when done */
transferred = end_pos;
bytes_per_second = 0;
}
/* calculate speed */ /* calculate speed */
if (elapsed != 0) if (elapsed != 0)
cur_speed = (transferred / elapsed); cur_speed = (transferred / elapsed);
else else
cur_speed = 0; cur_speed = transferred;
#define AGE_FACTOR 0.9 #define AGE_FACTOR 0.9
if (bytes_per_second != 0) { if (bytes_per_second != 0) {
@ -144,6 +153,8 @@ refresh_progress_meter(void)
len = snprintf(buf, file_len + 1, "\r%s", file); len = snprintf(buf, file_len + 1, "\r%s", file);
if (len < 0) if (len < 0)
len = 0; len = 0;
if (len >= file_len + 1)
len = file_len;
for (i = len; i < file_len; i++ ) for (i = len; i < file_len; i++ )
buf[i] = ' '; buf[i] = ' ';
buf[file_len] = '\0'; buf[file_len] = '\0';
@ -164,7 +175,7 @@ refresh_progress_meter(void)
/* bandwidth usage */ /* bandwidth usage */
format_rate(buf + strlen(buf), win_size - strlen(buf), format_rate(buf + strlen(buf), win_size - strlen(buf),
bytes_per_second); (off_t)bytes_per_second);
strlcat(buf, "/s ", win_size); strlcat(buf, "/s ", win_size);
/* ETA */ /* ETA */
@ -201,7 +212,7 @@ refresh_progress_meter(void)
strlcat(buf, " ", win_size); strlcat(buf, " ", win_size);
} }
atomicio(vwrite, STDOUT_FILENO, buf, win_size); atomicio(vwrite, STDOUT_FILENO, buf, win_size - 1);
last_update = now; last_update = now;
} }
@ -212,6 +223,10 @@ update_progress_meter(int ignore)
save_errno = errno; save_errno = errno;
if (win_resized) {
setscreensize();
win_resized = 0;
}
if (can_output()) if (can_output())
refresh_progress_meter(); refresh_progress_meter();
@ -221,32 +236,22 @@ update_progress_meter(int ignore)
} }
void 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); start = last_update = time(NULL);
file = f; file = f;
end_pos = filesize; end_pos = filesize;
cur_pos = 0; cur_pos = 0;
counter = stat; counter = ctr;
stalled = 0; stalled = 0;
bytes_per_second = 0; bytes_per_second = 0;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) != -1 && setscreensize();
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 */
if (can_output()) if (can_output())
refresh_progress_meter(); refresh_progress_meter();
signal(SIGALRM, update_progress_meter); signal(SIGALRM, update_progress_meter);
signal(SIGWINCH, sig_winch);
alarm(UPDATE_INTERVAL); alarm(UPDATE_INTERVAL);
} }
@ -264,4 +269,26 @@ stop_progress_meter(void)
atomicio(vwrite, STDOUT_FILENO, "\n", 1); 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 */ #endif /* PROGRESS_METER */

343
scp.c
View File

@ -71,40 +71,20 @@
*/ */
#include "includes.h" #include "includes.h"
/*RCSID("$OpenBSD: scp.c,v 1.130 2006/01/31 10:35:43 djm Exp $");*/
#include "atomicio.h" #include "atomicio.h"
#include "compat.h" #include "compat.h"
#include "scpmisc.h" #include "scpmisc.h"
#include "progressmeter.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); void bwlimit(int);
/* Struct for addargs */ /* Struct for addargs */
arglist args; arglist args;
/* Bandwidth limit */ /* Bandwidth limit */
off_t limitbw = 0; off_t limit_rate = 0;
/* Name of current file being transferred. */ /* Name of current file being transferred. */
char *curfile; char *curfile;
@ -112,10 +92,8 @@ char *curfile;
/* This is set to non-zero to enable verbose mode. */ /* This is set to non-zero to enable verbose mode. */
int verbose_mode = 0; int verbose_mode = 0;
#ifdef PROGRESS_METER
/* This is set to zero if the progressmeter is not desired. */ /* This is set to zero if the progressmeter is not desired. */
int showprogress = 1; int showprogress = 1;
#endif
/* This is the program to execute for the secured connection. ("ssh" or -S) */ /* This is the program to execute for the secured connection. ("ssh" or -S) */
char *ssh_program = _PATH_SSH_PROGRAM; char *ssh_program = _PATH_SSH_PROGRAM;
@ -126,10 +104,56 @@ pid_t do_cmd_pid = -1;
static void static void
killchild(int signo) killchild(int signo)
{ {
if (do_cmd_pid > 1) if (do_cmd_pid > 1) {
kill(do_cmd_pid, signo); kill(do_cmd_pid, signo ? signo : SIGTERM);
waitpid(do_cmd_pid, NULL, 0);
}
_exit(1); 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");
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 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
pipe(reserved); pipe(reserved);
/* Create a socket pair for communicating with ssh. */ /* Create a socket pair for communicating with ssh. */
if (pipe(pin) < 0 || pipe(pout) < 0) if (pipe(pin) < 0)
{ fatal("pipe: %s", strerror(errno));
fprintf(stderr, "Fatal error: pipe: %s\n", strerror(errno)); if (pipe(pout) < 0)
exit(1); fatal("pipe: %s", strerror(errno));
}
/* Free the reserved descriptors. */ /* Free the reserved descriptors. */
close(reserved[0]); close(reserved[0]);
@ -169,19 +192,20 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
/* uClinux needs to build the args here before vforking, /* uClinux needs to build the args here before vforking,
otherwise we do it later on. */ otherwise we do it later on. */
#ifdef __uClinux__ #ifdef __uClinux__
args.list[0] = ssh_program; replacearg(&args, 0, "%s", ssh_program);
if (remuser != NULL) if (remuser != NULL)
addargs(&args, "-l%s", remuser); addargs(&args, "-l%s", remuser);
addargs(&args, "%s", host); addargs(&args, "%s", host);
addargs(&args, "%s", cmd); addargs(&args, "%s", cmd);
#endif /* __uClinux__ */ #endif /* __uClinux__ */
/* Fork a child to execute the command on the remote host using ssh. */ /* Fork a child to execute the command on the remote host using ssh. */
#ifdef __uClinux__ #ifndef __uClinux__
do_cmd_pid = vfork(); do_cmd_pid = vfork();
#else #else
do_cmd_pid = fork(); do_cmd_pid = fork();
#endif /* __uClinux__ */ #endif /* __uClinux__ */
if (do_cmd_pid == 0) { if (do_cmd_pid == 0) {
/* Child. */ /* Child. */
close(pin[1]); close(pin[1]);
@ -192,38 +216,39 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
close(pout[1]); close(pout[1]);
#ifndef __uClinux__ #ifndef __uClinux__
args.list[0] = ssh_program; replacearg(&args, 0, "%s", ssh_program);
if (remuser != NULL) { if (remuser != NULL)
addargs(&args, "-l"); addargs(&args, "-l%s", remuser);
addargs(&args, "%s", remuser);
}
addargs(&args, "%s", host); addargs(&args, "%s", host);
addargs(&args, "%s", cmd); addargs(&args, "%s", cmd);
#endif #endif /* __uClinux__ */
execvp(ssh_program, args.list); execvp(ssh_program, args.list);
perror(ssh_program); perror(ssh_program);
exit(1); exit(1);
} else if (do_cmd_pid == -1) { } else if (do_cmd_pid == -1) {
fprintf(stderr, "Fatal error: fork: %s\n", strerror(errno)); fatal("fork: %s", strerror(errno));
exit(1);
} }
#ifdef __uClinux__ #ifdef __uClinux__
/* clean up command */ /* clean up command */
/* pop cmd */ /* pop cmd */
xfree(args->list[--args->num]); xfree(args->list[args->num-1]);
args->list[args->num]=NULL; args->list[args->num-1]=NULL;
args->num--;
/* pop host */ /* pop host */
xfree(args->list[--args->num-1]); xfree(args->list[args->num-1]);
args->list[args->num]=NULL; args->list[args->num-1]=NULL;
args->num--;
/* pop user */ /* pop user */
if (remuser != NULL) { if (remuser != NULL) {
xfree(args->list[--args->num-1]); xfree(args->list[args->num-1]);
args->list[args->num]=NULL; args->list[args->num-1]=NULL;
args->num--;
} }
#endif /* __uClinux__ */ #endif /* __uClinux__ */
/* Parent. Close the other side, and return the local side. */ /* Parent. Close the other side, and return the local side. */
close(pin[0]); close(pin[0]);
*fdout = pin[1]; *fdout = pin[1];
@ -236,7 +261,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
} }
typedef struct { typedef struct {
int cnt; size_t cnt;
char *buf; char *buf;
} BUF; } BUF;
@ -267,6 +292,7 @@ void usage(void);
#if defined(DBMULTI_scp) && defined(DROPBEAR_MULTI) #if defined(DBMULTI_scp) && defined(DROPBEAR_MULTI)
int scp_main(int argc, char **argv) int scp_main(int argc, char **argv)
#else #else
int
main(int argc, char **argv) main(int argc, char **argv)
#endif #endif
{ {
@ -276,10 +302,15 @@ main(int argc, char **argv)
extern char *optarg; extern char *optarg;
extern int optind; 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; args.list = NULL;
addargs(&args, "ssh"); /* overwritten with ssh_program */ addargs(&args, "%s", ssh_program);
addargs(&args, "-x"); addargs(&args, "-x");
addargs(&args, "-oForwardAgent no"); addargs(&args, "-oForwardAgent no");
addargs(&args, "-oPermitLocalCommand no");
addargs(&args, "-oClearAllForwardings yes"); addargs(&args, "-oClearAllForwardings yes");
fflag = tflag = 0; fflag = tflag = 0;
@ -309,7 +340,7 @@ main(int argc, char **argv)
speed = strtod(optarg, &endp); speed = strtod(optarg, &endp);
if (speed <= 0 || *endp != '\0') if (speed <= 0 || *endp != '\0')
usage(); usage();
limitbw = speed * 1024; limit_rate = speed * 1024;
break; break;
case 'p': case 'p':
pflag = 1; pflag = 1;
@ -326,6 +357,7 @@ main(int argc, char **argv)
break; break;
#ifdef PROGRESS_METER #ifdef PROGRESS_METER
case 'q': case 'q':
addargs(&args, "-q");
showprogress = 0; showprogress = 0;
break; break;
#endif #endif
@ -351,14 +383,11 @@ main(int argc, char **argv)
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if ((pwd = getpwuid(userid = getuid())) == NULL) { if ((pwd = getpwuid(userid = getuid())) == NULL)
fprintf(stderr, "unknown user %u", (u_int) userid); fatal("unknown user %u", (u_int) userid);
}
#ifdef PROGRESS_METER
if (!isatty(STDERR_FILENO)) if (!isatty(STDERR_FILENO))
showprogress = 0; showprogress = 0;
#endif
remin = STDIN_FILENO; remin = STDIN_FILENO;
remout = STDOUT_FILENO; remout = STDOUT_FILENO;
@ -392,9 +421,9 @@ main(int argc, char **argv)
if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */
toremote(targ, argc, argv); toremote(targ, argc, argv);
else { else {
tolocal(argc, argv); /* Dest is local host. */
if (targetshouldbedirectory) if (targetshouldbedirectory)
verifydir(argv[argc - 1]); verifydir(argv[argc - 1]);
tolocal(argc, argv); /* Dest is local host. */
} }
/* /*
* Finally check the exit status of the ssh process, if one was forked * Finally check the exit status of the ssh process, if one was forked
@ -414,78 +443,76 @@ main(int argc, char **argv)
} }
exit(errs != 0); exit(errs != 0);
} }
#endif /* DBMULTI stuff */ #endif /* DBMULTI_scp stuff */
void void
toremote(char *targ, int argc, char **argv) toremote(char *targ, int argc, char **argv)
{ {
int i, len; 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; *targ++ = 0;
if (*targ == 0) if (*targ == 0)
targ = "."; targ = ".";
if ((thost = strrchr(argv[argc - 1], '@'))) { arg = xstrdup(argv[argc - 1]);
if ((thost = strrchr(arg, '@'))) {
/* user@host */ /* user@host */
*thost++ = 0; *thost++ = 0;
tuser = argv[argc - 1]; tuser = arg;
if (*tuser == '\0') if (*tuser == '\0')
tuser = NULL; tuser = NULL;
} else { } else {
thost = argv[argc - 1]; thost = arg;
tuser = NULL; tuser = NULL;
} }
if (tuser != NULL && !okname(tuser)) {
xfree(arg);
return;
}
for (i = 0; i < argc - 1; i++) { for (i = 0; i < argc - 1; i++) {
src = colon(argv[i]); src = colon(argv[i]);
if (src) { /* remote to remote */ if (src) { /* remote to remote */
static char *ssh_options = freeargs(&alist);
"-x -o'ClearAllForwardings yes'"; addargs(&alist, "%s", ssh_program);
if (verbose_mode)
addargs(&alist, "-v");
addargs(&alist, "-x");
addargs(&alist, "-oClearAllForwardings yes");
addargs(&alist, "-n");
*src++ = 0; *src++ = 0;
if (*src == 0) if (*src == 0)
src = "."; src = ".";
host = strrchr(argv[i], '@'); 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) { if (host) {
*host++ = 0; *host++ = 0;
host = cleanhostname(host); host = cleanhostname(host);
suser = argv[i]; suser = argv[i];
if (*suser == '\0') if (*suser == '\0')
suser = pwd->pw_name; suser = pwd->pw_name;
else if (!okname(suser)) { else if (!okname(suser))
xfree(bp);
continue; continue;
} addargs(&alist, "-l");
if (tuser && !okname(tuser)) { addargs(&alist, "%s", suser);
xfree(bp);
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);
} else { } else {
host = cleanhostname(argv[i]); 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) addargs(&alist, "%s", host);
fprintf(stderr, "Executing: %s\n", bp); addargs(&alist, "%s", cmd);
(void) system(bp); addargs(&alist, "%s", src);
(void) xfree(bp); addargs(&alist, "%s%s%s:%s",
tuser ? tuser : "", tuser ? "@" : "",
thost, targ);
if (do_local_cmd(&alist) != 0)
errs = 1;
} else { /* local to remote */ } else { /* local to remote */
if (remin == -1) { if (remin == -1) {
len = strlen(targ) + CMDNEEDS + 20; len = strlen(targ) + CMDNEEDS + 20;
@ -509,20 +536,23 @@ tolocal(int argc, char **argv)
{ {
int i, len; int i, len;
char *bp, *host, *src, *suser; char *bp, *host, *src, *suser;
arglist alist;
memset(&alist, '\0', sizeof(alist));
alist.list = NULL;
for (i = 0; i < argc - 1; i++) { for (i = 0; i < argc - 1; i++) {
if (!(src = colon(argv[i]))) { /* Local to local. */ if (!(src = colon(argv[i]))) { /* Local to local. */
len = strlen(_PATH_CP) + strlen(argv[i]) + freeargs(&alist);
strlen(argv[argc - 1]) + 20; addargs(&alist, "%s", _PATH_CP);
bp = xmalloc(len); if (iamrecursive)
(void) snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, addargs(&alist, "-r");
iamrecursive ? " -r" : "", pflag ? " -p" : "", if (pflag)
argv[i], argv[argc - 1]); addargs(&alist, "-p");
if (verbose_mode) addargs(&alist, "%s", argv[i]);
fprintf(stderr, "Executing: %s\n", bp); addargs(&alist, "%s", argv[argc-1]);
if (system(bp)) if (do_local_cmd(&alist))
++errs; ++errs;
(void) xfree(bp);
continue; continue;
} }
*src++ = 0; *src++ = 0;
@ -559,8 +589,9 @@ source(int argc, char **argv)
struct stat stb; struct stat stb;
static BUF buffer; static BUF buffer;
BUF *bp; BUF *bp;
off_t i, amt, result, statbytes; off_t i, amt, statbytes;
int fd, haderr, indx; size_t result;
int fd = -1, haderr, indx;
char *last, *name, buf[2048]; char *last, *name, buf[2048];
int len; int len;
@ -614,7 +645,7 @@ syserr: run_err("%s: %s", name, strerror(errno));
#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) #define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
snprintf(buf, sizeof buf, "C%04o %lld %s\n", snprintf(buf, sizeof buf, "C%04o %lld %s\n",
(u_int) (stb.st_mode & FILEMODEMASK), (u_int) (stb.st_mode & FILEMODEMASK),
(int64_t)stb.st_size, last); (long long)stb.st_size, last);
if (verbose_mode) { if (verbose_mode) {
fprintf(stderr, "Sending file modes: %s", buf); fprintf(stderr, "Sending file modes: %s", buf);
} }
@ -622,10 +653,13 @@ syserr: run_err("%s: %s", name, strerror(errno));
if (response() < 0) if (response() < 0)
goto next; goto next;
if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) { if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) {
next: (void) close(fd); next: if (fd != -1) {
(void) close(fd);
fd = -1;
}
continue; continue;
} }
#ifdef PROGRESS_METER #if PROGRESS_METER
if (showprogress) if (showprogress)
start_progress_meter(curfile, stb.st_size, &statbytes); start_progress_meter(curfile, stb.st_size, &statbytes);
#endif #endif
@ -637,17 +671,17 @@ next: (void) close(fd);
if (!haderr) { if (!haderr) {
result = atomicio(read, fd, bp->buf, amt); result = atomicio(read, fd, bp->buf, amt);
if (result != amt) if (result != amt)
haderr = result >= 0 ? EIO : errno; haderr = errno;
} }
if (haderr) if (haderr)
(void) atomicio(vwrite, remout, bp->buf, amt); (void) atomicio(vwrite, remout, bp->buf, amt);
else { else {
result = atomicio(vwrite, remout, bp->buf, amt); result = atomicio(vwrite, remout, bp->buf, amt);
if (result != amt) if (result != amt)
haderr = result >= 0 ? EIO : errno; haderr = errno;
statbytes += result; statbytes += result;
} }
if (limitbw) if (limit_rate)
bwlimit(amt); bwlimit(amt);
} }
#ifdef PROGRESS_METER #ifdef PROGRESS_METER
@ -655,8 +689,11 @@ next: (void) close(fd);
stop_progress_meter(); stop_progress_meter();
#endif #endif
if (close(fd) < 0 && !haderr) if (fd != -1) {
haderr = errno; if (close(fd) < 0 && !haderr)
haderr = errno;
fd = -1;
}
if (!haderr) if (!haderr)
(void) atomicio(vwrite, remout, "", 1); (void) atomicio(vwrite, remout, "", 1);
else else
@ -723,7 +760,7 @@ bwlimit(int amount)
{ {
static struct timeval bwstart, bwend; static struct timeval bwstart, bwend;
static int lamt, thresh = 16384; static int lamt, thresh = 16384;
uint64_t wait; u_int64_t waitlen;
struct timespec ts, rm; struct timespec ts, rm;
if (!timerisset(&bwstart)) { if (!timerisset(&bwstart)) {
@ -741,10 +778,10 @@ bwlimit(int amount)
return; return;
lamt *= 8; lamt *= 8;
wait = (double)1000000L * lamt / limitbw; waitlen = (double)1000000L * lamt / limit_rate;
bwstart.tv_sec = wait / 1000000L; bwstart.tv_sec = waitlen / 1000000L;
bwstart.tv_usec = wait % 1000000L; bwstart.tv_usec = waitlen % 1000000L;
if (timercmp(&bwstart, &bwend, >)) { if (timercmp(&bwstart, &bwend, >)) {
timersub(&bwstart, &bwend, &bwend); timersub(&bwstart, &bwend, &bwend);
@ -781,8 +818,9 @@ sink(int argc, char **argv)
YES, NO, DISPLAYED YES, NO, DISPLAYED
} wrerr; } wrerr;
BUF *bp; BUF *bp;
off_t i, j; off_t i;
int amt, count, exists, first, mask, mode, ofd, omode; size_t j, count;
int amt, exists, first, mask, mode, ofd, omode;
off_t size, statbytes; off_t size, statbytes;
int setimes, targisdir, wrerrno = 0; int setimes, targisdir, wrerrno = 0;
char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
@ -790,7 +828,7 @@ sink(int argc, char **argv)
#define atime tv[0] #define atime tv[0]
#define mtime tv[1] #define mtime tv[1]
#define SCREWUP(str) do { why = str; goto screwup; } while (0) #define SCREWUP(str) { why = str; goto screwup; }
setimes = targisdir = 0; setimes = targisdir = 0;
mask = umask(0); mask = umask(0);
@ -809,7 +847,7 @@ sink(int argc, char **argv)
targisdir = 1; targisdir = 1;
for (first = 1;; first = 0) { for (first = 1;; first = 0) {
cp = buf; cp = buf;
if (atomicio(read, remin, cp, 1) <= 0) if (atomicio(read, remin, cp, 1) != 1)
return; return;
if (*cp++ == '\n') if (*cp++ == '\n')
SCREWUP("unexpected <newline>"); SCREWUP("unexpected <newline>");
@ -819,6 +857,8 @@ sink(int argc, char **argv)
*cp++ = ch; *cp++ = ch;
} while (cp < &buf[sizeof(buf) - 1] && ch != '\n'); } while (cp < &buf[sizeof(buf) - 1] && ch != '\n');
*cp = 0; *cp = 0;
if (verbose_mode)
fprintf(stderr, "Sink: %s", buf);
if (buf[0] == '\01' || buf[0] == '\02') { if (buf[0] == '\01' || buf[0] == '\02') {
if (iamremote == 0) if (iamremote == 0)
@ -882,9 +922,13 @@ sink(int argc, char **argv)
size = size * 10 + (*cp++ - '0'); size = size * 10 + (*cp++ - '0');
if (*cp++ != ' ') if (*cp++ != ' ')
SCREWUP("size not delimited"); SCREWUP("size not delimited");
if ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) {
run_err("error: unexpected filename: %s", cp);
exit(1);
}
if (targisdir) { if (targisdir) {
static char *namebuf; static char *namebuf;
static int cursize; static size_t cursize;
size_t need; size_t need;
need = strlen(targ) + strlen(cp) + 250; need = strlen(targ) + strlen(cp) + 250;
@ -903,6 +947,8 @@ sink(int argc, char **argv)
exists = stat(np, &stb) == 0; exists = stat(np, &stb) == 0;
if (buf[0] == 'D') { if (buf[0] == 'D') {
int mod_flag = pflag; int mod_flag = pflag;
if (!iamrecursive)
SCREWUP("received directory without -r");
if (exists) { if (exists) {
if (!S_ISDIR(stb.st_mode)) { if (!S_ISDIR(stb.st_mode)) {
errno = ENOTDIR; errno = ENOTDIR;
@ -956,11 +1002,8 @@ bad: run_err("%s: %s", np, strerror(errno));
amt = size - i; amt = size - i;
count += amt; count += amt;
do { do {
j = read(remin, cp, amt); j = atomicio(read, remin, cp, amt);
if (j == -1 && (errno == EINTR || if (j == 0) {
errno == EAGAIN)) {
continue;
} else if (j <= 0) {
run_err("%s", j ? strerror(errno) : run_err("%s", j ? strerror(errno) :
"dropped connection"); "dropped connection");
exit(1); exit(1);
@ -969,17 +1012,17 @@ bad: run_err("%s: %s", np, strerror(errno));
cp += j; cp += j;
statbytes += j; statbytes += j;
} while (amt > 0); } while (amt > 0);
if (limitbw) if (limit_rate)
bwlimit(4096); bwlimit(4096);
if (count == bp->cnt) { if (count == bp->cnt) {
/* Keep reading so we stay sync'd up. */ /* Keep reading so we stay sync'd up. */
if (wrerr == NO) { if (wrerr == NO) {
j = atomicio(vwrite, ofd, bp->buf, count); if (atomicio(vwrite, ofd, bp->buf,
if (j != count) { count) != count) {
wrerr = YES; wrerr = YES;
wrerrno = j >= 0 ? EIO : errno; wrerrno = errno;
} }
} }
count = 0; count = 0;
@ -991,9 +1034,9 @@ bad: run_err("%s: %s", np, strerror(errno));
stop_progress_meter(); stop_progress_meter();
#endif #endif
if (count != 0 && wrerr == NO && if (count != 0 && wrerr == NO &&
(j = atomicio(vwrite, ofd, bp->buf, count)) != count) { atomicio(vwrite, ofd, bp->buf, count) != count) {
wrerr = YES; wrerr = YES;
wrerrno = j >= 0 ? EIO : errno; wrerrno = errno;
} }
if (wrerr == NO && ftruncate(ofd, size) != 0) { if (wrerr == NO && ftruncate(ofd, size) != 0) {
run_err("%s: truncate: %s", np, strerror(errno)); run_err("%s: truncate: %s", np, strerror(errno));
@ -1002,21 +1045,25 @@ bad: run_err("%s: %s", np, strerror(errno));
if (pflag) { if (pflag) {
if (exists || omode != mode) if (exists || omode != mode)
#ifdef HAVE_FCHMOD #ifdef HAVE_FCHMOD
if (fchmod(ofd, omode)) if (fchmod(ofd, omode)) {
#else /* HAVE_FCHMOD */ #else /* HAVE_FCHMOD */
if (chmod(np, omode)) if (chmod(np, omode)) {
#endif /* HAVE_FCHMOD */ #endif /* HAVE_FCHMOD */
run_err("%s: set mode: %s", run_err("%s: set mode: %s",
np, strerror(errno)); np, strerror(errno));
wrerr = DISPLAYED;
}
} else { } else {
if (!exists && omode != mode) if (!exists && omode != mode)
#ifdef HAVE_FCHMOD #ifdef HAVE_FCHMOD
if (fchmod(ofd, omode & ~mask)) if (fchmod(ofd, omode & ~mask)) {
#else /* HAVE_FCHMOD */ #else /* HAVE_FCHMOD */
if (chmod(np, omode & ~mask)) if (chmod(np, omode & ~mask)) {
#endif /* HAVE_FCHMOD */ #endif /* HAVE_FCHMOD */
run_err("%s: set mode: %s", run_err("%s: set mode: %s",
np, strerror(errno)); np, strerror(errno));
wrerr = DISPLAYED;
}
} }
if (close(ofd) == -1) { if (close(ofd) == -1) {
wrerr = YES; wrerr = YES;
@ -1084,8 +1131,8 @@ void
usage(void) usage(void)
{ {
(void) fprintf(stderr, (void) fprintf(stderr,
"usage: scp [-pqrvBC1246] [-F config] [-S program] [-P port]\n" "usage: scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
" [-c cipher] [-i identity] [-l limit] [-o option]\n" " [-l limit] [-o ssh_option] [-P port] [-S program]\n"
" [[user@]host1:]file1 [...] [[user@]host2:]file2\n"); " [[user@]host1:]file1 [...] [[user@]host2:]file2\n");
exit(1); exit(1);
} }
@ -1126,7 +1173,7 @@ verifydir(char *cp)
errno = ENOTDIR; errno = ENOTDIR;
} }
run_err("%s: %s", cp, strerror(errno)); run_err("%s: %s", cp, strerror(errno));
exit(1); killchild(0);
} }
int int

View File

@ -140,12 +140,15 @@ void
addargs(arglist *args, char *fmt, ...) addargs(arglist *args, char *fmt, ...)
{ {
va_list ap; va_list ap;
char buf[1024]; char *cp;
int nalloc; u_int nalloc;
int r;
va_start(ap, fmt); va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap); r = vasprintf(&cp, fmt, ap);
va_end(ap); va_end(ap);
if (r == -1)
fatal("addargs: argument too long");
nalloc = args->nalloc; nalloc = args->nalloc;
if (args->list == NULL) { if (args->list == NULL) {
@ -156,6 +159,90 @@ addargs(arglist *args, char *fmt, ...)
args->list = xrealloc(args->list, nalloc * sizeof(char *)); args->list = xrealloc(args->list, nalloc * sizeof(char *));
args->nalloc = nalloc; args->nalloc = nalloc;
args->list[args->num++] = xstrdup(buf); args->list[args->num++] = cp;
args->list[args->num] = NULL; 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);
}

View File

@ -34,6 +34,8 @@ struct arglist {
int nalloc; int nalloc;
}; };
void addargs(arglist *, char *, ...); void addargs(arglist *, char *, ...);
void replacearg(arglist *, u_int, char *, ...);
void freeargs(arglist *);
/* from xmalloc.h */ /* from xmalloc.h */
void *xmalloc(size_t); void *xmalloc(size_t);
@ -41,4 +43,6 @@ void *xrealloc(void *, size_t);
void xfree(void *); void xfree(void *);
char *xstrdup(const char *); char *xstrdup(const char *);
char *ssh_get_progname(char *);
void fatal(char* fmt,...);
void sanitise_stdfd(void);