1 /* $NetBSD: server.c,v 1.33 2019/02/03 03:19:29 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. 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.33 2019/02/03 03:19:29 mrg 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 /* FALLTHROUGH */ 235 case '\0': 236 continue; 237 } 238 } 239 } 240 241 /* 242 * Update the file(s) if they are different. 243 * destdir = 1 if destination should be a directory 244 * (i.e., more than one source is being copied to the same destination). 245 */ 246 void 247 install(char *src, char *dest, int destdir, int 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 } else if (!(opts & WHOLE)) { 256 /* prepare for proper renaming of directory trees */ 257 Destcopy = destcopy; 258 Destcopylen = strlen(dest); 259 while (Destcopylen > 0 && dest[Destcopylen] == '/') 260 Destcopylen--; 261 } 262 strlcpy(destcopy, dest, sizeof(destcopy)); 263 264 if (nflag || debug) { 265 printf("%s%s%s%s%s %s %s\n", opts & VERIFY ? "verify":"install", 266 opts & WHOLE ? " -w" : "", 267 opts & YOUNGER ? " -y" : "", 268 opts & COMPARE ? " -b" : "", 269 opts & REMOVE ? " -R" : "", src, dest); 270 if (nflag) 271 return; 272 } 273 274 rname = exptilde(target, src); 275 if (rname == NULL) 276 return; 277 tp = target; 278 while (*tp) 279 tp++; 280 if (Destcopy) { 281 /* We can only do this after expansion of src */ 282 Sourcelen = strlen(target); 283 while (Sourcelen > 0 && target[Sourcelen] == '/') 284 Sourcelen--; 285 } 286 /* 287 * If we are renaming a directory and we want to preserve 288 * the directory hierarchy (-w), we must strip off the leading 289 * directory name and preserve the rest. 290 */ 291 if (opts & WHOLE) { 292 while (*rname == '/') 293 rname++; 294 destdir = 1; 295 } else { 296 rname = strrchr(target, '/'); 297 if (rname == NULL) 298 rname = target; 299 else 300 rname++; 301 } 302 if (debug) 303 printf("target = %s, rname = %s\n", target, rname); 304 /* 305 * Pass the destination file/directory name to remote. 306 */ 307 (void) snprintf(buf, sizeof(buf), "%c%s\n", destdir ? 'T' : 't', dest); 308 if (debug) 309 printf("buf = %s", buf); 310 if (write(rem, buf, strlen(buf)) < 0) 311 error("could not pass filename to remote: %s\n", 312 strerror(errno)); 313 if (response() < 0) 314 return; 315 316 if (destdir) 317 Tdest = destcopy; 318 sendf(rname, opts); 319 Destcopy = 0; 320 Tdest = 0; 321 } 322 323 #define protoname() (pw ? pw->pw_name : user) 324 #define protogroup() (gr ? gr->gr_name : group) 325 /* 326 * Transfer the file or directory in target[]. 327 * rname is the name of the file on the remote host. 328 */ 329 static void 330 sendf(char *rname, int opts) 331 { 332 struct subcmd *sc; 333 struct stat stb; 334 int sizerr, f, u, len; 335 off_t i; 336 DIR *d; 337 struct dirent *dp; 338 char *otp, *cp; 339 extern struct subcmd *subcmds; 340 static char user[15], group[15]; 341 342 if (debug) 343 printf("sendf(%s, %x)\n", rname, opts); 344 345 if (except(target)) 346 return; 347 if ((opts & FOLLOW ? stat(target, &stb) : lstat(target, &stb)) < 0) { 348 error("%s: %s\n", target, strerror(errno)); 349 return; 350 } 351 if ((u = update(rname, opts, &stb)) == 0) { 352 if (S_ISREG(stb.st_mode) && stb.st_nlink > 1) 353 (void) savelink(&stb); 354 return; 355 } 356 357 if (pw == NULL || pw->pw_uid != stb.st_uid) 358 if ((pw = getpwuid(stb.st_uid)) == NULL) { 359 dolog(lfp, "%s: no password entry for uid %d \n", 360 target, stb.st_uid); 361 pw = NULL; 362 (void)snprintf(user, sizeof(user), ":%lu", 363 (u_long)stb.st_uid); 364 } 365 if (gr == NULL || gr->gr_gid != stb.st_gid) 366 if ((gr = getgrgid(stb.st_gid)) == NULL) { 367 dolog(lfp, "%s: no name for group %d\n", 368 target, stb.st_gid); 369 gr = NULL; 370 (void)snprintf(group, sizeof(group), ":%lu", 371 (u_long)stb.st_gid); 372 } 373 if (u == 1) { 374 if (opts & VERIFY) { 375 dolog(lfp, "need to install: %s\n", target); 376 goto dospecial; 377 } 378 dolog(lfp, "installing: %s\n", target); 379 opts &= ~(COMPARE|REMOVE); 380 } 381 382 switch (stb.st_mode & S_IFMT) { 383 case S_IFDIR: 384 if ((d = opendir(target)) == NULL) { 385 error("%s: %s\n", target, strerror(errno)); 386 return; 387 } 388 (void) snprintf(buf, sizeof(buf), "D%o %04o 0 0 %s %s %s\n", 389 opts, stb.st_mode & 07777, protoname(), protogroup(), 390 rname); 391 if (debug) 392 printf("buf = %s", buf); 393 if (write(rem, buf, strlen(buf)) < 0) 394 error("can not write dir spec to remote: %s\n", 395 strerror(errno)); 396 397 if (response() < 0) { 398 closedir(d); 399 return; 400 } 401 402 if (opts & REMOVE) 403 rmchk(opts); 404 405 otp = tp; 406 len = tp - target; 407 while ((dp = readdir(d)) != NULL) { 408 if (!strcmp(dp->d_name, ".") || 409 !strcmp(dp->d_name, "..")) 410 continue; 411 if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 412 error("%s/%s: Name too long\n", target, 413 dp->d_name); 414 continue; 415 } 416 tp = otp; 417 *tp++ = '/'; 418 cp = dp->d_name; 419 while ((*tp++ = *cp++) != 0) 420 ; 421 tp--; 422 sendf(dp->d_name, opts); 423 } 424 closedir(d); 425 if (write(rem, "E\n", 2) < 0) 426 error("can not write E to remote: %s\n", 427 strerror(errno)); 428 (void) response(); 429 tp = otp; 430 *tp = '\0'; 431 return; 432 433 case S_IFLNK: 434 if (u != 1) 435 opts |= COMPARE; 436 if (stb.st_nlink > 1) { 437 struct linkbuf *lp; 438 439 if ((lp = savelink(&stb)) != NULL) { 440 /* install link */ 441 if (*lp->target == 0) 442 (void) snprintf(buf, sizeof(buf), 443 "k%o %s %s\n", opts, lp->pathname, rname); 444 else 445 (void) snprintf(buf, sizeof(buf), 446 "k%o %s/%s %s\n", opts, lp->target, 447 lp->pathname, rname); 448 if (debug) 449 printf("buf = %s", buf); 450 if (write(rem, buf, strlen(buf)) < 0) 451 error("can not write link spec to remote: %s\n", 452 strerror(errno)); 453 (void) response(); 454 return; 455 } 456 } 457 (void) snprintf(buf, sizeof(buf), "K%o %o %lld %ld %s %s %s\n", 458 opts, stb.st_mode & 07777, (unsigned long long)stb.st_size, 459 (u_long)stb.st_mtime, protoname(), protogroup(), rname); 460 if (debug) 461 printf("buf = %s", buf); 462 if (write(rem, buf, strlen(buf)) < 0) 463 error("can not write link spec to remote: %s\n", 464 strerror(errno)); 465 if (response() < 0) 466 return; 467 sizerr = (readlink(target, buf, BUFSIZ) != stb.st_size); 468 if (write(rem, buf, stb.st_size) < 0) 469 error("can not write link name to remote: %s\n", 470 strerror(errno)); 471 if (debug) 472 printf("readlink = %.*s\n", (int)stb.st_size, buf); 473 goto done; 474 475 case S_IFREG: 476 break; 477 478 default: 479 error("%s: not a file or directory\n", target); 480 return; 481 } 482 483 if (u == 2) { 484 if (opts & VERIFY) { 485 dolog(lfp, "need to update: %s\n", target); 486 goto dospecial; 487 } 488 dolog(lfp, "updating: %s\n", target); 489 } 490 491 if (stb.st_nlink > 1) { 492 struct linkbuf *lp; 493 494 if ((lp = savelink(&stb)) != NULL) { 495 /* install link */ 496 if (*lp->target == 0) 497 (void) snprintf(buf, sizeof(buf), "k%o %s %s\n", opts, 498 lp->pathname, rname); 499 else 500 (void) snprintf(buf, sizeof(buf), "k%o %s/%s %s\n", 501 opts, lp->target, lp->pathname, rname); 502 if (debug) 503 printf("buf = %s", buf); 504 if (write(rem, buf, strlen(buf)) <0) 505 error("write of file name failed: %s\n", 506 strerror(errno)); 507 (void) response(); 508 return; 509 } 510 } 511 512 if ((f = open(target, O_RDONLY, 0)) < 0) { 513 error("%s: %s\n", target, strerror(errno)); 514 return; 515 } 516 (void)snprintf(buf, sizeof(buf), "R%o %o %lld %lu %s %s %s\n", opts, 517 stb.st_mode & 07777, (unsigned long long)stb.st_size, 518 (u_long)stb.st_mtime, protoname(), protogroup(), rname); 519 if (debug) 520 printf("buf = %s", buf); 521 if (write(rem, buf, strlen(buf)) < 0) 522 error("write of file name failed: %s\n", strerror(errno)); 523 if (response() < 0) { 524 (void) close(f); 525 return; 526 } 527 sizerr = 0; 528 for (i = 0; i < stb.st_size; i += BUFSIZ) { 529 int amt = BUFSIZ; 530 if (i + amt > stb.st_size) 531 amt = stb.st_size - i; 532 if (sizerr == 0 && read(f, buf, amt) != amt) 533 sizerr = 1; 534 if (write(rem, buf, amt) < 0) 535 error("write of file data failed: %s\n", strerror(errno)); 536 } 537 (void) close(f); 538 done: 539 if (sizerr) { 540 error("%s: file changed size\n", target); 541 err(); 542 } else 543 ack(); 544 f = response(); 545 if (f < 0 || (f == 0 && (opts & COMPARE))) 546 return; 547 dospecial: 548 for (sc = subcmds; sc != NULL; sc = sc->sc_next) { 549 if (sc->sc_type != SPECIAL) 550 continue; 551 if (sc->sc_args != NULL && !inlist(sc->sc_args, target)) 552 continue; 553 dolog(lfp, "special \"%s\"\n", sc->sc_name); 554 if (opts & VERIFY) 555 continue; 556 (void) snprintf(buf, sizeof(buf), "SFILE=%s;%s\n", target, 557 sc->sc_name); 558 if (debug) 559 printf("buf = %s", buf); 560 if (write(rem, buf, strlen(buf)) < 0) 561 error("write of special failed: %s\n", strerror(errno)); 562 while (response() > 0) 563 ; 564 } 565 } 566 567 static struct linkbuf * 568 savelink(struct stat *st) 569 { 570 struct linkbuf *lp; 571 572 for (lp = ihead; lp != NULL; lp = lp->nextp) 573 if (lp->inum == st->st_ino && lp->devnum == st->st_dev) { 574 lp->count--; 575 return(lp); 576 } 577 lp = (struct linkbuf *) malloc(sizeof(*lp)); 578 if (lp == NULL) 579 dolog(lfp, "out of memory, link information lost\n"); 580 else { 581 lp->nextp = ihead; 582 ihead = lp; 583 lp->inum = st->st_ino; 584 lp->devnum = st->st_dev; 585 lp->count = st->st_nlink - 1; 586 if (Destcopy) { 587 /* 588 * Change the starting directory of target 589 * into the destination directory 590 */ 591 strncpy(lp->pathname, Destcopy, Destcopylen); 592 strlcpy(lp->pathname + Destcopylen, target + Sourcelen, sizeof(lp->pathname) - Destcopylen); 593 } else 594 strlcpy(lp->pathname, target, sizeof(lp->pathname)); 595 if (Tdest) 596 strlcpy(lp->target, Tdest, sizeof(lp->target)); 597 else 598 *lp->target = 0; 599 } 600 return(NULL); 601 } 602 603 /* 604 * Check to see if file needs to be updated on the remote machine. 605 * Returns 0 if no update, 1 if remote doesn't exist, 2 if out of date 606 * and 3 if comparing binaries to determine if out of date. 607 */ 608 static int 609 update(char *rname, int opts, struct stat *st) 610 { 611 char *cp, *s; 612 off_t size; 613 time_t mtime; 614 615 if (debug) 616 printf("update(%s, %lx, %lx)\n", rname, (long)opts, (long)st); 617 618 /* 619 * Check to see if the file exists on the remote machine. 620 */ 621 (void) snprintf(buf, sizeof(buf), "Q%s\n", rname); 622 if (debug) 623 printf("buf = %s", buf); 624 if (write(rem, buf, strlen(buf)) < 0) 625 error("write to remote failed: %s\n", strerror(errno)); 626 again: 627 cp = s = buf; 628 do { 629 if (read(rem, cp, 1) != 1) 630 lostconn(0); 631 } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); 632 633 switch (*s++) { 634 case 'Y': 635 break; 636 637 case 'N': /* file doesn't exist so install it */ 638 return(1); 639 640 case '\1': 641 nerrs++; 642 if (*s != '\n') { 643 if (!iamremote) { 644 fflush(stdout); 645 (void) write(2, s, cp - s); 646 } 647 if (lfp != NULL) 648 (void) fwrite(s, 1, cp - s, lfp); 649 } 650 return(0); 651 652 case '\3': 653 *--cp = '\0'; 654 if (lfp != NULL) 655 dolog(lfp, "update: note: %s\n", s); 656 goto again; 657 658 default: 659 *--cp = '\0'; 660 error("update: unexpected response '%s'\n", s); 661 return(0); 662 } 663 664 if (*s == '\n') 665 return(2); 666 667 if (opts & COMPARE) 668 return(3); 669 670 size = 0; 671 while (isdigit((unsigned char)*s)) 672 size = size * 10 + (*s++ - '0'); 673 if (*s++ != ' ') { 674 error("update: size not delimited\n"); 675 return(0); 676 } 677 mtime = 0; 678 while (isdigit((unsigned char)*s)) 679 mtime = mtime * 10 + (*s++ - '0'); 680 if (*s != '\n') { 681 error("update: mtime not delimited\n"); 682 return(0); 683 } 684 /* 685 * File needs to be updated? 686 */ 687 if (opts & YOUNGER) { 688 if (st->st_mtime == mtime) 689 return(0); 690 if (st->st_mtime < mtime) { 691 dolog(lfp, "Warning: %s: remote copy is newer\n", 692 target); 693 return(0); 694 } 695 } else if (st->st_mtime == mtime && st->st_size == size) 696 return(0); 697 return(2); 698 } 699 700 /* 701 * Query. Check to see if file exists. Return one of the following: 702 * N\n - doesn't exist 703 * Ysize mtime\n - exists and its a regular file (size & mtime of file) 704 * Y\n - exists and its a directory or symbolic link 705 * ^Aerror message\n 706 */ 707 static void 708 query(char *name) 709 { 710 struct stat stb; 711 712 if (catname) 713 (void) snprintf(tp, sizeof(target) - (tp - target), 714 "/%s", name); 715 716 if (lstat(target, &stb) < 0) { 717 if (errno == ENOENT) { 718 if (write(rem, "N\n", 2) < 0) 719 error("write to remote failed: %s\n", 720 strerror(errno)); 721 } else 722 error("%s:%s: %s\n", host, target, strerror(errno)); 723 *tp = '\0'; 724 return; 725 } 726 727 switch (stb.st_mode & S_IFMT) { 728 case S_IFREG: 729 (void)snprintf(buf, sizeof(buf), "Y%lld %ld\n", 730 (unsigned long long)stb.st_size, (u_long)stb.st_mtime); 731 if (write(rem, buf, strlen(buf)) < 0) 732 error("write to remote failed: %s\n", strerror(errno)); 733 break; 734 735 case S_IFLNK: 736 case S_IFDIR: 737 if (write(rem, "Y\n", 2) < 0) 738 error("write to remote failed: %s\n", strerror(errno)); 739 break; 740 741 default: 742 error("%s: not a file or directory\n", name); 743 break; 744 } 745 *tp = '\0'; 746 } 747 748 static void 749 recvf(char *cmd, int type) 750 { 751 char *cp = cmd; 752 int f = -1, opts = 0, wrerr; 753 mode_t mode; 754 off_t i, size; 755 time_t mtime; 756 struct stat stb; 757 char *owner, *group; 758 char new[BUFSIZ]; 759 extern char *tempname; 760 761 while (*cp >= '0' && *cp <= '7') 762 opts = (opts << 3) | (*cp++ - '0'); 763 if (*cp++ != ' ') { 764 error("recvf: options not delimited\n"); 765 return; 766 } 767 mode = 0; 768 while (*cp >= '0' && *cp <= '7') 769 mode = (mode << 3) | (*cp++ - '0'); 770 if (*cp++ != ' ') { 771 error("recvf: mode not delimited\n"); 772 return; 773 } 774 size = 0; 775 while (isdigit((unsigned char)*cp)) 776 size = size * 10 + (*cp++ - '0'); 777 if (*cp++ != ' ') { 778 error("recvf: size not delimited\n"); 779 return; 780 } 781 mtime = 0; 782 while (isdigit((unsigned char)*cp)) 783 mtime = mtime * 10 + (*cp++ - '0'); 784 if (*cp++ != ' ') { 785 error("recvf: mtime not delimited\n"); 786 return; 787 } 788 owner = cp; 789 while (*cp && *cp != ' ') 790 cp++; 791 if (*cp != ' ') { 792 error("recvf: owner name not delimited\n"); 793 return; 794 } 795 *cp++ = '\0'; 796 group = cp; 797 while (*cp && *cp != ' ') 798 cp++; 799 if (*cp != ' ') { 800 error("recvf: group name not delimited\n"); 801 return; 802 } 803 *cp++ = '\0'; 804 805 if (type == S_IFDIR) { 806 if (catname >= (int)sizeof(stp)) { 807 error("%s:%s: too many directory levels\n", 808 host, target); 809 return; 810 } 811 stp[catname] = tp; 812 if (catname++) { 813 *tp++ = '/'; 814 while ((*tp++ = *cp++) != 0) 815 ; 816 tp--; 817 } 818 if (opts & VERIFY) { 819 ack(); 820 return; 821 } 822 if (lstat(target, &stb) == 0) { 823 if (S_ISDIR(stb.st_mode)) { 824 if ((stb.st_mode & 07777) == mode) { 825 ack(); 826 return; 827 } 828 buf[0] = '\0'; 829 (void) snprintf(buf + 1, sizeof(buf) - 1, 830 "%s: Warning: remote mode %o != local mode %o\n", 831 target, stb.st_mode & 07777, mode); 832 if (write(rem, buf, strlen(buf + 1) + 1) < 0) 833 error("write to remote failed: %s\n", 834 strerror(errno)); 835 return; 836 } 837 errno = ENOTDIR; 838 } else if ((errno == ENOENT && mkdir(target, mode) == 0) || 839 (chkparent(target) == 0 && mkdir(target, mode) == 0)) { 840 if (fchtogm(-1, target, mtime, owner, group, mode) == 0) 841 ack(); 842 return; 843 } 844 error("%s:%s: %s\n", host, target, strerror(errno)); 845 tp = stp[--catname]; 846 *tp = '\0'; 847 return; 848 } 849 850 if (catname) 851 (void) snprintf(tp, sizeof(target) - (tp - target), "/%s", cp); 852 cp = strrchr(target, '/'); 853 if (cp == NULL) 854 strlcpy(new, tempname, sizeof(new)); 855 else if (cp == target) 856 (void) snprintf(new, sizeof(new), "/%s", tempname); 857 else { 858 *cp = '\0'; 859 (void) snprintf(new, sizeof(new), "%s/%s", target, tempname); 860 *cp = '/'; 861 } 862 863 if (type == S_IFLNK) { 864 int j; 865 866 ack(); 867 cp = buf; 868 for (i = 0; i < size; i += j) { 869 if ((j = read(rem, cp, size - i)) <= 0) 870 cleanup(0); 871 cp += j; 872 } 873 *cp = '\0'; 874 if (response() < 0) { 875 err(); 876 return; 877 } 878 if (symlink(buf, new) < 0) { 879 if (errno != ENOENT || chkparent(new) < 0 || 880 symlink(buf, new) < 0) 881 goto badnew1; 882 } 883 mode &= 0777; 884 if (opts & COMPARE) { 885 char tbuf[BUFSIZ]; 886 887 if ((i = readlink(target, tbuf, BUFSIZ)) >= 0 && 888 i == size && strncmp(buf, tbuf, size) == 0) { 889 (void) unlink(new); 890 ack(); 891 return; 892 } 893 if (opts & VERIFY) 894 goto differ; 895 } 896 goto fixup; 897 } 898 899 if ((f = creat(new, mode)) < 0) { 900 if (errno != ENOENT || chkparent(new) < 0 || 901 (f = creat(new, mode)) < 0) 902 goto badnew1; 903 } 904 905 ack(); 906 wrerr = 0; 907 for (i = 0; i < size; i += BUFSIZ) { 908 int amt = BUFSIZ; 909 910 cp = buf; 911 if (i + amt > size) 912 amt = size - i; 913 do { 914 int j = read(rem, cp, amt); 915 916 if (j <= 0) { 917 (void) close(f); 918 (void) unlink(new); 919 cleanup(0); 920 } 921 amt -= j; 922 cp += j; 923 } while (amt > 0); 924 amt = BUFSIZ; 925 if (i + amt > size) 926 amt = size - i; 927 if (wrerr == 0 && write(f, buf, amt) != amt) { 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 /* FALLTHROUGH */ 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