# 2.11BSD#431 - /usr/src/ucb/rdist/server.c

##### Functions

    ack               X
    chkparent         X
    chog              X
    clean             X
    cleanup           X
    comment           X
    dospecial         X
    error             X
    fatal             X
    hardlink          X
    install           X
    log               X
    note              X
    query             X
    recvf             X
    remove            X
    response          X
    rmchk             X
    savelink          X
    sendf             X
    server            X
    update            X

##### Variables

    Tdest             X
    buf               X
    catname           X
    ihead             X
    oumask            X
    stp               X
    target            X
    tp                X

##### Macros

    err               X
    protogroup        X
    protoname         X

       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

- in line 86, 113, 138, 152, 458, 732, 738, 752, 777, 801, 816, 871, 912, 969, 1121, 1170, 1354

chkparent defined in line 975; used 5 times

- in line 750, 790, 811, 954, 986

chog defined in line 1002; used 2 times

- in line 751, 896

clean defined in line 1150; used 1 times

- in line 117

cleanup defined in line 1491; used 18 times

- in line 33, 48-52(5), 69, 781, 830, 1197, 1437
- in /usr/src/ucb/rdist/docmd.c line 20, 36-39(4), 139, 260

comment defined in line 1510; used 1 times

- in line 1507

dospecial defined in line 1290; used 1 times

- in line 125

error defined in line 1379; used 58 times

- in line 64, 108, 160, 179, 281, 316, 339, 397, 429, 455, 577, 591, 598, 635, 652, 677, 684, 691, 698, 705, 713, 720, 755, 850, 862, 903, 931, 938, 949, 955-965(3), 1140, 1163-1167(2), 1178, 1189, 1243, 1256, 1267, 1277, 1299, 1352
- in /usr/src/ucb/rdist/docmd.c line 96, 235-237(2), 281, 309-313(2), 325, 384, 397, 418, 427, 469-473(2), 487
- in /usr/src/ucb/rdist/expand.c line 603

fatal defined in line 1410; used 10 times

- in /usr/src/ucb/rdist/docmd.c line 72, 111, 205
- in /usr/src/ucb/rdist/expand.c line 550
- in /usr/src/ucb/rdist/gram.y line 363, 394, 433, 450, 469
- in /usr/src/ucb/rdist/lookup.c line 130

hardlink defined in line 918; used 1 times

- in line 102

install defined in line 191; used 3 times

- in line 163
- in /usr/src/ucb/rdist/docmd.c line 130-135(2)

log defined in line 1360; used 18 times

- in line 167, 292, 299, 306-309(2), 403-406(2), 468, 493, 499, 572, 608, 1116, 1459, 1465
- in /usr/src/ucb/rdist/docmd.c line 154, 261, 402

note defined in line 1497; used 4 times

- in line 894, 1018, 1038, 1057

query defined in line 623; used 1 times

- in line 121

recvf defined in line 658; used 3 times

- in line 90-98(3)

remove defined in line 1222; used 2 times

- in line 1209, 1270

response defined in line 1441; used 14 times

- in line 244, 324, 353, 375, 385, 423, 438, 459, 475, 785, 844, 1085, 1213, 1466

rmchk defined in line 1069; used 1 times

- in line 330

savelink defined in line 480; used 4 times

- in line 34, 286, 364, 412

sendf defined in line 261; used 2 times

- in line 251, 349

server defined in line 43; used 1 times

- in /usr/src/ucb/rdist/main.c line 167

update defined in line 524; used 1 times

- in line 284

#### Defined variables

Tdest defined in line 26; used 7 times

- in line 249-252(2), 496-498(3), 511-512(2)

ack2ch defined in line 17; used 1 times

- in line 18

buf defined in line 23; used 211 times

- in line 56-57(3), 142-144(2), 240-243(4), 319-323(4), 367-390(12), 415-422(5), 432-437(4), 448-450(2), 471-474(4), 539-548(6), 642-643(3), 741-745(4), 778, 789-791(2), 799, 821, 838, 879-881(4), 908-910(4), 1081-1092(6), 1135-1140(2), 1192-1207(8), 1281-1284(2), 1322-1323(3), 1501-1507(3)
- in /usr/src/ucb/rdist/docmd.c line 200, 211-220(3), 227-229(2), 484-485(2), 516-517(2)
- in /usr/src/ucb/rdist/expand.c line 113, 147-153(4), 167, 173-176(4), 576-577(2), 584-585(2), 613
- in /usr/src/ucb/rdist/lookup.c line 101, 116-117(2), 124
- in /usr/src/ucb/rdist/server.c line 56-57(3), 142-144(2), 240-243(4), 319-323(4), 367-390(12), 415-422(5), 432-437(4), 448-450(2), 471-474(4), 539-548(6), 642-643(3), 741-745(4), 778, 789-791(2), 799, 821, 838, 879-881(4), 908-910(4), 1081-1092(6), 1135-1140(2), 1192-1207(8), 1281-1284(2), 1322-1323(3), 1501-1507(3)

catname defined in line 27; used 11 times

- in line 75-79(2), 107-111(2), 628, 719-725(3), 756-761(2), 943

ihead defined in line 22; used 16 times

- in line 486, 505-506(2)
- in /usr/src/ucb/rdist/docmd.c line 148-155(10)
- in /usr/src/ucb/rdist/server.c line 486, 505-506(2)

oumask defined in line 29; used 2 times

- in line 55, 987

sccsid defined in line 8; never used
stp defined in line 28; used 21 times

- in line 111, 481-487(4), 507-509(3), 524-527(2), 534, 605-611(4), 719-724(2), 756, 1222-1223(2), 1232

target defined in line 24; used 97 times

- in line 81-83(2), 213-216(2), 229-236(3), 278-281(4), 293, 300, 306-309(2), 315-316(2), 333, 339, 366-371(2), 387, 397, 403-406(2), 414-419(2), 428-429(2), 455, 466-471(2), 495-501(5), 510-514(3), 608, 631-635(2), 721, 735, 744-755(6), 763-770(3), 798, 858, 880, 901-903(2), 909, 946-966(8), 1104-1107(3), 1166-1167(2), 1173, 1179, 1188-1189(2), 1206, 1235, 1243-1251(3), 1257, 1266-1267(2), 1275-1277(2), 1283
- in /usr/src/ucb/rdist/docmd.c line 150(2), 377-379(2), 417-427(4), 436

tp defined in line 25; used 59 times

- in line 83-85(3), 106-112(3), 216-218(3), 332-333(2), 343-348(4), 354-355(2), 629, 636, 655, 724-729(4), 756-762(3), 944, 1102, 1120, 1172-1173(2), 1182-1187(4), 1214-1215(2), 1250-1251(2), 1260-1265(4), 1273-1274(2)
- in /usr/src/ucb/rdist/docmd.c line 341, 376-381(4), 421-422(2), 430-440(6)

#### Defined macros

err defined in line 20; used 4 times

- in line 456, 786, 845, 1141

protogroup defined in line 256; used 3 times

- in line 320, 381, 434

protoname defined in line 255; used 3 times

- in line 320, 381, 434

Last modified: 1995-05-17 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 4464 |