* Copyright (c) 1985, 1993
* The Regents of the University of California. All rights reserved.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)interactive.c 8.5 (Berkeley) %G%";
#include <ufs/ufs/dinode.h>
#include <protocols/dumprestore.h>
#define round(a, b) (((a) + (b) - 1) / (b) * (b))
* Things to handle interruptions.
static char *nextarg
= NULL
;
* Structure and routines associated with listing directories.
ino_t fnum
; /* inode number of file */
char *fname
; /* file name */
short len
; /* name length */
char prefix
; /* prefix character */
char postfix
; /* postfix character */
int freeglob
; /* glob structure needs to be freed */
int argcnt
; /* next globbed argument to return */
glob_t glob
; /* globbing information */
char *cmd
; /* the current command */
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
*));
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
*));
static void printlist
__P((char *, char *));
* Read and execute commands from the terminal.
register struct entry
*np
;
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
;
if (setjmp(reset
) != 0) {
if (arglist
.freeglob
!= 0) {
getcmd(curdir
, cmd
, name
, &arglist
);
* Add elements to the extraction list.
if (strncmp(cmd
, "add", strlen(cmd
)) != 0)
treescan(name
, ino
, addfile
);
* Change working directory.
if (strncmp(cmd
, "cd", strlen(cmd
)) != 0)
if (inodetype(ino
) == LEAF
) {
fprintf(stderr
, "%s: not a directory\n", name
);
(void) strcpy(curdir
, name
);
* Delete elements from the extraction list.
if (strncmp(cmd
, "delete", strlen(cmd
)) != 0)
if (np
== NULL
|| (np
->e_flags
& NEW
) == 0) {
fprintf(stderr
, "%s: not on extraction list\n", name
);
treescan(name
, np
->e_ino
, deletefile
);
* Extract the requested list.
if (strncmp(cmd
, "extract", strlen(cmd
)) != 0)
* List available commands.
if (strncmp(cmd
, "help", strlen(cmd
)) != 0)
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",
"\tpwd - print current directory\n",
"\tadd [arg] - add `arg' to list of",
" files to be extracted\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",
"\twhat - list dump header information\n",
"\tverbose - toggle verbose flag",
" (useful with ``ls'')\n",
"\thelp or `?' - print this list\n",
"If no `arg' is supplied, the current",
if (strncmp(cmd
, "ls", strlen(cmd
)) != 0)
* Print current directory.
if (strncmp(cmd
, "pwd", strlen(cmd
)) != 0)
fprintf(stderr
, "%s\n", &curdir
[1]);
if (strncmp(cmd
, "quit", strlen(cmd
)) != 0)
if (strncmp(cmd
, "xit", strlen(cmd
)) != 0)
if (strncmp(cmd
, "verbose", strlen(cmd
)) != 0)
fprintf(stderr
, "verbose mode off\n");
fprintf(stderr
, "verbose mode on\n");
* Just restore requested directory modes.
if (strncmp(cmd
, "setmodes", strlen(cmd
)) != 0)
* Print out dump header information.
if (strncmp(cmd
, "what", strlen(cmd
)) != 0)
if (strncmp(cmd
, "Debug", strlen(cmd
)) != 0)
fprintf(stderr
, "debugging mode off\n");
fprintf(stderr
, "debugging mode on\n");
fprintf(stderr
, "%s: unknown command; type ? for help\n", cmd
);
* Read and parse an interactive command.
* The first word on the line is assigned to "cmd". If
* there are no arguments on the command line, then "curdir"
* is returned as the argument. If there are arguments
* on the line they are returned one at a time on each
* successive call to getcmd. Each argument is first assigned
* to "name". If it does not start with "/" the pathname in
* "curdir" is prepended to it. Finally "canon" is called to
* eliminate any embedded ".." components.
getcmd(curdir
, cmd
, name
, ap
)
char *curdir
, *cmd
, *name
;
static char input
[BUFSIZ
];
# define rawname input /* save space by reusing input buffer */
* Check to see if still processing arguments.
* Read a command line and trim off trailing white space.
fprintf(stderr
, "restore > ");
(void) fgets(input
, BUFSIZ
, terminal
);
} while (!feof(terminal
) && input
[0] == '\n');
(void) strcpy(cmd
, "quit");
for (cp
= &input
[strlen(input
) - 2]; *cp
== ' ' || *cp
== '\t'; cp
--)
/* trim off trailing white space and newline */;
* Copy the command into "cmd".
cp
= copynext(input
, cmd
);
* If no argument, use curdir as the default.
(void) strcpy(name
, curdir
);
* Find the next argument.
cp
= copynext(nextarg
, rawname
);
* If it is an absolute pathname, canonicalize it and return it.
* 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
);
if (glob(name
, GLOB_ALTDIRFUNC
, NULL
, &ap
->glob
) < 0)
fprintf(stderr
, "%s: out of memory\n", ap
->cmd
);
if (ap
->glob
.gl_pathc
== 0)
ap
->argcnt
= ap
->glob
.gl_pathc
;
strcpy(name
, ap
->glob
.gl_pathv
[ap
->glob
.gl_pathc
- ap
->argcnt
]);
* Strip off the next token of the input.
for (cp
= input
; *cp
== ' ' || *cp
== '\t'; cp
++)
while (*cp
!= ' ' && *cp
!= '\t' && *cp
!= '\0') {
"command lines cannot be continued\n");
* The usual unquoted case.
if (*cp
!= '\'' && *cp
!= '"') {
* Handle single and double quotes.
while (*cp
!= quote
&& *cp
!= '\0')
fprintf(stderr
, "missing %c\n", quote
);
* Canonicalize file names to always start with ``./'' and
* remove any imbedded "." and ".." components.
canon(rawname
, canonname
)
char *rawname
, *canonname
;
if (strcmp(rawname
, ".") == 0 || strncmp(rawname
, "./", 2) == 0)
(void) strcpy(canonname
, "");
else if (rawname
[0] == '/')
(void) strcpy(canonname
, ".");
(void) strcpy(canonname
, "./");
(void) strcat(canonname
, rawname
);
* Eliminate multiple and trailing '/'s
for (cp
= np
= canonname
; *np
!= '\0'; cp
++) {
while (*cp
== '/' && *np
== '/')
* Eliminate extraneous "." and ".." from pathnames.
for (np
= canonname
; *np
!= '\0'; ) {
while (*np
!= '/' && *np
!= '\0')
if (np
- cp
== 1 && *cp
== '.') {
if (np
- cp
== 2 && strncmp(cp
, "..", 2) == 0) {
while (cp
> &canonname
[1] && *--cp
!= '/')
/* find beginning of name */;
* Do an "ls" style listing of a directory
printlist(name
, basename
)
register struct afile
*fp
, *list
, *listp
;
register struct direct
*dp
;
int entries
, len
, namelen
;
char locname
[MAXPATHLEN
+ 1];
if (dp
== NULL
|| (!dflag
&& TSTINO(dp
->d_ino
, dumpmap
) == 0) ||
(!vflag
&& dp
->d_ino
== WINO
))
if ((dirp
= rst_opendir(name
)) == NULL
) {
len
= strlen(basename
) + 1;
if (strlen(name
) - len
> single
.len
) {
single
.fname
= savename(&name
[len
]);
single
.len
= strlen(single
.fname
);
while (dp
= rst_readdir(dirp
))
list
= (struct afile
*)malloc(entries
* sizeof(struct afile
));
fprintf(stderr
, "ls: out of memory\n");
if ((dirp
= rst_opendir(name
)) == NULL
)
panic("directory reopen failed\n");
fprintf(stderr
, "%s:\n", name
);
(void) strncpy(locname
, name
, MAXPATHLEN
);
(void) strncat(locname
, "/", MAXPATHLEN
);
namelen
= strlen(locname
);
while (dp
= rst_readdir(dirp
)) {
if (!dflag
&& TSTINO(dp
->d_ino
, dumpmap
) == 0)
if (!vflag
&& (dp
->d_ino
== WINO
||
strcmp(dp
->d_name
, ".") == 0 ||
strcmp(dp
->d_name
, "..") == 0))
if (namelen
+ dp
->d_namlen
>= MAXPATHLEN
) {
fprintf(stderr
, "%s%s: name exceeds %d char\n",
locname
, dp
->d_name
, MAXPATHLEN
);
(void) strncat(locname
, dp
->d_name
,
mkentry(locname
, dp
, listp
++);
qsort((char *)list
, entries
, sizeof(struct afile
), fcmp
);
for (fp
= listp
- 1; fp
>= list
; fp
--)
* Read the contents of a directory.
register struct afile
*fp
;
fp
->fname
= savename(dp
->d_name
);
for (cp
= fp
->fname
; *cp
; cp
++)
if (!vflag
&& (*cp
< ' ' || *cp
>= 0177))
fp
->len
= cp
- fp
->fname
;
if (dflag
&& TSTINO(fp
->fnum
, dumpmap
) == 0)
else if ((np
= lookupname(name
)) != NULL
&& (np
->e_flags
& NEW
))
fprintf(stderr
, "Warning: undefined file type %d\n",
if (inodetype(dp
->d_ino
) == NODE
)
* Print out a pretty listing of a directory
register struct afile
*list
;
register struct afile
*fp
, *endlist
;
int width
, bigino
, haveprefix
, havepostfix
;
int i
, j
, w
, precision
, columns
, lines
;
for (fp
= &list
[0]; fp
< endlist
; fp
++) {
for (precision
= 0, i
= bigino
; i
> 0; i
/= 10)
lines
= (nentry
+ columns
- 1) / columns
;
for (i
= 0; i
< lines
; i
++) {
for (j
= 0; j
< columns
; j
++) {
fp
= &list
[j
* lines
+ i
];
fprintf(stderr
, "%*d ", precision
, fp
->fnum
);
fp
->len
+= precision
+ 1;
putc(fp
->prefix
, stderr
);
fprintf(stderr
, "%s", fp
->fname
);
putc(fp
->postfix
, stderr
);
if (fp
+ lines
>= endlist
) {
for (w
= fp
->len
; w
< width
; w
++)
* Skip over directory entries that are not on the tape
* First have to get definition of a dirent.
static struct dirent adirent
;
while ((dp
= rst_readdir(dirp
)) != NULL
) {
if (!vflag
&& dp
->d_ino
== WINO
)
if (dflag
|| TSTINO(dp
->d_ino
, dumpmap
))
adirent
.d_fileno
= dp
->d_ino
;
adirent
.d_namlen
= dp
->d_namlen
;
memmove(adirent
.d_name
, dp
->d_name
, dp
->d_namlen
+ 1);
* Return st_mode information in response to stat or lstat calls
register struct direct
*dp
;
if (dp
== NULL
|| (!dflag
&& TSTINO(dp
->d_ino
, dumpmap
) == 0) ||
(!vflag
&& dp
->d_ino
== WINO
))
if (inodetype(dp
->d_ino
) == NODE
)
* Comparison routine for qsort.
register const void *f1
, *f2
;
return (strcmp(((struct afile
*)f1
)->fname
,
((struct afile
*)f2
)->fname
));
if (command
== 'i' && runshell
)
if (reply("restore interrupted, continue") == FAIL
)