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*56429Smckusick static char sccsid[] = "@(#)interactive.c 5.15 (Berkeley) 10/05/92"; 1036105Sbostic #endif /* not lint */ 1117752Smckusick 1217752Smckusick #include "restore.h" 1323546Smckusick #include <protocols/dumprestore.h> 1417752Smckusick #include <setjmp.h> 1551625Sbostic #include <ufs/ufs/dir.h> 1617752Smckusick 1717756Smckusick #define round(a, b) (((a) + (b) - 1) / (b) * (b)) 1817756Smckusick 1917752Smckusick /* 2017752Smckusick * Things to handle interruptions. 2117752Smckusick */ 22*56429Smckusick static int runshell; 2317752Smckusick static jmp_buf reset; 2417752Smckusick static char *nextarg = NULL; 2517752Smckusick 2617752Smckusick /* 2717752Smckusick * Structure and routines associated with listing directories. 2817752Smckusick */ 2917752Smckusick struct afile { 3017752Smckusick ino_t fnum; /* inode number of file */ 3117752Smckusick char *fname; /* file name */ 3217752Smckusick short fflags; /* extraction flags, if any */ 3317752Smckusick char ftype; /* file type, e.g. LEAF or NODE */ 3454593Smckusick char finotype; /* file type specified in directory entry */ 3517752Smckusick }; 3618003Smckusick struct arglist { 3718003Smckusick struct afile *head; /* start of argument list */ 3818003Smckusick struct afile *last; /* end of argument list */ 3918003Smckusick struct afile *base; /* current list arena */ 4018003Smckusick int nent; /* maximum size of list */ 4118003Smckusick char *cmd; /* the current command */ 4218003Smckusick }; 4317752Smckusick extern int fcmp(); 4417752Smckusick extern char *fmtentry(); 4517752Smckusick char *copynext(); 4617752Smckusick 4717752Smckusick /* 4817752Smckusick * Read and execute commands from the terminal. 4917752Smckusick */ 5017752Smckusick runcmdshell() 5117752Smckusick { 5217752Smckusick register struct entry *np; 5317752Smckusick ino_t ino; 5418003Smckusick static struct arglist alist = { 0, 0, 0, 0, 0 }; 5517752Smckusick char curdir[MAXPATHLEN]; 5617752Smckusick char name[MAXPATHLEN]; 5717752Smckusick char cmd[BUFSIZ]; 5817752Smckusick 5917752Smckusick canon("/", curdir); 6017752Smckusick loop: 6117752Smckusick if (setjmp(reset) != 0) { 6218003Smckusick for (; alist.head < alist.last; alist.head++) 6318003Smckusick freename(alist.head->fname); 6417752Smckusick nextarg = NULL; 6517752Smckusick volno = 0; 6617752Smckusick } 67*56429Smckusick runshell = 1; 6818003Smckusick getcmd(curdir, cmd, name, &alist); 6917752Smckusick switch (cmd[0]) { 7017752Smckusick /* 7117752Smckusick * Add elements to the extraction list. 7217752Smckusick */ 7317752Smckusick case 'a': 7429903Smckusick if (strncmp(cmd, "add", strlen(cmd)) != 0) 7529903Smckusick goto bad; 7617752Smckusick ino = dirlookup(name); 7717752Smckusick if (ino == 0) 7817752Smckusick break; 7917752Smckusick if (mflag) 8017752Smckusick pathcheck(name); 8117752Smckusick treescan(name, ino, addfile); 8217752Smckusick break; 8317752Smckusick /* 8417752Smckusick * Change working directory. 8517752Smckusick */ 8617752Smckusick case 'c': 8729903Smckusick if (strncmp(cmd, "cd", strlen(cmd)) != 0) 8829903Smckusick goto bad; 8917752Smckusick ino = dirlookup(name); 9017752Smckusick if (ino == 0) 9117752Smckusick break; 9217752Smckusick if (inodetype(ino) == LEAF) { 9317752Smckusick fprintf(stderr, "%s: not a directory\n", name); 9417752Smckusick break; 9517752Smckusick } 9617752Smckusick (void) strcpy(curdir, name); 9717752Smckusick break; 9817752Smckusick /* 9917752Smckusick * Delete elements from the extraction list. 10017752Smckusick */ 10117752Smckusick case 'd': 10229903Smckusick if (strncmp(cmd, "delete", strlen(cmd)) != 0) 10329903Smckusick goto bad; 10417752Smckusick np = lookupname(name); 10517752Smckusick if (np == NIL || (np->e_flags & NEW) == 0) { 10617752Smckusick fprintf(stderr, "%s: not on extraction list\n", name); 10717752Smckusick break; 10817752Smckusick } 10917752Smckusick treescan(name, np->e_ino, deletefile); 11017752Smckusick break; 11117752Smckusick /* 11217752Smckusick * Extract the requested list. 11317752Smckusick */ 11417752Smckusick case 'e': 11529903Smckusick if (strncmp(cmd, "extract", strlen(cmd)) != 0) 11629903Smckusick goto bad; 11717752Smckusick createfiles(); 11817752Smckusick createlinks(); 11955880Smckusick setdirmodes(0); 12017752Smckusick if (dflag) 12117752Smckusick checkrestore(); 12217752Smckusick volno = 0; 12317752Smckusick break; 12417752Smckusick /* 12517752Smckusick * List available commands. 12617752Smckusick */ 12717752Smckusick case 'h': 12829903Smckusick if (strncmp(cmd, "help", strlen(cmd)) != 0) 12929903Smckusick goto bad; 13017752Smckusick case '?': 13129903Smckusick fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 13217752Smckusick "Available commands are:\n", 13317752Smckusick "\tls [arg] - list directory\n", 13417752Smckusick "\tcd arg - change directory\n", 13517752Smckusick "\tpwd - print current directory\n", 13617752Smckusick "\tadd [arg] - add `arg' to list of", 13717752Smckusick " files to be extracted\n", 13817752Smckusick "\tdelete [arg] - delete `arg' from", 13917752Smckusick " list of files to be extracted\n", 14017752Smckusick "\textract - extract requested files\n", 14121096Smckusick "\tsetmodes - set modes of requested directories\n", 14217752Smckusick "\tquit - immediately exit program\n", 14329903Smckusick "\twhat - list dump header information\n", 14417752Smckusick "\tverbose - toggle verbose flag", 14517752Smckusick " (useful with ``ls'')\n", 14617752Smckusick "\thelp or `?' - print this list\n", 14717752Smckusick "If no `arg' is supplied, the current", 14817752Smckusick " directory is used\n"); 14917752Smckusick break; 15017752Smckusick /* 15117752Smckusick * List a directory. 15217752Smckusick */ 15317752Smckusick case 'l': 15429903Smckusick if (strncmp(cmd, "ls", strlen(cmd)) != 0) 15529903Smckusick goto bad; 15617752Smckusick ino = dirlookup(name); 15717752Smckusick if (ino == 0) 15817752Smckusick break; 15917752Smckusick printlist(name, ino, curdir); 16017752Smckusick break; 16117752Smckusick /* 16217752Smckusick * Print current directory. 16317752Smckusick */ 16417752Smckusick case 'p': 16529903Smckusick if (strncmp(cmd, "pwd", strlen(cmd)) != 0) 16629903Smckusick goto bad; 16717752Smckusick if (curdir[1] == '\0') 16817752Smckusick fprintf(stderr, "/\n"); 16917752Smckusick else 17017752Smckusick fprintf(stderr, "%s\n", &curdir[1]); 17117752Smckusick break; 17217752Smckusick /* 17317752Smckusick * Quit. 17417752Smckusick */ 17517752Smckusick case 'q': 17629903Smckusick if (strncmp(cmd, "quit", strlen(cmd)) != 0) 17729903Smckusick goto bad; 17829903Smckusick return; 17917752Smckusick case 'x': 18029903Smckusick if (strncmp(cmd, "xit", strlen(cmd)) != 0) 18129903Smckusick goto bad; 18217752Smckusick return; 18317752Smckusick /* 18417752Smckusick * Toggle verbose mode. 18517752Smckusick */ 18617752Smckusick case 'v': 18729903Smckusick if (strncmp(cmd, "verbose", strlen(cmd)) != 0) 18829903Smckusick goto bad; 18917752Smckusick if (vflag) { 19017752Smckusick fprintf(stderr, "verbose mode off\n"); 19117752Smckusick vflag = 0; 19217752Smckusick break; 19317752Smckusick } 19417752Smckusick fprintf(stderr, "verbose mode on\n"); 19517752Smckusick vflag++; 19617752Smckusick break; 19717752Smckusick /* 19817752Smckusick * Just restore requested directory modes. 19917752Smckusick */ 20021096Smckusick case 's': 20129903Smckusick if (strncmp(cmd, "setmodes", strlen(cmd)) != 0) 20229903Smckusick goto bad; 20355880Smckusick setdirmodes(FORCE); 20417752Smckusick break; 20517752Smckusick /* 20629903Smckusick * Print out dump header information. 20729903Smckusick */ 20829903Smckusick case 'w': 20929903Smckusick if (strncmp(cmd, "what", strlen(cmd)) != 0) 21029903Smckusick goto bad; 21129903Smckusick printdumpinfo(); 21229903Smckusick break; 21329903Smckusick /* 21417752Smckusick * Turn on debugging. 21517752Smckusick */ 21617752Smckusick case 'D': 21729903Smckusick if (strncmp(cmd, "Debug", strlen(cmd)) != 0) 21829903Smckusick goto bad; 21917752Smckusick if (dflag) { 22017752Smckusick fprintf(stderr, "debugging mode off\n"); 22117752Smckusick dflag = 0; 22217752Smckusick break; 22317752Smckusick } 22417752Smckusick fprintf(stderr, "debugging mode on\n"); 22517752Smckusick dflag++; 22617752Smckusick break; 22717752Smckusick /* 22817752Smckusick * Unknown command. 22917752Smckusick */ 23017752Smckusick default: 23129903Smckusick bad: 23217752Smckusick fprintf(stderr, "%s: unknown command; type ? for help\n", cmd); 23317752Smckusick break; 23417752Smckusick } 23517752Smckusick goto loop; 23617752Smckusick } 23717752Smckusick 23817752Smckusick /* 23917752Smckusick * Read and parse an interactive command. 24017752Smckusick * The first word on the line is assigned to "cmd". If 24117752Smckusick * there are no arguments on the command line, then "curdir" 24217752Smckusick * is returned as the argument. If there are arguments 24317752Smckusick * on the line they are returned one at a time on each 24417752Smckusick * successive call to getcmd. Each argument is first assigned 24517752Smckusick * to "name". If it does not start with "/" the pathname in 24617752Smckusick * "curdir" is prepended to it. Finally "canon" is called to 24717752Smckusick * eliminate any embedded ".." components. 24817752Smckusick */ 24918003Smckusick getcmd(curdir, cmd, name, ap) 25017752Smckusick char *curdir, *cmd, *name; 25118003Smckusick struct arglist *ap; 25217752Smckusick { 25317752Smckusick register char *cp; 25417752Smckusick static char input[BUFSIZ]; 25517752Smckusick char output[BUFSIZ]; 25617752Smckusick # define rawname input /* save space by reusing input buffer */ 25717752Smckusick 25817752Smckusick /* 25917752Smckusick * Check to see if still processing arguments. 26017752Smckusick */ 26118003Smckusick if (ap->head != ap->last) { 26218003Smckusick strcpy(name, ap->head->fname); 26318003Smckusick freename(ap->head->fname); 26418003Smckusick ap->head++; 26518003Smckusick return; 26618003Smckusick } 26717752Smckusick if (nextarg != NULL) 26817752Smckusick goto getnext; 26917752Smckusick /* 27017752Smckusick * Read a command line and trim off trailing white space. 27117752Smckusick */ 27217752Smckusick do { 27317752Smckusick fprintf(stderr, "restore > "); 27417752Smckusick (void) fflush(stderr); 27517752Smckusick (void) fgets(input, BUFSIZ, terminal); 27617752Smckusick } while (!feof(terminal) && input[0] == '\n'); 27717752Smckusick if (feof(terminal)) { 27817752Smckusick (void) strcpy(cmd, "quit"); 27917752Smckusick return; 28017752Smckusick } 28117752Smckusick for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--) 28217752Smckusick /* trim off trailing white space and newline */; 28317752Smckusick *++cp = '\0'; 28417752Smckusick /* 28517752Smckusick * Copy the command into "cmd". 28617752Smckusick */ 28717752Smckusick cp = copynext(input, cmd); 28818003Smckusick ap->cmd = cmd; 28917752Smckusick /* 29017752Smckusick * If no argument, use curdir as the default. 29117752Smckusick */ 29217752Smckusick if (*cp == '\0') { 29317752Smckusick (void) strcpy(name, curdir); 29417752Smckusick return; 29517752Smckusick } 29617752Smckusick nextarg = cp; 29717752Smckusick /* 29817752Smckusick * Find the next argument. 29917752Smckusick */ 30017752Smckusick getnext: 30117752Smckusick cp = copynext(nextarg, rawname); 30217752Smckusick if (*cp == '\0') 30317752Smckusick nextarg = NULL; 30417752Smckusick else 30517752Smckusick nextarg = cp; 30617752Smckusick /* 30717752Smckusick * If it an absolute pathname, canonicalize it and return it. 30817752Smckusick */ 30917752Smckusick if (rawname[0] == '/') { 31017752Smckusick canon(rawname, name); 31117752Smckusick } else { 31217752Smckusick /* 31317752Smckusick * For relative pathnames, prepend the current directory to 31417752Smckusick * it then canonicalize and return it. 31517752Smckusick */ 31617752Smckusick (void) strcpy(output, curdir); 31717752Smckusick (void) strcat(output, "/"); 31817752Smckusick (void) strcat(output, rawname); 31917752Smckusick canon(output, name); 32017752Smckusick } 32118003Smckusick expandarg(name, ap); 32218003Smckusick strcpy(name, ap->head->fname); 32318003Smckusick freename(ap->head->fname); 32418003Smckusick ap->head++; 32517752Smckusick # undef rawname 32617752Smckusick } 32717752Smckusick 32817752Smckusick /* 32917752Smckusick * Strip off the next token of the input. 33017752Smckusick */ 33117752Smckusick char * 33217752Smckusick copynext(input, output) 33317752Smckusick char *input, *output; 33417752Smckusick { 33517752Smckusick register char *cp, *bp; 33617752Smckusick char quote; 33717752Smckusick 33817752Smckusick for (cp = input; *cp == ' ' || *cp == '\t'; cp++) 33917752Smckusick /* skip to argument */; 34017752Smckusick bp = output; 34117752Smckusick while (*cp != ' ' && *cp != '\t' && *cp != '\0') { 34217752Smckusick /* 34317752Smckusick * Handle back slashes. 34417752Smckusick */ 34517752Smckusick if (*cp == '\\') { 34617752Smckusick if (*++cp == '\0') { 34717752Smckusick fprintf(stderr, 34817752Smckusick "command lines cannot be continued\n"); 34917752Smckusick continue; 35017752Smckusick } 35117752Smckusick *bp++ = *cp++; 35217752Smckusick continue; 35317752Smckusick } 35417752Smckusick /* 35517752Smckusick * The usual unquoted case. 35617752Smckusick */ 35717752Smckusick if (*cp != '\'' && *cp != '"') { 35817752Smckusick *bp++ = *cp++; 35917752Smckusick continue; 36017752Smckusick } 36117752Smckusick /* 36217752Smckusick * Handle single and double quotes. 36317752Smckusick */ 36417752Smckusick quote = *cp++; 36517752Smckusick while (*cp != quote && *cp != '\0') 36617752Smckusick *bp++ = *cp++ | 0200; 36717752Smckusick if (*cp++ == '\0') { 36817752Smckusick fprintf(stderr, "missing %c\n", quote); 36917752Smckusick cp--; 37017752Smckusick continue; 37117752Smckusick } 37217752Smckusick } 37317752Smckusick *bp = '\0'; 37417752Smckusick return (cp); 37517752Smckusick } 37617752Smckusick 37717752Smckusick /* 37817752Smckusick * Canonicalize file names to always start with ``./'' and 37918003Smckusick * remove any imbedded "." and ".." components. 38017752Smckusick */ 38117752Smckusick canon(rawname, canonname) 38217752Smckusick char *rawname, *canonname; 38317752Smckusick { 38417752Smckusick register char *cp, *np; 38517752Smckusick int len; 38617752Smckusick 38717752Smckusick if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0) 38817752Smckusick (void) strcpy(canonname, ""); 38917752Smckusick else if (rawname[0] == '/') 39017752Smckusick (void) strcpy(canonname, "."); 39117752Smckusick else 39217752Smckusick (void) strcpy(canonname, "./"); 39317752Smckusick (void) strcat(canonname, rawname); 39417752Smckusick /* 39518003Smckusick * Eliminate multiple and trailing '/'s 39617752Smckusick */ 39718003Smckusick for (cp = np = canonname; *np != '\0'; cp++) { 39818003Smckusick *cp = *np++; 39918003Smckusick while (*cp == '/' && *np == '/') 40018003Smckusick np++; 40118003Smckusick } 40218003Smckusick *cp = '\0'; 40318003Smckusick if (*--cp == '/') 40418003Smckusick *cp = '\0'; 40518003Smckusick /* 40618003Smckusick * Eliminate extraneous "." and ".." from pathnames. 40718003Smckusick */ 40817752Smckusick for (np = canonname; *np != '\0'; ) { 40917752Smckusick np++; 41017752Smckusick cp = np; 41117752Smckusick while (*np != '/' && *np != '\0') 41217752Smckusick np++; 41318003Smckusick if (np - cp == 1 && *cp == '.') { 41418003Smckusick cp--; 41518003Smckusick (void) strcpy(cp, np); 41618003Smckusick np = cp; 41718003Smckusick } 41817752Smckusick if (np - cp == 2 && strncmp(cp, "..", 2) == 0) { 41917752Smckusick cp--; 42017752Smckusick while (cp > &canonname[1] && *--cp != '/') 42117752Smckusick /* find beginning of name */; 42217752Smckusick (void) strcpy(cp, np); 42317752Smckusick np = cp; 42417752Smckusick } 42517752Smckusick } 42617752Smckusick } 42717752Smckusick 42817752Smckusick /* 42917756Smckusick * globals (file name generation) 43017756Smckusick * 43117756Smckusick * "*" in params matches r.e ".*" 43217756Smckusick * "?" in params matches r.e. "." 43317756Smckusick * "[...]" in params matches character class 43417756Smckusick * "[...a-z...]" in params matches a through z. 43517756Smckusick */ 43618003Smckusick expandarg(arg, ap) 43717756Smckusick char *arg; 43818003Smckusick register struct arglist *ap; 43917756Smckusick { 44020850Smckusick static struct afile single; 44130950Smckusick struct entry *ep; 44217756Smckusick int size; 44317756Smckusick 44418003Smckusick ap->head = ap->last = (struct afile *)0; 44518003Smckusick size = expand(arg, 0, ap); 44617756Smckusick if (size == 0) { 44730950Smckusick ep = lookupname(arg); 44830950Smckusick single.fnum = ep ? ep->e_ino : 0; 44918003Smckusick single.fname = savename(arg); 45018003Smckusick ap->head = &single; 45118003Smckusick ap->last = ap->head + 1; 45218003Smckusick return; 45317756Smckusick } 45418003Smckusick qsort((char *)ap->head, ap->last - ap->head, sizeof *ap->head, fcmp); 45517756Smckusick } 45617756Smckusick 45717756Smckusick /* 45817756Smckusick * Expand a file name 45917756Smckusick */ 46018003Smckusick expand(as, rflg, ap) 46117756Smckusick char *as; 46217756Smckusick int rflg; 46318003Smckusick register struct arglist *ap; 46417756Smckusick { 46517756Smckusick int count, size; 46617756Smckusick char dir = 0; 46717756Smckusick char *rescan = 0; 46850655Smckusick RST_DIR *dirp; 46917756Smckusick register char *s, *cs; 47018003Smckusick int sindex, rindex, lindex; 47117756Smckusick struct direct *dp; 47217756Smckusick register char slash; 47317756Smckusick register char *rs; 47417756Smckusick register char c; 47517756Smckusick 47617756Smckusick /* 47717756Smckusick * check for meta chars 47817756Smckusick */ 47917756Smckusick s = cs = as; 48017756Smckusick slash = 0; 48117756Smckusick while (*cs != '*' && *cs != '?' && *cs != '[') { 48218003Smckusick if (*cs++ == 0) { 48317756Smckusick if (rflg && slash) 48417756Smckusick break; 48517756Smckusick else 48617756Smckusick return (0) ; 48718003Smckusick } else if (*cs == '/') { 48817756Smckusick slash++; 48917756Smckusick } 49017756Smckusick } 49117756Smckusick for (;;) { 49217756Smckusick if (cs == s) { 49318003Smckusick s = ""; 49417756Smckusick break; 49517756Smckusick } else if (*--cs == '/') { 49617756Smckusick *cs = 0; 49717756Smckusick if (s == cs) 49817756Smckusick s = "/"; 49917756Smckusick break; 50017756Smckusick } 50117756Smckusick } 50217756Smckusick if ((dirp = rst_opendir(s)) != NULL) 50317756Smckusick dir++; 50417756Smckusick count = 0; 50517756Smckusick if (*cs == 0) 50618003Smckusick *cs++ = 0200; 50717756Smckusick if (dir) { 50817756Smckusick /* 50917756Smckusick * check for rescan 51017756Smckusick */ 51117756Smckusick rs = cs; 51217756Smckusick do { 51317756Smckusick if (*rs == '/') { 51417756Smckusick rescan = rs; 51517756Smckusick *rs = 0; 51617756Smckusick } 51717756Smckusick } while (*rs++); 51818003Smckusick sindex = ap->last - ap->head; 51917756Smckusick while ((dp = rst_readdir(dirp)) != NULL && dp->d_ino != 0) { 52056427Smckusick if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) 52117756Smckusick continue; 52217756Smckusick if ((*dp->d_name == '.' && *cs != '.')) 52317756Smckusick continue; 52417756Smckusick if (gmatch(dp->d_name, cs)) { 52518003Smckusick if (addg(dp, s, rescan, ap) < 0) 52617756Smckusick return (-1); 52717756Smckusick count++; 52817756Smckusick } 52917756Smckusick } 53017756Smckusick if (rescan) { 53118003Smckusick rindex = sindex; 53218003Smckusick lindex = ap->last - ap->head; 53317756Smckusick if (count) { 53417756Smckusick count = 0; 53518003Smckusick while (rindex < lindex) { 53618003Smckusick size = expand(ap->head[rindex].fname, 53718003Smckusick 1, ap); 53817756Smckusick if (size < 0) 53917756Smckusick return (size); 54017756Smckusick count += size; 54118003Smckusick rindex++; 54217756Smckusick } 54317756Smckusick } 54418003Smckusick bcopy((char *)&ap->head[lindex], 54518003Smckusick (char *)&ap->head[sindex], 54618003Smckusick (ap->last - &ap->head[rindex]) * sizeof *ap->head); 54718003Smckusick ap->last -= lindex - sindex; 54817756Smckusick *rescan = '/'; 54917756Smckusick } 55017756Smckusick } 55117756Smckusick s = as; 55217756Smckusick while (c = *s) 55317756Smckusick *s++ = (c&0177 ? c : '/'); 55417756Smckusick return (count); 55517756Smckusick } 55617756Smckusick 55717756Smckusick /* 55817756Smckusick * Check for a name match 55917756Smckusick */ 56017756Smckusick gmatch(s, p) 56117756Smckusick register char *s, *p; 56217756Smckusick { 56317756Smckusick register int scc; 56417756Smckusick char c; 56517756Smckusick char ok; 56617756Smckusick int lc; 56717756Smckusick 56817756Smckusick if (scc = *s++) 56917756Smckusick if ((scc &= 0177) == 0) 57017756Smckusick scc = 0200; 57117756Smckusick switch (c = *p++) { 57217756Smckusick 57317756Smckusick case '[': 57417756Smckusick ok = 0; 57517756Smckusick lc = 077777; 57617756Smckusick while (c = *p++) { 57718003Smckusick if (c == ']') { 57817756Smckusick return (ok ? gmatch(s, p) : 0); 57917756Smckusick } else if (c == '-') { 58017756Smckusick if (lc <= scc && scc <= (*p++)) 58117756Smckusick ok++ ; 58217756Smckusick } else { 58317756Smckusick if (scc == (lc = (c&0177))) 58417756Smckusick ok++ ; 58517756Smckusick } 58617756Smckusick } 58717756Smckusick return (0); 58817756Smckusick 58917756Smckusick default: 59017756Smckusick if ((c&0177) != scc) 59117756Smckusick return (0) ; 59217756Smckusick /* falls through */ 59317756Smckusick 59417756Smckusick case '?': 59517756Smckusick return (scc ? gmatch(s, p) : 0); 59617756Smckusick 59717756Smckusick case '*': 59817756Smckusick if (*p == 0) 59917756Smckusick return (1) ; 60017756Smckusick s--; 60117756Smckusick while (*s) { 60217756Smckusick if (gmatch(s++, p)) 60317756Smckusick return (1); 60417756Smckusick } 60517756Smckusick return (0); 60617756Smckusick 60717756Smckusick case 0: 60817756Smckusick return (scc == 0); 60917756Smckusick } 61017756Smckusick } 61117756Smckusick 61217756Smckusick /* 61317756Smckusick * Construct a matched name. 61417756Smckusick */ 61518003Smckusick addg(dp, as1, as3, ap) 61618003Smckusick struct direct *dp; 61718003Smckusick char *as1, *as3; 61818003Smckusick struct arglist *ap; 61917756Smckusick { 62017756Smckusick register char *s1, *s2; 62117756Smckusick register int c; 62218003Smckusick char buf[BUFSIZ]; 62317756Smckusick 62418003Smckusick s2 = buf; 62517756Smckusick s1 = as1; 62617756Smckusick while (c = *s1++) { 62717756Smckusick if ((c &= 0177) == 0) { 62818003Smckusick *s2++ = '/'; 62917756Smckusick break; 63017756Smckusick } 63117756Smckusick *s2++ = c; 63217756Smckusick } 63318003Smckusick s1 = dp->d_name; 63417756Smckusick while (*s2 = *s1++) 63517756Smckusick s2++; 63617756Smckusick if (s1 = as3) { 63717756Smckusick *s2++ = '/'; 63817756Smckusick while (*s2++ = *++s1) 63917756Smckusick /* void */; 64017756Smckusick } 64154593Smckusick if (mkentry(buf, dp, ap) == FAIL) 64218003Smckusick return (-1); 64317756Smckusick } 64417756Smckusick 64517756Smckusick /* 64617752Smckusick * Do an "ls" style listing of a directory 64717752Smckusick */ 64817752Smckusick printlist(name, ino, basename) 64917752Smckusick char *name; 65017752Smckusick ino_t ino; 65117752Smckusick char *basename; 65217752Smckusick { 65317752Smckusick register struct afile *fp; 65418003Smckusick register struct direct *dp; 65518003Smckusick static struct arglist alist = { 0, 0, 0, 0, "ls" }; 65617752Smckusick struct afile single; 65750655Smckusick RST_DIR *dirp; 65817752Smckusick 65917752Smckusick if ((dirp = rst_opendir(name)) == NULL) { 66017752Smckusick single.fnum = ino; 66118003Smckusick single.fname = savename(name + strlen(basename) + 1); 66218003Smckusick alist.head = &single; 66318003Smckusick alist.last = alist.head + 1; 66417752Smckusick } else { 66518003Smckusick alist.head = (struct afile *)0; 66618003Smckusick fprintf(stderr, "%s:\n", name); 66718003Smckusick while (dp = rst_readdir(dirp)) { 66818003Smckusick if (dp == NULL || dp->d_ino == 0) 66918003Smckusick break; 67056427Smckusick if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) 67118003Smckusick continue; 67218003Smckusick if (vflag == 0 && 67318003Smckusick (strcmp(dp->d_name, ".") == 0 || 67418003Smckusick strcmp(dp->d_name, "..") == 0)) 67518003Smckusick continue; 67654593Smckusick if (!mkentry(dp->d_name, dp, &alist)) 67718003Smckusick return; 67818003Smckusick } 67917752Smckusick } 68018003Smckusick if (alist.head != 0) { 68118003Smckusick qsort((char *)alist.head, alist.last - alist.head, 68218003Smckusick sizeof *alist.head, fcmp); 68318003Smckusick formatf(&alist); 68418003Smckusick for (fp = alist.head; fp < alist.last; fp++) 68518003Smckusick freename(fp->fname); 68618003Smckusick } 68718003Smckusick if (dirp != NULL) 68818003Smckusick fprintf(stderr, "\n"); 68917752Smckusick } 69017752Smckusick 69117752Smckusick /* 69217752Smckusick * Read the contents of a directory. 69317752Smckusick */ 69454593Smckusick mkentry(name, dp, ap) 69518003Smckusick char *name; 69654593Smckusick struct direct *dp; 69718003Smckusick register struct arglist *ap; 69817752Smckusick { 69917752Smckusick register struct afile *fp; 70017752Smckusick 70118003Smckusick if (ap->base == NULL) { 70218003Smckusick ap->nent = 20; 70318003Smckusick ap->base = (struct afile *)calloc((unsigned)ap->nent, 70417752Smckusick sizeof (struct afile)); 70518003Smckusick if (ap->base == NULL) { 70618003Smckusick fprintf(stderr, "%s: out of memory\n", ap->cmd); 70717752Smckusick return (FAIL); 70817752Smckusick } 70917752Smckusick } 71018003Smckusick if (ap->head == 0) 71118003Smckusick ap->head = ap->last = ap->base; 71218003Smckusick fp = ap->last; 71354593Smckusick fp->fnum = dp->d_ino; 71454593Smckusick if (oldinofmt) 71554593Smckusick fp->finotype = DT_UNKNOWN; 71654593Smckusick else 71754593Smckusick fp->finotype = dp->d_type; 71818003Smckusick fp->fname = savename(name); 71918003Smckusick fp++; 72018003Smckusick if (fp == ap->head + ap->nent) { 72118003Smckusick ap->base = (struct afile *)realloc((char *)ap->base, 72218003Smckusick (unsigned)(2 * ap->nent * sizeof (struct afile))); 72318003Smckusick if (ap->base == 0) { 72418003Smckusick fprintf(stderr, "%s: out of memory\n", ap->cmd); 72518003Smckusick return (FAIL); 72617752Smckusick } 72718003Smckusick ap->head = ap->base; 72818003Smckusick fp = ap->head + ap->nent; 72918003Smckusick ap->nent *= 2; 73017752Smckusick } 73118003Smckusick ap->last = fp; 73217752Smckusick return (GOOD); 73317752Smckusick } 73417752Smckusick 73517752Smckusick /* 73617752Smckusick * Print out a pretty listing of a directory 73717752Smckusick */ 73818003Smckusick formatf(ap) 73918003Smckusick register struct arglist *ap; 74017752Smckusick { 74117752Smckusick register struct afile *fp; 74217752Smckusick struct entry *np; 74318003Smckusick int width = 0, w, nentry = ap->last - ap->head; 74417752Smckusick int i, j, len, columns, lines; 74517752Smckusick char *cp; 74617752Smckusick 74718003Smckusick if (ap->head == ap->last) 74817752Smckusick return; 74918003Smckusick for (fp = ap->head; fp < ap->last; fp++) { 75017752Smckusick fp->ftype = inodetype(fp->fnum); 75117752Smckusick np = lookupino(fp->fnum); 75217752Smckusick if (np != NIL) 75317752Smckusick fp->fflags = np->e_flags; 75417752Smckusick else 75517752Smckusick fp->fflags = 0; 75617752Smckusick len = strlen(fmtentry(fp)); 75717752Smckusick if (len > width) 75817752Smckusick width = len; 75917752Smckusick } 76017752Smckusick width += 2; 76117752Smckusick columns = 80 / width; 76217752Smckusick if (columns == 0) 76317752Smckusick columns = 1; 76417752Smckusick lines = (nentry + columns - 1) / columns; 76517752Smckusick for (i = 0; i < lines; i++) { 76617752Smckusick for (j = 0; j < columns; j++) { 76718003Smckusick fp = ap->head + j * lines + i; 76817752Smckusick cp = fmtentry(fp); 76917752Smckusick fprintf(stderr, "%s", cp); 77018003Smckusick if (fp + lines >= ap->last) { 77117752Smckusick fprintf(stderr, "\n"); 77217752Smckusick break; 77317752Smckusick } 77417752Smckusick w = strlen(cp); 77517752Smckusick while (w < width) { 77617752Smckusick w++; 77717752Smckusick fprintf(stderr, " "); 77817752Smckusick } 77917752Smckusick } 78017752Smckusick } 78117752Smckusick } 78217752Smckusick 78317752Smckusick /* 78417752Smckusick * Comparison routine for qsort. 78517752Smckusick */ 78617752Smckusick fcmp(f1, f2) 78717752Smckusick register struct afile *f1, *f2; 78817752Smckusick { 78917752Smckusick 79017752Smckusick return (strcmp(f1->fname, f2->fname)); 79117752Smckusick } 79217752Smckusick 79317752Smckusick /* 79417752Smckusick * Format a directory entry. 79517752Smckusick */ 79617752Smckusick char * 79717752Smckusick fmtentry(fp) 79817752Smckusick register struct afile *fp; 79917752Smckusick { 80017752Smckusick static char fmtres[BUFSIZ]; 80123982Smckusick static int precision = 0; 80223982Smckusick int i; 80317752Smckusick register char *cp, *dp; 80417752Smckusick 80523982Smckusick if (!vflag) { 80617752Smckusick fmtres[0] = '\0'; 80723982Smckusick } else { 80823982Smckusick if (precision == 0) 80923982Smckusick for (i = maxino; i > 0; i /= 10) 81023982Smckusick precision++; 81123982Smckusick (void) sprintf(fmtres, "%*d ", precision, fp->fnum); 81223982Smckusick } 81317752Smckusick dp = &fmtres[strlen(fmtres)]; 81456427Smckusick if (dflag && TSTINO(fp->fnum, dumpmap) == 0) 81517752Smckusick *dp++ = '^'; 81617752Smckusick else if ((fp->fflags & NEW) != 0) 81717752Smckusick *dp++ = '*'; 81817752Smckusick else 81917752Smckusick *dp++ = ' '; 82017752Smckusick for (cp = fp->fname; *cp; cp++) 82117752Smckusick if (!vflag && (*cp < ' ' || *cp >= 0177)) 82217752Smckusick *dp++ = '?'; 82317752Smckusick else 82417752Smckusick *dp++ = *cp; 82554593Smckusick switch(fp->finotype) { 82654593Smckusick 82754593Smckusick case DT_LNK: 82854593Smckusick *dp++ = '@'; 82954593Smckusick break; 83054593Smckusick 83154593Smckusick case DT_FIFO: 83254593Smckusick case DT_SOCK: 83354593Smckusick *dp++ = '='; 83454593Smckusick break; 83554593Smckusick 83654593Smckusick case DT_CHR: 83754593Smckusick case DT_BLK: 83854593Smckusick *dp++ = '#'; 83954593Smckusick break; 84054593Smckusick 84154593Smckusick case DT_UNKNOWN: 84254593Smckusick case DT_DIR: 84354593Smckusick if (fp->ftype == NODE) 84454593Smckusick *dp++ = '/'; 84554593Smckusick break; 84654593Smckusick 84754593Smckusick case DT_REG: 84854593Smckusick /* nothing */ 84954593Smckusick break; 85054593Smckusick 85154593Smckusick default: 85254593Smckusick fprintf(stderr, "Warning: undefined file type %d\n", 85354593Smckusick fp->finotype); 85454593Smckusick } 85517752Smckusick *dp++ = 0; 85617752Smckusick return (fmtres); 85717752Smckusick } 85817752Smckusick 85917752Smckusick /* 86017752Smckusick * respond to interrupts 86117752Smckusick */ 86239942Sbostic void 86317752Smckusick onintr() 86417752Smckusick { 865*56429Smckusick if (command == 'i' && runshell) 86617752Smckusick longjmp(reset, 1); 86717752Smckusick if (reply("restore interrupted, continue") == FAIL) 86817752Smckusick done(1); 86917752Smckusick } 870