121166Sdist /* 261536Sbostic * Copyright (c) 1985, 1993 361536Sbostic * The Regents of the University of California. All rights reserved. 436105Sbostic * 542708Sbostic * %sccs.include.redist.c% 621166Sdist */ 717752Smckusick 817752Smckusick #ifndef lint 9*67757Smckusick static char sccsid[] = "@(#)interactive.c 8.2 (Berkeley) 08/31/94"; 1036105Sbostic #endif /* not lint */ 1117752Smckusick 1256567Sbostic #include <sys/param.h> 1356567Sbostic #include <sys/time.h> 1456948Smckusick #include <sys/stat.h> 1556567Sbostic 1656567Sbostic #include <ufs/ffs/fs.h> 1756567Sbostic #include <ufs/ufs/dinode.h> 1856567Sbostic #include <ufs/ufs/dir.h> 1923546Smckusick #include <protocols/dumprestore.h> 2056567Sbostic 2117752Smckusick #include <setjmp.h> 2256948Smckusick #include <glob.h> 2356567Sbostic #include <stdio.h> 2456567Sbostic #include <stdlib.h> 2556567Sbostic #include <string.h> 2617752Smckusick 2756567Sbostic #include "restore.h" 2856567Sbostic #include "extern.h" 2956567Sbostic 3017756Smckusick #define round(a, b) (((a) + (b) - 1) / (b) * (b)) 3117756Smckusick 3217752Smckusick /* 3317752Smckusick * Things to handle interruptions. 3417752Smckusick */ 3556429Smckusick static int runshell; 3617752Smckusick static jmp_buf reset; 3717752Smckusick static char *nextarg = NULL; 3817752Smckusick 3917752Smckusick /* 4017752Smckusick * Structure and routines associated with listing directories. 4117752Smckusick */ 4217752Smckusick struct afile { 4317752Smckusick ino_t fnum; /* inode number of file */ 4417752Smckusick char *fname; /* file name */ 4556948Smckusick short len; /* name length */ 4656948Smckusick char prefix; /* prefix character */ 4756948Smckusick char postfix; /* postfix character */ 4817752Smckusick }; 4918003Smckusick struct arglist { 5056948Smckusick int freeglob; /* glob structure needs to be freed */ 5156948Smckusick int argcnt; /* next globbed argument to return */ 5256948Smckusick glob_t glob; /* globbing information */ 5356948Smckusick char *cmd; /* the current command */ 5418003Smckusick }; 5517752Smckusick 5656567Sbostic static char *copynext __P((char *, char *)); 5756567Sbostic static int fcmp __P((const void *, const void *)); 5856948Smckusick static void formatf __P((struct afile *, int)); 5956567Sbostic static void getcmd __P((char *, char *, char *, struct arglist *)); 6056948Smckusick struct dirent *glob_readdir __P((RST_DIR *dirp)); 6157896Sbostic static int glob_stat __P((const char *, struct stat *)); 62*67757Smckusick static void mkentry __P((char *, struct direct *, struct afile *)); 6356948Smckusick static void printlist __P((char *, char *)); 6456567Sbostic 6517752Smckusick /* 6617752Smckusick * Read and execute commands from the terminal. 6717752Smckusick */ 6856567Sbostic void 6917752Smckusick runcmdshell() 7017752Smckusick { 7117752Smckusick register struct entry *np; 7217752Smckusick ino_t ino; 7356948Smckusick struct arglist arglist; 7417752Smckusick char curdir[MAXPATHLEN]; 7517752Smckusick char name[MAXPATHLEN]; 7617752Smckusick char cmd[BUFSIZ]; 7717752Smckusick 7856948Smckusick arglist.freeglob = 0; 7956948Smckusick arglist.argcnt = 0; 8056948Smckusick arglist.glob.gl_flags = GLOB_ALTDIRFUNC; 8156948Smckusick arglist.glob.gl_opendir = (void *)rst_opendir; 8256948Smckusick arglist.glob.gl_readdir = (void *)glob_readdir; 8360607Sbostic arglist.glob.gl_closedir = (void *)rst_closedir; 8456948Smckusick arglist.glob.gl_lstat = glob_stat; 8556948Smckusick arglist.glob.gl_stat = glob_stat; 8617752Smckusick canon("/", curdir); 8717752Smckusick loop: 8817752Smckusick if (setjmp(reset) != 0) { 8956948Smckusick if (arglist.freeglob != 0) { 9056948Smckusick arglist.freeglob = 0; 9156948Smckusick arglist.argcnt = 0; 9256948Smckusick globfree(&arglist.glob); 9356948Smckusick } 9417752Smckusick nextarg = NULL; 9517752Smckusick volno = 0; 9617752Smckusick } 9756429Smckusick runshell = 1; 9856948Smckusick getcmd(curdir, cmd, name, &arglist); 9917752Smckusick switch (cmd[0]) { 10017752Smckusick /* 10117752Smckusick * Add elements to the extraction list. 10217752Smckusick */ 10317752Smckusick case 'a': 10429903Smckusick if (strncmp(cmd, "add", strlen(cmd)) != 0) 10529903Smckusick goto bad; 10617752Smckusick ino = dirlookup(name); 10717752Smckusick if (ino == 0) 10817752Smckusick break; 10917752Smckusick if (mflag) 11017752Smckusick pathcheck(name); 11117752Smckusick treescan(name, ino, addfile); 11217752Smckusick break; 11317752Smckusick /* 11417752Smckusick * Change working directory. 11517752Smckusick */ 11617752Smckusick case 'c': 11729903Smckusick if (strncmp(cmd, "cd", strlen(cmd)) != 0) 11829903Smckusick goto bad; 11917752Smckusick ino = dirlookup(name); 12017752Smckusick if (ino == 0) 12117752Smckusick break; 12217752Smckusick if (inodetype(ino) == LEAF) { 12317752Smckusick fprintf(stderr, "%s: not a directory\n", name); 12417752Smckusick break; 12517752Smckusick } 12617752Smckusick (void) strcpy(curdir, name); 12717752Smckusick break; 12817752Smckusick /* 12917752Smckusick * Delete elements from the extraction list. 13017752Smckusick */ 13117752Smckusick case 'd': 13229903Smckusick if (strncmp(cmd, "delete", strlen(cmd)) != 0) 13329903Smckusick goto bad; 13417752Smckusick np = lookupname(name); 13556567Sbostic if (np == NULL || (np->e_flags & NEW) == 0) { 13617752Smckusick fprintf(stderr, "%s: not on extraction list\n", name); 13717752Smckusick break; 13817752Smckusick } 13917752Smckusick treescan(name, np->e_ino, deletefile); 14017752Smckusick break; 14117752Smckusick /* 14217752Smckusick * Extract the requested list. 14317752Smckusick */ 14417752Smckusick case 'e': 14529903Smckusick if (strncmp(cmd, "extract", strlen(cmd)) != 0) 14629903Smckusick goto bad; 14717752Smckusick createfiles(); 14817752Smckusick createlinks(); 14955880Smckusick setdirmodes(0); 15017752Smckusick if (dflag) 15117752Smckusick checkrestore(); 15217752Smckusick volno = 0; 15317752Smckusick break; 15417752Smckusick /* 15517752Smckusick * List available commands. 15617752Smckusick */ 15717752Smckusick case 'h': 15829903Smckusick if (strncmp(cmd, "help", strlen(cmd)) != 0) 15929903Smckusick goto bad; 16017752Smckusick case '?': 16129903Smckusick fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 16217752Smckusick "Available commands are:\n", 16317752Smckusick "\tls [arg] - list directory\n", 16417752Smckusick "\tcd arg - change directory\n", 16517752Smckusick "\tpwd - print current directory\n", 16617752Smckusick "\tadd [arg] - add `arg' to list of", 16717752Smckusick " files to be extracted\n", 16817752Smckusick "\tdelete [arg] - delete `arg' from", 16917752Smckusick " list of files to be extracted\n", 17017752Smckusick "\textract - extract requested files\n", 17121096Smckusick "\tsetmodes - set modes of requested directories\n", 17217752Smckusick "\tquit - immediately exit program\n", 17329903Smckusick "\twhat - list dump header information\n", 17417752Smckusick "\tverbose - toggle verbose flag", 17517752Smckusick " (useful with ``ls'')\n", 17617752Smckusick "\thelp or `?' - print this list\n", 17717752Smckusick "If no `arg' is supplied, the current", 17817752Smckusick " directory is used\n"); 17917752Smckusick break; 18017752Smckusick /* 18117752Smckusick * List a directory. 18217752Smckusick */ 18317752Smckusick case 'l': 18429903Smckusick if (strncmp(cmd, "ls", strlen(cmd)) != 0) 18529903Smckusick goto bad; 18656948Smckusick printlist(name, curdir); 18717752Smckusick break; 18817752Smckusick /* 18917752Smckusick * Print current directory. 19017752Smckusick */ 19117752Smckusick case 'p': 19229903Smckusick if (strncmp(cmd, "pwd", strlen(cmd)) != 0) 19329903Smckusick goto bad; 19417752Smckusick if (curdir[1] == '\0') 19517752Smckusick fprintf(stderr, "/\n"); 19617752Smckusick else 19717752Smckusick fprintf(stderr, "%s\n", &curdir[1]); 19817752Smckusick break; 19917752Smckusick /* 20017752Smckusick * Quit. 20117752Smckusick */ 20217752Smckusick case 'q': 20329903Smckusick if (strncmp(cmd, "quit", strlen(cmd)) != 0) 20429903Smckusick goto bad; 20529903Smckusick return; 20617752Smckusick case 'x': 20729903Smckusick if (strncmp(cmd, "xit", strlen(cmd)) != 0) 20829903Smckusick goto bad; 20917752Smckusick return; 21017752Smckusick /* 21117752Smckusick * Toggle verbose mode. 21217752Smckusick */ 21317752Smckusick case 'v': 21429903Smckusick if (strncmp(cmd, "verbose", strlen(cmd)) != 0) 21529903Smckusick goto bad; 21617752Smckusick if (vflag) { 21717752Smckusick fprintf(stderr, "verbose mode off\n"); 21817752Smckusick vflag = 0; 21917752Smckusick break; 22017752Smckusick } 22117752Smckusick fprintf(stderr, "verbose mode on\n"); 22217752Smckusick vflag++; 22317752Smckusick break; 22417752Smckusick /* 22517752Smckusick * Just restore requested directory modes. 22617752Smckusick */ 22721096Smckusick case 's': 22829903Smckusick if (strncmp(cmd, "setmodes", strlen(cmd)) != 0) 22929903Smckusick goto bad; 23055880Smckusick setdirmodes(FORCE); 23117752Smckusick break; 23217752Smckusick /* 23329903Smckusick * Print out dump header information. 23429903Smckusick */ 23529903Smckusick case 'w': 23629903Smckusick if (strncmp(cmd, "what", strlen(cmd)) != 0) 23729903Smckusick goto bad; 23829903Smckusick printdumpinfo(); 23929903Smckusick break; 24029903Smckusick /* 24117752Smckusick * Turn on debugging. 24217752Smckusick */ 24317752Smckusick case 'D': 24429903Smckusick if (strncmp(cmd, "Debug", strlen(cmd)) != 0) 24529903Smckusick goto bad; 24617752Smckusick if (dflag) { 24717752Smckusick fprintf(stderr, "debugging mode off\n"); 24817752Smckusick dflag = 0; 24917752Smckusick break; 25017752Smckusick } 25117752Smckusick fprintf(stderr, "debugging mode on\n"); 25217752Smckusick dflag++; 25317752Smckusick break; 25417752Smckusick /* 25517752Smckusick * Unknown command. 25617752Smckusick */ 25717752Smckusick default: 25829903Smckusick bad: 25917752Smckusick fprintf(stderr, "%s: unknown command; type ? for help\n", cmd); 26017752Smckusick break; 26117752Smckusick } 26217752Smckusick goto loop; 26317752Smckusick } 26417752Smckusick 26517752Smckusick /* 26617752Smckusick * Read and parse an interactive command. 26717752Smckusick * The first word on the line is assigned to "cmd". If 26817752Smckusick * there are no arguments on the command line, then "curdir" 26917752Smckusick * is returned as the argument. If there are arguments 27017752Smckusick * on the line they are returned one at a time on each 27117752Smckusick * successive call to getcmd. Each argument is first assigned 27217752Smckusick * to "name". If it does not start with "/" the pathname in 27317752Smckusick * "curdir" is prepended to it. Finally "canon" is called to 27417752Smckusick * eliminate any embedded ".." components. 27517752Smckusick */ 27656567Sbostic static void 27718003Smckusick getcmd(curdir, cmd, name, ap) 27817752Smckusick char *curdir, *cmd, *name; 27918003Smckusick struct arglist *ap; 28017752Smckusick { 28117752Smckusick register char *cp; 28217752Smckusick static char input[BUFSIZ]; 28317752Smckusick char output[BUFSIZ]; 28417752Smckusick # define rawname input /* save space by reusing input buffer */ 28517752Smckusick 28617752Smckusick /* 28717752Smckusick * Check to see if still processing arguments. 28817752Smckusick */ 28956948Smckusick if (ap->argcnt > 0) 29056948Smckusick goto retnext; 29117752Smckusick if (nextarg != NULL) 29217752Smckusick goto getnext; 29317752Smckusick /* 29417752Smckusick * Read a command line and trim off trailing white space. 29517752Smckusick */ 29617752Smckusick do { 29717752Smckusick fprintf(stderr, "restore > "); 29817752Smckusick (void) fflush(stderr); 29917752Smckusick (void) fgets(input, BUFSIZ, terminal); 30017752Smckusick } while (!feof(terminal) && input[0] == '\n'); 30117752Smckusick if (feof(terminal)) { 30217752Smckusick (void) strcpy(cmd, "quit"); 30317752Smckusick return; 30417752Smckusick } 30517752Smckusick for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--) 30617752Smckusick /* trim off trailing white space and newline */; 30717752Smckusick *++cp = '\0'; 30817752Smckusick /* 30917752Smckusick * Copy the command into "cmd". 31017752Smckusick */ 31117752Smckusick cp = copynext(input, cmd); 31218003Smckusick ap->cmd = cmd; 31317752Smckusick /* 31417752Smckusick * If no argument, use curdir as the default. 31517752Smckusick */ 31617752Smckusick if (*cp == '\0') { 31717752Smckusick (void) strcpy(name, curdir); 31817752Smckusick return; 31917752Smckusick } 32017752Smckusick nextarg = cp; 32117752Smckusick /* 32217752Smckusick * Find the next argument. 32317752Smckusick */ 32417752Smckusick getnext: 32517752Smckusick cp = copynext(nextarg, rawname); 32617752Smckusick if (*cp == '\0') 32717752Smckusick nextarg = NULL; 32817752Smckusick else 32917752Smckusick nextarg = cp; 33017752Smckusick /* 33156948Smckusick * If it is an absolute pathname, canonicalize it and return it. 33217752Smckusick */ 33317752Smckusick if (rawname[0] == '/') { 33417752Smckusick canon(rawname, name); 33517752Smckusick } else { 33617752Smckusick /* 33717752Smckusick * For relative pathnames, prepend the current directory to 33817752Smckusick * it then canonicalize and return it. 33917752Smckusick */ 34017752Smckusick (void) strcpy(output, curdir); 34117752Smckusick (void) strcat(output, "/"); 34217752Smckusick (void) strcat(output, rawname); 34317752Smckusick canon(output, name); 34417752Smckusick } 34556948Smckusick if (glob(name, GLOB_ALTDIRFUNC, NULL, &ap->glob) < 0) 34656948Smckusick fprintf(stderr, "%s: out of memory\n", ap->cmd); 34756948Smckusick if (ap->glob.gl_pathc == 0) 34856948Smckusick return; 34956948Smckusick ap->freeglob = 1; 35056948Smckusick ap->argcnt = ap->glob.gl_pathc; 35156948Smckusick 35256948Smckusick retnext: 35356948Smckusick strcpy(name, ap->glob.gl_pathv[ap->glob.gl_pathc - ap->argcnt]); 35456948Smckusick if (--ap->argcnt == 0) { 35556948Smckusick ap->freeglob = 0; 35656948Smckusick globfree(&ap->glob); 35756948Smckusick } 35817752Smckusick # undef rawname 35917752Smckusick } 36017752Smckusick 36117752Smckusick /* 36217752Smckusick * Strip off the next token of the input. 36317752Smckusick */ 36456567Sbostic static char * 36517752Smckusick copynext(input, output) 36617752Smckusick char *input, *output; 36717752Smckusick { 36817752Smckusick register char *cp, *bp; 36917752Smckusick char quote; 37017752Smckusick 37117752Smckusick for (cp = input; *cp == ' ' || *cp == '\t'; cp++) 37217752Smckusick /* skip to argument */; 37317752Smckusick bp = output; 37417752Smckusick while (*cp != ' ' && *cp != '\t' && *cp != '\0') { 37517752Smckusick /* 37617752Smckusick * Handle back slashes. 37717752Smckusick */ 37817752Smckusick if (*cp == '\\') { 37917752Smckusick if (*++cp == '\0') { 38017752Smckusick fprintf(stderr, 38117752Smckusick "command lines cannot be continued\n"); 38217752Smckusick continue; 38317752Smckusick } 38417752Smckusick *bp++ = *cp++; 38517752Smckusick continue; 38617752Smckusick } 38717752Smckusick /* 38817752Smckusick * The usual unquoted case. 38917752Smckusick */ 39017752Smckusick if (*cp != '\'' && *cp != '"') { 39117752Smckusick *bp++ = *cp++; 39217752Smckusick continue; 39317752Smckusick } 39417752Smckusick /* 39517752Smckusick * Handle single and double quotes. 39617752Smckusick */ 39717752Smckusick quote = *cp++; 39817752Smckusick while (*cp != quote && *cp != '\0') 39917752Smckusick *bp++ = *cp++ | 0200; 40017752Smckusick if (*cp++ == '\0') { 40117752Smckusick fprintf(stderr, "missing %c\n", quote); 40217752Smckusick cp--; 40317752Smckusick continue; 40417752Smckusick } 40517752Smckusick } 40617752Smckusick *bp = '\0'; 40717752Smckusick return (cp); 40817752Smckusick } 40917752Smckusick 41017752Smckusick /* 41117752Smckusick * Canonicalize file names to always start with ``./'' and 41218003Smckusick * remove any imbedded "." and ".." components. 41317752Smckusick */ 41456567Sbostic void 41517752Smckusick canon(rawname, canonname) 41617752Smckusick char *rawname, *canonname; 41717752Smckusick { 41817752Smckusick register char *cp, *np; 41917752Smckusick 42017752Smckusick if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0) 42117752Smckusick (void) strcpy(canonname, ""); 42217752Smckusick else if (rawname[0] == '/') 42317752Smckusick (void) strcpy(canonname, "."); 42417752Smckusick else 42517752Smckusick (void) strcpy(canonname, "./"); 42617752Smckusick (void) strcat(canonname, rawname); 42717752Smckusick /* 42818003Smckusick * Eliminate multiple and trailing '/'s 42917752Smckusick */ 43018003Smckusick for (cp = np = canonname; *np != '\0'; cp++) { 43118003Smckusick *cp = *np++; 43218003Smckusick while (*cp == '/' && *np == '/') 43318003Smckusick np++; 43418003Smckusick } 43518003Smckusick *cp = '\0'; 43618003Smckusick if (*--cp == '/') 43718003Smckusick *cp = '\0'; 43818003Smckusick /* 43918003Smckusick * Eliminate extraneous "." and ".." from pathnames. 44018003Smckusick */ 44117752Smckusick for (np = canonname; *np != '\0'; ) { 44217752Smckusick np++; 44317752Smckusick cp = np; 44417752Smckusick while (*np != '/' && *np != '\0') 44517752Smckusick np++; 44618003Smckusick if (np - cp == 1 && *cp == '.') { 44718003Smckusick cp--; 44818003Smckusick (void) strcpy(cp, np); 44918003Smckusick np = cp; 45018003Smckusick } 45117752Smckusick if (np - cp == 2 && strncmp(cp, "..", 2) == 0) { 45217752Smckusick cp--; 45317752Smckusick while (cp > &canonname[1] && *--cp != '/') 45417752Smckusick /* find beginning of name */; 45517752Smckusick (void) strcpy(cp, np); 45617752Smckusick np = cp; 45717752Smckusick } 45817752Smckusick } 45917752Smckusick } 46017752Smckusick 46117752Smckusick /* 46217752Smckusick * Do an "ls" style listing of a directory 46317752Smckusick */ 46456567Sbostic static void 46556948Smckusick printlist(name, basename) 46617752Smckusick char *name; 46717752Smckusick char *basename; 46817752Smckusick { 46956948Smckusick register struct afile *fp, *list, *listp; 47018003Smckusick register struct direct *dp; 47117752Smckusick struct afile single; 47250655Smckusick RST_DIR *dirp; 473*67757Smckusick int entries, len, namelen; 474*67757Smckusick char locname[MAXPATHLEN + 1]; 47517752Smckusick 47656948Smckusick dp = pathsearch(name); 477*67757Smckusick if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) || 478*67757Smckusick (!vflag && dp->d_ino == WINO)) 47956948Smckusick return; 48017752Smckusick if ((dirp = rst_opendir(name)) == NULL) { 48156948Smckusick entries = 1; 48256948Smckusick list = &single; 483*67757Smckusick mkentry(name, dp, list); 48456948Smckusick len = strlen(basename) + 1; 48556948Smckusick if (strlen(name) - len > single.len) { 48656948Smckusick freename(single.fname); 48756948Smckusick single.fname = savename(&name[len]); 48856948Smckusick single.len = strlen(single.fname); 48956948Smckusick } 49017752Smckusick } else { 49156948Smckusick entries = 0; 49256948Smckusick while (dp = rst_readdir(dirp)) 49356948Smckusick entries++; 49456948Smckusick rst_closedir(dirp); 49556948Smckusick list = (struct afile *)malloc(entries * sizeof(struct afile)); 49656948Smckusick if (list == NULL) { 49756948Smckusick fprintf(stderr, "ls: out of memory\n"); 49856948Smckusick return; 49956948Smckusick } 50056948Smckusick if ((dirp = rst_opendir(name)) == NULL) 50156948Smckusick panic("directory reopen failed\n"); 50218003Smckusick fprintf(stderr, "%s:\n", name); 50356948Smckusick entries = 0; 50456948Smckusick listp = list; 505*67757Smckusick (void) strncpy(locname, name, MAXPATHLEN); 506*67757Smckusick (void) strncat(locname, "/", MAXPATHLEN); 507*67757Smckusick namelen = strlen(locname); 50818003Smckusick while (dp = rst_readdir(dirp)) { 509*67757Smckusick if (dp == NULL) 51018003Smckusick break; 51156427Smckusick if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) 51218003Smckusick continue; 513*67757Smckusick if (!vflag && (dp->d_ino == WINO || 514*67757Smckusick strcmp(dp->d_name, ".") == 0 || 51518003Smckusick strcmp(dp->d_name, "..") == 0)) 51618003Smckusick continue; 517*67757Smckusick locname[namelen] = '\0'; 518*67757Smckusick if (namelen + dp->d_namlen >= MAXPATHLEN) { 519*67757Smckusick fprintf(stderr, "%s%s: name exceeds %d char\n", 520*67757Smckusick locname, dp->d_name, MAXPATHLEN); 521*67757Smckusick } else { 522*67757Smckusick (void) strncat(locname, dp->d_name, 523*67757Smckusick (int)dp->d_namlen); 524*67757Smckusick mkentry(locname, dp, listp++); 525*67757Smckusick entries++; 526*67757Smckusick } 52718003Smckusick } 52856948Smckusick rst_closedir(dirp); 52956948Smckusick if (entries == 0) { 53056948Smckusick fprintf(stderr, "\n"); 53156948Smckusick free(list); 53256948Smckusick return; 53356948Smckusick } 53456948Smckusick qsort((char *)list, entries, sizeof(struct afile), fcmp); 53517752Smckusick } 53656948Smckusick formatf(list, entries); 53756948Smckusick if (dirp != NULL) { 53856948Smckusick for (fp = listp - 1; fp >= list; fp--) 53918003Smckusick freename(fp->fname); 54056948Smckusick fprintf(stderr, "\n"); 54156948Smckusick free(list); 54218003Smckusick } 54317752Smckusick } 54417752Smckusick 54517752Smckusick /* 54617752Smckusick * Read the contents of a directory. 54717752Smckusick */ 54856948Smckusick static void 549*67757Smckusick mkentry(name, dp, fp) 550*67757Smckusick char *name; 55154593Smckusick struct direct *dp; 55256948Smckusick register struct afile *fp; 55317752Smckusick { 55456948Smckusick char *cp; 55556948Smckusick struct entry *np; 55617752Smckusick 55754593Smckusick fp->fnum = dp->d_ino; 55856948Smckusick fp->fname = savename(dp->d_name); 55956948Smckusick for (cp = fp->fname; *cp; cp++) 56056948Smckusick if (!vflag && (*cp < ' ' || *cp >= 0177)) 56156948Smckusick *cp = '?'; 56256948Smckusick fp->len = cp - fp->fname; 56356948Smckusick if (dflag && TSTINO(fp->fnum, dumpmap) == 0) 56456948Smckusick fp->prefix = '^'; 565*67757Smckusick else if ((np = lookupname(name)) != NULL && (np->e_flags & NEW)) 56656948Smckusick fp->prefix = '*'; 56754593Smckusick else 56856948Smckusick fp->prefix = ' '; 56956948Smckusick switch(dp->d_type) { 57056948Smckusick 57156948Smckusick default: 57256948Smckusick fprintf(stderr, "Warning: undefined file type %d\n", 57356948Smckusick dp->d_type); 57456948Smckusick /* fall through */ 57556948Smckusick case DT_REG: 57656948Smckusick fp->postfix = ' '; 57756948Smckusick break; 57856948Smckusick 57956948Smckusick case DT_LNK: 58056948Smckusick fp->postfix = '@'; 58156948Smckusick break; 58256948Smckusick 58356948Smckusick case DT_FIFO: 58456948Smckusick case DT_SOCK: 58556948Smckusick fp->postfix = '='; 58656948Smckusick break; 58756948Smckusick 58856948Smckusick case DT_CHR: 58956948Smckusick case DT_BLK: 59056948Smckusick fp->postfix = '#'; 59156948Smckusick break; 59256948Smckusick 59356948Smckusick case DT_UNKNOWN: 59456948Smckusick case DT_DIR: 59556948Smckusick if (inodetype(dp->d_ino) == NODE) 59656948Smckusick fp->postfix = '/'; 59756948Smckusick else 59856948Smckusick fp->postfix = ' '; 59956948Smckusick break; 60017752Smckusick } 60156948Smckusick return; 60217752Smckusick } 60317752Smckusick 60417752Smckusick /* 60517752Smckusick * Print out a pretty listing of a directory 60617752Smckusick */ 60756567Sbostic static void 60856948Smckusick formatf(list, nentry) 60956948Smckusick register struct afile *list; 61056948Smckusick int nentry; 61117752Smckusick { 61256948Smckusick register struct afile *fp, *endlist; 61356948Smckusick int width, bigino, haveprefix, havepostfix; 61456948Smckusick int i, j, w, precision, columns, lines; 61517752Smckusick 61656948Smckusick width = 0; 61756948Smckusick haveprefix = 0; 61856948Smckusick havepostfix = 0; 61956948Smckusick bigino = ROOTINO; 62056948Smckusick endlist = &list[nentry]; 62156948Smckusick for (fp = &list[0]; fp < endlist; fp++) { 62256948Smckusick if (bigino < fp->fnum) 62356948Smckusick bigino = fp->fnum; 62456948Smckusick if (width < fp->len) 62556948Smckusick width = fp->len; 62656948Smckusick if (fp->prefix != ' ') 62756948Smckusick haveprefix = 1; 62856948Smckusick if (fp->postfix != ' ') 62956948Smckusick havepostfix = 1; 63017752Smckusick } 63156948Smckusick if (haveprefix) 63256948Smckusick width++; 63356948Smckusick if (havepostfix) 63456948Smckusick width++; 63556948Smckusick if (vflag) { 63656948Smckusick for (precision = 0, i = bigino; i > 0; i /= 10) 63756948Smckusick precision++; 63856948Smckusick width += precision + 1; 63956948Smckusick } 64056948Smckusick width++; 64156948Smckusick columns = 81 / width; 64217752Smckusick if (columns == 0) 64317752Smckusick columns = 1; 64417752Smckusick lines = (nentry + columns - 1) / columns; 64517752Smckusick for (i = 0; i < lines; i++) { 64617752Smckusick for (j = 0; j < columns; j++) { 64756948Smckusick fp = &list[j * lines + i]; 64856948Smckusick if (vflag) { 64956948Smckusick fprintf(stderr, "%*d ", precision, fp->fnum); 65056948Smckusick fp->len += precision + 1; 65156948Smckusick } 65256948Smckusick if (haveprefix) { 65356948Smckusick putc(fp->prefix, stderr); 65456948Smckusick fp->len++; 65556948Smckusick } 65656948Smckusick fprintf(stderr, "%s", fp->fname); 65756948Smckusick if (havepostfix) { 65856948Smckusick putc(fp->postfix, stderr); 65956948Smckusick fp->len++; 66056948Smckusick } 66156948Smckusick if (fp + lines >= endlist) { 66217752Smckusick fprintf(stderr, "\n"); 66317752Smckusick break; 66417752Smckusick } 66556948Smckusick for (w = fp->len; w < width; w++) 66656948Smckusick putc(' ', stderr); 66717752Smckusick } 66817752Smckusick } 66917752Smckusick } 67017752Smckusick 67117752Smckusick /* 67256948Smckusick * Skip over directory entries that are not on the tape 67356948Smckusick * 67456948Smckusick * First have to get definition of a dirent. 67517752Smckusick */ 67656948Smckusick #undef DIRBLKSIZ 67756948Smckusick #include <dirent.h> 67856948Smckusick #undef d_ino 67956948Smckusick 68056948Smckusick struct dirent * 68156948Smckusick glob_readdir(dirp) 68256948Smckusick RST_DIR *dirp; 68317752Smckusick { 68456948Smckusick struct direct *dp; 68556948Smckusick static struct dirent adirent; 68656948Smckusick 68756948Smckusick while ((dp = rst_readdir(dirp)) != NULL) { 68856948Smckusick if (dp->d_ino == 0) 68956948Smckusick continue; 69056948Smckusick if (dflag || TSTINO(dp->d_ino, dumpmap)) 69156948Smckusick break; 69256948Smckusick } 69356948Smckusick if (dp == NULL) 69456948Smckusick return (NULL); 69556948Smckusick adirent.d_fileno = dp->d_ino; 69656948Smckusick adirent.d_namlen = dp->d_namlen; 69756948Smckusick bcopy(dp->d_name, adirent.d_name, dp->d_namlen + 1); 69856948Smckusick return (&adirent); 69917752Smckusick } 70017752Smckusick 70117752Smckusick /* 70256948Smckusick * Return st_mode information in response to stat or lstat calls 70317752Smckusick */ 70456948Smckusick static int 70556948Smckusick glob_stat(name, stp) 70657896Sbostic const char *name; 70756948Smckusick struct stat *stp; 70817752Smckusick { 70956948Smckusick register struct direct *dp; 71017752Smckusick 71156948Smckusick dp = pathsearch(name); 71256948Smckusick if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0)) 71356948Smckusick return (-1); 71456948Smckusick if (inodetype(dp->d_ino) == NODE) 71556948Smckusick stp->st_mode = IFDIR; 71617752Smckusick else 71756948Smckusick stp->st_mode = IFREG; 71856948Smckusick return (0); 71956948Smckusick } 72054593Smckusick 72156948Smckusick /* 72256948Smckusick * Comparison routine for qsort. 72356948Smckusick */ 72456948Smckusick static int 72556948Smckusick fcmp(f1, f2) 72656948Smckusick register const void *f1, *f2; 72756948Smckusick { 72856948Smckusick return (strcmp(((struct afile *)f1)->fname, 72956948Smckusick ((struct afile *)f2)->fname)); 73017752Smckusick } 73117752Smckusick 73217752Smckusick /* 73317752Smckusick * respond to interrupts 73417752Smckusick */ 73539942Sbostic void 73656567Sbostic onintr(signo) 73756567Sbostic int signo; 73817752Smckusick { 73956429Smckusick if (command == 'i' && runshell) 74017752Smckusick longjmp(reset, 1); 74117752Smckusick if (reply("restore interrupted, continue") == FAIL) 74217752Smckusick done(1); 74317752Smckusick } 744