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