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