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