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*50655Smckusick static char sccsid[] = "@(#)interactive.c 5.10 (Berkeley) 07/29/91"; 1036105Sbostic #endif /* not lint */ 1117752Smckusick 1217752Smckusick #include "restore.h" 1323546Smckusick #include <protocols/dumprestore.h> 1417752Smckusick #include <setjmp.h> 1540093Smckusick #include <ufs/dir.h> 1617752Smckusick 1717756Smckusick #define round(a, b) (((a) + (b) - 1) / (b) * (b)) 1817756Smckusick 1917752Smckusick /* 2017752Smckusick * Things to handle interruptions. 2117752Smckusick */ 2217752Smckusick static jmp_buf reset; 2317752Smckusick static char *nextarg = NULL; 2417752Smckusick 2517752Smckusick /* 2617752Smckusick * Structure and routines associated with listing directories. 2717752Smckusick */ 2817752Smckusick struct afile { 2917752Smckusick ino_t fnum; /* inode number of file */ 3017752Smckusick char *fname; /* file name */ 3117752Smckusick short fflags; /* extraction flags, if any */ 3217752Smckusick char ftype; /* file type, e.g. LEAF or NODE */ 3317752Smckusick }; 3418003Smckusick struct arglist { 3518003Smckusick struct afile *head; /* start of argument list */ 3618003Smckusick struct afile *last; /* end of argument list */ 3718003Smckusick struct afile *base; /* current list arena */ 3818003Smckusick int nent; /* maximum size of list */ 3918003Smckusick char *cmd; /* the current command */ 4018003Smckusick }; 4117752Smckusick extern int fcmp(); 4217752Smckusick extern char *fmtentry(); 4317752Smckusick char *copynext(); 4417752Smckusick 4517752Smckusick /* 4617752Smckusick * Read and execute commands from the terminal. 4717752Smckusick */ 4817752Smckusick runcmdshell() 4917752Smckusick { 5017752Smckusick register struct entry *np; 5117752Smckusick ino_t ino; 5218003Smckusick static struct arglist alist = { 0, 0, 0, 0, 0 }; 5317752Smckusick char curdir[MAXPATHLEN]; 5417752Smckusick char name[MAXPATHLEN]; 5517752Smckusick char cmd[BUFSIZ]; 5617752Smckusick 5717752Smckusick canon("/", curdir); 5817752Smckusick loop: 5917752Smckusick if (setjmp(reset) != 0) { 6018003Smckusick for (; alist.head < alist.last; alist.head++) 6118003Smckusick freename(alist.head->fname); 6217752Smckusick nextarg = NULL; 6317752Smckusick volno = 0; 6417752Smckusick } 6518003Smckusick getcmd(curdir, cmd, name, &alist); 6617752Smckusick switch (cmd[0]) { 6717752Smckusick /* 6817752Smckusick * Add elements to the extraction list. 6917752Smckusick */ 7017752Smckusick case 'a': 7129903Smckusick if (strncmp(cmd, "add", strlen(cmd)) != 0) 7229903Smckusick goto bad; 7317752Smckusick ino = dirlookup(name); 7417752Smckusick if (ino == 0) 7517752Smckusick break; 7617752Smckusick if (mflag) 7717752Smckusick pathcheck(name); 7817752Smckusick treescan(name, ino, addfile); 7917752Smckusick break; 8017752Smckusick /* 8117752Smckusick * Change working directory. 8217752Smckusick */ 8317752Smckusick case 'c': 8429903Smckusick if (strncmp(cmd, "cd", strlen(cmd)) != 0) 8529903Smckusick goto bad; 8617752Smckusick ino = dirlookup(name); 8717752Smckusick if (ino == 0) 8817752Smckusick break; 8917752Smckusick if (inodetype(ino) == LEAF) { 9017752Smckusick fprintf(stderr, "%s: not a directory\n", name); 9117752Smckusick break; 9217752Smckusick } 9317752Smckusick (void) strcpy(curdir, name); 9417752Smckusick break; 9517752Smckusick /* 9617752Smckusick * Delete elements from the extraction list. 9717752Smckusick */ 9817752Smckusick case 'd': 9929903Smckusick if (strncmp(cmd, "delete", strlen(cmd)) != 0) 10029903Smckusick goto bad; 10117752Smckusick np = lookupname(name); 10217752Smckusick if (np == NIL || (np->e_flags & NEW) == 0) { 10317752Smckusick fprintf(stderr, "%s: not on extraction list\n", name); 10417752Smckusick break; 10517752Smckusick } 10617752Smckusick treescan(name, np->e_ino, deletefile); 10717752Smckusick break; 10817752Smckusick /* 10917752Smckusick * Extract the requested list. 11017752Smckusick */ 11117752Smckusick case 'e': 11229903Smckusick if (strncmp(cmd, "extract", strlen(cmd)) != 0) 11329903Smckusick goto bad; 11417752Smckusick createfiles(); 11517752Smckusick createlinks(); 11617752Smckusick setdirmodes(); 11717752Smckusick if (dflag) 11817752Smckusick checkrestore(); 11917752Smckusick volno = 0; 12017752Smckusick break; 12117752Smckusick /* 12217752Smckusick * List available commands. 12317752Smckusick */ 12417752Smckusick case 'h': 12529903Smckusick if (strncmp(cmd, "help", strlen(cmd)) != 0) 12629903Smckusick goto bad; 12717752Smckusick case '?': 12829903Smckusick fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 12917752Smckusick "Available commands are:\n", 13017752Smckusick "\tls [arg] - list directory\n", 13117752Smckusick "\tcd arg - change directory\n", 13217752Smckusick "\tpwd - print current directory\n", 13317752Smckusick "\tadd [arg] - add `arg' to list of", 13417752Smckusick " files to be extracted\n", 13517752Smckusick "\tdelete [arg] - delete `arg' from", 13617752Smckusick " list of files to be extracted\n", 13717752Smckusick "\textract - extract requested files\n", 13821096Smckusick "\tsetmodes - set modes of requested directories\n", 13917752Smckusick "\tquit - immediately exit program\n", 14029903Smckusick "\twhat - list dump header information\n", 14117752Smckusick "\tverbose - toggle verbose flag", 14217752Smckusick " (useful with ``ls'')\n", 14317752Smckusick "\thelp or `?' - print this list\n", 14417752Smckusick "If no `arg' is supplied, the current", 14517752Smckusick " directory is used\n"); 14617752Smckusick break; 14717752Smckusick /* 14817752Smckusick * List a directory. 14917752Smckusick */ 15017752Smckusick case 'l': 15129903Smckusick if (strncmp(cmd, "ls", strlen(cmd)) != 0) 15229903Smckusick goto bad; 15317752Smckusick ino = dirlookup(name); 15417752Smckusick if (ino == 0) 15517752Smckusick break; 15617752Smckusick printlist(name, ino, curdir); 15717752Smckusick break; 15817752Smckusick /* 15917752Smckusick * Print current directory. 16017752Smckusick */ 16117752Smckusick case 'p': 16229903Smckusick if (strncmp(cmd, "pwd", strlen(cmd)) != 0) 16329903Smckusick goto bad; 16417752Smckusick if (curdir[1] == '\0') 16517752Smckusick fprintf(stderr, "/\n"); 16617752Smckusick else 16717752Smckusick fprintf(stderr, "%s\n", &curdir[1]); 16817752Smckusick break; 16917752Smckusick /* 17017752Smckusick * Quit. 17117752Smckusick */ 17217752Smckusick case 'q': 17329903Smckusick if (strncmp(cmd, "quit", strlen(cmd)) != 0) 17429903Smckusick goto bad; 17529903Smckusick return; 17617752Smckusick case 'x': 17729903Smckusick if (strncmp(cmd, "xit", strlen(cmd)) != 0) 17829903Smckusick goto bad; 17917752Smckusick return; 18017752Smckusick /* 18117752Smckusick * Toggle verbose mode. 18217752Smckusick */ 18317752Smckusick case 'v': 18429903Smckusick if (strncmp(cmd, "verbose", strlen(cmd)) != 0) 18529903Smckusick goto bad; 18617752Smckusick if (vflag) { 18717752Smckusick fprintf(stderr, "verbose mode off\n"); 18817752Smckusick vflag = 0; 18917752Smckusick break; 19017752Smckusick } 19117752Smckusick fprintf(stderr, "verbose mode on\n"); 19217752Smckusick vflag++; 19317752Smckusick break; 19417752Smckusick /* 19517752Smckusick * Just restore requested directory modes. 19617752Smckusick */ 19721096Smckusick case 's': 19829903Smckusick if (strncmp(cmd, "setmodes", strlen(cmd)) != 0) 19929903Smckusick goto bad; 20017752Smckusick setdirmodes(); 20117752Smckusick break; 20217752Smckusick /* 20329903Smckusick * Print out dump header information. 20429903Smckusick */ 20529903Smckusick case 'w': 20629903Smckusick if (strncmp(cmd, "what", strlen(cmd)) != 0) 20729903Smckusick goto bad; 20829903Smckusick printdumpinfo(); 20929903Smckusick break; 21029903Smckusick /* 21117752Smckusick * Turn on debugging. 21217752Smckusick */ 21317752Smckusick case 'D': 21429903Smckusick if (strncmp(cmd, "Debug", strlen(cmd)) != 0) 21529903Smckusick goto bad; 21617752Smckusick if (dflag) { 21717752Smckusick fprintf(stderr, "debugging mode off\n"); 21817752Smckusick dflag = 0; 21917752Smckusick break; 22017752Smckusick } 22117752Smckusick fprintf(stderr, "debugging mode on\n"); 22217752Smckusick dflag++; 22317752Smckusick break; 22417752Smckusick /* 22517752Smckusick * Unknown command. 22617752Smckusick */ 22717752Smckusick default: 22829903Smckusick bad: 22917752Smckusick fprintf(stderr, "%s: unknown command; type ? for help\n", cmd); 23017752Smckusick break; 23117752Smckusick } 23217752Smckusick goto loop; 23317752Smckusick } 23417752Smckusick 23517752Smckusick /* 23617752Smckusick * Read and parse an interactive command. 23717752Smckusick * The first word on the line is assigned to "cmd". If 23817752Smckusick * there are no arguments on the command line, then "curdir" 23917752Smckusick * is returned as the argument. If there are arguments 24017752Smckusick * on the line they are returned one at a time on each 24117752Smckusick * successive call to getcmd. Each argument is first assigned 24217752Smckusick * to "name". If it does not start with "/" the pathname in 24317752Smckusick * "curdir" is prepended to it. Finally "canon" is called to 24417752Smckusick * eliminate any embedded ".." components. 24517752Smckusick */ 24618003Smckusick getcmd(curdir, cmd, name, ap) 24717752Smckusick char *curdir, *cmd, *name; 24818003Smckusick struct arglist *ap; 24917752Smckusick { 25017752Smckusick register char *cp; 25117752Smckusick static char input[BUFSIZ]; 25217752Smckusick char output[BUFSIZ]; 25317752Smckusick # define rawname input /* save space by reusing input buffer */ 25417752Smckusick 25517752Smckusick /* 25617752Smckusick * Check to see if still processing arguments. 25717752Smckusick */ 25818003Smckusick if (ap->head != ap->last) { 25918003Smckusick strcpy(name, ap->head->fname); 26018003Smckusick freename(ap->head->fname); 26118003Smckusick ap->head++; 26218003Smckusick return; 26318003Smckusick } 26417752Smckusick if (nextarg != NULL) 26517752Smckusick goto getnext; 26617752Smckusick /* 26717752Smckusick * Read a command line and trim off trailing white space. 26817752Smckusick */ 26917752Smckusick do { 27017752Smckusick fprintf(stderr, "restore > "); 27117752Smckusick (void) fflush(stderr); 27217752Smckusick (void) fgets(input, BUFSIZ, terminal); 27317752Smckusick } while (!feof(terminal) && input[0] == '\n'); 27417752Smckusick if (feof(terminal)) { 27517752Smckusick (void) strcpy(cmd, "quit"); 27617752Smckusick return; 27717752Smckusick } 27817752Smckusick for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--) 27917752Smckusick /* trim off trailing white space and newline */; 28017752Smckusick *++cp = '\0'; 28117752Smckusick /* 28217752Smckusick * Copy the command into "cmd". 28317752Smckusick */ 28417752Smckusick cp = copynext(input, cmd); 28518003Smckusick ap->cmd = cmd; 28617752Smckusick /* 28717752Smckusick * If no argument, use curdir as the default. 28817752Smckusick */ 28917752Smckusick if (*cp == '\0') { 29017752Smckusick (void) strcpy(name, curdir); 29117752Smckusick return; 29217752Smckusick } 29317752Smckusick nextarg = cp; 29417752Smckusick /* 29517752Smckusick * Find the next argument. 29617752Smckusick */ 29717752Smckusick getnext: 29817752Smckusick cp = copynext(nextarg, rawname); 29917752Smckusick if (*cp == '\0') 30017752Smckusick nextarg = NULL; 30117752Smckusick else 30217752Smckusick nextarg = cp; 30317752Smckusick /* 30417752Smckusick * If it an absolute pathname, canonicalize it and return it. 30517752Smckusick */ 30617752Smckusick if (rawname[0] == '/') { 30717752Smckusick canon(rawname, name); 30817752Smckusick } else { 30917752Smckusick /* 31017752Smckusick * For relative pathnames, prepend the current directory to 31117752Smckusick * it then canonicalize and return it. 31217752Smckusick */ 31317752Smckusick (void) strcpy(output, curdir); 31417752Smckusick (void) strcat(output, "/"); 31517752Smckusick (void) strcat(output, rawname); 31617752Smckusick canon(output, name); 31717752Smckusick } 31818003Smckusick expandarg(name, ap); 31918003Smckusick strcpy(name, ap->head->fname); 32018003Smckusick freename(ap->head->fname); 32118003Smckusick ap->head++; 32217752Smckusick # undef rawname 32317752Smckusick } 32417752Smckusick 32517752Smckusick /* 32617752Smckusick * Strip off the next token of the input. 32717752Smckusick */ 32817752Smckusick char * 32917752Smckusick copynext(input, output) 33017752Smckusick char *input, *output; 33117752Smckusick { 33217752Smckusick register char *cp, *bp; 33317752Smckusick char quote; 33417752Smckusick 33517752Smckusick for (cp = input; *cp == ' ' || *cp == '\t'; cp++) 33617752Smckusick /* skip to argument */; 33717752Smckusick bp = output; 33817752Smckusick while (*cp != ' ' && *cp != '\t' && *cp != '\0') { 33917752Smckusick /* 34017752Smckusick * Handle back slashes. 34117752Smckusick */ 34217752Smckusick if (*cp == '\\') { 34317752Smckusick if (*++cp == '\0') { 34417752Smckusick fprintf(stderr, 34517752Smckusick "command lines cannot be continued\n"); 34617752Smckusick continue; 34717752Smckusick } 34817752Smckusick *bp++ = *cp++; 34917752Smckusick continue; 35017752Smckusick } 35117752Smckusick /* 35217752Smckusick * The usual unquoted case. 35317752Smckusick */ 35417752Smckusick if (*cp != '\'' && *cp != '"') { 35517752Smckusick *bp++ = *cp++; 35617752Smckusick continue; 35717752Smckusick } 35817752Smckusick /* 35917752Smckusick * Handle single and double quotes. 36017752Smckusick */ 36117752Smckusick quote = *cp++; 36217752Smckusick while (*cp != quote && *cp != '\0') 36317752Smckusick *bp++ = *cp++ | 0200; 36417752Smckusick if (*cp++ == '\0') { 36517752Smckusick fprintf(stderr, "missing %c\n", quote); 36617752Smckusick cp--; 36717752Smckusick continue; 36817752Smckusick } 36917752Smckusick } 37017752Smckusick *bp = '\0'; 37117752Smckusick return (cp); 37217752Smckusick } 37317752Smckusick 37417752Smckusick /* 37517752Smckusick * Canonicalize file names to always start with ``./'' and 37618003Smckusick * remove any imbedded "." and ".." components. 37717752Smckusick */ 37817752Smckusick canon(rawname, canonname) 37917752Smckusick char *rawname, *canonname; 38017752Smckusick { 38117752Smckusick register char *cp, *np; 38217752Smckusick int len; 38317752Smckusick 38417752Smckusick if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0) 38517752Smckusick (void) strcpy(canonname, ""); 38617752Smckusick else if (rawname[0] == '/') 38717752Smckusick (void) strcpy(canonname, "."); 38817752Smckusick else 38917752Smckusick (void) strcpy(canonname, "./"); 39017752Smckusick (void) strcat(canonname, rawname); 39117752Smckusick /* 39218003Smckusick * Eliminate multiple and trailing '/'s 39317752Smckusick */ 39418003Smckusick for (cp = np = canonname; *np != '\0'; cp++) { 39518003Smckusick *cp = *np++; 39618003Smckusick while (*cp == '/' && *np == '/') 39718003Smckusick np++; 39818003Smckusick } 39918003Smckusick *cp = '\0'; 40018003Smckusick if (*--cp == '/') 40118003Smckusick *cp = '\0'; 40218003Smckusick /* 40318003Smckusick * Eliminate extraneous "." and ".." from pathnames. 40418003Smckusick */ 40517752Smckusick for (np = canonname; *np != '\0'; ) { 40617752Smckusick np++; 40717752Smckusick cp = np; 40817752Smckusick while (*np != '/' && *np != '\0') 40917752Smckusick np++; 41018003Smckusick if (np - cp == 1 && *cp == '.') { 41118003Smckusick cp--; 41218003Smckusick (void) strcpy(cp, np); 41318003Smckusick np = cp; 41418003Smckusick } 41517752Smckusick if (np - cp == 2 && strncmp(cp, "..", 2) == 0) { 41617752Smckusick cp--; 41717752Smckusick while (cp > &canonname[1] && *--cp != '/') 41817752Smckusick /* find beginning of name */; 41917752Smckusick (void) strcpy(cp, np); 42017752Smckusick np = cp; 42117752Smckusick } 42217752Smckusick } 42317752Smckusick } 42417752Smckusick 42517752Smckusick /* 42617756Smckusick * globals (file name generation) 42717756Smckusick * 42817756Smckusick * "*" in params matches r.e ".*" 42917756Smckusick * "?" in params matches r.e. "." 43017756Smckusick * "[...]" in params matches character class 43117756Smckusick * "[...a-z...]" in params matches a through z. 43217756Smckusick */ 43318003Smckusick expandarg(arg, ap) 43417756Smckusick char *arg; 43518003Smckusick register struct arglist *ap; 43617756Smckusick { 43720850Smckusick static struct afile single; 43830950Smckusick struct entry *ep; 43917756Smckusick int size; 44017756Smckusick 44118003Smckusick ap->head = ap->last = (struct afile *)0; 44218003Smckusick size = expand(arg, 0, ap); 44317756Smckusick if (size == 0) { 44430950Smckusick ep = lookupname(arg); 44530950Smckusick single.fnum = ep ? ep->e_ino : 0; 44618003Smckusick single.fname = savename(arg); 44718003Smckusick ap->head = &single; 44818003Smckusick ap->last = ap->head + 1; 44918003Smckusick return; 45017756Smckusick } 45118003Smckusick qsort((char *)ap->head, ap->last - ap->head, sizeof *ap->head, fcmp); 45217756Smckusick } 45317756Smckusick 45417756Smckusick /* 45517756Smckusick * Expand a file name 45617756Smckusick */ 45718003Smckusick expand(as, rflg, ap) 45817756Smckusick char *as; 45917756Smckusick int rflg; 46018003Smckusick register struct arglist *ap; 46117756Smckusick { 46217756Smckusick int count, size; 46317756Smckusick char dir = 0; 46417756Smckusick char *rescan = 0; 465*50655Smckusick RST_DIR *dirp; 46617756Smckusick register char *s, *cs; 46718003Smckusick int sindex, rindex, lindex; 46817756Smckusick struct direct *dp; 46917756Smckusick register char slash; 47017756Smckusick register char *rs; 47117756Smckusick register char c; 47217756Smckusick 47317756Smckusick /* 47417756Smckusick * check for meta chars 47517756Smckusick */ 47617756Smckusick s = cs = as; 47717756Smckusick slash = 0; 47817756Smckusick while (*cs != '*' && *cs != '?' && *cs != '[') { 47918003Smckusick if (*cs++ == 0) { 48017756Smckusick if (rflg && slash) 48117756Smckusick break; 48217756Smckusick else 48317756Smckusick return (0) ; 48418003Smckusick } else if (*cs == '/') { 48517756Smckusick slash++; 48617756Smckusick } 48717756Smckusick } 48817756Smckusick for (;;) { 48917756Smckusick if (cs == s) { 49018003Smckusick s = ""; 49117756Smckusick break; 49217756Smckusick } else if (*--cs == '/') { 49317756Smckusick *cs = 0; 49417756Smckusick if (s == cs) 49517756Smckusick s = "/"; 49617756Smckusick break; 49717756Smckusick } 49817756Smckusick } 49917756Smckusick if ((dirp = rst_opendir(s)) != NULL) 50017756Smckusick dir++; 50117756Smckusick count = 0; 50217756Smckusick if (*cs == 0) 50318003Smckusick *cs++ = 0200; 50417756Smckusick if (dir) { 50517756Smckusick /* 50617756Smckusick * check for rescan 50717756Smckusick */ 50817756Smckusick rs = cs; 50917756Smckusick do { 51017756Smckusick if (*rs == '/') { 51117756Smckusick rescan = rs; 51217756Smckusick *rs = 0; 51317756Smckusick } 51417756Smckusick } while (*rs++); 51518003Smckusick sindex = ap->last - ap->head; 51617756Smckusick while ((dp = rst_readdir(dirp)) != NULL && dp->d_ino != 0) { 51717756Smckusick if (!dflag && BIT(dp->d_ino, dumpmap) == 0) 51817756Smckusick continue; 51917756Smckusick if ((*dp->d_name == '.' && *cs != '.')) 52017756Smckusick continue; 52117756Smckusick if (gmatch(dp->d_name, cs)) { 52218003Smckusick if (addg(dp, s, rescan, ap) < 0) 52317756Smckusick return (-1); 52417756Smckusick count++; 52517756Smckusick } 52617756Smckusick } 52717756Smckusick if (rescan) { 52818003Smckusick rindex = sindex; 52918003Smckusick lindex = ap->last - ap->head; 53017756Smckusick if (count) { 53117756Smckusick count = 0; 53218003Smckusick while (rindex < lindex) { 53318003Smckusick size = expand(ap->head[rindex].fname, 53418003Smckusick 1, ap); 53517756Smckusick if (size < 0) 53617756Smckusick return (size); 53717756Smckusick count += size; 53818003Smckusick rindex++; 53917756Smckusick } 54017756Smckusick } 54118003Smckusick bcopy((char *)&ap->head[lindex], 54218003Smckusick (char *)&ap->head[sindex], 54318003Smckusick (ap->last - &ap->head[rindex]) * sizeof *ap->head); 54418003Smckusick ap->last -= lindex - sindex; 54517756Smckusick *rescan = '/'; 54617756Smckusick } 54717756Smckusick } 54817756Smckusick s = as; 54917756Smckusick while (c = *s) 55017756Smckusick *s++ = (c&0177 ? c : '/'); 55117756Smckusick return (count); 55217756Smckusick } 55317756Smckusick 55417756Smckusick /* 55517756Smckusick * Check for a name match 55617756Smckusick */ 55717756Smckusick gmatch(s, p) 55817756Smckusick register char *s, *p; 55917756Smckusick { 56017756Smckusick register int scc; 56117756Smckusick char c; 56217756Smckusick char ok; 56317756Smckusick int lc; 56417756Smckusick 56517756Smckusick if (scc = *s++) 56617756Smckusick if ((scc &= 0177) == 0) 56717756Smckusick scc = 0200; 56817756Smckusick switch (c = *p++) { 56917756Smckusick 57017756Smckusick case '[': 57117756Smckusick ok = 0; 57217756Smckusick lc = 077777; 57317756Smckusick while (c = *p++) { 57418003Smckusick if (c == ']') { 57517756Smckusick return (ok ? gmatch(s, p) : 0); 57617756Smckusick } else if (c == '-') { 57717756Smckusick if (lc <= scc && scc <= (*p++)) 57817756Smckusick ok++ ; 57917756Smckusick } else { 58017756Smckusick if (scc == (lc = (c&0177))) 58117756Smckusick ok++ ; 58217756Smckusick } 58317756Smckusick } 58417756Smckusick return (0); 58517756Smckusick 58617756Smckusick default: 58717756Smckusick if ((c&0177) != scc) 58817756Smckusick return (0) ; 58917756Smckusick /* falls through */ 59017756Smckusick 59117756Smckusick case '?': 59217756Smckusick return (scc ? gmatch(s, p) : 0); 59317756Smckusick 59417756Smckusick case '*': 59517756Smckusick if (*p == 0) 59617756Smckusick return (1) ; 59717756Smckusick s--; 59817756Smckusick while (*s) { 59917756Smckusick if (gmatch(s++, p)) 60017756Smckusick return (1); 60117756Smckusick } 60217756Smckusick return (0); 60317756Smckusick 60417756Smckusick case 0: 60517756Smckusick return (scc == 0); 60617756Smckusick } 60717756Smckusick } 60817756Smckusick 60917756Smckusick /* 61017756Smckusick * Construct a matched name. 61117756Smckusick */ 61218003Smckusick addg(dp, as1, as3, ap) 61318003Smckusick struct direct *dp; 61418003Smckusick char *as1, *as3; 61518003Smckusick struct arglist *ap; 61617756Smckusick { 61717756Smckusick register char *s1, *s2; 61817756Smckusick register int c; 61918003Smckusick char buf[BUFSIZ]; 62017756Smckusick 62118003Smckusick s2 = buf; 62217756Smckusick s1 = as1; 62317756Smckusick while (c = *s1++) { 62417756Smckusick if ((c &= 0177) == 0) { 62518003Smckusick *s2++ = '/'; 62617756Smckusick break; 62717756Smckusick } 62817756Smckusick *s2++ = c; 62917756Smckusick } 63018003Smckusick s1 = dp->d_name; 63117756Smckusick while (*s2 = *s1++) 63217756Smckusick s2++; 63317756Smckusick if (s1 = as3) { 63417756Smckusick *s2++ = '/'; 63517756Smckusick while (*s2++ = *++s1) 63617756Smckusick /* void */; 63717756Smckusick } 63818003Smckusick if (mkentry(buf, dp->d_ino, ap) == FAIL) 63918003Smckusick return (-1); 64017756Smckusick } 64117756Smckusick 64217756Smckusick /* 64317752Smckusick * Do an "ls" style listing of a directory 64417752Smckusick */ 64517752Smckusick printlist(name, ino, basename) 64617752Smckusick char *name; 64717752Smckusick ino_t ino; 64817752Smckusick char *basename; 64917752Smckusick { 65017752Smckusick register struct afile *fp; 65118003Smckusick register struct direct *dp; 65218003Smckusick static struct arglist alist = { 0, 0, 0, 0, "ls" }; 65317752Smckusick struct afile single; 654*50655Smckusick RST_DIR *dirp; 65517752Smckusick 65617752Smckusick if ((dirp = rst_opendir(name)) == NULL) { 65717752Smckusick single.fnum = ino; 65818003Smckusick single.fname = savename(name + strlen(basename) + 1); 65918003Smckusick alist.head = &single; 66018003Smckusick alist.last = alist.head + 1; 66117752Smckusick } else { 66218003Smckusick alist.head = (struct afile *)0; 66318003Smckusick fprintf(stderr, "%s:\n", name); 66418003Smckusick while (dp = rst_readdir(dirp)) { 66518003Smckusick if (dp == NULL || dp->d_ino == 0) 66618003Smckusick break; 66718003Smckusick if (!dflag && BIT(dp->d_ino, dumpmap) == 0) 66818003Smckusick continue; 66918003Smckusick if (vflag == 0 && 67018003Smckusick (strcmp(dp->d_name, ".") == 0 || 67118003Smckusick strcmp(dp->d_name, "..") == 0)) 67218003Smckusick continue; 67318003Smckusick if (!mkentry(dp->d_name, dp->d_ino, &alist)) 67418003Smckusick return; 67518003Smckusick } 67617752Smckusick } 67718003Smckusick if (alist.head != 0) { 67818003Smckusick qsort((char *)alist.head, alist.last - alist.head, 67918003Smckusick sizeof *alist.head, fcmp); 68018003Smckusick formatf(&alist); 68118003Smckusick for (fp = alist.head; fp < alist.last; fp++) 68218003Smckusick freename(fp->fname); 68318003Smckusick } 68418003Smckusick if (dirp != NULL) 68518003Smckusick fprintf(stderr, "\n"); 68617752Smckusick } 68717752Smckusick 68817752Smckusick /* 68917752Smckusick * Read the contents of a directory. 69017752Smckusick */ 69118003Smckusick mkentry(name, ino, ap) 69218003Smckusick char *name; 69318003Smckusick ino_t ino; 69418003Smckusick register struct arglist *ap; 69517752Smckusick { 69617752Smckusick register struct afile *fp; 69717752Smckusick 69818003Smckusick if (ap->base == NULL) { 69918003Smckusick ap->nent = 20; 70018003Smckusick ap->base = (struct afile *)calloc((unsigned)ap->nent, 70117752Smckusick sizeof (struct afile)); 70218003Smckusick if (ap->base == NULL) { 70318003Smckusick fprintf(stderr, "%s: out of memory\n", ap->cmd); 70417752Smckusick return (FAIL); 70517752Smckusick } 70617752Smckusick } 70718003Smckusick if (ap->head == 0) 70818003Smckusick ap->head = ap->last = ap->base; 70918003Smckusick fp = ap->last; 71018003Smckusick fp->fnum = ino; 71118003Smckusick fp->fname = savename(name); 71218003Smckusick fp++; 71318003Smckusick if (fp == ap->head + ap->nent) { 71418003Smckusick ap->base = (struct afile *)realloc((char *)ap->base, 71518003Smckusick (unsigned)(2 * ap->nent * sizeof (struct afile))); 71618003Smckusick if (ap->base == 0) { 71718003Smckusick fprintf(stderr, "%s: out of memory\n", ap->cmd); 71818003Smckusick return (FAIL); 71917752Smckusick } 72018003Smckusick ap->head = ap->base; 72118003Smckusick fp = ap->head + ap->nent; 72218003Smckusick ap->nent *= 2; 72317752Smckusick } 72418003Smckusick ap->last = fp; 72517752Smckusick return (GOOD); 72617752Smckusick } 72717752Smckusick 72817752Smckusick /* 72917752Smckusick * Print out a pretty listing of a directory 73017752Smckusick */ 73118003Smckusick formatf(ap) 73218003Smckusick register struct arglist *ap; 73317752Smckusick { 73417752Smckusick register struct afile *fp; 73517752Smckusick struct entry *np; 73618003Smckusick int width = 0, w, nentry = ap->last - ap->head; 73717752Smckusick int i, j, len, columns, lines; 73817752Smckusick char *cp; 73917752Smckusick 74018003Smckusick if (ap->head == ap->last) 74117752Smckusick return; 74218003Smckusick for (fp = ap->head; fp < ap->last; fp++) { 74317752Smckusick fp->ftype = inodetype(fp->fnum); 74417752Smckusick np = lookupino(fp->fnum); 74517752Smckusick if (np != NIL) 74617752Smckusick fp->fflags = np->e_flags; 74717752Smckusick else 74817752Smckusick fp->fflags = 0; 74917752Smckusick len = strlen(fmtentry(fp)); 75017752Smckusick if (len > width) 75117752Smckusick width = len; 75217752Smckusick } 75317752Smckusick width += 2; 75417752Smckusick columns = 80 / width; 75517752Smckusick if (columns == 0) 75617752Smckusick columns = 1; 75717752Smckusick lines = (nentry + columns - 1) / columns; 75817752Smckusick for (i = 0; i < lines; i++) { 75917752Smckusick for (j = 0; j < columns; j++) { 76018003Smckusick fp = ap->head + j * lines + i; 76117752Smckusick cp = fmtentry(fp); 76217752Smckusick fprintf(stderr, "%s", cp); 76318003Smckusick if (fp + lines >= ap->last) { 76417752Smckusick fprintf(stderr, "\n"); 76517752Smckusick break; 76617752Smckusick } 76717752Smckusick w = strlen(cp); 76817752Smckusick while (w < width) { 76917752Smckusick w++; 77017752Smckusick fprintf(stderr, " "); 77117752Smckusick } 77217752Smckusick } 77317752Smckusick } 77417752Smckusick } 77517752Smckusick 77617752Smckusick /* 77717752Smckusick * Comparison routine for qsort. 77817752Smckusick */ 77917752Smckusick fcmp(f1, f2) 78017752Smckusick register struct afile *f1, *f2; 78117752Smckusick { 78217752Smckusick 78317752Smckusick return (strcmp(f1->fname, f2->fname)); 78417752Smckusick } 78517752Smckusick 78617752Smckusick /* 78717752Smckusick * Format a directory entry. 78817752Smckusick */ 78917752Smckusick char * 79017752Smckusick fmtentry(fp) 79117752Smckusick register struct afile *fp; 79217752Smckusick { 79317752Smckusick static char fmtres[BUFSIZ]; 79423982Smckusick static int precision = 0; 79523982Smckusick int i; 79617752Smckusick register char *cp, *dp; 79717752Smckusick 79823982Smckusick if (!vflag) { 79917752Smckusick fmtres[0] = '\0'; 80023982Smckusick } else { 80123982Smckusick if (precision == 0) 80223982Smckusick for (i = maxino; i > 0; i /= 10) 80323982Smckusick precision++; 80423982Smckusick (void) sprintf(fmtres, "%*d ", precision, fp->fnum); 80523982Smckusick } 80617752Smckusick dp = &fmtres[strlen(fmtres)]; 80717752Smckusick if (dflag && BIT(fp->fnum, dumpmap) == 0) 80817752Smckusick *dp++ = '^'; 80917752Smckusick else if ((fp->fflags & NEW) != 0) 81017752Smckusick *dp++ = '*'; 81117752Smckusick else 81217752Smckusick *dp++ = ' '; 81317752Smckusick for (cp = fp->fname; *cp; cp++) 81417752Smckusick if (!vflag && (*cp < ' ' || *cp >= 0177)) 81517752Smckusick *dp++ = '?'; 81617752Smckusick else 81717752Smckusick *dp++ = *cp; 81817752Smckusick if (fp->ftype == NODE) 81917752Smckusick *dp++ = '/'; 82017752Smckusick *dp++ = 0; 82117752Smckusick return (fmtres); 82217752Smckusick } 82317752Smckusick 82417752Smckusick /* 82517752Smckusick * respond to interrupts 82617752Smckusick */ 82739942Sbostic void 82817752Smckusick onintr() 82917752Smckusick { 83017752Smckusick if (command == 'i') 83117752Smckusick longjmp(reset, 1); 83217752Smckusick if (reply("restore interrupted, continue") == FAIL) 83317752Smckusick done(1); 83417752Smckusick } 835