]> git.wh0rd.org - dump.git/blobdiff - restore/interactive.c
Fix restore when symtab file is over 2GB in size.
[dump.git] / restore / interactive.c
index c7b730bdd9b4d5d2b2b68685086b26766a80ad9d..ecbffda09e8a3dde54e457f666529feb24fa1253 100644 (file)
@@ -1,8 +1,9 @@
 /*
  *     Ported to Linux's Second Extended File System as part of the
  *     dump and restore backup suit
- *     Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
- *
+ *     Remy Card <card@Linux.EU.Org>, 1994-1997
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - AlcĂ´ve <www.alcove.com>, 2000-2002
  */
 
 /*
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)interactive.c      8.5 (Berkeley) 5/1/95";
+static const char rcsid[] =
+       "$Id: interactive.c,v 1.27 2003/10/26 16:05:48 stelian Exp $";
 #endif /* not lint */
 
+#include <config.h>
+#include <sys/types.h>
 #include <sys/param.h>
-#include <sys/time.h>
 #include <sys/stat.h>
 
 #ifdef __linux__
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
 #include <linux/ext2_fs.h>
+#endif
 #include <bsdcompat.h>
 #else  /* __linux__ */
+#ifdef sunos
+#include <sys/fcntl.h>
+#include <bsdcompat.h>
+#else
 #include <ufs/ufs/dinode.h>
 #include <ufs/ufs/dir.h>
-#include <ufs/ffs/fs.h>
+#endif
 #endif /* __linux__ */
 #include <protocols/dumprestore.h>
 
 #include <setjmp.h>
-#include <glob.h>
+#include <compaterr.h>
+#include <errno.h>
+#include <compatglob.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -66,9 +75,24 @@ static char sccsid[] = "@(#)interactive.c    8.5 (Berkeley) 5/1/95";
 #include <ext2fs/ext2fs.h>
 #endif
 
+#if defined(__linux__) || defined(sunos)
+extern char * __progname;
+#endif
+
 #include "restore.h"
 #include "extern.h"
 
