* Copyright (c) 1985 The Regents of the University of California.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)interactive.c 5.11 (Berkeley) %G%";
#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 fflags
; /* extraction flags, if any */
char ftype
; /* file type, e.g. LEAF or NODE */
struct afile
*head
; /* start of argument list */
struct afile
*last
; /* end of argument list */
struct afile
*base
; /* current list arena */
int nent
; /* maximum size of list */
char *cmd
; /* the current command */
* Read and execute commands from the terminal.
register struct entry
*np
;
static struct arglist alist
= { 0, 0, 0, 0, 0 };
if (setjmp(reset
) != 0) {
for (; alist
.head
< alist
.last
; alist
.head
++)
freename(alist
.head
->fname
);
getcmd(curdir
, cmd
, name
, &alist
);
* 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
== NIL
|| (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)
printlist(name
, ino
, curdir
);
* 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.
if (ap
->head
!= ap
->last
) {
strcpy(name
, ap
->head
->fname
);
freename(ap
->head
->fname
);
* 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 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
);
strcpy(name
, ap
->head
->fname
);
freename(ap
->head
->fname
);
* 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 */;
* globals (file name generation)
* "*" in params matches r.e ".*"
* "?" in params matches r.e. "."
* "[...]" in params matches character class
* "[...a-z...]" in params matches a through z.
register struct arglist
*ap
;
static struct afile single
;
ap
->head
= ap
->last
= (struct afile
*)0;
size
= expand(arg
, 0, ap
);
single
.fnum
= ep
? ep
->e_ino
: 0;
single
.fname
= savename(arg
);
qsort((char *)ap
->head
, ap
->last
- ap
->head
, sizeof *ap
->head
, fcmp
);
register struct arglist
*ap
;
int sindex
, rindex
, lindex
;
while (*cs
!= '*' && *cs
!= '?' && *cs
!= '[') {
} else if (*--cs
== '/') {
if ((dirp
= rst_opendir(s
)) != NULL
)
sindex
= ap
->last
- ap
->head
;
while ((dp
= rst_readdir(dirp
)) != NULL
&& dp
->d_ino
!= 0) {
if (!dflag
&& BIT(dp
->d_ino
, dumpmap
) == 0)
if ((*dp
->d_name
== '.' && *cs
!= '.'))
if (gmatch(dp
->d_name
, cs
)) {
if (addg(dp
, s
, rescan
, ap
) < 0)
lindex
= ap
->last
- ap
->head
;
while (rindex
< lindex
) {
size
= expand(ap
->head
[rindex
].fname
,
bcopy((char *)&ap
->head
[lindex
],
(char *)&ap
->head
[sindex
],
(ap
->last
- &ap
->head
[rindex
]) * sizeof *ap
->head
);
ap
->last
-= lindex
- sindex
;
*s
++ = (c
&0177 ? c
: '/');
return (ok
? gmatch(s
, p
) : 0);
if (lc
<= scc
&& scc
<= (*p
++))
if (scc
== (lc
= (c
&0177)))
return (scc
? gmatch(s
, p
) : 0);
* Construct a matched name.
if (mkentry(buf
, dp
->d_ino
, ap
) == FAIL
)
* Do an "ls" style listing of a directory
printlist(name
, ino
, basename
)
register struct afile
*fp
;
register struct direct
*dp
;
static struct arglist alist
= { 0, 0, 0, 0, "ls" };
if ((dirp
= rst_opendir(name
)) == NULL
) {
single
.fname
= savename(name
+ strlen(basename
) + 1);
alist
.last
= alist
.head
+ 1;
alist
.head
= (struct afile
*)0;
fprintf(stderr
, "%s:\n", name
);
while (dp
= rst_readdir(dirp
)) {
if (dp
== NULL
|| dp
->d_ino
== 0)
if (!dflag
&& BIT(dp
->d_ino
, dumpmap
) == 0)
(strcmp(dp
->d_name
, ".") == 0 ||
strcmp(dp
->d_name
, "..") == 0))
if (!mkentry(dp
->d_name
, dp
->d_ino
, &alist
))
qsort((char *)alist
.head
, alist
.last
- alist
.head
,
sizeof *alist
.head
, fcmp
);
for (fp
= alist
.head
; fp
< alist
.last
; fp
++)
* Read the contents of a directory.
register struct arglist
*ap
;
register struct afile
*fp
;
ap
->base
= (struct afile
*)calloc((unsigned)ap
->nent
,
fprintf(stderr
, "%s: out of memory\n", ap
->cmd
);
ap
->head
= ap
->last
= ap
->base
;
fp
->fname
= savename(name
);
if (fp
== ap
->head
+ ap
->nent
) {
ap
->base
= (struct afile
*)realloc((char *)ap
->base
,
(unsigned)(2 * ap
->nent
* sizeof (struct afile
)));
fprintf(stderr
, "%s: out of memory\n", ap
->cmd
);
fp
= ap
->head
+ ap
->nent
;
* Print out a pretty listing of a directory
register struct arglist
*ap
;
register struct afile
*fp
;
int width
= 0, w
, nentry
= ap
->last
- ap
->head
;
int i
, j
, len
, columns
, lines
;
if (ap
->head
== ap
->last
)
for (fp
= ap
->head
; fp
< ap
->last
; fp
++) {
fp
->ftype
= inodetype(fp
->fnum
);
np
= lookupino(fp
->fnum
);
fp
->fflags
= np
->e_flags
;
len
= strlen(fmtentry(fp
));
lines
= (nentry
+ columns
- 1) / columns
;
for (i
= 0; i
< lines
; i
++) {
for (j
= 0; j
< columns
; j
++) {
fp
= ap
->head
+ j
* lines
+ i
;
fprintf(stderr
, "%s", cp
);
if (fp
+ lines
>= ap
->last
) {
* Comparison routine for qsort.
register struct afile
*f1
, *f2
;
return (strcmp(f1
->fname
, f2
->fname
));
* Format a directory entry.
register struct afile
*fp
;
static char fmtres
[BUFSIZ
];
static int precision
= 0;
for (i
= maxino
; i
> 0; i
/= 10)
(void) sprintf(fmtres
, "%*d ", precision
, fp
->fnum
);
dp
= &fmtres
[strlen(fmtres
)];
if (dflag
&& BIT(fp
->fnum
, dumpmap
) == 0)
else if ((fp
->fflags
& NEW
) != 0)
for (cp
= fp
->fname
; *cp
; cp
++)
if (!vflag
&& (*cp
< ' ' || *cp
>= 0177))
if (reply("restore interrupted, continue") == FAIL
)