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*56567Sbostic static char sccsid[] = "@(#)interactive.c 5.17 (Berkeley) 10/16/92"; 1036105Sbostic #endif /* not lint */ 1117752Smckusick 12*56567Sbostic #include <sys/param.h> 13*56567Sbostic #include <sys/time.h> 14*56567Sbostic 15*56567Sbostic #include <ufs/ffs/fs.h> 16*56567Sbostic #include <ufs/ufs/dinode.h> 17*56567Sbostic #include <ufs/ufs/dir.h> 1823546Smckusick #include <protocols/dumprestore.h> 19*56567Sbostic 2017752Smckusick #include <setjmp.h> 21*56567Sbostic #include <stdio.h> 22*56567Sbostic #include <stdlib.h> 23*56567Sbostic #include <string.h> 2417752Smckusick 25*56567Sbostic #include "restore.h" 26*56567Sbostic #include "extern.h" 27*56567Sbostic 2817756Smckusick #define round(a, b) (((a) + (b) - 1) / (b) * (b)) 2917756Smckusick 3017752Smckusick /* 3117752Smckusick * Things to handle interruptions. 3217752Smckusick */ 3356429Smckusick static int runshell; 3417752Smckusick static jmp_buf reset; 3517752Smckusick static char *nextarg = NULL; 3617752Smckusick 3717752Smckusick /* 3817752Smckusick * Structure and routines associated with listing directories. 3917752Smckusick */ 4017752Smckusick struct afile { 4117752Smckusick ino_t fnum; /* inode number of file */ 4217752Smckusick char *fname; /* file name */ 4317752Smckusick short fflags; /* extraction flags, if any */ 4417752Smckusick char ftype; /* file type, e.g. LEAF or NODE */ 4554593Smckusick char finotype; /* file type specified in directory entry */ 4617752Smckusick }; 4718003Smckusick struct arglist { 4818003Smckusick struct afile *head; /* start of argument list */ 4918003Smckusick struct afile *last; /* end of argument list */ 5018003Smckusick struct afile *base; /* current list arena */ 5118003Smckusick int nent; /* maximum size of list */ 5218003Smckusick char *cmd; /* the current command */ 5318003Smckusick }; 5417752Smckusick 55*56567Sbostic static int addg __P((struct direct *, char *, char *, struct arglist *)); 56*56567Sbostic static char *copynext __P((char *, char *)); 57*56567Sbostic static int expand __P((char *, int, struct arglist *)); 58*56567Sbostic static void expandarg __P((char *, struct arglist *)); 59*56567Sbostic static int fcmp __P((const void *, const void *)); 60*56567Sbostic static char *fmtentry __P((struct afile *)); 61*56567Sbostic static void formatf __P((struct arglist *)); 62*56567Sbostic static void getcmd __P((char *, char *, char *, struct arglist *)); 63*56567Sbostic static int gmatch __P((char *, char *)); 64*56567Sbostic static int mkentry __P((char *, struct direct *, struct arglist *)); 65*56567Sbostic static void printlist __P((char *, ino_t, char *)); 66*56567Sbostic 6717752Smckusick /* 6817752Smckusick * Read and execute commands from the terminal. 6917752Smckusick */ 70*56567Sbostic void 7117752Smckusick runcmdshell() 7217752Smckusick { 7317752Smckusick register struct entry *np; 7417752Smckusick ino_t ino; 7518003Smckusick static struct arglist alist = { 0, 0, 0, 0, 0 }; 7617752Smckusick char curdir[MAXPATHLEN]; 7717752Smckusick char name[MAXPATHLEN]; 7817752Smckusick char cmd[BUFSIZ]; 7917752Smckusick 8017752Smckusick canon("/", curdir); 8117752Smckusick loop: 8217752Smckusick if (setjmp(reset) != 0) { 8318003Smckusick for (; alist.head < alist.last; alist.head++) 8418003Smckusick freename(alist.head->fname); 8517752Smckusick nextarg = NULL; 8617752Smckusick volno = 0; 8717752Smckusick } 8856429Smckusick runshell = 1; 8918003Smckusick getcmd(curdir, cmd, name, &alist); 9017752Smckusick switch (cmd[0]) { 9117752Smckusick /* 9217752Smckusick * Add elements to the extraction list. 9317752Smckusick */ 9417752Smckusick case 'a': 9529903Smckusick if (strncmp(cmd, "add", strlen(cmd)) != 0) 9629903Smckusick goto bad; 9717752Smckusick ino = dirlookup(name); 9817752Smckusick if (ino == 0) 9917752Smckusick break; 10017752Smckusick if (mflag) 10117752Smckusick pathcheck(name); 10217752Smckusick treescan(name, ino, addfile); 10317752Smckusick break; 10417752Smckusick /* 10517752Smckusick * Change working directory. 10617752Smckusick */ 10717752Smckusick case 'c': 10829903Smckusick if (strncmp(cmd, "cd", strlen(cmd)) != 0) 10929903Smckusick goto bad; 11017752Smckusick ino = dirlookup(name); 11117752Smckusick if (ino == 0) 11217752Smckusick break; 11317752Smckusick if (inodetype(ino) == LEAF) { 11417752Smckusick fprintf(stderr, "%s: not a directory\n", name); 11517752Smckusick break; 11617752Smckusick } 11717752Smckusick (void) strcpy(curdir, name); 11817752Smckusick break; 11917752Smckusick /* 12017752Smckusick * Delete elements from the extraction list. 12117752Smckusick */ 12217752Smckusick case 'd': 12329903Smckusick if (strncmp(cmd, "delete", strlen(cmd)) != 0) 12429903Smckusick goto bad; 12517752Smckusick np = lookupname(name); 126*56567Sbostic if (np == NULL || (np->e_flags & NEW) == 0) { 12717752Smckusick fprintf(stderr, "%s: not on extraction list\n", name); 12817752Smckusick break; 12917752Smckusick } 13017752Smckusick treescan(name, np->e_ino, deletefile); 13117752Smckusick break; 13217752Smckusick /* 13317752Smckusick * Extract the requested list. 13417752Smckusick */ 13517752Smckusick case 'e': 13629903Smckusick if (strncmp(cmd, "extract", strlen(cmd)) != 0) 13729903Smckusick goto bad; 13817752Smckusick createfiles(); 13917752Smckusick createlinks(); 14055880Smckusick setdirmodes(0); 14117752Smckusick if (dflag) 14217752Smckusick checkrestore(); 14317752Smckusick volno = 0; 14417752Smckusick break; 14517752Smckusick /* 14617752Smckusick * List available commands. 14717752Smckusick */ 14817752Smckusick case 'h': 14929903Smckusick if (strncmp(cmd, "help", strlen(cmd)) != 0) 15029903Smckusick goto bad; 15117752Smckusick case '?': 15229903Smckusick fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 15317752Smckusick "Available commands are:\n", 15417752Smckusick "\tls [arg] - list directory\n", 15517752Smckusick "\tcd arg - change directory\n", 15617752Smckusick "\tpwd - print current directory\n", 15717752Smckusick "\tadd [arg] - add `arg' to list of", 15817752Smckusick " files to be extracted\n", 15917752Smckusick "\tdelete [arg] - delete `arg' from", 16017752Smckusick " list of files to be extracted\n", 16117752Smckusick "\textract - extract requested files\n", 16221096Smckusick "\tsetmodes - set modes of requested directories\n", 16317752Smckusick "\tquit - immediately exit program\n", 16429903Smckusick "\twhat - list dump header information\n", 16517752Smckusick "\tverbose - toggle verbose flag", 16617752Smckusick " (useful with ``ls'')\n", 16717752Smckusick "\thelp or `?' - print this list\n", 16817752Smckusick "If no `arg' is supplied, the current", 16917752Smckusick " directory is used\n"); 17017752Smckusick break; 17117752Smckusick /* 17217752Smckusick * List a directory. 17317752Smckusick */ 17417752Smckusick case 'l': 17529903Smckusick if (strncmp(cmd, "ls", strlen(cmd)) != 0) 17629903Smckusick goto bad; 17717752Smckusick ino = dirlookup(name); 17817752Smckusick if (ino == 0) 17917752Smckusick break; 18017752Smckusick printlist(name, ino, curdir); 18117752Smckusick break; 18217752Smckusick /* 18317752Smckusick * Print current directory. 18417752Smckusick */ 18517752Smckusick case 'p': 18629903Smckusick if (strncmp(cmd, "pwd", strlen(cmd)) != 0) 18729903Smckusick goto bad; 18817752Smckusick if (curdir[1] == '\0') 18917752Smckusick fprintf(stderr, "/\n"); 19017752Smckusick else 19117752Smckusick fprintf(stderr, "%s\n", &curdir[1]); 19217752Smckusick break; 19317752Smckusick /* 19417752Smckusick * Quit. 19517752Smckusick */ 19617752Smckusick case 'q': 19729903Smckusick if (strncmp(cmd, "quit", strlen(cmd)) != 0) 19829903Smckusick goto bad; 19929903Smckusick return; 20017752Smckusick case 'x': 20129903Smckusick if (strncmp(cmd, "xit", strlen(cmd)) != 0) 20229903Smckusick goto bad; 20317752Smckusick return; 20417752Smckusick /* 20517752Smckusick * Toggle verbose mode. 20617752Smckusick */ 20717752Smckusick case 'v': 20829903Smckusick if (strncmp(cmd, "verbose", strlen(cmd)) != 0) 20929903Smckusick goto bad; 21017752Smckusick if (vflag) { 21117752Smckusick fprintf(stderr, "verbose mode off\n"); 21217752Smckusick vflag = 0; 21317752Smckusick break; 21417752Smckusick } 21517752Smckusick fprintf(stderr, "verbose mode on\n"); 21617752Smckusick vflag++; 21717752Smckusick break; 21817752Smckusick /* 21917752Smckusick * Just restore requested directory modes. 22017752Smckusick */ 22121096Smckusick case 's': 22229903Smckusick if (strncmp(cmd, "setmodes", strlen(cmd)) != 0) 22329903Smckusick goto bad; 22455880Smckusick setdirmodes(FORCE); 22517752Smckusick break; 22617752Smckusick /* 22729903Smckusick * Print out dump header information. 22829903Smckusick */ 22929903Smckusick case 'w': 23029903Smckusick if (strncmp(cmd, "what", strlen(cmd)) != 0) 23129903Smckusick goto bad; 23229903Smckusick printdumpinfo(); 23329903Smckusick break; 23429903Smckusick /* 23517752Smckusick * Turn on debugging. 23617752Smckusick */ 23717752Smckusick case 'D': 23829903Smckusick if (strncmp(cmd, "Debug", strlen(cmd)) != 0) 23929903Smckusick goto bad; 24017752Smckusick if (dflag) { 24117752Smckusick fprintf(stderr, "debugging mode off\n"); 24217752Smckusick dflag = 0; 24317752Smckusick break; 24417752Smckusick } 24517752Smckusick fprintf(stderr, "debugging mode on\n"); 24617752Smckusick dflag++; 24717752Smckusick break; 24817752Smckusick /* 24917752Smckusick * Unknown command. 25017752Smckusick */ 25117752Smckusick default: 25229903Smckusick bad: 25317752Smckusick fprintf(stderr, "%s: unknown command; type ? for help\n", cmd); 25417752Smckusick break; 25517752Smckusick } 25617752Smckusick goto loop; 25717752Smckusick } 25817752Smckusick 25917752Smckusick /* 26017752Smckusick * Read and parse an interactive command. 26117752Smckusick * The first word on the line is assigned to "cmd". If 26217752Smckusick * there are no arguments on the command line, then "curdir" 26317752Smckusick * is returned as the argument. If there are arguments 26417752Smckusick * on the line they are returned one at a time on each 26517752Smckusick * successive call to getcmd. Each argument is first assigned 26617752Smckusick * to "name". If it does not start with "/" the pathname in 26717752Smckusick * "curdir" is prepended to it. Finally "canon" is called to 26817752Smckusick * eliminate any embedded ".." components. 26917752Smckusick */ 270*56567Sbostic static void 27118003Smckusick getcmd(curdir, cmd, name, ap) 27217752Smckusick char *curdir, *cmd, *name; 27318003Smckusick struct arglist *ap; 27417752Smckusick { 27517752Smckusick register char *cp; 27617752Smckusick static char input[BUFSIZ]; 27717752Smckusick char output[BUFSIZ]; 27817752Smckusick # define rawname input /* save space by reusing input buffer */ 27917752Smckusick 28017752Smckusick /* 28117752Smckusick * Check to see if still processing arguments. 28217752Smckusick */ 28318003Smckusick if (ap->head != ap->last) { 28418003Smckusick strcpy(name, ap->head->fname); 28518003Smckusick freename(ap->head->fname); 28618003Smckusick ap->head++; 28718003Smckusick return; 28818003Smckusick } 28917752Smckusick if (nextarg != NULL) 29017752Smckusick goto getnext; 29117752Smckusick /* 29217752Smckusick * Read a command line and trim off trailing white space. 29317752Smckusick */ 29417752Smckusick do { 29517752Smckusick fprintf(stderr, "restore > "); 29617752Smckusick (void) fflush(stderr); 29717752Smckusick (void) fgets(input, BUFSIZ, terminal); 29817752Smckusick } while (!feof(terminal) && input[0] == '\n'); 29917752Smckusick if (feof(terminal)) { 30017752Smckusick (void) strcpy(cmd, "quit"); 30117752Smckusick return; 30217752Smckusick } 30317752Smckusick for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--) 30417752Smckusick /* trim off trailing white space and newline */; 30517752Smckusick *++cp = '\0'; 30617752Smckusick /* 30717752Smckusick * Copy the command into "cmd". 30817752Smckusick */ 30917752Smckusick cp = copynext(input, cmd); 31018003Smckusick ap->cmd = cmd; 31117752Smckusick /* 31217752Smckusick * If no argument, use curdir as the default. 31317752Smckusick */ 31417752Smckusick if (*cp == '\0') { 31517752Smckusick (void) strcpy(name, curdir); 31617752Smckusick return; 31717752Smckusick } 31817752Smckusick nextarg = cp; 31917752Smckusick /* 32017752Smckusick * Find the next argument. 32117752Smckusick */ 32217752Smckusick getnext: 32317752Smckusick cp = copynext(nextarg, rawname); 32417752Smckusick if (*cp == '\0') 32517752Smckusick nextarg = NULL; 32617752Smckusick else 32717752Smckusick nextarg = cp; 32817752Smckusick /* 32917752Smckusick * If it an absolute pathname, canonicalize it and return it. 33017752Smckusick */ 33117752Smckusick if (rawname[0] == '/') { 33217752Smckusick canon(rawname, name); 33317752Smckusick } else { 33417752Smckusick /* 33517752Smckusick * For relative pathnames, prepend the current directory to 33617752Smckusick * it then canonicalize and return it. 33717752Smckusick */ 33817752Smckusick (void) strcpy(output, curdir); 33917752Smckusick (void) strcat(output, "/"); 34017752Smckusick (void) strcat(output, rawname); 34117752Smckusick canon(output, name); 34217752Smckusick } 34318003Smckusick expandarg(name, ap); 34418003Smckusick strcpy(name, ap->head->fname); 34518003Smckusick freename(ap->head->fname); 34618003Smckusick ap->head++; 34717752Smckusick # undef rawname 34817752Smckusick } 34917752Smckusick 35017752Smckusick /* 35117752Smckusick * Strip off the next token of the input. 35217752Smckusick */ 353*56567Sbostic static char * 35417752Smckusick copynext(input, output) 35517752Smckusick char *input, *output; 35617752Smckusick { 35717752Smckusick register char *cp, *bp; 35817752Smckusick char quote; 35917752Smckusick 36017752Smckusick for (cp = input; *cp == ' ' || *cp == '\t'; cp++) 36117752Smckusick /* skip to argument */; 36217752Smckusick bp = output; 36317752Smckusick while (*cp != ' ' && *cp != '\t' && *cp != '\0') { 36417752Smckusick /* 36517752Smckusick * Handle back slashes. 36617752Smckusick */ 36717752Smckusick if (*cp == '\\') { 36817752Smckusick if (*++cp == '\0') { 36917752Smckusick fprintf(stderr, 37017752Smckusick "command lines cannot be continued\n"); 37117752Smckusick continue; 37217752Smckusick } 37317752Smckusick *bp++ = *cp++; 37417752Smckusick continue; 37517752Smckusick } 37617752Smckusick /* 37717752Smckusick * The usual unquoted case. 37817752Smckusick */ 37917752Smckusick if (*cp != '\'' && *cp != '"') { 38017752Smckusick *bp++ = *cp++; 38117752Smckusick continue; 38217752Smckusick } 38317752Smckusick /* 38417752Smckusick * Handle single and double quotes. 38517752Smckusick */ 38617752Smckusick quote = *cp++; 38717752Smckusick while (*cp != quote && *cp != '\0') 38817752Smckusick *bp++ = *cp++ | 0200; 38917752Smckusick if (*cp++ == '\0') { 39017752Smckusick fprintf(stderr, "missing %c\n", quote); 39117752Smckusick cp--; 39217752Smckusick continue; 39317752Smckusick } 39417752Smckusick } 39517752Smckusick *bp = '\0'; 39617752Smckusick return (cp); 39717752Smckusick } 39817752Smckusick 39917752Smckusick /* 40017752Smckusick * Canonicalize file names to always start with ``./'' and 40118003Smckusick * remove any imbedded "." and ".." components. 40217752Smckusick */ 403*56567Sbostic void 40417752Smckusick canon(rawname, canonname) 40517752Smckusick char *rawname, *canonname; 40617752Smckusick { 40717752Smckusick register char *cp, *np; 40817752Smckusick 40917752Smckusick if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0) 41017752Smckusick (void) strcpy(canonname, ""); 41117752Smckusick else if (rawname[0] == '/') 41217752Smckusick (void) strcpy(canonname, "."); 41317752Smckusick else 41417752Smckusick (void) strcpy(canonname, "./"); 41517752Smckusick (void) strcat(canonname, rawname); 41617752Smckusick /* 41718003Smckusick * Eliminate multiple and trailing '/'s 41817752Smckusick */ 41918003Smckusick for (cp = np = canonname; *np != '\0'; cp++) { 42018003Smckusick *cp = *np++; 42118003Smckusick while (*cp == '/' && *np == '/') 42218003Smckusick np++; 42318003Smckusick } 42418003Smckusick *cp = '\0'; 42518003Smckusick if (*--cp == '/') 42618003Smckusick *cp = '\0'; 42718003Smckusick /* 42818003Smckusick * Eliminate extraneous "." and ".." from pathnames. 42918003Smckusick */ 43017752Smckusick for (np = canonname; *np != '\0'; ) { 43117752Smckusick np++; 43217752Smckusick cp = np; 43317752Smckusick while (*np != '/' && *np != '\0') 43417752Smckusick np++; 43518003Smckusick if (np - cp == 1 && *cp == '.') { 43618003Smckusick cp--; 43718003Smckusick (void) strcpy(cp, np); 43818003Smckusick np = cp; 43918003Smckusick } 44017752Smckusick if (np - cp == 2 && strncmp(cp, "..", 2) == 0) { 44117752Smckusick cp--; 44217752Smckusick while (cp > &canonname[1] && *--cp != '/') 44317752Smckusick /* find beginning of name */; 44417752Smckusick (void) strcpy(cp, np); 44517752Smckusick np = cp; 44617752Smckusick } 44717752Smckusick } 44817752Smckusick } 44917752Smckusick 45017752Smckusick /* 45117756Smckusick * globals (file name generation) 45217756Smckusick * 45317756Smckusick * "*" in params matches r.e ".*" 45417756Smckusick * "?" in params matches r.e. "." 45517756Smckusick * "[...]" in params matches character class 45617756Smckusick * "[...a-z...]" in params matches a through z. 45717756Smckusick */ 458*56567Sbostic static void 45918003Smckusick expandarg(arg, ap) 46017756Smckusick char *arg; 46118003Smckusick register struct arglist *ap; 46217756Smckusick { 46320850Smckusick static struct afile single; 46430950Smckusick struct entry *ep; 46517756Smckusick int size; 46617756Smckusick 46718003Smckusick ap->head = ap->last = (struct afile *)0; 46818003Smckusick size = expand(arg, 0, ap); 46917756Smckusick if (size == 0) { 47030950Smckusick ep = lookupname(arg); 47130950Smckusick single.fnum = ep ? ep->e_ino : 0; 47218003Smckusick single.fname = savename(arg); 47318003Smckusick ap->head = &single; 47418003Smckusick ap->last = ap->head + 1; 47518003Smckusick return; 47617756Smckusick } 47718003Smckusick qsort((char *)ap->head, ap->last - ap->head, sizeof *ap->head, fcmp); 47817756Smckusick } 47917756Smckusick 48017756Smckusick /* 48117756Smckusick * Expand a file name 48217756Smckusick */ 483*56567Sbostic static int 48418003Smckusick expand(as, rflg, ap) 48517756Smckusick char *as; 48617756Smckusick int rflg; 48718003Smckusick register struct arglist *ap; 48817756Smckusick { 48917756Smckusick int count, size; 49017756Smckusick char dir = 0; 49117756Smckusick char *rescan = 0; 49250655Smckusick RST_DIR *dirp; 49317756Smckusick register char *s, *cs; 49418003Smckusick int sindex, rindex, lindex; 49517756Smckusick struct direct *dp; 49617756Smckusick register char slash; 49717756Smckusick register char *rs; 49817756Smckusick register char c; 49917756Smckusick 50017756Smckusick /* 50117756Smckusick * check for meta chars 50217756Smckusick */ 50317756Smckusick s = cs = as; 50417756Smckusick slash = 0; 50517756Smckusick while (*cs != '*' && *cs != '?' && *cs != '[') { 50618003Smckusick if (*cs++ == 0) { 50717756Smckusick if (rflg && slash) 50817756Smckusick break; 50917756Smckusick else 51017756Smckusick return (0) ; 51118003Smckusick } else if (*cs == '/') { 51217756Smckusick slash++; 51317756Smckusick } 51417756Smckusick } 51517756Smckusick for (;;) { 51617756Smckusick if (cs == s) { 51718003Smckusick s = ""; 51817756Smckusick break; 51917756Smckusick } else if (*--cs == '/') { 52017756Smckusick *cs = 0; 52117756Smckusick if (s == cs) 52217756Smckusick s = "/"; 52317756Smckusick break; 52417756Smckusick } 52517756Smckusick } 52617756Smckusick if ((dirp = rst_opendir(s)) != NULL) 52717756Smckusick dir++; 52817756Smckusick count = 0; 52917756Smckusick if (*cs == 0) 53018003Smckusick *cs++ = 0200; 53117756Smckusick if (dir) { 53217756Smckusick /* 53317756Smckusick * check for rescan 53417756Smckusick */ 53517756Smckusick rs = cs; 53617756Smckusick do { 53717756Smckusick if (*rs == '/') { 53817756Smckusick rescan = rs; 53917756Smckusick *rs = 0; 54017756Smckusick } 54117756Smckusick } while (*rs++); 54218003Smckusick sindex = ap->last - ap->head; 54317756Smckusick while ((dp = rst_readdir(dirp)) != NULL && dp->d_ino != 0) { 54456427Smckusick if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) 54517756Smckusick continue; 54617756Smckusick if ((*dp->d_name == '.' && *cs != '.')) 54717756Smckusick continue; 54817756Smckusick if (gmatch(dp->d_name, cs)) { 54918003Smckusick if (addg(dp, s, rescan, ap) < 0) 55017756Smckusick return (-1); 55117756Smckusick count++; 55217756Smckusick } 55317756Smckusick } 55417756Smckusick if (rescan) { 55518003Smckusick rindex = sindex; 55618003Smckusick lindex = ap->last - ap->head; 55717756Smckusick if (count) { 55817756Smckusick count = 0; 55918003Smckusick while (rindex < lindex) { 56018003Smckusick size = expand(ap->head[rindex].fname, 56118003Smckusick 1, ap); 56217756Smckusick if (size < 0) 56317756Smckusick return (size); 56417756Smckusick count += size; 56518003Smckusick rindex++; 56617756Smckusick } 56717756Smckusick } 56818003Smckusick bcopy((char *)&ap->head[lindex], 56918003Smckusick (char *)&ap->head[sindex], 57018003Smckusick (ap->last - &ap->head[rindex]) * sizeof *ap->head); 57118003Smckusick ap->last -= lindex - sindex; 57217756Smckusick *rescan = '/'; 57317756Smckusick } 57417756Smckusick } 57517756Smckusick s = as; 57617756Smckusick while (c = *s) 57717756Smckusick *s++ = (c&0177 ? c : '/'); 57817756Smckusick return (count); 57917756Smckusick } 58017756Smckusick 58117756Smckusick /* 58217756Smckusick * Check for a name match 58317756Smckusick */ 584*56567Sbostic static int 58517756Smckusick gmatch(s, p) 58617756Smckusick register char *s, *p; 58717756Smckusick { 58817756Smckusick register int scc; 58917756Smckusick char c; 59017756Smckusick char ok; 59117756Smckusick int lc; 59217756Smckusick 59317756Smckusick if (scc = *s++) 59417756Smckusick if ((scc &= 0177) == 0) 59517756Smckusick scc = 0200; 59617756Smckusick switch (c = *p++) { 59717756Smckusick 59817756Smckusick case '[': 59917756Smckusick ok = 0; 60017756Smckusick lc = 077777; 60117756Smckusick while (c = *p++) { 60218003Smckusick if (c == ']') { 60317756Smckusick return (ok ? gmatch(s, p) : 0); 60417756Smckusick } else if (c == '-') { 60517756Smckusick if (lc <= scc && scc <= (*p++)) 60617756Smckusick ok++ ; 60717756Smckusick } else { 60817756Smckusick if (scc == (lc = (c&0177))) 60917756Smckusick ok++ ; 61017756Smckusick } 61117756Smckusick } 61217756Smckusick return (0); 61317756Smckusick 61417756Smckusick default: 61517756Smckusick if ((c&0177) != scc) 61617756Smckusick return (0) ; 61717756Smckusick /* falls through */ 61817756Smckusick 61917756Smckusick case '?': 62017756Smckusick return (scc ? gmatch(s, p) : 0); 62117756Smckusick 62217756Smckusick case '*': 62317756Smckusick if (*p == 0) 62417756Smckusick return (1) ; 62517756Smckusick s--; 62617756Smckusick while (*s) { 62717756Smckusick if (gmatch(s++, p)) 62817756Smckusick return (1); 62917756Smckusick } 63017756Smckusick return (0); 63117756Smckusick 63217756Smckusick case 0: 63317756Smckusick return (scc == 0); 63417756Smckusick } 63517756Smckusick } 63617756Smckusick 63717756Smckusick /* 63817756Smckusick * Construct a matched name. 63917756Smckusick */ 640*56567Sbostic static int 64118003Smckusick addg(dp, as1, as3, ap) 64218003Smckusick struct direct *dp; 64318003Smckusick char *as1, *as3; 64418003Smckusick struct arglist *ap; 64517756Smckusick { 64617756Smckusick register char *s1, *s2; 64717756Smckusick register int c; 64818003Smckusick char buf[BUFSIZ]; 64917756Smckusick 65018003Smckusick s2 = buf; 65117756Smckusick s1 = as1; 65217756Smckusick while (c = *s1++) { 65317756Smckusick if ((c &= 0177) == 0) { 65418003Smckusick *s2++ = '/'; 65517756Smckusick break; 65617756Smckusick } 65717756Smckusick *s2++ = c; 65817756Smckusick } 65918003Smckusick s1 = dp->d_name; 66017756Smckusick while (*s2 = *s1++) 66117756Smckusick s2++; 66217756Smckusick if (s1 = as3) { 66317756Smckusick *s2++ = '/'; 66417756Smckusick while (*s2++ = *++s1) 66517756Smckusick /* void */; 66617756Smckusick } 66754593Smckusick if (mkentry(buf, dp, ap) == FAIL) 66818003Smckusick return (-1); 669*56567Sbostic return (0); 67017756Smckusick } 67117756Smckusick 67217756Smckusick /* 67317752Smckusick * Do an "ls" style listing of a directory 67417752Smckusick */ 675*56567Sbostic static void 67617752Smckusick printlist(name, ino, basename) 67717752Smckusick char *name; 67817752Smckusick ino_t ino; 67917752Smckusick char *basename; 68017752Smckusick { 68117752Smckusick register struct afile *fp; 68218003Smckusick register struct direct *dp; 68318003Smckusick static struct arglist alist = { 0, 0, 0, 0, "ls" }; 68417752Smckusick struct afile single; 68550655Smckusick RST_DIR *dirp; 68617752Smckusick 68717752Smckusick if ((dirp = rst_opendir(name)) == NULL) { 68817752Smckusick single.fnum = ino; 68956433Smckusick single.finotype = DT_UNKNOWN; 69018003Smckusick single.fname = savename(name + strlen(basename) + 1); 69118003Smckusick alist.head = &single; 69218003Smckusick alist.last = alist.head + 1; 69317752Smckusick } else { 69418003Smckusick alist.head = (struct afile *)0; 69518003Smckusick fprintf(stderr, "%s:\n", name); 69618003Smckusick while (dp = rst_readdir(dirp)) { 69718003Smckusick if (dp == NULL || dp->d_ino == 0) 69818003Smckusick break; 69956427Smckusick if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) 70018003Smckusick continue; 70118003Smckusick if (vflag == 0 && 70218003Smckusick (strcmp(dp->d_name, ".") == 0 || 70318003Smckusick strcmp(dp->d_name, "..") == 0)) 70418003Smckusick continue; 70554593Smckusick if (!mkentry(dp->d_name, dp, &alist)) 70618003Smckusick return; 70718003Smckusick } 70817752Smckusick } 70918003Smckusick if (alist.head != 0) { 71018003Smckusick qsort((char *)alist.head, alist.last - alist.head, 71118003Smckusick sizeof *alist.head, fcmp); 71218003Smckusick formatf(&alist); 71318003Smckusick for (fp = alist.head; fp < alist.last; fp++) 71418003Smckusick freename(fp->fname); 71518003Smckusick } 71618003Smckusick if (dirp != NULL) 71718003Smckusick fprintf(stderr, "\n"); 71817752Smckusick } 71917752Smckusick 72017752Smckusick /* 72117752Smckusick * Read the contents of a directory. 72217752Smckusick */ 723*56567Sbostic static int 72454593Smckusick mkentry(name, dp, ap) 72518003Smckusick char *name; 72654593Smckusick struct direct *dp; 72718003Smckusick register struct arglist *ap; 72817752Smckusick { 72917752Smckusick register struct afile *fp; 73017752Smckusick 73118003Smckusick if (ap->base == NULL) { 73218003Smckusick ap->nent = 20; 73318003Smckusick ap->base = (struct afile *)calloc((unsigned)ap->nent, 73417752Smckusick sizeof (struct afile)); 73518003Smckusick if (ap->base == NULL) { 73618003Smckusick fprintf(stderr, "%s: out of memory\n", ap->cmd); 73717752Smckusick return (FAIL); 73817752Smckusick } 73917752Smckusick } 74018003Smckusick if (ap->head == 0) 74118003Smckusick ap->head = ap->last = ap->base; 74218003Smckusick fp = ap->last; 74354593Smckusick fp->fnum = dp->d_ino; 74454593Smckusick if (oldinofmt) 74554593Smckusick fp->finotype = DT_UNKNOWN; 74654593Smckusick else 74754593Smckusick fp->finotype = dp->d_type; 74818003Smckusick fp->fname = savename(name); 74918003Smckusick fp++; 75018003Smckusick if (fp == ap->head + ap->nent) { 75118003Smckusick ap->base = (struct afile *)realloc((char *)ap->base, 75218003Smckusick (unsigned)(2 * ap->nent * sizeof (struct afile))); 75318003Smckusick if (ap->base == 0) { 75418003Smckusick fprintf(stderr, "%s: out of memory\n", ap->cmd); 75518003Smckusick return (FAIL); 75617752Smckusick } 75718003Smckusick ap->head = ap->base; 75818003Smckusick fp = ap->head + ap->nent; 75918003Smckusick ap->nent *= 2; 76017752Smckusick } 76118003Smckusick ap->last = fp; 76217752Smckusick return (GOOD); 76317752Smckusick } 76417752Smckusick 76517752Smckusick /* 76617752Smckusick * Print out a pretty listing of a directory 76717752Smckusick */ 768*56567Sbostic static void 76918003Smckusick formatf(ap) 77018003Smckusick register struct arglist *ap; 77117752Smckusick { 77217752Smckusick register struct afile *fp; 77317752Smckusick struct entry *np; 77418003Smckusick int width = 0, w, nentry = ap->last - ap->head; 77517752Smckusick int i, j, len, columns, lines; 77617752Smckusick char *cp; 77717752Smckusick 77818003Smckusick if (ap->head == ap->last) 77917752Smckusick return; 78018003Smckusick for (fp = ap->head; fp < ap->last; fp++) { 78117752Smckusick fp->ftype = inodetype(fp->fnum); 78217752Smckusick np = lookupino(fp->fnum); 783*56567Sbostic if (np != NULL) 78417752Smckusick fp->fflags = np->e_flags; 78517752Smckusick else 78617752Smckusick fp->fflags = 0; 78717752Smckusick len = strlen(fmtentry(fp)); 78817752Smckusick if (len > width) 78917752Smckusick width = len; 79017752Smckusick } 79117752Smckusick width += 2; 79217752Smckusick columns = 80 / width; 79317752Smckusick if (columns == 0) 79417752Smckusick columns = 1; 79517752Smckusick lines = (nentry + columns - 1) / columns; 79617752Smckusick for (i = 0; i < lines; i++) { 79717752Smckusick for (j = 0; j < columns; j++) { 79818003Smckusick fp = ap->head + j * lines + i; 79917752Smckusick cp = fmtentry(fp); 80017752Smckusick fprintf(stderr, "%s", cp); 80118003Smckusick if (fp + lines >= ap->last) { 80217752Smckusick fprintf(stderr, "\n"); 80317752Smckusick break; 80417752Smckusick } 80517752Smckusick w = strlen(cp); 80617752Smckusick while (w < width) { 80717752Smckusick w++; 80817752Smckusick fprintf(stderr, " "); 80917752Smckusick } 81017752Smckusick } 81117752Smckusick } 81217752Smckusick } 81317752Smckusick 81417752Smckusick /* 81517752Smckusick * Comparison routine for qsort. 81617752Smckusick */ 817*56567Sbostic static int 81817752Smckusick fcmp(f1, f2) 819*56567Sbostic register const void *f1, *f2; 82017752Smckusick { 821*56567Sbostic return (strcmp(((struct afile *)f1)->fname, 822*56567Sbostic ((struct afile *)f2)->fname)); 82317752Smckusick } 82417752Smckusick 82517752Smckusick /* 82617752Smckusick * Format a directory entry. 82717752Smckusick */ 828*56567Sbostic static char * 82917752Smckusick fmtentry(fp) 83017752Smckusick register struct afile *fp; 83117752Smckusick { 83217752Smckusick static char fmtres[BUFSIZ]; 83323982Smckusick static int precision = 0; 83423982Smckusick int i; 83517752Smckusick register char *cp, *dp; 83617752Smckusick 83723982Smckusick if (!vflag) { 83817752Smckusick fmtres[0] = '\0'; 83923982Smckusick } else { 84023982Smckusick if (precision == 0) 84123982Smckusick for (i = maxino; i > 0; i /= 10) 84223982Smckusick precision++; 84323982Smckusick (void) sprintf(fmtres, "%*d ", precision, fp->fnum); 84423982Smckusick } 84517752Smckusick dp = &fmtres[strlen(fmtres)]; 84656427Smckusick if (dflag && TSTINO(fp->fnum, dumpmap) == 0) 84717752Smckusick *dp++ = '^'; 84817752Smckusick else if ((fp->fflags & NEW) != 0) 84917752Smckusick *dp++ = '*'; 85017752Smckusick else 85117752Smckusick *dp++ = ' '; 85217752Smckusick for (cp = fp->fname; *cp; cp++) 85317752Smckusick if (!vflag && (*cp < ' ' || *cp >= 0177)) 85417752Smckusick *dp++ = '?'; 85517752Smckusick else 85617752Smckusick *dp++ = *cp; 85754593Smckusick switch(fp->finotype) { 85854593Smckusick 85954593Smckusick case DT_LNK: 86054593Smckusick *dp++ = '@'; 86154593Smckusick break; 86254593Smckusick 86354593Smckusick case DT_FIFO: 86454593Smckusick case DT_SOCK: 86554593Smckusick *dp++ = '='; 86654593Smckusick break; 86754593Smckusick 86854593Smckusick case DT_CHR: 86954593Smckusick case DT_BLK: 87054593Smckusick *dp++ = '#'; 87154593Smckusick break; 87254593Smckusick 87354593Smckusick case DT_UNKNOWN: 87454593Smckusick case DT_DIR: 87554593Smckusick if (fp->ftype == NODE) 87654593Smckusick *dp++ = '/'; 87754593Smckusick break; 87854593Smckusick 87954593Smckusick case DT_REG: 88054593Smckusick /* nothing */ 88154593Smckusick break; 88254593Smckusick 88354593Smckusick default: 88454593Smckusick fprintf(stderr, "Warning: undefined file type %d\n", 88554593Smckusick fp->finotype); 88654593Smckusick } 88717752Smckusick *dp++ = 0; 88817752Smckusick return (fmtres); 88917752Smckusick } 89017752Smckusick 89117752Smckusick /* 89217752Smckusick * respond to interrupts 89317752Smckusick */ 89439942Sbostic void 895*56567Sbostic onintr(signo) 896*56567Sbostic int signo; 89717752Smckusick { 89856429Smckusick if (command == 'i' && runshell) 89917752Smckusick longjmp(reset, 1); 90017752Smckusick if (reply("restore interrupted, continue") == FAIL) 90117752Smckusick done(1); 90217752Smckusick } 903