1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)server.c 5.13 (Berkeley) 08/27/90"; 10 #endif /* not lint */ 11 12 #include "defs.h" 13 14 #define ack() (void) write(rem, "\0\n", 2) 15 #define err() (void) write(rem, "\1\n", 2) 16 17 struct linkbuf *ihead; /* list of files with more than one link */ 18 char buf[BUFSIZ]; /* general purpose buffer */ 19 char target[BUFSIZ]; /* target/source directory name */ 20 char *tp; /* pointer to end of target name */ 21 char *Tdest; /* pointer to last T dest*/ 22 int catname; /* cat name to target name */ 23 char *stp[32]; /* stack of saved tp's for directories */ 24 int oumask; /* old umask for creating files */ 25 26 extern FILE *lfp; /* log file for mailing changes */ 27 28 int cleanup(); 29 struct linkbuf *savelink(); 30 31 /* 32 * Server routine to read requests and process them. 33 * Commands are: 34 * Tname - Transmit file if out of date 35 * Vname - Verify if file out of date or not 36 * Qname - Query if file exists. Return mtime & size if it does. 37 */ 38 server() 39 { 40 char cmdbuf[BUFSIZ]; 41 register char *cp; 42 43 signal(SIGHUP, cleanup); 44 signal(SIGINT, cleanup); 45 signal(SIGQUIT, cleanup); 46 signal(SIGTERM, cleanup); 47 signal(SIGPIPE, cleanup); 48 49 rem = 0; 50 oumask = umask(0); 51 (void) sprintf(buf, "V%d\n", VERSION); 52 (void) write(rem, buf, strlen(buf)); 53 54 for (;;) { 55 cp = cmdbuf; 56 if (read(rem, cp, 1) <= 0) 57 return; 58 if (*cp++ == '\n') { 59 error("server: expected control record\n"); 60 continue; 61 } 62 do { 63 if (read(rem, cp, 1) != 1) 64 cleanup(); 65 } while (*cp++ != '\n' && cp < &cmdbuf[BUFSIZ]); 66 *--cp = '\0'; 67 cp = cmdbuf; 68 switch (*cp++) { 69 case 'T': /* init target file/directory name */ 70 catname = 1; /* target should be directory */ 71 goto dotarget; 72 73 case 't': /* init target file/directory name */ 74 catname = 0; 75 dotarget: 76 if (exptilde(target, cp) == NULL) 77 continue; 78 tp = target; 79 while (*tp) 80 tp++; 81 ack(); 82 continue; 83 84 case 'R': /* Transfer a regular file. */ 85 recvf(cp, S_IFREG); 86 continue; 87 88 case 'D': /* Transfer a directory. */ 89 recvf(cp, S_IFDIR); 90 continue; 91 92 case 'K': /* Transfer symbolic link. */ 93 recvf(cp, S_IFLNK); 94 continue; 95 96 case 'k': /* Transfer hard link. */ 97 hardlink(cp); 98 continue; 99 100 case 'E': /* End. (of directory) */ 101 *tp = '\0'; 102 if (catname <= 0) { 103 error("server: too many 'E's\n"); 104 continue; 105 } 106 tp = stp[--catname]; 107 *tp = '\0'; 108 ack(); 109 continue; 110 111 case 'C': /* Clean. Cleanup a directory */ 112 clean(cp); 113 continue; 114 115 case 'Q': /* Query. Does the file/directory exist? */ 116 query(cp); 117 continue; 118 119 case 'S': /* Special. Execute commands */ 120 dospecial(cp); 121 continue; 122 123 #ifdef notdef 124 /* 125 * These entries are reserved but not currently used. 126 * The intent is to allow remote hosts to have master copies. 127 * Currently, only the host rdist runs on can have masters. 128 */ 129 case 'X': /* start a new list of files to exclude */ 130 except = bp = NULL; 131 case 'x': /* add name to list of files to exclude */ 132 if (*cp == '\0') { 133 ack(); 134 continue; 135 } 136 if (*cp == '~') { 137 if (exptilde(buf, cp) == NULL) 138 continue; 139 cp = buf; 140 } 141 if (bp == NULL) 142 except = bp = expand(makeblock(NAME, cp), E_VARS); 143 else 144 bp->b_next = expand(makeblock(NAME, cp), E_VARS); 145 while (bp->b_next != NULL) 146 bp = bp->b_next; 147 ack(); 148 continue; 149 150 case 'I': /* Install. Transfer file if out of date. */ 151 opts = 0; 152 while (*cp >= '0' && *cp <= '7') 153 opts = (opts << 3) | (*cp++ - '0'); 154 if (*cp++ != ' ') { 155 error("server: options not delimited\n"); 156 return; 157 } 158 install(cp, opts); 159 continue; 160 161 case 'L': /* Log. save message in log file */ 162 log(lfp, cp); 163 continue; 164 #endif 165 166 case '\1': 167 nerrs++; 168 continue; 169 170 case '\2': 171 return; 172 173 default: 174 error("server: unknown command '%s'\n", cp); 175 case '\0': 176 continue; 177 } 178 } 179 } 180 181 /* 182 * Update the file(s) if they are different. 183 * destdir = 1 if destination should be a directory 184 * (i.e., more than one source is being copied to the same destination). 185 */ 186 install(src, dest, destdir, opts) 187 char *src, *dest; 188 int destdir, opts; 189 { 190 char *rname; 191 char destcopy[BUFSIZ]; 192 193 if (dest == NULL) { 194 opts &= ~WHOLE; /* WHOLE mode only useful if renaming */ 195 dest = src; 196 } 197 198 if (nflag || debug) { 199 printf("%s%s%s%s%s %s %s\n", opts & VERIFY ? "verify":"install", 200 opts & WHOLE ? " -w" : "", 201 opts & YOUNGER ? " -y" : "", 202 opts & COMPARE ? " -b" : "", 203 opts & REMOVE ? " -R" : "", src, dest); 204 if (nflag) 205 return; 206 } 207 208 rname = exptilde(target, src); 209 if (rname == NULL) 210 return; 211 tp = target; 212 while (*tp) 213 tp++; 214 /* 215 * If we are renaming a directory and we want to preserve 216 * the directory heirarchy (-w), we must strip off the leading 217 * directory name and preserve the rest. 218 */ 219 if (opts & WHOLE) { 220 while (*rname == '/') 221 rname++; 222 destdir = 1; 223 } else { 224 rname = rindex(target, '/'); 225 if (rname == NULL) 226 rname = target; 227 else 228 rname++; 229 } 230 if (debug) 231 printf("target = %s, rname = %s\n", target, rname); 232 /* 233 * Pass the destination file/directory name to remote. 234 */ 235 (void) sprintf(buf, "%c%s\n", destdir ? 'T' : 't', dest); 236 if (debug) 237 printf("buf = %s", buf); 238 (void) write(rem, buf, strlen(buf)); 239 if (response() < 0) 240 return; 241 242 if (destdir) { 243 strcpy(destcopy, dest); 244 Tdest = destcopy; 245 } 246 sendf(rname, opts); 247 Tdest = 0; 248 } 249 250 #define protoname() (pw ? pw->pw_name : user) 251 #define protogroup() (gr ? gr->gr_name : group) 252 /* 253 * Transfer the file or directory in target[]. 254 * rname is the name of the file on the remote host. 255 */ 256 sendf(rname, opts) 257 char *rname; 258 int opts; 259 { 260 register struct subcmd *sc; 261 struct stat stb; 262 int sizerr, f, u, len; 263 off_t i; 264 DIR *d; 265 struct direct *dp; 266 char *otp, *cp; 267 extern struct subcmd *subcmds; 268 static char user[15], group[15]; 269 270 if (debug) 271 printf("sendf(%s, %x)\n", rname, opts); 272 273 if (except(target)) 274 return; 275 if ((opts & FOLLOW ? stat(target, &stb) : lstat(target, &stb)) < 0) { 276 error("%s: %s\n", target, strerror(errno)); 277 return; 278 } 279 if ((u = update(rname, opts, &stb)) == 0) { 280 if ((stb.st_mode & S_IFMT) == S_IFREG && stb.st_nlink > 1) 281 (void) savelink(&stb); 282 return; 283 } 284 285 if (pw == NULL || pw->pw_uid != stb.st_uid) 286 if ((pw = getpwuid(stb.st_uid)) == NULL) { 287 log(lfp, "%s: no password entry for uid %d \n", 288 target, stb.st_uid); 289 pw = NULL; 290 sprintf(user, ":%d", stb.st_uid); 291 } 292 if (gr == NULL || gr->gr_gid != stb.st_gid) 293 if ((gr = getgrgid(stb.st_gid)) == NULL) { 294 log(lfp, "%s: no name for group %d\n", 295 target, stb.st_gid); 296 gr = NULL; 297 sprintf(group, ":%d", stb.st_gid); 298 } 299 if (u == 1) { 300 if (opts & VERIFY) { 301 log(lfp, "need to install: %s\n", target); 302 goto dospecial; 303 } 304 log(lfp, "installing: %s\n", target); 305 opts &= ~(COMPARE|REMOVE); 306 } 307 308 switch (stb.st_mode & S_IFMT) { 309 case S_IFDIR: 310 if ((d = opendir(target)) == NULL) { 311 error("%s: %s\n", target, strerror(errno)); 312 return; 313 } 314 (void) sprintf(buf, "D%o %04o 0 0 %s %s %s\n", opts, 315 stb.st_mode & 07777, protoname(), protogroup(), rname); 316 if (debug) 317 printf("buf = %s", buf); 318 (void) write(rem, buf, strlen(buf)); 319 if (response() < 0) { 320 closedir(d); 321 return; 322 } 323 324 if (opts & REMOVE) 325 rmchk(opts); 326 327 otp = tp; 328 len = tp - target; 329 while (dp = readdir(d)) { 330 if (!strcmp(dp->d_name, ".") || 331 !strcmp(dp->d_name, "..")) 332 continue; 333 if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 334 error("%s/%s: Name too long\n", target, 335 dp->d_name); 336 continue; 337 } 338 tp = otp; 339 *tp++ = '/'; 340 cp = dp->d_name; 341 while (*tp++ = *cp++) 342 ; 343 tp--; 344 sendf(dp->d_name, opts); 345 } 346 closedir(d); 347 (void) write(rem, "E\n", 2); 348 (void) response(); 349 tp = otp; 350 *tp = '\0'; 351 return; 352 353 case S_IFLNK: 354 if (u != 1) 355 opts |= COMPARE; 356 if (stb.st_nlink > 1) { 357 struct linkbuf *lp; 358 359 if ((lp = savelink(&stb)) != NULL) { 360 /* install link */ 361 if (*lp->target == 0) 362 (void) sprintf(buf, "k%o %s %s\n", opts, 363 lp->pathname, rname); 364 else 365 (void) sprintf(buf, "k%o %s/%s %s\n", opts, 366 lp->target, lp->pathname, rname); 367 if (debug) 368 printf("buf = %s", buf); 369 (void) write(rem, buf, strlen(buf)); 370 (void) response(); 371 return; 372 } 373 } 374 (void) sprintf(buf, "K%o %o %ld %ld %s %s %s\n", opts, 375 stb.st_mode & 07777, stb.st_size, stb.st_mtime, 376 protoname(), protogroup(), rname); 377 if (debug) 378 printf("buf = %s", buf); 379 (void) write(rem, buf, strlen(buf)); 380 if (response() < 0) 381 return; 382 sizerr = (readlink(target, buf, BUFSIZ) != stb.st_size); 383 (void) write(rem, buf, stb.st_size); 384 if (debug) 385 printf("readlink = %.*s\n", (int)stb.st_size, buf); 386 goto done; 387 388 case S_IFREG: 389 break; 390 391 default: 392 error("%s: not a file or directory\n", target); 393 return; 394 } 395 396 if (u == 2) { 397 if (opts & VERIFY) { 398 log(lfp, "need to update: %s\n", target); 399 goto dospecial; 400 } 401 log(lfp, "updating: %s\n", target); 402 } 403 404 if (stb.st_nlink > 1) { 405 struct linkbuf *lp; 406 407 if ((lp = savelink(&stb)) != NULL) { 408 /* install link */ 409 if (*lp->target == 0) 410 (void) sprintf(buf, "k%o %s %s\n", opts, 411 lp->pathname, rname); 412 else 413 (void) sprintf(buf, "k%o %s/%s %s\n", opts, 414 lp->target, lp->pathname, rname); 415 if (debug) 416 printf("buf = %s", buf); 417 (void) write(rem, buf, strlen(buf)); 418 (void) response(); 419 return; 420 } 421 } 422 423 if ((f = open(target, 0)) < 0) { 424 error("%s: %s\n", target, strerror(errno)); 425 return; 426 } 427 (void) sprintf(buf, "R%o %o %ld %ld %s %s %s\n", opts, 428 stb.st_mode & 07777, stb.st_size, stb.st_mtime, 429 protoname(), protogroup(), rname); 430 if (debug) 431 printf("buf = %s", buf); 432 (void) write(rem, buf, strlen(buf)); 433 if (response() < 0) { 434 (void) close(f); 435 return; 436 } 437 sizerr = 0; 438 for (i = 0; i < stb.st_size; i += BUFSIZ) { 439 int amt = BUFSIZ; 440 if (i + amt > stb.st_size) 441 amt = stb.st_size - i; 442 if (sizerr == 0 && read(f, buf, amt) != amt) 443 sizerr = 1; 444 (void) write(rem, buf, amt); 445 } 446 (void) close(f); 447 done: 448 if (sizerr) { 449 error("%s: file changed size\n", target); 450 err(); 451 } else 452 ack(); 453 f = response(); 454 if (f < 0 || f == 0 && (opts & COMPARE)) 455 return; 456 dospecial: 457 for (sc = subcmds; sc != NULL; sc = sc->sc_next) { 458 if (sc->sc_type != SPECIAL) 459 continue; 460 if (sc->sc_args != NULL && !inlist(sc->sc_args, target)) 461 continue; 462 log(lfp, "special \"%s\"\n", sc->sc_name); 463 if (opts & VERIFY) 464 continue; 465 (void) sprintf(buf, "SFILE=%s;%s\n", target, sc->sc_name); 466 if (debug) 467 printf("buf = %s", buf); 468 (void) write(rem, buf, strlen(buf)); 469 while (response() > 0) 470 ; 471 } 472 } 473 474 struct linkbuf * 475 savelink(stp) 476 struct stat *stp; 477 { 478 struct linkbuf *lp; 479 int found = 0; 480 481 for (lp = ihead; lp != NULL; lp = lp->nextp) 482 if (lp->inum == stp->st_ino && lp->devnum == stp->st_dev) { 483 lp->count--; 484 return(lp); 485 } 486 lp = (struct linkbuf *) malloc(sizeof(*lp)); 487 if (lp == NULL) 488 log(lfp, "out of memory, link information lost\n"); 489 else { 490 lp->nextp = ihead; 491 ihead = lp; 492 lp->inum = stp->st_ino; 493 lp->devnum = stp->st_dev; 494 lp->count = stp->st_nlink - 1; 495 strcpy(lp->pathname, target); 496 if (Tdest) 497 strcpy(lp->target, Tdest); 498 else 499 *lp->target = 0; 500 } 501 return(NULL); 502 } 503 504 /* 505 * Check to see if file needs to be updated on the remote machine. 506 * Returns 0 if no update, 1 if remote doesn't exist, 2 if out of date 507 * and 3 if comparing binaries to determine if out of date. 508 */ 509 update(rname, opts, stp) 510 char *rname; 511 int opts; 512 struct stat *stp; 513 { 514 register char *cp, *s; 515 register off_t size; 516 register time_t mtime; 517 518 if (debug) 519 printf("update(%s, %x, %x)\n", rname, opts, stp); 520 521 /* 522 * Check to see if the file exists on the remote machine. 523 */ 524 (void) sprintf(buf, "Q%s\n", rname); 525 if (debug) 526 printf("buf = %s", buf); 527 (void) write(rem, buf, strlen(buf)); 528 again: 529 cp = s = buf; 530 do { 531 if (read(rem, cp, 1) != 1) 532 lostconn(); 533 } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); 534 535 switch (*s++) { 536 case 'Y': 537 break; 538 539 case 'N': /* file doesn't exist so install it */ 540 return(1); 541 542 case '\1': 543 nerrs++; 544 if (*s != '\n') { 545 if (!iamremote) { 546 fflush(stdout); 547 (void) write(2, s, cp - s); 548 } 549 if (lfp != NULL) 550 (void) fwrite(s, 1, cp - s, lfp); 551 } 552 return(0); 553 554 case '\3': 555 *--cp = '\0'; 556 if (lfp != NULL) 557 log(lfp, "update: note: %s\n", s); 558 goto again; 559 560 default: 561 *--cp = '\0'; 562 error("update: unexpected response '%s'\n", s); 563 return(0); 564 } 565 566 if (*s == '\n') 567 return(2); 568 569 if (opts & COMPARE) 570 return(3); 571 572 size = 0; 573 while (isdigit(*s)) 574 size = size * 10 + (*s++ - '0'); 575 if (*s++ != ' ') { 576 error("update: size not delimited\n"); 577 return(0); 578 } 579 mtime = 0; 580 while (isdigit(*s)) 581 mtime = mtime * 10 + (*s++ - '0'); 582 if (*s != '\n') { 583 error("update: mtime not delimited\n"); 584 return(0); 585 } 586 /* 587 * File needs to be updated? 588 */ 589 if (opts & YOUNGER) { 590 if (stp->st_mtime == mtime) 591 return(0); 592 if (stp->st_mtime < mtime) { 593 log(lfp, "Warning: %s: remote copy is newer\n", target); 594 return(0); 595 } 596 } else if (stp->st_mtime == mtime && stp->st_size == size) 597 return(0); 598 return(2); 599 } 600 601 /* 602 * Query. Check to see if file exists. Return one of the following: 603 * N\n - doesn't exist 604 * Ysize mtime\n - exists and its a regular file (size & mtime of file) 605 * Y\n - exists and its a directory or symbolic link 606 * ^Aerror message\n 607 */ 608 query(name) 609 char *name; 610 { 611 struct stat stb; 612 613 if (catname) 614 (void) sprintf(tp, "/%s", name); 615 616 if (lstat(target, &stb) < 0) { 617 if (errno == ENOENT) 618 (void) write(rem, "N\n", 2); 619 else 620 error("%s:%s: %s\n", host, target, strerror(errno)); 621 *tp = '\0'; 622 return; 623 } 624 625 switch (stb.st_mode & S_IFMT) { 626 case S_IFREG: 627 (void) sprintf(buf, "Y%ld %ld\n", stb.st_size, stb.st_mtime); 628 (void) write(rem, buf, strlen(buf)); 629 break; 630 631 case S_IFLNK: 632 case S_IFDIR: 633 (void) write(rem, "Y\n", 2); 634 break; 635 636 default: 637 error("%s: not a file or directory\n", name); 638 break; 639 } 640 *tp = '\0'; 641 } 642 643 recvf(cmd, type) 644 char *cmd; 645 int type; 646 { 647 register char *cp; 648 int f, mode, opts, wrerr, olderrno; 649 off_t i, size; 650 time_t mtime; 651 struct stat stb; 652 struct timeval tvp[2]; 653 char *owner, *group; 654 char new[BUFSIZ]; 655 extern char *tempname; 656 657 cp = cmd; 658 opts = 0; 659 while (*cp >= '0' && *cp <= '7') 660 opts = (opts << 3) | (*cp++ - '0'); 661 if (*cp++ != ' ') { 662 error("recvf: options not delimited\n"); 663 return; 664 } 665 mode = 0; 666 while (*cp >= '0' && *cp <= '7') 667 mode = (mode << 3) | (*cp++ - '0'); 668 if (*cp++ != ' ') { 669 error("recvf: mode not delimited\n"); 670 return; 671 } 672 size = 0; 673 while (isdigit(*cp)) 674 size = size * 10 + (*cp++ - '0'); 675 if (*cp++ != ' ') { 676 error("recvf: size not delimited\n"); 677 return; 678 } 679 mtime = 0; 680 while (isdigit(*cp)) 681 mtime = mtime * 10 + (*cp++ - '0'); 682 if (*cp++ != ' ') { 683 error("recvf: mtime not delimited\n"); 684 return; 685 } 686 owner = cp; 687 while (*cp && *cp != ' ') 688 cp++; 689 if (*cp != ' ') { 690 error("recvf: owner name not delimited\n"); 691 return; 692 } 693 *cp++ = '\0'; 694 group = cp; 695 while (*cp && *cp != ' ') 696 cp++; 697 if (*cp != ' ') { 698 error("recvf: group name not delimited\n"); 699 return; 700 } 701 *cp++ = '\0'; 702 703 if (type == S_IFDIR) { 704 if (catname >= sizeof(stp)) { 705 error("%s:%s: too many directory levels\n", 706 host, target); 707 return; 708 } 709 stp[catname] = tp; 710 if (catname++) { 711 *tp++ = '/'; 712 while (*tp++ = *cp++) 713 ; 714 tp--; 715 } 716 if (opts & VERIFY) { 717 ack(); 718 return; 719 } 720 if (lstat(target, &stb) == 0) { 721 if (ISDIR(stb.st_mode)) { 722 if ((stb.st_mode & 07777) == mode) { 723 ack(); 724 return; 725 } 726 buf[0] = '\0'; 727 (void) sprintf(buf + 1, 728 "%s: Warning: remote mode %o != local mode %o\n", 729 target, stb.st_mode & 07777, mode); 730 (void) write(rem, buf, strlen(buf + 1) + 1); 731 return; 732 } 733 errno = ENOTDIR; 734 } else if (errno == ENOENT && (mkdir(target, mode) == 0 || 735 chkparent(target) == 0 && mkdir(target, mode) == 0)) { 736 if (chog(target, owner, group, mode) == 0) 737 ack(); 738 return; 739 } 740 error("%s:%s: %s\n", host, target, strerror(errno)); 741 tp = stp[--catname]; 742 *tp = '\0'; 743 return; 744 } 745 746 if (catname) 747 (void) sprintf(tp, "/%s", cp); 748 cp = rindex(target, '/'); 749 if (cp == NULL) 750 strcpy(new, tempname); 751 else if (cp == target) 752 (void) sprintf(new, "/%s", tempname); 753 else { 754 *cp = '\0'; 755 (void) sprintf(new, "%s/%s", target, tempname); 756 *cp = '/'; 757 } 758 759 if (type == S_IFLNK) { 760 int j; 761 762 ack(); 763 cp = buf; 764 for (i = 0; i < size; i += j) { 765 if ((j = read(rem, cp, size - i)) <= 0) 766 cleanup(); 767 cp += j; 768 } 769 *cp = '\0'; 770 if (response() < 0) { 771 err(); 772 return; 773 } 774 if (symlink(buf, new) < 0) { 775 if (errno != ENOENT || chkparent(new) < 0 || 776 symlink(buf, new) < 0) 777 goto badn; 778 } 779 mode &= 0777; 780 if (opts & COMPARE) { 781 char tbuf[BUFSIZ]; 782 783 if ((i = readlink(target, tbuf, BUFSIZ)) >= 0 && 784 i == size && strncmp(buf, tbuf, size) == 0) { 785 (void) unlink(new); 786 ack(); 787 return; 788 } 789 if (opts & VERIFY) 790 goto differ; 791 } 792 goto fixup; 793 } 794 795 if ((f = creat(new, mode)) < 0) { 796 if (errno != ENOENT || chkparent(new) < 0 || 797 (f = creat(new, mode)) < 0) 798 goto badn; 799 } 800 801 ack(); 802 wrerr = 0; 803 for (i = 0; i < size; i += BUFSIZ) { 804 int amt = BUFSIZ; 805 806 cp = buf; 807 if (i + amt > size) 808 amt = size - i; 809 do { 810 int j = read(rem, cp, amt); 811 812 if (j <= 0) { 813 (void) close(f); 814 (void) unlink(new); 815 cleanup(); 816 } 817 amt -= j; 818 cp += j; 819 } while (amt > 0); 820 amt = BUFSIZ; 821 if (i + amt > size) 822 amt = size - i; 823 if (wrerr == 0 && write(f, buf, amt) != amt) { 824 olderrno = errno; 825 wrerr++; 826 } 827 } 828 (void) close(f); 829 if (response() < 0) { 830 err(); 831 (void) unlink(new); 832 return; 833 } 834 if (wrerr) { 835 error("%s:%s: %s\n", host, new, strerror(errno)); 836 (void) unlink(new); 837 return; 838 } 839 if (opts & COMPARE) { 840 FILE *f1, *f2; 841 int c; 842 843 if ((f1 = fopen(target, "r")) == NULL) 844 goto badt; 845 if ((f2 = fopen(new, "r")) == NULL) { 846 badn: 847 error("%s:%s: %s\n", host, new, strerror(errno)); 848 (void) unlink(new); 849 return; 850 } 851 while ((c = getc(f1)) == getc(f2)) 852 if (c == EOF) { 853 (void) fclose(f1); 854 (void) fclose(f2); 855 (void) unlink(new); 856 ack(); 857 return; 858 } 859 (void) fclose(f1); 860 (void) fclose(f2); 861 if (opts & VERIFY) { 862 differ: 863 (void) unlink(new); 864 buf[0] = '\0'; 865 (void) sprintf(buf + 1, "need to update: %s\n",target); 866 (void) write(rem, buf, strlen(buf + 1) + 1); 867 return; 868 } 869 } 870 871 /* 872 * Set last modified time 873 */ 874 tvp[0].tv_sec = stb.st_atime; /* old atime from target */ 875 tvp[0].tv_usec = 0; 876 tvp[1].tv_sec = mtime; 877 tvp[1].tv_usec = 0; 878 if (utimes(new, tvp) < 0) { 879 note("%s:utimes failed %s: %s\n", host, new, strerror(errno)); 880 } 881 if (chog(new, owner, group, mode) < 0) { 882 (void) unlink(new); 883 return; 884 } 885 fixup: 886 if (rename(new, target) < 0) { 887 badt: 888 error("%s:%s: %s\n", host, target, strerror(errno)); 889 (void) unlink(new); 890 return; 891 } 892 if (opts & COMPARE) { 893 buf[0] = '\0'; 894 (void) sprintf(buf + 1, "updated %s\n", target); 895 (void) write(rem, buf, strlen(buf + 1) + 1); 896 } else 897 ack(); 898 } 899 900 /* 901 * Creat a hard link to existing file. 902 */ 903 hardlink(cmd) 904 char *cmd; 905 { 906 register char *cp; 907 struct stat stb; 908 char *oldname; 909 int opts, exists = 0; 910 911 cp = cmd; 912 opts = 0; 913 while (*cp >= '0' && *cp <= '7') 914 opts = (opts << 3) | (*cp++ - '0'); 915 if (*cp++ != ' ') { 916 error("hardlink: options not delimited\n"); 917 return; 918 } 919 oldname = cp; 920 while (*cp && *cp != ' ') 921 cp++; 922 if (*cp != ' ') { 923 error("hardlink: oldname name not delimited\n"); 924 return; 925 } 926 *cp++ = '\0'; 927 928 if (catname) { 929 (void) sprintf(tp, "/%s", cp); 930 } 931 if (lstat(target, &stb) == 0) { 932 int mode = stb.st_mode & S_IFMT; 933 if (mode != S_IFREG && mode != S_IFLNK) { 934 error("%s:%s: not a regular file\n", host, target); 935 return; 936 } 937 exists = 1; 938 } 939 if (chkparent(target) < 0 ) { 940 error("%s:%s: %s (no parent)\n", 941 host, target, strerror(errno)); 942 return; 943 } 944 if (exists && (unlink(target) < 0)) { 945 error("%s:%s: %s (unlink)\n", 946 host, target, strerror(errno)); 947 return; 948 } 949 if (link(oldname, target) < 0) { 950 error("%s:can't link %s to %s\n", 951 host, target, oldname); 952 return; 953 } 954 ack(); 955 } 956 957 /* 958 * Check to see if parent directory exists and create one if not. 959 */ 960 chkparent(name) 961 char *name; 962 { 963 register char *cp; 964 struct stat stb; 965 966 cp = rindex(name, '/'); 967 if (cp == NULL || cp == name) 968 return(0); 969 *cp = '\0'; 970 if (lstat(name, &stb) < 0) { 971 if (errno == ENOENT && chkparent(name) >= 0 && 972 mkdir(name, 0777 & ~oumask) >= 0) { 973 *cp = '/'; 974 return(0); 975 } 976 } else if (ISDIR(stb.st_mode)) { 977 *cp = '/'; 978 return(0); 979 } 980 *cp = '/'; 981 return(-1); 982 } 983 984 /* 985 * Change owner, group and mode of file. 986 */ 987 chog(file, owner, group, mode) 988 char *file, *owner, *group; 989 int mode; 990 { 991 register int i; 992 int uid, gid; 993 extern char user[]; 994 extern int userid; 995 996 uid = userid; 997 if (userid == 0) { 998 if (*owner == ':') { 999 uid = atoi(owner + 1); 1000 } else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) { 1001 if ((pw = getpwnam(owner)) == NULL) { 1002 if (mode & 04000) { 1003 note("%s:%s: unknown login name, clearing setuid", 1004 host, owner); 1005 mode &= ~04000; 1006 uid = 0; 1007 } 1008 } else 1009 uid = pw->pw_uid; 1010 } else 1011 uid = pw->pw_uid; 1012 if (*group == ':') { 1013 gid = atoi(group + 1); 1014 goto ok; 1015 } 1016 } else if ((mode & 04000) && strcmp(user, owner) != 0) 1017 mode &= ~04000; 1018 gid = -1; 1019 if (gr == NULL || strcmp(group, gr->gr_name) != 0) { 1020 if ((*group == ':' && (getgrgid(gid = atoi(group + 1)) == NULL)) 1021 || ((gr = getgrnam(group)) == NULL)) { 1022 if (mode & 02000) { 1023 note("%s:%s: unknown group", host, group); 1024 mode &= ~02000; 1025 } 1026 } else 1027 gid = gr->gr_gid; 1028 } else 1029 gid = gr->gr_gid; 1030 if (userid && gid >= 0) { 1031 if (gr) for (i = 0; gr->gr_mem[i] != NULL; i++) 1032 if (!(strcmp(user, gr->gr_mem[i]))) 1033 goto ok; 1034 mode &= ~02000; 1035 gid = -1; 1036 } 1037 ok: 1038 if (userid) 1039 setreuid(userid, 0); 1040 if (chown(file, uid, gid) < 0 || 1041 (mode & 07000) && chmod(file, mode) < 0) { 1042 note("%s: chown or chmod failed: file %s: %s", 1043 host, file, strerror(errno)); 1044 } 1045 if (userid) 1046 setreuid(0, userid); 1047 return(0); 1048 } 1049 1050 /* 1051 * Check for files on the machine being updated that are not on the master 1052 * machine and remove them. 1053 */ 1054 rmchk(opts) 1055 int opts; 1056 { 1057 register char *cp, *s; 1058 struct stat stb; 1059 1060 if (debug) 1061 printf("rmchk()\n"); 1062 1063 /* 1064 * Tell the remote to clean the files from the last directory sent. 1065 */ 1066 (void) sprintf(buf, "C%o\n", opts & VERIFY); 1067 if (debug) 1068 printf("buf = %s", buf); 1069 (void) write(rem, buf, strlen(buf)); 1070 if (response() < 0) 1071 return; 1072 for (;;) { 1073 cp = s = buf; 1074 do { 1075 if (read(rem, cp, 1) != 1) 1076 lostconn(); 1077 } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); 1078 1079 switch (*s++) { 1080 case 'Q': /* Query if file should be removed */ 1081 /* 1082 * Return the following codes to remove query. 1083 * N\n -- file exists - DON'T remove. 1084 * Y\n -- file doesn't exist - REMOVE. 1085 */ 1086 *--cp = '\0'; 1087 (void) sprintf(tp, "/%s", s); 1088 if (debug) 1089 printf("check %s\n", target); 1090 if (except(target)) 1091 (void) write(rem, "N\n", 2); 1092 else if (lstat(target, &stb) < 0) 1093 (void) write(rem, "Y\n", 2); 1094 else 1095 (void) write(rem, "N\n", 2); 1096 break; 1097 1098 case '\0': 1099 *--cp = '\0'; 1100 if (*s != '\0') 1101 log(lfp, "%s\n", s); 1102 break; 1103 1104 case 'E': 1105 *tp = '\0'; 1106 ack(); 1107 return; 1108 1109 case '\1': 1110 case '\2': 1111 nerrs++; 1112 if (*s != '\n') { 1113 if (!iamremote) { 1114 fflush(stdout); 1115 (void) write(2, s, cp - s); 1116 } 1117 if (lfp != NULL) 1118 (void) fwrite(s, 1, cp - s, lfp); 1119 } 1120 if (buf[0] == '\2') 1121 lostconn(); 1122 break; 1123 1124 default: 1125 error("rmchk: unexpected response '%s'\n", buf); 1126 err(); 1127 } 1128 } 1129 } 1130 1131 /* 1132 * Check the current directory (initialized by the 'T' command to server()) 1133 * for extraneous files and remove them. 1134 */ 1135 clean(cp) 1136 register char *cp; 1137 { 1138 DIR *d; 1139 register struct direct *dp; 1140 struct stat stb; 1141 char *otp; 1142 int len, opts; 1143 1144 opts = 0; 1145 while (*cp >= '0' && *cp <= '7') 1146 opts = (opts << 3) | (*cp++ - '0'); 1147 if (*cp != '\0') { 1148 error("clean: options not delimited\n"); 1149 return; 1150 } 1151 if ((d = opendir(target)) == NULL) { 1152 error("%s:%s: %s\n", host, target, strerror(errno)); 1153 return; 1154 } 1155 ack(); 1156 1157 otp = tp; 1158 len = tp - target; 1159 while (dp = readdir(d)) { 1160 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 1161 continue; 1162 if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 1163 error("%s:%s/%s: Name too long\n", 1164 host, target, dp->d_name); 1165 continue; 1166 } 1167 tp = otp; 1168 *tp++ = '/'; 1169 cp = dp->d_name;; 1170 while (*tp++ = *cp++) 1171 ; 1172 tp--; 1173 if (lstat(target, &stb) < 0) { 1174 error("%s:%s: %s\n", host, target, strerror(errno)); 1175 continue; 1176 } 1177 (void) sprintf(buf, "Q%s\n", dp->d_name); 1178 (void) write(rem, buf, strlen(buf)); 1179 cp = buf; 1180 do { 1181 if (read(rem, cp, 1) != 1) 1182 cleanup(); 1183 } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); 1184 *--cp = '\0'; 1185 cp = buf; 1186 if (*cp != 'Y') 1187 continue; 1188 if (opts & VERIFY) { 1189 cp = buf; 1190 *cp++ = '\0'; 1191 (void) sprintf(cp, "need to remove: %s\n", target); 1192 (void) write(rem, buf, strlen(cp) + 1); 1193 } else 1194 remove(&stb); 1195 } 1196 closedir(d); 1197 (void) write(rem, "E\n", 2); 1198 (void) response(); 1199 tp = otp; 1200 *tp = '\0'; 1201 } 1202 1203 /* 1204 * Remove a file or directory (recursively) and send back an acknowledge 1205 * or an error message. 1206 */ 1207 remove(stp) 1208 struct stat *stp; 1209 { 1210 DIR *d; 1211 struct direct *dp; 1212 register char *cp; 1213 struct stat stb; 1214 char *otp; 1215 int len; 1216 1217 switch (stp->st_mode & S_IFMT) { 1218 case S_IFREG: 1219 case S_IFLNK: 1220 if (unlink(target) < 0) 1221 goto bad; 1222 goto removed; 1223 1224 case S_IFDIR: 1225 break; 1226 1227 default: 1228 error("%s:%s: not a plain file\n", host, target); 1229 return; 1230 } 1231 1232 if ((d = opendir(target)) == NULL) 1233 goto bad; 1234 1235 otp = tp; 1236 len = tp - target; 1237 while (dp = readdir(d)) { 1238 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 1239 continue; 1240 if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 1241 error("%s:%s/%s: Name too long\n", 1242 host, target, dp->d_name); 1243 continue; 1244 } 1245 tp = otp; 1246 *tp++ = '/'; 1247 cp = dp->d_name;; 1248 while (*tp++ = *cp++) 1249 ; 1250 tp--; 1251 if (lstat(target, &stb) < 0) { 1252 error("%s:%s: %s\n", host, target, strerror(errno)); 1253 continue; 1254 } 1255 remove(&stb); 1256 } 1257 closedir(d); 1258 tp = otp; 1259 *tp = '\0'; 1260 if (rmdir(target) < 0) { 1261 bad: 1262 error("%s:%s: %s\n", host, target, strerror(errno)); 1263 return; 1264 } 1265 removed: 1266 cp = buf; 1267 *cp++ = '\0'; 1268 (void) sprintf(cp, "removed %s\n", target); 1269 (void) write(rem, buf, strlen(cp) + 1); 1270 } 1271 1272 /* 1273 * Execute a shell command to handle special cases. 1274 */ 1275 dospecial(cmd) 1276 char *cmd; 1277 { 1278 int fd[2], status, pid, i; 1279 register char *cp, *s; 1280 char sbuf[BUFSIZ]; 1281 extern int userid, groupid; 1282 1283 if (pipe(fd) < 0) { 1284 error("%s\n", strerror(errno)); 1285 return; 1286 } 1287 if ((pid = fork()) == 0) { 1288 /* 1289 * Return everything the shell commands print. 1290 */ 1291 (void) close(0); 1292 (void) close(1); 1293 (void) close(2); 1294 (void) open(_PATH_DEVNULL, O_RDONLY); 1295 (void) dup(fd[1]); 1296 (void) dup(fd[1]); 1297 (void) close(fd[0]); 1298 (void) close(fd[1]); 1299 setgid(groupid); 1300 setuid(userid); 1301 execl(_PATH_BSHELL, "sh", "-c", cmd, 0); 1302 _exit(127); 1303 } 1304 (void) close(fd[1]); 1305 s = sbuf; 1306 *s++ = '\0'; 1307 while ((i = read(fd[0], buf, sizeof(buf))) > 0) { 1308 cp = buf; 1309 do { 1310 *s++ = *cp++; 1311 if (cp[-1] != '\n') { 1312 if (s < &sbuf[sizeof(sbuf)-1]) 1313 continue; 1314 *s++ = '\n'; 1315 } 1316 /* 1317 * Throw away blank lines. 1318 */ 1319 if (s == &sbuf[2]) { 1320 s--; 1321 continue; 1322 } 1323 (void) write(rem, sbuf, s - sbuf); 1324 s = &sbuf[1]; 1325 } while (--i); 1326 } 1327 if (s > &sbuf[1]) { 1328 *s++ = '\n'; 1329 (void) write(rem, sbuf, s - sbuf); 1330 } 1331 while ((i = wait(&status)) != pid && i != -1) 1332 ; 1333 if (i == -1) 1334 status = -1; 1335 (void) close(fd[0]); 1336 if (status) 1337 error("shell returned %d\n", status); 1338 else 1339 ack(); 1340 } 1341 1342 /*VARARGS2*/ 1343 log(fp, fmt, a1, a2, a3) 1344 FILE *fp; 1345 char *fmt; 1346 int a1, a2, a3; 1347 { 1348 /* Print changes locally if not quiet mode */ 1349 if (!qflag) 1350 printf(fmt, a1, a2, a3); 1351 1352 /* Save changes (for mailing) if really updating files */ 1353 if (!(options & VERIFY) && fp != NULL) 1354 fprintf(fp, fmt, a1, a2, a3); 1355 } 1356 1357 /*VARARGS1*/ 1358 error(fmt, a1, a2, a3) 1359 char *fmt; 1360 int a1, a2, a3; 1361 { 1362 static FILE *fp; 1363 1364 ++nerrs; 1365 if (!fp && !(fp = fdopen(rem, "w"))) 1366 return; 1367 if (iamremote) { 1368 (void)fprintf(fp, "%crdist: ", 0x01); 1369 (void)fprintf(fp, fmt, a1, a2, a3); 1370 fflush(fp); 1371 } 1372 else { 1373 fflush(stdout); 1374 (void)fprintf(stderr, "rdist: "); 1375 (void)fprintf(stderr, fmt, a1, a2, a3); 1376 fflush(stderr); 1377 } 1378 if (lfp != NULL) { 1379 (void)fprintf(lfp, "rdist: "); 1380 (void)fprintf(lfp, fmt, a1, a2, a3); 1381 fflush(lfp); 1382 } 1383 } 1384 1385 /*VARARGS1*/ 1386 fatal(fmt, a1, a2,a3) 1387 char *fmt; 1388 int a1, a2, a3; 1389 { 1390 static FILE *fp; 1391 1392 ++nerrs; 1393 if (!fp && !(fp = fdopen(rem, "w"))) 1394 return; 1395 if (iamremote) { 1396 (void)fprintf(fp, "%crdist: ", 0x02); 1397 (void)fprintf(fp, fmt, a1, a2, a3); 1398 fflush(fp); 1399 } 1400 else { 1401 fflush(stdout); 1402 (void)fprintf(stderr, "rdist: "); 1403 (void)fprintf(stderr, fmt, a1, a2, a3); 1404 fflush(stderr); 1405 } 1406 if (lfp != NULL) { 1407 (void)fprintf(lfp, "rdist: "); 1408 (void)fprintf(lfp, fmt, a1, a2, a3); 1409 fflush(lfp); 1410 } 1411 cleanup(); 1412 } 1413 1414 response() 1415 { 1416 char *cp, *s; 1417 char resp[BUFSIZ]; 1418 1419 if (debug) 1420 printf("response()\n"); 1421 1422 cp = s = resp; 1423 do { 1424 if (read(rem, cp, 1) != 1) 1425 lostconn(); 1426 } while (*cp++ != '\n' && cp < &resp[BUFSIZ]); 1427 1428 switch (*s++) { 1429 case '\0': 1430 *--cp = '\0'; 1431 if (*s != '\0') { 1432 log(lfp, "%s\n", s); 1433 return(1); 1434 } 1435 return(0); 1436 case '\3': 1437 *--cp = '\0'; 1438 log(lfp, "Note: %s\n",s); 1439 return(response()); 1440 1441 default: 1442 s--; 1443 /* fall into... */ 1444 case '\1': 1445 case '\2': 1446 nerrs++; 1447 if (*s != '\n') { 1448 if (!iamremote) { 1449 fflush(stdout); 1450 (void) write(2, s, cp - s); 1451 } 1452 if (lfp != NULL) 1453 (void) fwrite(s, 1, cp - s, lfp); 1454 } 1455 if (resp[0] == '\2') 1456 lostconn(); 1457 return(-1); 1458 } 1459 } 1460 1461 /* 1462 * Remove temporary files and do any cleanup operations before exiting. 1463 */ 1464 cleanup() 1465 { 1466 (void) unlink(tempfile); 1467 exit(1); 1468 } 1469 1470 note(fmt, a1, a2, a3) 1471 { 1472 static char buf[BUFSIZ]; 1473 sprintf(buf, fmt, a1, a2, a3); 1474 comment(buf); 1475 } 1476 1477 comment(s) 1478 char *s; 1479 { 1480 char c = '\3'; 1481 write(rem, &c, 1); 1482 write(rem, s, strlen(s)); 1483 c = '\n'; 1484 write(rem, &c, 1); 1485 } 1486