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*56948Smckusick static char sccsid[] = "@(#)interactive.c 5.18 (Berkeley) 12/02/92"; 1036105Sbostic #endif /* not lint */ 1117752Smckusick 1256567Sbostic #include <sys/param.h> 1356567Sbostic #include <sys/time.h> 14*56948Smckusick #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> 22*56948Smckusick #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 */ 45*56948Smckusick short len; /* name length */ 46*56948Smckusick char prefix; /* prefix character */ 47*56948Smckusick char postfix; /* postfix character */ 4817752Smckusick }; 4918003Smckusick struct arglist { 50*56948Smckusick int freeglob; /* glob structure needs to be freed */ 51*56948Smckusick int argcnt; /* next globbed argument to return */ 52*56948Smckusick glob_t glob; /* globbing information */ 53*56948Smckusick 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 *)); 59*56948Smckusick static void formatf __P((struct afile *, int)); 6056567Sbostic static void getcmd __P((char *, char *, char *, struct arglist *)); 61*56948Smckusick struct dirent *glob_readdir __P((RST_DIR *dirp)); 62*56948Smckusick static int glob_stat __P((char *, struct stat *)); 63*56948Smckusick static void mkentry __P((struct direct *, struct afile *)); 64*56948Smckusick 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; 74*56948Smckusick struct arglist arglist; 7517752Smckusick char curdir[MAXPATHLEN]; 7617752Smckusick char name[MAXPATHLEN]; 7717752Smckusick char cmd[BUFSIZ]; 7817752Smckusick 79*56948Smckusick arglist.freeglob = 0; 80*56948Smckusick arglist.argcnt = 0; 81*56948Smckusick arglist.glob.gl_flags = GLOB_ALTDIRFUNC; 82*56948Smckusick arglist.glob.gl_opendir = (void *)rst_opendir; 83*56948Smckusick arglist.glob.gl_readdir = (void *)glob_readdir; 84*56948Smckusick arglist.glob.gl_closedir = rst_closedir; 85*56948Smckusick arglist.glob.gl_lstat = glob_stat; 86*56948Smckusick arglist.glob.gl_stat = glob_stat; 8717752Smckusick canon("/", curdir); 8817752Smckusick loop: 8917752Smckusick if (setjmp(reset) != 0) { 90*56948Smckusick if (arglist.freeglob != 0) { 91*56948Smckusick arglist.freeglob = 0; 92*56948Smckusick arglist.argcnt = 0; 93*56948Smckusick globfree(&arglist.glob); 94*56948Smckusick } 9517752Smckusick nextarg = NULL; 9617752Smckusick volno = 0; 9717752Smckusick } 9856429Smckusick runshell = 1; 99*56948Smckusick 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; 187*56948Smckusick 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 */ 290*56948Smckusick if (ap->argcnt > 0) 291*56948Smckusick 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 /* 332*56948Smckusick * 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 } 346*56948Smckusick if (glob(name, GLOB_ALTDIRFUNC, NULL, &ap->glob) < 0) 347*56948Smckusick fprintf(stderr, "%s: out of memory\n", ap->cmd); 348*56948Smckusick if (ap->glob.gl_pathc == 0) 349*56948Smckusick return; 350*56948Smckusick ap->freeglob = 1; 351*56948Smckusick ap->argcnt = ap->glob.gl_pathc; 352*56948Smckusick 353*56948Smckusick retnext: 354*56948Smckusick strcpy(name, ap->glob.gl_pathv[ap->glob.gl_pathc - ap->argcnt]); 355*56948Smckusick if (--ap->argcnt == 0) { 356*56948Smckusick ap->freeglob = 0; 357*56948Smckusick globfree(&ap->glob); 358*56948Smckusick } 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 466*56948Smckusick printlist(name, basename) 46717752Smckusick char *name; 46817752Smckusick char *basename; 46917752Smckusick { 470*56948Smckusick register struct afile *fp, *list, *listp; 47118003Smckusick register struct direct *dp; 47217752Smckusick struct afile single; 47350655Smckusick RST_DIR *dirp; 474*56948Smckusick int entries, len; 47517752Smckusick 476*56948Smckusick dp = pathsearch(name); 477*56948Smckusick if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0)) 478*56948Smckusick return; 47917752Smckusick if ((dirp = rst_opendir(name)) == NULL) { 480*56948Smckusick entries = 1; 481*56948Smckusick list = &single; 482*56948Smckusick mkentry(dp, list); 483*56948Smckusick len = strlen(basename) + 1; 484*56948Smckusick if (strlen(name) - len > single.len) { 485*56948Smckusick freename(single.fname); 486*56948Smckusick single.fname = savename(&name[len]); 487*56948Smckusick single.len = strlen(single.fname); 488*56948Smckusick } 48917752Smckusick } else { 490*56948Smckusick entries = 0; 491*56948Smckusick while (dp = rst_readdir(dirp)) 492*56948Smckusick entries++; 493*56948Smckusick rst_closedir(dirp); 494*56948Smckusick list = (struct afile *)malloc(entries * sizeof(struct afile)); 495*56948Smckusick if (list == NULL) { 496*56948Smckusick fprintf(stderr, "ls: out of memory\n"); 497*56948Smckusick return; 498*56948Smckusick } 499*56948Smckusick if ((dirp = rst_opendir(name)) == NULL) 500*56948Smckusick panic("directory reopen failed\n"); 50118003Smckusick fprintf(stderr, "%s:\n", name); 502*56948Smckusick entries = 0; 503*56948Smckusick 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; 513*56948Smckusick mkentry(dp, listp++); 514*56948Smckusick entries++; 51518003Smckusick } 516*56948Smckusick rst_closedir(dirp); 517*56948Smckusick if (entries == 0) { 518*56948Smckusick fprintf(stderr, "\n"); 519*56948Smckusick free(list); 520*56948Smckusick return; 521*56948Smckusick } 522*56948Smckusick qsort((char *)list, entries, sizeof(struct afile), fcmp); 52317752Smckusick } 524*56948Smckusick formatf(list, entries); 525*56948Smckusick if (dirp != NULL) { 526*56948Smckusick for (fp = listp - 1; fp >= list; fp--) 52718003Smckusick freename(fp->fname); 528*56948Smckusick fprintf(stderr, "\n"); 529*56948Smckusick free(list); 53018003Smckusick } 53117752Smckusick } 53217752Smckusick 53317752Smckusick /* 53417752Smckusick * Read the contents of a directory. 53517752Smckusick */ 536*56948Smckusick static void 537*56948Smckusick mkentry(dp, fp) 53854593Smckusick struct direct *dp; 539*56948Smckusick register struct afile *fp; 54017752Smckusick { 541*56948Smckusick char *cp; 542*56948Smckusick struct entry *np; 54317752Smckusick 54454593Smckusick fp->fnum = dp->d_ino; 545*56948Smckusick fp->fname = savename(dp->d_name); 546*56948Smckusick for (cp = fp->fname; *cp; cp++) 547*56948Smckusick if (!vflag && (*cp < ' ' || *cp >= 0177)) 548*56948Smckusick *cp = '?'; 549*56948Smckusick fp->len = cp - fp->fname; 550*56948Smckusick if (dflag && TSTINO(fp->fnum, dumpmap) == 0) 551*56948Smckusick fp->prefix = '^'; 552*56948Smckusick else if ((np = lookupino(fp->fnum)) != NULL && (np->e_flags & NEW)) 553*56948Smckusick fp->prefix = '*'; 55454593Smckusick else 555*56948Smckusick fp->prefix = ' '; 556*56948Smckusick switch(dp->d_type) { 557*56948Smckusick 558*56948Smckusick default: 559*56948Smckusick fprintf(stderr, "Warning: undefined file type %d\n", 560*56948Smckusick dp->d_type); 561*56948Smckusick /* fall through */ 562*56948Smckusick case DT_REG: 563*56948Smckusick fp->postfix = ' '; 564*56948Smckusick break; 565*56948Smckusick 566*56948Smckusick case DT_LNK: 567*56948Smckusick fp->postfix = '@'; 568*56948Smckusick break; 569*56948Smckusick 570*56948Smckusick case DT_FIFO: 571*56948Smckusick case DT_SOCK: 572*56948Smckusick fp->postfix = '='; 573*56948Smckusick break; 574*56948Smckusick 575*56948Smckusick case DT_CHR: 576*56948Smckusick case DT_BLK: 577*56948Smckusick fp->postfix = '#'; 578*56948Smckusick break; 579*56948Smckusick 580*56948Smckusick case DT_UNKNOWN: 581*56948Smckusick case DT_DIR: 582*56948Smckusick if (inodetype(dp->d_ino) == NODE) 583*56948Smckusick fp->postfix = '/'; 584*56948Smckusick else 585*56948Smckusick fp->postfix = ' '; 586*56948Smckusick break; 58717752Smckusick } 588*56948Smckusick return; 58917752Smckusick } 59017752Smckusick 59117752Smckusick /* 59217752Smckusick * Print out a pretty listing of a directory 59317752Smckusick */ 59456567Sbostic static void 595*56948Smckusick formatf(list, nentry) 596*56948Smckusick register struct afile *list; 597*56948Smckusick int nentry; 59817752Smckusick { 599*56948Smckusick register struct afile *fp, *endlist; 600*56948Smckusick int width, bigino, haveprefix, havepostfix; 601*56948Smckusick int i, j, w, precision, columns, lines; 60217752Smckusick 603*56948Smckusick width = 0; 604*56948Smckusick haveprefix = 0; 605*56948Smckusick havepostfix = 0; 606*56948Smckusick bigino = ROOTINO; 607*56948Smckusick endlist = &list[nentry]; 608*56948Smckusick for (fp = &list[0]; fp < endlist; fp++) { 609*56948Smckusick if (bigino < fp->fnum) 610*56948Smckusick bigino = fp->fnum; 611*56948Smckusick if (width < fp->len) 612*56948Smckusick width = fp->len; 613*56948Smckusick if (fp->prefix != ' ') 614*56948Smckusick haveprefix = 1; 615*56948Smckusick if (fp->postfix != ' ') 616*56948Smckusick havepostfix = 1; 61717752Smckusick } 618*56948Smckusick if (haveprefix) 619*56948Smckusick width++; 620*56948Smckusick if (havepostfix) 621*56948Smckusick width++; 622*56948Smckusick if (vflag) { 623*56948Smckusick for (precision = 0, i = bigino; i > 0; i /= 10) 624*56948Smckusick precision++; 625*56948Smckusick width += precision + 1; 626*56948Smckusick } 627*56948Smckusick width++; 628*56948Smckusick 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++) { 634*56948Smckusick fp = &list[j * lines + i]; 635*56948Smckusick if (vflag) { 636*56948Smckusick fprintf(stderr, "%*d ", precision, fp->fnum); 637*56948Smckusick fp->len += precision + 1; 638*56948Smckusick } 639*56948Smckusick if (haveprefix) { 640*56948Smckusick putc(fp->prefix, stderr); 641*56948Smckusick fp->len++; 642*56948Smckusick } 643*56948Smckusick fprintf(stderr, "%s", fp->fname); 644*56948Smckusick if (havepostfix) { 645*56948Smckusick putc(fp->postfix, stderr); 646*56948Smckusick fp->len++; 647*56948Smckusick } 648*56948Smckusick if (fp + lines >= endlist) { 64917752Smckusick fprintf(stderr, "\n"); 65017752Smckusick break; 65117752Smckusick } 652*56948Smckusick for (w = fp->len; w < width; w++) 653*56948Smckusick putc(' ', stderr); 65417752Smckusick } 65517752Smckusick } 65617752Smckusick } 65717752Smckusick 65817752Smckusick /* 659*56948Smckusick * Skip over directory entries that are not on the tape 660*56948Smckusick * 661*56948Smckusick * First have to get definition of a dirent. 66217752Smckusick */ 663*56948Smckusick #undef DIRBLKSIZ 664*56948Smckusick #include <dirent.h> 665*56948Smckusick #undef d_ino 666*56948Smckusick 667*56948Smckusick struct dirent * 668*56948Smckusick glob_readdir(dirp) 669*56948Smckusick RST_DIR *dirp; 67017752Smckusick { 671*56948Smckusick struct direct *dp; 672*56948Smckusick static struct dirent adirent; 673*56948Smckusick 674*56948Smckusick while ((dp = rst_readdir(dirp)) != NULL) { 675*56948Smckusick if (dp->d_ino == 0) 676*56948Smckusick continue; 677*56948Smckusick if (dflag || TSTINO(dp->d_ino, dumpmap)) 678*56948Smckusick break; 679*56948Smckusick } 680*56948Smckusick if (dp == NULL) 681*56948Smckusick return (NULL); 682*56948Smckusick adirent.d_fileno = dp->d_ino; 683*56948Smckusick adirent.d_namlen = dp->d_namlen; 684*56948Smckusick bcopy(dp->d_name, adirent.d_name, dp->d_namlen + 1); 685*56948Smckusick return (&adirent); 68617752Smckusick } 68717752Smckusick 68817752Smckusick /* 689*56948Smckusick * Return st_mode information in response to stat or lstat calls 69017752Smckusick */ 691*56948Smckusick static int 692*56948Smckusick glob_stat(name, stp) 693*56948Smckusick char *name; 694*56948Smckusick struct stat *stp; 69517752Smckusick { 696*56948Smckusick register struct direct *dp; 69717752Smckusick 698*56948Smckusick dp = pathsearch(name); 699*56948Smckusick if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0)) 700*56948Smckusick return (-1); 701*56948Smckusick if (inodetype(dp->d_ino) == NODE) 702*56948Smckusick stp->st_mode = IFDIR; 70317752Smckusick else 704*56948Smckusick stp->st_mode = IFREG; 705*56948Smckusick return (0); 706*56948Smckusick } 70754593Smckusick 708*56948Smckusick /* 709*56948Smckusick * Comparison routine for qsort. 710*56948Smckusick */ 711*56948Smckusick static int 712*56948Smckusick fcmp(f1, f2) 713*56948Smckusick register const void *f1, *f2; 714*56948Smckusick { 715*56948Smckusick return (strcmp(((struct afile *)f1)->fname, 716*56948Smckusick ((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