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" 78 RCSID("$OpenBSD: scp.c,v 1.43 2000/10/18 18:23:02 markus Exp $"); 79 80 #include "ssh.h" 81 #include "xmalloc.h" 82 83 #define _PATH_CP "cp" 84 85 /* For progressmeter() -- number of seconds before xfer considered "stalled" */ 86 #define STALLTIME 5 87 88 /* Visual statistics about files as they are transferred. */ 89 void progressmeter(int); 90 91 /* Returns width of the terminal (for progress meter calculations). */ 92 int getttywidth(void); 93 int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc); 94 95 /* setup arguments for the call to ssh */ 96 void addargs(char *fmt, ...) __attribute__((format(printf, 1, 2))); 97 98 /* Time a transfer started. */ 99 static struct timeval start; 100 101 /* Number of bytes of current file transferred so far. */ 102 volatile unsigned long statbytes; 103 104 /* Total size of current file. */ 105 off_t totalbytes = 0; 106 107 /* Name of current file being transferred. */ 108 char *curfile; 109 110 /* This is set to non-zero to enable verbose mode. */ 111 int verbose_mode = 0; 112 113 /* This is set to non-zero if compression is desired. */ 114 int compress = 0; 115 116 /* This is set to zero if the progressmeter is not desired. */ 117 int showprogress = 1; 118 119 /* This is the program to execute for the secured connection. ("ssh" or -S) */ 120 char *ssh_program = SSH_PROGRAM; 121 122 /* This is the list of arguments that scp passes to ssh */ 123 struct { 124 char **list; 125 int num; 126 int nalloc; 127 } args; 128 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 135 int 136 do_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, "Executing: program %s host %s, user %s, command %s\n", 142 ssh_program, host, remuser ? remuser : "(unspecified)", cmd); 143 144 /* 145 * Reserve two descriptors so that the real pipes won't get 146 * descriptors 0 and 1 because that will screw up dup2 below. 147 */ 148 pipe(reserved); 149 150 /* Create a socket pair for communicating with ssh. */ 151 if (pipe(pin) < 0) 152 fatal("pipe: %s", strerror(errno)); 153 if (pipe(pout) < 0) 154 fatal("pipe: %s", strerror(errno)); 155 156 /* Free the reserved descriptors. */ 157 close(reserved[0]); 158 close(reserved[1]); 159 160 /* For a child to execute the command on the remote host using ssh. */ 161 if (fork() == 0) { 162 /* Child. */ 163 close(pin[1]); 164 close(pout[0]); 165 dup2(pin[0], 0); 166 dup2(pout[1], 1); 167 close(pin[0]); 168 close(pout[1]); 169 170 args.list[0] = ssh_program; 171 if (remuser != NULL) 172 addargs("-l%s", remuser); 173 addargs("%s", host); 174 addargs("%s", cmd); 175 176 execvp(ssh_program, args.list); 177 perror(ssh_program); 178 exit(1); 179 } 180 /* Parent. Close the other side, and return the local side. */ 181 close(pin[0]); 182 *fdout = pin[1]; 183 close(pout[1]); 184 *fdin = pout[0]; 185 return 0; 186 } 187 188 void 189 fatal(const char *fmt,...) 190 { 191 va_list ap; 192 char buf[1024]; 193 194 va_start(ap, fmt); 195 vsnprintf(buf, sizeof(buf), fmt, ap); 196 va_end(ap); 197 fprintf(stderr, "%s\n", buf); 198 exit(255); 199 } 200 201 typedef struct { 202 int cnt; 203 char *buf; 204 } BUF; 205 206 extern int iamremote; 207 208 BUF *allocbuf(BUF *, int, int); 209 char *colon(char *); 210 void lostconn(int); 211 void nospace(void); 212 int okname(char *); 213 void run_err(const char *,...); 214 void verifydir(char *); 215 216 struct passwd *pwd; 217 uid_t userid; 218 int errs, remin, remout; 219 int pflag, iamremote, iamrecursive, targetshouldbedirectory; 220 221 #define CMDNEEDS 64 222 char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 223 224 int response(void); 225 void rsource(char *, struct stat *); 226 void sink(int, char *[]); 227 void source(int, char *[]); 228 void tolocal(int, char *[]); 229 void toremote(char *, int, char *[]); 230 void usage(void); 231 232 int 233 main(argc, argv) 234 int argc; 235 char *argv[]; 236 { 237 int ch, fflag, tflag; 238 char *targ; 239 extern char *optarg; 240 extern int optind; 241 242 args.list = NULL; 243 addargs("ssh"); /* overwritten with ssh_program */ 244 addargs("-x"); 245 addargs("-oFallBackToRsh no"); 246 247 fflag = tflag = 0; 248 while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:")) != EOF) 249 switch (ch) { 250 /* User-visible flags. */ 251 case '4': 252 case '6': 253 case 'C': 254 addargs("-%c", ch); 255 break; 256 case 'o': 257 case 'c': 258 case 'i': 259 addargs("-%c%s", ch, optarg); 260 break; 261 case 'P': 262 addargs("-p%s", optarg); 263 break; 264 case 'B': 265 addargs("-oBatchmode yes"); 266 break; 267 case 'p': 268 pflag = 1; 269 break; 270 case 'r': 271 iamrecursive = 1; 272 break; 273 case 'S': 274 ssh_program = xstrdup(optarg); 275 break; 276 case 'v': 277 verbose_mode = 1; 278 break; 279 case 'q': 280 showprogress = 0; 281 break; 282 283 /* Server options. */ 284 case 'd': 285 targetshouldbedirectory = 1; 286 break; 287 case 'f': /* "from" */ 288 iamremote = 1; 289 fflag = 1; 290 break; 291 case 't': /* "to" */ 292 iamremote = 1; 293 tflag = 1; 294 break; 295 case '?': 296 default: 297 usage(); 298 } 299 argc -= optind; 300 argv += optind; 301 302 if ((pwd = getpwuid(userid = getuid())) == NULL) 303 fatal("unknown user %d", (int) userid); 304 305 if (!isatty(STDERR_FILENO)) 306 showprogress = 0; 307 308 remin = STDIN_FILENO; 309 remout = STDOUT_FILENO; 310 311 if (fflag) { 312 /* Follow "protocol", send data. */ 313 (void) response(); 314 source(argc, argv); 315 exit(errs != 0); 316 } 317 if (tflag) { 318 /* Receive data. */ 319 sink(argc, argv); 320 exit(errs != 0); 321 } 322 if (argc < 2) 323 usage(); 324 if (argc > 2) 325 targetshouldbedirectory = 1; 326 327 remin = remout = -1; 328 /* Command to be executed on remote system using "ssh". */ 329 (void) sprintf(cmd, "scp%s%s%s%s", verbose_mode ? " -v" : "", 330 iamrecursive ? " -r" : "", pflag ? " -p" : "", 331 targetshouldbedirectory ? " -d" : ""); 332 333 (void) signal(SIGPIPE, lostconn); 334 335 if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ 336 toremote(targ, argc, argv); 337 else { 338 tolocal(argc, argv); /* Dest is local host. */ 339 if (targetshouldbedirectory) 340 verifydir(argv[argc - 1]); 341 } 342 exit(errs != 0); 343 } 344 345 char * 346 cleanhostname(host) 347 char *host; 348 { 349 if (*host == '[' && host[strlen(host) - 1] == ']') { 350 host[strlen(host) - 1] = '\0'; 351 return (host + 1); 352 } else 353 return host; 354 } 355 356 void 357 toremote(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 368 if ((thost = strchr(argv[argc - 1], '@'))) { 369 /* user@host */ 370 *thost++ = 0; 371 tuser = argv[argc - 1]; 372 if (*tuser == '\0') 373 tuser = NULL; 374 else if (!okname(tuser)) 375 exit(1); 376 } else { 377 thost = argv[argc - 1]; 378 tuser = NULL; 379 } 380 381 for (i = 0; i < argc - 1; i++) { 382 src = colon(argv[i]); 383 if (src) { /* remote to remote */ 384 *src++ = 0; 385 if (*src == 0) 386 src = "."; 387 host = strchr(argv[i], '@'); 388 len = strlen(ssh_program) + strlen(argv[i]) + 389 strlen(src) + (tuser ? strlen(tuser) : 0) + 390 strlen(thost) + strlen(targ) + CMDNEEDS + 32; 391 bp = xmalloc(len); 392 if (host) { 393 *host++ = 0; 394 host = cleanhostname(host); 395 suser = argv[i]; 396 if (*suser == '\0') 397 suser = pwd->pw_name; 398 else if (!okname(suser)) 399 continue; 400 (void) sprintf(bp, 401 "%s%s -x -o'FallBackToRsh no' -n -l %s %s %s %s '%s%s%s:%s'", 402 ssh_program, verbose_mode ? " -v" : "", 403 suser, host, cmd, src, 404 tuser ? tuser : "", tuser ? "@" : "", 405 thost, targ); 406 } else { 407 host = cleanhostname(argv[i]); 408 (void) sprintf(bp, 409 "exec %s%s -x -o'FallBackToRsh no' -n %s %s %s '%s%s%s:%s'", 410 ssh_program, verbose_mode ? " -v" : "", 411 host, cmd, src, 412 tuser ? tuser : "", tuser ? "@" : "", 413 thost, targ); 414 } 415 if (verbose_mode) 416 fprintf(stderr, "Executing: %s\n", bp); 417 (void) system(bp); 418 (void) xfree(bp); 419 } else { /* local to remote */ 420 if (remin == -1) { 421 len = strlen(targ) + CMDNEEDS + 20; 422 bp = xmalloc(len); 423 (void) sprintf(bp, "%s -t %s", cmd, targ); 424 host = cleanhostname(thost); 425 if (do_cmd(host, tuser, bp, &remin, 426 &remout, argc) < 0) 427 exit(1); 428 if (response() < 0) 429 exit(1); 430 (void) xfree(bp); 431 } 432 source(1, argv + i); 433 } 434 } 435 } 436 437 void 438 tolocal(argc, argv) 439 int argc; 440 char *argv[]; 441 { 442 int i, len; 443 char *bp, *host, *src, *suser; 444 445 for (i = 0; i < argc - 1; i++) { 446 if (!(src = colon(argv[i]))) { /* Local to local. */ 447 len = strlen(_PATH_CP) + strlen(argv[i]) + 448 strlen(argv[argc - 1]) + 20; 449 bp = xmalloc(len); 450 (void) sprintf(bp, "exec %s%s%s %s %s", _PATH_CP, 451 iamrecursive ? " -r" : "", pflag ? " -p" : "", 452 argv[i], argv[argc - 1]); 453 if (verbose_mode) 454 fprintf(stderr, "Executing: %s\n", bp); 455 if (system(bp)) 456 ++errs; 457 (void) xfree(bp); 458 continue; 459 } 460 *src++ = 0; 461 if (*src == 0) 462 src = "."; 463 if ((host = strchr(argv[i], '@')) == NULL) { 464 host = argv[i]; 465 suser = NULL; 466 } else { 467 *host++ = 0; 468 suser = argv[i]; 469 if (*suser == '\0') 470 suser = pwd->pw_name; 471 else if (!okname(suser)) 472 continue; 473 } 474 host = cleanhostname(host); 475 len = strlen(src) + CMDNEEDS + 20; 476 bp = xmalloc(len); 477 (void) sprintf(bp, "%s -f %s", cmd, src); 478 if (do_cmd(host, suser, bp, &remin, &remout, argc) < 0) { 479 (void) xfree(bp); 480 ++errs; 481 continue; 482 } 483 xfree(bp); 484 sink(1, argv + argc - 1); 485 (void) close(remin); 486 remin = remout = -1; 487 } 488 } 489 490 void 491 source(argc, argv) 492 int argc; 493 char *argv[]; 494 { 495 struct stat stb; 496 static BUF buffer; 497 BUF *bp; 498 off_t i; 499 int amt, fd, haderr, indx, result; 500 char *last, *name, buf[2048]; 501 502 for (indx = 0; indx < argc; ++indx) { 503 name = argv[indx]; 504 statbytes = 0; 505 if ((fd = open(name, O_RDONLY, 0)) < 0) 506 goto syserr; 507 if (fstat(fd, &stb) < 0) { 508 syserr: run_err("%s: %s", name, strerror(errno)); 509 goto next; 510 } 511 switch (stb.st_mode & S_IFMT) { 512 case S_IFREG: 513 break; 514 case S_IFDIR: 515 if (iamrecursive) { 516 rsource(name, &stb); 517 goto next; 518 } 519 /* FALLTHROUGH */ 520 default: 521 run_err("%s: not a regular file", name); 522 goto next; 523 } 524 if ((last = strrchr(name, '/')) == NULL) 525 last = name; 526 else 527 ++last; 528 curfile = last; 529 if (pflag) { 530 /* 531 * Make it compatible with possible future 532 * versions expecting microseconds. 533 */ 534 (void) sprintf(buf, "T%lu 0 %lu 0\n", 535 (unsigned long) stb.st_mtime, 536 (unsigned long) stb.st_atime); 537 (void) atomicio(write, remout, buf, strlen(buf)); 538 if (response() < 0) 539 goto next; 540 } 541 #define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) 542 (void) sprintf(buf, "C%04o %lu %s\n", 543 (unsigned int) (stb.st_mode & FILEMODEMASK), 544 (unsigned long) stb.st_size, 545 last); 546 if (verbose_mode) { 547 fprintf(stderr, "Sending file modes: %s", buf); 548 fflush(stderr); 549 } 550 (void) atomicio(write, remout, buf, strlen(buf)); 551 if (response() < 0) 552 goto next; 553 if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) { 554 next: (void) close(fd); 555 continue; 556 } 557 if (showprogress) { 558 totalbytes = stb.st_size; 559 progressmeter(-1); 560 } 561 /* Keep writing after an error so that we stay sync'd up. */ 562 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 563 amt = bp->cnt; 564 if (i + amt > stb.st_size) 565 amt = stb.st_size - i; 566 if (!haderr) { 567 result = atomicio(read, fd, bp->buf, amt); 568 if (result != amt) 569 haderr = result >= 0 ? EIO : errno; 570 } 571 if (haderr) 572 (void) atomicio(write, remout, bp->buf, amt); 573 else { 574 result = atomicio(write, remout, bp->buf, amt); 575 if (result != amt) 576 haderr = result >= 0 ? EIO : errno; 577 statbytes += result; 578 } 579 } 580 if (showprogress) 581 progressmeter(1); 582 583 if (close(fd) < 0 && !haderr) 584 haderr = errno; 585 if (!haderr) 586 (void) atomicio(write, remout, "", 1); 587 else 588 run_err("%s: %s", name, strerror(haderr)); 589 (void) response(); 590 } 591 } 592 593 void 594 rsource(name, statp) 595 char *name; 596 struct stat *statp; 597 { 598 DIR *dirp; 599 struct dirent *dp; 600 char *last, *vect[1], path[1100]; 601 602 if (!(dirp = opendir(name))) { 603 run_err("%s: %s", name, strerror(errno)); 604 return; 605 } 606 last = strrchr(name, '/'); 607 if (last == 0) 608 last = name; 609 else 610 last++; 611 if (pflag) { 612 (void) sprintf(path, "T%lu 0 %lu 0\n", 613 (unsigned long) statp->st_mtime, 614 (unsigned long) statp->st_atime); 615 (void) atomicio(write, remout, path, strlen(path)); 616 if (response() < 0) { 617 closedir(dirp); 618 return; 619 } 620 } 621 (void) sprintf(path, "D%04o %d %.1024s\n", 622 (unsigned int) (statp->st_mode & FILEMODEMASK), 0, last); 623 if (verbose_mode) 624 fprintf(stderr, "Entering directory: %s", path); 625 (void) atomicio(write, remout, path, strlen(path)); 626 if (response() < 0) { 627 closedir(dirp); 628 return; 629 } 630 while ((dp = readdir(dirp))) { 631 if (dp->d_ino == 0) 632 continue; 633 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 634 continue; 635 if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) { 636 run_err("%s/%s: name too long", name, dp->d_name); 637 continue; 638 } 639 (void) sprintf(path, "%s/%s", name, dp->d_name); 640 vect[0] = path; 641 source(1, vect); 642 } 643 (void) closedir(dirp); 644 (void) atomicio(write, remout, "E\n", 2); 645 (void) response(); 646 } 647 648 void 649 sink(argc, argv) 650 int argc; 651 char *argv[]; 652 { 653 static BUF buffer; 654 struct stat stb; 655 enum { 656 YES, NO, DISPLAYED 657 } wrerr; 658 BUF *bp; 659 off_t i, j; 660 int amt, count, exists, first, mask, mode, ofd, omode; 661 off_t size; 662 int setimes, targisdir, wrerrno = 0; 663 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; 664 int dummy_usec; 665 struct timeval tv[2]; 666 667 #define SCREWUP(str) { why = str; goto screwup; } 668 669 setimes = targisdir = 0; 670 mask = umask(0); 671 if (!pflag) 672 (void) umask(mask); 673 if (argc != 1) { 674 run_err("ambiguous target"); 675 exit(1); 676 } 677 targ = *argv; 678 if (targetshouldbedirectory) 679 verifydir(targ); 680 681 (void) atomicio(write, remout, "", 1); 682 if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) 683 targisdir = 1; 684 for (first = 1;; first = 0) { 685 cp = buf; 686 if (atomicio(read, remin, cp, 1) <= 0) 687 return; 688 if (*cp++ == '\n') 689 SCREWUP("unexpected <newline>"); 690 do { 691 if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) 692 SCREWUP("lost connection"); 693 *cp++ = ch; 694 } while (cp < &buf[sizeof(buf) - 1] && ch != '\n'); 695 *cp = 0; 696 697 if (buf[0] == '\01' || buf[0] == '\02') { 698 if (iamremote == 0) 699 (void) atomicio(write, STDERR_FILENO, 700 buf + 1, strlen(buf + 1)); 701 if (buf[0] == '\02') 702 exit(1); 703 ++errs; 704 continue; 705 } 706 if (buf[0] == 'E') { 707 (void) atomicio(write, remout, "", 1); 708 return; 709 } 710 if (ch == '\n') 711 *--cp = 0; 712 713 #define getnum(t) (t) = 0; \ 714 while (*cp >= '0' && *cp <= '9') (t) = (t) * 10 + (*cp++ - '0'); 715 cp = buf; 716 if (*cp == 'T') { 717 setimes++; 718 cp++; 719 getnum(tv[1].tv_sec); 720 if (*cp++ != ' ') 721 SCREWUP("mtime.sec not delimited"); 722 getnum(dummy_usec); 723 tv[1].tv_usec = 0; 724 if (*cp++ != ' ') 725 SCREWUP("mtime.usec not delimited"); 726 getnum(tv[0].tv_sec); 727 if (*cp++ != ' ') 728 SCREWUP("atime.sec not delimited"); 729 getnum(dummy_usec); 730 tv[0].tv_usec = 0; 731 if (*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; *cp >= '0' && *cp <= '9';) 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 namebuf = xmalloc(need); 771 (void) sprintf(namebuf, "%s%s%s", targ, 772 *targ ? "/" : "", cp); 773 np = namebuf; 774 } else 775 np = targ; 776 curfile = cp; 777 exists = stat(np, &stb) == 0; 778 if (buf[0] == 'D') { 779 int mod_flag = pflag; 780 if (exists) { 781 if (!S_ISDIR(stb.st_mode)) { 782 errno = ENOTDIR; 783 goto bad; 784 } 785 if (pflag) 786 (void) chmod(np, mode); 787 } else { 788 /* Handle copying from a read-only 789 directory */ 790 mod_flag = 1; 791 if (mkdir(np, mode | S_IRWXU) < 0) 792 goto bad; 793 } 794 vect[0] = np; 795 sink(1, vect); 796 if (setimes) { 797 setimes = 0; 798 if (utimes(np, tv) < 0) 799 run_err("%s: set times: %s", 800 np, strerror(errno)); 801 } 802 if (mod_flag) 803 (void) chmod(np, mode); 804 continue; 805 } 806 omode = mode; 807 mode |= S_IWRITE; 808 if ((ofd = open(np, O_WRONLY | O_CREAT | O_TRUNC, mode)) < 0) { 809 bad: run_err("%s: %s", np, strerror(errno)); 810 continue; 811 } 812 (void) atomicio(write, remout, "", 1); 813 if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) { 814 (void) close(ofd); 815 continue; 816 } 817 cp = bp->buf; 818 wrerr = NO; 819 820 if (showprogress) { 821 totalbytes = size; 822 progressmeter(-1); 823 } 824 statbytes = 0; 825 for (count = i = 0; i < size; i += 4096) { 826 amt = 4096; 827 if (i + amt > size) 828 amt = size - i; 829 count += amt; 830 do { 831 j = read(remin, cp, amt); 832 if (j == -1 && (errno == EINTR || errno == EAGAIN)) { 833 continue; 834 } else if (j <= 0) { 835 run_err("%s", j ? strerror(errno) : 836 "dropped connection"); 837 exit(1); 838 } 839 amt -= j; 840 cp += j; 841 statbytes += j; 842 } while (amt > 0); 843 if (count == bp->cnt) { 844 /* Keep reading so we stay sync'd up. */ 845 if (wrerr == NO) { 846 j = atomicio(write, ofd, bp->buf, count); 847 if (j != count) { 848 wrerr = YES; 849 wrerrno = j >= 0 ? EIO : errno; 850 } 851 } 852 count = 0; 853 cp = bp->buf; 854 } 855 } 856 if (showprogress) 857 progressmeter(1); 858 if (count != 0 && wrerr == NO && 859 (j = atomicio(write, ofd, bp->buf, count)) != count) { 860 wrerr = YES; 861 wrerrno = j >= 0 ? EIO : errno; 862 } 863 #if 0 864 if (ftruncate(ofd, size)) { 865 run_err("%s: truncate: %s", np, strerror(errno)); 866 wrerr = DISPLAYED; 867 } 868 #endif 869 if (pflag) { 870 if (exists || omode != mode) 871 if (fchmod(ofd, omode)) 872 run_err("%s: set mode: %s", 873 np, strerror(errno)); 874 } else { 875 if (!exists && omode != mode) 876 if (fchmod(ofd, omode & ~mask)) 877 run_err("%s: set mode: %s", 878 np, strerror(errno)); 879 } 880 if (close(ofd) == -1) { 881 wrerr = YES; 882 wrerrno = errno; 883 } 884 (void) response(); 885 if (setimes && wrerr == NO) { 886 setimes = 0; 887 if (utimes(np, tv) < 0) { 888 run_err("%s: set times: %s", 889 np, strerror(errno)); 890 wrerr = DISPLAYED; 891 } 892 } 893 switch (wrerr) { 894 case YES: 895 run_err("%s: %s", np, strerror(wrerrno)); 896 break; 897 case NO: 898 (void) atomicio(write, remout, "", 1); 899 break; 900 case DISPLAYED: 901 break; 902 } 903 } 904 screwup: 905 run_err("protocol error: %s", why); 906 exit(1); 907 } 908 909 int 910 response() 911 { 912 char ch, *cp, resp, rbuf[2048]; 913 914 if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp)) 915 lostconn(0); 916 917 cp = rbuf; 918 switch (resp) { 919 case 0: /* ok */ 920 return (0); 921 default: 922 *cp++ = resp; 923 /* FALLTHROUGH */ 924 case 1: /* error, followed by error msg */ 925 case 2: /* fatal error, "" */ 926 do { 927 if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) 928 lostconn(0); 929 *cp++ = ch; 930 } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n'); 931 932 if (!iamremote) 933 (void) atomicio(write, STDERR_FILENO, rbuf, cp - rbuf); 934 ++errs; 935 if (resp == 1) 936 return (-1); 937 exit(1); 938 } 939 /* NOTREACHED */ 940 } 941 942 void 943 usage() 944 { 945 (void) fprintf(stderr, "usage: scp " 946 "[-pqrvC46] [-S ssh] [-P port] [-c cipher] [-i identity] f1 f2; or:\n" 947 " scp [options] f1 ... fn directory\n"); 948 exit(1); 949 } 950 951 void 952 run_err(const char *fmt,...) 953 { 954 static FILE *fp; 955 va_list ap; 956 va_start(ap, fmt); 957 958 ++errs; 959 if (fp == NULL && !(fp = fdopen(remout, "w"))) 960 return; 961 (void) fprintf(fp, "%c", 0x01); 962 (void) fprintf(fp, "scp: "); 963 (void) vfprintf(fp, fmt, ap); 964 (void) fprintf(fp, "\n"); 965 (void) fflush(fp); 966 967 if (!iamremote) { 968 vfprintf(stderr, fmt, ap); 969 fprintf(stderr, "\n"); 970 } 971 va_end(ap); 972 } 973 974 char * 975 colon(cp) 976 char *cp; 977 { 978 int flag = 0; 979 980 if (*cp == ':') /* Leading colon is part of file name. */ 981 return (0); 982 if (*cp == '[') 983 flag = 1; 984 985 for (; *cp; ++cp) { 986 if (*cp == '@' && *(cp+1) == '[') 987 flag = 1; 988 if (*cp == ']' && *(cp+1) == ':' && flag) 989 return (cp+1); 990 if (*cp == ':' && !flag) 991 return (cp); 992 if (*cp == '/') 993 return (0); 994 } 995 return (0); 996 } 997 998 void 999 verifydir(cp) 1000 char *cp; 1001 { 1002 struct stat stb; 1003 1004 if (!stat(cp, &stb)) { 1005 if (S_ISDIR(stb.st_mode)) 1006 return; 1007 errno = ENOTDIR; 1008 } 1009 run_err("%s: %s", cp, strerror(errno)); 1010 exit(1); 1011 } 1012 1013 int 1014 okname(cp0) 1015 char *cp0; 1016 { 1017 int c; 1018 char *cp; 1019 1020 cp = cp0; 1021 do { 1022 c = *cp; 1023 if (c & 0200) 1024 goto bad; 1025 if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-' && c != '.') 1026 goto bad; 1027 } while (*++cp); 1028 return (1); 1029 1030 bad: fprintf(stderr, "%s: invalid user name\n", cp0); 1031 return (0); 1032 } 1033 1034 BUF * 1035 allocbuf(bp, fd, blksize) 1036 BUF *bp; 1037 int fd, blksize; 1038 { 1039 size_t size; 1040 struct stat stb; 1041 1042 if (fstat(fd, &stb) < 0) { 1043 run_err("fstat: %s", strerror(errno)); 1044 return (0); 1045 } 1046 if (stb.st_blksize == 0) 1047 size = blksize; 1048 else 1049 size = blksize + (stb.st_blksize - blksize % stb.st_blksize) % 1050 stb.st_blksize; 1051 if (bp->cnt >= size) 1052 return (bp); 1053 if (bp->buf == NULL) 1054 bp->buf = xmalloc(size); 1055 else 1056 bp->buf = xrealloc(bp->buf, size); 1057 bp->cnt = size; 1058 return (bp); 1059 } 1060 1061 void 1062 lostconn(signo) 1063 int signo; 1064 { 1065 if (!iamremote) 1066 fprintf(stderr, "lost connection\n"); 1067 exit(1); 1068 } 1069 1070 1071 void 1072 alarmtimer(int wait) 1073 { 1074 struct itimerval itv; 1075 1076 itv.it_value.tv_sec = wait; 1077 itv.it_value.tv_usec = 0; 1078 itv.it_interval = itv.it_value; 1079 setitimer(ITIMER_REAL, &itv, NULL); 1080 } 1081 1082 void 1083 updateprogressmeter(int ignore) 1084 { 1085 int save_errno = errno; 1086 1087 progressmeter(0); 1088 errno = save_errno; 1089 } 1090 1091 int 1092 foregroundproc() 1093 { 1094 static pid_t pgrp = -1; 1095 int ctty_pgrp; 1096 1097 if (pgrp == -1) 1098 pgrp = getpgrp(); 1099 1100 return ((ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 && 1101 ctty_pgrp == pgrp)); 1102 } 1103 1104 void 1105 progressmeter(int flag) 1106 { 1107 static const char prefixes[] = " KMGTP"; 1108 static struct timeval lastupdate; 1109 static off_t lastsize; 1110 struct timeval now, td, wait; 1111 off_t cursize, abbrevsize; 1112 double elapsed; 1113 int ratio, barlength, i, remaining; 1114 char buf[256]; 1115 1116 if (flag == -1) { 1117 (void) gettimeofday(&start, (struct timezone *) 0); 1118 lastupdate = start; 1119 lastsize = 0; 1120 } 1121 if (foregroundproc() == 0) 1122 return; 1123 1124 (void) gettimeofday(&now, (struct timezone *) 0); 1125 cursize = statbytes; 1126 if (totalbytes != 0) { 1127 ratio = 100.0 * cursize / totalbytes; 1128 ratio = MAX(ratio, 0); 1129 ratio = MIN(ratio, 100); 1130 } else 1131 ratio = 100; 1132 1133 snprintf(buf, sizeof(buf), "\r%-20.20s %3d%% ", curfile, ratio); 1134 1135 barlength = getttywidth() - 51; 1136 if (barlength > 0) { 1137 i = barlength * ratio / 100; 1138 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1139 "|%.*s%*s|", i, 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), " %5qd %c%c ", 1151 (quad_t) abbrevsize, prefixes[i], prefixes[i] == ' ' ? ' ' : 1152 '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 (statbytes <= 0 || elapsed <= 0.0 || cursize > totalbytes) { 1168 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1169 " --:-- ETA"); 1170 } else if (wait.tv_sec >= STALLTIME) { 1171 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1172 " - stalled -"); 1173 } else { 1174 if (flag != 1) 1175 remaining = 1176 (int)(totalbytes / (statbytes / elapsed) - elapsed); 1177 else 1178 remaining = elapsed; 1179 1180 i = remaining / 3600; 1181 if (i) 1182 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1183 "%2d:", i); 1184 else 1185 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1186 " "); 1187 i = remaining % 3600; 1188 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 1189 "%02d:%02d%s", i / 60, i % 60, 1190 (flag != 1) ? " ETA" : " "); 1191 } 1192 atomicio(write, fileno(stdout), buf, strlen(buf)); 1193 1194 if (flag == -1) { 1195 signal(SIGALRM, updateprogressmeter); 1196 alarmtimer(1); 1197 } else if (flag == 1) { 1198 alarmtimer(0); 1199 atomicio(write, fileno(stdout), "\n", 1); 1200 statbytes = 0; 1201 } 1202 } 1203 1204 int 1205 getttywidth(void) 1206 { 1207 struct winsize winsize; 1208 1209 if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1) 1210 return (winsize.ws_col ? winsize.ws_col : 80); 1211 else 1212 return (80); 1213 } 1214 1215 void 1216 addargs(char *fmt, ...) 1217 { 1218 va_list ap; 1219 char buf[1024]; 1220 1221 va_start(ap, fmt); 1222 vsnprintf(buf, sizeof(buf), fmt, ap); 1223 va_end(ap); 1224 1225 if (args.list == NULL) { 1226 args.nalloc = 32; 1227 args.num = 0; 1228 args.list = xmalloc(args.nalloc * sizeof(char *)); 1229 } else if (args.num+2 >= args.nalloc) { 1230 args.nalloc *= 2; 1231 args.list = xrealloc(args.list, args.nalloc * sizeof(char *)); 1232 } 1233 args.list[args.num++] = xstrdup(buf); 1234 args.list[args.num] = NULL; 1235 } 1236