xref: /csrg-svn/sbin/restore/interactive.c (revision 57896)
121166Sdist /*
236105Sbostic  * Copyright (c) 1985 The Regents of the University of California.
336105Sbostic  * All rights reserved.
436105Sbostic  *
542708Sbostic  * %sccs.include.redist.c%
621166Sdist  */
717752Smckusick 
817752Smckusick #ifndef lint
9*57896Sbostic static char sccsid[] = "@(#)interactive.c	5.19 (Berkeley) 02/10/93";
1036105Sbostic #endif /* not lint */
1117752Smckusick 
1256567Sbostic #include <sys/param.h>
1356567Sbostic #include <sys/time.h>
1456948Smckusick #include <sys/stat.h>
1556567Sbostic 
1656567Sbostic #include <ufs/ffs/fs.h>
1756567Sbostic #include <ufs/ufs/dinode.h>
1856567Sbostic #include <ufs/ufs/dir.h>
1923546Smckusick #include <protocols/dumprestore.h>
2056567Sbostic 
2117752Smckusick #include <setjmp.h>
2256948Smckusick #include <glob.h>
2356567Sbostic #include <stdio.h>
2456567Sbostic #include <stdlib.h>
2556567Sbostic #include <string.h>
2617752Smckusick 
2756567Sbostic #include "restore.h"
2856567Sbostic #include "extern.h"
2956567Sbostic 
3017756Smckusick #define round(a, b) (((a) + (b) - 1) / (b) * (b))
3117756Smckusick 
3217752Smckusick /*
3317752Smckusick  * Things to handle interruptions.
3417752Smckusick  */
3556429Smckusick static int runshell;
3617752Smckusick static jmp_buf reset;
3717752Smckusick static char *nextarg = NULL;
3817752Smckusick 
3917752Smckusick /*
4017752Smckusick  * Structure and routines associated with listing directories.
4117752Smckusick  */
4217752Smckusick struct afile {
4317752Smckusick 	ino_t	fnum;		/* inode number of file */
4417752Smckusick 	char	*fname;		/* file name */
4556948Smckusick 	short	len;		/* name length */
4656948Smckusick 	char	prefix;		/* prefix character */
4756948Smckusick 	char	postfix;	/* postfix character */
4817752Smckusick };
4918003Smckusick struct arglist {
5056948Smckusick 	int	freeglob;	/* glob structure needs to be freed */
5156948Smckusick 	int	argcnt;		/* next globbed argument to return */
5256948Smckusick 	glob_t	glob;		/* globbing information */
5356948Smckusick 	char	*cmd;		/* the current command */
5418003Smckusick };
5517752Smckusick 
5656567Sbostic static char	*copynext __P((char *, char *));
5756567Sbostic static int	 fcmp __P((const void *, const void *));
5856567Sbostic static char	*fmtentry __P((struct afile *));
5956948Smckusick static void	 formatf __P((struct afile *, int));
6056567Sbostic static void	 getcmd __P((char *, char *, char *, struct arglist *));
6156948Smckusick struct dirent	*glob_readdir __P((RST_DIR *dirp));
62*57896Sbostic static int	 glob_stat __P((const char *, struct stat *));
6356948Smckusick static void	 mkentry __P((struct direct *, struct afile *));
6456948Smckusick static void	 printlist __P((char *, char *));
6556567Sbostic 
6617752Smckusick /*
6717752Smckusick  * Read and execute commands from the terminal.
6817752Smckusick  */
6956567Sbostic void
7017752Smckusick runcmdshell()
7117752Smckusick {
7217752Smckusick 	register struct entry *np;
7317752Smckusick 	ino_t ino;
7456948Smckusick 	struct arglist arglist;
7517752Smckusick 	char curdir[MAXPATHLEN];
7617752Smckusick 	char name[MAXPATHLEN];
7717752Smckusick 	char cmd[BUFSIZ];
7817752Smckusick 
7956948Smckusick 	arglist.freeglob = 0;
8056948Smckusick 	arglist.argcnt = 0;
8156948Smckusick 	arglist.glob.gl_flags = GLOB_ALTDIRFUNC;
8256948Smckusick 	arglist.glob.gl_opendir = (void *)rst_opendir;
8356948Smckusick 	arglist.glob.gl_readdir = (void *)glob_readdir;
8456948Smckusick 	arglist.glob.gl_closedir = rst_closedir;
8556948Smckusick 	arglist.glob.gl_lstat = glob_stat;
8656948Smckusick 	arglist.glob.gl_stat = glob_stat;
8717752Smckusick 	canon("/", curdir);
8817752Smckusick loop:
8917752Smckusick 	if (setjmp(reset) != 0) {
9056948Smckusick 		if (arglist.freeglob != 0) {
9156948Smckusick 			arglist.freeglob = 0;
9256948Smckusick 			arglist.argcnt = 0;
9356948Smckusick 			globfree(&arglist.glob);
9456948Smckusick 		}
9517752Smckusick 		nextarg = NULL;
9617752Smckusick 		volno = 0;
9717752Smckusick 	}
9856429Smckusick 	runshell = 1;
9956948Smckusick 	getcmd(curdir, cmd, name, &arglist);
10017752Smckusick 	switch (cmd[0]) {
10117752Smckusick 	/*
10217752Smckusick 	 * Add elements to the extraction list.
10317752Smckusick 	 */
10417752Smckusick 	case 'a':
10529903Smckusick 		if (strncmp(cmd, "add", strlen(cmd)) != 0)
10629903Smckusick 			goto bad;
10717752Smckusick 		ino = dirlookup(name);
10817752Smckusick 		if (ino == 0)
10917752Smckusick 			break;
11017752Smckusick 		if (mflag)
11117752Smckusick 			pathcheck(name);
11217752Smckusick 		treescan(name, ino, addfile);
11317752Smckusick 		break;
11417752Smckusick 	/*
11517752Smckusick 	 * Change working directory.
11617752Smckusick 	 */
11717752Smckusick 	case 'c':
11829903Smckusick 		if (strncmp(cmd, "cd", strlen(cmd)) != 0)
11929903Smckusick 			goto bad;
12017752Smckusick 		ino = dirlookup(name);
12117752Smckusick 		if (ino == 0)
12217752Smckusick 			break;
12317752Smckusick 		if (inodetype(ino) == LEAF) {
12417752Smckusick 			fprintf(stderr, "%s: not a directory\n", name);
12517752Smckusick 			break;
12617752Smckusick 		}
12717752Smckusick 		(void) strcpy(curdir, name);
12817752Smckusick 		break;
12917752Smckusick 	/*
13017752Smckusick 	 * Delete elements from the extraction list.
13117752Smckusick 	 */
13217752Smckusick 	case 'd':
13329903Smckusick 		if (strncmp(cmd, "delete", strlen(cmd)) != 0)
13429903Smckusick 			goto bad;
13517752Smckusick 		np = lookupname(name);
13656567Sbostic 		if (np == NULL || (np->e_flags & NEW) == 0) {
13717752Smckusick 			fprintf(stderr, "%s: not on extraction list\n", name);
13817752Smckusick 			break;
13917752Smckusick 		}
14017752Smckusick 		treescan(name, np->e_ino, deletefile);
14117752Smckusick 		break;
14217752Smckusick 	/*
14317752Smckusick 	 * Extract the requested list.
14417752Smckusick 	 */
14517752Smckusick 	case 'e':
14629903Smckusick 		if (strncmp(cmd, "extract", strlen(cmd)) != 0)
14729903Smckusick 			goto bad;
14817752Smckusick 		createfiles();
14917752Smckusick 		createlinks();
15055880Smckusick 		setdirmodes(0);
15117752Smckusick 		if (dflag)
15217752Smckusick 			checkrestore();
15317752Smckusick 		volno = 0;
15417752Smckusick 		break;
15517752Smckusick 	/*
15617752Smckusick 	 * List available commands.
15717752Smckusick 	 */
15817752Smckusick 	case 'h':
15929903Smckusick 		if (strncmp(cmd, "help", strlen(cmd)) != 0)
16029903Smckusick 			goto bad;
16117752Smckusick 	case '?':
16229903Smckusick 		fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
16317752Smckusick 			"Available commands are:\n",
16417752Smckusick 			"\tls [arg] - list directory\n",
16517752Smckusick 			"\tcd arg - change directory\n",
16617752Smckusick 			"\tpwd - print current directory\n",
16717752Smckusick 			"\tadd [arg] - add `arg' to list of",
16817752Smckusick 			" files to be extracted\n",
16917752Smckusick 			"\tdelete [arg] - delete `arg' from",
17017752Smckusick 			" list of files to be extracted\n",
17117752Smckusick 			"\textract - extract requested files\n",
17221096Smckusick 			"\tsetmodes - set modes of requested directories\n",
17317752Smckusick 			"\tquit - immediately exit program\n",
17429903Smckusick 			"\twhat - list dump header information\n",
17517752Smckusick 			"\tverbose - toggle verbose flag",
17617752Smckusick 			" (useful with ``ls'')\n",
17717752Smckusick 			"\thelp or `?' - print this list\n",
17817752Smckusick 			"If no `arg' is supplied, the current",
17917752Smckusick 			" directory is used\n");
18017752Smckusick 		break;
18117752Smckusick 	/*
18217752Smckusick 	 * List a directory.
18317752Smckusick 	 */
18417752Smckusick 	case 'l':
18529903Smckusick 		if (strncmp(cmd, "ls", strlen(cmd)) != 0)
18629903Smckusick 			goto bad;
18756948Smckusick 		printlist(name, curdir);
18817752Smckusick 		break;
18917752Smckusick 	/*
19017752Smckusick 	 * Print current directory.
19117752Smckusick 	 */
19217752Smckusick 	case 'p':
19329903Smckusick 		if (strncmp(cmd, "pwd", strlen(cmd)) != 0)
19429903Smckusick 			goto bad;
19517752Smckusick 		if (curdir[1] == '\0')
19617752Smckusick 			fprintf(stderr, "/\n");
19717752Smckusick 		else
19817752Smckusick 			fprintf(stderr, "%s\n", &curdir[1]);
19917752Smckusick 		break;
20017752Smckusick 	/*
20117752Smckusick 	 * Quit.
20217752Smckusick 	 */
20317752Smckusick 	case 'q':
20429903Smckusick 		if (strncmp(cmd, "quit", strlen(cmd)) != 0)
20529903Smckusick 			goto bad;
20629903Smckusick 		return;
20717752Smckusick 	case 'x':
20829903Smckusick 		if (strncmp(cmd, "xit", strlen(cmd)) != 0)
20929903Smckusick 			goto bad;
21017752Smckusick 		return;
21117752Smckusick 	/*
21217752Smckusick 	 * Toggle verbose mode.
21317752Smckusick 	 */
21417752Smckusick 	case 'v':
21529903Smckusick 		if (strncmp(cmd, "verbose", strlen(cmd)) != 0)
21629903Smckusick 			goto bad;
21717752Smckusick 		if (vflag) {
21817752Smckusick 			fprintf(stderr, "verbose mode off\n");
21917752Smckusick 			vflag = 0;
22017752Smckusick 			break;
22117752Smckusick 		}
22217752Smckusick 		fprintf(stderr, "verbose mode on\n");
22317752Smckusick 		vflag++;
22417752Smckusick 		break;
22517752Smckusick 	/*
22617752Smckusick 	 * Just restore requested directory modes.
22717752Smckusick 	 */
22821096Smckusick 	case 's':
22929903Smckusick 		if (strncmp(cmd, "setmodes", strlen(cmd)) != 0)
23029903Smckusick 			goto bad;
23155880Smckusick 		setdirmodes(FORCE);
23217752Smckusick 		break;
23317752Smckusick 	/*
23429903Smckusick 	 * Print out dump header information.
23529903Smckusick 	 */
23629903Smckusick 	case 'w':
23729903Smckusick 		if (strncmp(cmd, "what", strlen(cmd)) != 0)
23829903Smckusick 			goto bad;
23929903Smckusick 		printdumpinfo();
24029903Smckusick 		break;
24129903Smckusick 	/*
24217752Smckusick 	 * Turn on debugging.
24317752Smckusick 	 */
24417752Smckusick 	case 'D':
24529903Smckusick 		if (strncmp(cmd, "Debug", strlen(cmd)) != 0)
24629903Smckusick 			goto bad;
24717752Smckusick 		if (dflag) {
24817752Smckusick 			fprintf(stderr, "debugging mode off\n");
24917752Smckusick 			dflag = 0;
25017752Smckusick 			break;
25117752Smckusick 		}
25217752Smckusick 		fprintf(stderr, "debugging mode on\n");
25317752Smckusick 		dflag++;
25417752Smckusick 		break;
25517752Smckusick 	/*
25617752Smckusick 	 * Unknown command.
25717752Smckusick 	 */
25817752Smckusick 	default:
25929903Smckusick 	bad:
26017752Smckusick 		fprintf(stderr, "%s: unknown command; type ? for help\n", cmd);
26117752Smckusick 		break;
26217752Smckusick 	}
26317752Smckusick 	goto loop;
26417752Smckusick }
26517752Smckusick 
26617752Smckusick /*
26717752Smckusick  * Read and parse an interactive command.
26817752Smckusick  * The first word on the line is assigned to "cmd". If
26917752Smckusick  * there are no arguments on the command line, then "curdir"
27017752Smckusick  * is returned as the argument. If there are arguments
27117752Smckusick  * on the line they are returned one at a time on each
27217752Smckusick  * successive call to getcmd. Each argument is first assigned
27317752Smckusick  * to "name". If it does not start with "/" the pathname in
27417752Smckusick  * "curdir" is prepended to it. Finally "canon" is called to
27517752Smckusick  * eliminate any embedded ".." components.
27617752Smckusick  */
27756567Sbostic static void
27818003Smckusick getcmd(curdir, cmd, name, ap)
27917752Smckusick 	char *curdir, *cmd, *name;
28018003Smckusick 	struct arglist *ap;
28117752Smckusick {
28217752Smckusick 	register char *cp;
28317752Smckusick 	static char input[BUFSIZ];
28417752Smckusick 	char output[BUFSIZ];
28517752Smckusick #	define rawname input	/* save space by reusing input buffer */
28617752Smckusick 
28717752Smckusick 	/*
28817752Smckusick 	 * Check to see if still processing arguments.
28917752Smckusick 	 */
29056948Smckusick 	if (ap->argcnt > 0)
29156948Smckusick 		goto retnext;
29217752Smckusick 	if (nextarg != NULL)
29317752Smckusick 		goto getnext;
29417752Smckusick 	/*
29517752Smckusick 	 * Read a command line and trim off trailing white space.
29617752Smckusick 	 */
29717752Smckusick 	do	{
29817752Smckusick 		fprintf(stderr, "restore > ");
29917752Smckusick 		(void) fflush(stderr);
30017752Smckusick 		(void) fgets(input, BUFSIZ, terminal);
30117752Smckusick 	} while (!feof(terminal) && input[0] == '\n');
30217752Smckusick 	if (feof(terminal)) {
30317752Smckusick 		(void) strcpy(cmd, "quit");
30417752Smckusick 		return;
30517752Smckusick 	}
30617752Smckusick 	for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--)
30717752Smckusick 		/* trim off trailing white space and newline */;
30817752Smckusick 	*++cp = '\0';
30917752Smckusick 	/*
31017752Smckusick 	 * Copy the command into "cmd".
31117752Smckusick 	 */
31217752Smckusick 	cp = copynext(input, cmd);
31318003Smckusick 	ap->cmd = cmd;
31417752Smckusick 	/*
31517752Smckusick 	 * If no argument, use curdir as the default.
31617752Smckusick 	 */
31717752Smckusick 	if (*cp == '\0') {
31817752Smckusick 		(void) strcpy(name, curdir);
31917752Smckusick 		return;
32017752Smckusick 	}
32117752Smckusick 	nextarg = cp;
32217752Smckusick 	/*
32317752Smckusick 	 * Find the next argument.
32417752Smckusick 	 */
32517752Smckusick getnext:
32617752Smckusick 	cp = copynext(nextarg, rawname);
32717752Smckusick 	if (*cp == '\0')
32817752Smckusick 		nextarg = NULL;
32917752Smckusick 	else
33017752Smckusick 		nextarg = cp;
33117752Smckusick 	/*
33256948Smckusick 	 * If it is an absolute pathname, canonicalize it and return it.
33317752Smckusick 	 */
33417752Smckusick 	if (rawname[0] == '/') {
33517752Smckusick 		canon(rawname, name);
33617752Smckusick 	} else {
33717752Smckusick 		/*
33817752Smckusick 		 * For relative pathnames, prepend the current directory to
33917752Smckusick 		 * it then canonicalize and return it.
34017752Smckusick 		 */
34117752Smckusick 		(void) strcpy(output, curdir);
34217752Smckusick 		(void) strcat(output, "/");
34317752Smckusick 		(void) strcat(output, rawname);
34417752Smckusick 		canon(output, name);
34517752Smckusick 	}
34656948Smckusick 	if (glob(name, GLOB_ALTDIRFUNC, NULL, &ap->glob) < 0)
34756948Smckusick 		fprintf(stderr, "%s: out of memory\n", ap->cmd);
34856948Smckusick 	if (ap->glob.gl_pathc == 0)
34956948Smckusick 		return;
35056948Smckusick 	ap->freeglob = 1;
35156948Smckusick 	ap->argcnt = ap->glob.gl_pathc;
35256948Smckusick 
35356948Smckusick retnext:
35456948Smckusick 	strcpy(name, ap->glob.gl_pathv[ap->glob.gl_pathc - ap->argcnt]);
35556948Smckusick 	if (--ap->argcnt == 0) {
35656948Smckusick 		ap->freeglob = 0;
35756948Smckusick 		globfree(&ap->glob);
35856948Smckusick 	}
35917752Smckusick #	undef rawname
36017752Smckusick }
36117752Smckusick 
36217752Smckusick /*
36317752Smckusick  * Strip off the next token of the input.
36417752Smckusick  */
36556567Sbostic static char *
36617752Smckusick copynext(input, output)
36717752Smckusick 	char *input, *output;
36817752Smckusick {
36917752Smckusick 	register char *cp, *bp;
37017752Smckusick 	char quote;
37117752Smckusick 
37217752Smckusick 	for (cp = input; *cp == ' ' || *cp == '\t'; cp++)
37317752Smckusick 		/* skip to argument */;
37417752Smckusick 	bp = output;
37517752Smckusick 	while (*cp != ' ' && *cp != '\t' && *cp != '\0') {
37617752Smckusick 		/*
37717752Smckusick 		 * Handle back slashes.
37817752Smckusick 		 */
37917752Smckusick 		if (*cp == '\\') {
38017752Smckusick 			if (*++cp == '\0') {
38117752Smckusick 				fprintf(stderr,
38217752Smckusick 					"command lines cannot be continued\n");
38317752Smckusick 				continue;
38417752Smckusick 			}
38517752Smckusick 			*bp++ = *cp++;
38617752Smckusick 			continue;
38717752Smckusick 		}
38817752Smckusick 		/*
38917752Smckusick 		 * The usual unquoted case.
39017752Smckusick 		 */
39117752Smckusick 		if (*cp != '\'' && *cp != '"') {
39217752Smckusick 			*bp++ = *cp++;
39317752Smckusick 			continue;
39417752Smckusick 		}
39517752Smckusick 		/*
39617752Smckusick 		 * Handle single and double quotes.
39717752Smckusick 		 */
39817752Smckusick 		quote = *cp++;
39917752Smckusick 		while (*cp != quote && *cp != '\0')
40017752Smckusick 			*bp++ = *cp++ | 0200;
40117752Smckusick 		if (*cp++ == '\0') {
40217752Smckusick 			fprintf(stderr, "missing %c\n", quote);
40317752Smckusick 			cp--;
40417752Smckusick 			continue;
40517752Smckusick 		}
40617752Smckusick 	}
40717752Smckusick 	*bp = '\0';
40817752Smckusick 	return (cp);
40917752Smckusick }
41017752Smckusick 
41117752Smckusick /*
41217752Smckusick  * Canonicalize file names to always start with ``./'' and
41318003Smckusick  * remove any imbedded "." and ".." components.
41417752Smckusick  */
41556567Sbostic void
41617752Smckusick canon(rawname, canonname)
41717752Smckusick 	char *rawname, *canonname;
41817752Smckusick {
41917752Smckusick 	register char *cp, *np;
42017752Smckusick 
42117752Smckusick 	if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0)
42217752Smckusick 		(void) strcpy(canonname, "");
42317752Smckusick 	else if (rawname[0] == '/')
42417752Smckusick 		(void) strcpy(canonname, ".");
42517752Smckusick 	else
42617752Smckusick 		(void) strcpy(canonname, "./");
42717752Smckusick 	(void) strcat(canonname, rawname);
42817752Smckusick 	/*
42918003Smckusick 	 * Eliminate multiple and trailing '/'s
43017752Smckusick 	 */
43118003Smckusick 	for (cp = np = canonname; *np != '\0'; cp++) {
43218003Smckusick 		*cp = *np++;
43318003Smckusick 		while (*cp == '/' && *np == '/')
43418003Smckusick 			np++;
43518003Smckusick 	}
43618003Smckusick 	*cp = '\0';
43718003Smckusick 	if (*--cp == '/')
43818003Smckusick 		*cp = '\0';
43918003Smckusick 	/*
44018003Smckusick 	 * Eliminate extraneous "." and ".." from pathnames.
44118003Smckusick 	 */
44217752Smckusick 	for (np = canonname; *np != '\0'; ) {
44317752Smckusick 		np++;
44417752Smckusick 		cp = np;
44517752Smckusick 		while (*np != '/' && *np != '\0')
44617752Smckusick 			np++;
44718003Smckusick 		if (np - cp == 1 && *cp == '.') {
44818003Smckusick 			cp--;
44918003Smckusick 			(void) strcpy(cp, np);
45018003Smckusick 			np = cp;
45118003Smckusick 		}
45217752Smckusick 		if (np - cp == 2 && strncmp(cp, "..", 2) == 0) {
45317752Smckusick 			cp--;
45417752Smckusick 			while (cp > &canonname[1] && *--cp != '/')
45517752Smckusick 				/* find beginning of name */;
45617752Smckusick 			(void) strcpy(cp, np);
45717752Smckusick 			np = cp;
45817752Smckusick 		}
45917752Smckusick 	}
46017752Smckusick }
46117752Smckusick 
46217752Smckusick /*
46317752Smckusick  * Do an "ls" style listing of a directory
46417752Smckusick  */
46556567Sbostic static void
46656948Smckusick printlist(name, basename)
46717752Smckusick 	char *name;
46817752Smckusick 	char *basename;
46917752Smckusick {
47056948Smckusick 	register struct afile *fp, *list, *listp;
47118003Smckusick 	register struct direct *dp;
47217752Smckusick 	struct afile single;
47350655Smckusick 	RST_DIR *dirp;
47456948Smckusick 	int entries, len;
47517752Smckusick 
47656948Smckusick 	dp = pathsearch(name);
47756948Smckusick 	if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0))
47856948Smckusick 		return;
47917752Smckusick 	if ((dirp = rst_opendir(name)) == NULL) {
48056948Smckusick 		entries = 1;
48156948Smckusick 		list = &single;
48256948Smckusick 		mkentry(dp, list);
48356948Smckusick 		len = strlen(basename) + 1;
48456948Smckusick 		if (strlen(name) - len > single.len) {
48556948Smckusick 			freename(single.fname);
48656948Smckusick 			single.fname = savename(&name[len]);
48756948Smckusick 			single.len = strlen(single.fname);
48856948Smckusick 		}
48917752Smckusick 	} else {
49056948Smckusick 		entries = 0;
49156948Smckusick 		while (dp = rst_readdir(dirp))
49256948Smckusick 			entries++;
49356948Smckusick 		rst_closedir(dirp);
49456948Smckusick 		list = (struct afile *)malloc(entries * sizeof(struct afile));
49556948Smckusick 		if (list == NULL) {
49656948Smckusick 			fprintf(stderr, "ls: out of memory\n");
49756948Smckusick 			return;
49856948Smckusick 		}
49956948Smckusick 		if ((dirp = rst_opendir(name)) == NULL)
50056948Smckusick 			panic("directory reopen failed\n");
50118003Smckusick 		fprintf(stderr, "%s:\n", name);
50256948Smckusick 		entries = 0;
50356948Smckusick 		listp = list;
50418003Smckusick 		while (dp = rst_readdir(dirp)) {
50518003Smckusick 			if (dp == NULL || dp->d_ino == 0)
50618003Smckusick 				break;
50756427Smckusick 			if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0)
50818003Smckusick 				continue;
50918003Smckusick 			if (vflag == 0 &&
51018003Smckusick 			    (strcmp(dp->d_name, ".") == 0 ||
51118003Smckusick 			     strcmp(dp->d_name, "..") == 0))
51218003Smckusick 				continue;
51356948Smckusick 			mkentry(dp, listp++);
51456948Smckusick 			entries++;
51518003Smckusick 		}
51656948Smckusick 		rst_closedir(dirp);
51756948Smckusick 		if (entries == 0) {
51856948Smckusick 			fprintf(stderr, "\n");
51956948Smckusick 			free(list);
52056948Smckusick 			return;
52156948Smckusick 		}
52256948Smckusick 		qsort((char *)list, entries, sizeof(struct afile), fcmp);
52317752Smckusick 	}
52456948Smckusick 	formatf(list, entries);
52556948Smckusick 	if (dirp != NULL) {
52656948Smckusick 		for (fp = listp - 1; fp >= list; fp--)
52718003Smckusick 			freename(fp->fname);
52856948Smckusick 		fprintf(stderr, "\n");
52956948Smckusick 		free(list);
53018003Smckusick 	}
53117752Smckusick }
53217752Smckusick 
53317752Smckusick /*
53417752Smckusick  * Read the contents of a directory.
53517752Smckusick  */
53656948Smckusick static void
53756948Smckusick mkentry(dp, fp)
53854593Smckusick 	struct direct *dp;
53956948Smckusick 	register struct afile *fp;
54017752Smckusick {
54156948Smckusick 	char *cp;
54256948Smckusick 	struct entry *np;
54317752Smckusick 
54454593Smckusick 	fp->fnum = dp->d_ino;
54556948Smckusick 	fp->fname = savename(dp->d_name);
54656948Smckusick 	for (cp = fp->fname; *cp; cp++)
54756948Smckusick 		if (!vflag && (*cp < ' ' || *cp >= 0177))
54856948Smckusick 			*cp = '?';
54956948Smckusick 	fp->len = cp - fp->fname;
55056948Smckusick 	if (dflag && TSTINO(fp->fnum, dumpmap) == 0)
55156948Smckusick 		fp->prefix = '^';
55256948Smckusick 	else if ((np = lookupino(fp->fnum)) != NULL && (np->e_flags & NEW))
55356948Smckusick 		fp->prefix = '*';
55454593Smckusick 	else
55556948Smckusick 		fp->prefix = ' ';
55656948Smckusick 	switch(dp->d_type) {
55756948Smckusick 
55856948Smckusick 	default:
55956948Smckusick 		fprintf(stderr, "Warning: undefined file type %d\n",
56056948Smckusick 		    dp->d_type);
56156948Smckusick 		/* fall through */
56256948Smckusick 	case DT_REG:
56356948Smckusick 		fp->postfix = ' ';
56456948Smckusick 		break;
56556948Smckusick 
56656948Smckusick 	case DT_LNK:
56756948Smckusick 		fp->postfix = '@';
56856948Smckusick 		break;
56956948Smckusick 
57056948Smckusick 	case DT_FIFO:
57156948Smckusick 	case DT_SOCK:
57256948Smckusick 		fp->postfix = '=';
57356948Smckusick 		break;
57456948Smckusick 
57556948Smckusick 	case DT_CHR:
57656948Smckusick 	case DT_BLK:
57756948Smckusick 		fp->postfix = '#';
57856948Smckusick 		break;
57956948Smckusick 
58056948Smckusick 	case DT_UNKNOWN:
58156948Smckusick 	case DT_DIR:
58256948Smckusick 		if (inodetype(dp->d_ino) == NODE)
58356948Smckusick 			fp->postfix = '/';
58456948Smckusick 		else
58556948Smckusick 			fp->postfix = ' ';
58656948Smckusick 		break;
58717752Smckusick 	}
58856948Smckusick 	return;
58917752Smckusick }
59017752Smckusick 
59117752Smckusick /*
59217752Smckusick  * Print out a pretty listing of a directory
59317752Smckusick  */
59456567Sbostic static void
59556948Smckusick formatf(list, nentry)
59656948Smckusick 	register struct afile *list;
59756948Smckusick 	int nentry;
59817752Smckusick {
59956948Smckusick 	register struct afile *fp, *endlist;
60056948Smckusick 	int width, bigino, haveprefix, havepostfix;
60156948Smckusick 	int i, j, w, precision, columns, lines;
60217752Smckusick 
60356948Smckusick 	width = 0;
60456948Smckusick 	haveprefix = 0;
60556948Smckusick 	havepostfix = 0;
60656948Smckusick 	bigino = ROOTINO;
60756948Smckusick 	endlist = &list[nentry];
60856948Smckusick 	for (fp = &list[0]; fp < endlist; fp++) {
60956948Smckusick 		if (bigino < fp->fnum)
61056948Smckusick 			bigino = fp->fnum;
61156948Smckusick 		if (width < fp->len)
61256948Smckusick 			width = fp->len;
61356948Smckusick 		if (fp->prefix != ' ')
61456948Smckusick 			haveprefix = 1;
61556948Smckusick 		if (fp->postfix != ' ')
61656948Smckusick 			havepostfix = 1;
61717752Smckusick 	}
61856948Smckusick 	if (haveprefix)
61956948Smckusick 		width++;
62056948Smckusick 	if (havepostfix)
62156948Smckusick 		width++;
62256948Smckusick 	if (vflag) {
62356948Smckusick 		for (precision = 0, i = bigino; i > 0; i /= 10)
62456948Smckusick 			precision++;
62556948Smckusick 		width += precision + 1;
62656948Smckusick 	}
62756948Smckusick 	width++;
62856948Smckusick 	columns = 81 / width;
62917752Smckusick 	if (columns == 0)
63017752Smckusick 		columns = 1;
63117752Smckusick 	lines = (nentry + columns - 1) / columns;
63217752Smckusick 	for (i = 0; i < lines; i++) {
63317752Smckusick 		for (j = 0; j < columns; j++) {
63456948Smckusick 			fp = &list[j * lines + i];
63556948Smckusick 			if (vflag) {
63656948Smckusick 				fprintf(stderr, "%*d ", precision, fp->fnum);
63756948Smckusick 				fp->len += precision + 1;
63856948Smckusick 			}
63956948Smckusick 			if (haveprefix) {
64056948Smckusick 				putc(fp->prefix, stderr);
64156948Smckusick 				fp->len++;
64256948Smckusick 			}
64356948Smckusick 			fprintf(stderr, "%s", fp->fname);
64456948Smckusick 			if (havepostfix) {
64556948Smckusick 				putc(fp->postfix, stderr);
64656948Smckusick 				fp->len++;
64756948Smckusick 			}
64856948Smckusick 			if (fp + lines >= endlist) {
64917752Smckusick 				fprintf(stderr, "\n");
65017752Smckusick 				break;
65117752Smckusick 			}
65256948Smckusick 			for (w = fp->len; w < width; w++)
65356948Smckusick 				putc(' ', stderr);
65417752Smckusick 		}
65517752Smckusick 	}
65617752Smckusick }
65717752Smckusick 
65817752Smckusick /*
65956948Smckusick  * Skip over directory entries that are not on the tape
66056948Smckusick  *
66156948Smckusick  * First have to get definition of a dirent.
66217752Smckusick  */
66356948Smckusick #undef DIRBLKSIZ
66456948Smckusick #include <dirent.h>
66556948Smckusick #undef d_ino
66656948Smckusick 
66756948Smckusick struct dirent *
66856948Smckusick glob_readdir(dirp)
66956948Smckusick 	RST_DIR *dirp;
67017752Smckusick {
67156948Smckusick 	struct direct *dp;
67256948Smckusick 	static struct dirent adirent;
67356948Smckusick 
67456948Smckusick 	while ((dp = rst_readdir(dirp)) != NULL) {
67556948Smckusick 		if (dp->d_ino == 0)
67656948Smckusick 			continue;
67756948Smckusick 		if (dflag || TSTINO(dp->d_ino, dumpmap))
67856948Smckusick 			break;
67956948Smckusick 	}
68056948Smckusick 	if (dp == NULL)
68156948Smckusick 		return (NULL);
68256948Smckusick 	adirent.d_fileno = dp->d_ino;
68356948Smckusick 	adirent.d_namlen = dp->d_namlen;
68456948Smckusick 	bcopy(dp->d_name, adirent.d_name, dp->d_namlen + 1);
68556948Smckusick 	return (&adirent);
68617752Smckusick }
68717752Smckusick 
68817752Smckusick /*
68956948Smckusick  * Return st_mode information in response to stat or lstat calls
69017752Smckusick  */
69156948Smckusick static int
69256948Smckusick glob_stat(name, stp)
693*57896Sbostic 	const char *name;
69456948Smckusick 	struct stat *stp;
69517752Smckusick {
69656948Smckusick 	register struct direct *dp;
69717752Smckusick 
69856948Smckusick 	dp = pathsearch(name);
69956948Smckusick 	if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0))
70056948Smckusick 		return (-1);
70156948Smckusick 	if (inodetype(dp->d_ino) == NODE)
70256948Smckusick 		stp->st_mode = IFDIR;
70317752Smckusick 	else
70456948Smckusick 		stp->st_mode = IFREG;
70556948Smckusick 	return (0);
70656948Smckusick }
70754593Smckusick 
70856948Smckusick /*
70956948Smckusick  * Comparison routine for qsort.
71056948Smckusick  */
71156948Smckusick static int
71256948Smckusick fcmp(f1, f2)
71356948Smckusick 	register const void *f1, *f2;
71456948Smckusick {
71556948Smckusick 	return (strcmp(((struct afile *)f1)->fname,
71656948Smckusick 	    ((struct afile *)f2)->fname));
71717752Smckusick }
71817752Smckusick 
71917752Smckusick /*
72017752Smckusick  * respond to interrupts
72117752Smckusick  */
72239942Sbostic void
72356567Sbostic onintr(signo)
72456567Sbostic 	int signo;
72517752Smckusick {
72656429Smckusick 	if (command == 'i' && runshell)
72717752Smckusick 		longjmp(reset, 1);
72817752Smckusick 	if (reply("restore interrupted, continue") == FAIL)
72917752Smckusick 		done(1);
73017752Smckusick }
731