X-Git-Url: https://git.wh0rd.org/?p=dump.git;a=blobdiff_plain;f=restore%2Finteractive.c;h=ecbffda09e8a3dde54e457f666529feb24fa1253;hp=c7b730bdd9b4d5d2b2b68685086b26766a80ad9d;hb=0556ca2241619d3aded24726dfe34a511da39d52;hpb=1227625a12a66e0ded78a1997c2d23f23202a382 diff --git a/restore/interactive.c b/restore/interactive.c index c7b730b..ecbffda 100644 --- a/restore/interactive.c +++ b/restore/interactive.c @@ -1,8 +1,9 @@ /* * Ported to Linux's Second Extended File System as part of the * dump and restore backup suit - * Remy Card , 1994, 1995, 1996 - * + * Remy Card , 1994-1997 + * Stelian Pop , 1999-2000 + * Stelian Pop - AlcĂ´ve , 2000-2002 */ /* @@ -17,11 +18,7 @@ * 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. * @@ -39,25 +36,37 @@ */ #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 +#include #include -#include #include #ifdef __linux__ +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include +#else #include +#endif #include #else /* __linux__ */ +#ifdef sunos +#include +#include +#else #include #include -#include +#endif #endif /* __linux__ */ #include #include -#include +#include +#include +#include #include #include #include @@ -66,9 +75,24 @@ static char sccsid[] = "@(#)interactive.c 8.5 (Berkeley) 5/1/95"; #include #endif +#if defined(__linux__) || defined(sunos) +extern char * __progname; +#endif + #include "restore.h" #include "extern.h" +#if HAVE_READLINE +#include +#include + +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 #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 */