1 /* $NetBSD: server.c,v 1.32 2013/10/18 20:41:49 christos 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.32 2013/10/18 20:41:49 christos 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; 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 wrerr++; 928 } 929 } 930 if (response() < 0) { 931 err(); 932 goto badnew2; 933 } 934 if (wrerr) 935 goto badnew1; 936 if (opts & COMPARE) { 937 FILE *f1, *f2; 938 int c; 939 940 if ((f1 = fopen(target, "r")) == NULL) 941 goto badtarget; 942 if ((f2 = fopen(new, "r")) == NULL) { 943 badnew1: error("%s:%s: %s\n", host, new, strerror(errno)); 944 goto badnew2; 945 } 946 while ((c = getc(f1)) == getc(f2)) 947 if (c == EOF) { 948 (void) fclose(f1); 949 (void) fclose(f2); 950 ack(); 951 goto badnew2; 952 } 953 (void) fclose(f1); 954 (void) fclose(f2); 955 if (opts & VERIFY) { 956 differ: buf[0] = '\0'; 957 (void)snprintf(buf + 1, sizeof(buf) - 1, 958 "need to update: %s\n",target); 959 (void) write(rem, buf, strlen(buf + 1) + 1); 960 goto badnew2; 961 } 962 } 963 964 if (fchtogm(f, new, mtime, owner, group, mode) < 0) { 965 badnew2: 966 if (f != -1) 967 (void) close(f); 968 (void) unlink(new); 969 return; 970 } 971 (void) close(f); 972 973 fixup: if (rename(new, target) < 0) { 974 badtarget: error("%s:%s: %s\n", host, target, strerror(errno)); 975 (void) unlink(new); 976 return; 977 } 978 979 if (opts & COMPARE) { 980 buf[0] = '\0'; 981 (void) snprintf(buf + 1, sizeof(buf) - 1, 982 "updated %s\n", target); 983 (void) write(rem, buf, strlen(buf + 1) + 1); 984 } else 985 ack(); 986 } 987 988 /* 989 * Creat a hard link to existing file. 990 */ 991 static void 992 hardlink(char *cmd) 993 { 994 char *cp; 995 struct stat stb; 996 char *oldname; 997 int opts, exists = 0; 998 999 cp = cmd; 1000 opts = 0; 1001 while (*cp >= '0' && *cp <= '7') 1002 opts = (opts << 3) | (*cp++ - '0'); 1003 if (*cp++ != ' ') { 1004 error("hardlink: options not delimited\n"); 1005 return; 1006 } 1007 oldname = cp; 1008 while (*cp && *cp != ' ') 1009 cp++; 1010 if (*cp != ' ') { 1011 error("hardlink: oldname name not delimited\n"); 1012 return; 1013 } 1014 *cp++ = '\0'; 1015 1016 if (catname) { 1017 (void) snprintf(tp, sizeof(target) - (tp - target), "/%s", cp); 1018 } 1019 if (lstat(target, &stb) == 0) { 1020 if (!S_ISREG(stb.st_mode) && !S_ISLNK(stb.st_mode)) { 1021 error("%s: %s: not a regular file\n", host, target); 1022 return; 1023 } 1024 exists = 1; 1025 } 1026 if (chkparent(target) < 0 ) { 1027 error("%s:%s: %s (no parent)\n", 1028 host, target, strerror(errno)); 1029 return; 1030 } 1031 if (exists && (unlink(target) < 0)) { 1032 error("%s:%s: %s (unlink)\n", 1033 host, target, strerror(errno)); 1034 return; 1035 } 1036 if (link(oldname, target) < 0) { 1037 error("%s:can't link %s to %s\n", 1038 host, target, oldname); 1039 return; 1040 } 1041 ack(); 1042 } 1043 1044 /* 1045 * Check to see if parent directory exists and create one if not. 1046 */ 1047 static int 1048 chkparent(char *name) 1049 { 1050 char *cp; 1051 struct stat stb; 1052 1053 cp = strrchr(name, '/'); 1054 if (cp == NULL || cp == name) 1055 return(0); 1056 *cp = '\0'; 1057 if (lstat(name, &stb) < 0) { 1058 if (errno == ENOENT && chkparent(name) >= 0 && 1059 mkdir(name, 0777 & ~oumask) >= 0) { 1060 *cp = '/'; 1061 return(0); 1062 } 1063 } else if (S_ISDIR(stb.st_mode)) { 1064 *cp = '/'; 1065 return(0); 1066 } 1067 *cp = '/'; 1068 return(-1); 1069 } 1070 1071 /* 1072 * Change owner, group and mode of file. 1073 */ 1074 static int 1075 fchtogm(int fd, char *file, time_t mtime, char *owner, char *group, __mode_t mode) 1076 { 1077 int i; 1078 struct timeval tv[2]; 1079 uid_t uid; 1080 gid_t gid; 1081 extern char user[]; 1082 1083 uid = userid; 1084 if (userid == 0) { 1085 if (*owner == ':') { 1086 uid = atoi(owner + 1); 1087 } else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) { 1088 if ((pw = getpwnam(owner)) == NULL) { 1089 if (mode & 04000) { 1090 note("%s:%s: unknown login name, clearing setuid", 1091 host, owner); 1092 mode &= ~04000; 1093 uid = 0; 1094 } 1095 } else 1096 uid = pw->pw_uid; 1097 } else 1098 uid = pw->pw_uid; 1099 if (*group == ':') { 1100 gid = atoi(group + 1); 1101 goto ok; 1102 } 1103 } else if ((mode & 04000) && strcmp(user, owner) != 0) 1104 mode &= ~04000; 1105 gid = -1; 1106 if (gr == NULL || strcmp(group, gr->gr_name) != 0) { 1107 if ((*group == ':' && (getgrgid(gid = atoi(group + 1)) == NULL)) 1108 || ((gr = getgrnam(group)) == NULL)) { 1109 if (mode & 02000) { 1110 note("%s:%s: unknown group", host, group); 1111 mode &= ~02000; 1112 } 1113 } else 1114 gid = gr->gr_gid; 1115 } else 1116 gid = gr->gr_gid; 1117 if (userid && gid != (gid_t)-1) { 1118 if (gr) for (i = 0; gr->gr_mem[i] != NULL; i++) 1119 if (!(strcmp(user, gr->gr_mem[i]))) 1120 goto ok; 1121 mode &= ~02000; 1122 gid = -1; 1123 } 1124 ok: 1125 (void) gettimeofday(&tv[0], (struct timezone *)0); 1126 tv[1].tv_sec = mtime; 1127 tv[1].tv_usec = 0; 1128 if (fd != -1 ? futimes(fd, tv) < 0 : utimes(file, tv) < 0) 1129 note("%s: %s utimes: %s", host, file, strerror(errno)); 1130 if (fd != -1 ? fchown(fd, uid, gid) < 0 : chown(file, uid, gid) < 0) 1131 note("%s: %s chown: %s", host, file, strerror(errno)); 1132 else if (mode & 07000 && 1133 (fd != -1 ? fchmod(fd, mode) < 0 : chmod(file, mode) < 0)) 1134 note("%s: %s chmod: %s", host, file, strerror(errno)); 1135 return(0); 1136 } 1137 1138 /* 1139 * Check for files on the machine being updated that are not on the master 1140 * machine and remove them. 1141 */ 1142 static void 1143 rmchk(int opts) 1144 { 1145 char *cp, *s; 1146 struct stat stb; 1147 1148 if (debug) 1149 printf("rmchk()\n"); 1150 1151 /* 1152 * Tell the remote to clean the files from the last directory sent. 1153 */ 1154 (void) snprintf(buf, sizeof(buf), "C%o\n", opts & VERIFY); 1155 if (debug) 1156 printf("buf = %s", buf); 1157 (void) write(rem, buf, strlen(buf)); 1158 if (response() < 0) 1159 return; 1160 for (;;) { 1161 cp = s = buf; 1162 do { 1163 if (read(rem, cp, 1) != 1) 1164 lostconn(0); 1165 } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); 1166 1167 switch (*s++) { 1168 case 'Q': /* Query if file should be removed */ 1169 /* 1170 * Return the following codes to remove query. 1171 * N\n -- file exists - DON'T remove. 1172 * Y\n -- file doesn't exist - REMOVE. 1173 */ 1174 *--cp = '\0'; 1175 (void) snprintf(tp, sizeof(target) - (tp - target), 1176 "/%s", s); 1177 if (debug) 1178 printf("check %s\n", target); 1179 if (except(target)) 1180 (void) write(rem, "N\n", 2); 1181 else if (lstat(target, &stb) < 0) 1182 (void) write(rem, "Y\n", 2); 1183 else 1184 (void) write(rem, "N\n", 2); 1185 break; 1186 1187 case '\0': 1188 *--cp = '\0'; 1189 if (*s != '\0') 1190 dolog(lfp, "%s\n", s); 1191 break; 1192 1193 case 'E': 1194 *tp = '\0'; 1195 ack(); 1196 return; 1197 1198 case '\1': 1199 case '\2': 1200 nerrs++; 1201 if (*s != '\n') { 1202 if (!iamremote) { 1203 fflush(stdout); 1204 (void) write(2, s, cp - s); 1205 } 1206 if (lfp != NULL) 1207 (void) fwrite(s, 1, cp - s, lfp); 1208 } 1209 if (buf[0] == '\2') 1210 lostconn(0); 1211 break; 1212 1213 default: 1214 error("rmchk: unexpected response '%s'\n", buf); 1215 err(); 1216 } 1217 } 1218 } 1219 1220 /* 1221 * Check the current directory (initialized by the 'T' command to server()) 1222 * for extraneous files and remove them. 1223 */ 1224 static void 1225 clean(char *cp) 1226 { 1227 DIR *d; 1228 struct dirent *dp; 1229 struct stat stb; 1230 char *otp; 1231 int len, opts; 1232 1233 opts = 0; 1234 while (*cp >= '0' && *cp <= '7') 1235 opts = (opts << 3) | (*cp++ - '0'); 1236 if (*cp != '\0') { 1237 error("clean: options not delimited\n"); 1238 return; 1239 } 1240 if ((d = opendir(target)) == NULL) { 1241 error("%s:%s: %s\n", host, target, strerror(errno)); 1242 return; 1243 } 1244 ack(); 1245 1246 otp = tp; 1247 len = tp - target; 1248 while ((dp = readdir(d)) != NULL) { 1249 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 1250 continue; 1251 if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 1252 error("%s:%s/%s: Name too long\n", 1253 host, target, dp->d_name); 1254 continue; 1255 } 1256 tp = otp; 1257 *tp++ = '/'; 1258 cp = dp->d_name; 1259 while ((*tp++ = *cp++) != 0) 1260 ; 1261 tp--; 1262 if (lstat(target, &stb) < 0) { 1263 error("%s:%s: %s\n", host, target, strerror(errno)); 1264 continue; 1265 } 1266 (void) snprintf(buf, sizeof(buf), "Q%s\n", dp->d_name); 1267 (void) write(rem, buf, strlen(buf)); 1268 cp = buf; 1269 do { 1270 if (read(rem, cp, 1) != 1) 1271 cleanup(0); 1272 } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); 1273 *--cp = '\0'; 1274 cp = buf; 1275 if (*cp != 'Y') 1276 continue; 1277 if (opts & VERIFY) { 1278 cp = buf; 1279 *cp++ = '\0'; 1280 (void) snprintf(cp, sizeof(buf) - 1, 1281 "need to remove: %s\n", target); 1282 (void) write(rem, buf, strlen(cp) + 1); 1283 } else 1284 removeit(&stb); 1285 } 1286 closedir(d); 1287 (void) write(rem, "E\n", 2); 1288 (void) response(); 1289 tp = otp; 1290 *tp = '\0'; 1291 } 1292 1293 /* 1294 * Remove a file or directory (recursively) and send back an acknowledge 1295 * or an error message. 1296 */ 1297 static void 1298 removeit(struct stat *st) 1299 { 1300 DIR *d; 1301 struct dirent *dp; 1302 char *cp; 1303 struct stat stb; 1304 char *otp; 1305 int len; 1306 1307 switch (st->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(char *cmd) 1367 { 1368 int fd[2], status, pid, i; 1369 char *cp, *s; 1370 char sbuf[BUFSIZ]; 1371 1372 if (pipe(fd) < 0) { 1373 error("%s\n", strerror(errno)); 1374 return; 1375 } 1376 if ((pid = fork()) == 0) { 1377 /* 1378 * Return everything the shell commands print. 1379 */ 1380 (void) close(0); 1381 (void) close(1); 1382 (void) close(2); 1383 (void) open(_PATH_DEVNULL, O_RDONLY); 1384 (void) dup(fd[1]); 1385 (void) dup(fd[1]); 1386 (void) close(fd[0]); 1387 (void) close(fd[1]); 1388 setgid(groupid); 1389 setuid(userid); 1390 execl(_PATH_BSHELL, "sh", "-c", cmd, NULL); 1391 _exit(127); 1392 } 1393 (void) close(fd[1]); 1394 s = sbuf; 1395 *s++ = '\0'; 1396 while ((i = read(fd[0], buf, sizeof(buf))) > 0) { 1397 cp = buf; 1398 do { 1399 *s++ = *cp++; 1400 if (cp[-1] != '\n') { 1401 if (s < &sbuf[sizeof(sbuf)-1]) 1402 continue; 1403 *s++ = '\n'; 1404 } 1405 /* 1406 * Throw away blank lines. 1407 */ 1408 if (s == &sbuf[2]) { 1409 s--; 1410 continue; 1411 } 1412 (void) write(rem, sbuf, s - sbuf); 1413 s = &sbuf[1]; 1414 } while (--i); 1415 } 1416 if (s > &sbuf[1]) { 1417 *s++ = '\n'; 1418 (void) write(rem, sbuf, s - sbuf); 1419 } 1420 while ((i = wait(&status)) != pid && i != -1) 1421 ; 1422 if (i == -1) 1423 status = -1; 1424 (void) close(fd[0]); 1425 if (status) 1426 error("shell returned %d\n", status); 1427 else 1428 ack(); 1429 } 1430 1431 1432 void 1433 dolog(FILE *fp, const char *fmt, ...) 1434 { 1435 va_list ap; 1436 1437 /* Print changes locally if not quiet mode */ 1438 if (!qflag) { 1439 va_start(ap, fmt); 1440 (void)vprintf(fmt, ap); 1441 va_end(ap); 1442 } 1443 1444 /* Save changes (for mailing) if really updating files */ 1445 if (!(options & VERIFY) && fp != NULL) { 1446 va_start(ap, fmt); 1447 (void)vfprintf(fp, fmt, ap); 1448 va_end(ap); 1449 } 1450 } 1451 1452 void 1453 error(const char *fmt, ...) 1454 { 1455 static FILE *fp; 1456 va_list ap; 1457 1458 ++nerrs; 1459 if (!fp && !(fp = fdopen(rem, "w"))) 1460 return; 1461 va_start(ap, fmt); 1462 if (iamremote) { 1463 (void)fprintf(fp, "%crdist: ", 0x01); 1464 (void)vfprintf(fp, fmt, ap); 1465 fflush(fp); 1466 } 1467 else { 1468 fflush(stdout); 1469 (void)fprintf(stderr, "rdist: "); 1470 (void)vfprintf(stderr, fmt, ap); 1471 fflush(stderr); 1472 } 1473 va_end(ap); 1474 if (lfp != NULL) { 1475 (void)fprintf(lfp, "rdist: "); 1476 va_start(ap, fmt); 1477 (void)vfprintf(lfp, fmt, ap); 1478 va_end(ap); 1479 fflush(lfp); 1480 } 1481 } 1482 1483 void 1484 fatal(const char *fmt, ...) 1485 { 1486 static FILE *fp; 1487 va_list ap; 1488 1489 ++nerrs; 1490 if (!fp && !(fp = fdopen(rem, "w"))) 1491 return; 1492 va_start(ap, fmt); 1493 if (iamremote) { 1494 (void)fprintf(fp, "%crdist: ", 0x02); 1495 (void)vfprintf(fp, fmt, ap); 1496 fflush(fp); 1497 } 1498 else { 1499 fflush(stdout); 1500 (void)fprintf(stderr, "rdist: "); 1501 (void)vfprintf(stderr, fmt, ap); 1502 fflush(stderr); 1503 } 1504 va_end(ap); 1505 if (lfp != NULL) { 1506 (void)fprintf(lfp, "rdist: "); 1507 va_start(ap, fmt); 1508 (void)vfprintf(lfp, fmt, ap); 1509 va_end(ap); 1510 fflush(lfp); 1511 } 1512 cleanup(0); 1513 } 1514 1515 static int 1516 response(void) 1517 { 1518 char *cp, *s; 1519 char resp[BUFSIZ]; 1520 1521 if (debug) 1522 printf("response()\n"); 1523 1524 cp = s = resp; 1525 do { 1526 if (read(rem, cp, 1) != 1) 1527 lostconn(0); 1528 } while (*cp++ != '\n' && cp < &resp[BUFSIZ]); 1529 1530 switch (*s++) { 1531 case '\0': 1532 *--cp = '\0'; 1533 if (*s != '\0') { 1534 dolog(lfp, "%s\n", s); 1535 return(1); 1536 } 1537 return(0); 1538 case '\3': 1539 *--cp = '\0'; 1540 dolog(lfp, "Note: %s\n",s); 1541 return(response()); 1542 1543 default: 1544 s--; 1545 /* fall into... */ 1546 case '\1': 1547 case '\2': 1548 nerrs++; 1549 if (*s != '\n') { 1550 if (!iamremote) { 1551 fflush(stdout); 1552 (void) write(2, s, cp - s); 1553 } 1554 if (lfp != NULL) 1555 (void) fwrite(s, 1, cp - s, lfp); 1556 } 1557 if (resp[0] == '\2') 1558 lostconn(0); 1559 return(-1); 1560 } 1561 } 1562 1563 /* 1564 * Remove temporary files and do any cleanup operations before exiting. 1565 */ 1566 void 1567 /*ARGSUSED*/ 1568 cleanup(int signo __unused) 1569 { 1570 (void) unlink(tempfile); 1571 exit(1); 1572 } 1573 1574 static void 1575 note(const char *fmt, ...) 1576 { 1577 static char nbuf[BUFSIZ]; 1578 va_list ap; 1579 1580 va_start(ap, fmt); 1581 (void)vsnprintf(nbuf, sizeof(nbuf), fmt, ap); 1582 va_end(ap); 1583 comment(nbuf); 1584 } 1585 1586 static void 1587 comment(char *s) 1588 { 1589 char c; 1590 1591 c = '\3'; 1592 write(rem, &c, 1); 1593 write(rem, s, strlen(s)); 1594 c = '\n'; 1595 write(rem, &c, 1); 1596 } 1597