Annotation of 43BSD/etc/restore/interactive.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1985 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[] = "@(#)interactive.c      5.3 (Berkeley) 7/21/85";
                      9: #endif not lint
                     10: 
                     11: #include "restore.h"
                     12: #include <protocols/dumprestore.h>
                     13: #include <setjmp.h>
                     14: 
                     15: #define round(a, b) (((a) + (b) - 1) / (b) * (b))
                     16: 
                     17: /*
                     18:  * Things to handle interruptions.
                     19:  */
                     20: static jmp_buf reset;
                     21: static char *nextarg = NULL;
                     22: 
                     23: /*
                     24:  * Structure and routines associated with listing directories.
                     25:  */
                     26: struct afile {
                     27:        ino_t   fnum;           /* inode number of file */
                     28:        char    *fname;         /* file name */
                     29:        short   fflags;         /* extraction flags, if any */
                     30:        char    ftype;          /* file type, e.g. LEAF or NODE */
                     31: };
                     32: struct arglist {
                     33:        struct afile    *head;  /* start of argument list */
                     34:        struct afile    *last;  /* end of argument list */
                     35:        struct afile    *base;  /* current list arena */
                     36:        int             nent;   /* maximum size of list */
                     37:        char            *cmd;   /* the current command */
                     38: };
                     39: extern int fcmp();
                     40: extern char *fmtentry();
                     41: char *copynext();
                     42: 
                     43: /*
                     44:  * Read and execute commands from the terminal.
                     45:  */
                     46: runcmdshell()
                     47: {
                     48:        register struct entry *np;
                     49:        ino_t ino;
                     50:        static struct arglist alist = { 0, 0, 0, 0, 0 };
                     51:        char curdir[MAXPATHLEN];
                     52:        char name[MAXPATHLEN];
                     53:        char cmd[BUFSIZ];
                     54: 
                     55:        canon("/", curdir);
                     56: loop:
                     57:        if (setjmp(reset) != 0) {
                     58:                for (; alist.head < alist.last; alist.head++)
                     59:                        freename(alist.head->fname);
                     60:                nextarg = NULL;
                     61:                volno = 0;
                     62:        }
                     63:        getcmd(curdir, cmd, name, &alist);
                     64:        switch (cmd[0]) {
                     65:        /*
                     66:         * Add elements to the extraction list.
                     67:         */
                     68:        case 'a':
                     69:                ino = dirlookup(name);
                     70:                if (ino == 0)
                     71:                        break;
                     72:                if (mflag)
                     73:                        pathcheck(name);
                     74:                treescan(name, ino, addfile);
                     75:                break;
                     76:        /*
                     77:         * Change working directory.
                     78:         */
                     79:        case 'c':
                     80:                ino = dirlookup(name);
                     81:                if (ino == 0)
                     82:                        break;
                     83:                if (inodetype(ino) == LEAF) {
                     84:                        fprintf(stderr, "%s: not a directory\n", name);
                     85:                        break;
                     86:                }
                     87:                (void) strcpy(curdir, name);
                     88:                break;
                     89:        /*
                     90:         * Delete elements from the extraction list.
                     91:         */
                     92:        case 'd':
                     93:                np = lookupname(name);
                     94:                if (np == NIL || (np->e_flags & NEW) == 0) {
                     95:                        fprintf(stderr, "%s: not on extraction list\n", name);
                     96:                        break;
                     97:                }
                     98:                treescan(name, np->e_ino, deletefile);
                     99:                break;
                    100:        /*
                    101:         * Extract the requested list.
                    102:         */
                    103:        case 'e':
                    104:                createfiles();
                    105:                createlinks();
                    106:                setdirmodes();
                    107:                if (dflag)
                    108:                        checkrestore();
                    109:                volno = 0;
                    110:                break;
                    111:        /*
                    112:         * List available commands.
                    113:         */
                    114:        case 'h':
                    115:        case '?':
                    116:                fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
                    117:                        "Available commands are:\n",
                    118:                        "\tls [arg] - list directory\n",
                    119:                        "\tcd arg - change directory\n",
                    120:                        "\tpwd - print current directory\n",
                    121:                        "\tadd [arg] - add `arg' to list of",
                    122:                        " files to be extracted\n",
                    123:                        "\tdelete [arg] - delete `arg' from",
                    124:                        " list of files to be extracted\n",
                    125:                        "\textract - extract requested files\n",
                    126:                        "\tsetmodes - set modes of requested directories\n",
                    127:                        "\tquit - immediately exit program\n",
                    128:                        "\tverbose - toggle verbose flag",
                    129:                        " (useful with ``ls'')\n",
                    130:                        "\thelp or `?' - print this list\n",
                    131:                        "If no `arg' is supplied, the current",
                    132:                        " directory is used\n");
                    133:                break;
                    134:        /*
                    135:         * List a directory.
                    136:         */
                    137:        case 'l':
                    138:                ino = dirlookup(name);
                    139:                if (ino == 0)
                    140:                        break;
                    141:                printlist(name, ino, curdir);
                    142:                break;
                    143:        /*
                    144:         * Print current directory.
                    145:         */
                    146:        case 'p':
                    147:                if (curdir[1] == '\0')
                    148:                        fprintf(stderr, "/\n");
                    149:                else
                    150:                        fprintf(stderr, "%s\n", &curdir[1]);
                    151:                break;
                    152:        /*
                    153:         * Quit.
                    154:         */
                    155:        case 'q':
                    156:        case 'x':
                    157:                return;
                    158:        /*
                    159:         * Toggle verbose mode.
                    160:         */
                    161:        case 'v':
                    162:                if (vflag) {
                    163:                        fprintf(stderr, "verbose mode off\n");
                    164:                        vflag = 0;
                    165:                        break;
                    166:                }
                    167:                fprintf(stderr, "verbose mode on\n");
                    168:                vflag++;
                    169:                break;
                    170:        /*
                    171:         * Just restore requested directory modes.
                    172:         */
                    173:        case 's':
                    174:                setdirmodes();
                    175:                break;
                    176:        /*
                    177:         * Turn on debugging.
                    178:         */
                    179:        case 'D':
                    180:                if (dflag) {
                    181:                        fprintf(stderr, "debugging mode off\n");
                    182:                        dflag = 0;
                    183:                        break;
                    184:                }
                    185:                fprintf(stderr, "debugging mode on\n");
                    186:                dflag++;
                    187:                break;
                    188:        /*
                    189:         * Unknown command.
                    190:         */
                    191:        default:
                    192:                fprintf(stderr, "%s: unknown command; type ? for help\n", cmd);
                    193:                break;
                    194:        }
                    195:        goto loop;
                    196: }
                    197: 
                    198: /*
                    199:  * Read and parse an interactive command.
                    200:  * The first word on the line is assigned to "cmd". If
                    201:  * there are no arguments on the command line, then "curdir"
                    202:  * is returned as the argument. If there are arguments
                    203:  * on the line they are returned one at a time on each
                    204:  * successive call to getcmd. Each argument is first assigned
                    205:  * to "name". If it does not start with "/" the pathname in
                    206:  * "curdir" is prepended to it. Finally "canon" is called to
                    207:  * eliminate any embedded ".." components.
                    208:  */
                    209: getcmd(curdir, cmd, name, ap)
                    210:        char *curdir, *cmd, *name;
                    211:        struct arglist *ap;
                    212: {
                    213:        register char *cp;
                    214:        static char input[BUFSIZ];
                    215:        char output[BUFSIZ];
                    216: #      define rawname input    /* save space by reusing input buffer */
                    217: 
                    218:        /*
                    219:         * Check to see if still processing arguments.
                    220:         */
                    221:        if (ap->head != ap->last) {
                    222:                strcpy(name, ap->head->fname);
                    223:                freename(ap->head->fname);
                    224:                ap->head++;
                    225:                return;
                    226:        }
                    227:        if (nextarg != NULL)
                    228:                goto getnext;
                    229:        /*
                    230:         * Read a command line and trim off trailing white space.
                    231:         */
                    232:        do      {
                    233:                fprintf(stderr, "restore > ");
                    234:                (void) fflush(stderr);
                    235:                (void) fgets(input, BUFSIZ, terminal);
                    236:        } while (!feof(terminal) && input[0] == '\n');
                    237:        if (feof(terminal)) {
                    238:                (void) strcpy(cmd, "quit");
                    239:                return;
                    240:        }
                    241:        for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--)
                    242:                /* trim off trailing white space and newline */;
                    243:        *++cp = '\0';
                    244:        /*
                    245:         * Copy the command into "cmd".
                    246:         */
                    247:        cp = copynext(input, cmd);
                    248:        ap->cmd = cmd;
                    249:        /*
                    250:         * If no argument, use curdir as the default.
                    251:         */
                    252:        if (*cp == '\0') {
                    253:                (void) strcpy(name, curdir);
                    254:                return;
                    255:        }
                    256:        nextarg = cp;
                    257:        /*
                    258:         * Find the next argument.
                    259:         */
                    260: getnext:
                    261:        cp = copynext(nextarg, rawname);
                    262:        if (*cp == '\0')
                    263:                nextarg = NULL;
                    264:        else
                    265:                nextarg = cp;
                    266:        /*
                    267:         * If it an absolute pathname, canonicalize it and return it.
                    268:         */
                    269:        if (rawname[0] == '/') {
                    270:                canon(rawname, name);
                    271:        } else {
                    272:                /*
                    273:                 * For relative pathnames, prepend the current directory to
                    274:                 * it then canonicalize and return it.
                    275:                 */
                    276:                (void) strcpy(output, curdir);
                    277:                (void) strcat(output, "/");
                    278:                (void) strcat(output, rawname);
                    279:                canon(output, name);
                    280:        }
                    281:        expandarg(name, ap);
                    282:        strcpy(name, ap->head->fname);
                    283:        freename(ap->head->fname);
                    284:        ap->head++;
                    285: #      undef rawname
                    286: }
                    287: 
                    288: /*
                    289:  * Strip off the next token of the input.
                    290:  */
                    291: char *
                    292: copynext(input, output)
                    293:        char *input, *output;
                    294: {
                    295:        register char *cp, *bp;
                    296:        char quote;
                    297: 
                    298:        for (cp = input; *cp == ' ' || *cp == '\t'; cp++)
                    299:                /* skip to argument */;
                    300:        bp = output;
                    301:        while (*cp != ' ' && *cp != '\t' && *cp != '\0') {
                    302:                /*
                    303:                 * Handle back slashes.
                    304:                 */
                    305:                if (*cp == '\\') {
                    306:                        if (*++cp == '\0') {
                    307:                                fprintf(stderr,
                    308:                                        "command lines cannot be continued\n");
                    309:                                continue;
                    310:                        }
                    311:                        *bp++ = *cp++;
                    312:                        continue;
                    313:                }
                    314:                /*
                    315:                 * The usual unquoted case.
                    316:                 */
                    317:                if (*cp != '\'' && *cp != '"') {
                    318:                        *bp++ = *cp++;
                    319:                        continue;
                    320:                }
                    321:                /*
                    322:                 * Handle single and double quotes.
                    323:                 */
                    324:                quote = *cp++;
                    325:                while (*cp != quote && *cp != '\0')
                    326:                        *bp++ = *cp++ | 0200;
                    327:                if (*cp++ == '\0') {
                    328:                        fprintf(stderr, "missing %c\n", quote);
                    329:                        cp--;
                    330:                        continue;
                    331:                }
                    332:        }
                    333:        *bp = '\0';
                    334:        return (cp);
                    335: }
                    336: 
                    337: /*
                    338:  * Canonicalize file names to always start with ``./'' and
                    339:  * remove any imbedded "." and ".." components.
                    340:  */
                    341: canon(rawname, canonname)
                    342:        char *rawname, *canonname;
                    343: {
                    344:        register char *cp, *np;
                    345:        int len;
                    346: 
                    347:        if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0)
                    348:                (void) strcpy(canonname, "");
                    349:        else if (rawname[0] == '/')
                    350:                (void) strcpy(canonname, ".");
                    351:        else
                    352:                (void) strcpy(canonname, "./");
                    353:        (void) strcat(canonname, rawname);
                    354:        /*
                    355:         * Eliminate multiple and trailing '/'s
                    356:         */
                    357:        for (cp = np = canonname; *np != '\0'; cp++) {
                    358:                *cp = *np++;
                    359:                while (*cp == '/' && *np == '/')
                    360:                        np++;
                    361:        }
                    362:        *cp = '\0';
                    363:        if (*--cp == '/')
                    364:                *cp = '\0';
                    365:        /*
                    366:         * Eliminate extraneous "." and ".." from pathnames.
                    367:         */
                    368:        for (np = canonname; *np != '\0'; ) {
                    369:                np++;
                    370:                cp = np;
                    371:                while (*np != '/' && *np != '\0')
                    372:                        np++;
                    373:                if (np - cp == 1 && *cp == '.') {
                    374:                        cp--;
                    375:                        (void) strcpy(cp, np);
                    376:                        np = cp;
                    377:                }
                    378:                if (np - cp == 2 && strncmp(cp, "..", 2) == 0) {
                    379:                        cp--;
                    380:                        while (cp > &canonname[1] && *--cp != '/')
                    381:                                /* find beginning of name */;
                    382:                        (void) strcpy(cp, np);
                    383:                        np = cp;
                    384:                }
                    385:        }
                    386: }
                    387: 
                    388: /*
                    389:  * globals (file name generation)
                    390:  *
                    391:  * "*" in params matches r.e ".*"
                    392:  * "?" in params matches r.e. "."
                    393:  * "[...]" in params matches character class
                    394:  * "[...a-z...]" in params matches a through z.
                    395:  */
                    396: expandarg(arg, ap)
                    397:        char *arg;
                    398:        register struct arglist *ap;
                    399: {
                    400:        static struct afile single;
                    401:        int size;
                    402: 
                    403:        ap->head = ap->last = (struct afile *)0;
                    404:        size = expand(arg, 0, ap);
                    405:        if (size == 0) {
                    406:                single.fnum = lookupname(arg)->e_ino;
                    407:                single.fname = savename(arg);
                    408:                ap->head = &single;
                    409:                ap->last = ap->head + 1;
                    410:                return;
                    411:        }
                    412:        qsort((char *)ap->head, ap->last - ap->head, sizeof *ap->head, fcmp);
                    413: }
                    414: 
                    415: /*
                    416:  * Expand a file name
                    417:  */
                    418: expand(as, rflg, ap)
                    419:        char *as;
                    420:        int rflg;
                    421:        register struct arglist *ap;
                    422: {
                    423:        int             count, size;
                    424:        char            dir = 0;
                    425:        char            *rescan = 0;
                    426:        DIR             *dirp;
                    427:        register char   *s, *cs;
                    428:        int             sindex, rindex, lindex;
                    429:        struct direct   *dp;
                    430:        register char   slash; 
                    431:        register char   *rs; 
                    432:        register char   c;
                    433: 
                    434:        /*
                    435:         * check for meta chars
                    436:         */
                    437:        s = cs = as;
                    438:        slash = 0;
                    439:        while (*cs != '*' && *cs != '?' && *cs != '[') {        
                    440:                if (*cs++ == 0) {       
                    441:                        if (rflg && slash)
                    442:                                break; 
                    443:                        else
                    444:                                return (0) ;
                    445:                } else if (*cs == '/') {        
                    446:                        slash++;
                    447:                }
                    448:        }
                    449:        for (;;) {      
                    450:                if (cs == s) {  
                    451:                        s = "";
                    452:                        break;
                    453:                } else if (*--cs == '/') {      
                    454:                        *cs = 0;
                    455:                        if (s == cs)
                    456:                                s = "/";
                    457:                        break;
                    458:                }
                    459:        }
                    460:        if ((dirp = rst_opendir(s)) != NULL)
                    461:                dir++;
                    462:        count = 0;
                    463:        if (*cs == 0)
                    464:                *cs++ = 0200;
                    465:        if (dir) {
                    466:                /*
                    467:                 * check for rescan
                    468:                 */
                    469:                rs = cs;
                    470:                do {    
                    471:                        if (*rs == '/') { 
                    472:                                rescan = rs; 
                    473:                                *rs = 0; 
                    474:                        }
                    475:                } while (*rs++);
                    476:                sindex = ap->last - ap->head;
                    477:                while ((dp = rst_readdir(dirp)) != NULL && dp->d_ino != 0) {
                    478:                        if (!dflag && BIT(dp->d_ino, dumpmap) == 0)
                    479:                                continue;
                    480:                        if ((*dp->d_name == '.' && *cs != '.'))
                    481:                                continue;
                    482:                        if (gmatch(dp->d_name, cs)) {   
                    483:                                if (addg(dp, s, rescan, ap) < 0)
                    484:                                        return (-1);
                    485:                                count++;
                    486:                        }
                    487:                }
                    488:                if (rescan) {   
                    489:                        rindex = sindex; 
                    490:                        lindex = ap->last - ap->head;
                    491:                        if (count) {    
                    492:                                count = 0;
                    493:                                while (rindex < lindex) {       
                    494:                                        size = expand(ap->head[rindex].fname,
                    495:                                            1, ap);
                    496:                                        if (size < 0)
                    497:                                                return (size);
                    498:                                        count += size;
                    499:                                        rindex++;
                    500:                                }
                    501:                        }
                    502:                        bcopy((char *)&ap->head[lindex],
                    503:                             (char *)&ap->head[sindex],
                    504:                             (ap->last - &ap->head[rindex]) * sizeof *ap->head);
                    505:                        ap->last -= lindex - sindex;
                    506:                        *rescan = '/';
                    507:                }
                    508:        }
                    509:        s = as;
                    510:        while (c = *s)
                    511:                *s++ = (c&0177 ? c : '/');
                    512:        return (count);
                    513: }
                    514: 
                    515: /*
                    516:  * Check for a name match
                    517:  */
                    518: gmatch(s, p)
                    519:        register char   *s, *p;
                    520: {
                    521:        register int    scc;
                    522:        char            c;
                    523:        char            ok; 
                    524:        int             lc;
                    525: 
                    526:        if (scc = *s++)
                    527:                if ((scc &= 0177) == 0)
                    528:                        scc = 0200;
                    529:        switch (c = *p++) {
                    530: 
                    531:        case '[':
                    532:                ok = 0; 
                    533:                lc = 077777;
                    534:                while (c = *p++) {      
                    535:                        if (c == ']') {
                    536:                                return (ok ? gmatch(s, p) : 0);
                    537:                        } else if (c == '-') {  
                    538:                                if (lc <= scc && scc <= (*p++))
                    539:                                        ok++ ;
                    540:                        } else {        
                    541:                                if (scc == (lc = (c&0177)))
                    542:                                        ok++ ;
                    543:                        }
                    544:                }
                    545:                return (0);
                    546: 
                    547:        default:
                    548:                if ((c&0177) != scc)
                    549:                        return (0) ;
                    550:                /* falls through */
                    551: 
                    552:        case '?':
                    553:                return (scc ? gmatch(s, p) : 0);
                    554: 
                    555:        case '*':
                    556:                if (*p == 0)
                    557:                        return (1) ;
                    558:                s--;
                    559:                while (*s) {  
                    560:                        if (gmatch(s++, p))
                    561:                                return (1);
                    562:                }
                    563:                return (0);
                    564: 
                    565:        case 0:
                    566:                return (scc == 0);
                    567:        }
                    568: }
                    569: 
                    570: /*
                    571:  * Construct a matched name.
                    572:  */
                    573: addg(dp, as1, as3, ap)
                    574:        struct direct   *dp;
                    575:        char            *as1, *as3;
                    576:        struct arglist  *ap;
                    577: {
                    578:        register char   *s1, *s2;
                    579:        register int    c;
                    580:        char            buf[BUFSIZ];
                    581: 
                    582:        s2 = buf;
                    583:        s1 = as1;
                    584:        while (c = *s1++) {     
                    585:                if ((c &= 0177) == 0) { 
                    586:                        *s2++ = '/';
                    587:                        break;
                    588:                }
                    589:                *s2++ = c;
                    590:        }
                    591:        s1 = dp->d_name;
                    592:        while (*s2 = *s1++)
                    593:                s2++;
                    594:        if (s1 = as3) { 
                    595:                *s2++ = '/';
                    596:                while (*s2++ = *++s1)
                    597:                        /* void */;
                    598:        }
                    599:        if (mkentry(buf, dp->d_ino, ap) == FAIL)
                    600:                return (-1);
                    601: }
                    602: 
                    603: /*
                    604:  * Do an "ls" style listing of a directory
                    605:  */
                    606: printlist(name, ino, basename)
                    607:        char *name;
                    608:        ino_t ino;
                    609:        char *basename;
                    610: {
                    611:        register struct afile *fp;
                    612:        register struct direct *dp;
                    613:        static struct arglist alist = { 0, 0, 0, 0, "ls" };
                    614:        struct afile single;
                    615:        DIR *dirp;
                    616: 
                    617:        if ((dirp = rst_opendir(name)) == NULL) {
                    618:                single.fnum = ino;
                    619:                single.fname = savename(name + strlen(basename) + 1);
                    620:                alist.head = &single;
                    621:                alist.last = alist.head + 1;
                    622:        } else {
                    623:                alist.head = (struct afile *)0;
                    624:                fprintf(stderr, "%s:\n", name);
                    625:                while (dp = rst_readdir(dirp)) {
                    626:                        if (dp == NULL || dp->d_ino == 0)
                    627:                                break;
                    628:                        if (!dflag && BIT(dp->d_ino, dumpmap) == 0)
                    629:                                continue;
                    630:                        if (vflag == 0 &&
                    631:                            (strcmp(dp->d_name, ".") == 0 ||
                    632:                             strcmp(dp->d_name, "..") == 0))
                    633:                                continue;
                    634:                        if (!mkentry(dp->d_name, dp->d_ino, &alist))
                    635:                                return;
                    636:                }
                    637:        }
                    638:        if (alist.head != 0) {
                    639:                qsort((char *)alist.head, alist.last - alist.head,
                    640:                        sizeof *alist.head, fcmp);
                    641:                formatf(&alist);
                    642:                for (fp = alist.head; fp < alist.last; fp++)
                    643:                        freename(fp->fname);
                    644:        }
                    645:        if (dirp != NULL)
                    646:                fprintf(stderr, "\n");
                    647: }
                    648: 
                    649: /*
                    650:  * Read the contents of a directory.
                    651:  */
                    652: mkentry(name, ino, ap)
                    653:        char *name;
                    654:        ino_t ino;
                    655:        register struct arglist *ap;
                    656: {
                    657:        register struct afile *fp;
                    658: 
                    659:        if (ap->base == NULL) {
                    660:                ap->nent = 20;
                    661:                ap->base = (struct afile *)calloc((unsigned)ap->nent,
                    662:                        sizeof (struct afile));
                    663:                if (ap->base == NULL) {
                    664:                        fprintf(stderr, "%s: out of memory\n", ap->cmd);
                    665:                        return (FAIL);
                    666:                }
                    667:        }
                    668:        if (ap->head == 0)
                    669:                ap->head = ap->last = ap->base;
                    670:        fp = ap->last;
                    671:        fp->fnum = ino;
                    672:        fp->fname = savename(name);
                    673:        fp++;
                    674:        if (fp == ap->head + ap->nent) {
                    675:                ap->base = (struct afile *)realloc((char *)ap->base,
                    676:                    (unsigned)(2 * ap->nent * sizeof (struct afile)));
                    677:                if (ap->base == 0) {
                    678:                        fprintf(stderr, "%s: out of memory\n", ap->cmd);
                    679:                        return (FAIL);
                    680:                }
                    681:                ap->head = ap->base;
                    682:                fp = ap->head + ap->nent;
                    683:                ap->nent *= 2;
                    684:        }
                    685:        ap->last = fp;
                    686:        return (GOOD);
                    687: }
                    688: 
                    689: /*
                    690:  * Print out a pretty listing of a directory
                    691:  */
                    692: formatf(ap)
                    693:        register struct arglist *ap;
                    694: {
                    695:        register struct afile *fp;
                    696:        struct entry *np;
                    697:        int width = 0, w, nentry = ap->last - ap->head;
                    698:        int i, j, len, columns, lines;
                    699:        char *cp;
                    700: 
                    701:        if (ap->head == ap->last)
                    702:                return;
                    703:        for (fp = ap->head; fp < ap->last; fp++) {
                    704:                fp->ftype = inodetype(fp->fnum);
                    705:                np = lookupino(fp->fnum);
                    706:                if (np != NIL)
                    707:                        fp->fflags = np->e_flags;
                    708:                else
                    709:                        fp->fflags = 0;
                    710:                len = strlen(fmtentry(fp));
                    711:                if (len > width)
                    712:                        width = len;
                    713:        }
                    714:        width += 2;
                    715:        columns = 80 / width;
                    716:        if (columns == 0)
                    717:                columns = 1;
                    718:        lines = (nentry + columns - 1) / columns;
                    719:        for (i = 0; i < lines; i++) {
                    720:                for (j = 0; j < columns; j++) {
                    721:                        fp = ap->head + j * lines + i;
                    722:                        cp = fmtentry(fp);
                    723:                        fprintf(stderr, "%s", cp);
                    724:                        if (fp + lines >= ap->last) {
                    725:                                fprintf(stderr, "\n");
                    726:                                break;
                    727:                        }
                    728:                        w = strlen(cp);
                    729:                        while (w < width) {
                    730:                                w++;
                    731:                                fprintf(stderr, " ");
                    732:                        }
                    733:                }
                    734:        }
                    735: }
                    736: 
                    737: /*
                    738:  * Comparison routine for qsort.
                    739:  */
                    740: fcmp(f1, f2)
                    741:        register struct afile *f1, *f2;
                    742: {
                    743: 
                    744:        return (strcmp(f1->fname, f2->fname));
                    745: }
                    746: 
                    747: /*
                    748:  * Format a directory entry.
                    749:  */
                    750: char *
                    751: fmtentry(fp)
                    752:        register struct afile *fp;
                    753: {
                    754:        static char fmtres[BUFSIZ];
                    755:        static int precision = 0;
                    756:        int i;
                    757:        register char *cp, *dp;
                    758: 
                    759:        if (!vflag) {
                    760:                fmtres[0] = '\0';
                    761:        } else {
                    762:                if (precision == 0)
                    763:                        for (i = maxino; i > 0; i /= 10)
                    764:                                precision++;
                    765:                (void) sprintf(fmtres, "%*d ", precision, fp->fnum);
                    766:        }
                    767:        dp = &fmtres[strlen(fmtres)];
                    768:        if (dflag && BIT(fp->fnum, dumpmap) == 0)
                    769:                *dp++ = '^';
                    770:        else if ((fp->fflags & NEW) != 0)
                    771:                *dp++ = '*';
                    772:        else
                    773:                *dp++ = ' ';
                    774:        for (cp = fp->fname; *cp; cp++)
                    775:                if (!vflag && (*cp < ' ' || *cp >= 0177))
                    776:                        *dp++ = '?';
                    777:                else
                    778:                        *dp++ = *cp;
                    779:        if (fp->ftype == NODE)
                    780:                *dp++ = '/';
                    781:        *dp++ = 0;
                    782:        return (fmtres);
                    783: }
                    784: 
                    785: /*
                    786:  * respond to interrupts
                    787:  */
                    788: onintr()
                    789: {
                    790:        if (command == 'i')
                    791:                longjmp(reset, 1);
                    792:        if (reply("restore interrupted, continue") == FAIL)
                    793:                done(1);
                    794: }

unix.superglobalmegacorp.com

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