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