1 /* 2 * Copyright 2005 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 #pragma ident "%Z%%M% %I% %E% SMI" 20 21 #include "defs.h" 22 #include <signal.h> 23 #include <string.h> 24 #include <errno.h> 25 #include <limits.h> 26 #include <ctype.h> 27 #include <krb5defs.h> 28 29 /* 30 * If we want to write *to* the client rdist program, *from* the server 31 * side (server-side child `rdist -Server' process exec'ed off of in.rshd), 32 * we write to stdout/stderr, since there is a pipe connecting stdout/stderr 33 * to the outside world (which is why we use `wrem' and not `rem'). 34 */ 35 int wrem = 1; 36 37 #define ack() (void) write(wrem, "\0\n", 2) 38 #define err() (void) write(wrem, "\1\n", 2) 39 40 /* 41 * Set when a desread() is reqd. in response() 42 */ 43 44 struct linkbuf *ihead; /* list of files with more than one link */ 45 char buf[RDIST_BUFSIZ]; /* general purpose buffer */ 46 char source[RDIST_BUFSIZ]; /* base source directory name */ 47 char destination[RDIST_BUFSIZ]; /* base destination directory name */ 48 char target[RDIST_BUFSIZ]; /* target/source directory name */ 49 char *tp; /* pointer to end of target name */ 50 char *Tdest; /* pointer to last T dest */ 51 int catname; /* cat name to target name */ 52 char *stp[32]; /* stack of saved tp's for directories */ 53 int oumask; /* old umask for creating files */ 54 55 extern FILE *lfp; /* log file for mailing changes */ 56 57 void cleanup(); 58 struct linkbuf *savelink(); 59 char *strsub(); 60 61 static void comment(char *s); 62 static void note(); 63 static void hardlink(char *cmd); 64 void error(); 65 void log(); 66 static void recursive_remove(struct stat *stp); 67 static void recvf(char *cmd, int type); 68 static void query(char *name); 69 static void sendf(char *rname, int opts); 70 static void rmchk(int opts); 71 static void dospecial(char *cmd); 72 static void clean(char *cp); 73 74 /* 75 * Server routine to read requests and process them. 76 * Commands are: 77 * Tname - Transmit file if out of date 78 * Vname - Verify if file out of date or not 79 * Qname - Query if file exists. Return mtime & size if it does. 80 */ 81 void 82 server() 83 { 84 char cmdbuf[RDIST_BUFSIZ]; 85 register char *cp; 86 87 signal(SIGHUP, cleanup); 88 signal(SIGINT, cleanup); 89 signal(SIGQUIT, cleanup); 90 signal(SIGTERM, cleanup); 91 signal(SIGPIPE, cleanup); 92 93 rem = 0; 94 oumask = umask(0); 95 96 (void) sprintf(buf, "V%d\n", VERSION); 97 (void) write(wrem, buf, strlen(buf)); 98 99 for (;;) { 100 cp = cmdbuf; 101 if (read(rem, cp, 1) <= 0) 102 return; 103 if (*cp++ == '\n') { 104 error("server: expected control record\n"); 105 continue; 106 } 107 do { 108 if (read(rem, cp, 1) != 1) 109 cleanup(); 110 } while (*cp++ != '\n' && cp < &cmdbuf[RDIST_BUFSIZ]); 111 *--cp = '\0'; 112 cp = cmdbuf; 113 switch (*cp++) { 114 case 'T': /* init target file/directory name */ 115 catname = 1; /* target should be directory */ 116 goto dotarget; 117 118 case 't': /* init target file/directory name */ 119 catname = 0; 120 dotarget: 121 if (exptilde(target, sizeof (target), cp) == NULL) 122 continue; 123 tp = target; 124 while (*tp) 125 tp++; 126 ack(); 127 continue; 128 129 case 'R': /* Transfer a regular file. */ 130 recvf(cp, S_IFREG); 131 continue; 132 133 case 'D': /* Transfer a directory. */ 134 recvf(cp, S_IFDIR); 135 continue; 136 137 case 'K': /* Transfer symbolic link. */ 138 recvf(cp, S_IFLNK); 139 continue; 140 141 case 'k': /* Transfer hard link. */ 142 hardlink(cp); 143 continue; 144 145 case 'E': /* End. (of directory) */ 146 *tp = '\0'; 147 if (catname <= 0) { 148 error("server: too many 'E's\n"); 149 continue; 150 } 151 tp = stp[--catname]; 152 *tp = '\0'; 153 ack(); 154 continue; 155 156 case 'C': /* Clean. Cleanup a directory */ 157 clean(cp); 158 continue; 159 160 case 'Q': /* Query. Does the file/directory exist? */ 161 query(cp); 162 continue; 163 164 case 'S': /* Special. Execute commands */ 165 dospecial(cp); 166 continue; 167 168 #ifdef notdef 169 /* 170 * These entries are reserved but not currently used. 171 * The intent is to allow remote hosts to have master copies. 172 * Currently, only the host rdist runs on can have masters. 173 */ 174 case 'X': /* start a new list of files to exclude */ 175 except = bp = NULL; 176 case 'x': /* add name to list of files to exclude */ 177 if (*cp == '\0') { 178 ack(); 179 continue; 180 } 181 if (*cp == '~') { 182 if (exptilde(buf, sizeof (buf), cp) == NULL) 183 continue; 184 cp = buf; 185 } 186 if (bp == NULL) 187 except = bp = expand(makeblock(NAME, cp), 188 E_VARS); 189 else 190 bp->b_next = expand(makeblock(NAME, cp), 191 E_VARS); 192 while (bp->b_next != NULL) 193 bp = bp->b_next; 194 ack(); 195 continue; 196 197 case 'I': /* Install. Transfer file if out of date. */ 198 opts = 0; 199 while (*cp >= '0' && *cp <= '7') 200 opts = (opts << 3) | (*cp++ - '0'); 201 if (*cp++ != ' ') { 202 error("server: options not delimited\n"); 203 return; 204 } 205 install(cp, opts); 206 continue; 207 208 case 'L': /* Log. save message in log file */ 209 log(lfp, cp); 210 continue; 211 #endif 212 213 case '\1': 214 nerrs++; 215 continue; 216 217 case '\2': 218 return; 219 220 default: 221 error("server: unknown command '%s'\n", cp); 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 strcpy(lp->pathname, 581 opts & WHOLE ? 582 target : strsub(source, destination, target)); 583 if (Tdest) 584 strcpy(lp->target, Tdest); 585 else 586 *lp->target = 0; 587 } 588 return (NULL); 589 } 590 591 /* 592 * Check to see if file needs to be updated on the remote machine. 593 * Returns 0 if no update, 1 if remote doesn't exist, 2 if out of date 594 * and 3 if comparing binaries to determine if out of date. 595 */ 596 int 597 update(rname, opts, stp) 598 char *rname; 599 int opts; 600 struct stat *stp; 601 { 602 register char *cp, *s; 603 register off_t size; 604 register time_t mtime; 605 606 if (debug) 607 printf("update(%s, %x%s, %x)\n", rname, opts, 608 printb(opts, OBITS), stp); 609 610 /* 611 * Check to see if the file exists on the remote machine. 612 */ 613 if (snprintf(buf, sizeof (buf), "Q%s\n", rname) >= sizeof (buf)) { 614 error("%s: Name too long\n", rname); 615 return (0); 616 } 617 if (debug) 618 printf("buf = %s", buf); 619 (void) deswrite(rem, buf, strlen(buf), 0); 620 again: 621 cp = s = buf; 622 more: 623 do { 624 if (desread(rem, cp, 1, 0) != 1) 625 lostconn(); 626 } while (*cp++ != '\n' && cp < &buf[RDIST_BUFSIZ]); 627 628 if (cp < &buf[RDIST_BUFSIZ]) 629 *cp = '\0'; 630 if (debug) { 631 printf("update reply: "); 632 switch (*s) { 633 case 'Y': 634 case 'N': 635 putchar(*s); 636 break; 637 default: 638 if (iscntrl(*s)) { 639 putchar('^'); 640 putchar('A' + *s - 1); 641 } else 642 printf("%#x", *s & 0xff); 643 break; 644 } 645 printf("%s", &s[1]); 646 } 647 648 switch (*s++) { 649 case 'Y': 650 break; 651 652 case 'N': /* file doesn't exist so install it */ 653 return (1); 654 655 case '\1': 656 nerrs++; 657 if (*s != '\n') { 658 if (!iamremote) { 659 fflush(stdout); 660 (void) write(2, s, cp - s); 661 } 662 if (lfp != NULL) 663 (void) fwrite(s, 1, cp - s, lfp); 664 } 665 if (cp == &buf[RDIST_BUFSIZ] && *(cp - 1) != '\n') { 666 /* preserve status code */ 667 cp = s; 668 s = buf; 669 goto more; 670 } 671 return (0); 672 673 case '\3': 674 *--cp = '\0'; 675 if (lfp != NULL) 676 log(lfp, "update: note: %s\n", s); 677 goto again; 678 679 default: 680 *--cp = '\0'; 681 error("update: unexpected response '%s'\n", s); 682 return (0); 683 } 684 685 if (*s == '\n') 686 return (2); 687 688 if (opts & COMPARE) 689 return (3); 690 691 size = 0; 692 while (isdigit(*s)) 693 size = size * 10 + (*s++ - '0'); 694 if (*s++ != ' ') { 695 error("update: size not delimited\n"); 696 return (0); 697 } 698 mtime = 0; 699 while (isdigit(*s)) 700 mtime = mtime * 10 + (*s++ - '0'); 701 if (*s != '\n') { 702 error("update: mtime not delimited\n"); 703 return (0); 704 } 705 /* 706 * File needs to be updated? 707 */ 708 if (opts & YOUNGER) { 709 if (stp->st_mtime == mtime) 710 return (0); 711 if (stp->st_mtime < mtime) { 712 log(lfp, "Warning: %s: remote copy is newer\n", target); 713 return (0); 714 } 715 } else if (stp->st_mtime == mtime && stp->st_size == size) 716 return (0); 717 return (2); 718 } 719 720 /* 721 * Query. Check to see if file exists. Return one of the following: 722 * N\n - doesn't exist 723 * Ysize mtime\n - exists and its a regular file (size & mtime of file) 724 * Y\n - exists and its a directory or symbolic link 725 * ^Aerror message\n 726 */ 727 static void 728 query(name) 729 char *name; 730 { 731 struct stat stb; 732 733 if (catname) { 734 if (sizeof (target) - (tp - target) >= strlen(name) + 2) { 735 (void) sprintf(tp, "/%s", name); 736 } else { 737 error("%.*s/%s: Name too long\n", tp - target, 738 target, name); 739 return; 740 } 741 } 742 743 if (lstat(target, &stb) < 0) { 744 if (errno == ENOENT) 745 (void) write(wrem, "N\n", 2); 746 else 747 error("%s:%s: %s\n", host, target, strerror(errno)); 748 *tp = '\0'; 749 return; 750 } 751 752 switch (stb.st_mode & S_IFMT) { 753 case S_IFREG: 754 (void) sprintf(buf, "Y%ld %ld\n", stb.st_size, stb.st_mtime); 755 (void) write(wrem, buf, strlen(buf)); 756 break; 757 758 case S_IFLNK: 759 case S_IFDIR: 760 (void) write(wrem, "Y\n", 2); 761 break; 762 763 default: 764 error("%s: not a file or directory\n", name); 765 break; 766 } 767 *tp = '\0'; 768 } 769 770 static void 771 recvf(cmd, type) 772 char *cmd; 773 int type; 774 { 775 register char *cp; 776 int f, mode, opts, wrerr, olderrno; 777 off_t i, size; 778 time_t mtime; 779 struct stat stb; 780 struct timeval tvp[2]; 781 char *owner, *group; 782 char new[RDIST_BUFSIZ]; 783 extern char *tmpname; 784 785 cp = cmd; 786 opts = 0; 787 while (*cp >= '0' && *cp <= '7') 788 opts = (opts << 3) | (*cp++ - '0'); 789 if (*cp++ != ' ') { 790 error("recvf: options not delimited\n"); 791 return; 792 } 793 mode = 0; 794 while (*cp >= '0' && *cp <= '7') 795 mode = (mode << 3) | (*cp++ - '0'); 796 if (*cp++ != ' ') { 797 error("recvf: mode not delimited\n"); 798 return; 799 } 800 size = 0; 801 while (isdigit(*cp)) 802 size = size * 10 + (*cp++ - '0'); 803 if (*cp++ != ' ') { 804 error("recvf: size not delimited\n"); 805 return; 806 } 807 mtime = 0; 808 while (isdigit(*cp)) 809 mtime = mtime * 10 + (*cp++ - '0'); 810 if (*cp++ != ' ') { 811 error("recvf: mtime not delimited\n"); 812 return; 813 } 814 owner = cp; 815 while (*cp && *cp != ' ') 816 cp++; 817 if (*cp != ' ') { 818 error("recvf: owner name not delimited\n"); 819 return; 820 } 821 *cp++ = '\0'; 822 group = cp; 823 while (*cp && *cp != ' ') 824 cp++; 825 if (*cp != ' ') { 826 error("recvf: group name not delimited\n"); 827 return; 828 } 829 *cp++ = '\0'; 830 831 if (type == S_IFDIR) { 832 int isdot; 833 834 if (strcmp(cp, ".") == 0) 835 isdot = 1; 836 else 837 isdot = 0; 838 if (catname >= sizeof (stp) / sizeof (stp[0])) { 839 error("%s:%s: too many directory levels\n", 840 host, target); 841 return; 842 } 843 stp[catname] = tp; 844 if (catname++) { 845 *tp++ = '/'; 846 while (*tp++ = *cp++) 847 ; 848 tp--; 849 } 850 if (opts & VERIFY) { 851 ack(); 852 return; 853 } 854 if (lstat(target, &stb) == 0) { 855 if (ISDIR(stb.st_mode)) { 856 if ((stb.st_mode & 07777) == mode) { 857 ack(); 858 return; 859 } 860 sendrem("%s: Warning: remote mode %o != " 861 "local mode %o", target, 862 stb.st_mode & 07777, mode); 863 return; 864 } 865 errno = ENOTDIR; 866 } else if (errno == ENOENT && (mkdir(target, mode) == 0 || 867 chkparent(target) == 0 && 868 (isdot == 1 || mkdir(target, mode) == 0))) { 869 if (chog(target, owner, group, mode) == 0) 870 ack(); 871 return; 872 } 873 error("%s:%s: %s\n", host, target, strerror(errno)); 874 tp = stp[--catname]; 875 *tp = '\0'; 876 return; 877 } 878 879 if (catname) { 880 if (sizeof (target) - (tp - target) >= strlen(cp) + 2) { 881 (void) sprintf(tp, "/%s", cp); 882 } else { 883 error("%.*s/%s: Name too long\n", tp - target, 884 target, cp); 885 return; 886 } 887 } 888 cp = rindex(target, '/'); 889 if (cp == NULL) 890 strcpy(new, tmpname); 891 else if (cp == target) 892 (void) sprintf(new, "/%s", tmpname); 893 else { 894 *cp = '\0'; 895 (void) sprintf(new, "%s/%s", target, tmpname); 896 *cp = '/'; 897 } 898 899 if (type == S_IFLNK) { 900 int j; 901 902 ack(); 903 cp = buf; 904 for (i = 0; i < size; i += j) { 905 if ((j = read(rem, cp, size - i)) <= 0) 906 cleanup(); 907 cp += j; 908 } 909 *cp = '\0'; 910 if (response() < 0) { 911 err(); 912 return; 913 } 914 if (symlink(buf, new) < 0) { 915 if (errno != ENOENT || chkparent(new) < 0 || 916 symlink(buf, new) < 0) 917 goto badn; 918 } 919 mode &= 0777; 920 if (opts & COMPARE) { 921 char tbuf[MAXPATHLEN]; 922 923 if ((i = readlink(target, tbuf, MAXPATHLEN)) >= 0 && 924 i == size && strncmp(buf, tbuf, size) == 0) { 925 (void) unlink(new); 926 ack(); 927 return; 928 } 929 if (opts & VERIFY) 930 goto differ; 931 } 932 goto fixup; 933 } 934 935 if ((f = creat(new, mode & ~06000)) < 0) { 936 if (errno != ENOENT || chkparent(new) < 0 || 937 (f = creat(new, mode & ~06000)) < 0) 938 goto badn; 939 } 940 941 ack(); 942 wrerr = 0; 943 for (i = 0; i < size; i += RDIST_BUFSIZ) { 944 int amt = RDIST_BUFSIZ; 945 946 cp = buf; 947 if (i + amt > size) 948 amt = size - i; 949 do { 950 int j = read(rem, cp, amt); 951 if (j <= 0) { 952 (void) close(f); 953 (void) unlink(new); 954 cleanup(); 955 } 956 amt -= j; 957 cp += j; 958 } while (amt > 0); 959 amt = RDIST_BUFSIZ; 960 if (i + amt > size) 961 amt = size - i; 962 if (wrerr == 0 && write(f, buf, amt) != amt) { 963 olderrno = errno; 964 wrerr++; 965 } 966 } 967 (void) close(f); 968 969 if (response() < 0) { 970 err(); 971 (void) unlink(new); 972 return; 973 } 974 if (wrerr) { 975 error("%s:%s: %s\n", host, new, strerror(olderrno)); 976 (void) unlink(new); 977 return; 978 } 979 if (opts & COMPARE) { 980 FILE *f1, *f2; 981 int c; 982 983 if ((f1 = fopen(target, "r")) == NULL) 984 goto badt; 985 if ((f2 = fopen(new, "r")) == NULL) { 986 badn: 987 error("%s:%s: %s\n", host, new, strerror(errno)); 988 (void) unlink(new); 989 return; 990 } 991 while ((c = getc(f1)) == getc(f2)) 992 if (c == EOF) { 993 (void) fclose(f1); 994 (void) fclose(f2); 995 (void) unlink(new); 996 ack(); 997 return; 998 } 999 (void) fclose(f1); 1000 (void) fclose(f2); 1001 if (opts & VERIFY) { 1002 differ: 1003 (void) unlink(new); 1004 sendrem("need to update: %s", target); 1005 return; 1006 } 1007 } 1008 1009 /* 1010 * Set last modified time. For type == S_IFDIR, the lstat above filled 1011 * in stb. Otherwise, do it now. 1012 */ 1013 if (type != S_IFDIR) 1014 (void) lstat(new, &stb); 1015 tvp[0].tv_sec = stb.st_atime; /* old atime from target */ 1016 tvp[0].tv_usec = 0; 1017 tvp[1].tv_sec = mtime; 1018 tvp[1].tv_usec = 0; 1019 if (utimes(new, tvp) < 0) { 1020 note("%s:utimes failed %s: %s", host, new, strerror(errno)); 1021 } 1022 if (chog(new, owner, group, mode) < 0) { 1023 (void) unlink(new); 1024 return; 1025 } 1026 fixup: 1027 if (rename(new, target) < 0) { 1028 badt: 1029 error("%s:%s: %s\n", host, target, strerror(errno)); 1030 (void) unlink(new); 1031 return; 1032 } 1033 if (opts & COMPARE) { 1034 sendrem("updated %s", target); 1035 } else 1036 ack(); 1037 } 1038 1039 /* 1040 * Creat a hard link to existing file. 1041 */ 1042 static void 1043 hardlink(cmd) 1044 char *cmd; 1045 { 1046 register char *cp; 1047 struct stat stb; 1048 char *oldname; 1049 int opts, exists = 0; 1050 char oldnamebuf[RDIST_BUFSIZ]; 1051 1052 cp = cmd; 1053 opts = 0; 1054 while (*cp >= '0' && *cp <= '7') 1055 opts = (opts << 3) | (*cp++ - '0'); 1056 if (*cp++ != ' ') { 1057 error("hardlink: options not delimited\n"); 1058 return; 1059 } 1060 oldname = cp; 1061 while (*cp && *cp != ' ') 1062 cp++; 1063 if (*cp != ' ') { 1064 error("hardlink: oldname name not delimited\n"); 1065 return; 1066 } 1067 *cp++ = '\0'; 1068 1069 if (catname) { 1070 if (sizeof (target) - (tp - target) >= strlen(cp) + 2) { 1071 (void) sprintf(tp, "/%s", cp); 1072 } else { 1073 error("%.*s/%s: Name too long\n", tp - target, 1074 target, cp); 1075 return; 1076 } 1077 } 1078 if (lstat(target, &stb) == 0) { 1079 int mode = stb.st_mode & S_IFMT; 1080 if (mode != S_IFREG && mode != S_IFLNK) { 1081 error("%s:%s: not a regular file\n", host, target); 1082 return; 1083 } 1084 exists = 1; 1085 } 1086 if (chkparent(target) < 0) { 1087 error("%s:%s: %s (no parent)\n", 1088 host, target, strerror(errno)); 1089 return; 1090 } 1091 if (opts & VERIFY) { 1092 struct stat nstb; 1093 1094 if (exists && lstat(oldname, &nstb) == 0 && 1095 nstb.st_mode == stb.st_mode && 1096 nstb.st_ino == stb.st_ino && 1097 nstb.st_dev == stb.st_dev) { 1098 ack(); 1099 return; 1100 } else { 1101 sendrem("need to update: %s", target); 1102 return; 1103 } 1104 } 1105 if (exists && (unlink(target) < 0)) { 1106 error("%s:%s: %s (unlink)\n", 1107 host, target, strerror(errno)); 1108 return; 1109 } 1110 if (*oldname == '~') 1111 oldname = exptilde(oldnamebuf, sizeof (oldnamebuf), oldname); 1112 if (link(oldname, target) < 0) { 1113 error("%s:can't link %s to %s\n", 1114 host, target, oldname); 1115 return; 1116 } 1117 ack(); 1118 } 1119 1120 /* 1121 * Check to see if parent directory exists and create one if not. 1122 */ 1123 int 1124 chkparent(name) 1125 char *name; 1126 { 1127 register char *cp; 1128 struct stat stb; 1129 1130 cp = rindex(name, '/'); 1131 if (cp == NULL || cp == name) 1132 return (0); 1133 *cp = '\0'; 1134 if (lstat(name, &stb) < 0) { 1135 if (errno == ENOENT && chkparent(name) >= 0 && 1136 mkdir(name, 0777 & ~oumask) >= 0) { 1137 *cp = '/'; 1138 return (0); 1139 } 1140 } else if (ISDIR(stb.st_mode)) { 1141 *cp = '/'; 1142 return (0); 1143 } 1144 *cp = '/'; 1145 return (-1); 1146 } 1147 1148 /* 1149 * Change owner, group and mode of file. 1150 */ 1151 int 1152 chog(file, owner, group, mode) 1153 char *file, *owner, *group; 1154 int mode; 1155 { 1156 register int i; 1157 uid_t uid, gid; 1158 extern char user[]; 1159 1160 /* 1161 * by default, set uid of file to the uid of the person running 1162 * this program. 1163 */ 1164 uid = getuid(); 1165 1166 /* 1167 * We'll use available privileges so we just try to do what 1168 * the client specifies. If the chown() fails we'll not 1169 * add the set-[ug]id bits; and if we want to add the set-[ug]id 1170 * bits and we're not permitted to do so, the OS will prevent us 1171 * from doing so. 1172 */ 1173 if (*owner == ':') { 1174 uid = atoi(owner + 1); 1175 } else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) { 1176 if ((pw = getpwnam(owner)) == NULL) { 1177 if (mode & 04000) { 1178 note("%s:%s: unknown login name, " 1179 "clearing setuid", host, owner); 1180 mode &= ~04000; 1181 } 1182 } else { 1183 uid = pw->pw_uid; 1184 } 1185 } else { 1186 uid = pw->pw_uid; 1187 } 1188 1189 if (*group == ':') { 1190 gid = atoi(group + 1); 1191 goto ok; 1192 } 1193 1194 gid = -1; 1195 if (gr == NULL || strcmp(group, gr->gr_name) != 0) { 1196 if ((*group == ':' && 1197 (getgrgid(gid = atoi(group + 1)) == NULL)) || 1198 ((gr = getgrnam(group)) == NULL)) { 1199 if (mode & 02000) { 1200 note("%s:%s: unknown group", host, group); 1201 mode &= ~02000; 1202 } 1203 } else 1204 gid = gr->gr_gid; 1205 } else 1206 gid = gr->gr_gid; 1207 ok: 1208 if (chown(file, uid, gid) < 0 || 1209 (mode & 07000) && chmod(file, mode) < 0) { 1210 note("%s: chown or chmod failed: file %s: %s", 1211 host, file, strerror(errno)); 1212 } 1213 return (0); 1214 } 1215 1216 /* 1217 * Check for files on the machine being updated that are not on the master 1218 * machine and remove them. 1219 */ 1220 static void 1221 rmchk(opts) 1222 int opts; 1223 { 1224 register char *cp, *s; 1225 struct stat stb; 1226 1227 if (debug) 1228 printf("rmchk()\n"); 1229 1230 /* 1231 * Tell the remote to clean the files from the last directory sent. 1232 */ 1233 (void) sprintf(buf, "C%o\n", opts & VERIFY); 1234 if (debug) 1235 printf("buf = %s", buf); 1236 (void) deswrite(rem, buf, strlen(buf), 0); 1237 if (response() < 0) 1238 return; 1239 for (;;) { 1240 cp = s = buf; 1241 do { 1242 if (desread(rem, cp, 1, 0) != 1) 1243 lostconn(); 1244 } while (*cp++ != '\n' && cp < &buf[RDIST_BUFSIZ]); 1245 1246 switch (*s++) { 1247 case 'Q': /* Query if file should be removed */ 1248 /* 1249 * Return the following codes to remove query. 1250 * N\n -- file exists - DON'T remove. 1251 * Y\n -- file doesn't exist - REMOVE. 1252 */ 1253 *--cp = '\0'; 1254 (void) sprintf(tp, "/%s", s); 1255 if (debug) 1256 printf("check %s\n", target); 1257 if (except(target)) 1258 (void) deswrite(rem, "N\n", 2, 0); 1259 else if (lstat(target, &stb) < 0) 1260 (void) deswrite(rem, "Y\n", 2, 0); 1261 else 1262 (void) deswrite(rem, "N\n", 2, 0); 1263 break; 1264 1265 case '\0': 1266 *--cp = '\0'; 1267 if (*s != '\0') 1268 log(lfp, "%s\n", s); 1269 break; 1270 1271 case 'E': 1272 *tp = '\0'; 1273 (void) deswrite(rem, "\0\n", 2, 0); 1274 return; 1275 1276 case '\1': 1277 case '\2': 1278 nerrs++; 1279 if (*s != '\n') { 1280 if (!iamremote) { 1281 fflush(stdout); 1282 (void) write(2, s, cp - s); 1283 } 1284 if (lfp != NULL) 1285 (void) fwrite(s, 1, cp - s, lfp); 1286 } 1287 if (buf[0] == '\2') 1288 lostconn(); 1289 break; 1290 1291 default: 1292 error("rmchk: unexpected response '%s'\n", buf); 1293 (void) deswrite(rem, "\1\n", 2, 0); 1294 } 1295 } 1296 } 1297 1298 /* 1299 * Check the current directory (initialized by the 'T' command to server()) 1300 * for extraneous files and remove them. 1301 */ 1302 static void 1303 clean(cp) 1304 register char *cp; 1305 { 1306 DIR *d; 1307 register struct dirent *dp; 1308 struct stat stb; 1309 char *otp; 1310 int len, opts; 1311 1312 opts = 0; 1313 while (*cp >= '0' && *cp <= '7') 1314 opts = (opts << 3) | (*cp++ - '0'); 1315 if (*cp != '\0') { 1316 error("clean: options not delimited\n"); 1317 return; 1318 } 1319 if ((d = opendir(target)) == NULL) { 1320 error("%s:%s: %s\n", host, target, strerror(errno)); 1321 return; 1322 } 1323 ack(); 1324 1325 otp = tp; 1326 len = tp - target; 1327 while (dp = readdir(d)) { 1328 if ((strcmp(dp->d_name, ".") == 0) || 1329 (strcmp(dp->d_name, "..") == 0)) 1330 continue; 1331 if ((int)(len + 1 + strlen(dp->d_name)) >= 1332 (int)(RDIST_BUFSIZ - 1)) { 1333 error("%s:%s/%s: Name too long\n", 1334 host, target, dp->d_name); 1335 continue; 1336 } 1337 tp = otp; 1338 *tp++ = '/'; 1339 cp = dp->d_name; 1340 while (*tp++ = *cp++) 1341 ; 1342 tp--; 1343 if (lstat(target, &stb) < 0) { 1344 error("%s:%s: %s\n", host, target, strerror(errno)); 1345 continue; 1346 } 1347 (void) snprintf(buf, sizeof (buf), "Q%s\n", dp->d_name); 1348 (void) write(wrem, buf, strlen(buf)); 1349 cp = buf; 1350 do { 1351 if (read(rem, cp, 1) != 1) 1352 cleanup(); 1353 } while (*cp++ != '\n' && cp < &buf[RDIST_BUFSIZ]); 1354 *--cp = '\0'; 1355 cp = buf; 1356 if (*cp != 'Y') 1357 continue; 1358 if (opts & VERIFY) { 1359 sendrem("need to remove: %s", target); 1360 } else 1361 (void) recursive_remove(&stb); 1362 } 1363 closedir(d); 1364 (void) write(wrem, "E\n", 2); 1365 (void) response(); 1366 tp = otp; 1367 *tp = '\0'; 1368 } 1369 1370 /* 1371 * Remove a file or directory (recursively) and send back an acknowledge 1372 * or an error message. 1373 */ 1374 static void 1375 recursive_remove(stp) 1376 struct stat *stp; 1377 { 1378 DIR *d; 1379 struct dirent *dp; 1380 register char *cp; 1381 struct stat stb; 1382 char *otp; 1383 int len; 1384 1385 switch (stp->st_mode & S_IFMT) { 1386 case S_IFREG: 1387 case S_IFLNK: 1388 if (unlink(target) < 0) 1389 goto bad; 1390 goto removed; 1391 1392 case S_IFDIR: 1393 break; 1394 1395 default: 1396 error("%s:%s: not a plain file\n", host, target); 1397 return; 1398 } 1399 1400 if ((d = opendir(target)) == NULL) 1401 goto bad; 1402 1403 otp = tp; 1404 len = tp - target; 1405 while (dp = readdir(d)) { 1406 if ((strcmp(dp->d_name, ".") == 0) || 1407 (strcmp(dp->d_name, "..") == 0)) 1408 continue; 1409 if ((int)(len + 1 + strlen(dp->d_name)) >= 1410 (int)(RDIST_BUFSIZ - 1)) { 1411 error("%s:%s/%s: Name too long\n", 1412 host, target, dp->d_name); 1413 continue; 1414 } 1415 tp = otp; 1416 *tp++ = '/'; 1417 cp = dp->d_name; 1418 while (*tp++ = *cp++) 1419 ; 1420 tp--; 1421 if (lstat(target, &stb) < 0) { 1422 error("%s:%s: %s\n", host, target, strerror(errno)); 1423 continue; 1424 } 1425 recursive_remove(&stb); 1426 } 1427 closedir(d); 1428 tp = otp; 1429 *tp = '\0'; 1430 if (rmdir(target) < 0) { 1431 bad: 1432 error("%s:%s: %s\n", host, target, strerror(errno)); 1433 return; 1434 } 1435 removed: 1436 sendrem("removed %s", target); 1437 } 1438 1439 /* 1440 * Execute a shell command to handle special cases. 1441 */ 1442 static void 1443 dospecial(cmd) 1444 char *cmd; 1445 { 1446 int fd[2], status, pid, i; 1447 register char *cp, *s; 1448 char sbuf[RDIST_BUFSIZ]; 1449 1450 if (pipe(fd) < 0) { 1451 error("%s\n", strerror(errno)); 1452 return; 1453 } 1454 if ((pid = fork()) == 0) { 1455 /* 1456 * Return everything the shell commands print. 1457 */ 1458 (void) close(0); 1459 (void) close(1); 1460 (void) close(2); 1461 (void) open("/dev/null", 0); 1462 (void) dup(fd[1]); 1463 (void) dup(fd[1]); 1464 (void) close(fd[0]); 1465 (void) close(fd[1]); 1466 execl("/bin/sh", "sh", "-c", cmd, 0); 1467 _exit(127); 1468 } 1469 (void) close(fd[1]); 1470 s = sbuf; 1471 *s++ = '\0'; 1472 while ((i = read(fd[0], buf, RDIST_BUFSIZ)) > 0) { 1473 cp = buf; 1474 do { 1475 *s++ = *cp++; 1476 if (cp[-1] != '\n') { 1477 if (s < &sbuf[RDIST_BUFSIZ - 1]) 1478 continue; 1479 *s++ = '\n'; 1480 } 1481 /* 1482 * Throw away blank lines. 1483 */ 1484 if (s == &sbuf[2]) { 1485 s--; 1486 continue; 1487 } 1488 (void) write(wrem, sbuf, s - sbuf); 1489 s = &sbuf[1]; 1490 } while (--i); 1491 } 1492 if (s > &sbuf[1]) { 1493 *s++ = '\n'; 1494 (void) write(wrem, sbuf, s - sbuf); 1495 } 1496 while ((i = wait(&status)) != pid && i != -1) 1497 ; 1498 if (i == -1) 1499 status = -1; 1500 (void) close(fd[0]); 1501 if (status) 1502 error("shell returned %d\n", status); 1503 else 1504 ack(); 1505 } 1506 1507 /*VARARGS2*/ 1508 void 1509 log(fp, fmt, a1, a2, a3) 1510 FILE *fp; 1511 char *fmt; 1512 int a1, a2, a3; 1513 { 1514 /* Print changes locally if not quiet mode */ 1515 if (!qflag) 1516 printf(fmt, a1, a2, a3); 1517 1518 /* Save changes (for mailing) if really updating files */ 1519 if (!(options & VERIFY) && fp != NULL) 1520 fprintf(fp, fmt, a1, a2, a3); 1521 } 1522 1523 /*VARARGS1*/ 1524 void 1525 error(fmt, a1, a2, a3) 1526 char *fmt; 1527 int a1, a2, a3; 1528 { 1529 static FILE *fp; 1530 1531 nerrs++; 1532 if (!fp && !(fp = fdopen(rem, "w"))) 1533 return; 1534 if (iamremote) { 1535 (void) fprintf(fp, "%crdist: ", 0x01); 1536 (void) fprintf(fp, fmt, a1, a2, a3); 1537 fflush(fp); 1538 } else { 1539 fflush(stdout); 1540 (void) fprintf(stderr, "rdist: "); 1541 (void) fprintf(stderr, fmt, a1, a2, a3); 1542 fflush(stderr); 1543 } 1544 if (lfp != NULL) { 1545 (void) fprintf(lfp, "rdist: "); 1546 (void) fprintf(lfp, fmt, a1, a2, a3); 1547 fflush(lfp); 1548 } 1549 } 1550 1551 /*VARARGS1*/ 1552 void 1553 fatal(fmt, a1, a2, a3) 1554 char *fmt; 1555 int a1, a2, a3; 1556 { 1557 static FILE *fp; 1558 1559 nerrs++; 1560 if (!fp && !(fp = fdopen(rem, "w"))) 1561 return; 1562 if (iamremote) { 1563 (void) fprintf(fp, "%crdist: ", 0x02); 1564 (void) fprintf(fp, fmt, a1, a2, a3); 1565 fflush(fp); 1566 } else { 1567 fflush(stdout); 1568 (void) fprintf(stderr, "rdist: "); 1569 (void) fprintf(stderr, fmt, a1, a2, a3); 1570 fflush(stderr); 1571 } 1572 if (lfp != NULL) { 1573 (void) fprintf(lfp, "rdist: "); 1574 (void) fprintf(lfp, fmt, a1, a2, a3); 1575 fflush(lfp); 1576 } 1577 cleanup(); 1578 } 1579 1580 int 1581 response() 1582 { 1583 char *cp, *s; 1584 char resp[RDIST_BUFSIZ]; 1585 1586 if (debug) 1587 printf("response()\n"); 1588 1589 cp = s = resp; 1590 more: 1591 do { 1592 if (desread(rem, cp, 1, 0) != 1) 1593 lostconn(); 1594 } while (*cp++ != '\n' && cp < &resp[RDIST_BUFSIZ]); 1595 1596 switch (*s++) { 1597 case '\0': 1598 *--cp = '\0'; 1599 if (*s != '\0') { 1600 log(lfp, "%s\n", s); 1601 return (1); 1602 } 1603 return (0); 1604 case '\3': 1605 *--cp = '\0'; 1606 log(lfp, "Note: %s\n", s); 1607 return (response()); 1608 1609 default: 1610 s--; 1611 /* fall into... */ 1612 case '\1': 1613 case '\2': 1614 nerrs++; 1615 if (*s != '\n') { 1616 if (!iamremote) { 1617 fflush(stdout); 1618 (void) write(2, s, cp - s); 1619 } 1620 if (lfp != NULL) 1621 (void) fwrite(s, 1, cp - s, lfp); 1622 } 1623 if (cp == &resp[RDIST_BUFSIZ] && *(cp - 1) != '\n') { 1624 /* preserve status code */ 1625 cp = s; 1626 s = resp; 1627 goto more; 1628 } 1629 if (resp[0] == '\2') 1630 lostconn(); 1631 return (-1); 1632 } 1633 } 1634 1635 /* 1636 * Remove temporary files and do any cleanup operations before exiting. 1637 */ 1638 void 1639 cleanup() 1640 { 1641 (void) unlink(Tmpfile); 1642 exit(1); 1643 } 1644 1645 static void 1646 note(fmt, a1, a2, a3) 1647 char *fmt; 1648 int a1, a2, a3; 1649 { 1650 static char buf[RDIST_BUFSIZ]; 1651 (void) snprintf(buf, sizeof (buf) - 1, fmt, a1, a2, a3); 1652 comment(buf); 1653 } 1654 1655 static void 1656 comment(s) 1657 char *s; 1658 { 1659 char three = '\3'; 1660 char nl = '\n'; 1661 struct iovec iov[3]; 1662 1663 iov[0].iov_base = &three; 1664 iov[0].iov_len = sizeof (char); 1665 iov[1].iov_base = s; 1666 iov[1].iov_len = strlen(s); 1667 iov[2].iov_base = &nl; 1668 iov[2].iov_len = sizeof (char); 1669 (void) writev(rem, iov, 3); 1670 } 1671 1672 /* 1673 * Send message to other end. 1674 * N.B.: uses buf[]. 1675 */ 1676 void 1677 sendrem(fmt, a1, a2, a3) 1678 char *fmt; 1679 int a1, a2, a3; 1680 { 1681 register int len; 1682 1683 buf[0] = '\0'; 1684 len = snprintf(buf + 1, sizeof (buf) - 1, fmt, a1, a2, a3) + 2; 1685 if (len > sizeof (buf)) 1686 len = sizeof (buf); 1687 buf[len - 1] = '\n'; 1688 (void) write(wrem, buf, len); 1689 } 1690 1691 /* 1692 * strsub(old, new, s) 1693 * 1694 * Return a pointer to a new string created by replacing substring old 1695 * with substring new in string s. String s is assumed to begin with 1696 * substring old. 1697 */ 1698 char * 1699 strsub(old, new, s) 1700 char *old, *new, *s; 1701 { 1702 static char pbuf[PATH_MAX]; 1703 register char *p, *q, *r, *plim; 1704 1705 /* prepend new to pbuf */ 1706 for (p = pbuf, q = new, plim = pbuf + sizeof (pbuf) - 1; 1707 /* CSTYLED */ 1708 *q && (p < plim);) 1709 *p++ = *q++; 1710 /* p now points to the byte in pbuf where more copying should begin */ 1711 1712 /* skip over the part of s which begins with old */ 1713 for (r = old, q = s; *r; q++, r++) 1714 ; 1715 /* q now points to the byte in s where more copying should begin */ 1716 1717 while (*q && (p < plim)) 1718 *p++ = *q++; 1719 *p = '\0'; 1720 1721 return (pbuf); 1722 } 1723