+#if HAVE_READLINE
+#include <readline/readline.h>
+#include <readline/history.h>
+
+static char *rl_gets (char *prompt);
+static void initialize_readline(void);
+static char **restore_completion (const char *text, int start, int end);
+static char *command_generator(const char *text, int state);
+static char *filename_generator(const char *text, int state);
+#endif
+
 #define round(a, b) (((a) + (b) - 1) / (b) * (b))
 
 /*
@@ -77,12 +101,12 @@ static char sccsid[] = "@(#)interactive.c  8.5 (Berkeley) 5/1/95";
 static int runshell;
 static jmp_buf reset;
 static char *nextarg = NULL;
-
+static int pflag = 0;          /* prompt mode */
 /*
  * Structure and routines associated with listing directories.
  */
 struct afile {
-       ino_t   fnum;           /* inode number of file */
+       dump_ino_t fnum;        /* inode number of file */
        char    *fname;         /* file name */
        short   len;            /* name length */
        char    prefix;         /* prefix character */
@@ -98,7 +122,7 @@ struct arglist {
 static char    *copynext __P((char *, char *));
 static int      fcmp __P((const void *, const void *));
 static void     formatf __P((struct afile *, int));
-static void     getcmd __P((char *, char *, char *, struct arglist *));
+static void     getcmd __P((char *, char *, char *, int, struct arglist *));
 struct dirent  *glob_readdir __P((RST_DIR *dirp));
 static int      glob_stat __P((const char *, struct stat *));
 static void     mkentry __P((char *, struct direct *, struct afile *));
@@ -108,24 +132,27 @@ static void        printlist __P((char *, char *));
  * Read and execute commands from the terminal.
  */
 void
-runcmdshell()
+runcmdshell(void)
 {
-       register struct entry *np;
-       ino_t ino;
+       struct entry *np;
+       dump_ino_t ino;
        struct arglist arglist;
        char curdir[MAXPATHLEN];
        char name[MAXPATHLEN];
        char cmd[BUFSIZ];
 
+#if HAVE_READLINE
+       initialize_readline();
+#endif
        arglist.freeglob = 0;
        arglist.argcnt = 0;
        arglist.glob.gl_flags = GLOB_ALTDIRFUNC;
        arglist.glob.gl_opendir = (void *)rst_opendir;
        arglist.glob.gl_readdir = (void *)glob_readdir;
        arglist.glob.gl_closedir = (void *)rst_closedir;
-       arglist.glob.gl_lstat = glob_stat;
-       arglist.glob.gl_stat = glob_stat;
-       canon("/", curdir);
+       arglist.glob.gl_lstat = (int (*)(const char *, void *))glob_stat;
+       arglist.glob.gl_stat = (int (*)(const char *, void *))glob_stat;
+       canon("/", curdir, sizeof(curdir));
 loop:
        if (setjmp(reset) != 0) {
                if (arglist.freeglob != 0) {
@@ -137,7 +164,7 @@ loop:
                volno = 0;
        }
        runshell = 1;
-       getcmd(curdir, cmd, name, &arglist);
+       getcmd(curdir, cmd, name, sizeof(name), &arglist);
        switch (cmd[0]) {
        /*
         * Add elements to the extraction list.
@@ -165,7 +192,8 @@ loop:
                        fprintf(stderr, "%s: not a directory\n", name);
                        break;
                }
-               (void) strcpy(curdir, name);
+               (void) strncpy(curdir, name, sizeof(curdir));
+               curdir[sizeof(curdir) - 1] = '\0';
                break;
        /*
         * Delete elements from the extraction list.
@@ -188,7 +216,7 @@ loop:
                        goto bad;
                createfiles();
                createlinks();
-               setdirmodes(0);
+               setdirmodes(oflag ? FORCE : 0);
                if (dflag)
                        checkrestore();
                volno = 0;
@@ -200,7 +228,7 @@ loop:
                if (strncmp(cmd, "help", strlen(cmd)) != 0)
                        goto bad;
        case '?':
-               fprintf(stderr, "%s%s%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%s",
                        "Available commands are:\n",
                        "\tls [arg] - list directory\n",
                        "\tcd arg - change directory\n",
@@ -215,6 +243,7 @@ loop:
                        "\twhat - list dump header information\n",
                        "\tverbose - toggle verbose flag",
                        " (useful with ``ls'')\n",
+                       "\tprompt - toggle the prompt display\n",
                        "\thelp or `?' - print this list\n",
                        "If no `arg' is supplied, the current",
                        " directory is used\n");
@@ -231,12 +260,26 @@ loop:
         * Print current directory.
         */
        case 'p':
-               if (strncmp(cmd, "pwd", strlen(cmd)) != 0)
-                       goto bad;
-               if (curdir[1] == '\0')
-                       fprintf(stderr, "/\n");
-               else
-                       fprintf(stderr, "%s\n", &curdir[1]);
+               if (strncmp(cmd, "pwd", strlen(cmd)) == 0) {
+                       if (curdir[1] == '\0')
+                               fprintf(stderr, "/\n");
+                       else
+                               fprintf(stderr, "%s\n", &curdir[1]);
+               }
+       /*
+        * Toggle prompt mode.
+        */
+               else if (strncmp(cmd, "prompt", strlen(cmd)) == 0) {
+                       if (pflag) {
+                               fprintf(stderr, "prompt mode off\n");
+                               pflag = 0;
+                               break;
+                       }
+                       fprintf(stderr, "prompt mode on\n");
+                       pflag++;
+                       break;
+               }
+               else goto bad;
                break;
        /*
         * Quit.
@@ -278,6 +321,7 @@ loop:
                if (strncmp(cmd, "what", strlen(cmd)) != 0)
                        goto bad;
                printdumpinfo();
+               printvolinfo();
                break;
        /*
         * Turn on debugging.
@@ -316,11 +360,9 @@ loop:
  * eliminate any embedded ".." components.
  */
 static void
-getcmd(curdir, cmd, name, ap)
-       char *curdir, *cmd, *name;
-       struct arglist *ap;
+getcmd(char *curdir, char *cmd, char *name, int size, struct arglist *ap)
 {
-       register char *cp;
+       char *cp;
        static char input[BUFSIZ];
        char output[BUFSIZ];
 #      define rawname input    /* save space by reusing input buffer */
@@ -335,8 +377,17 @@ getcmd(curdir, cmd, name, ap)
        /*
         * Read a command line and trim off trailing white space.
         */
+#if HAVE_READLINE
+       snprintf(input, BUFSIZ, "%s\n", rl_gets(curdir));
+#else
        do      {
-               fprintf(stderr, "restore > ");
+               if (pflag)
+                       fprintf(stderr, "%s:%s:%s > ", 
+                               __progname,
+                               spcl.c_filesys, 
+                               curdir[1] ? &curdir[1] : "/");
+               else
+                       fprintf(stderr, "%s > ", __progname);
                (void) fflush(stderr);
                (void) fgets(input, BUFSIZ, terminal);
        } while (!feof(terminal) && input[0] == '\n');
@@ -344,6 +395,7 @@ getcmd(curdir, cmd, name, ap)
                (void) strcpy(cmd, "quit");
                return;
        }
+#endif
        for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--)
                /* trim off trailing white space and newline */;
        *++cp = '\0';
@@ -356,7 +408,8 @@ getcmd(curdir, cmd, name, ap)
         * If no argument, use curdir as the default.
         */
        if (*cp == '\0') {
-               (void) strcpy(name, curdir);
+               (void) strncpy(name, curdir, size);
+               name[size - 1] = '\0';
                return;
        }
        nextarg = cp;
@@ -373,16 +426,14 @@ getnext:
         * If it is an absolute pathname, canonicalize it and return it.
         */
        if (rawname[0] == '/') {
-               canon(rawname, name);
+               canon(rawname, name, size);
        } else {
                /*
                 * For relative pathnames, prepend the current directory to
                 * it then canonicalize and return it.
                 */
-               (void) strcpy(output, curdir);
-               (void) strcat(output, "/");
-               (void) strcat(output, rawname);
-               canon(output, name);
+               snprintf(output, sizeof(output), "%s/%s", curdir, rawname);
+               canon(output, name, size);
        }
        if (glob(name, GLOB_ALTDIRFUNC, NULL, &ap->glob) < 0)
                fprintf(stderr, "%s: out of memory\n", ap->cmd);
@@ -392,7 +443,8 @@ getnext:
        ap->argcnt = ap->glob.gl_pathc;
 
 retnext:
-       strcpy(name, ap->glob.gl_pathv[ap->glob.gl_pathc - ap->argcnt]);
+       strncpy(name, ap->glob.gl_pathv[ap->glob.gl_pathc - ap->argcnt], size);
+       name[size - 1] = '\0';
        if (--ap->argcnt == 0) {
                ap->freeglob = 0;
                globfree(&ap->glob);
@@ -404,10 +456,9 @@ retnext:
  * Strip off the next token of the input.
  */
 static char *
-copynext(input, output)
-       char *input, *output;
+copynext(char *input, char *output)
 {
-       register char *cp, *bp;
+       char *cp, *bp;
        char quote;
 
        for (cp = input; *cp == ' ' || *cp == '\t'; cp++)
@@ -438,7 +489,7 @@ copynext(input, output)
                 */
                quote = *cp++;
                while (*cp != quote && *cp != '\0')
-                       *bp++ = *cp++ /* | 0200 */;
+                       *bp++ = *cp++;
                if (*cp++ == '\0') {
                        fprintf(stderr, "missing %c\n", quote);
                        cp--;
@@ -451,13 +502,12 @@ copynext(input, output)
 
 /*
  * Canonicalize file names to always start with ``./'' and
- * remove any imbedded "." and ".." components.
+ * remove any embedded "." and ".." components.
  */
 void
-canon(rawname, canonname)
-       char *rawname, *canonname;
+canon(char *rawname, char *canonname, int len)
 {
-       register char *cp, *np;
+       char *cp, *np;
 
        if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0)
                (void) strcpy(canonname, "");
@@ -465,6 +515,9 @@ canon(rawname, canonname)
                (void) strcpy(canonname, ".");
        else
                (void) strcpy(canonname, "./");
+       if (strlen(canonname) + strlen(rawname) >= (unsigned)len)
+               errx(1, "canonname: not enough buffer space");
+               
        (void) strcat(canonname, rawname);
        /*
         * Eliminate multiple and trailing '/'s
@@ -504,12 +557,10 @@ canon(rawname, canonname)
  * Do an "ls" style listing of a directory
  */
 static void
-printlist(name, basename)
-       char *name;
-       char *basename;
+printlist(char *name, char *basename)
 {
-       register struct afile *fp, *list, *listp;
-       register struct direct *dp;
+       struct afile *fp, *list, *listp = NULL;
+       struct direct *dp;
        struct afile single;
        RST_DIR *dirp;
        int entries, len, namelen;
@@ -524,15 +575,14 @@ printlist(name, basename)
                list = &single;
                mkentry(name, dp, list);
                len = strlen(basename) + 1;
-               if (strlen(name) - len > single.len) {
+               if (strlen(name) - len > (unsigned)single.len) {
                        freename(single.fname);
                        single.fname = savename(&name[len]);
                        single.len = strlen(single.fname);
                }
        } else {
                entries = 0;
-/*             while ((dp = rst_readdir(dirp)) && (dp->d_ino != 0)) */
-               while (dp = rst_readdir(dirp))
+               while ((dp = rst_readdir(dirp)))
                        entries++;
                rst_closedir(dirp);
                list = (struct afile *)malloc(entries * sizeof(struct afile));
@@ -545,10 +595,10 @@ printlist(name, basename)
                fprintf(stderr, "%s:\n", name);
                entries = 0;
                listp = list;
-               (void) strncpy(locname, name, MAXPATHLEN);
-               (void) strncat(locname, "/", MAXPATHLEN);
-               namelen = strlen(locname);
-               while (dp = rst_readdir(dirp)) {
+               namelen = snprintf(locname, sizeof(locname), "%s/", name);
+               if (namelen >= (int)sizeof(locname))
+                       namelen = sizeof(locname) - 1;
+               while ((dp = rst_readdir(dirp))) {
                        if (dp == NULL)
                                break;
                        if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0)
@@ -558,12 +608,12 @@ printlist(name, basename)
                             strcmp(dp->d_name, "..") == 0))
                                continue;
                        locname[namelen] = '\0';
-                       if (namelen + dp->d_namlen >= MAXPATHLEN) {
+                       if (namelen + strlen(dp->d_name) >= MAXPATHLEN) {
                                fprintf(stderr, "%s%s: name exceeds %d char\n",
                                        locname, dp->d_name, MAXPATHLEN);
                        } else {
                                (void) strncat(locname, dp->d_name,
-                                   (int)dp->d_namlen);
+                                   (int)strlen(dp->d_name));
                                mkentry(locname, dp, listp++);
                                entries++;
                        }
@@ -589,10 +639,7 @@ printlist(name, basename)
  * Read the contents of a directory.
  */
 static void
-mkentry(name, dp, fp)
-       char *name;
-       struct direct *dp;
-       register struct afile *fp;
+mkentry(char *name, struct direct *dp, struct afile *fp)
 {
        char *cp;
        struct entry *np;
@@ -609,12 +656,6 @@ mkentry(name, dp, fp)
                fp->prefix = '*';
        else
                fp->prefix = ' ';
-#if    0
-       if (inodetype(dp->d_ino) == NODE)
-               fp->postfix = '/';
-       else
-               fp->postfix = ' ';
-#else  /* __linux__ */
        switch(dp->d_type) {
 
        default:
@@ -639,9 +680,12 @@ mkentry(name, dp, fp)
                fp->postfix = '#';
                break;
 
+#ifndef __linux__
+       /* no need for this */
        case DT_WHT:
                fp->postfix = '%';
                break;
+#endif
 
        case DT_UNKNOWN:
        case DT_DIR:
@@ -651,7 +695,6 @@ mkentry(name, dp, fp)
                        fp->postfix = ' ';
                break;
        }
-#endif /* __linux__ */
        return;
 }
 
@@ -659,13 +702,11 @@ mkentry(name, dp, fp)
  * Print out a pretty listing of a directory
  */
 static void
-formatf(list, nentry)
-       register struct afile *list;
-       int nentry;
+formatf(struct afile *list, int nentry)
 {
-       register struct afile *fp, *endlist;
+       struct afile *fp, *endlist;
        int width, bigino, haveprefix, havepostfix;
-       int i, j, w, precision, columns, lines;
+       int i, j, w, precision = 0, columns, lines;
 
        width = 0;
        haveprefix = 0;
@@ -673,7 +714,7 @@ formatf(list, nentry)
        bigino = ROOTINO;
        endlist = &list[nentry];
        for (fp = &list[0]; fp < endlist; fp++) {
-               if (bigino < fp->fnum)
+               if (bigino < (int)fp->fnum)
                        bigino = fp->fnum;
                if (width < fp->len)
                        width = fp->len;
@@ -700,7 +741,7 @@ formatf(list, nentry)
                for (j = 0; j < columns; j++) {
                        fp = &list[j * lines + i];
                        if (vflag) {
-                               fprintf(stderr, "%*d ", precision, fp->fnum);
+                               fprintf(stderr, "%*ld ", precision, (long)fp->fnum);
                                fp->len += precision + 1;
                        }
                        if (haveprefix) {
@@ -726,27 +767,20 @@ formatf(list, nentry)
  * Skip over directory entries that are not on the tape
  *
  * First have to get definition of a dirent.
+ *
+ * For Linux the dirent struct is now included from bsdcompat.h
  */
-#ifdef __linux__
-struct dirent {
-       off_t           d_off;          /* offset of next disk dir entry */
-        unsigned long   d_fileno;       /* file number of entry */
-        unsigned short  d_reclen;       /* length of this record */
-        unsigned short  d_namlen;       /* length of string in d_name */
-        char            d_name[255+1];  /* name (up to MAXNAMLEN + 1) */
-};
-#else  /* __linux__ */
+#ifndef        __linux__
 #undef DIRBLKSIZ
 #include <dirent.h>
 #undef d_ino
-#endif /* __linux__ */
+#endif /* __linux__ */
 
 struct dirent *
-glob_readdir(dirp)
-       RST_DIR *dirp;
+glob_readdir(RST_DIR *dirp)
 {
        struct direct *dp;
-       static struct dirent adirent;
+       static struct dirent adirent; 
 
        while ((dp = rst_readdir(dirp)) != NULL) {
                if (!vflag && dp->d_ino == WINO)
@@ -757,11 +791,6 @@ glob_readdir(dirp)
        if (dp == NULL)
                return (NULL);
        adirent.d_fileno = dp->d_ino;
-#ifdef __linux__
-       adirent.d_namlen = dp->d_namlen;
-#else
-       adirent.d_namlen = dp->d_namlen & 0xff;
-#endif
        memmove(adirent.d_name, dp->d_name, dp->d_namlen + 1);
        return (&adirent);
 }
@@ -770,12 +799,9 @@ glob_readdir(dirp)
  * Return st_mode information in response to stat or lstat calls
  */
 static int
-glob_stat(name, stp)
-       const char *name;
-       struct stat *stp;
+glob_stat(const char *name, struct stat *stp)
 {
-       register struct direct *dp;
-
+       struct direct *dp;
        dp = pathsearch(name);
        if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) ||
            (!vflag && dp->d_ino == WINO))
@@ -791,8 +817,7 @@ glob_stat(name, stp)
  * Comparison routine for qsort.
  */
 static int
-fcmp(f1, f2)
-       register const void *f1, *f2;
+fcmp(const void *f1, const void *f2)
 {
        return (strcmp(((struct afile *)f1)->fname,
            ((struct afile *)f2)->fname));
@@ -802,11 +827,216 @@ fcmp(f1, f2)
  * respond to interrupts
  */
 void
-onintr(signo)
-       int signo;
+onintr(UNUSED(int signo))
 {
+       int save_errno = errno;
+
        if (command == 'i' && runshell)
                longjmp(reset, 1);
        if (reply("restore interrupted, continue") == FAIL)
-               done(1);
+               exit(1);
+       errno = save_errno;
+}
+
+
+#if HAVE_READLINE
+
+#if !HAVE_READLINE_RLCM
+#define rl_completion_matches completion_matches
+#endif
+
+/* A static variable for holding the line. */
+static char *line_read = NULL;
+
+static char completion_curdir[MAXPATHLEN];
+
+static char *commands[] = { 
+       "add ", "cd ", "delete ", "extract ", "help ", 
+       "? ", "ls ", "pwd ", "prompt ", "quit ", "xit ", 
+       "verbose ", "setmodes ", "what ", "Debug ",
+       NULL };
+
+static char *files = NULL;
+
+static char *
+rl_gets (char *dir)
+{
+       char *prompt;
+       int sz;
+
+       snprintf(completion_curdir, MAXPATHLEN, "%s", dir);
+       completion_curdir[MAXPATHLEN - 1] = '\0';
+
+       if (pflag) {
+               sz = 6 + strlen(__progname) + strlen(spcl.c_filesys) + strlen((completion_curdir + 1 ? completion_curdir + 1 : "/"));
+               prompt = (char *)malloc(sz);
+               if (!prompt)
+                       return NULL;
+               snprintf(prompt, sz, "%s:%s:%s > ", 
+                       __progname,
+                       spcl.c_filesys, 
+                       (completion_curdir + 1 ? completion_curdir + 1 : "/"));
+       }
+       else {
+               sz = 4 + strlen(__progname);
+               prompt = (char *)malloc(sz);
+               if (!prompt)
+                       return NULL;
+               snprintf(prompt, sz, "%s > ", __progname);
+       }
+       prompt[sz - 1] = '\0';
+
+       if (line_read) {
+               free (line_read);
+               line_read = (char *)NULL;
+       }
+
+       do {
+               line_read = readline (prompt);
+       } while (line_read && !*line_read);
+
+       free(prompt);
+
+       if (!line_read) {
+               printf("\n");
+               return strdup("quit");
+       }
+
+       add_history (line_read);
+
+       return (line_read);
+}
+
+static char *
+command_generator(const char *text, int state)
+{
+       static int list_index, len;
+       char *name;
+
+       if (!state) {
+               list_index = 0;
+               len = strlen(text);
+       }
+
+       while ( (name = commands[list_index]) != NULL) {
+
+               list_index ++;
+
+               if (strncmp(name, text, len) == 0)
+                       return strdup(name);
+       }
+
+       return NULL;
+}
+
+static char *
+filename_generator(const char *text, int state)
+{
+       static int list_index;
+       char *name;
+       RST_DIR *dirp;
+       struct direct *dp;
+       static int entries;
+       char pname[MAXPATHLEN];
+       char fname[MAXPATHLEN];
+       char *slash;
+       char ppname[MAXPATHLEN];
+
+       if (!state) {
+               list_index = 0;
+
+               if (files != NULL) {
+                       free(files);
+                       entries = 0;
+                       files = NULL;
+               }
+               if ((slash = strrchr(text, '/')) != NULL) {
+                       int idx = slash - text;
+                       if (idx > MAXPATHLEN - 2)
+                               idx = MAXPATHLEN - 2;
+                       strncpy(ppname, text, MAXPATHLEN);
+                       ppname[MAXPATHLEN - 1] = '\0';
+                       ppname[idx] = '\0';
+                       if (text[0] == '/')
+                               snprintf(pname, MAXPATHLEN, ".%s", ppname);
+                       else
+                               snprintf(pname, MAXPATHLEN, "%s/%s", completion_curdir, ppname);
+                       strncpy(fname, ppname + idx + 1, MAXPATHLEN);
+                       ppname[idx] = '/';
+                       ppname[idx + 1] = '\0';
+               }
+               else {
+                       strncpy(pname, completion_curdir, MAXPATHLEN);
+                       strncpy(fname, text, MAXPATHLEN);
+                       ppname[0] = '\0';
+               }
+               pname[MAXPATHLEN - 1] = '\0';
+               fname[MAXPATHLEN - 1] = '\0';
+               if ((dirp = rst_opendir(pname)) == NULL)
+                       return NULL;
+               entries = 0;
+               while ((dp = rst_readdir(dirp)))
+                       entries++;
+               rst_closedir(dirp);
+               files = (char *)malloc(entries * MAXPATHLEN);
+               if (files == NULL) {
+                       fprintf(stderr, "Out of memory\n");
+                       entries = 0;
+                       return NULL;
+               }
+               if ((dirp = rst_opendir(pname)) == NULL)
+                       panic("directory reopen failed\n");
+               entries = 0;
+               while ((dp = rst_readdir(dirp))) {
+                        if (TSTINO(dp->d_ino, dumpmap) == 0)
+                                continue;
+                       if (strcmp(dp->d_name, ".") == 0 ||
+                           strcmp(dp->d_name, "..") == 0)
+                               continue;
+                       if (strncmp(dp->d_name, fname, strlen(fname)) == 0) {
+                               if (inodetype(dp->d_ino) == NODE)
+                                       snprintf(files + entries * MAXPATHLEN, MAXPATHLEN, "%s%s/", ppname, dp->d_name);
+                               else
+                                       snprintf(files + entries * MAXPATHLEN, MAXPATHLEN, "%s%s ", ppname, dp->d_name);
+                               *(files + (entries + 1) * MAXPATHLEN - 1) = '\0';
+                               ++entries;
+                       }
+                 }
+                 rst_closedir(dirp);
+       }
+
+       if (list_index >= entries)
+               return NULL;
+
+       name = strdup(files + list_index * MAXPATHLEN);
+       list_index ++;
+
+       return name;
 }
+
+static char **
+restore_completion (const char *text, int start, UNUSED(int end))
+{
+       char **matches;
+
+       if (start == 0)
+               matches = rl_completion_matches (text, command_generator);
+       else
+               matches = rl_completion_matches (text, filename_generator);
+
+       return (matches);
+}
+
+static void 
+initialize_readline(void) 
+{
+       rl_readline_name = "dump";
+       rl_attempted_completion_function = restore_completion;
+       rl_completion_entry_function = NULL;
+#if HAVE_READLINE_CAC  /* compile with readline 2.0 */
+       rl_completion_append_character = '\0';
+#endif
+       rl_instream = terminal;
+}
+
+#endif /* HAVE_READLINE */