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