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