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