allow cg's to start at frag instead of block boundries
[unix-history] / usr / src / sbin / restore / interactive.c
index f4937a4..112f5db 100644 (file)
@@ -1,11 +1,15 @@
-/* Copyright (c) 1985 Regents of the University of California */
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
 
 #ifndef lint
 
 #ifndef lint
-static char sccsid[] = "@(#)interactive.c      3.2     (Berkeley)      %G%";
+static char sccsid[] = "@(#)interactive.c      5.5 (Berkeley) %G%";
 #endif not lint
 
 #include "restore.h"
 #endif not lint
 
 #include "restore.h"
-#include <dumprestor.h>
+#include <protocols/dumprestore.h>
 #include <setjmp.h>
 
 #define round(a, b) (((a) + (b) - 1) / (b) * (b))
 #include <setjmp.h>
 
 #define round(a, b) (((a) + (b) - 1) / (b) * (b))
@@ -16,17 +20,6 @@ static char sccsid[] = "@(#)interactive.c    3.2     (Berkeley)      %G%";
 static jmp_buf reset;
 static char *nextarg = NULL;
 
 static jmp_buf reset;
 static char *nextarg = NULL;
 
-/*
- * Structure associated with file name globbing.
- */
-struct argnod {
-       struct argnod *argnxt;
-       char argval[1];
-}; 
-static struct argnod *gchain, *stakbot, *staktop;
-static char *brkend, *nullstr = "";
-struct argnod *locstak(), *endstak();
-
 /*
  * Structure and routines associated with listing directories.
  */
 /*
  * Structure and routines associated with listing directories.
  */
@@ -36,6 +29,13 @@ struct afile {
        short   fflags;         /* extraction flags, if any */
        char    ftype;          /* file type, e.g. LEAF or NODE */
 };
        short   fflags;         /* extraction flags, if any */
        char    ftype;          /* file type, e.g. LEAF or NODE */
 };
+struct arglist {
+       struct afile    *head;  /* start of argument list */
+       struct afile    *last;  /* end of argument list */
+       struct afile    *base;  /* current list arena */
+       int             nent;   /* maximum size of list */
+       char            *cmd;   /* the current command */
+};
 extern int fcmp();
 extern char *fmtentry();
 char *copynext();
 extern int fcmp();
 extern char *fmtentry();
 char *copynext();
