121166Sdist /* 221166Sdist * Copyright (c) 1985 Regents of the University of California. 321166Sdist * All rights reserved. The Berkeley software License Agreement 421166Sdist * specifies the terms and conditions for redistribution. 521166Sdist */ 617752Smckusick 717752Smckusick #ifndef lint 8*29903Smckusick static char sccsid[] = "@(#)interactive.c 5.4 (Berkeley) 10/21/86"; 917752Smckusick #endif not lint 1017752Smckusick 1117752Smckusick #include "restore.h" 1223546Smckusick #include <protocols/dumprestore.h> 1317752Smckusick #include <setjmp.h> 1417752Smckusick 1517756Smckusick #define round(a, b) (((a) + (b) - 1) / (b) * (b)) 1617756Smckusick 1717752Smckusick /* 1817752Smckusick * Things to handle interruptions. 1917752Smckusick */ 2017752Smckusick static jmp_buf reset; 2117752Smckusick static char *nextarg = NULL; 2217752Smckusick 2317752Smckusick /* 2417752Smckusick * Structure and routines associated with listing directories. 2517752Smckusick */ 2617752Smckusick struct afile { 2717752Smckusick ino_t fnum; /* inode number of file */ 2817752Smckusick char *fname; /* file name */ 2917752Smckusick short fflags; /* extraction flags, if any */ 3017752Smckusick char ftype; /* file type, e.g. LEAF or NODE */ 3117752Smckusick }; 3218003Smckusick struct arglist { 3318003Smckusick struct afile *head; /* start of argument list */ 3418003Smckusick struct afile *last; /* end of argument list */ 3518003Smckusick struct afile *base; /* current list arena */ 3618003Smckusick int nent; /* maximum size of list */ 3718003Smckusick char *cmd; /* the current command */ 3818003Smckusick }; 3917752Smckusick extern int fcmp(); 4017752Smckusick extern char *fmtentry(); 4117752Smckusick char *copynext(); 4217752Smckusick 4317752Smckusick /* 4417752Smckusick * Read and execute commands from the terminal. 4517752Smckusick */ 4617752Smckusick runcmdshell() 4717752Smckusick { 4817752Smckusick register struct entry *np; 4917752Smckusick ino_t ino; 5018003Smckusick static struct arglist alist = { 0, 0, 0, 0, 0 }; 5117752Smckusick char curdir[MAXPATHLEN]; 5217752Smckusick char name[MAXPATHLEN]; 5317752Smckusick char cmd[BUFSIZ]; 5417752Smckusick 5517752Smckusick canon("/", curdir); 5617752Smckusick loop: 5717752Smckusick if (setjmp(reset) != 0) { 5818003Smckusick for (; alist.head < alist.last; alist.head++) 5918003Smckusick freename(alist.head->fname); 6017752Smckusick nextarg = NULL; 6117752Smckusick volno = 0; 6217752Smckusick } 6318003Smckusick getcmd(curdir, cmd, name, &alist); 6417752Smckusick switch (cmd[0]) { 6517752Smckusick /* 6617752Smckusick * Add elements to the extraction list. 6717752Smckusick */ 6817752Smckusick case 'a': 69*29903Smckusick if (strncmp(cmd, "add", strlen(cmd)) != 0) 70*29903Smckusick goto bad; 7117752Smckusick ino = dirlookup(name); 7217752Smckusick if (ino == 0) 7317752Smckusick break; 7417752Smckusick if (mflag) 7517752Smckusick pathcheck(name); 7617752Smckusick treescan(name, ino, addfile); 7717752Smckusick break; 7817752Smckusick /* 7917752Smckusick * Change working directory. 8017752Smckusick */ 8117752Smckusick case 'c': 82*29903Smckusick if (strncmp(cmd, "cd", strlen(cmd)) != 0) 83*29903Smckusick goto bad; 8417752Smckusick ino = dirlookup(name); 8517752Smckusick if (ino == 0) 8617752Smckusick break; 8717752Smckusick if (inodetype(ino) == LEAF) { 8817752Smckusick fprintf(stderr, "%s: not a directory\n", name); 8917752Smckusick break; 9017752Smckusick } 9117752Smckusick (void) strcpy(curdir, name); 9217752Smckusick break; 9317752Smckusick /* 9417752Smckusick * Delete elements from the extraction list. 9517752Smckusick */ 9617752Smckusick case 'd': 97*29903Smckusick if (strncmp(cmd, "delete", strlen(cmd)) != 0) 98*29903Smckusick goto bad; 9917752Smckusick np = lookupname(name); 10017752Smckusick if (np == NIL || (np->e_flags & NEW) == 0) { 10117752Smckusick fprintf(stderr, "%s: not on extraction list\n", name); 10217752Smckusick break; 10317752Smckusick } 10417752Smckusick treescan(name, np->e_ino, deletefile); 10517752Smckusick break; 10617752Smckusick /* 10717752Smckusick * Extract the requested list. 10817752Smckusick */ 10917752Smckusick case 'e': 110*29903Smckusick if (strncmp(cmd, "extract", strlen(cmd)) != 0) 111*29903Smckusick goto bad; 11217752Smckusick createfiles(); 11317752Smckusick createlinks(); 11417752Smckusick setdirmodes(); 11517752Smckusick if (dflag) 11617752Smckusick checkrestore(); 11717752Smckusick volno = 0; 11817752Smckusick break; 11917752Smckusick /* 12017752Smckusick * List available commands. 12117752Smckusick */ 12217752Smckusick case 'h': 123*29903Smckusick if (strncmp(cmd, "help", strlen(cmd)) != 0) 124*29903Smckusick goto bad; 12517752Smckusick case '?': 126*29903Smckusick fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 12717752Smckusick "Available commands are:\n", 12817752Smckusick "\tls [arg] - list directory\n", 12917752Smckusick "\tcd arg - change directory\n", 13017752Smckusick "\tpwd - print current directory\n", 13117752Smckusick "\tadd [arg] - add `arg' to list of", 13217752Smckusick " files to be extracted\n", 13317752Smckusick "\tdelete [arg] - delete `arg' from", 13417752Smckusick " list of files to be extracted\n", 13517752Smckusick "\textract - extract requested files\n", 13621096Smckusick "\tsetmodes - set modes of requested directories\n", 13717752Smckusick "\tquit - immediately exit program\n", 138*29903Smckusick "\twhat - list dump header information\n", 13917752Smckusick "\tverbose - toggle verbose flag", 14017752Smckusick " (useful with ``ls'')\n", 14117752Smckusick "\thelp or `?' - print this list\n", 14217752Smckusick "If no `arg' is supplied, the current", 14317752Smckusick " directory is used\n"); 14417752Smckusick break; 14517752Smckusick /* 14617752Smckusick * List a directory. 14717752Smckusick */ 14817752Smckusick case 'l': 149*29903Smckusick if (strncmp(cmd, "ls", strlen(cmd)) != 0) 150*29903Smckusick goto bad; 15117752Smckusick ino = dirlookup(name); 15217752Smckusick if (ino == 0) 15317752Smckusick break; 15417752Smckusick printlist(name, ino, curdir); 15517752Smckusick break; 15617752Smckusick /* 15717752Smckusick * Print current directory. 15817752Smckusick */ 15917752Smckusick case 'p': 160*29903Smckusick if (strncmp(cmd, "pwd", strlen(cmd)) != 0) 161*29903Smckusick goto bad; 16217752Smckusick if (curdir[1] == '\0') 16317752Smckusick fprintf(stderr, "/\n"); 16417752Smckusick else 16517752Smckusick fprintf(stderr, "%s\n", &curdir[1]); 16617752Smckusick break; 16717752Smckusick /* 16817752Smckusick * Quit. 16917752Smckusick */ 17017752Smckusick case 'q': 171*29903Smckusick if (strncmp(cmd, "quit", strlen(cmd)) != 0) 172*29903Smckusick goto bad; 173*29903Smckusick return; 17417752Smckusick case 'x': 175*29903Smckusick if (strncmp(cmd, "xit", strlen(cmd)) != 0) 176*29903Smckusick goto bad; 17717752Smckusick return; 17817752Smckusick /* 17917752Smckusick * Toggle verbose mode. 18017752Smckusick */ 18117752Smckusick case 'v': 182*29903Smckusick if (strncmp(cmd, "verbose", strlen(cmd)) != 0) 183*29903Smckusick goto bad; 18417752Smckusick if (vflag) { 18517752Smckusick fprintf(stderr, "verbose mode off\n"); 18617752Smckusick vflag = 0; 18717752Smckusick break; 18817752Smckusick } 18917752Smckusick fprintf(stderr, "verbose mode on\n"); 19017752Smckusick vflag++; 19117752Smckusick break; 19217752Smckusick /* 19317752Smckusick * Just restore requested directory modes. 19417752Smckusick */ 19521096Smckusick case 's': 196*29903Smckusick if (strncmp(cmd, "setmodes", strlen(cmd)) != 0) 197*29903Smckusick goto bad; 19817752Smckusick setdirmodes(); 19917752Smckusick break; 20017752Smckusick /* 201*29903Smckusick * Print out dump header information. 202*29903Smckusick */ 203*29903Smckusick case 'w': 204*29903Smckusick if (strncmp(cmd, "what", strlen(cmd)) != 0) 205*29903Smckusick goto bad; 206*29903Smckusick printdumpinfo(); 207*29903Smckusick break; 208*29903Smckusick /* 20917752Smckusick * Turn on debugging. 21017752Smckusick */ 21117752Smckusick case 'D': 212*29903Smckusick if (strncmp(cmd, "Debug", strlen(cmd)) != 0) 213*29903Smckusick goto bad; 21417752Smckusick if (dflag) { 21517752Smckusick fprintf(stderr, "debugging mode off\n"); 21617752Smckusick dflag = 0; 21717752Smckusick break; 21817752Smckusick } 21917752Smckusick fprintf(stderr, "debugging mode on\n"); 22017752Smckusick dflag++; 22117752Smckusick break; 22217752Smckusick /* 22317752Smckusick * Unknown command. 22417752Smckusick */ 22517752Smckusick default: 226*29903Smckusick bad: 22717752Smckusick fprintf(stderr, "%s: unknown command; type ? for help\n", cmd); 22817752Smckusick break; 22917752Smckusick } 23017752Smckusick goto loop; 23117752Smckusick } 23217752Smckusick 23317752Smckusick /* 23417752Smckusick * Read and parse an interactive command. 23517752Smckusick * The first word on the line is assigned to "cmd". If 23617752Smckusick * there are no arguments on the command line, then "curdir" 23717752Smckusick * is returned as the argument. If there are arguments 23817752Smckusick * on the line they are returned one at a time on each 23917752Smckusick * successive call to getcmd. Each argument is first assigned 24017752Smckusick * to "name". If it does not start with "/" the pathname in 24117752Smckusick * "curdir" is prepended to it. Finally "canon" is called to 24217752Smckusick * eliminate any embedded ".." components. 24317752Smckusick */ 24418003Smckusick getcmd(curdir, cmd, name, ap) 24517752Smckusick char *curdir, *cmd, *name; 24618003Smckusick struct arglist *ap; 24717752Smckusick { 24817752Smckusick register char *cp; 24917752Smckusick static char input[BUFSIZ]; 25017752Smckusick char output[BUFSIZ]; 25117752Smckusick # define rawname input /* save space by reusing input buffer */ 25217752Smckusick 25317752Smckusick /* 25417752Smckusick * Check to see if still processing arguments. 25517752Smckusick */ 25618003Smckusick if (ap->head != ap->last) { 25718003Smckusick strcpy(name, ap->head->fname); 25818003Smckusick freename(ap->head->fname); 25918003Smckusick ap->head++; 26018003Smckusick return; 26118003Smckusick } 26217752Smckusick if (nextarg != NULL) 26317752Smckusick goto getnext; 26417752Smckusick /* 26517752Smckusick * Read a command line and trim off trailing white space. 26617752Smckusick */ 26717752Smckusick do { 26817752Smckusick fprintf(stderr, "restore > "); 26917752Smckusick (void) fflush(stderr); 27017752Smckusick (void) fgets(input, BUFSIZ, terminal); 27117752Smckusick } while (!feof(terminal) && input[0] == '\n'); 27217752Smckusick if (feof(terminal)) { 27317752Smckusick (void) strcpy(cmd, "quit"); 27417752Smckusick return; 27517752Smckusick } 27617752Smckusick for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--) 27717752Smckusick /* trim off trailing white space and newline */; 27817752Smckusick *++cp = '\0'; 27917752Smckusick /* 28017752Smckusick * Copy the command into "cmd". 28117752Smckusick */ 28217752Smckusick cp = copynext(input, cmd); 28318003Smckusick ap->cmd = cmd; 28417752Smckusick /* 28517752Smckusick * If no argument, use curdir as the default. 28617752Smckusick */ 28717752Smckusick if (*cp == '\0') { 28817752Smckusick (void) strcpy(name, curdir); 28917752Smckusick return; 29017752Smckusick } 29117752Smckusick nextarg = cp; 29217752Smckusick /* 29317752Smckusick * Find the next argument. 29417752Smckusick */ 29517752Smckusick getnext: 29617752Smckusick cp = copynext(nextarg, rawname); 29717752Smckusick if (*cp == '\0') 29817752Smckusick nextarg = NULL; 29917752Smckusick else 30017752Smckusick nextarg = cp; 30117752Smckusick /* 30217752Smckusick * If it an absolute pathname, canonicalize it and return it. 30317752Smckusick */ 30417752Smckusick if (rawname[0] == '/') { 30517752Smckusick canon(rawname, name); 30617752Smckusick } else { 30717752Smckusick /* 30817752Smckusick * For relative pathnames, prepend the current directory to 30917752Smckusick * it then canonicalize and return it. 31017752Smckusick */ 31117752Smckusick (void) strcpy(output, curdir); 31217752Smckusick (void) strcat(output, "/"); 31317752Smckusick (void) strcat(output, rawname); 31417752Smckusick canon(output, name); 31517752Smckusick } 31618003Smckusick expandarg(name, ap); 31718003Smckusick strcpy(name, ap->head->fname); 31818003Smckusick freename(ap->head->fname); 31918003Smckusick ap->head++; 32017752Smckusick # undef rawname 32117752Smckusick } 32217752Smckusick 32317752Smckusick /* 32417752Smckusick * Strip off the next token of the input. 32517752Smckusick */ 32617752Smckusick char * 32717752Smckusick copynext(input, output) 32817752Smckusick char *input, *output; 32917752Smckusick { 33017752Smckusick register char *cp, *bp; 33117752Smckusick char quote; 33217752Smckusick 33317752Smckusick for (cp = input; *cp == ' ' || *cp == '\t'; cp++) 33417752Smckusick /* skip to argument */; 33517752Smckusick bp = output; 33617752Smckusick while (*cp != ' ' && *cp != '\t' && *cp != '\0') { 33717752Smckusick /* 33817752Smckusick * Handle back slashes. 33917752Smckusick */ 34017752Smckusick if (*cp == '\\') { 34117752Smckusick if (*++cp == '\0') { 34217752Smckusick fprintf(stderr, 34317752Smckusick "command lines cannot be continued\n"); 34417752Smckusick continue; 34517752Smckusick } 34617752Smckusick *bp++ = *cp++; 34717752Smckusick continue; 34817752Smckusick } 34917752Smckusick /* 35017752Smckusick * The usual unquoted case. 35117752Smckusick */ 35217752Smckusick if (*cp != '\'' && *cp != '"') { 35317752Smckusick *bp++ = *cp++; 35417752Smckusick continue; 35517752Smckusick } 35617752Smckusick /* 35717752Smckusick * Handle single and double quotes. 35817752Smckusick */ 35917752Smckusick quote = *cp++; 36017752Smckusick while (*cp != quote && *cp != '\0') 36117752Smckusick *bp++ = *cp++ | 0200; 36217752Smckusick if (*cp++ == '\0') { 36317752Smckusick fprintf(stderr, "missing %c\n", quote); 36417752Smckusick cp--; 36517752Smckusick continue; 36617752Smckusick } 36717752Smckusick } 36817752Smckusick *bp = '\0'; 36917752Smckusick return (cp); 37017752Smckusick } 37117752Smckusick 37217752Smckusick /* 37317752Smckusick * Canonicalize file names to always start with ``./'' and 37418003Smckusick * remove any imbedded "." and ".." components. 37517752Smckusick */ 37617752Smckusick canon(rawname, canonname) 37717752Smckusick char *rawname, *canonname; 37817752Smckusick { 37917752Smckusick register char *cp, *np; 38017752Smckusick int len; 38117752Smckusick 38217752Smckusick if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0) 38317752Smckusick (void) strcpy(canonname, ""); 38417752Smckusick else if (rawname[0] == '/') 38517752Smckusick (void) strcpy(canonname, "."); 38617752Smckusick else 38717752Smckusick (void) strcpy(canonname, "./"); 38817752Smckusick (void) strcat(canonname, rawname); 38917752Smckusick /* 39018003Smckusick * Eliminate multiple and trailing '/'s 39117752Smckusick */ 39218003Smckusick for (cp = np = canonname; *np != '\0'; cp++) { 39318003Smckusick *cp = *np++; 39418003Smckusick while (*cp == '/' && *np == '/') 39518003Smckusick np++; 39618003Smckusick } 39718003Smckusick *cp = '\0'; 39818003Smckusick if (*--cp == '/') 39918003Smckusick *cp = '\0'; 40018003Smckusick /* 40118003Smckusick * Eliminate extraneous "." and ".." from pathnames. 40218003Smckusick */ 40317752Smckusick for (np = canonname; *np != '\0'; ) { 40417752Smckusick np++; 40517752Smckusick cp = np; 40617752Smckusick while (*np != '/' && *np != '\0') 40717752Smckusick np++; 40818003Smckusick if (np - cp == 1 && *cp == '.') { 40918003Smckusick cp--; 41018003Smckusick (void) strcpy(cp, np); 41118003Smckusick np = cp; 41218003Smckusick } 41317752Smckusick if (np - cp == 2 && strncmp(cp, "..", 2) == 0) { 41417752Smckusick cp--; 41517752Smckusick while (cp > &canonname[1] && *--cp != '/') 41617752Smckusick /* find beginning of name */; 41717752Smckusick (void) strcpy(cp, np); 41817752Smckusick np = cp; 41917752Smckusick } 42017752Smckusick } 42117752Smckusick } 42217752Smckusick 42317752Smckusick /* 42417756Smckusick * globals (file name generation) 42517756Smckusick * 42617756Smckusick * "*" in params matches r.e ".*" 42717756Smckusick * "?" in params matches r.e. "." 42817756Smckusick * "[...]" in params matches character class 42917756Smckusick * "[...a-z...]" in params matches a through z. 43017756Smckusick */ 43118003Smckusick expandarg(arg, ap) 43217756Smckusick char *arg; 43318003Smckusick register struct arglist *ap; 43417756Smckusick { 43520850Smckusick static struct afile single; 43617756Smckusick int size; 43717756Smckusick 43818003Smckusick ap->head = ap->last = (struct afile *)0; 43918003Smckusick size = expand(arg, 0, ap); 44017756Smckusick if (size == 0) { 44118003Smckusick single.fnum = lookupname(arg)->e_ino; 44218003Smckusick single.fname = savename(arg); 44318003Smckusick ap->head = &single; 44418003Smckusick ap->last = ap->head + 1; 44518003Smckusick return; 44617756Smckusick } 44718003Smckusick qsort((char *)ap->head, ap->last - ap->head, sizeof *ap->head, fcmp); 44817756Smckusick } 44917756Smckusick 45017756Smckusick /* 45117756Smckusick * Expand a file name 45217756Smckusick */ 45318003Smckusick expand(as, rflg, ap) 45417756Smckusick char *as; 45517756Smckusick int rflg; 45618003Smckusick register struct arglist *ap; 45717756Smckusick { 45817756Smckusick int count, size; 45917756Smckusick char dir = 0; 46017756Smckusick char *rescan = 0; 46117756Smckusick DIR *dirp; 46217756Smckusick register char *s, *cs; 46318003Smckusick int sindex, rindex, lindex; 46417756Smckusick struct direct *dp; 46517756Smckusick register char slash; 46617756Smckusick register char *rs; 46717756Smckusick register char c; 46817756Smckusick 46917756Smckusick /* 47017756Smckusick * check for meta chars 47117756Smckusick */ 47217756Smckusick s = cs = as; 47317756Smckusick slash = 0; 47417756Smckusick while (*cs != '*' && *cs != '?' && *cs != '[') { 47518003Smckusick if (*cs++ == 0) { 47617756Smckusick if (rflg && slash) 47717756Smckusick break; 47817756Smckusick else 47917756Smckusick return (0) ; 48018003Smckusick } else if (*cs == '/') { 48117756Smckusick slash++; 48217756Smckusick } 48317756Smckusick } 48417756Smckusick for (;;) { 48517756Smckusick if (cs == s) { 48618003Smckusick s = ""; 48717756Smckusick break; 48817756Smckusick } else if (*--cs == '/') { 48917756Smckusick *cs = 0; 49017756Smckusick if (s == cs) 49117756Smckusick s = "/"; 49217756Smckusick break; 49317756Smckusick } 49417756Smckusick } 49517756Smckusick if ((dirp = rst_opendir(s)) != NULL) 49617756Smckusick dir++; 49717756Smckusick count = 0; 49817756Smckusick if (*cs == 0) 49918003Smckusick *cs++ = 0200; 50017756Smckusick if (dir) { 50117756Smckusick /* 50217756Smckusick * check for rescan 50317756Smckusick */ 50417756Smckusick rs = cs; 50517756Smckusick do { 50617756Smckusick if (*rs == '/') { 50717756Smckusick rescan = rs; 50817756Smckusick *rs = 0; 50917756Smckusick } 51017756Smckusick } while (*rs++); 51118003Smckusick sindex = ap->last - ap->head; 51217756Smckusick while ((dp = rst_readdir(dirp)) != NULL && dp->d_ino != 0) { 51317756Smckusick if (!dflag && BIT(dp->d_ino, dumpmap) == 0) 51417756Smckusick continue; 51517756Smckusick if ((*dp->d_name == '.' && *cs != '.')) 51617756Smckusick continue; 51717756Smckusick if (gmatch(dp->d_name, cs)) { 51818003Smckusick if (addg(dp, s, rescan, ap) < 0) 51917756Smckusick return (-1); 52017756Smckusick count++; 52117756Smckusick } 52217756Smckusick } 52317756Smckusick if (rescan) { 52418003Smckusick rindex = sindex; 52518003Smckusick lindex = ap->last - ap->head; 52617756Smckusick if (count) { 52717756Smckusick count = 0; 52818003Smckusick while (rindex < lindex) { 52918003Smckusick size = expand(ap->head[rindex].fname, 53018003Smckusick 1, ap); 53117756Smckusick if (size < 0) 53217756Smckusick return (size); 53317756Smckusick count += size; 53418003Smckusick rindex++; 53517756Smckusick } 53617756Smckusick } 53718003Smckusick bcopy((char *)&ap->head[lindex], 53818003Smckusick (char *)&ap->head[sindex], 53918003Smckusick (ap->last - &ap->head[rindex]) * sizeof *ap->head); 54018003Smckusick ap->last -= lindex - sindex; 54117756Smckusick *rescan = '/'; 54217756Smckusick } 54317756Smckusick } 54417756Smckusick s = as; 54517756Smckusick while (c = *s) 54617756Smckusick *s++ = (c&0177 ? c : '/'); 54717756Smckusick return (count); 54817756Smckusick } 54917756Smckusick 55017756Smckusick /* 55117756Smckusick * Check for a name match 55217756Smckusick */ 55317756Smckusick gmatch(s, p) 55417756Smckusick register char *s, *p; 55517756Smckusick { 55617756Smckusick register int scc; 55717756Smckusick char c; 55817756Smckusick char ok; 55917756Smckusick int lc; 56017756Smckusick 56117756Smckusick if (scc = *s++) 56217756Smckusick if ((scc &= 0177) == 0) 56317756Smckusick scc = 0200; 56417756Smckusick switch (c = *p++) { 56517756Smckusick 56617756Smckusick case '[': 56717756Smckusick ok = 0; 56817756Smckusick lc = 077777; 56917756Smckusick while (c = *p++) { 57018003Smckusick if (c == ']') { 57117756Smckusick return (ok ? gmatch(s, p) : 0); 57217756Smckusick } else if (c == '-') { 57317756Smckusick if (lc <= scc && scc <= (*p++)) 57417756Smckusick ok++ ; 57517756Smckusick } else { 57617756Smckusick if (scc == (lc = (c&0177))) 57717756Smckusick ok++ ; 57817756Smckusick } 57917756Smckusick } 58017756Smckusick return (0); 58117756Smckusick 58217756Smckusick default: 58317756Smckusick if ((c&0177) != scc) 58417756Smckusick return (0) ; 58517756Smckusick /* falls through */ 58617756Smckusick 58717756Smckusick case '?': 58817756Smckusick return (scc ? gmatch(s, p) : 0); 58917756Smckusick 59017756Smckusick case '*': 59117756Smckusick if (*p == 0) 59217756Smckusick return (1) ; 59317756Smckusick s--; 59417756Smckusick while (*s) { 59517756Smckusick if (gmatch(s++, p)) 59617756Smckusick return (1); 59717756Smckusick } 59817756Smckusick return (0); 59917756Smckusick 60017756Smckusick case 0: 60117756Smckusick return (scc == 0); 60217756Smckusick } 60317756Smckusick } 60417756Smckusick 60517756Smckusick /* 60617756Smckusick * Construct a matched name. 60717756Smckusick */ 60818003Smckusick addg(dp, as1, as3, ap) 60918003Smckusick struct direct *dp; 61018003Smckusick char *as1, *as3; 61118003Smckusick struct arglist *ap; 61217756Smckusick { 61317756Smckusick register char *s1, *s2; 61417756Smckusick register int c; 61518003Smckusick char buf[BUFSIZ]; 61617756Smckusick 61718003Smckusick s2 = buf; 61817756Smckusick s1 = as1; 61917756Smckusick while (c = *s1++) { 62017756Smckusick if ((c &= 0177) == 0) { 62118003Smckusick *s2++ = '/'; 62217756Smckusick break; 62317756Smckusick } 62417756Smckusick *s2++ = c; 62517756Smckusick } 62618003Smckusick s1 = dp->d_name; 62717756Smckusick while (*s2 = *s1++) 62817756Smckusick s2++; 62917756Smckusick if (s1 = as3) { 63017756Smckusick *s2++ = '/'; 63117756Smckusick while (*s2++ = *++s1) 63217756Smckusick /* void */; 63317756Smckusick } 63418003Smckusick if (mkentry(buf, dp->d_ino, ap) == FAIL) 63518003Smckusick return (-1); 63617756Smckusick } 63717756Smckusick 63817756Smckusick /* 63917752Smckusick * Do an "ls" style listing of a directory 64017752Smckusick */ 64117752Smckusick printlist(name, ino, basename) 64217752Smckusick char *name; 64317752Smckusick ino_t ino; 64417752Smckusick char *basename; 64517752Smckusick { 64617752Smckusick register struct afile *fp; 64718003Smckusick register struct direct *dp; 64818003Smckusick static struct arglist alist = { 0, 0, 0, 0, "ls" }; 64917752Smckusick struct afile single; 65017752Smckusick DIR *dirp; 65117752Smckusick 65217752Smckusick if ((dirp = rst_opendir(name)) == NULL) { 65317752Smckusick single.fnum = ino; 65418003Smckusick single.fname = savename(name + strlen(basename) + 1); 65518003Smckusick alist.head = &single; 65618003Smckusick alist.last = alist.head + 1; 65717752Smckusick } else { 65818003Smckusick alist.head = (struct afile *)0; 65918003Smckusick fprintf(stderr, "%s:\n", name); 66018003Smckusick while (dp = rst_readdir(dirp)) { 66118003Smckusick if (dp == NULL || dp->d_ino == 0) 66218003Smckusick break; 66318003Smckusick if (!dflag && BIT(dp->d_ino, dumpmap) == 0) 66418003Smckusick continue; 66518003Smckusick if (vflag == 0 && 66618003Smckusick (strcmp(dp->d_name, ".") == 0 || 66718003Smckusick strcmp(dp->d_name, "..") == 0)) 66818003Smckusick continue; 66918003Smckusick if (!mkentry(dp->d_name, dp->d_ino, &alist)) 67018003Smckusick return; 67118003Smckusick } 67217752Smckusick } 67318003Smckusick if (alist.head != 0) { 67418003Smckusick qsort((char *)alist.head, alist.last - alist.head, 67518003Smckusick sizeof *alist.head, fcmp); 67618003Smckusick formatf(&alist); 67718003Smckusick for (fp = alist.head; fp < alist.last; fp++) 67818003Smckusick freename(fp->fname); 67918003Smckusick } 68018003Smckusick if (dirp != NULL) 68118003Smckusick fprintf(stderr, "\n"); 68217752Smckusick } 68317752Smckusick 68417752Smckusick /* 68517752Smckusick * Read the contents of a directory. 68617752Smckusick */ 68718003Smckusick mkentry(name, ino, ap) 68818003Smckusick char *name; 68918003Smckusick ino_t ino; 69018003Smckusick register struct arglist *ap; 69117752Smckusick { 69217752Smckusick register struct afile *fp; 69317752Smckusick 69418003Smckusick if (ap->base == NULL) { 69518003Smckusick ap->nent = 20; 69618003Smckusick ap->base = (struct afile *)calloc((unsigned)ap->nent, 69717752Smckusick sizeof (struct afile)); 69818003Smckusick if (ap->base == NULL) { 69918003Smckusick fprintf(stderr, "%s: out of memory\n", ap->cmd); 70017752Smckusick return (FAIL); 70117752Smckusick } 70217752Smckusick } 70318003Smckusick if (ap->head == 0) 70418003Smckusick ap->head = ap->last = ap->base; 70518003Smckusick fp = ap->last; 70618003Smckusick fp->fnum = ino; 70718003Smckusick fp->fname = savename(name); 70818003Smckusick fp++; 70918003Smckusick if (fp == ap->head + ap->nent) { 71018003Smckusick ap->base = (struct afile *)realloc((char *)ap->base, 71118003Smckusick (unsigned)(2 * ap->nent * sizeof (struct afile))); 71218003Smckusick if (ap->base == 0) { 71318003Smckusick fprintf(stderr, "%s: out of memory\n", ap->cmd); 71418003Smckusick return (FAIL); 71517752Smckusick } 71618003Smckusick ap->head = ap->base; 71718003Smckusick fp = ap->head + ap->nent; 71818003Smckusick ap->nent *= 2; 71917752Smckusick } 72018003Smckusick ap->last = fp; 72117752Smckusick return (GOOD); 72217752Smckusick } 72317752Smckusick 72417752Smckusick /* 72517752Smckusick * Print out a pretty listing of a directory 72617752Smckusick */ 72718003Smckusick formatf(ap) 72818003Smckusick register struct arglist *ap; 72917752Smckusick { 73017752Smckusick register struct afile *fp; 73117752Smckusick struct entry *np; 73218003Smckusick int width = 0, w, nentry = ap->last - ap->head; 73317752Smckusick int i, j, len, columns, lines; 73417752Smckusick char *cp; 73517752Smckusick 73618003Smckusick if (ap->head == ap->last) 73717752Smckusick return; 73818003Smckusick for (fp = ap->head; fp < ap->last; fp++) { 73917752Smckusick fp->ftype = inodetype(fp->fnum); 74017752Smckusick np = lookupino(fp->fnum); 74117752Smckusick if (np != NIL) 74217752Smckusick fp->fflags = np->e_flags; 74317752Smckusick else 74417752Smckusick fp->fflags = 0; 74517752Smckusick len = strlen(fmtentry(fp)); 74617752Smckusick if (len > width) 74717752Smckusick width = len; 74817752Smckusick } 74917752Smckusick width += 2; 75017752Smckusick columns = 80 / width; 75117752Smckusick if (columns == 0) 75217752Smckusick columns = 1; 75317752Smckusick lines = (nentry + columns - 1) / columns; 75417752Smckusick for (i = 0; i < lines; i++) { 75517752Smckusick for (j = 0; j < columns; j++) { 75618003Smckusick fp = ap->head + j * lines + i; 75717752Smckusick cp = fmtentry(fp); 75817752Smckusick fprintf(stderr, "%s", cp); 75918003Smckusick if (fp + lines >= ap->last) { 76017752Smckusick fprintf(stderr, "\n"); 76117752Smckusick break; 76217752Smckusick } 76317752Smckusick w = strlen(cp); 76417752Smckusick while (w < width) { 76517752Smckusick w++; 76617752Smckusick fprintf(stderr, " "); 76717752Smckusick } 76817752Smckusick } 76917752Smckusick } 77017752Smckusick } 77117752Smckusick 77217752Smckusick /* 77317752Smckusick * Comparison routine for qsort. 77417752Smckusick */ 77517752Smckusick fcmp(f1, f2) 77617752Smckusick register struct afile *f1, *f2; 77717752Smckusick { 77817752Smckusick 77917752Smckusick return (strcmp(f1->fname, f2->fname)); 78017752Smckusick } 78117752Smckusick 78217752Smckusick /* 78317752Smckusick * Format a directory entry. 78417752Smckusick */ 78517752Smckusick char * 78617752Smckusick fmtentry(fp) 78717752Smckusick register struct afile *fp; 78817752Smckusick { 78917752Smckusick static char fmtres[BUFSIZ]; 79023982Smckusick static int precision = 0; 79123982Smckusick int i; 79217752Smckusick register char *cp, *dp; 79317752Smckusick 79423982Smckusick if (!vflag) { 79517752Smckusick fmtres[0] = '\0'; 79623982Smckusick } else { 79723982Smckusick if (precision == 0) 79823982Smckusick for (i = maxino; i > 0; i /= 10) 79923982Smckusick precision++; 80023982Smckusick (void) sprintf(fmtres, "%*d ", precision, fp->fnum); 80123982Smckusick } 80217752Smckusick dp = &fmtres[strlen(fmtres)]; 80317752Smckusick if (dflag && BIT(fp->fnum, dumpmap) == 0) 80417752Smckusick *dp++ = '^'; 80517752Smckusick else if ((fp->fflags & NEW) != 0) 80617752Smckusick *dp++ = '*'; 80717752Smckusick else 80817752Smckusick *dp++ = ' '; 80917752Smckusick for (cp = fp->fname; *cp; cp++) 81017752Smckusick if (!vflag && (*cp < ' ' || *cp >= 0177)) 81117752Smckusick *dp++ = '?'; 81217752Smckusick else 81317752Smckusick *dp++ = *cp; 81417752Smckusick if (fp->ftype == NODE) 81517752Smckusick *dp++ = '/'; 81617752Smckusick *dp++ = 0; 81717752Smckusick return (fmtres); 81817752Smckusick } 81917752Smckusick 82017752Smckusick /* 82117752Smckusick * respond to interrupts 82217752Smckusick */ 82317752Smckusick onintr() 82417752Smckusick { 82517752Smckusick if (command == 'i') 82617752Smckusick longjmp(reset, 1); 82717752Smckusick if (reply("restore interrupted, continue") == FAIL) 82817752Smckusick done(1); 82917752Smckusick } 830