1 /* 2 * Copyright (c) 1983 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)rcp.c 5.21 (Berkeley) 07/17/89"; 26 #endif /* not lint */ 27 28 /* 29 * rcp 30 */ 31 #include <sys/param.h> 32 #include <sys/file.h> 33 #include <sys/stat.h> 34 #include <sys/time.h> 35 #include <sys/ioctl.h> 36 #include <sys/dir.h> 37 #include <sys/signal.h> 38 #include <netinet/in.h> 39 #include <pwd.h> 40 #include <netdb.h> 41 #include <errno.h> 42 #include <strings.h> 43 #include <stdio.h> 44 #include <ctype.h> 45 #include "pathnames.h" 46 47 #ifdef KERBEROS 48 #include <kerberos/krb.h> 49 50 char krb_realm[REALM_SZ]; 51 int use_kerberos = 1, encrypt = 0; 52 CREDENTIALS cred; 53 Key_schedule schedule; 54 #endif 55 56 extern int errno; 57 struct passwd *pwd; 58 int errs, pflag, port, rem, userid; 59 int iamremote, iamrecursive, targetshouldbedirectory; 60 61 #define CMDNEEDS 20 62 char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 63 64 typedef struct _buf { 65 int cnt; 66 char *buf; 67 } BUF; 68 69 main(argc, argv) 70 int argc; 71 char **argv; 72 { 73 extern int optind; 74 struct servent *sp; 75 int ch, fflag, tflag; 76 char *targ, *colon(); 77 struct passwd *getpwuid(); 78 int lostconn(); 79 80 #ifdef KERBEROS 81 sp = getservbyname("kshell", "tcp"); 82 if (sp == NULL) { 83 use_kerberos = 0; 84 old_warning("kshell service unknown"); 85 sp = getservbyname("kshell", "tcp"); 86 } 87 #else 88 sp = getservbyname("shell", "tcp"); 89 #endif 90 if (!sp) { 91 (void)fprintf(stderr, "rcp: shell/tcp: unknown service\n"); 92 exit(1); 93 } 94 port = sp->s_port; 95 96 if (!(pwd = getpwuid(userid = getuid()))) { 97 (void)fprintf(stderr, "rcp: unknown user %d.\n", userid); 98 exit(1); 99 } 100 101 fflag = tflag = 0; 102 while ((ch = getopt(argc, argv, "dfkprtx")) != EOF) 103 switch(ch) { 104 case 'd': 105 targetshouldbedirectory = 1; 106 break; 107 case 'f': /* "from" */ 108 fflag = 1; 109 break; 110 #ifdef KERBEROS 111 case 'k': 112 strncpy(krb_realm, ++argv, REALM_SZ); 113 break; 114 #endif 115 case 'p': /* preserve access/mod times */ 116 ++pflag; 117 break; 118 case 'r': 119 ++iamrecursive; 120 break; 121 case 't': /* "to" */ 122 tflag = 1; 123 break; 124 #ifdef KERBEROS 125 case 'x': 126 encrypt = 1; 127 des_set_key(cred.session, schedule); 128 break; 129 #endif 130 case '?': 131 default: 132 usage(); 133 } 134 argc -= optind; 135 argv += optind; 136 137 if (fflag) { 138 iamremote = 1; 139 (void)response(); 140 (void)setuid(userid); 141 source(argc, argv); 142 exit(errs); 143 } 144 145 if (tflag) { 146 iamremote = 1; 147 (void)setuid(userid); 148 sink(argc, argv); 149 exit(errs); 150 } 151 152 if (argc < 2) 153 usage(); 154 if (argc > 2) 155 targetshouldbedirectory = 1; 156 157 rem = -1; 158 (void)sprintf(cmd, "rcp%s%s%s", iamrecursive ? " -r" : "", 159 pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); 160 161 (void)signal(SIGPIPE, lostconn); 162 163 if (targ = colon(argv[argc - 1])) 164 toremote(targ, argc, argv); 165 else { 166 tolocal(argc, argv); 167 if (targetshouldbedirectory) 168 verifydir(argv[argc - 1]); 169 } 170 exit(errs); 171 } 172 173 toremote(targ, argc, argv) 174 char *targ; 175 int argc; 176 char **argv; 177 { 178 int i; 179 char *bp, *host, *src, *suser, *thost, *tuser; 180 char *colon(), *malloc(); 181 182 *targ++ = 0; 183 if (*targ == 0) 184 targ = "."; 185 186 if (thost = index(argv[argc - 1], '@')) { 187 *thost++ = 0; 188 tuser = argv[argc - 1]; 189 if (*tuser == '\0') 190 tuser = NULL; 191 else if (!okname(tuser)) 192 exit(1); 193 } else { 194 thost = argv[argc - 1]; 195 tuser = NULL; 196 } 197 198 for (i = 0; i < argc - 1; i++) { 199 src = colon(argv[i]); 200 if (src) { /* remote to remote */ 201 *src++ = 0; 202 if (*src == 0) 203 src = "."; 204 host = index(argv[i], '@'); 205 if (!(bp = malloc((u_int)(strlen(_PATH_RSH) + 206 strlen(argv[i]) + strlen(src) + 207 tuser ? strlen(tuser) : 0 + strlen(thost) + 208 strlen(targ)) + CMDNEEDS + 20))) 209 nospace(); 210 if (host) { 211 *host++ = 0; 212 suser = argv[i]; 213 if (*suser == '\0') 214 suser = pwd->pw_name; 215 else if (!okname(suser)) 216 continue; 217 (void)sprintf(bp, 218 "%s %s -l %s -n %s %s '%s%s%s:%s'", 219 _PATH_RSH, host, suser, cmd, src, 220 tuser ? tuser : "", tuser ? "@" : "", 221 thost, targ); 222 } else 223 (void)sprintf(bp, "%s %s -n %s %s '%s%s%s:%s'", 224 _PATH_RSH, argv[i], cmd, src, 225 tuser ? tuser : "", tuser ? "@" : "", 226 thost, targ); 227 (void)susystem(bp); 228 (void)free(bp); 229 } else { /* local to remote */ 230 if (rem == -1) { 231 if (!(bp = malloc((u_int)strlen(targ) + 232 CMDNEEDS + 20))) 233 nospace(); 234 (void)sprintf(bp, "%s -t %s", cmd, targ); 235 host = thost; 236 #ifdef KERBEROS 237 if (use_kerberos) 238 kerberos(bp, 239 tuser ? tuser : pwd->pw_name); 240 else 241 #endif 242 rem = rcmd(&host, port, pwd->pw_name, 243 tuser ? tuser : pwd->pw_name, 244 bp, 0); 245 if (rem < 0) 246 exit(1); 247 if (response() < 0) 248 exit(1); 249 (void)free(bp); 250 (void)setuid(userid); 251 } 252 source(1, argv+i); 253 } 254 } 255 } 256 257 tolocal(argc, argv) 258 int argc; 259 char **argv; 260 { 261 int i; 262 char *bp, *host, *src, *suser; 263 char *colon(), *malloc(); 264 265 for (i = 0; i < argc - 1; i++) { 266 if (!(src = colon(argv[i]))) { /* local to local */ 267 if (!(bp = malloc((u_int)(strlen(_PATH_CP) + 268 strlen(argv[i]) + strlen(argv[argc - 1])) + 20))) 269 nospace(); 270 (void)sprintf(bp, "%s%s%s %s %s", _PATH_CP, 271 iamrecursive ? " -r" : "", pflag ? " -p" : "", 272 argv[i], argv[argc - 1]); 273 (void)susystem(bp); 274 (void)free(bp); 275 continue; 276 } 277 *src++ = 0; 278 if (*src == 0) 279 src = "."; 280 host = index(argv[i], '@'); 281 if (host) { 282 *host++ = 0; 283 suser = argv[i]; 284 if (*suser == '\0') 285 suser = pwd->pw_name; 286 else if (!okname(suser)) 287 continue; 288 } else { 289 host = argv[i]; 290 suser = pwd->pw_name; 291 } 292 if (!(bp = malloc((u_int)(strlen(src)) + CMDNEEDS + 20))) 293 nospace(); 294 (void)sprintf(bp, "%s -f %s", cmd, src); 295 #ifdef KERBEROS 296 if (use_kerberos) 297 kerberos(bp, suser); 298 else 299 #endif 300 rem = rcmd(&host, port, pwd->pw_name, suser, bp, 0); 301 (void)free(bp); 302 if (rem < 0) 303 continue; 304 (void)setreuid(0, userid); 305 sink(1, argv + argc - 1); 306 (void)setreuid(userid, 0); 307 (void)close(rem); 308 rem = -1; 309 } 310 } 311 312 #ifdef KERBEROS 313 kerberos(bp, user) 314 char *bp, *user; 315 { 316 struct servent *sp; 317 char *host; 318 319 again: rem = KSUCCESS; 320 if (krb_realm[0] == '\0') 321 rem = krb_get_lrealm(krb_realm, 1); 322 if (rem == KSUCCESS) { 323 if (encrypt) 324 rem = krcmd_mutual(&host, port, user, bp, 0, 325 krb_realm, &cred, schedule); 326 else 327 rem = krcmd(&host, port, user, bp, 0, krb_realm); 328 } else { 329 (void)fprintf(stderr, 330 "rcp: error getting local realm %s\n", krb_err_txt[rem]); 331 exit(1); 332 } 333 if (rem < 0 && errno == ECONNREFUSED) { 334 use_kerberos = 0; 335 old_warning("remote host doesn't support Kerberos"); 336 sp = getservbyname("shell", "tcp"); 337 if (sp == NULL) { 338 (void)fprintf(stderr, 339 "rcp: unknown service shell/tcp\n"); 340 exit(1); 341 } 342 port = sp->s_port; 343 goto again; 344 } 345 } 346 #endif /* KERBEROS */ 347 348 verifydir(cp) 349 char *cp; 350 { 351 struct stat stb; 352 353 if (stat(cp, &stb) >= 0) { 354 if ((stb.st_mode & S_IFMT) == S_IFDIR) 355 return; 356 errno = ENOTDIR; 357 } 358 error("rcp: %s: %s.\n", cp, strerror(errno)); 359 exit(1); 360 } 361 362 char * 363 colon(cp) 364 register char *cp; 365 { 366 for (; *cp; ++cp) { 367 if (*cp == ':') 368 return(cp); 369 if (*cp == '/') 370 return(0); 371 } 372 return(0); 373 } 374 375 okname(cp0) 376 char *cp0; 377 { 378 register char *cp = cp0; 379 register int c; 380 381 do { 382 c = *cp; 383 if (c & 0200) 384 goto bad; 385 if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') 386 goto bad; 387 } while (*++cp); 388 return(1); 389 bad: 390 (void)fprintf(stderr, "rcp: invalid user name %s\n", cp0); 391 return(0); 392 } 393 394 susystem(s) 395 char *s; 396 { 397 int status, pid, w; 398 register int (*istat)(), (*qstat)(); 399 400 if ((pid = vfork()) == 0) { 401 (void)setuid(userid); 402 execl(_PATH_BSHELL, "sh", "-c", s, (char *)0); 403 _exit(127); 404 } 405 istat = signal(SIGINT, SIG_IGN); 406 qstat = signal(SIGQUIT, SIG_IGN); 407 while ((w = wait(&status)) != pid && w != -1) 408 ; 409 if (w == -1) 410 status = -1; 411 (void)signal(SIGINT, istat); 412 (void)signal(SIGQUIT, qstat); 413 return(status); 414 } 415 416 source(argc, argv) 417 int argc; 418 char **argv; 419 { 420 struct stat stb; 421 static BUF buffer; 422 BUF *bp; 423 off_t i; 424 int x, readerr, f, amt; 425 char *last, *name, buf[BUFSIZ]; 426 BUF *allocbuf(); 427 428 for (x = 0; x < argc; x++) { 429 name = argv[x]; 430 if ((f = open(name, O_RDONLY, 0)) < 0) { 431 error("rcp: %s: %s\n", name, strerror(errno)); 432 continue; 433 } 434 if (fstat(f, &stb) < 0) 435 goto notreg; 436 switch (stb.st_mode&S_IFMT) { 437 438 case S_IFREG: 439 break; 440 441 case S_IFDIR: 442 if (iamrecursive) { 443 (void)close(f); 444 rsource(name, &stb); 445 continue; 446 } 447 /* FALLTHROUGH */ 448 default: 449 notreg: (void)close(f); 450 error("rcp: %s: not a plain file\n", name); 451 continue; 452 } 453 last = rindex(name, '/'); 454 if (last == 0) 455 last = name; 456 else 457 last++; 458 if (pflag) { 459 /* 460 * Make it compatible with possible future 461 * versions expecting microseconds. 462 */ 463 (void)sprintf(buf, "T%ld 0 %ld 0\n", stb.st_mtime, 464 stb.st_atime); 465 (void)write(rem, buf, strlen(buf)); 466 if (response() < 0) { 467 (void)close(f); 468 continue; 469 } 470 } 471 (void)sprintf(buf, "C%04o %ld %s\n", stb.st_mode&07777, 472 stb.st_size, last); 473 (void)write(rem, buf, strlen(buf)); 474 if (response() < 0) { 475 (void)close(f); 476 continue; 477 } 478 if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) { 479 (void)close(f); 480 continue; 481 } 482 readerr = 0; 483 for (i = 0; i < stb.st_size; i += bp->cnt) { 484 amt = bp->cnt; 485 if (i + amt > stb.st_size) 486 amt = stb.st_size - i; 487 if (readerr == 0 && read(f, bp->buf, amt) != amt) 488 readerr = errno; 489 (void)write(rem, bp->buf, amt); 490 } 491 (void)close(f); 492 if (readerr == 0) 493 (void)write(rem, "", 1); 494 else 495 error("rcp: %s: %s\n", name, strerror(readerr)); 496 (void)response(); 497 } 498 } 499 500 rsource(name, statp) 501 char *name; 502 struct stat *statp; 503 { 504 DIR *d; 505 struct direct *dp; 506 char *last, *vect[1], path[MAXPATHLEN]; 507 508 if (!(d = opendir(name))) { 509 error("rcp: %s: %s\n", name, strerror(errno)); 510 return; 511 } 512 last = rindex(name, '/'); 513 if (last == 0) 514 last = name; 515 else 516 last++; 517 if (pflag) { 518 (void)sprintf(path, "T%ld 0 %ld 0\n", statp->st_mtime, 519 statp->st_atime); 520 (void)write(rem, path, strlen(path)); 521 if (response() < 0) { 522 closedir(d); 523 return; 524 } 525 } 526 (void)sprintf(path, "D%04o %d %s\n", statp->st_mode&07777, 0, last); 527 (void)write(rem, path, strlen(path)); 528 if (response() < 0) { 529 closedir(d); 530 return; 531 } 532 while (dp = readdir(d)) { 533 if (dp->d_ino == 0) 534 continue; 535 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 536 continue; 537 if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) { 538 error("%s/%s: name too long.\n", name, dp->d_name); 539 continue; 540 } 541 (void)sprintf(path, "%s/%s", name, dp->d_name); 542 vect[0] = path; 543 source(1, vect); 544 } 545 closedir(d); 546 (void)write(rem, "E\n", 2); 547 (void)response(); 548 } 549 550 response() 551 { 552 register char *cp; 553 char ch, resp, rbuf[BUFSIZ]; 554 555 if (read(rem, &resp, sizeof(resp)) != sizeof(resp)) 556 lostconn(); 557 558 cp = rbuf; 559 switch(resp) { 560 case 0: /* ok */ 561 return(0); 562 default: 563 *cp++ = resp; 564 /* FALLTHROUGH */ 565 case 1: /* error, followed by err msg */ 566 case 2: /* fatal error, "" */ 567 do { 568 if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 569 lostconn(); 570 *cp++ = ch; 571 } while (cp < &rbuf[BUFSIZ] && ch != '\n'); 572 573 if (!iamremote) 574 (void)write(2, rbuf, cp - rbuf); 575 ++errs; 576 if (resp == 1) 577 return(-1); 578 exit(1); 579 } 580 /*NOTREACHED*/ 581 } 582 583 lostconn() 584 { 585 if (!iamremote) 586 (void)fprintf(stderr, "rcp: lost connection\n"); 587 exit(1); 588 } 589 590 sink(argc, argv) 591 int argc; 592 char **argv; 593 { 594 register char *cp; 595 static BUF buffer; 596 struct stat stb; 597 struct timeval tv[2]; 598 enum { YES, NO, DISPLAYED } wrerr; 599 BUF *bp, *allocbuf(); 600 off_t i, j; 601 char ch, *targ, *why; 602 int amt, count, exists, first, mask, mode; 603 int ofd, setimes, size, targisdir; 604 char *np, *vect[1], buf[BUFSIZ], *malloc(); 605 606 #define atime tv[0] 607 #define mtime tv[1] 608 #define SCREWUP(str) { why = str; goto screwup; } 609 610 setimes = targisdir = 0; 611 mask = umask(0); 612 if (!pflag) 613 (void)umask(mask); 614 if (argc != 1) { 615 error("rcp: ambiguous target\n"); 616 exit(1); 617 } 618 targ = *argv; 619 if (targetshouldbedirectory) 620 verifydir(targ); 621 (void)write(rem, "", 1); 622 if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) 623 targisdir = 1; 624 for (first = 1;; first = 0) { 625 cp = buf; 626 if (read(rem, cp, 1) <= 0) 627 return; 628 if (*cp++ == '\n') 629 SCREWUP("unexpected <newline>"); 630 do { 631 if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 632 SCREWUP("lost connection"); 633 *cp++ = ch; 634 } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); 635 *cp = 0; 636 637 if (buf[0] == '\01' || buf[0] == '\02') { 638 if (iamremote == 0) 639 (void)write(2, buf + 1, strlen(buf + 1)); 640 if (buf[0] == '\02') 641 exit(1); 642 errs++; 643 continue; 644 } 645 if (buf[0] == 'E') { 646 (void)write(rem, "", 1); 647 return; 648 } 649 650 if (ch == '\n') 651 *--cp = 0; 652 653 #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0'); 654 cp = buf; 655 if (*cp == 'T') { 656 setimes++; 657 cp++; 658 getnum(mtime.tv_sec); 659 if (*cp++ != ' ') 660 SCREWUP("mtime.sec not delimited"); 661 getnum(mtime.tv_usec); 662 if (*cp++ != ' ') 663 SCREWUP("mtime.usec not delimited"); 664 getnum(atime.tv_sec); 665 if (*cp++ != ' ') 666 SCREWUP("atime.sec not delimited"); 667 getnum(atime.tv_usec); 668 if (*cp++ != '\0') 669 SCREWUP("atime.usec not delimited"); 670 (void)write(rem, "", 1); 671 continue; 672 } 673 if (*cp != 'C' && *cp != 'D') { 674 /* 675 * Check for the case "rcp remote:foo\* local:bar". 676 * In this case, the line "No match." can be returned 677 * by the shell before the rcp command on the remote is 678 * executed so the ^Aerror_message convention isn't 679 * followed. 680 */ 681 if (first) { 682 error("%s\n", cp); 683 exit(1); 684 } 685 SCREWUP("expected control record"); 686 } 687 mode = 0; 688 for (++cp; cp < buf + 5; cp++) { 689 if (*cp < '0' || *cp > '7') 690 SCREWUP("bad mode"); 691 mode = (mode << 3) | (*cp - '0'); 692 } 693 if (*cp++ != ' ') 694 SCREWUP("mode not delimited"); 695 size = 0; 696 while (isdigit(*cp)) 697 size = size * 10 + (*cp++ - '0'); 698 if (*cp++ != ' ') 699 SCREWUP("size not delimited"); 700 if (targisdir) { 701 static char *namebuf; 702 static int cursize; 703 int need; 704 705 need = strlen(targ) + strlen(cp) + 250; 706 if (need > cursize) { 707 if (!(namebuf = malloc((u_int)need))) 708 error("out of memory\n"); 709 } 710 (void)sprintf(namebuf, "%s%s%s", targ, 711 *targ ? "/" : "", cp); 712 np = namebuf; 713 } 714 else 715 np = targ; 716 exists = stat(np, &stb) == 0; 717 if (buf[0] == 'D') { 718 if (exists) { 719 if ((stb.st_mode&S_IFMT) != S_IFDIR) { 720 errno = ENOTDIR; 721 goto bad; 722 } 723 if (pflag) 724 (void)chmod(np, mode); 725 } else if (mkdir(np, mode) < 0) 726 goto bad; 727 vect[0] = np; 728 sink(1, vect); 729 if (setimes) { 730 setimes = 0; 731 if (utimes(np, tv) < 0) 732 error("rcp: can't set times on %s: %s\n", 733 np, strerror(errno)); 734 } 735 continue; 736 } 737 if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 738 bad: error("rcp: %s: %s\n", np, strerror(errno)); 739 continue; 740 } 741 if (exists && pflag) 742 (void)fchmod(ofd, mode); 743 (void)write(rem, "", 1); 744 if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == 0) { 745 (void)close(ofd); 746 continue; 747 } 748 cp = bp->buf; 749 count = 0; 750 wrerr = NO; 751 for (i = 0; i < size; i += BUFSIZ) { 752 amt = BUFSIZ; 753 if (i + amt > size) 754 amt = size - i; 755 count += amt; 756 do { 757 j = read(rem, cp, amt); 758 if (j <= 0) { 759 error("rcp: %s\n", 760 j ? strerror(errno) : 761 "dropped connection"); 762 exit(1); 763 } 764 amt -= j; 765 cp += j; 766 } while (amt > 0); 767 if (count == bp->cnt) { 768 if (wrerr == NO && 769 write(ofd, bp->buf, count) != count) 770 wrerr = YES; 771 count = 0; 772 cp = bp->buf; 773 } 774 } 775 if (count != 0 && wrerr == NO && 776 write(ofd, bp->buf, count) != count) 777 wrerr = YES; 778 if (ftruncate(ofd, size)) { 779 error("rcp: can't truncate %s: %s\n", np, 780 strerror(errno)); 781 wrerr = DISPLAYED; 782 } 783 (void)close(ofd); 784 (void)response(); 785 if (setimes && wrerr == NO) { 786 setimes = 0; 787 if (utimes(np, tv) < 0) { 788 error("rcp: can't set times on %s: %s\n", 789 np, strerror(errno)); 790 wrerr = DISPLAYED; 791 } 792 } 793 switch(wrerr) { 794 case YES: 795 error("rcp: %s: %s\n", np, strerror(errno)); 796 break; 797 case NO: 798 (void)write(rem, "", 1); 799 break; 800 case DISPLAYED: 801 break; 802 } 803 } 804 screwup: 805 error("rcp: protocol screwup: %s\n", why); 806 exit(1); 807 } 808 809 BUF * 810 allocbuf(bp, fd, blksize) 811 BUF *bp; 812 int fd, blksize; 813 { 814 struct stat stb; 815 int size; 816 char *malloc(); 817 818 if (fstat(fd, &stb) < 0) { 819 error("rcp: fstat: %s\n", strerror(errno)); 820 return(0); 821 } 822 size = roundup(stb.st_blksize, blksize); 823 if (size == 0) 824 size = blksize; 825 if (bp->cnt < size) { 826 if (bp->buf != 0) 827 free(bp->buf); 828 bp->buf = (char *)malloc((u_int)size); 829 if (!bp->buf) { 830 error("rcp: malloc: out of memory\n"); 831 return(0); 832 } 833 } 834 bp->cnt = size; 835 return(bp); 836 } 837 838 /* VARARGS1 */ 839 error(fmt, a1, a2, a3) 840 char *fmt; 841 int a1, a2, a3; 842 { 843 static FILE *fp; 844 845 ++errs; 846 if (!fp && !(fp = fdopen(rem, "w"))) 847 return; 848 (void)fprintf(fp, "%c", 0x01); 849 (void)fprintf(fp, fmt, a1, a2, a3); 850 (void)fflush(fp); 851 if (!iamremote) 852 (void)fprintf(stderr, fmt, a1, a2, a3); 853 } 854 855 nospace() 856 { 857 (void)fprintf(stderr, "rcp: out of memory.\n"); 858 exit(1); 859 } 860 861 #ifdef KERBEROS 862 old_warning(str) 863 char *str; 864 { 865 (void)fprintf(stderr, "rcp: warning: %s, using standard rcp\n", str); 866 } 867 #endif 868 869 usage() 870 { 871 #ifdef KERBEROS 872 (void)fprintf(stderr, "%s\n\t%s\n", 873 "usage: rcp [-k realm] [-px] f1 f2", 874 "or: rcp [-k realm] [-rpx] f1 ... fn directory"); 875 #else 876 (void)fprintf(stderr, 877 "usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn directory\n"); 878 #endif 879 exit(1); 880 } 881