home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sbin / restore / interactive.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-01  |  16.8 KB  |  757 lines

  1. /*
  2.  * Copyright (c) 1985 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)interactive.c    5.18 (Berkeley) 12/2/92";
  36. #endif /* not lint */
  37.  
  38. #include <sys/param.h>
  39. #include <sys/time.h>
  40. #include <sys/stat.h>
  41.  
  42. #include <ufs/ffs/fs.h>
  43. #include <ufs/ufs/dinode.h>
  44. #include <ufs/ufs/dir.h>
  45. #include <protocols/dumprestore.h>
  46.  
  47. #include <setjmp.h>
  48. #include <glob.h>
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <string.h>
  52.  
  53. #include "restore.h"
  54. #include "extern.h"
  55.  
  56. #define round(a, b) (((a) + (b) - 1) / (b) * (b))
  57.  
  58. /*
  59.  * Things to handle interruptions.
  60.  */
  61. static int runshell;
  62. static jmp_buf reset;
  63. static char *nextarg = NULL;
  64.  
  65. /*
  66.  * Structure and routines associated with listing directories.
  67.  */
  68. struct afile {
  69.     ino_t    fnum;        /* inode number of file */
  70.     char    *fname;        /* file name */
  71.     short    len;        /* name length */
  72.     char    prefix;        /* prefix character */
  73.     char    postfix;    /* postfix character */
  74. };
  75. struct arglist {
  76.     int    freeglob;    /* glob structure needs to be freed */
  77.     int    argcnt;        /* next globbed argument to return */
  78.     glob_t    glob;        /* globbing information */
  79.     char    *cmd;        /* the current command */
  80. };
  81.  
  82. static char    *copynext __P((char *, char *));
  83. static int     fcmp __P((const void *, const void *));
  84. static char    *fmtentry __P((struct afile *));
  85. static void     formatf __P((struct afile *, int));
  86. static void     getcmd __P((char *, char *, char *, struct arglist *));
  87. struct dirent    *glob_readdir __P((RST_DIR *dirp));
  88. static int     glob_stat __P((char *, struct stat *));
  89. static void     mkentry __P((struct direct *, struct afile *));
  90. static void     printlist __P((char *, char *));
  91.  
  92. /*
  93.  * Read and execute commands from the terminal.
  94.  */
  95. void
  96. runcmdshell()
  97. {
  98.     register struct entry *np;
  99.     ino_t ino;
  100.     struct arglist arglist;
  101.     char curdir[MAXPATHLEN];
  102.     char name[MAXPATHLEN];
  103.     char cmd[BUFSIZ];
  104.  
  105.     arglist.freeglob = 0;
  106.     arglist.argcnt = 0;
  107.     arglist.glob.gl_flags = GLOB_ALTDIRFUNC;
  108.     arglist.glob.gl_opendir = (void *)rst_opendir;
  109.     arglist.glob.gl_readdir = (void *)glob_readdir;
  110.     arglist.glob.gl_closedir = rst_closedir;
  111.     arglist.glob.gl_lstat = glob_stat;
  112.     arglist.glob.gl_stat = glob_stat;
  113.     canon("/", curdir);
  114. loop:
  115.     if (setjmp(reset) != 0) {
  116.         if (arglist.freeglob != 0) {
  117.             arglist.freeglob = 0;
  118.             arglist.argcnt = 0;
  119.             globfree(&arglist.glob);
  120.         }
  121.         nextarg = NULL;
  122.         volno = 0;
  123.     }
  124.     runshell = 1;
  125.     getcmd(curdir, cmd, name, &arglist);
  126.     switch (cmd[0]) {
  127.     /*
  128.      * Add elements to the extraction list.
  129.      */
  130.     case 'a':
  131.         if (strncmp(cmd, "add", strlen(cmd)) != 0)
  132.             goto bad;
  133.         ino = dirlookup(name);
  134.         if (ino == 0)
  135.             break;
  136.         if (mflag)
  137.             pathcheck(name);
  138.         treescan(name, ino, addfile);
  139.         break;
  140.     /*
  141.      * Change working directory.
  142.      */
  143.     case 'c':
  144.         if (strncmp(cmd, "cd", strlen(cmd)) != 0)
  145.             goto bad;
  146.         ino = dirlookup(name);
  147.         if (ino == 0)
  148.             break;
  149.         if (inodetype(ino) == LEAF) {
  150.             fprintf(stderr, "%s: not a directory\n", name);
  151.             break;
  152.         }
  153.         (void) strcpy(curdir, name);
  154.         break;
  155.     /*
  156.      * Delete elements from the extraction list.
  157.      */
  158.     case 'd':
  159.         if (strncmp(cmd, "delete", strlen(cmd)) != 0)
  160.             goto bad;
  161.         np = lookupname(name);
  162.         if (np == NULL || (np->e_flags & NEW) == 0) {
  163.             fprintf(stderr, "%s: not on extraction list\n", name);
  164.             break;
  165.         }
  166.         treescan(name, np->e_ino, deletefile);
  167.         break;
  168.     /*
  169.      * Extract the requested list.
  170.      */
  171.     case 'e':
  172.         if (strncmp(cmd, "extract", strlen(cmd)) != 0)
  173.             goto bad;
  174.         createfiles();
  175.         createlinks();
  176.         setdirmodes(0);
  177.         if (dflag)
  178.             checkrestore();
  179.         volno = 0;
  180.         break;
  181.     /*
  182.      * List available commands.
  183.      */
  184.     case 'h':
  185.         if (strncmp(cmd, "help", strlen(cmd)) != 0)
  186.             goto bad;
  187.     case '?':
  188.         fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
  189.             "Available commands are:\n",
  190.             "\tls [arg] - list directory\n",
  191.             "\tcd arg - change directory\n",
  192.             "\tpwd - print current directory\n",
  193.             "\tadd [arg] - add `arg' to list of",
  194.             " files to be extracted\n",
  195.             "\tdelete [arg] - delete `arg' from",
  196.             " list of files to be extracted\n",
  197.             "\textract - extract requested files\n",
  198.             "\tsetmodes - set modes of requested directories\n",
  199.             "\tquit - immediately exit program\n",
  200.             "\twhat - list dump header information\n",
  201.             "\tverbose - toggle verbose flag",
  202.             " (useful with ``ls'')\n",
  203.             "\thelp or `?' - print this list\n",
  204.             "If no `arg' is supplied, the current",
  205.             " directory is used\n");
  206.         break;
  207.     /*
  208.      * List a directory.
  209.      */
  210.     case 'l':
  211.         if (strncmp(cmd, "ls", strlen(cmd)) != 0)
  212.             goto bad;
  213.         printlist(name, curdir);
  214.         break;
  215.     /*
  216.      * Print current directory.
  217.      */
  218.     case 'p':
  219.         if (strncmp(cmd, "pwd", strlen(cmd)) != 0)
  220.             goto bad;
  221.         if (curdir[1] == '\0')
  222.             fprintf(stderr, "/\n");
  223.         else
  224.             fprintf(stderr, "%s\n", &curdir[1]);
  225.         break;
  226.     /*
  227.      * Quit.
  228.      */
  229.     case 'q':
  230.         if (strncmp(cmd, "quit", strlen(cmd)) != 0)
  231.             goto bad;
  232.         return;
  233.     case 'x':
  234.         if (strncmp(cmd, "xit", strlen(cmd)) != 0)
  235.             goto bad;
  236.         return;
  237.     /*
  238.      * Toggle verbose mode.
  239.      */
  240.     case 'v':
  241.         if (strncmp(cmd, "verbose", strlen(cmd)) != 0)
  242.             goto bad;
  243.         if (vflag) {
  244.             fprintf(stderr, "verbose mode off\n");
  245.             vflag = 0;
  246.             break;
  247.         }
  248.         fprintf(stderr, "verbose mode on\n");
  249.         vflag++;
  250.         break;
  251.     /*
  252.      * Just restore requested directory modes.
  253.      */
  254.     case 's':
  255.         if (strncmp(cmd, "setmodes", strlen(cmd)) != 0)
  256.             goto bad;
  257.         setdirmodes(FORCE);
  258.         break;
  259.     /*
  260.      * Print out dump header information.
  261.      */
  262.     case 'w':
  263.         if (strncmp(cmd, "what", strlen(cmd)) != 0)
  264.             goto bad;
  265.         printdumpinfo();
  266.         break;
  267.     /*
  268.      * Turn on debugging.
  269.      */
  270.     case 'D':
  271.         if (strncmp(cmd, "Debug", strlen(cmd)) != 0)
  272.             goto bad;
  273.         if (dflag) {
  274.             fprintf(stderr, "debugging mode off\n");
  275.             dflag = 0;
  276.             break;
  277.         }
  278.         fprintf(stderr, "debugging mode on\n");
  279.         dflag++;
  280.         break;
  281.     /*
  282.      * Unknown command.
  283.      */
  284.     default:
  285.     bad:
  286.         fprintf(stderr, "%s: unknown command; type ? for help\n", cmd);
  287.         break;
  288.     }
  289.     goto loop;
  290. }
  291.  
  292. /*
  293.  * Read and parse an interactive command.
  294.  * The first word on the line is assigned to "cmd". If
  295.  * there are no arguments on the command line, then "curdir"
  296.  * is returned as the argument. If there are arguments
  297.  * on the line they are returned one at a time on each
  298.  * successive call to getcmd. Each argument is first assigned
  299.  * to "name". If it does not start with "/" the pathname in
  300.  * "curdir" is prepended to it. Finally "canon" is called to
  301.  * eliminate any embedded ".." components.
  302.  */
  303. static void
  304. getcmd(curdir, cmd, name, ap)
  305.     char *curdir, *cmd, *name;
  306.     struct arglist *ap;
  307. {
  308.     register char *cp;
  309.     static char input[BUFSIZ];
  310.     char output[BUFSIZ];
  311. #    define rawname input    /* save space by reusing input buffer */
  312.  
  313.     /*
  314.      * Check to see if still processing arguments.
  315.      */
  316.     if (ap->argcnt > 0)
  317.         goto retnext;
  318.     if (nextarg != NULL)
  319.         goto getnext;
  320.     /*
  321.      * Read a command line and trim off trailing white space.
  322.      */
  323.     do    {
  324.         fprintf(stderr, "restore > ");
  325.         (void) fflush(stderr);
  326.         (void) fgets(input, BUFSIZ, terminal);
  327.     } while (!feof(terminal) && input[0] == '\n');
  328.     if (feof(terminal)) {
  329.         (void) strcpy(cmd, "quit");
  330.         return;
  331.     }
  332.     for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--)
  333.         /* trim off trailing white space and newline */;
  334.     *++cp = '\0';
  335.     /*
  336.      * Copy the command into "cmd".
  337.      */
  338.     cp = copynext(input, cmd);
  339.     ap->cmd = cmd;
  340.     /*
  341.      * If no argument, use curdir as the default.
  342.      */
  343.     if (*cp == '\0') {
  344.         (void) strcpy(name, curdir);
  345.         return;
  346.     }
  347.     nextarg = cp;
  348.     /*
  349.      * Find the next argument.
  350.      */
  351. getnext:
  352.     cp = copynext(nextarg, rawname);
  353.     if (*cp == '\0')
  354.         nextarg = NULL;
  355.     else
  356.         nextarg = cp;
  357.     /*
  358.      * If it is an absolute pathname, canonicalize it and return it.
  359.      */
  360.     if (rawname[0] == '/') {
  361.         canon(rawname, name);
  362.     } else {
  363.         /*
  364.          * For relative pathnames, prepend the current directory to
  365.          * it then canonicalize and return it.
  366.          */
  367.         (void) strcpy(output, curdir);
  368.         (void) strcat(output, "/");
  369.         (void) strcat(output, rawname);
  370.         canon(output, name);
  371.     }
  372.     if (glob(name, GLOB_ALTDIRFUNC, NULL, &ap->glob) < 0)
  373.         fprintf(stderr, "%s: out of memory\n", ap->cmd);
  374.     if (ap->glob.gl_pathc == 0)
  375.         return;
  376.     ap->freeglob = 1;
  377.     ap->argcnt = ap->glob.gl_pathc;
  378.  
  379. retnext:
  380.     strcpy(name, ap->glob.gl_pathv[ap->glob.gl_pathc - ap->argcnt]);
  381.     if (--ap->argcnt == 0) {
  382.         ap->freeglob = 0;
  383.         globfree(&ap->glob);
  384.     }
  385. #    undef rawname
  386. }
  387.  
  388. /*
  389.  * Strip off the next token of the input.
  390.  */
  391. static char *
  392. copynext(input, output)
  393.     char *input, *output;
  394. {
  395.     register char *cp, *bp;
  396.     char quote;
  397.  
  398.     for (cp = input; *cp == ' ' || *cp == '\t'; cp++)
  399.         /* skip to argument */;
  400.     bp = output;
  401.     while (*cp != ' ' && *cp != '\t' && *cp != '\0') {
  402.         /*
  403.          * Handle back slashes.
  404.          */
  405.         if (*cp == '\\') {
  406.             if (*++cp == '\0') {
  407.                 fprintf(stderr,
  408.                     "command lines cannot be continued\n");
  409.                 continue;
  410.             }
  411.             *bp++ = *cp++;
  412.             continue;
  413.         }
  414.         /*
  415.          * The usual unquoted case.
  416.          */
  417.         if (*cp != '\'' && *cp != '"') {
  418.             *bp++ = *cp++;
  419.             continue;
  420.         }
  421.         /*
  422.          * Handle single and double quotes.
  423.          */
  424.         quote = *cp++;
  425.         while (*cp != quote && *cp != '\0')
  426.             *bp++ = *cp++ | 0200;
  427.         if (*cp++ == '\0') {
  428.             fprintf(stderr, "missing %c\n", quote);
  429.             cp--;
  430.             continue;
  431.         }
  432.     }
  433.     *bp = '\0';
  434.     return (cp);
  435. }
  436.  
  437. /*
  438.  * Canonicalize file names to always start with ``./'' and
  439.  * remove any imbedded "." and ".." components.
  440.  */
  441. void
  442. canon(rawname, canonname)
  443.     char *rawname, *canonname;
  444. {
  445.     register char *cp, *np;
  446.  
  447.     if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0)
  448.         (void) strcpy(canonname, "");
  449.     else if (rawname[0] == '/')
  450.         (void) strcpy(canonname, ".");
  451.     else
  452.         (void) strcpy(canonname, "./");
  453.     (void) strcat(canonname, rawname);
  454.     /*
  455.      * Eliminate multiple and trailing '/'s
  456.      */
  457.     for (cp = np = canonname; *np != '\0'; cp++) {
  458.         *cp = *np++;
  459.         while (*cp == '/' && *np == '/')
  460.             np++;
  461.     }
  462.     *cp = '\0';
  463.     if (*--cp == '/')
  464.         *cp = '\0';
  465.     /*
  466.      * Eliminate extraneous "." and ".." from pathnames.
  467.      */
  468.     for (np = canonname; *np != '\0'; ) {
  469.         np++;
  470.         cp = np;
  471.         while (*np != '/' && *np != '\0')
  472.             np++;
  473.         if (np - cp == 1 && *cp == '.') {
  474.             cp--;
  475.             (void) strcpy(cp, np);
  476.             np = cp;
  477.         }
  478.         if (np - cp == 2 && strncmp(cp, "..", 2) == 0) {
  479.             cp--;
  480.             while (cp > &canonname[1] && *--cp != '/')
  481.                 /* find beginning of name */;
  482.             (void) strcpy(cp, np);
  483.             np = cp;
  484.         }
  485.     }
  486. }
  487.  
  488. /*
  489.  * Do an "ls" style listing of a directory
  490.  */
  491. static void
  492. printlist(name, basename)
  493.     char *name;
  494.     char *basename;
  495. {
  496.     register struct afile *fp, *list, *listp;
  497.     register struct direct *dp;
  498.     struct afile single;
  499.     RST_DIR *dirp;
  500.     int entries, len;
  501.  
  502.     dp = pathsearch(name);
  503.     if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0))
  504.         return;
  505.     if ((dirp = rst_opendir(name)) == NULL) {
  506.         entries = 1;
  507.         list = &single;
  508.         mkentry(dp, list);
  509.         len = strlen(basename) + 1;
  510.         if (strlen(name) - len > single.len) {
  511.             freename(single.fname);
  512.             single.fname = savename(&name[len]);
  513.             single.len = strlen(single.fname);
  514.         }
  515.     } else {
  516.         entries = 0;
  517.         while (dp = rst_readdir(dirp))
  518.             entries++;
  519.         rst_closedir(dirp);
  520.         list = (struct afile *)malloc(entries * sizeof(struct afile));
  521.         if (list == NULL) {
  522.             fprintf(stderr, "ls: out of memory\n");
  523.             return;
  524.         }
  525.         if ((dirp = rst_opendir(name)) == NULL)
  526.             panic("directory reopen failed\n");
  527.         fprintf(stderr, "%s:\n", name);
  528.         entries = 0;
  529.         listp = list;
  530.         while (dp = rst_readdir(dirp)) {
  531.             if (dp == NULL || dp->d_ino == 0)
  532.                 break;
  533.             if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0)
  534.                 continue;
  535.             if (vflag == 0 &&
  536.                 (strcmp(dp->d_name, ".") == 0 ||
  537.                  strcmp(dp->d_name, "..") == 0))
  538.                 continue;
  539.             mkentry(dp, listp++);
  540.             entries++;
  541.         }
  542.         rst_closedir(dirp);
  543.         if (entries == 0) {
  544.             fprintf(stderr, "\n");
  545.             free(list);
  546.             return;
  547.         }
  548.         qsort((char *)list, entries, sizeof(struct afile), fcmp);
  549.     }
  550.     formatf(list, entries);
  551.     if (dirp != NULL) {
  552.         for (fp = listp - 1; fp >= list; fp--)
  553.             freename(fp->fname);
  554.         fprintf(stderr, "\n");
  555.         free(list);
  556.     }
  557. }
  558.  
  559. /*
  560.  * Read the contents of a directory.
  561.  */
  562. static void
  563. mkentry(dp, fp)
  564.     struct direct *dp;
  565.     register struct afile *fp;
  566. {
  567.     char *cp;
  568.     struct entry *np;
  569.  
  570.     fp->fnum = dp->d_ino;
  571.     fp->fname = savename(dp->d_name);
  572.     for (cp = fp->fname; *cp; cp++)
  573.         if (!vflag && (*cp < ' ' || *cp >= 0177))
  574.             *cp = '?';
  575.     fp->len = cp - fp->fname;
  576.     if (dflag && TSTINO(fp->fnum, dumpmap) == 0)
  577.         fp->prefix = '^';
  578.     else if ((np = lookupino(fp->fnum)) != NULL && (np->e_flags & NEW))
  579.         fp->prefix = '*';
  580.     else
  581.         fp->prefix = ' ';
  582.     switch(dp->d_type) {
  583.  
  584.     default:
  585.         fprintf(stderr, "Warning: undefined file type %d\n",
  586.             dp->d_type);
  587.         /* fall through */
  588.     case DT_REG:
  589.         fp->postfix = ' ';
  590.         break;
  591.  
  592.     case DT_LNK:
  593.         fp->postfix = '@';
  594.         break;
  595.  
  596.     case DT_FIFO:
  597.     case DT_SOCK:
  598.         fp->postfix = '=';
  599.         break;
  600.  
  601.     case DT_CHR:
  602.     case DT_BLK:
  603.         fp->postfix = '#';
  604.         break;
  605.  
  606.     case DT_UNKNOWN:
  607.     case DT_DIR:
  608.         if (inodetype(dp->d_ino) == NODE)
  609.             fp->postfix = '/';
  610.         else
  611.             fp->postfix = ' ';
  612.         break;
  613.     }
  614.     return;
  615. }
  616.  
  617. /*
  618.  * Print out a pretty listing of a directory
  619.  */
  620. static void
  621. formatf(list, nentry)
  622.     register struct afile *list;
  623.     int nentry;
  624. {
  625.     register struct afile *fp, *endlist;
  626.     int width, bigino, haveprefix, havepostfix;
  627.     int i, j, w, precision, columns, lines;
  628.  
  629.     width = 0;
  630.     haveprefix = 0;
  631.     havepostfix = 0;
  632.     bigino = ROOTINO;
  633.     endlist = &list[nentry];
  634.     for (fp = &list[0]; fp < endlist; fp++) {
  635.         if (bigino < fp->fnum)
  636.             bigino = fp->fnum;
  637.         if (width < fp->len)
  638.             width = fp->len;
  639.         if (fp->prefix != ' ')
  640.             haveprefix = 1;
  641.         if (fp->postfix != ' ')
  642.             havepostfix = 1;
  643.     }
  644.     if (haveprefix)
  645.         width++;
  646.     if (havepostfix)
  647.         width++;
  648.     if (vflag) {
  649.         for (precision = 0, i = bigino; i > 0; i /= 10)
  650.             precision++;
  651.         width += precision + 1;
  652.     }
  653.     width++;
  654.     columns = 81 / width;
  655.     if (columns == 0)
  656.         columns = 1;
  657.     lines = (nentry + columns - 1) / columns;
  658.     for (i = 0; i < lines; i++) {
  659.         for (j = 0; j < columns; j++) {
  660.             fp = &list[j * lines + i];
  661.             if (vflag) {
  662.                 fprintf(stderr, "%*d ", precision, fp->fnum);
  663.                 fp->len += precision + 1;
  664.             }
  665.             if (haveprefix) {
  666.                 putc(fp->prefix, stderr);
  667.                 fp->len++;
  668.             }
  669.             fprintf(stderr, "%s", fp->fname);
  670.             if (havepostfix) {
  671.                 putc(fp->postfix, stderr);
  672.                 fp->len++;
  673.             }
  674.             if (fp + lines >= endlist) {
  675.                 fprintf(stderr, "\n");
  676.                 break;
  677.             }
  678.             for (w = fp->len; w < width; w++)
  679.                 putc(' ', stderr);
  680.         }
  681.     }
  682. }
  683.  
  684. /*
  685.  * Skip over directory entries that are not on the tape
  686.  *
  687.  * First have to get definition of a dirent.
  688.  */
  689. #undef DIRBLKSIZ
  690. #include <dirent.h>
  691. #undef d_ino
  692.  
  693. struct dirent *
  694. glob_readdir(dirp)
  695.     RST_DIR *dirp;
  696. {
  697.     struct direct *dp;
  698.     static struct dirent adirent;
  699.  
  700.     while ((dp = rst_readdir(dirp)) != NULL) {
  701.         if (dp->d_ino == 0)
  702.             continue;
  703.         if (dflag || TSTINO(dp->d_ino, dumpmap))
  704.             break;
  705.     }
  706.     if (dp == NULL)
  707.         return (NULL);
  708.     adirent.d_fileno = dp->d_ino;
  709.     adirent.d_namlen = dp->d_namlen;
  710.     bcopy(dp->d_name, adirent.d_name, dp->d_namlen + 1);
  711.     return (&adirent);
  712. }
  713.  
  714. /*
  715.  * Return st_mode information in response to stat or lstat calls
  716.  */
  717. static int
  718. glob_stat(name, stp)
  719.     char *name;
  720.     struct stat *stp;
  721. {
  722.     register struct direct *dp;
  723.  
  724.     dp = pathsearch(name);
  725.     if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0))
  726.         return (-1);
  727.     if (inodetype(dp->d_ino) == NODE)
  728.         stp->st_mode = IFDIR;
  729.     else
  730.         stp->st_mode = IFREG;
  731.     return (0);
  732. }
  733.  
  734. /*
  735.  * Comparison routine for qsort.
  736.  */
  737. static int
  738. fcmp(f1, f2)
  739.     register const void *f1, *f2;
  740. {
  741.     return (strcmp(((struct afile *)f1)->fname,
  742.         ((struct afile *)f2)->fname));
  743. }
  744.  
  745. /*
  746.  * respond to interrupts
  747.  */
  748. void
  749. onintr(signo)
  750.     int signo;
  751. {
  752.     if (command == 'i' && runshell)
  753.         longjmp(reset, 1);
  754.     if (reply("restore interrupted, continue") == FAIL)
  755.         done(1);
  756. }
  757.