117752Smckusick /* Copyright (c) 1985 Regents of the University of California */ 217752Smckusick 317752Smckusick #ifndef lint 4*18003Smckusick static char sccsid[] = "@(#)interactive.c 3.3 (Berkeley) 02/18/85"; 517752Smckusick #endif not lint 617752Smckusick 717752Smckusick #include "restore.h" 817752Smckusick #include <dumprestor.h> 917752Smckusick #include <setjmp.h> 1017752Smckusick 1117756Smckusick #define round(a, b) (((a) + (b) - 1) / (b) * (b)) 1217756Smckusick 1317752Smckusick /* 1417752Smckusick * Things to handle interruptions. 1517752Smckusick */ 1617752Smckusick static jmp_buf reset; 1717752Smckusick static char *nextarg = NULL; 1817752Smckusick 1917752Smckusick /* 2017752Smckusick * Structure and routines associated with listing directories. 2117752Smckusick */ 2217752Smckusick struct afile { 2317752Smckusick ino_t fnum; /* inode number of file */ 2417752Smckusick char *fname; /* file name */ 2517752Smckusick short fflags; /* extraction flags, if any */ 2617752Smckusick char ftype; /* file type, e.g. LEAF or NODE */ 2717752Smckusick }; 28*18003Smckusick struct arglist { 29*18003Smckusick struct afile *head; /* start of argument list */ 30*18003Smckusick struct afile *last; /* end of argument list */ 31*18003Smckusick struct afile *base; /* current list arena */ 32*18003Smckusick int nent; /* maximum size of list */ 33*18003Smckusick char *cmd; /* the current command */ 34*18003Smckusick }; 3517752Smckusick extern int fcmp(); 3617752Smckusick extern char *fmtentry(); 3717752Smckusick char *copynext(); 3817752Smckusick 3917752Smckusick /* 4017752Smckusick * Read and execute commands from the terminal. 4117752Smckusick */ 4217752Smckusick runcmdshell() 4317752Smckusick { 4417752Smckusick register struct entry *np; 4517752Smckusick ino_t ino; 46*18003Smckusick static struct arglist alist = { 0, 0, 0, 0, 0 }; 4717752Smckusick char curdir[MAXPATHLEN]; 4817752Smckusick char name[MAXPATHLEN]; 4917752Smckusick char cmd[BUFSIZ]; 5017752Smckusick 5117752Smckusick canon("/", curdir); 5217752Smckusick loop: 5317752Smckusick if (setjmp(reset) != 0) { 54*18003Smckusick for (; alist.head < alist.last; alist.head++) 55*18003Smckusick freename(alist.head->fname); 5617752Smckusick nextarg = NULL; 5717752Smckusick volno = 0; 5817752Smckusick } 59*18003Smckusick getcmd(curdir, cmd, name, &alist); 6017752Smckusick switch (cmd[0]) { 6117752Smckusick /* 6217752Smckusick * Add elements to the extraction list. 6317752Smckusick */ 6417752Smckusick case 'a': 6517752Smckusick ino = dirlookup(name); 6617752Smckusick if (ino == 0) 6717752Smckusick break; 6817752Smckusick if (mflag) 6917752Smckusick pathcheck(name); 7017752Smckusick treescan(name, ino, addfile); 7117752Smckusick break; 7217752Smckusick /* 7317752Smckusick * Change working directory. 7417752Smckusick */ 7517752Smckusick case 'c': 7617752Smckusick ino = dirlookup(name); 7717752Smckusick if (ino == 0) 7817752Smckusick break; 7917752Smckusick if (inodetype(ino) == LEAF) { 8017752Smckusick fprintf(stderr, "%s: not a directory\n", name); 8117752Smckusick break; 8217752Smckusick } 8317752Smckusick (void) strcpy(curdir, name); 8417752Smckusick break; 8517752Smckusick /* 8617752Smckusick * Delete elements from the extraction list. 8717752Smckusick */ 8817752Smckusick case 'd': 8917752Smckusick np = lookupname(name); 9017752Smckusick if (np == NIL || (np->e_flags & NEW) == 0) { 9117752Smckusick fprintf(stderr, "%s: not on extraction list\n", name); 9217752Smckusick break; 9317752Smckusick } 9417752Smckusick treescan(name, np->e_ino, deletefile); 9517752Smckusick break; 9617752Smckusick /* 9717752Smckusick * Extract the requested list. 9817752Smckusick */ 9917752Smckusick case 'e': 10017752Smckusick createfiles(); 10117752Smckusick createlinks(); 10217752Smckusick setdirmodes(); 10317752Smckusick if (dflag) 10417752Smckusick checkrestore(); 10517752Smckusick volno = 0; 10617752Smckusick break; 10717752Smckusick /* 10817752Smckusick * List available commands. 10917752Smckusick */ 11017752Smckusick case 'h': 11117752Smckusick case '?': 11217752Smckusick fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 11317752Smckusick "Available commands are:\n", 11417752Smckusick "\tls [arg] - list directory\n", 11517752Smckusick "\tcd arg - change directory\n", 11617752Smckusick "\tpwd - print current directory\n", 11717752Smckusick "\tadd [arg] - add `arg' to list of", 11817752Smckusick " files to be extracted\n", 11917752Smckusick "\tdelete [arg] - delete `arg' from", 12017752Smckusick " list of files to be extracted\n", 12117752Smckusick "\textract - extract requested files\n", 12217752Smckusick "\tquit - immediately exit program\n", 12317752Smckusick "\tverbose - toggle verbose flag", 12417752Smckusick " (useful with ``ls'')\n", 12517752Smckusick "\thelp or `?' - print this list\n", 12617752Smckusick "If no `arg' is supplied, the current", 12717752Smckusick " directory is used\n"); 12817752Smckusick break; 12917752Smckusick /* 13017752Smckusick * List a directory. 13117752Smckusick */ 13217752Smckusick case 'l': 13317752Smckusick ino = dirlookup(name); 13417752Smckusick if (ino == 0) 13517752Smckusick break; 13617752Smckusick printlist(name, ino, curdir); 13717752Smckusick break; 13817752Smckusick /* 13917752Smckusick * Print current directory. 14017752Smckusick */ 14117752Smckusick case 'p': 14217752Smckusick if (curdir[1] == '\0') 14317752Smckusick fprintf(stderr, "/\n"); 14417752Smckusick else 14517752Smckusick fprintf(stderr, "%s\n", &curdir[1]); 14617752Smckusick break; 14717752Smckusick /* 14817752Smckusick * Quit. 14917752Smckusick */ 15017752Smckusick case 'q': 15117752Smckusick case 'x': 15217752Smckusick return; 15317752Smckusick /* 15417752Smckusick * Toggle verbose mode. 15517752Smckusick */ 15617752Smckusick case 'v': 15717752Smckusick if (vflag) { 15817752Smckusick fprintf(stderr, "verbose mode off\n"); 15917752Smckusick vflag = 0; 16017752Smckusick break; 16117752Smckusick } 16217752Smckusick fprintf(stderr, "verbose mode on\n"); 16317752Smckusick vflag++; 16417752Smckusick break; 16517752Smckusick /* 16617752Smckusick * Just restore requested directory modes. 16717752Smckusick */ 16817752Smckusick case 'R': 16917752Smckusick setdirmodes(); 17017752Smckusick break; 17117752Smckusick /* 17217752Smckusick * Turn on debugging. 17317752Smckusick */ 17417752Smckusick case 'D': 17517752Smckusick if (dflag) { 17617752Smckusick fprintf(stderr, "debugging mode off\n"); 17717752Smckusick dflag = 0; 17817752Smckusick break; 17917752Smckusick } 18017752Smckusick fprintf(stderr, "debugging mode on\n"); 18117752Smckusick dflag++; 18217752Smckusick break; 18317752Smckusick /* 18417752Smckusick * Unknown command. 18517752Smckusick */ 18617752Smckusick default: 18717752Smckusick fprintf(stderr, "%s: unknown command; type ? for help\n", cmd); 18817752Smckusick break; 18917752Smckusick } 19017752Smckusick goto loop; 19117752Smckusick } 19217752Smckusick 19317752Smckusick /* 19417752Smckusick * Read and parse an interactive command. 19517752Smckusick * The first word on the line is assigned to "cmd". If 19617752Smckusick * there are no arguments on the command line, then "curdir" 19717752Smckusick * is returned as the argument. If there are arguments 19817752Smckusick * on the line they are returned one at a time on each 19917752Smckusick * successive call to getcmd. Each argument is first assigned 20017752Smckusick * to "name". If it does not start with "/" the pathname in 20117752Smckusick * "curdir" is prepended to it. Finally "canon" is called to 20217752Smckusick * eliminate any embedded ".." components. 20317752Smckusick */ 204*18003Smckusick getcmd(curdir, cmd, name, ap) 20517752Smckusick char *curdir, *cmd, *name; 206*18003Smckusick struct arglist *ap; 20717752Smckusick { 20817752Smckusick register char *cp; 20917752Smckusick static char input[BUFSIZ]; 21017752Smckusick char output[BUFSIZ]; 21117752Smckusick # define rawname input /* save space by reusing input buffer */ 21217752Smckusick 21317752Smckusick /* 21417752Smckusick * Check to see if still processing arguments. 21517752Smckusick */ 216*18003Smckusick if (ap->head != ap->last) { 217*18003Smckusick strcpy(name, ap->head->fname); 218*18003Smckusick freename(ap->head->fname); 219*18003Smckusick ap->head++; 220*18003Smckusick return; 221*18003Smckusick } 22217752Smckusick if (nextarg != NULL) 22317752Smckusick goto getnext; 22417752Smckusick /* 22517752Smckusick * Read a command line and trim off trailing white space. 22617752Smckusick */ 22717752Smckusick do { 22817752Smckusick fprintf(stderr, "restore > "); 22917752Smckusick (void) fflush(stderr); 23017752Smckusick (void) fgets(input, BUFSIZ, terminal); 23117752Smckusick } while (!feof(terminal) && input[0] == '\n'); 23217752Smckusick if (feof(terminal)) { 23317752Smckusick (void) strcpy(cmd, "quit"); 23417752Smckusick return; 23517752Smckusick } 23617752Smckusick for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--) 23717752Smckusick /* trim off trailing white space and newline */; 23817752Smckusick *++cp = '\0'; 23917752Smckusick /* 24017752Smckusick * Copy the command into "cmd". 24117752Smckusick */ 24217752Smckusick cp = copynext(input, cmd); 243*18003Smckusick ap->cmd = cmd; 24417752Smckusick /* 24517752Smckusick * If no argument, use curdir as the default. 24617752Smckusick */ 24717752Smckusick if (*cp == '\0') { 24817752Smckusick (void) strcpy(name, curdir); 24917752Smckusick return; 25017752Smckusick } 25117752Smckusick nextarg = cp; 25217752Smckusick /* 25317752Smckusick * Find the next argument. 25417752Smckusick */ 25517752Smckusick getnext: 25617752Smckusick cp = copynext(nextarg, rawname); 25717752Smckusick if (*cp == '\0') 25817752Smckusick nextarg = NULL; 25917752Smckusick else 26017752Smckusick nextarg = cp; 26117752Smckusick /* 26217752Smckusick * If it an absolute pathname, canonicalize it and return it. 26317752Smckusick */ 26417752Smckusick if (rawname[0] == '/') { 26517752Smckusick canon(rawname, name); 26617752Smckusick } else { 26717752Smckusick /* 26817752Smckusick * For relative pathnames, prepend the current directory to 26917752Smckusick * it then canonicalize and return it. 27017752Smckusick */ 27117752Smckusick (void) strcpy(output, curdir); 27217752Smckusick (void) strcat(output, "/"); 27317752Smckusick (void) strcat(output, rawname); 27417752Smckusick canon(output, name); 27517752Smckusick } 276*18003Smckusick expandarg(name, ap); 277*18003Smckusick strcpy(name, ap->head->fname); 278*18003Smckusick freename(ap->head->fname); 279*18003Smckusick ap->head++; 28017752Smckusick # undef rawname 28117752Smckusick } 28217752Smckusick 28317752Smckusick /* 28417752Smckusick * Strip off the next token of the input. 28517752Smckusick */ 28617752Smckusick char * 28717752Smckusick copynext(input, output) 28817752Smckusick char *input, *output; 28917752Smckusick { 29017752Smckusick register char *cp, *bp; 29117752Smckusick char quote; 29217752Smckusick 29317752Smckusick for (cp = input; *cp == ' ' || *cp == '\t'; cp++) 29417752Smckusick /* skip to argument */; 29517752Smckusick bp = output; 29617752Smckusick while (*cp != ' ' && *cp != '\t' && *cp != '\0') { 29717752Smckusick /* 29817752Smckusick * Handle back slashes. 29917752Smckusick */ 30017752Smckusick if (*cp == '\\') { 30117752Smckusick if (*++cp == '\0') { 30217752Smckusick fprintf(stderr, 30317752Smckusick "command lines cannot be continued\n"); 30417752Smckusick continue; 30517752Smckusick } 30617752Smckusick *bp++ = *cp++; 30717752Smckusick continue; 30817752Smckusick } 30917752Smckusick /* 31017752Smckusick * The usual unquoted case. 31117752Smckusick */ 31217752Smckusick if (*cp != '\'' && *cp != '"') { 31317752Smckusick *bp++ = *cp++; 31417752Smckusick continue; 31517752Smckusick } 31617752Smckusick /* 31717752Smckusick * Handle single and double quotes. 31817752Smckusick */ 31917752Smckusick quote = *cp++; 32017752Smckusick while (*cp != quote && *cp != '\0') 32117752Smckusick *bp++ = *cp++ | 0200; 32217752Smckusick if (*cp++ == '\0') { 32317752Smckusick fprintf(stderr, "missing %c\n", quote); 32417752Smckusick cp--; 32517752Smckusick continue; 32617752Smckusick } 32717752Smckusick } 32817752Smckusick *bp = '\0'; 32917752Smckusick return (cp); 33017752Smckusick } 33117752Smckusick 33217752Smckusick /* 33317752Smckusick * Canonicalize file names to always start with ``./'' and 334*18003Smckusick * remove any imbedded "." and ".." components. 33517752Smckusick */ 33617752Smckusick canon(rawname, canonname) 33717752Smckusick char *rawname, *canonname; 33817752Smckusick { 33917752Smckusick register char *cp, *np; 34017752Smckusick int len; 34117752Smckusick 34217752Smckusick if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0) 34317752Smckusick (void) strcpy(canonname, ""); 34417752Smckusick else if (rawname[0] == '/') 34517752Smckusick (void) strcpy(canonname, "."); 34617752Smckusick else 34717752Smckusick (void) strcpy(canonname, "./"); 34817752Smckusick (void) strcat(canonname, rawname); 34917752Smckusick /* 350*18003Smckusick * Eliminate multiple and trailing '/'s 35117752Smckusick */ 352*18003Smckusick for (cp = np = canonname; *np != '\0'; cp++) { 353*18003Smckusick *cp = *np++; 354*18003Smckusick while (*cp == '/' && *np == '/') 355*18003Smckusick np++; 356*18003Smckusick } 357*18003Smckusick *cp = '\0'; 358*18003Smckusick if (*--cp == '/') 359*18003Smckusick *cp = '\0'; 360*18003Smckusick /* 361*18003Smckusick * Eliminate extraneous "." and ".." from pathnames. 362*18003Smckusick */ 36317752Smckusick for (np = canonname; *np != '\0'; ) { 36417752Smckusick np++; 36517752Smckusick cp = np; 36617752Smckusick while (*np != '/' && *np != '\0') 36717752Smckusick np++; 368*18003Smckusick if (np - cp == 1 && *cp == '.') { 369*18003Smckusick cp--; 370*18003Smckusick (void) strcpy(cp, np); 371*18003Smckusick np = cp; 372*18003Smckusick } 37317752Smckusick if (np - cp == 2 && strncmp(cp, "..", 2) == 0) { 37417752Smckusick cp--; 37517752Smckusick while (cp > &canonname[1] && *--cp != '/') 37617752Smckusick /* find beginning of name */; 37717752Smckusick (void) strcpy(cp, np); 37817752Smckusick np = cp; 37917752Smckusick } 38017752Smckusick } 38117752Smckusick } 38217752Smckusick 38317752Smckusick /* 38417756Smckusick * globals (file name generation) 38517756Smckusick * 38617756Smckusick * "*" in params matches r.e ".*" 38717756Smckusick * "?" in params matches r.e. "." 38817756Smckusick * "[...]" in params matches character class 38917756Smckusick * "[...a-z...]" in params matches a through z. 39017756Smckusick */ 391*18003Smckusick expandarg(arg, ap) 39217756Smckusick char *arg; 393*18003Smckusick register struct arglist *ap; 39417756Smckusick { 395*18003Smckusick struct afile single; 39617756Smckusick int size; 39717756Smckusick 398*18003Smckusick ap->head = ap->last = (struct afile *)0; 399*18003Smckusick size = expand(arg, 0, ap); 40017756Smckusick if (size == 0) { 401*18003Smckusick single.fnum = lookupname(arg)->e_ino; 402*18003Smckusick single.fname = savename(arg); 403*18003Smckusick ap->head = &single; 404*18003Smckusick ap->last = ap->head + 1; 405*18003Smckusick return; 40617756Smckusick } 407*18003Smckusick qsort((char *)ap->head, ap->last - ap->head, sizeof *ap->head, fcmp); 40817756Smckusick } 40917756Smckusick 41017756Smckusick /* 41117756Smckusick * Expand a file name 41217756Smckusick */ 413*18003Smckusick expand(as, rflg, ap) 41417756Smckusick char *as; 41517756Smckusick int rflg; 416*18003Smckusick register struct arglist *ap; 41717756Smckusick { 41817756Smckusick int count, size; 41917756Smckusick char dir = 0; 42017756Smckusick char *rescan = 0; 42117756Smckusick DIR *dirp; 42217756Smckusick register char *s, *cs; 423*18003Smckusick int sindex, rindex, lindex; 42417756Smckusick struct direct *dp; 42517756Smckusick register char slash; 42617756Smckusick register char *rs; 42717756Smckusick register char c; 42817756Smckusick 42917756Smckusick /* 43017756Smckusick * check for meta chars 43117756Smckusick */ 43217756Smckusick s = cs = as; 43317756Smckusick slash = 0; 43417756Smckusick while (*cs != '*' && *cs != '?' && *cs != '[') { 435*18003Smckusick if (*cs++ == 0) { 43617756Smckusick if (rflg && slash) 43717756Smckusick break; 43817756Smckusick else 43917756Smckusick return (0) ; 440*18003Smckusick } else if (*cs == '/') { 44117756Smckusick slash++; 44217756Smckusick } 44317756Smckusick } 44417756Smckusick for (;;) { 44517756Smckusick if (cs == s) { 446*18003Smckusick s = ""; 44717756Smckusick break; 44817756Smckusick } else if (*--cs == '/') { 44917756Smckusick *cs = 0; 45017756Smckusick if (s == cs) 45117756Smckusick s = "/"; 45217756Smckusick break; 45317756Smckusick } 45417756Smckusick } 45517756Smckusick if ((dirp = rst_opendir(s)) != NULL) 45617756Smckusick dir++; 45717756Smckusick count = 0; 45817756Smckusick if (*cs == 0) 459*18003Smckusick *cs++ = 0200; 46017756Smckusick if (dir) { 46117756Smckusick /* 46217756Smckusick * check for rescan 46317756Smckusick */ 46417756Smckusick rs = cs; 46517756Smckusick do { 46617756Smckusick if (*rs == '/') { 46717756Smckusick rescan = rs; 46817756Smckusick *rs = 0; 46917756Smckusick } 47017756Smckusick } while (*rs++); 471*18003Smckusick sindex = ap->last - ap->head; 47217756Smckusick while ((dp = rst_readdir(dirp)) != NULL && dp->d_ino != 0) { 47317756Smckusick if (!dflag && BIT(dp->d_ino, dumpmap) == 0) 47417756Smckusick continue; 47517756Smckusick if ((*dp->d_name == '.' && *cs != '.')) 47617756Smckusick continue; 47717756Smckusick if (gmatch(dp->d_name, cs)) { 478*18003Smckusick if (addg(dp, s, rescan, ap) < 0) 47917756Smckusick return (-1); 48017756Smckusick count++; 48117756Smckusick } 48217756Smckusick } 48317756Smckusick if (rescan) { 484*18003Smckusick rindex = sindex; 485*18003Smckusick lindex = ap->last - ap->head; 48617756Smckusick if (count) { 48717756Smckusick count = 0; 488*18003Smckusick while (rindex < lindex) { 489*18003Smckusick size = expand(ap->head[rindex].fname, 490*18003Smckusick 1, ap); 49117756Smckusick if (size < 0) 49217756Smckusick return (size); 49317756Smckusick count += size; 494*18003Smckusick rindex++; 49517756Smckusick } 49617756Smckusick } 497*18003Smckusick bcopy((char *)&ap->head[lindex], 498*18003Smckusick (char *)&ap->head[sindex], 499*18003Smckusick (ap->last - &ap->head[rindex]) * sizeof *ap->head); 500*18003Smckusick ap->last -= lindex - sindex; 50117756Smckusick *rescan = '/'; 50217756Smckusick } 50317756Smckusick } 50417756Smckusick s = as; 50517756Smckusick while (c = *s) 50617756Smckusick *s++ = (c&0177 ? c : '/'); 50717756Smckusick return (count); 50817756Smckusick } 50917756Smckusick 51017756Smckusick /* 51117756Smckusick * Check for a name match 51217756Smckusick */ 51317756Smckusick gmatch(s, p) 51417756Smckusick register char *s, *p; 51517756Smckusick { 51617756Smckusick register int scc; 51717756Smckusick char c; 51817756Smckusick char ok; 51917756Smckusick int lc; 52017756Smckusick 52117756Smckusick if (scc = *s++) 52217756Smckusick if ((scc &= 0177) == 0) 52317756Smckusick scc = 0200; 52417756Smckusick switch (c = *p++) { 52517756Smckusick 52617756Smckusick case '[': 52717756Smckusick ok = 0; 52817756Smckusick lc = 077777; 52917756Smckusick while (c = *p++) { 530*18003Smckusick if (c == ']') { 53117756Smckusick return (ok ? gmatch(s, p) : 0); 53217756Smckusick } else if (c == '-') { 53317756Smckusick if (lc <= scc && scc <= (*p++)) 53417756Smckusick ok++ ; 53517756Smckusick } else { 53617756Smckusick if (scc == (lc = (c&0177))) 53717756Smckusick ok++ ; 53817756Smckusick } 53917756Smckusick } 54017756Smckusick return (0); 54117756Smckusick 54217756Smckusick default: 54317756Smckusick if ((c&0177) != scc) 54417756Smckusick return (0) ; 54517756Smckusick /* falls through */ 54617756Smckusick 54717756Smckusick case '?': 54817756Smckusick return (scc ? gmatch(s, p) : 0); 54917756Smckusick 55017756Smckusick case '*': 55117756Smckusick if (*p == 0) 55217756Smckusick return (1) ; 55317756Smckusick s--; 55417756Smckusick while (*s) { 55517756Smckusick if (gmatch(s++, p)) 55617756Smckusick return (1); 55717756Smckusick } 55817756Smckusick return (0); 55917756Smckusick 56017756Smckusick case 0: 56117756Smckusick return (scc == 0); 56217756Smckusick } 56317756Smckusick } 56417756Smckusick 56517756Smckusick /* 56617756Smckusick * Construct a matched name. 56717756Smckusick */ 568*18003Smckusick addg(dp, as1, as3, ap) 569*18003Smckusick struct direct *dp; 570*18003Smckusick char *as1, *as3; 571*18003Smckusick struct arglist *ap; 57217756Smckusick { 57317756Smckusick register char *s1, *s2; 57417756Smckusick register int c; 575*18003Smckusick char buf[BUFSIZ]; 57617756Smckusick 577*18003Smckusick s2 = buf; 57817756Smckusick s1 = as1; 57917756Smckusick while (c = *s1++) { 58017756Smckusick if ((c &= 0177) == 0) { 581*18003Smckusick *s2++ = '/'; 58217756Smckusick break; 58317756Smckusick } 58417756Smckusick *s2++ = c; 58517756Smckusick } 586*18003Smckusick s1 = dp->d_name; 58717756Smckusick while (*s2 = *s1++) 58817756Smckusick s2++; 58917756Smckusick if (s1 = as3) { 59017756Smckusick *s2++ = '/'; 59117756Smckusick while (*s2++ = *++s1) 59217756Smckusick /* void */; 59317756Smckusick } 594*18003Smckusick if (mkentry(buf, dp->d_ino, ap) == FAIL) 595*18003Smckusick return (-1); 59617756Smckusick } 59717756Smckusick 59817756Smckusick /* 59917752Smckusick * Do an "ls" style listing of a directory 60017752Smckusick */ 60117752Smckusick printlist(name, ino, basename) 60217752Smckusick char *name; 60317752Smckusick ino_t ino; 60417752Smckusick char *basename; 60517752Smckusick { 60617752Smckusick register struct afile *fp; 607*18003Smckusick register struct direct *dp; 608*18003Smckusick static struct arglist alist = { 0, 0, 0, 0, "ls" }; 60917752Smckusick struct afile single; 61017752Smckusick DIR *dirp; 61117752Smckusick 61217752Smckusick if ((dirp = rst_opendir(name)) == NULL) { 61317752Smckusick single.fnum = ino; 614*18003Smckusick single.fname = savename(name + strlen(basename) + 1); 615*18003Smckusick alist.head = &single; 616*18003Smckusick alist.last = alist.head + 1; 61717752Smckusick } else { 618*18003Smckusick alist.head = (struct afile *)0; 619*18003Smckusick fprintf(stderr, "%s:\n", name); 620*18003Smckusick while (dp = rst_readdir(dirp)) { 621*18003Smckusick if (dp == NULL || dp->d_ino == 0) 622*18003Smckusick break; 623*18003Smckusick if (!dflag && BIT(dp->d_ino, dumpmap) == 0) 624*18003Smckusick continue; 625*18003Smckusick if (vflag == 0 && 626*18003Smckusick (strcmp(dp->d_name, ".") == 0 || 627*18003Smckusick strcmp(dp->d_name, "..") == 0)) 628*18003Smckusick continue; 629*18003Smckusick if (!mkentry(dp->d_name, dp->d_ino, &alist)) 630*18003Smckusick return; 631*18003Smckusick } 63217752Smckusick } 633*18003Smckusick if (alist.head != 0) { 634*18003Smckusick qsort((char *)alist.head, alist.last - alist.head, 635*18003Smckusick sizeof *alist.head, fcmp); 636*18003Smckusick formatf(&alist); 637*18003Smckusick for (fp = alist.head; fp < alist.last; fp++) 638*18003Smckusick freename(fp->fname); 639*18003Smckusick } 640*18003Smckusick if (dirp != NULL) 641*18003Smckusick fprintf(stderr, "\n"); 64217752Smckusick } 64317752Smckusick 64417752Smckusick /* 64517752Smckusick * Read the contents of a directory. 64617752Smckusick */ 647*18003Smckusick mkentry(name, ino, ap) 648*18003Smckusick char *name; 649*18003Smckusick ino_t ino; 650*18003Smckusick register struct arglist *ap; 65117752Smckusick { 65217752Smckusick register struct afile *fp; 65317752Smckusick 654*18003Smckusick if (ap->base == NULL) { 655*18003Smckusick ap->nent = 20; 656*18003Smckusick ap->base = (struct afile *)calloc((unsigned)ap->nent, 65717752Smckusick sizeof (struct afile)); 658*18003Smckusick if (ap->base == NULL) { 659*18003Smckusick fprintf(stderr, "%s: out of memory\n", ap->cmd); 66017752Smckusick return (FAIL); 66117752Smckusick } 66217752Smckusick } 663*18003Smckusick if (ap->head == 0) 664*18003Smckusick ap->head = ap->last = ap->base; 665*18003Smckusick fp = ap->last; 666*18003Smckusick fp->fnum = ino; 667*18003Smckusick fp->fname = savename(name); 668*18003Smckusick fp++; 669*18003Smckusick if (fp == ap->head + ap->nent) { 670*18003Smckusick ap->base = (struct afile *)realloc((char *)ap->base, 671*18003Smckusick (unsigned)(2 * ap->nent * sizeof (struct afile))); 672*18003Smckusick if (ap->base == 0) { 673*18003Smckusick fprintf(stderr, "%s: out of memory\n", ap->cmd); 674*18003Smckusick return (FAIL); 67517752Smckusick } 676*18003Smckusick ap->head = ap->base; 677*18003Smckusick fp = ap->head + ap->nent; 678*18003Smckusick ap->nent *= 2; 67917752Smckusick } 680*18003Smckusick ap->last = fp; 68117752Smckusick return (GOOD); 68217752Smckusick } 68317752Smckusick 68417752Smckusick /* 68517752Smckusick * Print out a pretty listing of a directory 68617752Smckusick */ 687*18003Smckusick formatf(ap) 688*18003Smckusick register struct arglist *ap; 68917752Smckusick { 69017752Smckusick register struct afile *fp; 69117752Smckusick struct entry *np; 692*18003Smckusick int width = 0, w, nentry = ap->last - ap->head; 69317752Smckusick int i, j, len, columns, lines; 69417752Smckusick char *cp; 69517752Smckusick 696*18003Smckusick if (ap->head == ap->last) 69717752Smckusick return; 698*18003Smckusick for (fp = ap->head; fp < ap->last; fp++) { 69917752Smckusick fp->ftype = inodetype(fp->fnum); 70017752Smckusick np = lookupino(fp->fnum); 70117752Smckusick if (np != NIL) 70217752Smckusick fp->fflags = np->e_flags; 70317752Smckusick else 70417752Smckusick fp->fflags = 0; 70517752Smckusick len = strlen(fmtentry(fp)); 70617752Smckusick if (len > width) 70717752Smckusick width = len; 70817752Smckusick } 70917752Smckusick width += 2; 71017752Smckusick columns = 80 / width; 71117752Smckusick if (columns == 0) 71217752Smckusick columns = 1; 71317752Smckusick lines = (nentry + columns - 1) / columns; 71417752Smckusick for (i = 0; i < lines; i++) { 71517752Smckusick for (j = 0; j < columns; j++) { 716*18003Smckusick fp = ap->head + j * lines + i; 71717752Smckusick cp = fmtentry(fp); 71817752Smckusick fprintf(stderr, "%s", cp); 719*18003Smckusick if (fp + lines >= ap->last) { 72017752Smckusick fprintf(stderr, "\n"); 72117752Smckusick break; 72217752Smckusick } 72317752Smckusick w = strlen(cp); 72417752Smckusick while (w < width) { 72517752Smckusick w++; 72617752Smckusick fprintf(stderr, " "); 72717752Smckusick } 72817752Smckusick } 72917752Smckusick } 73017752Smckusick } 73117752Smckusick 73217752Smckusick /* 73317752Smckusick * Comparison routine for qsort. 73417752Smckusick */ 73517752Smckusick fcmp(f1, f2) 73617752Smckusick register struct afile *f1, *f2; 73717752Smckusick { 73817752Smckusick 73917752Smckusick return (strcmp(f1->fname, f2->fname)); 74017752Smckusick } 74117752Smckusick 74217752Smckusick /* 74317752Smckusick * Format a directory entry. 74417752Smckusick */ 74517752Smckusick char * 74617752Smckusick fmtentry(fp) 74717752Smckusick register struct afile *fp; 74817752Smckusick { 74917752Smckusick static char fmtres[BUFSIZ]; 75017752Smckusick register char *cp, *dp; 75117752Smckusick 75217752Smckusick if (vflag) 75317752Smckusick (void) sprintf(fmtres, "%5d ", fp->fnum); 75417752Smckusick else 75517752Smckusick fmtres[0] = '\0'; 75617752Smckusick dp = &fmtres[strlen(fmtres)]; 75717752Smckusick if (dflag && BIT(fp->fnum, dumpmap) == 0) 75817752Smckusick *dp++ = '^'; 75917752Smckusick else if ((fp->fflags & NEW) != 0) 76017752Smckusick *dp++ = '*'; 76117752Smckusick else 76217752Smckusick *dp++ = ' '; 76317752Smckusick for (cp = fp->fname; *cp; cp++) 76417752Smckusick if (!vflag && (*cp < ' ' || *cp >= 0177)) 76517752Smckusick *dp++ = '?'; 76617752Smckusick else 76717752Smckusick *dp++ = *cp; 76817752Smckusick if (fp->ftype == NODE) 76917752Smckusick *dp++ = '/'; 77017752Smckusick *dp++ = 0; 77117752Smckusick return (fmtres); 77217752Smckusick } 77317752Smckusick 77417752Smckusick /* 77517752Smckusick * respond to interrupts 77617752Smckusick */ 77717752Smckusick onintr() 77817752Smckusick { 77917752Smckusick if (command == 'i') 78017752Smckusick longjmp(reset, 1); 78117752Smckusick if (reply("restore interrupted, continue") == FAIL) 78217752Smckusick done(1); 78317752Smckusick } 784