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

Defined functions

ack defined in line 18; used 17 times
chkparent defined in line 975; used 5 times
chog defined in line 1002; used 2 times
clean defined in line 1150; used 1 times
cleanup defined in line 1491; used 18 times
comment defined in line 1510; used 1 times
dospecial defined in line 1290; used 1 times
error defined in line 1379; used 58 times
hardlink defined in line 918; used 1 times
install defined in line 191; used 3 times
log defined in line 1360; used 18 times
note defined in line 1497; used 4 times
query defined in line 623; used 1 times
recvf defined in line 658; used 3 times
remove defined in line 1222; used 2 times
response defined in line 1441; used 14 times
rmchk defined in line 1069; used 1 times
savelink defined in line 480; used 4 times
sendf defined in line 261; used 2 times
server defined in line 43; used 1 times
update defined in line 524; used 1 times

Defined variables

Tdest defined in line 26; used 7 times
ack2ch defined in line 17; used 1 times
  • in line 18
buf defined in line 23; used 211 times
catname defined in line 27; used 11 times
ihead defined in line 22; used 16 times
oumask defined in line 29; used 2 times
sccsid defined in line 8; never used
stp defined in line 28; used 21 times
target defined in line 24; used 97 times
tp defined in line 25; used 59 times

Defined macros

err defined in line 20; used 4 times
protogroup defined in line 256; used 3 times
protoname defined in line 255; used 3 times
Last modified: 1995-05-17
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 8963
Valid CSS Valid XHTML 1.0 Strict