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