@@ -47,6 +47,7 @@ runcmdshell()
 {
        register struct entry *np;
        ino_t ino;
 {
        register struct entry *np;
        ino_t ino;
+       static struct arglist alist = { 0, 0, 0, 0, 0 };
        char curdir[MAXPATHLEN];
        char name[MAXPATHLEN];
        char cmd[BUFSIZ];
        char curdir[MAXPATHLEN];
        char name[MAXPATHLEN];
        char cmd[BUFSIZ];
@@ -54,16 +55,19 @@ runcmdshell()
        canon("/", curdir);
 loop:
        if (setjmp(reset) != 0) {
        canon("/", curdir);
 loop:
        if (setjmp(reset) != 0) {
-               gchain = 0;
+               for (; alist.head < alist.last; alist.head++)
+                       freename(alist.head->fname);
                nextarg = NULL;
                volno = 0;
        }
                nextarg = NULL;
                volno = 0;
        }
-       getcmd(curdir, cmd, name);
+       getcmd(curdir, cmd, name, &alist);
        switch (cmd[0]) {
        /*
         * Add elements to the extraction list.
         */
        case 'a':
        switch (cmd[0]) {
        /*
         * Add elements to the extraction list.
         */
        case 'a':
+               if (strncmp(cmd, "add", strlen(cmd)) != 0)
+                       goto bad;
                ino = dirlookup(name);
                if (ino == 0)
                        break;
                ino = dirlookup(name);
                if (ino == 0)
                        break;
@@ -75,6 +79,8 @@ loop:
         * Change working directory.
         */
        case 'c':
         * Change working directory.
         */
        case 'c':
+               if (strncmp(cmd, "cd", strlen(cmd)) != 0)
+                       goto bad;
                ino = dirlookup(name);
                if (ino == 0)
                        break;
                ino = dirlookup(name);
                if (ino == 0)
                        break;
@@ -88,6 +94,8 @@ loop:
         * Delete elements from the extraction list.
         */
        case 'd':
         * Delete elements from the extraction list.
         */
        case 'd':
+               if (strncmp(cmd, "delete", strlen(cmd)) != 0)
+                       goto bad;
                np = lookupname(name);
                if (np == NIL || (np->e_flags & NEW) == 0) {
                        fprintf(stderr, "%s: not on extraction list\n", name);
                np = lookupname(name);
                if (np == NIL || (np->e_flags & NEW) == 0) {
                        fprintf(stderr, "%s: not on extraction list\n", name);
@@ -99,6 +107,8 @@ loop:
         * Extract the requested list.
         */
        case 'e':
         * Extract the requested list.
         */
        case 'e':
+               if (strncmp(cmd, "extract", strlen(cmd)) != 0)
+                       goto bad;
                createfiles();
                createlinks();
                setdirmodes();
                createfiles();
                createlinks();
                setdirmodes();
@@ -110,8 +120,10 @@ loop:
         * List available commands.
         */
        case 'h':
         * List available commands.
         */
        case 'h':
+               if (strncmp(cmd, "help", strlen(cmd)) != 0)
+                       goto bad;
        case '?':
        case '?':
-               fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+               fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
                        "Available commands are:\n",
                        "\tls [arg] - list directory\n",
                        "\tcd arg - change directory\n",
                        "Available commands are:\n",
                        "\tls [arg] - list directory\n",
                        "\tcd arg - change directory\n",
@@ -121,7 +133,9 @@ loop:
                        "\tdelete [arg] - delete `arg' from",
                        " list of files to be extracted\n",
                        "\textract - extract requested files\n",
                        "\tdelete [arg] - delete `arg' from",
                        " list of files to be extracted\n",
                        "\textract - extract requested files\n",
+                       "\tsetmodes - set modes of requested directories\n",
                        "\tquit - immediately exit program\n",
                        "\tquit - immediately exit program\n",
+                       "\twhat - list dump header information\n",
                        "\tverbose - toggle verbose flag",
                        " (useful with ``ls'')\n",
                        "\thelp or `?' - print this list\n",
                        "\tverbose - toggle verbose flag",
                        " (useful with ``ls'')\n",
                        "\thelp or `?' - print this list\n",
@@ -132,6 +146,8 @@ loop:
         * List a directory.
         */
        case 'l':
         * List a directory.
         */
        case 'l':
+               if (strncmp(cmd, "ls", strlen(cmd)) != 0)
+                       goto bad;
                ino = dirlookup(name);
                if (ino == 0)
                        break;
                ino = dirlookup(name);
                if (ino == 0)
                        break;
@@ -141,6 +157,8 @@ loop:
         * Print current directory.
         */
        case 'p':
         * Print current directory.
         */
        case 'p':
+               if (strncmp(cmd, "pwd", strlen(cmd)) != 0)
+                       goto bad;
                if (curdir[1] == '\0')
                        fprintf(stderr, "/\n");
                else
                if (curdir[1] == '\0')
                        fprintf(stderr, "/\n");
                else
@@ -150,12 +168,19 @@ loop:
         * Quit.
         */
        case 'q':
         * Quit.
         */
        case 'q':
+               if (strncmp(cmd, "quit", strlen(cmd)) != 0)
+                       goto bad;
+               return;
        case 'x':
        case 'x':
+               if (strncmp(cmd, "xit", strlen(cmd)) != 0)
+                       goto bad;
                return;
        /*
         * Toggle verbose mode.
         */
        case 'v':
                return;
        /*
         * Toggle verbose mode.
         */
        case 'v':
+               if (strncmp(cmd, "verbose", strlen(cmd)) != 0)
+                       goto bad;
                if (vflag) {
                        fprintf(stderr, "verbose mode off\n");
                        vflag = 0;
                if (vflag) {
                        fprintf(stderr, "verbose mode off\n");
                        vflag = 0;
@@ -167,13 +192,25 @@ loop:
        /*
         * Just restore requested directory modes.
         */
        /*
         * Just restore requested directory modes.
         */
-       case 'R':
+       case 's':
+               if (strncmp(cmd, "setmodes", strlen(cmd)) != 0)
+                       goto bad;
                setdirmodes();
                break;
                setdirmodes();
                break;
+       /*
+        * Print out dump header information.
+        */
+       case 'w':
+               if (strncmp(cmd, "what", strlen(cmd)) != 0)
+                       goto bad;
+               printdumpinfo();
+               break;
        /*
         * Turn on debugging.
         */
        case 'D':
        /*
         * Turn on debugging.
         */
        case 'D':
+               if (strncmp(cmd, "Debug", strlen(cmd)) != 0)
+                       goto bad;
                if (dflag) {
                        fprintf(stderr, "debugging mode off\n");
                        dflag = 0;
                if (dflag) {
                        fprintf(stderr, "debugging mode off\n");
                        dflag = 0;
@@ -186,6 +223,7 @@ loop:
         * Unknown command.
         */
        default:
         * Unknown command.
         */
        default:
+       bad:
                fprintf(stderr, "%s: unknown command; type ? for help\n", cmd);
                break;
        }
                fprintf(stderr, "%s: unknown command; type ? for help\n", cmd);
                break;
        }
@@ -203,8 +241,9 @@ loop:
  * "curdir" is prepended to it. Finally "canon" is called to
  * eliminate any embedded ".." components.
  */
  * "curdir" is prepended to it. Finally "canon" is called to
  * eliminate any embedded ".." components.
  */
-getcmd(curdir, cmd, name)
+getcmd(curdir, cmd, name, ap)
        char *curdir, *cmd, *name;
        char *curdir, *cmd, *name;
+       struct arglist *ap;
 {
        register char *cp;
        static char input[BUFSIZ];
 {
        register char *cp;
        static char input[BUFSIZ];
@@ -214,8 +253,12 @@ getcmd(curdir, cmd, name)
        /*
         * Check to see if still processing arguments.
         */
        /*
         * Check to see if still processing arguments.
         */
-       if (gchain != 0)
-               goto getnextexp;
+       if (ap->head != ap->last) {
+               strcpy(name, ap->head->fname);
+               freename(ap->head->fname);
+               ap->head++;
+               return;
+       }
        if (nextarg != NULL)
                goto getnext;
        /*
        if (nextarg != NULL)
                goto getnext;
        /*
@@ -237,6 +280,7 @@ getcmd(curdir, cmd, name)
         * Copy the command into "cmd".
         */
        cp = copynext(input, cmd);
         * Copy the command into "cmd".
         */
        cp = copynext(input, cmd);
+       ap->cmd = cmd;
        /*
         * If no argument, use curdir as the default.
         */
        /*
         * If no argument, use curdir as the default.
         */
@@ -269,10 +313,10 @@ getnext:
                (void) strcat(output, rawname);
                canon(output, name);
        }
                (void) strcat(output, rawname);
                canon(output, name);
        }
-       expandarg(name);
-getnextexp:
-       strcpy(name, gchain->argval);
-       gchain = gchain->argnxt;
+       expandarg(name, ap);
+       strcpy(name, ap->head->fname);
+       freename(ap->head->fname);
+       ap->head++;
 #      undef rawname
 }
 
 #      undef rawname
 }
 
@@ -327,7 +371,7 @@ copynext(input, output)
 
 /*
  * Canonicalize file names to always start with ``./'' and
 
 /*
  * Canonicalize file names to always start with ``./'' and
- * remove any imbedded ".." components.
+ * remove any imbedded "." and ".." components.
  */
 canon(rawname, canonname)
        char *rawname, *canonname;
  */
 canon(rawname, canonname)
        char *rawname, *canonname;
@@ -342,17 +386,30 @@ canon(rawname, canonname)
        else
                (void) strcpy(canonname, "./");
        (void) strcat(canonname, rawname);
        else
                (void) strcpy(canonname, "./");
        (void) strcat(canonname, rawname);
-       len = strlen(canonname) - 1;
-       if (canonname[len] == '/')
-               canonname[len] = '\0';
        /*
        /*
-        * Eliminate extraneous ".." from pathnames.
+        * Eliminate multiple and trailing '/'s
+        */
+       for (cp = np = canonname; *np != '\0'; cp++) {
+               *cp = *np++;
+               while (*cp == '/' && *np == '/')
+                       np++;
+       }
+       *cp = '\0';
+       if (*--cp == '/')
+               *cp = '\0';
+       /*
+        * Eliminate extraneous "." and ".." from pathnames.
         */
        for (np = canonname; *np != '\0'; ) {
                np++;
                cp = np;
                while (*np != '/' && *np != '\0')
                        np++;
         */
        for (np = canonname; *np != '\0'; ) {
                np++;
                cp = np;
                while (*np != '/' && *np != '\0')
                        np++;
+               if (np - cp == 1 && *cp == '.') {
+                       cp--;
+                       (void) strcpy(cp, np);
+                       np = cp;
+               }
                if (np - cp == 2 && strncmp(cp, "..", 2) == 0) {
                        cp--;
                        while (cp > &canonname[1] && *--cp != '/')
                if (np - cp == 2 && strncmp(cp, "..", 2) == 0) {
                        cp--;
                        while (cp > &canonname[1] && *--cp != '/')
@@ -371,49 +428,44 @@ canon(rawname, canonname)
  * "[...]" in params matches character class
  * "[...a-z...]" in params matches a through z.
  */
  * "[...]" in params matches character class
  * "[...a-z...]" in params matches a through z.
  */
-expandarg(arg)
+expandarg(arg, ap)
        char *arg;
        char *arg;
+       register struct arglist *ap;
 {
 {
-       static char *expbuf = NULL;
-       static unsigned expsize = BUFSIZ;
+       static struct afile single;
+       struct entry *ep;
        int size;
        int size;
-       char argbuf[BUFSIZ];
-
-       do {
-               if (expbuf != NULL)
-                       free(expbuf);
-               expbuf = malloc(expsize);
-               brkend = expbuf + expsize;
-               expsize <<= 1;
-               stakbot = (struct argnod *)expbuf;
-               gchain = 0;
-               (void)strcpy(argbuf, arg);
-               size = expand(argbuf, 0);
-       } while (size < 0);
+
+       ap->head = ap->last = (struct afile *)0;
+       size = expand(arg, 0, ap);
        if (size == 0) {
        if (size == 0) {
-               gchain = (struct argnod *)expbuf;
-               gchain->argnxt = 0;
-               (void)strcpy(gchain->argval, arg);
+               ep = lookupname(arg);
+               single.fnum = ep ? ep->e_ino : 0;
+               single.fname = savename(arg);
+               ap->head = &single;
+               ap->last = ap->head + 1;
+               return;
        }
        }
+       qsort((char *)ap->head, ap->last - ap->head, sizeof *ap->head, fcmp);
 }
 
 /*
  * Expand a file name
  */
 }
 
 /*
  * Expand a file name
  */
-expand(as, rflg)
+expand(as, rflg, ap)
        char *as;
        int rflg;
        char *as;
        int rflg;
+       register struct arglist *ap;
 {
        int             count, size;
        char            dir = 0;
        char            *rescan = 0;
        DIR             *dirp;
        register char   *s, *cs;
 {
        int             count, size;
        char            dir = 0;
        char            *rescan = 0;
        DIR             *dirp;
        register char   *s, *cs;
-       struct argnod   *schain = gchain;
+       int             sindex, rindex, lindex;
        struct direct   *dp;
        register char   slash; 
        register char   *rs; 
        struct direct   *dp;
        register char   slash; 
        register char   *rs; 
-       struct argnod   *rchain;
        register char   c;
 
        /*
        register char   c;
 
        /*
@@ -422,18 +474,18 @@ expand(as, rflg)
        s = cs = as;
        slash = 0;
        while (*cs != '*' && *cs != '?' && *cs != '[') {        
        s = cs = as;
        slash = 0;
        while (*cs != '*' && *cs != '?' && *cs != '[') {        
-               if (*cs++==0) { 
+               if (*cs++ == 0) {       
                        if (rflg && slash)
                                break; 
                        else
                                return (0) ;
                        if (rflg && slash)
                                break; 
                        else
                                return (0) ;
-               } else if (*cs=='/') {  
+               } else if (*cs == '/') {        
                        slash++;
                }
        }
        for (;;) {      
                if (cs == s) {  
                        slash++;
                }
        }
        for (;;) {      
                if (cs == s) {  
-                       s = nullstr;
+                       s = "";
                        break;
                } else if (*--cs == '/') {      
                        *cs = 0;
                        break;
                } else if (*--cs == '/') {      
                        *cs = 0;
@@ -446,7 +498,7 @@ expand(as, rflg)
                dir++;
        count = 0;
        if (*cs == 0)
                dir++;
        count = 0;
        if (*cs == 0)
-               *cs++=0200 ;
+               *cs++ = 0200;
        if (dir) {
                /*
                 * check for rescan
        if (dir) {
                /*
                 * check for rescan
@@ -456,33 +508,38 @@ expand(as, rflg)
                        if (*rs == '/') { 
                                rescan = rs; 
                                *rs = 0; 
                        if (*rs == '/') { 
                                rescan = rs; 
                                *rs = 0; 
-                               gchain = 0 ;
                        }
                } while (*rs++);
                        }
                } while (*rs++);
+               sindex = ap->last - ap->head;
                while ((dp = rst_readdir(dirp)) != NULL && dp->d_ino != 0) {
                        if (!dflag && BIT(dp->d_ino, dumpmap) == 0)
                                continue;
                        if ((*dp->d_name == '.' && *cs != '.'))
                                continue;
                        if (gmatch(dp->d_name, cs)) {   
                while ((dp = rst_readdir(dirp)) != NULL && dp->d_ino != 0) {
                        if (!dflag && BIT(dp->d_ino, dumpmap) == 0)
                                continue;
                        if ((*dp->d_name == '.' && *cs != '.'))
                                continue;
                        if (gmatch(dp->d_name, cs)) {   
-                               if (addg(s, dp->d_name, rescan) < 0)
+                               if (addg(dp, s, rescan, ap) < 0)
                                        return (-1);
                                count++;
                        }
                }
                if (rescan) {   
                                        return (-1);
                                count++;
                        }
                }
                if (rescan) {   
-                       rchain = gchain
-                       gchain = schain;
+                       rindex = sindex
+                       lindex = ap->last - ap->head;
                        if (count) {    
                                count = 0;
                        if (count) {    
                                count = 0;
-                               while (rchain) {        
-                                       size = expand(rchain->argval, 1);
+                               while (rindex < lindex) {       
+                                       size = expand(ap->head[rindex].fname,
+                                           1, ap);
                                        if (size < 0)
                                                return (size);
                                        count += size;
                                        if (size < 0)
                                                return (size);
                                        count += size;
-                                       rchain = rchain->argnxt;
+                                       rindex++;
                                }
                        }
                                }
                        }
+                       bcopy((char *)&ap->head[lindex],
+                            (char *)&ap->head[sindex],
+                            (ap->last - &ap->head[rindex]) * sizeof *ap->head);
+                       ap->last -= lindex - sindex;
                        *rescan = '/';
                }
        }
                        *rescan = '/';
                }
        }
@@ -512,7 +569,7 @@ gmatch(s, p)
                ok = 0; 
                lc = 077777;
                while (c = *p++) {      
                ok = 0; 
                lc = 077777;
                while (c = *p++) {      
-                       if (c==']') {
+                       if (c == ']') {
                                return (ok ? gmatch(s, p) : 0);
                        } else if (c == '-') {  
                                if (lc <= scc && scc <= (*p++))
                                return (ok ? gmatch(s, p) : 0);
                        } else if (c == '-') {  
                                if (lc <= scc && scc <= (*p++))
@@ -550,24 +607,25 @@ gmatch(s, p)
 /*
  * Construct a matched name.
  */
 /*
  * Construct a matched name.
  */
-addg(as1, as2, as3)
-       char            *as1, *as2, *as3;
+addg(dp, as1, as3, ap)
+       struct direct   *dp;
+       char            *as1, *as3;
+       struct arglist  *ap;
 {
        register char   *s1, *s2;
        register int    c;
 {
        register char   *s1, *s2;
        register int    c;
+       char            buf[BUFSIZ];
 
 
-       if ((s2 = (char *)locstak()) == 0)
-               return (-1);
-       s2 += sizeof(char *);
+       s2 = buf;
        s1 = as1;
        while (c = *s1++) {     
                if ((c &= 0177) == 0) { 
        s1 = as1;
        while (c = *s1++) {     
                if ((c &= 0177) == 0) { 
-                       *s2++='/';
+                       *s2++ = '/';
                        break;
                }
                *s2++ = c;
        }
                        break;
                }
                *s2++ = c;
        }
-       s1 = as2;
+       s1 = dp->d_name;
        while (*s2 = *s1++)
                s2++;
        if (s1 = as3) { 
        while (*s2 = *s1++)
                s2++;
        if (s1 = as3) { 
@@ -575,47 +633,8 @@ addg(as1, as2, as3)
                while (*s2++ = *++s1)
                        /* void */;
        }
                while (*s2++ = *++s1)
                        /* void */;
        }
-       makearg(endstak(s2));
-       return (0);
-}
-
-/*
- * Add a matched name to the list.
- */
-makearg(args)
-       register struct argnod *args;
-{
-       args->argnxt = gchain;
-       gchain = args;
-}
-
-/*
- * set up stack for local use
- * should be followed by `endstak'
- */
-struct argnod *
-locstak()
-{
-       if (brkend - (char *)stakbot < 100) {   
-               fprintf(stderr, "ran out of arg space\n");
-               return (0);
-       }
-       return (stakbot);
-}
-
-/*
- * tidy up after `locstak'
- */
-struct argnod *
-endstak(argp)
-       register char *argp;
-{
-       register struct argnod *oldstak;
-
-       *argp++ = 0;
-       oldstak = stakbot;
-       stakbot = staktop = (struct argnod *)round((int)argp, sizeof(char *));
-       return (oldstak);
+       if (mkentry(buf, dp->d_ino, ap) == FAIL)
+               return (-1);
 }
 
 /*
 }
 
 /*
@@ -627,91 +646,98 @@ printlist(name, ino, basename)
        char *basename;
 {
        register struct afile *fp;
        char *basename;
 {
        register struct afile *fp;
-       struct afile *dfp0, *dfplast;
+       register struct direct *dp;
+       static struct arglist alist = { 0, 0, 0, 0, "ls" };
        struct afile single;
        DIR *dirp;
 
        if ((dirp = rst_opendir(name)) == NULL) {
                single.fnum = ino;
        struct afile single;
        DIR *dirp;
 
        if ((dirp = rst_opendir(name)) == NULL) {
                single.fnum = ino;
-               single.fname = savename(name + strlen(basename));
-               dfp0 = &single;
-               dfplast = dfp0 + 1;
+               single.fname = savename(name + strlen(basename) + 1);
+               alist.head = &single;
+               alist.last = alist.head + 1;
        } else {
        } else {
-               if (getdir(dirp, &dfp0, &dfplast) == FAIL)
-                       return;
+               alist.head = (struct afile *)0;
+               fprintf(stderr, "%s:\n", name);
+               while (dp = rst_readdir(dirp)) {
+                       if (dp == NULL || dp->d_ino == 0)
+                               break;
+                       if (!dflag && BIT(dp->d_ino, dumpmap) == 0)
+                               continue;
+                       if (vflag == 0 &&
+                           (strcmp(dp->d_name, ".") == 0 ||
+                            strcmp(dp->d_name, "..") == 0))
+                               continue;
+                       if (!mkentry(dp->d_name, dp->d_ino, &alist))
+                               return;
+               }
        }
        }
-       qsort((char *)dfp0, dfplast - dfp0, sizeof (struct afile), fcmp);
-       formatf(dfp0, dfplast);
-       for (fp = dfp0; fp < dfplast; fp++)
-               freename(fp->fname);
+       if (alist.head != 0) {
+               qsort((char *)alist.head, alist.last - alist.head,
+                       sizeof *alist.head, fcmp);
+               formatf(&alist);
+               for (fp = alist.head; fp < alist.last; fp++)
+                       freename(fp->fname);
+       }
+       if (dirp != NULL)
+               fprintf(stderr, "\n");
 }
 
 /*
  * Read the contents of a directory.
  */
 }
 
 /*
  * Read the contents of a directory.
  */
-getdir(dirp, pfp0, pfplast)
-       DIR *dirp;
-       struct afile **pfp0, **pfplast;
+mkentry(name, ino, ap)
+       char *name;
+       ino_t ino;
+       register struct arglist *ap;
 {
        register struct afile *fp;
 {
        register struct afile *fp;
-       register struct direct *dp;
-       static struct afile *basefp = NULL;
-       static long nent = 20;
 
 
-       if (basefp == NULL) {
-               basefp = (struct afile *)calloc((unsigned)nent,
+       if (ap->base == NULL) {
+               ap->nent = 20;
+               ap->base = (struct afile *)calloc((unsigned)ap->nent,
                        sizeof (struct afile));
                        sizeof (struct afile));
-               if (basefp == NULL) {
-                       fprintf(stderr, "ls: out of memory\n");
+               if (ap->base == NULL) {
+                       fprintf(stderr, "%s: out of memory\n", ap->cmd);
                        return (FAIL);
                }
        }
                        return (FAIL);
                }
        }
-       fp = *pfp0 = basefp;
-       *pfplast = *pfp0 + nent;
-       while (dp = rst_readdir(dirp)) {
-               if (dp == NULL || dp->d_ino == 0)
-                       break;
-               if (!dflag && BIT(dp->d_ino, dumpmap) == 0)
-                       continue;
-               if (vflag == 0 &&
-                   (strcmp(dp->d_name, ".") == 0 ||
-                    strcmp(dp->d_name, "..") == 0))
-                       continue;
-               fp->fnum = dp->d_ino;
-               fp->fname = savename(dp->d_name);
-               fp++;
-               if (fp == *pfplast) {
-                       basefp = (struct afile *)realloc((char *)basefp,
-                           (unsigned)(2 * nent * sizeof (struct afile)));
-                       if (basefp == 0) {
-                               fprintf(stderr, "ls: out of memory\n");
-                               return (FAIL);
-                       }
-                       *pfp0 = basefp;
-                       fp = *pfp0 + nent;
-                       *pfplast = fp + nent;
-                       nent *= 2;
+       if (ap->head == 0)
+               ap->head = ap->last = ap->base;
+       fp = ap->last;
+       fp->fnum = ino;
+       fp->fname = savename(name);
+       fp++;
+       if (fp == ap->head + ap->nent) {
+               ap->base = (struct afile *)realloc((char *)ap->base,
+                   (unsigned)(2 * ap->nent * sizeof (struct afile)));
+               if (ap->base == 0) {
+                       fprintf(stderr, "%s: out of memory\n", ap->cmd);
+                       return (FAIL);
                }
                }
+               ap->head = ap->base;
+               fp = ap->head + ap->nent;
+               ap->nent *= 2;
        }
        }
-       *pfplast = fp;
+       ap->last = fp;
        return (GOOD);
 }
 
 /*
  * Print out a pretty listing of a directory
  */
        return (GOOD);
 }
 
 /*
  * Print out a pretty listing of a directory
  */
-formatf(fp0, fplast)
-       struct afile *fp0, *fplast;
+formatf(ap)
+       register struct arglist *ap;
 {
        register struct afile *fp;
        struct entry *np;
 {
        register struct afile *fp;
        struct entry *np;
-       int width = 0, w, nentry = fplast - fp0;
+       int width = 0, w, nentry = ap->last - ap->head;
        int i, j, len, columns, lines;
        char *cp;
 
        int i, j, len, columns, lines;
        char *cp;
 
-       if (fp0 == fplast)
+       if (ap->head == ap->last)
                return;
                return;
-       for (fp = fp0; fp < fplast; fp++) {
+       for (fp = ap->head; fp < ap->last; fp++) {
                fp->ftype = inodetype(fp->fnum);
                np = lookupino(fp->fnum);
                if (np != NIL)
                fp->ftype = inodetype(fp->fnum);
                np = lookupino(fp->fnum);
                if (np != NIL)
@@ -729,10 +755,10 @@ formatf(fp0, fplast)
        lines = (nentry + columns - 1) / columns;
        for (i = 0; i < lines; i++) {
                for (j = 0; j < columns; j++) {
        lines = (nentry + columns - 1) / columns;
        for (i = 0; i < lines; i++) {
                for (j = 0; j < columns; j++) {
-                       fp = fp0 + j * lines + i;
+                       fp = ap->head + j * lines + i;
                        cp = fmtentry(fp);
                        fprintf(stderr, "%s", cp);
                        cp = fmtentry(fp);
                        fprintf(stderr, "%s", cp);
-                       if (fp + lines >= fplast) {
+                       if (fp + lines >= ap->last) {
                                fprintf(stderr, "\n");
                                break;
                        }
                                fprintf(stderr, "\n");
                                break;
                        }
@@ -763,12 +789,18 @@ fmtentry(fp)
        register struct afile *fp;
 {
        static char fmtres[BUFSIZ];
        register struct afile *fp;
 {
        static char fmtres[BUFSIZ];
+       static int precision = 0;
+       int i;
        register char *cp, *dp;
 
        register char *cp, *dp;
 
-       if (vflag)
-               (void) sprintf(fmtres, "%5d ", fp->fnum);
-       else
+       if (!vflag) {
                fmtres[0] = '\0';
                fmtres[0] = '\0';
+       } else {
+               if (precision == 0)
+                       for (i = maxino; i > 0; i /= 10)
+                               precision++;
+               (void) sprintf(fmtres, "%*d ", precision, fp->fnum);
+       }
        dp = &fmtres[strlen(fmtres)];
        if (dflag && BIT(fp->fnum, dumpmap) == 0)
                *dp++ = '^';
        dp = &fmtres[strlen(fmtres)];
        if (dflag && BIT(fp->fnum, dumpmap) == 0)
                *dp++ = '^';