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