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