/*
* 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 <pop@cybercable.fr>, 1999-2000
*/
/*
*/
#ifndef lint
-static char sccsid[] = "@(#)interactive.c 8.5 (Berkeley) 5/1/95";
+static const char rcsid[] =
+ "$Id: interactive.c,v 1.9 2000/02/26 01:35:48 stelian Exp $";
#endif /* not lint */
#include <sys/param.h>
-#include <sys/time.h>
#include <sys/stat.h>
#ifdef __linux__
#else /* __linux__ */
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/dir.h>
-#include <ufs/ffs/fs.h>
#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>
#ifdef __linux__
#include <ext2fs/ext2fs.h>
+extern char * __progname;
#endif
#include "restore.h"
static int runshell;
static jmp_buf reset;
static char *nextarg = NULL;
-
+static int pflag = 0; /* prompt mode */
/*
* Structure and routines associated with listing directories.
*/
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 *));
* Read and execute commands from the terminal.
*/
void
-runcmdshell()
+runcmdshell(void)
{
register struct entry *np;
ino_t ino;
arglist.glob.gl_closedir = (void *)rst_closedir;
arglist.glob.gl_lstat = glob_stat;
arglist.glob.gl_stat = glob_stat;
- canon("/", curdir);
+ canon("/", curdir, sizeof(curdir));
loop:
if (setjmp(reset) != 0) {
if (arglist.freeglob != 0) {
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.
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.
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",
"\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");
* 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.
* 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;
static char input[BUFSIZ];
* Read a command line and trim off trailing white space.
*/
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');
* 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;
* 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);
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);
* 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 quote;
*/
quote = *cp++;
while (*cp != quote && *cp != '\0')
- *bp++ = *cp++ /* | 0200 */;
+ *bp++ = *cp++ | 0200;
if (*cp++ == '\0') {
fprintf(stderr, "missing %c\n", quote);
cp--;
/*
* 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;
(void) strcpy(canonname, ".");
else
(void) strcpy(canonname, "./");
+ if (strlen(canonname) + strlen(rawname) >= len)
+ errx(1, "canonname: not enough buffer space");
+
(void) strcat(canonname, rawname);
/*
* Eliminate multiple and trailing '/'s
* 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 afile *fp, *list, *listp = NULL;
register struct direct *dp;
struct afile single;
RST_DIR *dirp;
}
} 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));
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 >= sizeof(locname))
+ namelen = sizeof(locname) - 1;
+ while ((dp = rst_readdir(dirp))) {
if (dp == NULL)
break;
if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0)
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++;
}
* 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;
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:
fp->postfix = '#';
break;
+#ifndef __linux__
+ /* no need for this */
case DT_WHT:
fp->postfix = '%';
break;
+#endif
case DT_UNKNOWN:
case DT_DIR:
fp->postfix = ' ';
break;
}
-#endif /* __linux__ */
return;
}
* 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;
int width, bigino, haveprefix, havepostfix;
- int i, j, w, precision, columns, lines;
+ int i, j, w, precision = 0, columns, lines;
width = 0;
haveprefix = 0;
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) {
* 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)
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);
}
* 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;
-
dp = pathsearch(name);
if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) ||
(!vflag && dp->d_ino == WINO))
* 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));
* respond to interrupts
*/
void
-onintr(signo)
- int signo;
+onintr(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;
}