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