1/* 2 * scp - secure remote copy. This is basically patched BSD rcp which 3 * uses ssh to do the data transfer (instead of using rcmd). 4 * 5 * NOTE: This version should NOT be suid root. (This uses ssh to 6 * do the transfer and ssh has the necessary privileges.) 7 * 8 * 1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi> 9 * 10 * As far as I am concerned, the code I have written for this software 11 * can be used freely for any purpose. Any derived versions of this 12 * software must be clearly marked as such, and if the derived work is 13 * incompatible with the protocol description in the RFC file, it must be 14 * called by a name other than "ssh" or "Secure Shell". 15 */ 16/* 17 * Copyright (c) 1999 Theo de Raadt. All rights reserved. 18 * Copyright (c) 1999 Aaron Campbell. All rights reserved. 19 * 20 * Redistribution and use in source and binary forms, with or without 21 * modification, are permitted provided that the following conditions 22 * are met: 23 * 1. Redistributions of source code must retain the above copyright 24 * notice, this list of conditions and the following disclaimer. 25 * 2. Redistributions in binary form must reproduce the above copyright 26 * notice, this list of conditions and the following disclaimer in the 27 * documentation and/or other materials provided with the distribution. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 30 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 31 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 32 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 33 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 34 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 38 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41/* 42 * Parts from: 43 * 44 * Copyright (c) 1983, 1990, 1992, 1993, 1995 45 * The Regents of the University of California. All rights reserved. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. All advertising materials mentioning features or use of this software 56 * must display the following acknowledgement: 57 * This product includes software developed by the University of 58 * California, Berkeley and its contributors. 59 * 4. Neither the name of the University nor the names of its contributors 60 * may be used to endorse or promote products derived from this software 61 * without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 66 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 73 * SUCH DAMAGE. 74 * 75 */ 76 77#include "includes.h"
| 1/* 2 * scp - secure remote copy. This is basically patched BSD rcp which 3 * uses ssh to do the data transfer (instead of using rcmd). 4 * 5 * NOTE: This version should NOT be suid root. (This uses ssh to 6 * do the transfer and ssh has the necessary privileges.) 7 * 8 * 1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi> 9 * 10 * As far as I am concerned, the code I have written for this software 11 * can be used freely for any purpose. Any derived versions of this 12 * software must be clearly marked as such, and if the derived work is 13 * incompatible with the protocol description in the RFC file, it must be 14 * called by a name other than "ssh" or "Secure Shell". 15 */ 16/* 17 * Copyright (c) 1999 Theo de Raadt. All rights reserved. 18 * Copyright (c) 1999 Aaron Campbell. All rights reserved. 19 * 20 * Redistribution and use in source and binary forms, with or without 21 * modification, are permitted provided that the following conditions 22 * are met: 23 * 1. Redistributions of source code must retain the above copyright 24 * notice, this list of conditions and the following disclaimer. 25 * 2. Redistributions in binary form must reproduce the above copyright 26 * notice, this list of conditions and the following disclaimer in the 27 * documentation and/or other materials provided with the distribution. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 30 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 31 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 32 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 33 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 34 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 38 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41/* 42 * Parts from: 43 * 44 * Copyright (c) 1983, 1990, 1992, 1993, 1995 45 * The Regents of the University of California. All rights reserved. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. All advertising materials mentioning features or use of this software 56 * must display the following acknowledgement: 57 * This product includes software developed by the University of 58 * California, Berkeley and its contributors. 59 * 4. Neither the name of the University nor the names of its contributors 60 * may be used to endorse or promote products derived from this software 61 * without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 66 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 73 * SUCH DAMAGE. 74 * 75 */ 76 77#include "includes.h"
|
78RCSID("$OpenBSD: scp.c,v 1.91 2002/06/19 00:27:55 deraadt Exp $"); 79RCSID("$FreeBSD: head/crypto/openssh/scp.c 107857 2002-12-14 13:38:49Z des $");
| 78RCSID("$OpenBSD: scp.c,v 1.102 2003/03/05 22:33:43 markus Exp $"); 79RCSID("$FreeBSD: head/crypto/openssh/scp.c 113911 2003-04-23 17:13:13Z des $");
|
80 81#include "xmalloc.h" 82#include "atomicio.h" 83#include "pathnames.h" 84#include "log.h" 85#include "misc.h"
| 80 81#include "xmalloc.h" 82#include "atomicio.h" 83#include "pathnames.h" 84#include "log.h" 85#include "misc.h"
|
| 86#include "progressmeter.h"
|
86 87#ifdef HAVE___PROGNAME 88extern char *__progname; 89#else 90char *__progname; 91#endif 92
| 87 88#ifdef HAVE___PROGNAME 89extern char *__progname; 90#else 91char *__progname; 92#endif 93
|
93/* For progressmeter() -- number of seconds before xfer considered "stalled" */ 94#define STALLTIME 5 95/* alarm() interval for updating progress meter */ 96#define PROGRESSTIME 1
| 94void bwlimit(int);
|
97
| 95
|
98/* Visual statistics about files as they are transferred. */ 99void progressmeter(int); 100 101/* Returns width of the terminal (for progress meter calculations). */ 102int getttywidth(void); 103int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc); 104
| |
105/* Struct for addargs */ 106arglist args; 107
| 96/* Struct for addargs */ 97arglist args; 98
|
108/* Time a transfer started. */ 109static struct timeval start;
| 99/* Bandwidth limit */ 100off_t limitbw = 0;
|
110
| 101
|
111/* Number of bytes of current file transferred so far. */ 112volatile off_t statbytes; 113 114/* Total size of current file. */ 115off_t totalbytes = 0; 116
| |
117/* Name of current file being transferred. */ 118char *curfile; 119 120/* This is set to non-zero to enable verbose mode. */ 121int verbose_mode = 0; 122 123/* This is set to zero if the progressmeter is not desired. */ 124int showprogress = 1; 125 126/* This is the program to execute for the secured connection. ("ssh" or -S) */ 127char *ssh_program = _PATH_SSH_PROGRAM; 128
| 102/* Name of current file being transferred. */ 103char *curfile; 104 105/* This is set to non-zero to enable verbose mode. */ 106int verbose_mode = 0; 107 108/* This is set to zero if the progressmeter is not desired. */ 109int showprogress = 1; 110 111/* This is the program to execute for the secured connection. ("ssh" or -S) */ 112char *ssh_program = _PATH_SSH_PROGRAM; 113
|
| 114/* This is used to store the pid of ssh_program */ 115pid_t do_cmd_pid; 116
|
129/* 130 * This function executes the given command as the specified user on the 131 * given host. This returns < 0 if execution fails, and >= 0 otherwise. This 132 * assigns the input and output file descriptors on success. 133 */ 134 135int 136do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc) 137{ 138 int pin[2], pout[2], reserved[2]; 139 140 if (verbose_mode) 141 fprintf(stderr, 142 "Executing: program %s host %s, user %s, command %s\n", 143 ssh_program, host, 144 remuser ? remuser : "(unspecified)", cmd); 145 146 /* 147 * Reserve two descriptors so that the real pipes won't get 148 * descriptors 0 and 1 because that will screw up dup2 below. 149 */ 150 pipe(reserved); 151 152 /* Create a socket pair for communicating with ssh. */ 153 if (pipe(pin) < 0) 154 fatal("pipe: %s", strerror(errno)); 155 if (pipe(pout) < 0) 156 fatal("pipe: %s", strerror(errno)); 157 158 /* Free the reserved descriptors. */ 159 close(reserved[0]); 160 close(reserved[1]); 161 162 /* For a child to execute the command on the remote host using ssh. */
| 117/* 118 * This function executes the given command as the specified user on the 119 * given host. This returns < 0 if execution fails, and >= 0 otherwise. This 120 * assigns the input and output file descriptors on success. 121 */ 122 123int 124do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc) 125{ 126 int pin[2], pout[2], reserved[2]; 127 128 if (verbose_mode) 129 fprintf(stderr, 130 "Executing: program %s host %s, user %s, command %s\n", 131 ssh_program, host, 132 remuser ? remuser : "(unspecified)", cmd); 133 134 /* 135 * Reserve two descriptors so that the real pipes won't get 136 * descriptors 0 and 1 because that will screw up dup2 below. 137 */ 138 pipe(reserved); 139 140 /* Create a socket pair for communicating with ssh. */ 141 if (pipe(pin) < 0) 142 fatal("pipe: %s", strerror(errno)); 143 if (pipe(pout) < 0) 144 fatal("pipe: %s", strerror(errno)); 145 146 /* Free the reserved descriptors. */ 147 close(reserved[0]); 148 close(reserved[1]); 149 150 /* For a child to execute the command on the remote host using ssh. */
|
163 if (fork() == 0) {
| 151 do_cmd_pid = fork(); 152 if (do_cmd_pid == 0) {
|
164 /* Child. */ 165 close(pin[1]); 166 close(pout[0]); 167 dup2(pin[0], 0); 168 dup2(pout[1], 1); 169 close(pin[0]); 170 close(pout[1]); 171 172 args.list[0] = ssh_program; 173 if (remuser != NULL) 174 addargs(&args, "-l%s", remuser); 175 addargs(&args, "%s", host); 176 addargs(&args, "%s", cmd); 177 178 execvp(ssh_program, args.list); 179 perror(ssh_program); 180 exit(1);
| 153 /* Child. */ 154 close(pin[1]); 155 close(pout[0]); 156 dup2(pin[0], 0); 157 dup2(pout[1], 1); 158 close(pin[0]); 159 close(pout[1]); 160 161 args.list[0] = ssh_program; 162 if (remuser != NULL) 163 addargs(&args, "-l%s", remuser); 164 addargs(&args, "%s", host); 165 addargs(&args, "%s", cmd); 166 167 execvp(ssh_program, args.list); 168 perror(ssh_program); 169 exit(1);
|
| 170 } else if (do_cmd_pid == -1) { 171 fatal("fork: %s", strerror(errno));
|
181 } 182 /* Parent. Close the other side, and return the local side. */ 183 close(pin[0]); 184 *fdout = pin[1]; 185 close(pout[1]); 186 *fdin = pout[0]; 187 return 0; 188} 189 190typedef struct { 191 int cnt; 192 char *buf; 193} BUF; 194 195BUF *allocbuf(BUF *, int, int); 196void lostconn(int); 197void nospace(void); 198int okname(char *); 199void run_err(const char *,...); 200void verifydir(char *); 201 202struct passwd *pwd; 203uid_t userid; 204int errs, remin, remout; 205int pflag, iamremote, iamrecursive, targetshouldbedirectory; 206 207#define CMDNEEDS 64 208char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 209 210int response(void); 211void rsource(char *, struct stat *); 212void sink(int, char *[]); 213void source(int, char *[]); 214void tolocal(int, char *[]); 215void toremote(char *, int, char *[]); 216void usage(void); 217 218int 219main(argc, argv) 220 int argc; 221 char *argv[]; 222{
| 172 } 173 /* Parent. Close the other side, and return the local side. */ 174 close(pin[0]); 175 *fdout = pin[1]; 176 close(pout[1]); 177 *fdin = pout[0]; 178 return 0; 179} 180 181typedef struct { 182 int cnt; 183 char *buf; 184} BUF; 185 186BUF *allocbuf(BUF *, int, int); 187void lostconn(int); 188void nospace(void); 189int okname(char *); 190void run_err(const char *,...); 191void verifydir(char *); 192 193struct passwd *pwd; 194uid_t userid; 195int errs, remin, remout; 196int pflag, iamremote, iamrecursive, targetshouldbedirectory; 197 198#define CMDNEEDS 64 199char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 200 201int response(void); 202void rsource(char *, struct stat *); 203void sink(int, char *[]); 204void source(int, char *[]); 205void tolocal(int, char *[]); 206void toremote(char *, int, char *[]); 207void usage(void); 208 209int 210main(argc, argv) 211 int argc; 212 char *argv[]; 213{
|
223 int ch, fflag, tflag; 224 char *targ;
| 214 int ch, fflag, tflag, status; 215 double speed; 216 char *targ, *endp;
|
225 extern char *optarg; 226 extern int optind; 227 228 __progname = get_progname(argv[0]); 229 230 args.list = NULL; 231 addargs(&args, "ssh"); /* overwritten with ssh_program */ 232 addargs(&args, "-x"); 233 addargs(&args, "-oForwardAgent no"); 234 addargs(&args, "-oClearAllForwardings yes"); 235 236 fflag = tflag = 0;
| 217 extern char *optarg; 218 extern int optind; 219 220 __progname = get_progname(argv[0]); 221 222 args.list = NULL; 223 addargs(&args, "ssh"); /* overwritten with ssh_program */ 224 addargs(&args, "-x"); 225 addargs(&args, "-oForwardAgent no"); 226 addargs(&args, "-oClearAllForwardings yes"); 227 228 fflag = tflag = 0;
|
237 while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:F:")) != -1)
| 229 while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q1246S:o:F:")) != -1)
|
238 switch (ch) { 239 /* User-visible flags. */
| 230 switch (ch) { 231 /* User-visible flags. */
|
| 232 case '1': 233 case '2':
|
240 case '4': 241 case '6': 242 case 'C': 243 addargs(&args, "-%c", ch); 244 break; 245 case 'o': 246 case 'c': 247 case 'i': 248 case 'F': 249 addargs(&args, "-%c%s", ch, optarg); 250 break; 251 case 'P': 252 addargs(&args, "-p%s", optarg); 253 break; 254 case 'B': 255 addargs(&args, "-oBatchmode yes"); 256 break;
| 234 case '4': 235 case '6': 236 case 'C': 237 addargs(&args, "-%c", ch); 238 break; 239 case 'o': 240 case 'c': 241 case 'i': 242 case 'F': 243 addargs(&args, "-%c%s", ch, optarg); 244 break; 245 case 'P': 246 addargs(&args, "-p%s", optarg); 247 break; 248 case 'B': 249 addargs(&args, "-oBatchmode yes"); 250 break;
|
| 251 case 'l': 252 speed = strtod(optarg, &endp); 253 if (speed <= 0 || *endp != '\0') 254 usage(); 255 limitbw = speed * 1024; 256 break;
|
257 case 'p': 258 pflag = 1; 259 break; 260 case 'r': 261 iamrecursive = 1; 262 break; 263 case 'S': 264 ssh_program = xstrdup(optarg); 265 break; 266 case 'v': 267 addargs(&args, "-v"); 268 verbose_mode = 1; 269 break; 270 case 'q': 271 showprogress = 0; 272 break; 273 274 /* Server options. */ 275 case 'd': 276 targetshouldbedirectory = 1; 277 break; 278 case 'f': /* "from" */ 279 iamremote = 1; 280 fflag = 1; 281 break; 282 case 't': /* "to" */ 283 iamremote = 1; 284 tflag = 1; 285#ifdef HAVE_CYGWIN 286 setmode(0, O_BINARY); 287#endif 288 break; 289 default: 290 usage(); 291 } 292 argc -= optind; 293 argv += optind; 294 295 if ((pwd = getpwuid(userid = getuid())) == NULL) 296 fatal("unknown user %d", (int) userid); 297 298 if (!isatty(STDERR_FILENO)) 299 showprogress = 0; 300 301 remin = STDIN_FILENO; 302 remout = STDOUT_FILENO; 303 304 if (fflag) { 305 /* Follow "protocol", send data. */ 306 (void) response(); 307 source(argc, argv); 308 exit(errs != 0); 309 } 310 if (tflag) { 311 /* Receive data. */ 312 sink(argc, argv); 313 exit(errs != 0); 314 } 315 if (argc < 2) 316 usage(); 317 if (argc > 2) 318 targetshouldbedirectory = 1; 319 320 remin = remout = -1;
| 257 case 'p': 258 pflag = 1; 259 break; 260 case 'r': 261 iamrecursive = 1; 262 break; 263 case 'S': 264 ssh_program = xstrdup(optarg); 265 break; 266 case 'v': 267 addargs(&args, "-v"); 268 verbose_mode = 1; 269 break; 270 case 'q': 271 showprogress = 0; 272 break; 273 274 /* Server options. */ 275 case 'd': 276 targetshouldbedirectory = 1; 277 break; 278 case 'f': /* "from" */ 279 iamremote = 1; 280 fflag = 1; 281 break; 282 case 't': /* "to" */ 283 iamremote = 1; 284 tflag = 1; 285#ifdef HAVE_CYGWIN 286 setmode(0, O_BINARY); 287#endif 288 break; 289 default: 290 usage(); 291 } 292 argc -= optind; 293 argv += optind; 294 295 if ((pwd = getpwuid(userid = getuid())) == NULL) 296 fatal("unknown user %d", (int) userid); 297 298 if (!isatty(STDERR_FILENO)) 299 showprogress = 0; 300 301 remin = STDIN_FILENO; 302 remout = STDOUT_FILENO; 303 304 if (fflag) { 305 /* Follow "protocol", send data. */ 306 (void) response(); 307 source(argc, argv); 308 exit(errs != 0); 309 } 310 if (tflag) { 311 /* Receive data. */ 312 sink(argc, argv); 313 exit(errs != 0); 314 } 315 if (argc < 2) 316 usage(); 317 if (argc > 2) 318 targetshouldbedirectory = 1; 319 320 remin = remout = -1;
|
| 321 do_cmd_pid = -1;
|
321 /* Command to be executed on remote system using "ssh". */ 322 (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s", 323 verbose_mode ? " -v" : "", 324 iamrecursive ? " -r" : "", pflag ? " -p" : "", 325 targetshouldbedirectory ? " -d" : ""); 326 327 (void) signal(SIGPIPE, lostconn); 328 329 if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ 330 toremote(targ, argc, argv); 331 else { 332 tolocal(argc, argv); /* Dest is local host. */ 333 if (targetshouldbedirectory) 334 verifydir(argv[argc - 1]); 335 }
| 322 /* Command to be executed on remote system using "ssh". */ 323 (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s", 324 verbose_mode ? " -v" : "", 325 iamrecursive ? " -r" : "", pflag ? " -p" : "", 326 targetshouldbedirectory ? " -d" : ""); 327 328 (void) signal(SIGPIPE, lostconn); 329 330 if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ 331 toremote(targ, argc, argv); 332 else { 333 tolocal(argc, argv); /* Dest is local host. */ 334 if (targetshouldbedirectory) 335 verifydir(argv[argc - 1]); 336 }
|
| 337 /* 338 * Finally check the exit status of the ssh process, if one was forked 339 * and no error has occured yet 340 */ 341 if (do_cmd_pid != -1 && errs == 0) { 342 if (remin != -1) 343 (void) close(remin); 344 if (remout != -1) 345 (void) close(remout); 346 if (waitpid(do_cmd_pid, &status, 0) == -1) 347 errs = 1; 348 else { 349 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 350 errs = 1; 351 } 352 }
|
336 exit(errs != 0); 337} 338 339void 340toremote(targ, argc, argv) 341 char *targ, *argv[]; 342 int argc; 343{ 344 int i, len; 345 char *bp, *host, *src, *suser, *thost, *tuser; 346 347 *targ++ = 0; 348 if (*targ == 0) 349 targ = "."; 350
| 353 exit(errs != 0); 354} 355 356void 357toremote(targ, argc, argv) 358 char *targ, *argv[]; 359 int argc; 360{ 361 int i, len; 362 char *bp, *host, *src, *suser, *thost, *tuser; 363 364 *targ++ = 0; 365 if (*targ == 0) 366 targ = "."; 367
|
351 if ((thost = strchr(argv[argc - 1], '@'))) {
| 368 if ((thost = strrchr(argv[argc - 1], '@'))) {
|
352 /* user@host */ 353 *thost++ = 0; 354 tuser = argv[argc - 1]; 355 if (*tuser == '\0') 356 tuser = NULL;
| 369 /* user@host */ 370 *thost++ = 0; 371 tuser = argv[argc - 1]; 372 if (*tuser == '\0') 373 tuser = NULL;
|
357 else if (!okname(tuser)) 358 exit(1);
| |
359 } else { 360 thost = argv[argc - 1]; 361 tuser = NULL; 362 } 363 364 for (i = 0; i < argc - 1; i++) { 365 src = colon(argv[i]); 366 if (src) { /* remote to remote */ 367 static char *ssh_options = 368 "-x -o'ClearAllForwardings yes'"; 369 *src++ = 0; 370 if (*src == 0) 371 src = ".";
| 374 } else { 375 thost = argv[argc - 1]; 376 tuser = NULL; 377 } 378 379 for (i = 0; i < argc - 1; i++) { 380 src = colon(argv[i]); 381 if (src) { /* remote to remote */ 382 static char *ssh_options = 383 "-x -o'ClearAllForwardings yes'"; 384 *src++ = 0; 385 if (*src == 0) 386 src = ".";
|
372 host = strchr(argv[i], '@');
| 387 host = strrchr(argv[i], '@');
|
373 len = strlen(ssh_program) + strlen(argv[i]) + 374 strlen(src) + (tuser ? strlen(tuser) : 0) + 375 strlen(thost) + strlen(targ) + 376 strlen(ssh_options) + CMDNEEDS + 20; 377 bp = xmalloc(len); 378 if (host) { 379 *host++ = 0; 380 host = cleanhostname(host); 381 suser = argv[i]; 382 if (*suser == '\0') 383 suser = pwd->pw_name;
| 388 len = strlen(ssh_program) + strlen(argv[i]) + 389 strlen(src) + (tuser ? strlen(tuser) : 0) + 390 strlen(thost) + strlen(targ) + 391 strlen(ssh_options) + CMDNEEDS + 20; 392 bp = xmalloc(len); 393 if (host) { 394 *host++ = 0; 395 host = cleanhostname(host); 396 suser = argv[i]; 397 if (*suser == '\0') 398 suser = pwd->pw_name;
|
384 else if (!okname(suser))
| 399 else if (!okname(suser)) { 400 xfree(bp);
|
385 continue;
| 401 continue;
|
| 402 } 403 if (tuser && !okname(tuser)) { 404 xfree(bp); 405 continue; 406 }
|
386 snprintf(bp, len, 387 "%s%s %s -n " 388 "-l %s %s %s %s '%s%s%s:%s'", 389 ssh_program, verbose_mode ? " -v" : "", 390 ssh_options, suser, host, cmd, src, 391 tuser ? tuser : "", tuser ? "@" : "", 392 thost, targ); 393 } else { 394 host = cleanhostname(argv[i]); 395 snprintf(bp, len, 396 "exec %s%s %s -n %s " 397 "%s %s '%s%s%s:%s'", 398 ssh_program, verbose_mode ? " -v" : "", 399 ssh_options, host, cmd, src, 400 tuser ? tuser : "", tuser ? "@" : "", 401 thost, targ); 402 } 403 if (verbose_mode) 404 fprintf(stderr, "Executing: %s\n", bp); 405 (void) system(bp); 406 (void) xfree(bp); 407 } else { /* local to remote */ 408 if (remin == -1) { 409 len = strlen(targ) + CMDNEEDS + 20; 410 bp = xmalloc(len); 411 (void) snprintf(bp, len, "%s -t %s", cmd, targ); 412 host = cleanhostname(thost); 413 if (do_cmd(host, tuser, bp, &remin, 414 &remout, argc) < 0) 415 exit(1); 416 if (response() < 0) 417 exit(1); 418 (void) xfree(bp); 419 } 420 source(1, argv + i); 421 } 422 } 423} 424 425void 426tolocal(argc, argv) 427 int argc; 428 char *argv[]; 429{ 430 int i, len; 431 char *bp, *host, *src, *suser; 432 433 for (i = 0; i < argc - 1; i++) { 434 if (!(src = colon(argv[i]))) { /* Local to local. */ 435 len = strlen(_PATH_CP) + strlen(argv[i]) + 436 strlen(argv[argc - 1]) + 20; 437 bp = xmalloc(len); 438 (void) snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, 439 iamrecursive ? " -r" : "", pflag ? " -p" : "", 440 argv[i], argv[argc - 1]); 441 if (verbose_mode) 442 fprintf(stderr, "Executing: %s\n", bp); 443 if (system(bp)) 444 ++errs; 445 (void) xfree(bp); 446 continue; 447 } 448 *src++ = 0; 449 if (*src == 0) 450 src = ".";
| 407 snprintf(bp, len, 408 "%s%s %s -n " 409 "-l %s %s %s %s '%s%s%s:%s'", 410 ssh_program, verbose_mode ? " -v" : "", 411 ssh_options, suser, host, cmd, src, 412 tuser ? tuser : "", tuser ? "@" : "", 413 thost, targ); 414 } else { 415 host = cleanhostname(argv[i]); 416 snprintf(bp, len, 417 "exec %s%s %s -n %s " 418 "%s %s '%s%s%s:%s'", 419 ssh_program, verbose_mode ? " -v" : "", 420 ssh_options, host, cmd, src, 421 tuser ? tuser : "", tuser ? "@" : "", 422 thost, targ); 423 } 424 if (verbose_mode) 425 fprintf(stderr, "Executing: %s\n", bp); 426 (void) system(bp); 427 (void) xfree(bp); 428 } else { /* local to remote */ 429 if (remin == -1) { 430 len = strlen(targ) + CMDNEEDS + 20; 431 bp = xmalloc(len); 432 (void) snprintf(bp, len, "%s -t %s", cmd, targ); 433 host = cleanhostname(thost); 434 if (do_cmd(host, tuser, bp, &remin, 435 &remout, argc) < 0) 436 exit(1); 437 if (response() < 0) 438 exit(1); 439 (void) xfree(bp); 440 } 441 source(1, argv + i); 442 } 443 } 444} 445 446void 447tolocal(argc, argv) 448 int argc; 449 char *argv[]; 450{ 451 int i, len; 452 char *bp, *host, *src, *suser; 453 454 for (i = 0; i < argc - 1; i++) { 455 if (!(src = colon(argv[i]))) { /* Local to local. */ 456 len = strlen(_PATH_CP) + strlen(argv[i]) + 457 strlen(argv[argc - 1]) + 20; 458 bp = xmalloc(len); 459 (void) snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, 460 iamrecursive ? " -r" : "", pflag ? " -p" : "", 461 argv[i], argv[argc - 1]); 462 if (verbose_mode) 463 fprintf(stderr, "Executing: %s\n", bp); 464 if (system(bp)) 465 ++errs; 466 (void) xfree(bp); 467 continue; 468 } 469 *src++ = 0; 470 if (*src == 0) 471 src = ".";
|
451 if ((host = strchr(argv[i], '@')) == NULL) {
| 472 if ((host = strrchr(argv[i], '@')) == NULL) {
|
452 host = argv[i]; 453 suser = NULL; 454 } else { 455 *host++ = 0; 456 suser = argv[i]; 457 if (*suser == '\0') 458 suser = pwd->pw_name;
| 473 host = argv[i]; 474 suser = NULL; 475 } else { 476 *host++ = 0; 477 suser = argv[i]; 478 if (*suser == '\0') 479 suser = pwd->pw_name;
|
459 else if (!okname(suser)) 460 continue;
| |
461 } 462 host = cleanhostname(host); 463 len = strlen(src) + CMDNEEDS + 20; 464 bp = xmalloc(len); 465 (void) snprintf(bp, len, "%s -f %s", cmd, src); 466 if (do_cmd(host, suser, bp, &remin, &remout, argc) < 0) { 467 (void) xfree(bp); 468 ++errs; 469 continue; 470 } 471 xfree(bp); 472 sink(1, argv + argc - 1); 473 (void) close(remin); 474 remin = remout = -1; 475 } 476} 477 478void 479source(argc, argv) 480 int argc; 481 char *argv[]; 482{ 483 struct stat stb; 484 static BUF buffer; 485 BUF *bp;
| 480 } 481 host = cleanhostname(host); 482 len = strlen(src) + CMDNEEDS + 20; 483 bp = xmalloc(len); 484 (void) snprintf(bp, len, "%s -f %s", cmd, src); 485 if (do_cmd(host, suser, bp, &remin, &remout, argc) < 0) { 486 (void) xfree(bp); 487 ++errs; 488 continue; 489 } 490 xfree(bp); 491 sink(1, argv + argc - 1); 492 (void) close(remin); 493 remin = remout = -1; 494 } 495} 496 497void 498source(argc, argv) 499 int argc; 500 char *argv[]; 501{ 502 struct stat stb; 503 static BUF buffer; 504 BUF *bp;
|
486 off_t i, amt, result;
| 505 off_t i, amt, result, statbytes;
|
487 int fd, haderr, indx; 488 char *last, *name, buf[2048]; 489 int len; 490 491 for (indx = 0; indx < argc; ++indx) { 492 name = argv[indx]; 493 statbytes = 0; 494 len = strlen(name); 495 while (len > 1 && name[len-1] == '/') 496 name[--len] = '\0'; 497 if (strchr(name, '\n') != NULL) { 498 run_err("%s: skipping, filename contains a newline", 499 name); 500 goto next; 501 } 502 if ((fd = open(name, O_RDONLY, 0)) < 0) 503 goto syserr; 504 if (fstat(fd, &stb) < 0) { 505syserr: run_err("%s: %s", name, strerror(errno)); 506 goto next; 507 } 508 switch (stb.st_mode & S_IFMT) { 509 case S_IFREG: 510 break; 511 case S_IFDIR: 512 if (iamrecursive) { 513 rsource(name, &stb); 514 goto next; 515 } 516 /* FALLTHROUGH */ 517 default: 518 run_err("%s: not a regular file", name); 519 goto next; 520 } 521 if ((last = strrchr(name, '/')) == NULL) 522 last = name; 523 else 524 ++last; 525 curfile = last; 526 if (pflag) { 527 /* 528 * Make it compatible with possible future 529 * versions expecting microseconds. 530 */ 531 (void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n", 532 (u_long) stb.st_mtime, 533 (u_long) stb.st_atime); 534 (void) atomicio(write, remout, buf, strlen(buf)); 535 if (response() < 0) 536 goto next; 537 } 538#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) 539#ifdef HAVE_LONG_LONG_INT 540 snprintf(buf, sizeof buf, "C%04o %lld %s\n", 541 (u_int) (stb.st_mode & FILEMODEMASK), 542 (long long)stb.st_size, last); 543#else 544 /* XXX: Handle integer overflow? */ 545 snprintf(buf, sizeof buf, "C%04o %lu %s\n", 546 (u_int) (stb.st_mode & FILEMODEMASK), 547 (u_long) stb.st_size, last); 548#endif 549 if (verbose_mode) { 550 fprintf(stderr, "Sending file modes: %s", buf);
| 506 int fd, haderr, indx; 507 char *last, *name, buf[2048]; 508 int len; 509 510 for (indx = 0; indx < argc; ++indx) { 511 name = argv[indx]; 512 statbytes = 0; 513 len = strlen(name); 514 while (len > 1 && name[len-1] == '/') 515 name[--len] = '\0'; 516 if (strchr(name, '\n') != NULL) { 517 run_err("%s: skipping, filename contains a newline", 518 name); 519 goto next; 520 } 521 if ((fd = open(name, O_RDONLY, 0)) < 0) 522 goto syserr; 523 if (fstat(fd, &stb) < 0) { 524syserr: run_err("%s: %s", name, strerror(errno)); 525 goto next; 526 } 527 switch (stb.st_mode & S_IFMT) { 528 case S_IFREG: 529 break; 530 case S_IFDIR: 531 if (iamrecursive) { 532 rsource(name, &stb); 533 goto next; 534 } 535 /* FALLTHROUGH */ 536 default: 537 run_err("%s: not a regular file", name); 538 goto next; 539 } 540 if ((last = strrchr(name, '/')) == NULL) 541 last = name; 542 else 543 ++last; 544 curfile = last; 545 if (pflag) { 546 /* 547 * Make it compatible with possible future 548 * versions expecting microseconds. 549 */ 550 (void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n", 551 (u_long) stb.st_mtime, 552 (u_long) stb.st_atime); 553 (void) atomicio(write, remout, buf, strlen(buf)); 554 if (response() < 0) 555 goto next; 556 } 557#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) 558#ifdef HAVE_LONG_LONG_INT 559 snprintf(buf, sizeof buf, "C%04o %lld %s\n", 560 (u_int) (stb.st_mode & FILEMODEMASK), 561 (long long)stb.st_size, last); 562#else 563 /* XXX: Handle integer overflow? */ 564 snprintf(buf, sizeof buf, "C%04o %lu %s\n", 565 (u_int) (stb.st_mode & FILEMODEMASK), 566 (u_long) stb.st_size, last); 567#endif 568 if (verbose_mode) { 569 fprintf(stderr, "Sending file modes: %s", buf);
|
551 fflush(stderr);
| |
552 } 553 (void) atomicio(write, remout, buf, strlen(buf)); 554 if (response() < 0) 555 goto next; 556 if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) { 557next: (void) close(fd); 558 continue; 559 }
| 570 } 571 (void) atomicio(write, remout, buf, strlen(buf)); 572 if (response() < 0) 573 goto next; 574 if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) { 575next: (void) close(fd); 576 continue; 577 }
|
560 if (showprogress) { 561 totalbytes = stb.st_size; 562 progressmeter(-1); 563 }
| 578 if (showprogress) 579 start_progress_meter(curfile, stb.st_size, &statbytes);
|
564 /* Keep writing after an error so that we stay sync'd up. */ 565 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 566 amt = bp->cnt; 567 if (i + amt > stb.st_size) 568 amt = stb.st_size - i; 569 if (!haderr) { 570 result = atomicio(read, fd, bp->buf, amt); 571 if (result != amt) 572 haderr = result >= 0 ? EIO : errno; 573 } 574 if (haderr) 575 (void) atomicio(write, remout, bp->buf, amt); 576 else { 577 result = atomicio(write, remout, bp->buf, amt); 578 if (result != amt) 579 haderr = result >= 0 ? EIO : errno; 580 statbytes += result; 581 }
| 580 /* Keep writing after an error so that we stay sync'd up. */ 581 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 582 amt = bp->cnt; 583 if (i + amt > stb.st_size) 584 amt = stb.st_size - i; 585 if (!haderr) { 586 result = atomicio(read, fd, bp->buf, amt); 587 if (result != amt) 588 haderr = result >= 0 ? EIO : errno; 589 } 590 if (haderr) 591 (void) atomicio(write, remout, bp->buf, amt); 592 else { 593 result = atomicio(write, remout, bp->buf, amt); 594 if (result != amt) 595 haderr = result >= 0 ? EIO : errno; 596 statbytes += result; 597 }
|
| 598 if (limitbw) 599 bwlimit(amt);
|
582 } 583 if (showprogress)
| 600 } 601 if (showprogress)
|
584 progressmeter(1);
| 602 stop_progress_meter();
|
585 586 if (close(fd) < 0 && !haderr) 587 haderr = errno; 588 if (!haderr) 589 (void) atomicio(write, remout, "", 1); 590 else 591 run_err("%s: %s", name, strerror(haderr)); 592 (void) response(); 593 } 594} 595 596void 597rsource(name, statp) 598 char *name; 599 struct stat *statp; 600{ 601 DIR *dirp; 602 struct dirent *dp; 603 char *last, *vect[1], path[1100]; 604 605 if (!(dirp = opendir(name))) { 606 run_err("%s: %s", name, strerror(errno)); 607 return; 608 } 609 last = strrchr(name, '/'); 610 if (last == 0) 611 last = name; 612 else 613 last++; 614 if (pflag) { 615 (void) snprintf(path, sizeof(path), "T%lu 0 %lu 0\n", 616 (u_long) statp->st_mtime, 617 (u_long) statp->st_atime); 618 (void) atomicio(write, remout, path, strlen(path)); 619 if (response() < 0) { 620 closedir(dirp); 621 return; 622 } 623 } 624 (void) snprintf(path, sizeof path, "D%04o %d %.1024s\n", 625 (u_int) (statp->st_mode & FILEMODEMASK), 0, last); 626 if (verbose_mode) 627 fprintf(stderr, "Entering directory: %s", path); 628 (void) atomicio(write, remout, path, strlen(path)); 629 if (response() < 0) { 630 closedir(dirp); 631 return; 632 } 633 while ((dp = readdir(dirp)) != NULL) { 634 if (dp->d_ino == 0) 635 continue; 636 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 637 continue; 638 if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) { 639 run_err("%s/%s: name too long", name, dp->d_name); 640 continue; 641 } 642 (void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name); 643 vect[0] = path; 644 source(1, vect); 645 } 646 (void) closedir(dirp); 647 (void) atomicio(write, remout, "E\n", 2); 648 (void) response(); 649} 650 651void
| 603 604 if (close(fd) < 0 && !haderr) 605 haderr = errno; 606 if (!haderr) 607 (void) atomicio(write, remout, "", 1); 608 else 609 run_err("%s: %s", name, strerror(haderr)); 610 (void) response(); 611 } 612} 613 614void 615rsource(name, statp) 616 char *name; 617 struct stat *statp; 618{ 619 DIR *dirp; 620 struct dirent *dp; 621 char *last, *vect[1], path[1100]; 622 623 if (!(dirp = opendir(name))) { 624 run_err("%s: %s", name, strerror(errno)); 625 return; 626 } 627 last = strrchr(name, '/'); 628 if (last == 0) 629 last = name; 630 else 631 last++; 632 if (pflag) { 633 (void) snprintf(path, sizeof(path), "T%lu 0 %lu 0\n", 634 (u_long) statp->st_mtime, 635 (u_long) statp->st_atime); 636 (void) atomicio(write, remout, path, strlen(path)); 637 if (response() < 0) { 638 closedir(dirp); 639 return; 640 } 641 } 642 (void) snprintf(path, sizeof path, "D%04o %d %.1024s\n", 643 (u_int) (statp->st_mode & FILEMODEMASK), 0, last); 644 if (verbose_mode) 645 fprintf(stderr, "Entering directory: %s", path); 646 (void) atomicio(write, remout, path, strlen(path)); 647 if (response() < 0) { 648 closedir(dirp); 649 return; 650 } 651 while ((dp = readdir(dirp)) != NULL) { 652 if (dp->d_ino == 0) 653 continue; 654 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 655 continue; 656 if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) { 657 run_err("%s/%s: name too long", name, dp->d_name); 658 continue; 659 } 660 (void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name); 661 vect[0] = path; 662 source(1, vect); 663 } 664 (void) closedir(dirp); 665 (void) atomicio(write, remout, "E\n", 2); 666 (void) response(); 667} 668 669void
|
| 670bwlimit(int amount) 671{ 672 static struct timeval bwstart, bwend; 673 static int lamt, thresh = 16384; 674 u_int64_t wait; 675 struct timespec ts, rm; 676 677 if (!timerisset(&bwstart)) { 678 gettimeofday(&bwstart, NULL); 679 return; 680 } 681 682 lamt += amount; 683 if (lamt < thresh) 684 return; 685 686 gettimeofday(&bwend, NULL); 687 timersub(&bwend, &bwstart, &bwend); 688 if (!timerisset(&bwend)) 689 return; 690 691 lamt *= 8; 692 wait = (double)1000000L * lamt / limitbw; 693 694 bwstart.tv_sec = wait / 1000000L; 695 bwstart.tv_usec = wait % 1000000L; 696 697 if (timercmp(&bwstart, &bwend, >)) { 698 timersub(&bwstart, &bwend, &bwend); 699 700 /* Adjust the wait time */ 701 if (bwend.tv_sec) { 702 thresh /= 2; 703 if (thresh < 2048) 704 thresh = 2048; 705 } else if (bwend.tv_usec < 100) { 706 thresh *= 2; 707 if (thresh > 32768) 708 thresh = 32768; 709 } 710 711 TIMEVAL_TO_TIMESPEC(&bwend, &ts); 712 while (nanosleep(&ts, &rm) == -1) { 713 if (errno != EINTR) 714 break; 715 ts = rm; 716 } 717 } 718 719 lamt = 0; 720 gettimeofday(&bwstart, NULL); 721} 722 723void
|
652sink(argc, argv) 653 int argc; 654 char *argv[]; 655{ 656 static BUF buffer; 657 struct stat stb; 658 enum { 659 YES, NO, DISPLAYED 660 } wrerr; 661 BUF *bp; 662 off_t i, j; 663 int amt, count, exists, first, mask, mode, ofd, omode;
| 724sink(argc, argv) 725 int argc; 726 char *argv[]; 727{ 728 static BUF buffer; 729 struct stat stb; 730 enum { 731 YES, NO, DISPLAYED 732 } wrerr; 733 BUF *bp; 734 off_t i, j; 735 int amt, count, exists, first, mask, mode, ofd, omode;
|
664 off_t size;
| 736 off_t size, statbytes;
|
665 int setimes, targisdir, wrerrno = 0; 666 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; 667 struct timeval tv[2]; 668 669#define atime tv[0] 670#define mtime tv[1] 671#define SCREWUP(str) do { why = str; goto screwup; } while (0) 672 673 setimes = targisdir = 0; 674 mask = umask(0); 675 if (!pflag) 676 (void) umask(mask); 677 if (argc != 1) { 678 run_err("ambiguous target"); 679 exit(1); 680 } 681 targ = *argv; 682 if (targetshouldbedirectory) 683 verifydir(targ); 684 685 (void) atomicio(write, remout, "", 1); 686 if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) 687 targisdir = 1; 688 for (first = 1;; first = 0) { 689 cp = buf; 690 if (atomicio(read, remin, cp, 1) <= 0) 691 return; 692 if (*cp++ == '\n') 693 SCREWUP("unexpected <newline>"); 694 do { 695 if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) 696 SCREWUP("lost connection"); 697 *cp++ = ch; 698 } while (cp < &buf[sizeof(buf) - 1] && ch != '\n'); 699 *cp = 0; 700 701 if (buf[0] == '\01' || buf[0] == '\02') { 702 if (iamremote == 0) 703 (void) atomicio(write, STDERR_FILENO, 704 buf + 1, strlen(buf + 1)); 705 if (buf[0] == '\02') 706 exit(1); 707 ++errs; 708 continue; 709 } 710 if (buf[0] == 'E') { 711 (void) atomicio(write, remout, "", 1); 712 return; 713 } 714 if (ch == '\n') 715 *--cp = 0; 716 717 cp = buf; 718 if (*cp == 'T') { 719 setimes++; 720 cp++; 721 mtime.tv_sec = strtol(cp, &cp, 10); 722 if (!cp || *cp++ != ' ') 723 SCREWUP("mtime.sec not delimited"); 724 mtime.tv_usec = strtol(cp, &cp, 10); 725 if (!cp || *cp++ != ' ') 726 SCREWUP("mtime.usec not delimited"); 727 atime.tv_sec = strtol(cp, &cp, 10); 728 if (!cp || *cp++ != ' ') 729 SCREWUP("atime.sec not delimited"); 730 atime.tv_usec = strtol(cp, &cp, 10); 731 if (!cp || *cp++ != '\0') 732 SCREWUP("atime.usec not delimited"); 733 (void) atomicio(write, remout, "", 1); 734 continue; 735 } 736 if (*cp != 'C' && *cp != 'D') { 737 /* 738 * Check for the case "rcp remote:foo\* local:bar". 739 * In this case, the line "No match." can be returned 740 * by the shell before the rcp command on the remote is 741 * executed so the ^Aerror_message convention isn't 742 * followed. 743 */ 744 if (first) { 745 run_err("%s", cp); 746 exit(1); 747 } 748 SCREWUP("expected control record"); 749 } 750 mode = 0; 751 for (++cp; cp < buf + 5; cp++) { 752 if (*cp < '0' || *cp > '7') 753 SCREWUP("bad mode"); 754 mode = (mode << 3) | (*cp - '0'); 755 } 756 if (*cp++ != ' ') 757 SCREWUP("mode not delimited"); 758 759 for (size = 0; isdigit(*cp);) 760 size = size * 10 + (*cp++ - '0'); 761 if (*cp++ != ' ') 762 SCREWUP("size not delimited"); 763 if (targisdir) { 764 static char *namebuf; 765 static int cursize; 766 size_t need; 767 768 need = strlen(targ) + strlen(cp) + 250; 769 if (need > cursize) { 770 if (namebuf) 771 xfree(namebuf); 772 namebuf = xmalloc(need); 773 cursize = need; 774 } 775 (void) snprintf(namebuf, need, "%s%s%s", targ, 776 strcmp(targ, "/") ? "/" : "", cp); 777 np = namebuf; 778 } else 779 np = targ; 780 curfile = cp; 781 exists = stat(np, &stb) == 0; 782 if (buf[0] == 'D') { 783 int mod_flag = pflag; 784 if (exists) { 785 if (!S_ISDIR(stb.st_mode)) { 786 errno = ENOTDIR; 787 goto bad; 788 } 789 if (pflag) 790 (void) chmod(np, mode); 791 } else { 792 /* Handle copying from a read-only 793 directory */ 794 mod_flag = 1; 795 if (mkdir(np, mode | S_IRWXU) < 0) 796 goto bad; 797 } 798 vect[0] = xstrdup(np); 799 sink(1, vect); 800 if (setimes) { 801 setimes = 0; 802 if (utimes(vect[0], tv) < 0) 803 run_err("%s: set times: %s", 804 vect[0], strerror(errno)); 805 } 806 if (mod_flag) 807 (void) chmod(vect[0], mode); 808 if (vect[0]) 809 xfree(vect[0]); 810 continue; 811 } 812 omode = mode; 813 mode |= S_IWRITE; 814 if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 815bad: run_err("%s: %s", np, strerror(errno)); 816 continue; 817 } 818 (void) atomicio(write, remout, "", 1); 819 if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) { 820 (void) close(ofd); 821 continue; 822 } 823 cp = bp->buf; 824 wrerr = NO; 825
| 737 int setimes, targisdir, wrerrno = 0; 738 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; 739 struct timeval tv[2]; 740 741#define atime tv[0] 742#define mtime tv[1] 743#define SCREWUP(str) do { why = str; goto screwup; } while (0) 744 745 setimes = targisdir = 0; 746 mask = umask(0); 747 if (!pflag) 748 (void) umask(mask); 749 if (argc != 1) { 750 run_err("ambiguous target"); 751 exit(1); 752 } 753 targ = *argv; 754 if (targetshouldbedirectory) 755 verifydir(targ); 756 757 (void) atomicio(write, remout, "", 1); 758 if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) 759 targisdir = 1; 760 for (first = 1;; first = 0) { 761 cp = buf; 762 if (atomicio(read, remin, cp, 1) <= 0) 763 return; 764 if (*cp++ == '\n') 765 SCREWUP("unexpected <newline>"); 766 do { 767 if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) 768 SCREWUP("lost connection"); 769 *cp++ = ch; 770 } while (cp < &buf[sizeof(buf) - 1] && ch != '\n'); 771 *cp = 0; 772 773 if (buf[0] == '\01' || buf[0] == '\02') { 774 if (iamremote == 0) 775 (void) atomicio(write, STDERR_FILENO, 776 buf + 1, strlen(buf + 1)); 777 if (buf[0] == '\02') 778 exit(1); 779 ++errs; 780 continue; 781 } 782 if (buf[0] == 'E') { 783 (void) atomicio(write, remout, "", 1); 784 return; 785 } 786 if (ch == '\n') 787 *--cp = 0; 788 789 cp = buf; 790 if (*cp == 'T') { 791 setimes++; 792 cp++; 793 mtime.tv_sec = strtol(cp, &cp, 10); 794 if (!cp || *cp++ != ' ') 795 SCREWUP("mtime.sec not delimited"); 796 mtime.tv_usec = strtol(cp, &cp, 10); 797 if (!cp || *cp++ != ' ') 798 SCREWUP("mtime.usec not delimited"); 799 atime.tv_sec = strtol(cp, &cp, 10); 800 if (!cp || *cp++ != ' ') 801 SCREWUP("atime.sec not delimited"); 802 atime.tv_usec = strtol(cp, &cp, 10); 803 if (!cp || *cp++ != '\0') 804 SCREWUP("atime.usec not delimited"); 805 (void) atomicio(write, remout, "", 1); 806 continue; 807 } 808 if (*cp != 'C' && *cp != 'D') { 809 /* 810 * Check for the case "rcp remote:foo\* local:bar". 811 * In this case, the line "No match." can be returned 812 * by the shell before the rcp command on the remote is 813 * executed so the ^Aerror_message convention isn't 814 * followed. 815 */ 816 if (first) { 817 run_err("%s", cp); 818 exit(1); 819 } 820 SCREWUP("expected control record"); 821 } 822 mode = 0; 823 for (++cp; cp < buf + 5; cp++) { 824 if (*cp < '0' || *cp > '7') 825 SCREWUP("bad mode"); 826 mode = (mode << 3) | (*cp - '0'); 827 } 828 if (*cp++ != ' ') 829 SCREWUP("mode not delimited"); 830 831 for (size = 0; isdigit(*cp);) 832 size = size * 10 + (*cp++ - '0'); 833 if (*cp++ != ' ') 834 SCREWUP("size not delimited"); 835 if (targisdir) { 836 static char *namebuf; 837 static int cursize; 838 size_t need; 839 840 need = strlen(targ) + strlen(cp) + 250; 841 if (need > cursize) { 842 if (namebuf) 843 xfree(namebuf); 844 namebuf = xmalloc(need); 845 cursize = need; 846 } 847 (void) snprintf(namebuf, need, "%s%s%s", targ, 848 strcmp(targ, "/") ? "/" : "", cp); 849 np = namebuf; 850 } else 851 np = targ; 852 curfile = cp; 853 exists = stat(np, &stb) == 0; 854 if (buf[0] == 'D') { 855 int mod_flag = pflag; 856 if (exists) { 857 if (!S_ISDIR(stb.st_mode)) { 858 errno = ENOTDIR; 859 goto bad; 860 } 861 if (pflag) 862 (void) chmod(np, mode); 863 } else { 864 /* Handle copying from a read-only 865 directory */ 866 mod_flag = 1; 867 if (mkdir(np, mode | S_IRWXU) < 0) 868 goto bad; 869 } 870 vect[0] = xstrdup(np); 871 sink(1, vect); 872 if (setimes) { 873 setimes = 0; 874 if (utimes(vect[0], tv) < 0) 875 run_err("%s: set times: %s", 876 vect[0], strerror(errno)); 877 } 878 if (mod_flag) 879 (void) chmod(vect[0], mode); 880 if (vect[0]) 881 xfree(vect[0]); 882 continue; 883 } 884 omode = mode; 885 mode |= S_IWRITE; 886 if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 887bad: run_err("%s: %s", np, strerror(errno)); 888 continue; 889 } 890 (void) atomicio(write, remout, "", 1); 891 if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) { 892 (void) close(ofd); 893 continue; 894 } 895 cp = bp->buf; 896 wrerr = NO; 897
|
826 if (showprogress) { 827 totalbytes = size; 828 progressmeter(-1); 829 }
| |
830 statbytes = 0;
| 898 statbytes = 0;
|
| 899 if (showprogress) 900 start_progress_meter(curfile, size, &statbytes);
|
831 for (count = i = 0; i < size; i += 4096) { 832 amt = 4096; 833 if (i + amt > size) 834 amt = size - i; 835 count += amt; 836 do { 837 j = read(remin, cp, amt); 838 if (j == -1 && (errno == EINTR || 839 errno == EAGAIN)) { 840 continue; 841 } else if (j <= 0) { 842 run_err("%s", j ? strerror(errno) : 843 "dropped connection"); 844 exit(1); 845 } 846 amt -= j; 847 cp += j; 848 statbytes += j; 849 } while (amt > 0);
| 901 for (count = i = 0; i < size; i += 4096) { 902 amt = 4096; 903 if (i + amt > size) 904 amt = size - i; 905 count += amt; 906 do { 907 j = read(remin, cp, amt); 908 if (j == -1 && (errno == EINTR || 909 errno == EAGAIN)) { 910 continue; 911 } else if (j <= 0) { 912 run_err("%s", j ? strerror(errno) : 913 "dropped connection"); 914 exit(1); 915 } 916 amt -= j; 917 cp += j; 918 statbytes += j; 919 } while (amt > 0);
|
| 920 921 if (limitbw) 922 bwlimit(4096); 923
|
850 if (count == bp->cnt) { 851 /* Keep reading so we stay sync'd up. */ 852 if (wrerr == NO) { 853 j = atomicio(write, ofd, bp->buf, count); 854 if (j != count) { 855 wrerr = YES; 856 wrerrno = j >= 0 ? EIO : errno; 857 } 858 } 859 count = 0; 860 cp = bp->buf; 861 } 862 } 863 if (showprogress)
| 924 if (count == bp->cnt) { 925 /* Keep reading so we stay sync'd up. */ 926 if (wrerr == NO) { 927 j = atomicio(write, ofd, bp->buf, count); 928 if (j != count) { 929 wrerr = YES; 930 wrerrno = j >= 0 ? EIO : errno; 931 } 932 } 933 count = 0; 934 cp = bp->buf; 935 } 936 } 937 if (showprogress)
|
864 progressmeter(1);
| 938 stop_progress_meter();
|
865 if (count != 0 && wrerr == NO && 866 (j = atomicio(write, ofd, bp->buf, count)) != count) { 867 wrerr = YES; 868 wrerrno = j >= 0 ? EIO : errno; 869 }
| 939 if (count != 0 && wrerr == NO && 940 (j = atomicio(write, ofd, bp->buf, count)) != count) { 941 wrerr = YES; 942 wrerrno = j >= 0 ? EIO : errno; 943 }
|
870 if (ftruncate(ofd, size)) {
| 944 if (wrerr == NO && ftruncate(ofd, size) != 0) {
|
871 run_err("%s: truncate: %s", np, strerror(errno)); 872 wrerr = DISPLAYED; 873 } 874 if (pflag) { 875 if (exists || omode != mode) 876#ifdef HAVE_FCHMOD 877 if (fchmod(ofd, omode)) 878#else /* HAVE_FCHMOD */ 879 if (chmod(np, omode)) 880#endif /* HAVE_FCHMOD */ 881 run_err("%s: set mode: %s", 882 np, strerror(errno)); 883 } else { 884 if (!exists && omode != mode) 885#ifdef HAVE_FCHMOD 886 if (fchmod(ofd, omode & ~mask)) 887#else /* HAVE_FCHMOD */ 888 if (chmod(np, omode & ~mask)) 889#endif /* HAVE_FCHMOD */ 890 run_err("%s: set mode: %s", 891 np, strerror(errno)); 892 } 893 if (close(ofd) == -1) { 894 wrerr = YES; 895 wrerrno = errno; 896 } 897 (void) response(); 898 if (setimes && wrerr == NO) { 899 setimes = 0; 900 if (utimes(np, tv) < 0) { 901 run_err("%s: set times: %s", 902 np, strerror(errno)); 903 wrerr = DISPLAYED; 904 } 905 } 906 switch (wrerr) { 907 case YES: 908 run_err("%s: %s", np, strerror(wrerrno)); 909 break; 910 case NO: 911 (void) atomicio(write, remout, "", 1); 912 break; 913 case DISPLAYED: 914 break; 915 } 916 } 917screwup: 918 run_err("protocol error: %s", why); 919 exit(1); 920} 921 922int 923response(void) 924{ 925 char ch, *cp, resp, rbuf[2048]; 926 927 if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp)) 928 lostconn(0); 929 930 cp = rbuf; 931 switch (resp) { 932 case 0: /* ok */ 933 return (0); 934 default: 935 *cp++ = resp; 936 /* FALLTHROUGH */ 937 case 1: /* error, followed by error msg */ 938 case 2: /* fatal error, "" */ 939 do { 940 if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) 941 lostconn(0); 942 *cp++ = ch; 943 } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n'); 944 945 if (!iamremote) 946 (void) atomicio(write, STDERR_FILENO, rbuf, cp - rbuf); 947 ++errs; 948 if (resp == 1) 949 return (-1); 950 exit(1); 951 } 952 /* NOTREACHED */ 953} 954 955void 956usage(void) 957{ 958 (void) fprintf(stderr,
| 945 run_err("%s: truncate: %s", np, strerror(errno)); 946 wrerr = DISPLAYED; 947 } 948 if (pflag) { 949 if (exists || omode != mode) 950#ifdef HAVE_FCHMOD 951 if (fchmod(ofd, omode)) 952#else /* HAVE_FCHMOD */ 953 if (chmod(np, omode)) 954#endif /* HAVE_FCHMOD */ 955 run_err("%s: set mode: %s", 956 np, strerror(errno)); 957 } else { 958 if (!exists && omode != mode) 959#ifdef HAVE_FCHMOD 960 if (fchmod(ofd, omode & ~mask)) 961#else /* HAVE_FCHMOD */ 962 if (chmod(np, omode & ~mask)) 963#endif /* HAVE_FCHMOD */ 964 run_err("%s: set mode: %s", 965 np, strerror(errno)); 966 } 967 if (close(ofd) == -1) { 968 wrerr = YES; 969 wrerrno = errno; 970 } 971 (void) response(); 972 if (setimes && wrerr == NO) { 973 setimes = 0; 974 if (utimes(np, tv) < 0) { 975 run_err("%s: set times: %s", 976 np, strerror(errno)); 977 wrerr = DISPLAYED; 978 } 979 } 980 switch (wrerr) { 981 case YES: 982 run_err("%s: %s", np, strerror(wrerrno)); 983 break; 984 case NO: 985 (void) atomicio(write, remout, "", 1); 986 break; 987 case DISPLAYED: 988 break; 989 } 990 } 991screwup: 992 run_err("protocol error: %s", why); 993 exit(1); 994} 995 996int 997response(void) 998{ 999 char ch, *cp, resp, rbuf[2048]; 1000 1001 if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp)) 1002 lostconn(0); 1003 1004 cp = rbuf; 1005 switch (resp) { 1006 case 0: /* ok */ 1007 return (0); 1008 default: 1009 *cp++ = resp; 1010 /* FALLTHROUGH */ 1011 case 1: /* error, followed by error msg */ 1012 case 2: /* fatal error, "" */ 1013 do { 1014 if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) 1015 lostconn(0); 1016 *cp++ = ch; 1017 } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n'); 1018 1019 if (!iamremote) 1020 (void) atomicio(write, STDERR_FILENO, rbuf, cp - rbuf); 1021 ++errs; 1022 if (resp == 1) 1023 return (-1); 1024 exit(1); 1025 } 1026 /* NOTREACHED */ 1027} 1028 1029void 1030usage(void) 1031{ 1032 (void) fprintf(stderr,
|
959 "usage: scp [-pqrvBC46] [-F config] [-S program] [-P port]\n" 960 " [-c cipher] [-i identity] [-o option]\n"
| 1033 "usage: scp [-pqrvBC1246] [-F config] [-S program] [-P port]\n" 1034 " [-c cipher] [-i identity] [-l limit] [-o option]\n"
|
961 " [[user@]host1:]file1 [...] [[user@]host2:]file2\n"); 962 exit(1); 963} 964 965void 966run_err(const char *fmt,...) 967{ 968 static FILE *fp; 969 va_list ap; 970 971 ++errs; 972 if (fp == NULL && !(fp = fdopen(remout, "w"))) 973 return; 974 (void) fprintf(fp, "%c", 0x01); 975 (void) fprintf(fp, "scp: "); 976 va_start(ap, fmt); 977 (void) vfprintf(fp, fmt, ap); 978 va_end(ap); 979 (void) fprintf(fp, "\n"); 980 (void) fflush(fp); 981 982 if (!iamremote) { 983 va_start(ap, fmt); 984 vfprintf(stderr, fmt, ap); 985 va_end(ap); 986 fprintf(stderr, "\n"); 987 } 988} 989 990void 991verifydir(cp) 992 char *cp; 993{ 994 struct stat stb; 995 996 if (!stat(cp, &stb)) { 997 if (S_ISDIR(stb.st_mode)) 998 return; 999 errno = ENOTDIR; 1000 } 1001 run_err("%s: %s", cp, strerror(errno)); 1002 exit(1); 1003} 1004 1005int 1006okname(cp0) 1007 char *cp0; 1008{ 1009 int c; 1010 char *cp; 1011 1012 cp = cp0; 1013 do { 1014 c = (int)*cp; 1015 if (c & 0200) 1016 goto bad;
| 1035 " [[user@]host1:]file1 [...] [[user@]host2:]file2\n"); 1036 exit(1); 1037} 1038 1039void 1040run_err(const char *fmt,...) 1041{ 1042 static FILE *fp; 1043 va_list ap; 1044 1045 ++errs; 1046 if (fp == NULL && !(fp = fdopen(remout, "w"))) 1047 return; 1048 (void) fprintf(fp, "%c", 0x01); 1049 (void) fprintf(fp, "scp: "); 1050 va_start(ap, fmt); 1051 (void) vfprintf(fp, fmt, ap); 1052 va_end(ap); 1053 (void) fprintf(fp, "\n"); 1054 (void) fflush(fp); 1055 1056 if (!iamremote) { 1057 va_start(ap, fmt); 1058 vfprintf(stderr, fmt, ap); 1059 va_end(ap); 1060 fprintf(stderr, "\n"); 1061 } 1062} 1063 1064void 1065verifydir(cp) 1066 char *cp; 1067{ 1068 struct stat stb; 1069 1070 if (!stat(cp, &stb)) { 1071 if (S_ISDIR(stb.st_mode)) 1072 return; 1073 errno = ENOTDIR; 1074 } 1075 run_err("%s: %s", cp, strerror(errno)); 1076 exit(1); 1077} 1078 1079int 1080okname(cp0) 1081 char *cp0; 1082{ 1083 int c; 1084 char *cp; 1085 1086 cp = cp0; 1087 do { 1088 c = (int)*cp; 1089 if (c & 0200) 1090 goto bad;
|
1017 if (!isalpha(c) && !isdigit(c) && 1018 c != '_' && c != '-' && c != '.' && c != '+') 1019 goto bad;
| 1091 if (!isalpha(c) && !isdigit(c)) { 1092 switch (c) { 1093 case '\'': 1094 case '"': 1095 case '`': 1096 case ' ': 1097 case '#': 1098 goto bad; 1099 default: 1100 break; 1101 } 1102 }
|
1020 } while (*++cp); 1021 return (1); 1022 1023bad: fprintf(stderr, "%s: invalid user name\n", cp0); 1024 return (0); 1025} 1026 1027BUF * 1028allocbuf(bp, fd, blksize) 1029 BUF *bp; 1030 int fd, blksize; 1031{ 1032 size_t size; 1033#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE 1034 struct stat stb; 1035 1036 if (fstat(fd, &stb) < 0) { 1037 run_err("fstat: %s", strerror(errno)); 1038 return (0); 1039 }
| 1103 } while (*++cp); 1104 return (1); 1105 1106bad: fprintf(stderr, "%s: invalid user name\n", cp0); 1107 return (0); 1108} 1109 1110BUF * 1111allocbuf(bp, fd, blksize) 1112 BUF *bp; 1113 int fd, blksize; 1114{ 1115 size_t size; 1116#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE 1117 struct stat stb; 1118 1119 if (fstat(fd, &stb) < 0) { 1120 run_err("fstat: %s", strerror(errno)); 1121 return (0); 1122 }
|
1040 if (stb.st_blksize == 0)
| 1123 size = roundup(stb.st_blksize, blksize); 1124 if (size == 0)
|
1041 size = blksize;
| 1125 size = blksize;
|
1042 else 1043 size = roundup(stb.st_blksize, blksize);
| |
1044#else /* HAVE_STRUCT_STAT_ST_BLKSIZE */ 1045 size = blksize; 1046#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ 1047 if (bp->cnt >= size) 1048 return (bp); 1049 if (bp->buf == NULL) 1050 bp->buf = xmalloc(size); 1051 else 1052 bp->buf = xrealloc(bp->buf, size); 1053 memset(bp->buf, 0, size); 1054 bp->cnt = size; 1055 return (bp); 1056} 1057 1058void 1059lostconn(signo) 1060 int signo; 1061{ 1062 if (!iamremote) 1063 write(STDERR_FILENO, "lost connection\n", 16); 1064 if (signo) 1065 _exit(1); 1066 else 1067 exit(1); 1068}
| 1126#else /* HAVE_STRUCT_STAT_ST_BLKSIZE */ 1127 size = blksize; 1128#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ 1129 if (bp->cnt >= size) 1130 return (bp); 1131 if (bp->buf == NULL) 1132 bp->buf = xmalloc(size); 1133 else 1134 bp->buf = xrealloc(bp->buf, size); 1135 memset(bp->buf, 0, size); 1136 bp->cnt = size; 1137 return (bp); 1138} 1139 1140void 1141lostconn(signo) 1142 int signo; 1143{ 1144 if (!iamremote) 1145 write(STDERR_FILENO, "lost connection\n", 16); 1146 if (signo) 1147 _exit(1); 1148 else 1149 exit(1); 1150}
|
1069 1070static void 1071updateprogressmeter(int ignore) 1072{ 1073 int save_errno = errno; 1074 1075 progressmeter(0); 1076 signal(SIGALRM, updateprogressmeter); 1077 alarm(PROGRESSTIME); 1078 errno = save_errno; 1079} 1080 1081static int 1082foregroundproc(void) 1083{ 1084 static pid_t pgrp = -1; 1085 int ctty_pgrp; 1086 1087 if (pgrp == -1) 1088 pgrp = getpgrp(); 1089 1090#ifdef HAVE_TCGETPGRP 1091 return ((ctty_pgrp = tcgetpgrp(STDOUT_FILENO)) != -1 && 1092 ctty_pgrp == pgrp); 1093#else 1094 return ((ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 && 1095 ctty_pgrp == pgrp)); 1096#endif 1097} 1098 1099void 1100progressmeter(int flag) 1101{ 1102 static const char prefixes[] = " KMGTP"; 1103 static struct timeval lastupdate; 1104 static off_t lastsize; 1105 struct timeval now, td, wait; 1106 off_t cursize, abbrevsize; 1107 double elapsed; 1108 int ratio, barlength, i, remaining; 1109 char buf[512]; 1110 1111 if (flag == -1) { 1112 (void) gettimeofday(&start, (struct timezone *) 0); 1113 lastupdate = start; 1114 lastsize = 0; 1115 } 1116 if (foregroundproc() == 0) 1117 return; 1118 1119 (void) gettimeofday(&now, (struct timezone *) 0); 1120 cursize = statbytes; 1121 if (totalbytes != 0) { 1122 ratio = 100.0 * cursize / totalbytes; 1123 ratio = MAX(ratio, 0); 1124 ratio = MIN(ratio, 100); 1125 } else 1126 ratio = 100; 1127 1128 snprintf(buf, sizeof(buf), "\r%-20.20s %3d%% ", curfile, ratio); 1129 1130 barlength = getttywidth() - 51; 1131 if (barlength > 0) { 1132 i = barlength * ratio / 100; 1133 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1134 "|%.*s%*s|", i, 1135 "*******************************************************" 1136 "*******************************************************" 1137 "*******************************************************" 1138 "*******************************************************" 1139 "*******************************************************" 1140 "*******************************************************" 1141 "*******************************************************", 1142 barlength - i, ""); 1143 } 1144 i = 0; 1145 abbrevsize = cursize; 1146 while (abbrevsize >= 100000 && i < sizeof(prefixes)) { 1147 i++; 1148 abbrevsize >>= 10; 1149 } 1150 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5lu %c%c ", 1151 (unsigned long) abbrevsize, prefixes[i], 1152 prefixes[i] == ' ' ? ' ' : 'B'); 1153 1154 timersub(&now, &lastupdate, &wait); 1155 if (cursize > lastsize) { 1156 lastupdate = now; 1157 lastsize = cursize; 1158 if (wait.tv_sec >= STALLTIME) { 1159 start.tv_sec += wait.tv_sec; 1160 start.tv_usec += wait.tv_usec; 1161 } 1162 wait.tv_sec = 0; 1163 } 1164 timersub(&now, &start, &td); 1165 elapsed = td.tv_sec + (td.tv_usec / 1000000.0); 1166 1167 if (flag != 1 && 1168 (statbytes <= 0 || elapsed <= 0.0 || cursize > totalbytes)) { 1169 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1170 " --:-- ETA"); 1171 } else if (wait.tv_sec >= STALLTIME) { 1172 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1173 " - stalled -"); 1174 } else { 1175 if (flag != 1) 1176 remaining = (int)(totalbytes / (statbytes / elapsed) - 1177 elapsed); 1178 else 1179 remaining = elapsed; 1180 1181 i = remaining / 3600; 1182 if (i) 1183 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1184 "%2d:", i); 1185 else 1186 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1187 " "); 1188 i = remaining % 3600; 1189 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1190 "%02d:%02d%s", i / 60, i % 60, 1191 (flag != 1) ? " ETA" : " "); 1192 } 1193 atomicio(write, fileno(stdout), buf, strlen(buf)); 1194 1195 if (flag == -1) { 1196 mysignal(SIGALRM, updateprogressmeter); 1197 alarm(PROGRESSTIME); 1198 } else if (flag == 1) { 1199 alarm(0); 1200 atomicio(write, fileno(stdout), "\n", 1); 1201 statbytes = 0; 1202 } 1203} 1204 1205int 1206getttywidth(void) 1207{ 1208 struct winsize winsize; 1209 1210 if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1) 1211 return (winsize.ws_col ? winsize.ws_col : 80); 1212 else 1213 return (80); 1214}
| |
| |