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*57896Sbostic static char sccsid[] = "@(#)interactive.c 5.19 (Berkeley) 02/10/93"; 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 *)); 5856567Sbostic static char *fmtentry __P((struct afile *)); 5956948Smckusick static void formatf __P((struct afile *, int)); 6056567Sbostic static void getcmd __P((char *, char *, char *, struct arglist *)); 6156948Smckusick struct dirent *glob_readdir __P((RST_DIR *dirp)); 62*57896Sbostic static int glob_stat __P((const char *, struct stat *)); 6356948Smckusick static void mkentry __P((struct direct *, struct afile *)); 6456948Smckusick static void printlist __P((char *, char *)); 6556567Sbostic 6617752Smckusick /* 6717752Smckusick * Read and execute commands from the terminal. 6817752Smckusick */ 6956567Sbostic void 7017752Smckusick runcmdshell() 7117752Smckusick { 7217752Smckusick register struct entry *np; 7317752Smckusick ino_t ino; 7456948Smckusick struct arglist arglist; 7517752Smckusick char curdir[MAXPATHLEN]; 7617752Smckusick char name[MAXPATHLEN]; 7717752Smckusick char cmd[BUFSIZ]; 7817752Smckusick 7956948Smckusick arglist.freeglob = 0; 8056948Smckusick arglist.argcnt = 0; 8156948Smckusick arglist.glob.gl_flags = GLOB_ALTDIRFUNC; 8256948Smckusick arglist.glob.gl_opendir = (void *)rst_opendir; 8356948Smckusick arglist.glob.gl_readdir = (void *)glob_readdir; 8456948Smckusick arglist.glob.gl_closedir = rst_closedir; 8556948Smckusick arglist.glob.gl_lstat = glob_stat; 8656948Smckusick arglist.glob.gl_stat = glob_stat; 8717752Smckusick canon("/", curdir); 8817752Smckusick loop: 8917752Smckusick if (setjmp(reset) != 0) { 9056948Smckusick if (arglist.freeglob != 0) { 9156948Smckusick arglist.freeglob = 0; 9256948Smckusick arglist.argcnt = 0; 9356948Smckusick globfree(&arglist.glob); 9456948Smckusick } 9517752Smckusick nextarg = NULL; 9617752Smckusick volno = 0; 9717752Smckusick } 9856429Smckusick runshell = 1; 9956948Smckusick getcmd(curdir, cmd, name, &arglist); 10017752Smckusick switch (cmd[0]) { 10117752Smckusick /* 10217752Smckusick * Add elements to the extraction list. 10317752Smckusick */ 10417752Smckusick case 'a': 10529903Smckusick if (strncmp(cmd, "add", strlen(cmd)) != 0) 10629903Smckusick goto bad; 10717752Smckusick ino = dirlookup(name); 10817752Smckusick if (ino == 0) 10917752Smckusick break; 11017752Smckusick if (mflag) 11117752Smckusick pathcheck(name); 11217752Smckusick treescan(name, ino, addfile); 11317752Smckusick break; 11417752Smckusick /* 11517752Smckusick * Change working directory. 11617752Smckusick */ 11717752Smckusick case 'c': 11829903Smckusick if (strncmp(cmd, "cd", strlen(cmd)) != 0) 11929903Smckusick goto bad; 12017752Smckusick ino = dirlookup(name); 12117752Smckusick if (ino == 0) 12217752Smckusick break; 12317752Smckusick if (inodetype(ino) == LEAF) { 12417752Smckusick fprintf(stderr, "%s: not a directory\n", name); 12517752Smckusick break; 12617752Smckusick } 12717752Smckusick (void) strcpy(curdir, name); 12817752Smckusick break; 12917752Smckusick /* 13017752Smckusick * Delete elements from the extraction list. 13117752Smckusick */ 13217752Smckusick case 'd': 13329903Smckusick if (strncmp(cmd, "delete", strlen(cmd)) != 0) 13429903Smckusick goto bad; 13517752Smckusick np = lookupname(name); 13656567Sbostic if (np == NULL || (np->e_flags & NEW) == 0) { 13717752Smckusick fprintf(stderr, "%s: not on extraction list\n", name); 13817752Smckusick break; 13917752Smckusick } 14017752Smckusick treescan(name, np->e_ino, deletefile); 14117752Smckusick break; 14217752Smckusick /* 14317752Smckusick * Extract the requested list. 14417752Smckusick */ 14517752Smckusick case 'e': 14629903Smckusick if (strncmp(cmd, "extract", strlen(cmd)) != 0) 14729903Smckusick goto bad; 14817752Smckusick createfiles(); 14917752Smckusick createlinks(); 15055880Smckusick setdirmodes(0); 15117752Smckusick if (dflag) 15217752Smckusick checkrestore(); 15317752Smckusick volno = 0; 15417752Smckusick break; 15517752Smckusick /* 15617752Smckusick * List available commands. 15717752Smckusick */ 15817752Smckusick case 'h': 15929903Smckusick if (strncmp(cmd, "help", strlen(cmd)) != 0) 16029903Smckusick goto bad; 16117752Smckusick case '?': 16229903Smckusick fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 16317752Smckusick "Available commands are:\n", 16417752Smckusick "\tls [arg] - list directory\n", 16517752Smckusick "\tcd arg - change directory\n", 16617752Smckusick "\tpwd - print current directory\n", 16717752Smckusick "\tadd [arg] - add `arg' to list of", 16817752Smckusick " files to be extracted\n", 16917752Smckusick "\tdelete [arg] - delete `arg' from", 17017752Smckusick " list of files to be extracted\n", 17117752Smckusick "\textract - extract requested files\n", 17221096Smckusick "\tsetmodes - set modes of requested directories\n", 17317752Smckusick "\tquit - immediately exit program\n", 17429903Smckusick "\twhat - list dump header information\n", 17517752Smckusick "\tverbose - toggle verbose flag", 17617752Smckusick " (useful with ``ls'')\n", 17717752Smckusick "\thelp or `?' - print this list\n", 17817752Smckusick "If no `arg' is supplied, the current", 17917752Smckusick " directory is used\n"); 18017752Smckusick break; 18117752Smckusick /* 18217752Smckusick * List a directory. 18317752Smckusick */ 18417752Smckusick case 'l': 18529903Smckusick if (strncmp(cmd, "ls", strlen(cmd)) != 0) 18629903Smckusick goto bad; 18756948Smckusick printlist(name, curdir); 18817752Smckusick break; 18917752Smckusick /* 19017752Smckusick * Print current directory. 19117752Smckusick */ 19217752Smckusick case 'p': 19329903Smckusick if (strncmp(cmd, "pwd", strlen(cmd)) != 0) 19429903Smckusick goto bad; 19517752Smckusick if (curdir[1] == '\0') 19617752Smckusick fprintf(stderr, "/\n"); 19717752Smckusick else 19817752Smckusick fprintf(stderr, "%s\n", &curdir[1]); 19917752Smckusick break; 20017752Smckusick /* 20117752Smckusick * Quit. 20217752Smckusick */ 20317752Smckusick case 'q': 20429903Smckusick if (strncmp(cmd, "quit", strlen(cmd)) != 0) 20529903Smckusick goto bad; 20629903Smckusick return; 20717752Smckusick case 'x': 20829903Smckusick if (strncmp(cmd, "xit", strlen(cmd)) != 0) 20929903Smckusick goto bad; 21017752Smckusick return; 21117752Smckusick /* 21217752Smckusick * Toggle verbose mode. 21317752Smckusick */ 21417752Smckusick case 'v': 21529903Smckusick if (strncmp(cmd, "verbose", strlen(cmd)) != 0) 21629903Smckusick goto bad; 21717752Smckusick if (vflag) { 21817752Smckusick fprintf(stderr, "verbose mode off\n"); 21917752Smckusick vflag = 0; 22017752Smckusick break; 22117752Smckusick } 22217752Smckusick fprintf(stderr, "verbose mode on\n"); 22317752Smckusick vflag++; 22417752Smckusick break; 22517752Smckusick /* 22617752Smckusick * Just restore requested directory modes. 22717752Smckusick */ 22821096Smckusick case 's': 22929903Smckusick if (strncmp(cmd, "setmodes", strlen(cmd)) != 0) 23029903Smckusick goto bad; 23155880Smckusick setdirmodes(FORCE); 23217752Smckusick break; 23317752Smckusick /* 23429903Smckusick * Print out dump header information. 23529903Smckusick */ 23629903Smckusick case 'w': 23729903Smckusick if (strncmp(cmd, "what", strlen(cmd)) != 0) 23829903Smckusick goto bad; 23929903Smckusick printdumpinfo(); 24029903Smckusick break; 24129903Smckusick /* 24217752Smckusick * Turn on debugging. 24317752Smckusick */ 24417752Smckusick case 'D': 24529903Smckusick if (strncmp(cmd, "Debug", strlen(cmd)) != 0) 24629903Smckusick goto bad; 24717752Smckusick if (dflag) { 24817752Smckusick fprintf(stderr, "debugging mode off\n"); 24917752Smckusick dflag = 0; 25017752Smckusick break; 25117752Smckusick } 25217752Smckusick fprintf(stderr, "debugging mode on\n"); 25317752Smckusick dflag++; 25417752Smckusick break; 25517752Smckusick /* 25617752Smckusick * Unknown command. 25717752Smckusick */ 25817752Smckusick default: 25929903Smckusick bad: 26017752Smckusick fprintf(stderr, "%s: unknown command; type ? for help\n", cmd); 26117752Smckusick break; 26217752Smckusick } 26317752Smckusick goto loop; 26417752Smckusick } 26517752Smckusick 26617752Smckusick /* 26717752Smckusick * Read and parse an interactive command. 26817752Smckusick * The first word on the line is assigned to "cmd". If 26917752Smckusick * there are no arguments on the command line, then "curdir" 27017752Smckusick * is returned as the argument. If there are arguments 27117752Smckusick * on the line they are returned one at a time on each 27217752Smckusick * successive call to getcmd. Each argument is first assigned 27317752Smckusick * to "name". If it does not start with "/" the pathname in 27417752Smckusick * "curdir" is prepended to it. Finally "canon" is called to 27517752Smckusick * eliminate any embedded ".." components. 27617752Smckusick */ 27756567Sbostic static void 27818003Smckusick getcmd(curdir, cmd, name, ap) 27917752Smckusick char *curdir, *cmd, *name; 28018003Smckusick struct arglist *ap; 28117752Smckusick { 28217752Smckusick register char *cp; 28317752Smckusick static char input[BUFSIZ]; 28417752Smckusick char output[BUFSIZ]; 28517752Smckusick # define rawname input /* save space by reusing input buffer */ 28617752Smckusick 28717752Smckusick /* 28817752Smckusick * Check to see if still processing arguments. 28917752Smckusick */ 29056948Smckusick if (ap->argcnt > 0) 29156948Smckusick goto retnext; 29217752Smckusick if (nextarg != NULL) 29317752Smckusick goto getnext; 29417752Smckusick /* 29517752Smckusick * Read a command line and trim off trailing white space. 29617752Smckusick */ 29717752Smckusick do { 29817752Smckusick fprintf(stderr, "restore > "); 29917752Smckusick (void) fflush(stderr); 30017752Smckusick (void) fgets(input, BUFSIZ, terminal); 30117752Smckusick } while (!feof(terminal) && input[0] == '\n'); 30217752Smckusick if (feof(terminal)) { 30317752Smckusick (void) strcpy(cmd, "quit"); 30417752Smckusick return; 30517752Smckusick } 30617752Smckusick for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--) 30717752Smckusick /* trim off trailing white space and newline */; 30817752Smckusick *++cp = '\0'; 30917752Smckusick /* 31017752Smckusick * Copy the command into "cmd". 31117752Smckusick */ 31217752Smckusick cp = copynext(input, cmd); 31318003Smckusick ap->cmd = cmd; 31417752Smckusick /* 31517752Smckusick * If no argument, use curdir as the default. 31617752Smckusick */ 31717752Smckusick if (*cp == '\0') { 31817752Smckusick (void) strcpy(name, curdir); 31917752Smckusick return; 32017752Smckusick } 32117752Smckusick nextarg = cp; 32217752Smckusick /* 32317752Smckusick * Find the next argument. 32417752Smckusick */ 32517752Smckusick getnext: 32617752Smckusick cp = copynext(nextarg, rawname); 32717752Smckusick if (*cp == '\0') 32817752Smckusick nextarg = NULL; 32917752Smckusick else 33017752Smckusick nextarg = cp; 33117752Smckusick /* 33256948Smckusick * If it is an absolute pathname, canonicalize it and return it. 33317752Smckusick */ 33417752Smckusick if (rawname[0] == '/') { 33517752Smckusick canon(rawname, name); 33617752Smckusick } else { 33717752Smckusick /* 33817752Smckusick * For relative pathnames, prepend the current directory to 33917752Smckusick * it then canonicalize and return it. 34017752Smckusick */ 34117752Smckusick (void) strcpy(output, curdir); 34217752Smckusick (void) strcat(output, "/"); 34317752Smckusick (void) strcat(output, rawname); 34417752Smckusick canon(output, name); 34517752Smckusick } 34656948Smckusick if (glob(name, GLOB_ALTDIRFUNC, NULL, &ap->glob) < 0) 34756948Smckusick fprintf(stderr, "%s: out of memory\n", ap->cmd); 34856948Smckusick if (ap->glob.gl_pathc == 0) 34956948Smckusick return; 35056948Smckusick ap->freeglob = 1; 35156948Smckusick ap->argcnt = ap->glob.gl_pathc; 35256948Smckusick 35356948Smckusick retnext: 35456948Smckusick strcpy(name, ap->glob.gl_pathv[ap->glob.gl_pathc - ap->argcnt]); 35556948Smckusick if (--ap->argcnt == 0) { 35656948Smckusick ap->freeglob = 0; 35756948Smckusick globfree(&ap->glob); 35856948Smckusick } 35917752Smckusick # undef rawname 36017752Smckusick } 36117752Smckusick 36217752Smckusick /* 36317752Smckusick * Strip off the next token of the input. 36417752Smckusick */ 36556567Sbostic static char * 36617752Smckusick copynext(input, output) 36717752Smckusick char *input, *output; 36817752Smckusick { 36917752Smckusick register char *cp, *bp; 37017752Smckusick char quote; 37117752Smckusick 37217752Smckusick for (cp = input; *cp == ' ' || *cp == '\t'; cp++) 37317752Smckusick /* skip to argument */; 37417752Smckusick bp = output; 37517752Smckusick while (*cp != ' ' && *cp != '\t' && *cp != '\0') { 37617752Smckusick /* 37717752Smckusick * Handle back slashes. 37817752Smckusick */ 37917752Smckusick if (*cp == '\\') { 38017752Smckusick if (*++cp == '\0') { 38117752Smckusick fprintf(stderr, 38217752Smckusick "command lines cannot be continued\n"); 38317752Smckusick continue; 38417752Smckusick } 38517752Smckusick *bp++ = *cp++; 38617752Smckusick continue; 38717752Smckusick } 38817752Smckusick /* 38917752Smckusick * The usual unquoted case. 39017752Smckusick */ 39117752Smckusick if (*cp != '\'' && *cp != '"') { 39217752Smckusick *bp++ = *cp++; 39317752Smckusick continue; 39417752Smckusick } 39517752Smckusick /* 39617752Smckusick * Handle single and double quotes. 39717752Smckusick */ 39817752Smckusick quote = *cp++; 39917752Smckusick while (*cp != quote && *cp != '\0') 40017752Smckusick *bp++ = *cp++ | 0200; 40117752Smckusick if (*cp++ == '\0') { 40217752Smckusick fprintf(stderr, "missing %c\n", quote); 40317752Smckusick cp--; 40417752Smckusick continue; 40517752Smckusick } 40617752Smckusick } 40717752Smckusick *bp = '\0'; 40817752Smckusick return (cp); 40917752Smckusick } 41017752Smckusick 41117752Smckusick /* 41217752Smckusick * Canonicalize file names to always start with ``./'' and 41318003Smckusick * remove any imbedded "." and ".." components. 41417752Smckusick */ 41556567Sbostic void 41617752Smckusick canon(rawname, canonname) 41717752Smckusick char *rawname, *canonname; 41817752Smckusick { 41917752Smckusick register char *cp, *np; 42017752Smckusick 42117752Smckusick if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0) 42217752Smckusick (void) strcpy(canonname, ""); 42317752Smckusick else if (rawname[0] == '/') 42417752Smckusick (void) strcpy(canonname, "."); 42517752Smckusick else 42617752Smckusick (void) strcpy(canonname, "./"); 42717752Smckusick (void) strcat(canonname, rawname); 42817752Smckusick /* 42918003Smckusick * Eliminate multiple and trailing '/'s 43017752Smckusick */ 43118003Smckusick for (cp = np = canonname; *np != '\0'; cp++) { 43218003Smckusick *cp = *np++; 43318003Smckusick while (*cp == '/' && *np == '/') 43418003Smckusick np++; 43518003Smckusick } 43618003Smckusick *cp = '\0'; 43718003Smckusick if (*--cp == '/') 43818003Smckusick *cp = '\0'; 43918003Smckusick /* 44018003Smckusick * Eliminate extraneous "." and ".." from pathnames. 44118003Smckusick */ 44217752Smckusick for (np = canonname; *np != '\0'; ) { 44317752Smckusick np++; 44417752Smckusick cp = np; 44517752Smckusick while (*np != '/' && *np != '\0') 44617752Smckusick np++; 44718003Smckusick if (np - cp == 1 && *cp == '.') { 44818003Smckusick cp--; 44918003Smckusick (void) strcpy(cp, np); 45018003Smckusick np = cp; 45118003Smckusick } 45217752Smckusick if (np - cp == 2 && strncmp(cp, "..", 2) == 0) { 45317752Smckusick cp--; 45417752Smckusick while (cp > &canonname[1] && *--cp != '/') 45517752Smckusick /* find beginning of name */; 45617752Smckusick (void) strcpy(cp, np); 45717752Smckusick np = cp; 45817752Smckusick } 45917752Smckusick } 46017752Smckusick } 46117752Smckusick 46217752Smckusick /* 46317752Smckusick * Do an "ls" style listing of a directory 46417752Smckusick */ 46556567Sbostic static void 46656948Smckusick printlist(name, basename) 46717752Smckusick char *name; 46817752Smckusick char *basename; 46917752Smckusick { 47056948Smckusick register struct afile *fp, *list, *listp; 47118003Smckusick register struct direct *dp; 47217752Smckusick struct afile single; 47350655Smckusick RST_DIR *dirp; 47456948Smckusick int entries, len; 47517752Smckusick 47656948Smckusick dp = pathsearch(name); 47756948Smckusick if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0)) 47856948Smckusick return; 47917752Smckusick if ((dirp = rst_opendir(name)) == NULL) { 48056948Smckusick entries = 1; 48156948Smckusick list = &single; 48256948Smckusick mkentry(dp, list); 48356948Smckusick len = strlen(basename) + 1; 48456948Smckusick if (strlen(name) - len > single.len) { 48556948Smckusick freename(single.fname); 48656948Smckusick single.fname = savename(&name[len]); 48756948Smckusick single.len = strlen(single.fname); 48856948Smckusick } 48917752Smckusick } else { 49056948Smckusick entries = 0; 49156948Smckusick while (dp = rst_readdir(dirp)) 49256948Smckusick entries++; 49356948Smckusick rst_closedir(dirp); 49456948Smckusick list = (struct afile *)malloc(entries * sizeof(struct afile)); 49556948Smckusick if (list == NULL) { 49656948Smckusick fprintf(stderr, "ls: out of memory\n"); 49756948Smckusick return; 49856948Smckusick } 49956948Smckusick if ((dirp = rst_opendir(name)) == NULL) 50056948Smckusick panic("directory reopen failed\n"); 50118003Smckusick fprintf(stderr, "%s:\n", name); 50256948Smckusick entries = 0; 50356948Smckusick listp = list; 50418003Smckusick while (dp = rst_readdir(dirp)) { 50518003Smckusick if (dp == NULL || dp->d_ino == 0) 50618003Smckusick break; 50756427Smckusick if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) 50818003Smckusick continue; 50918003Smckusick if (vflag == 0 && 51018003Smckusick (strcmp(dp->d_name, ".") == 0 || 51118003Smckusick strcmp(dp->d_name, "..") == 0)) 51218003Smckusick continue; 51356948Smckusick mkentry(dp, listp++); 51456948Smckusick entries++; 51518003Smckusick } 51656948Smckusick rst_closedir(dirp); 51756948Smckusick if (entries == 0) { 51856948Smckusick fprintf(stderr, "\n"); 51956948Smckusick free(list); 52056948Smckusick return; 52156948Smckusick } 52256948Smckusick qsort((char *)list, entries, sizeof(struct afile), fcmp); 52317752Smckusick } 52456948Smckusick formatf(list, entries); 52556948Smckusick if (dirp != NULL) { 52656948Smckusick for (fp = listp - 1; fp >= list; fp--) 52718003Smckusick freename(fp->fname); 52856948Smckusick fprintf(stderr, "\n"); 52956948Smckusick free(list); 53018003Smckusick } 53117752Smckusick } 53217752Smckusick 53317752Smckusick /* 53417752Smckusick * Read the contents of a directory. 53517752Smckusick */ 53656948Smckusick static void 53756948Smckusick mkentry(dp, fp) 53854593Smckusick struct direct *dp; 53956948Smckusick register struct afile *fp; 54017752Smckusick { 54156948Smckusick char *cp; 54256948Smckusick struct entry *np; 54317752Smckusick 54454593Smckusick fp->fnum = dp->d_ino; 54556948Smckusick fp->fname = savename(dp->d_name); 54656948Smckusick for (cp = fp->fname; *cp; cp++) 54756948Smckusick if (!vflag && (*cp < ' ' || *cp >= 0177)) 54856948Smckusick *cp = '?'; 54956948Smckusick fp->len = cp - fp->fname; 55056948Smckusick if (dflag && TSTINO(fp->fnum, dumpmap) == 0) 55156948Smckusick fp->prefix = '^'; 55256948Smckusick else if ((np = lookupino(fp->fnum)) != NULL && (np->e_flags & NEW)) 55356948Smckusick fp->prefix = '*'; 55454593Smckusick else 55556948Smckusick fp->prefix = ' '; 55656948Smckusick switch(dp->d_type) { 55756948Smckusick 55856948Smckusick default: 55956948Smckusick fprintf(stderr, "Warning: undefined file type %d\n", 56056948Smckusick dp->d_type); 56156948Smckusick /* fall through */ 56256948Smckusick case DT_REG: 56356948Smckusick fp->postfix = ' '; 56456948Smckusick break; 56556948Smckusick 56656948Smckusick case DT_LNK: 56756948Smckusick fp->postfix = '@'; 56856948Smckusick break; 56956948Smckusick 57056948Smckusick case DT_FIFO: 57156948Smckusick case DT_SOCK: 57256948Smckusick fp->postfix = '='; 57356948Smckusick break; 57456948Smckusick 57556948Smckusick case DT_CHR: 57656948Smckusick case DT_BLK: 57756948Smckusick fp->postfix = '#'; 57856948Smckusick break; 57956948Smckusick 58056948Smckusick case DT_UNKNOWN: 58156948Smckusick case DT_DIR: 58256948Smckusick if (inodetype(dp->d_ino) == NODE) 58356948Smckusick fp->postfix = '/'; 58456948Smckusick else 58556948Smckusick fp->postfix = ' '; 58656948Smckusick break; 58717752Smckusick } 58856948Smckusick return; 58917752Smckusick } 59017752Smckusick 59117752Smckusick /* 59217752Smckusick * Print out a pretty listing of a directory 59317752Smckusick */ 59456567Sbostic static void 59556948Smckusick formatf(list, nentry) 59656948Smckusick register struct afile *list; 59756948Smckusick int nentry; 59817752Smckusick { 59956948Smckusick register struct afile *fp, *endlist; 60056948Smckusick int width, bigino, haveprefix, havepostfix; 60156948Smckusick int i, j, w, precision, columns, lines; 60217752Smckusick 60356948Smckusick width = 0; 60456948Smckusick haveprefix = 0; 60556948Smckusick havepostfix = 0; 60656948Smckusick bigino = ROOTINO; 60756948Smckusick endlist = &list[nentry]; 60856948Smckusick for (fp = &list[0]; fp < endlist; fp++) { 60956948Smckusick if (bigino < fp->fnum) 61056948Smckusick bigino = fp->fnum; 61156948Smckusick if (width < fp->len) 61256948Smckusick width = fp->len; 61356948Smckusick if (fp->prefix != ' ') 61456948Smckusick haveprefix = 1; 61556948Smckusick if (fp->postfix != ' ') 61656948Smckusick havepostfix = 1; 61717752Smckusick } 61856948Smckusick if (haveprefix) 61956948Smckusick width++; 62056948Smckusick if (havepostfix) 62156948Smckusick width++; 62256948Smckusick if (vflag) { 62356948Smckusick for (precision = 0, i = bigino; i > 0; i /= 10) 62456948Smckusick precision++; 62556948Smckusick width += precision + 1; 62656948Smckusick } 62756948Smckusick width++; 62856948Smckusick columns = 81 / width; 62917752Smckusick if (columns == 0) 63017752Smckusick columns = 1; 63117752Smckusick lines = (nentry + columns - 1) / columns; 63217752Smckusick for (i = 0; i < lines; i++) { 63317752Smckusick for (j = 0; j < columns; j++) { 63456948Smckusick fp = &list[j * lines + i]; 63556948Smckusick if (vflag) { 63656948Smckusick fprintf(stderr, "%*d ", precision, fp->fnum); 63756948Smckusick fp->len += precision + 1; 63856948Smckusick } 63956948Smckusick if (haveprefix) { 64056948Smckusick putc(fp->prefix, stderr); 64156948Smckusick fp->len++; 64256948Smckusick } 64356948Smckusick fprintf(stderr, "%s", fp->fname); 64456948Smckusick if (havepostfix) { 64556948Smckusick putc(fp->postfix, stderr); 64656948Smckusick fp->len++; 64756948Smckusick } 64856948Smckusick if (fp + lines >= endlist) { 64917752Smckusick fprintf(stderr, "\n"); 65017752Smckusick break; 65117752Smckusick } 65256948Smckusick for (w = fp->len; w < width; w++) 65356948Smckusick putc(' ', stderr); 65417752Smckusick } 65517752Smckusick } 65617752Smckusick } 65717752Smckusick 65817752Smckusick /* 65956948Smckusick * Skip over directory entries that are not on the tape 66056948Smckusick * 66156948Smckusick * First have to get definition of a dirent. 66217752Smckusick */ 66356948Smckusick #undef DIRBLKSIZ 66456948Smckusick #include <dirent.h> 66556948Smckusick #undef d_ino 66656948Smckusick 66756948Smckusick struct dirent * 66856948Smckusick glob_readdir(dirp) 66956948Smckusick RST_DIR *dirp; 67017752Smckusick { 67156948Smckusick struct direct *dp; 67256948Smckusick static struct dirent adirent; 67356948Smckusick 67456948Smckusick while ((dp = rst_readdir(dirp)) != NULL) { 67556948Smckusick if (dp->d_ino == 0) 67656948Smckusick continue; 67756948Smckusick if (dflag || TSTINO(dp->d_ino, dumpmap)) 67856948Smckusick break; 67956948Smckusick } 68056948Smckusick if (dp == NULL) 68156948Smckusick return (NULL); 68256948Smckusick adirent.d_fileno = dp->d_ino; 68356948Smckusick adirent.d_namlen = dp->d_namlen; 68456948Smckusick bcopy(dp->d_name, adirent.d_name, dp->d_namlen + 1); 68556948Smckusick return (&adirent); 68617752Smckusick } 68717752Smckusick 68817752Smckusick /* 68956948Smckusick * Return st_mode information in response to stat or lstat calls 69017752Smckusick */ 69156948Smckusick static int 69256948Smckusick glob_stat(name, stp) 693*57896Sbostic const char *name; 69456948Smckusick struct stat *stp; 69517752Smckusick { 69656948Smckusick register struct direct *dp; 69717752Smckusick 69856948Smckusick dp = pathsearch(name); 69956948Smckusick if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0)) 70056948Smckusick return (-1); 70156948Smckusick if (inodetype(dp->d_ino) == NODE) 70256948Smckusick stp->st_mode = IFDIR; 70317752Smckusick else 70456948Smckusick stp->st_mode = IFREG; 70556948Smckusick return (0); 70656948Smckusick } 70754593Smckusick 70856948Smckusick /* 70956948Smckusick * Comparison routine for qsort. 71056948Smckusick */ 71156948Smckusick static int 71256948Smckusick fcmp(f1, f2) 71356948Smckusick register const void *f1, *f2; 71456948Smckusick { 71556948Smckusick return (strcmp(((struct afile *)f1)->fname, 71656948Smckusick ((struct afile *)f2)->fname)); 71717752Smckusick } 71817752Smckusick 71917752Smckusick /* 72017752Smckusick * respond to interrupts 72117752Smckusick */ 72239942Sbostic void 72356567Sbostic onintr(signo) 72456567Sbostic int signo; 72517752Smckusick { 72656429Smckusick if (command == 'i' && runshell) 72717752Smckusick longjmp(reset, 1); 72817752Smckusick if (reply("restore interrupted, continue") == FAIL) 72917752Smckusick done(1); 73017752Smckusick } 731