Annotation of 43BSD/ucb/rdist/server.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.