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