132020Spc /*
232020Spc  * Copyright (c) 1985 Regents of the University of California.
332020Spc  * All rights reserved.  The Berkeley software License Agreement
432020Spc  * specifies the terms and conditions for redistribution.
532020Spc  */
632020Spc 
732020Spc #ifndef lint
8*32023Spc static char sccsid[] = "@(#)interactive.c	5.5 (Berkeley) 4/23/87";
932020Spc #endif not lint
1032020Spc 
1132020Spc #include "restore.h"
1232020Spc #include <protocols/dumprestore.h>
1332020Spc #include <setjmp.h>
1432020Spc 
1532020Spc #define round(a, b) (((a) + (b) - 1) / (b) * (b))
1632020Spc 
1732020Spc /*
1832020Spc  * Things to handle interruptions.
1932020Spc  */
2032020Spc static jmp_buf reset;
2132020Spc static char *nextarg = NULL;
2232020Spc 
2332020Spc /*
2432020Spc  * Structure and routines associated with listing directories.
2532020Spc  */
2632020Spc struct afile {
2732020Spc 	ino_t	fnum;		/* inode number of file */
2832020Spc 	char	*fname;		/* file name */
2932020Spc 	short	fflags;		/* extraction flags, if any */
3032020Spc 	char	ftype;		/* file type, e.g. LEAF or NODE */
3132020Spc };
3232020Spc struct arglist {
3332020Spc 	struct afile	*head;	/* start of argument list */
3432020Spc 	struct afile	*last;	/* end of argument list */
3532020Spc 	struct afile	*base;	/* current list arena */
3632020Spc 	int		nent;	/* maximum size of list */
3732020Spc 	char		*cmd;	/* the current command */
3832020Spc };
3932020Spc extern int fcmp();
4032020Spc extern char *fmtentry();
4132020Spc char *copynext();
4232020Spc 
4332020Spc /*
4432020Spc  * Read and execute commands from the terminal.
4532020Spc  */
runcmdshell()4632020Spc runcmdshell()
4732020Spc {
4832020Spc 	register struct entry *np;
4932020Spc 	ino_t ino;
5032020Spc 	static struct arglist alist = { 0, 0, 0, 0, 0 };
5132020Spc 	char curdir[MAXPATHLEN];
5232020Spc 	char name[MAXPATHLEN];
5332020Spc 	char cmd[BUFSIZ];
5432020Spc 
5532020Spc 	canon("/", curdir);
5632020Spc loop:
5732020Spc 	if (setjmp(reset) != 0) {
5832020Spc 		for (; alist.head < alist.last; alist.head++)
5932020Spc 			freename(alist.head->fname);
6032020Spc 		nextarg = NULL;
6132020Spc 		volno = 0;
6232020Spc 	}
6332020Spc 	getcmd(curdir, cmd, name, &alist);
6432020Spc 	switch (cmd[0]) {
6532020Spc 	/*
6632020Spc 	 * Add elements to the extraction list.
6732020Spc 	 */
6832020Spc 	case 'a':
69*32023Spc 		if (strncmp(cmd, "add", strlen(cmd)) != 0)
70*32023Spc 			goto bad;
7132020Spc 		ino = dirlookup(name);
7232020Spc 		if (ino == 0)
7332020Spc 			break;
7432020Spc 		if (mflag)
7532020Spc 			pathcheck(name);
7632020Spc 		treescan(name, ino, addfile);
7732020Spc 		break;
7832020Spc 	/*
7932020Spc 	 * Change working directory.
8032020Spc 	 */
8132020Spc 	case 'c':
82*32023Spc 		if (strncmp(cmd, "cd", strlen(cmd)) != 0)
83*32023Spc 			goto bad;
8432020Spc 		ino = dirlookup(name);
8532020Spc 		if (ino == 0)
8632020Spc 			break;
8732020Spc 		if (inodetype(ino) == LEAF) {
8832020Spc 			fprintf(stderr, "%s: not a directory\n", name);
8932020Spc 			break;
9032020Spc 		}
9132020Spc 		(void) strcpy(curdir, name);
9232020Spc 		break;
9332020Spc 	/*
9432020Spc 	 * Delete elements from the extraction list.
9532020Spc 	 */
9632020Spc 	case 'd':
97*32023Spc 		if (strncmp(cmd, "delete", strlen(cmd)) != 0)
98*32023Spc 			goto bad;
9932020Spc 		np = lookupname(name);
10032020Spc 		if (np == NIL || (np->e_flags & NEW) == 0) {
10132020Spc 			fprintf(stderr, "%s: not on extraction list\n", name);
10232020Spc 			break;
10332020Spc 		}
10432020Spc 		treescan(name, np->e_ino, deletefile);
10532020Spc 		break;
10632020Spc 	/*
10732020Spc 	 * Extract the requested list.
10832020Spc 	 */
10932020Spc 	case 'e':
110*32023Spc 		if (strncmp(cmd, "extract", strlen(cmd)) != 0)
111*32023Spc 			goto bad;
11232020Spc 		createfiles();
11332020Spc 		createlinks();
11432020Spc 		setdirmodes();
11532020Spc 		if (dflag)
11632020Spc 			checkrestore();
11732020Spc 		volno = 0;
11832020Spc 		break;
11932020Spc 	/*
12032020Spc 	 * List available commands.
12132020Spc 	 */
12232020Spc 	case 'h':
123*32023Spc 		if (strncmp(cmd, "help", strlen(cmd)) != 0)
124*32023Spc 			goto bad;
12532020Spc 	case '?':
126*32023Spc 		fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
12732020Spc 			"Available commands are:\n",
12832020Spc 			"\tls [arg] - list directory\n",
12932020Spc 			"\tcd arg - change directory\n",
13032020Spc 			"\tpwd - print current directory\n",
13132020Spc 			"\tadd [arg] - add `arg' to list of",
13232020Spc 			" files to be extracted\n",
13332020Spc 			"\tdelete [arg] - delete `arg' from",
13432020Spc 			" list of files to be extracted\n",
13532020Spc 			"\textract - extract requested files\n",
13632020Spc 			"\tsetmodes - set modes of requested directories\n",
13732020Spc 			"\tquit - immediately exit program\n",
138*32023Spc 			"\twhat - list dump header information\n",
13932020Spc 			"\tverbose - toggle verbose flag",
14032020Spc 			" (useful with ``ls'')\n",
14132020Spc 			"\thelp or `?' - print this list\n",
14232020Spc 			"If no `arg' is supplied, the current",
14332020Spc 			" directory is used\n");
14432020Spc 		break;
14532020Spc 	/*
14632020Spc 	 * List a directory.
14732020Spc 	 */
14832020Spc 	case 'l':
149*32023Spc 		if (strncmp(cmd, "ls", strlen(cmd)) != 0)
150*32023Spc 			goto bad;
15132020Spc 		ino = dirlookup(name);
15232020Spc 		if (ino == 0)
15332020Spc 			break;
15432020Spc 		printlist(name, ino, curdir);
15532020Spc 		break;
15632020Spc 	/*
15732020Spc 	 * Print current directory.
15832020Spc 	 */
15932020Spc 	case 'p':
160*32023Spc 		if (strncmp(cmd, "pwd", strlen(cmd)) != 0)
161*32023Spc 			goto bad;
16232020Spc 		if (curdir[1] == '\0')
16332020Spc 			fprintf(stderr, "/\n");
16432020Spc 		else
16532020Spc 			fprintf(stderr, "%s\n", &curdir[1]);
16632020Spc 		break;
16732020Spc 	/*
16832020Spc 	 * Quit.
16932020Spc 	 */
17032020Spc 	case 'q':
171*32023Spc 		if (strncmp(cmd, "quit", strlen(cmd)) != 0)
172*32023Spc 			goto bad;
173*32023Spc 		return;
17432020Spc 	case 'x':
175*32023Spc 		if (strncmp(cmd, "xit", strlen(cmd)) != 0)
176*32023Spc 			goto bad;
17732020Spc 		return;
17832020Spc 	/*
17932020Spc 	 * Toggle verbose mode.
18032020Spc 	 */
18132020Spc 	case 'v':
182*32023Spc 		if (strncmp(cmd, "verbose", strlen(cmd)) != 0)
183*32023Spc 			goto bad;
18432020Spc 		if (vflag) {
18532020Spc 			fprintf(stderr, "verbose mode off\n");
18632020Spc 			vflag = 0;
18732020Spc 			break;
18832020Spc 		}
18932020Spc 		fprintf(stderr, "verbose mode on\n");
19032020Spc 		vflag++;
19132020Spc 		break;
19232020Spc 	/*
19332020Spc 	 * Just restore requested directory modes.
19432020Spc 	 */
19532020Spc 	case 's':
196*32023Spc 		if (strncmp(cmd, "setmodes", strlen(cmd)) != 0)
197*32023Spc 			goto bad;
19832020Spc 		setdirmodes();
19932020Spc 		break;
20032020Spc 	/*
201*32023Spc 	 * Print out dump header information.
202*32023Spc 	 */
203*32023Spc 	case 'w':
204*32023Spc 		if (strncmp(cmd, "what", strlen(cmd)) != 0)
205*32023Spc 			goto bad;
206*32023Spc 		printdumpinfo();
207*32023Spc 		break;
208*32023Spc 	/*
20932020Spc 	 * Turn on debugging.
21032020Spc 	 */
21132020Spc 	case 'D':
212*32023Spc 		if (strncmp(cmd, "Debug", strlen(cmd)) != 0)
213*32023Spc 			goto bad;
21432020Spc 		if (dflag) {
21532020Spc 			fprintf(stderr, "debugging mode off\n");
21632020Spc 			dflag = 0;
21732020Spc 			break;
21832020Spc 		}
21932020Spc 		fprintf(stderr, "debugging mode on\n");
22032020Spc 		dflag++;
22132020Spc 		break;
22232020Spc 	/*
22332020Spc 	 * Unknown command.
22432020Spc 	 */
22532020Spc 	default:
226*32023Spc 	bad:
22732020Spc 		fprintf(stderr, "%s: unknown command; type ? for help\n", cmd);
22832020Spc 		break;
22932020Spc 	}
23032020Spc 	goto loop;
23132020Spc }
23232020Spc 
23332020Spc /*
23432020Spc  * Read and parse an interactive command.
23532020Spc  * The first word on the line is assigned to "cmd". If
23632020Spc  * there are no arguments on the command line, then "curdir"
23732020Spc  * is returned as the argument. If there are arguments
23832020Spc  * on the line they are returned one at a time on each
23932020Spc  * successive call to getcmd. Each argument is first assigned
24032020Spc  * to "name". If it does not start with "/" the pathname in
24132020Spc  * "curdir" is prepended to it. Finally "canon" is called to
24232020Spc  * eliminate any embedded ".." components.
24332020Spc  */
getcmd(curdir,cmd,name,ap)24432020Spc getcmd(curdir, cmd, name, ap)
24532020Spc 	char *curdir, *cmd, *name;
24632020Spc 	struct arglist *ap;
24732020Spc {
24832020Spc 	register char *cp;
24932020Spc 	static char input[BUFSIZ];
25032020Spc 	char output[BUFSIZ];
25132020Spc #	define rawname input	/* save space by reusing input buffer */
25232020Spc 
25332020Spc 	/*
25432020Spc 	 * Check to see if still processing arguments.
25532020Spc 	 */
25632020Spc 	if (ap->head != ap->last) {
25732020Spc 		strcpy(name, ap->head->fname);
25832020Spc 		freename(ap->head->fname);
25932020Spc 		ap->head++;
26032020Spc 		return;
26132020Spc 	}
26232020Spc 	if (nextarg != NULL)
26332020Spc 		goto getnext;
26432020Spc 	/*
26532020Spc 	 * Read a command line and trim off trailing white space.
26632020Spc 	 */
26732020Spc 	do	{
26832020Spc 		fprintf(stderr, "restore > ");
26932020Spc 		(void) fflush(stderr);
27032020Spc 		(void) fgets(input, BUFSIZ, terminal);
27132020Spc 	} while (!feof(terminal) && input[0] == '\n');
27232020Spc 	if (feof(terminal)) {
27332020Spc 		(void) strcpy(cmd, "quit");
27432020Spc 		return;
27532020Spc 	}
27632020Spc 	for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--)
27732020Spc 		/* trim off trailing white space and newline */;
27832020Spc 	*++cp = '\0';
27932020Spc 	/*
28032020Spc 	 * Copy the command into "cmd".
28132020Spc 	 */
28232020Spc 	cp = copynext(input, cmd);
28332020Spc 	ap->cmd = cmd;
28432020Spc 	/*
28532020Spc 	 * If no argument, use curdir as the default.
28632020Spc 	 */
28732020Spc 	if (*cp == '\0') {
28832020Spc 		(void) strcpy(name, curdir);
28932020Spc 		return;
29032020Spc 	}
29132020Spc 	nextarg = cp;
29232020Spc 	/*
29332020Spc 	 * Find the next argument.
29432020Spc 	 */
29532020Spc getnext:
29632020Spc 	cp = copynext(nextarg, rawname);
29732020Spc 	if (*cp == '\0')
29832020Spc 		nextarg = NULL;
29932020Spc 	else
30032020Spc 		nextarg = cp;
30132020Spc 	/*
30232020Spc 	 * If it an absolute pathname, canonicalize it and return it.
30332020Spc 	 */
30432020Spc 	if (rawname[0] == '/') {
30532020Spc 		canon(rawname, name);
30632020Spc 	} else {
30732020Spc 		/*
30832020Spc 		 * For relative pathnames, prepend the current directory to
30932020Spc 		 * it then canonicalize and return it.
31032020Spc 		 */
31132020Spc 		(void) strcpy(output, curdir);
31232020Spc 		(void) strcat(output, "/");
31332020Spc 		(void) strcat(output, rawname);
31432020Spc 		canon(output, name);
31532020Spc 	}
31632020Spc 	expandarg(name, ap);
31732020Spc 	strcpy(name, ap->head->fname);
31832020Spc 	freename(ap->head->fname);
31932020Spc 	ap->head++;
32032020Spc #	undef rawname
32132020Spc }
32232020Spc 
32332020Spc /*
32432020Spc  * Strip off the next token of the input.
32532020Spc  */
32632020Spc char *
copynext(input,output)32732020Spc copynext(input, output)
32832020Spc 	char *input, *output;
32932020Spc {
33032020Spc 	register char *cp, *bp;
33132020Spc 	char quote;
33232020Spc 
33332020Spc 	for (cp = input; *cp == ' ' || *cp == '\t'; cp++)
33432020Spc 		/* skip to argument */;
33532020Spc 	bp = output;
33632020Spc 	while (*cp != ' ' && *cp != '\t' && *cp != '\0') {
33732020Spc 		/*
33832020Spc 		 * Handle back slashes.
33932020Spc 		 */
34032020Spc 		if (*cp == '\\') {
34132020Spc 			if (*++cp == '\0') {
34232020Spc 				fprintf(stderr,
34332020Spc 					"command lines cannot be continued\n");
34432020Spc 				continue;
34532020Spc 			}
34632020Spc 			*bp++ = *cp++;
34732020Spc 			continue;
34832020Spc 		}
34932020Spc 		/*
35032020Spc 		 * The usual unquoted case.
35132020Spc 		 */
35232020Spc 		if (*cp != '\'' && *cp != '"') {
35332020Spc 			*bp++ = *cp++;
35432020Spc 			continue;
35532020Spc 		}
35632020Spc 		/*
35732020Spc 		 * Handle single and double quotes.
35832020Spc 		 */
35932020Spc 		quote = *cp++;
36032020Spc 		while (*cp != quote && *cp != '\0')
36132020Spc 			*bp++ = *cp++ | 0200;
36232020Spc 		if (*cp++ == '\0') {
36332020Spc 			fprintf(stderr, "missing %c\n", quote);
36432020Spc 			cp--;
36532020Spc 			continue;
36632020Spc 		}
36732020Spc 	}
36832020Spc 	*bp = '\0';
36932020Spc 	return (cp);
37032020Spc }
37132020Spc 
37232020Spc /*
37332020Spc  * Canonicalize file names to always start with ``./'' and
37432020Spc  * remove any imbedded "." and ".." components.
37532020Spc  */
canon(rawname,canonname)37632020Spc canon(rawname, canonname)
37732020Spc 	char *rawname, *canonname;
37832020Spc {
37932020Spc 	register char *cp, *np;
38032020Spc 	int len;
38132020Spc 
38232020Spc 	if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0)
38332020Spc 		(void) strcpy(canonname, "");
38432020Spc 	else if (rawname[0] == '/')
38532020Spc 		(void) strcpy(canonname, ".");
38632020Spc 	else
38732020Spc 		(void) strcpy(canonname, "./");
38832020Spc 	(void) strcat(canonname, rawname);
38932020Spc 	/*
39032020Spc 	 * Eliminate multiple and trailing '/'s
39132020Spc 	 */
39232020Spc 	for (cp = np = canonname; *np != '\0'; cp++) {
39332020Spc 		*cp = *np++;
39432020Spc 		while (*cp == '/' && *np == '/')
39532020Spc 			np++;
39632020Spc 	}
39732020Spc 	*cp = '\0';
39832020Spc 	if (*--cp == '/')
39932020Spc 		*cp = '\0';
40032020Spc 	/*
40132020Spc 	 * Eliminate extraneous "." and ".." from pathnames.
40232020Spc 	 */
40332020Spc 	for (np = canonname; *np != '\0'; ) {
40432020Spc 		np++;
40532020Spc 		cp = np;
40632020Spc 		while (*np != '/' && *np != '\0')
40732020Spc 			np++;
40832020Spc 		if (np - cp == 1 && *cp == '.') {
40932020Spc 			cp--;
41032020Spc 			(void) strcpy(cp, np);
41132020Spc 			np = cp;
41232020Spc 		}
41332020Spc 		if (np - cp == 2 && strncmp(cp, "..", 2) == 0) {
41432020Spc 			cp--;
41532020Spc 			while (cp > &canonname[1] && *--cp != '/')
41632020Spc 				/* find beginning of name */;
41732020Spc 			(void) strcpy(cp, np);
41832020Spc 			np = cp;
41932020Spc 		}
42032020Spc 	}
42132020Spc }
42232020Spc 
42332020Spc /*
42432020Spc  * globals (file name generation)
42532020Spc  *
42632020Spc  * "*" in params matches r.e ".*"
42732020Spc  * "?" in params matches r.e. "."
42832020Spc  * "[...]" in params matches character class
42932020Spc  * "[...a-z...]" in params matches a through z.
43032020Spc  */
expandarg(arg,ap)43132020Spc expandarg(arg, ap)
43232020Spc 	char *arg;
43332020Spc 	register struct arglist *ap;
43432020Spc {
43532020Spc 	static struct afile single;
436*32023Spc 	struct entry *ep;
43732020Spc 	int size;
43832020Spc 
43932020Spc 	ap->head = ap->last = (struct afile *)0;
44032020Spc 	size = expand(arg, 0, ap);
44132020Spc 	if (size == 0) {
442*32023Spc 		ep = lookupname(arg);
443*32023Spc 		single.fnum = ep ? ep->e_ino : 0;
44432020Spc 		single.fname = savename(arg);
44532020Spc 		ap->head = &single;
44632020Spc 		ap->last = ap->head + 1;
44732020Spc 		return;
44832020Spc 	}
44932020Spc 	qsort((char *)ap->head, ap->last - ap->head, sizeof *ap->head, fcmp);
45032020Spc }
45132020Spc 
45232020Spc /*
45332020Spc  * Expand a file name
45432020Spc  */
expand(as,rflg,ap)45532020Spc expand(as, rflg, ap)
45632020Spc 	char *as;
45732020Spc 	int rflg;
45832020Spc 	register struct arglist *ap;
45932020Spc {
46032020Spc 	int		count, size;
46132020Spc 	char		dir = 0;
46232020Spc 	char		*rescan = 0;
46332020Spc 	DIR		*dirp;
46432020Spc 	register char	*s, *cs;
46532020Spc 	int		sindex, rindex, lindex;
46632020Spc 	struct direct	*dp;
46732020Spc 	register char	slash;
46832020Spc 	register char	*rs;
46932020Spc 	register char	c;
47032020Spc 
47132020Spc 	/*
47232020Spc 	 * check for meta chars
47332020Spc 	 */
47432020Spc 	s = cs = as;
47532020Spc 	slash = 0;
47632020Spc 	while (*cs != '*' && *cs != '?' && *cs != '[') {
47732020Spc 		if (*cs++ == 0) {
47832020Spc 			if (rflg && slash)
47932020Spc 				break;
48032020Spc 			else
48132020Spc 				return (0) ;
48232020Spc 		} else if (*cs == '/') {
48332020Spc 			slash++;
48432020Spc 		}
48532020Spc 	}
48632020Spc 	for (;;) {
48732020Spc 		if (cs == s) {
48832020Spc 			s = "";
48932020Spc 			break;
49032020Spc 		} else if (*--cs == '/') {
49132020Spc 			*cs = 0;
49232020Spc 			if (s == cs)
49332020Spc 				s = "/";
49432020Spc 			break;
49532020Spc 		}
49632020Spc 	}
49732020Spc 	if ((dirp = rst_opendir(s)) != NULL)
49832020Spc 		dir++;
49932020Spc 	count = 0;
50032020Spc 	if (*cs == 0)
50132020Spc 		*cs++ = 0200;
50232020Spc 	if (dir) {
50332020Spc 		/*
50432020Spc 		 * check for rescan
50532020Spc 		 */
50632020Spc 		rs = cs;
50732020Spc 		do {
50832020Spc 			if (*rs == '/') {
50932020Spc 				rescan = rs;
51032020Spc 				*rs = 0;
51132020Spc 			}
51232020Spc 		} while (*rs++);
51332020Spc 		sindex = ap->last - ap->head;
51432020Spc 		while ((dp = rst_readdir(dirp)) != NULL && dp->d_ino != 0) {
51532020Spc 			if (!dflag && BIT(dp->d_ino, dumpmap) == 0)
51632020Spc 				continue;
51732020Spc 			if ((*dp->d_name == '.' && *cs != '.'))
51832020Spc 				continue;
51932020Spc 			if (gmatch(dp->d_name, cs)) {
52032020Spc 				if (addg(dp, s, rescan, ap) < 0)
52132020Spc 					return (-1);
52232020Spc 				count++;
52332020Spc 			}
52432020Spc 		}
52532020Spc 		if (rescan) {
52632020Spc 			rindex = sindex;
52732020Spc 			lindex = ap->last - ap->head;
52832020Spc 			if (count) {
52932020Spc 				count = 0;
53032020Spc 				while (rindex < lindex) {
53132020Spc 					size = expand(ap->head[rindex].fname,
53232020Spc 					    1, ap);
53332020Spc 					if (size < 0)
53432020Spc 						return (size);
53532020Spc 					count += size;
53632020Spc 					rindex++;
53732020Spc 				}
53832020Spc 			}
53932020Spc 			bcopy((char *)&ap->head[lindex],
54032020Spc 			     (char *)&ap->head[sindex],
54132020Spc 			     (ap->last - &ap->head[rindex]) * sizeof *ap->head);
54232020Spc 			ap->last -= lindex - sindex;
54332020Spc 			*rescan = '/';
54432020Spc 		}
54532020Spc 	}
54632020Spc 	s = as;
54732020Spc 	while (c = *s)
54832020Spc 		*s++ = (c&0177 ? c : '/');
54932020Spc 	return (count);
55032020Spc }
55132020Spc 
55232020Spc /*
55332020Spc  * Check for a name match
55432020Spc  */
gmatch(s,p)55532020Spc gmatch(s, p)
55632020Spc 	register char	*s, *p;
55732020Spc {
55832020Spc 	register int	scc;
55932020Spc 	char		c;
56032020Spc 	char		ok;
56132020Spc 	int		lc;
56232020Spc 
56332020Spc 	if (scc = *s++)
56432020Spc 		if ((scc &= 0177) == 0)
56532020Spc 			scc = 0200;
56632020Spc 	switch (c = *p++) {
56732020Spc 
56832020Spc 	case '[':
56932020Spc 		ok = 0;
57032020Spc 		lc = 077777;
57132020Spc 		while (c = *p++) {
57232020Spc 			if (c == ']') {
57332020Spc 				return (ok ? gmatch(s, p) : 0);
57432020Spc 			} else if (c == '-') {
57532020Spc 				if (lc <= scc && scc <= (*p++))
57632020Spc 					ok++ ;
57732020Spc 			} else {
57832020Spc 				if (scc == (lc = (c&0177)))
57932020Spc 					ok++ ;
58032020Spc 			}
58132020Spc 		}
58232020Spc 		return (0);
58332020Spc 
58432020Spc 	default:
58532020Spc 		if ((c&0177) != scc)
58632020Spc 			return (0) ;
58732020Spc 		/* falls through */
58832020Spc 
58932020Spc 	case '?':
59032020Spc 		return (scc ? gmatch(s, p) : 0);
59132020Spc 
59232020Spc 	case '*':
59332020Spc 		if (*p == 0)
59432020Spc 			return (1) ;
59532020Spc 		s--;
59632020Spc 		while (*s) {
59732020Spc 			if (gmatch(s++, p))
59832020Spc 				return (1);
59932020Spc 		}
60032020Spc 		return (0);
60132020Spc 
60232020Spc 	case 0:
60332020Spc 		return (scc == 0);
60432020Spc 	}
60532020Spc }
60632020Spc 
60732020Spc /*
60832020Spc  * Construct a matched name.
60932020Spc  */
61032020Spc addg(dp, as1, as3, ap)
61132020Spc 	struct direct	*dp;
61232020Spc 	char		*as1, *as3;
61332020Spc 	struct arglist	*ap;
61432020Spc {
61532020Spc 	register char	*s1, *s2;
61632020Spc 	register int	c;
61732020Spc 	char		buf[BUFSIZ];
61832020Spc 
61932020Spc 	s2 = buf;
62032020Spc 	s1 = as1;
62132020Spc 	while (c = *s1++) {
62232020Spc 		if ((c &= 0177) == 0) {
62332020Spc 			*s2++ = '/';
62432020Spc 			break;
62532020Spc 		}
62632020Spc 		*s2++ = c;
62732020Spc 	}
62832020Spc 	s1 = dp->d_name;
62932020Spc 	while (*s2 = *s1++)
63032020Spc 		s2++;
63132020Spc 	if (s1 = as3) {
63232020Spc 		*s2++ = '/';
63332020Spc 		while (*s2++ = *++s1)
63432020Spc 			/* void */;
63532020Spc 	}
63632020Spc 	if (mkentry(buf, dp->d_ino, ap) == FAIL)
63732020Spc 		return (-1);
63832020Spc }
63932020Spc 
64032020Spc /*
64132020Spc  * Do an "ls" style listing of a directory
64232020Spc  */
printlist(name,ino,basename)64332020Spc printlist(name, ino, basename)
64432020Spc 	char *name;
64532020Spc 	ino_t ino;
64632020Spc 	char *basename;
64732020Spc {
64832020Spc 	register struct afile *fp;
64932020Spc 	register struct direct *dp;
65032020Spc 	static struct arglist alist = { 0, 0, 0, 0, "ls" };
65132020Spc 	struct afile single;
65232020Spc 	DIR *dirp;
65332020Spc 
65432020Spc 	if ((dirp = rst_opendir(name)) == NULL) {
65532020Spc 		single.fnum = ino;
65632020Spc 		single.fname = savename(name + strlen(basename) + 1);
65732020Spc 		alist.head = &single;
65832020Spc 		alist.last = alist.head + 1;
65932020Spc 	} else {
66032020Spc 		alist.head = (struct afile *)0;
66132020Spc 		fprintf(stderr, "%s:\n", name);
66232020Spc 		while (dp = rst_readdir(dirp)) {
66332020Spc 			if (dp == NULL || dp->d_ino == 0)
66432020Spc 				break;
66532020Spc 			if (!dflag && BIT(dp->d_ino, dumpmap) == 0)
66632020Spc 				continue;
66732020Spc 			if (vflag == 0 &&
66832020Spc 			    (strcmp(dp->d_name, ".") == 0 ||
66932020Spc 			     strcmp(dp->d_name, "..") == 0))
67032020Spc 				continue;
67132020Spc 			if (!mkentry(dp->d_name, dp->d_ino, &alist))
67232020Spc 				return;
67332020Spc 		}
67432020Spc 	}
67532020Spc 	if (alist.head != 0) {
67632020Spc 		qsort((char *)alist.head, alist.last - alist.head,
67732020Spc 			sizeof *alist.head, fcmp);
67832020Spc 		formatf(&alist);
67932020Spc 		for (fp = alist.head; fp < alist.last; fp++)
68032020Spc 			freename(fp->fname);
68132020Spc 	}
68232020Spc 	if (dirp != NULL)
68332020Spc 		fprintf(stderr, "\n");
68432020Spc }
68532020Spc 
68632020Spc /*
68732020Spc  * Read the contents of a directory.
68832020Spc  */
mkentry(name,ino,ap)68932020Spc mkentry(name, ino, ap)
69032020Spc 	char *name;
69132020Spc 	ino_t ino;
69232020Spc 	register struct arglist *ap;
69332020Spc {
69432020Spc 	register struct afile *fp;
69532020Spc 
69632020Spc 	if (ap->base == NULL) {
69732020Spc 		ap->nent = 20;
69832020Spc 		ap->base = (struct afile *)calloc((unsigned)ap->nent,
69932020Spc 			sizeof (struct afile));
70032020Spc 		if (ap->base == NULL) {
70132020Spc 			fprintf(stderr, "%s: out of memory\n", ap->cmd);
70232020Spc 			return (FAIL);
70332020Spc 		}
70432020Spc 	}
70532020Spc 	if (ap->head == 0)
70632020Spc 		ap->head = ap->last = ap->base;
70732020Spc 	fp = ap->last;
70832020Spc 	fp->fnum = ino;
70932020Spc 	fp->fname = savename(name);
71032020Spc 	fp++;
71132020Spc 	if (fp == ap->head + ap->nent) {
71232020Spc 		ap->base = (struct afile *)realloc((char *)ap->base,
71332020Spc 		    (unsigned)(2 * ap->nent * sizeof (struct afile)));
71432020Spc 		if (ap->base == 0) {
71532020Spc 			fprintf(stderr, "%s: out of memory\n", ap->cmd);
71632020Spc 			return (FAIL);
71732020Spc 		}
71832020Spc 		ap->head = ap->base;
71932020Spc 		fp = ap->head + ap->nent;
72032020Spc 		ap->nent *= 2;
72132020Spc 	}
72232020Spc 	ap->last = fp;
72332020Spc 	return (GOOD);
72432020Spc }
72532020Spc 
72632020Spc /*
72732020Spc  * Print out a pretty listing of a directory
72832020Spc  */
formatf(ap)72932020Spc formatf(ap)
73032020Spc 	register struct arglist *ap;
73132020Spc {
73232020Spc 	register struct afile *fp;
73332020Spc 	struct entry *np;
73432020Spc 	int width = 0, w, nentry = ap->last - ap->head;
73532020Spc 	int i, j, len, columns, lines;
73632020Spc 	char *cp;
73732020Spc 
73832020Spc 	if (ap->head == ap->last)
73932020Spc 		return;
74032020Spc 	for (fp = ap->head; fp < ap->last; fp++) {
74132020Spc 		fp->ftype = inodetype(fp->fnum);
74232020Spc 		np = lookupino(fp->fnum);
74332020Spc 		if (np != NIL)
74432020Spc 			fp->fflags = np->e_flags;
74532020Spc 		else
74632020Spc 			fp->fflags = 0;
74732020Spc 		len = strlen(fmtentry(fp));
74832020Spc 		if (len > width)
74932020Spc 			width = len;
75032020Spc 	}
75132020Spc 	width += 2;
75232020Spc 	columns = 80 / width;
75332020Spc 	if (columns == 0)
75432020Spc 		columns = 1;
75532020Spc 	lines = (nentry + columns - 1) / columns;
75632020Spc 	for (i = 0; i < lines; i++) {
75732020Spc 		for (j = 0; j < columns; j++) {
75832020Spc 			fp = ap->head + j * lines + i;
75932020Spc 			cp = fmtentry(fp);
76032020Spc 			fprintf(stderr, "%s", cp);
76132020Spc 			if (fp + lines >= ap->last) {
76232020Spc 				fprintf(stderr, "\n");
76332020Spc 				break;
76432020Spc 			}
76532020Spc 			w = strlen(cp);
76632020Spc 			while (w < width) {
76732020Spc 				w++;
76832020Spc 				fprintf(stderr, " ");
76932020Spc 			}
77032020Spc 		}
77132020Spc 	}
77232020Spc }
77332020Spc 
77432020Spc /*
77532020Spc  * Comparison routine for qsort.
77632020Spc  */
fcmp(f1,f2)77732020Spc fcmp(f1, f2)
77832020Spc 	register struct afile *f1, *f2;
77932020Spc {
78032020Spc 
78132020Spc 	return (strcmp(f1->fname, f2->fname));
78232020Spc }
78332020Spc 
78432020Spc /*
78532020Spc  * Format a directory entry.
78632020Spc  */
78732020Spc char *
fmtentry(fp)78832020Spc fmtentry(fp)
78932020Spc 	register struct afile *fp;
79032020Spc {
79132020Spc 	static char fmtres[BUFSIZ];
79232020Spc 	static int precision = 0;
79332020Spc 	int i;
79432020Spc 	register char *cp, *dp;
79532020Spc 
79632020Spc 	if (!vflag) {
79732020Spc 		fmtres[0] = '\0';
79832020Spc 	} else {
79932020Spc 		if (precision == 0)
80032020Spc 			for (i = maxino; i > 0; i /= 10)
80132020Spc 				precision++;
80232020Spc 		(void) sprintf(fmtres, "%*d ", precision, fp->fnum);
80332020Spc 	}
80432020Spc 	dp = &fmtres[strlen(fmtres)];
80532020Spc 	if (dflag && BIT(fp->fnum, dumpmap) == 0)
80632020Spc 		*dp++ = '^';
80732020Spc 	else if ((fp->fflags & NEW) != 0)
80832020Spc 		*dp++ = '*';
80932020Spc 	else
81032020Spc 		*dp++ = ' ';
81132020Spc 	for (cp = fp->fname; *cp; cp++)
81232020Spc 		if (!vflag && (*cp < ' ' || *cp >= 0177))
81332020Spc 			*dp++ = '?';
81432020Spc 		else
81532020Spc 			*dp++ = *cp;
81632020Spc 	if (fp->ftype == NODE)
81732020Spc 		*dp++ = '/';
81832020Spc 	*dp++ = 0;
81932020Spc 	return (fmtres);
82032020Spc }
82132020Spc 
82232020Spc /*
82332020Spc  * respond to interrupts
82432020Spc  */
onintr()82532020Spc onintr()
82632020Spc {
82732020Spc 	if (command == 'i')
82832020Spc 		longjmp(reset, 1);
82932020Spc 	if (reply("restore interrupted, continue") == FAIL)
83032020Spc 		done(1);
83132020Spc }
832