interactive.c revision 37906
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1985, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 3. All advertising materials mentioning features or use of this software 141558Srgrimes * must display the following acknowledgement: 151558Srgrimes * This product includes software developed by the University of 161558Srgrimes * California, Berkeley and its contributors. 171558Srgrimes * 4. Neither the name of the University nor the names of its contributors 181558Srgrimes * may be used to endorse or promote products derived from this software 191558Srgrimes * without specific prior written permission. 201558Srgrimes * 211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311558Srgrimes * SUCH DAMAGE. 321558Srgrimes */ 331558Srgrimes 341558Srgrimes#ifndef lint 3537906Scharnier#if 0 3623685Speterstatic char sccsid[] = "@(#)interactive.c 8.5 (Berkeley) 5/1/95"; 3737906Scharnier#endif 3837906Scharnierstatic const char rcsid[] = 3937906Scharnier "$Id$"; 401558Srgrimes#endif /* not lint */ 411558Srgrimes 421558Srgrimes#include <sys/param.h> 431558Srgrimes#include <sys/stat.h> 441558Srgrimes 451558Srgrimes#include <ufs/ufs/dinode.h> 461558Srgrimes#include <ufs/ufs/dir.h> 471558Srgrimes#include <protocols/dumprestore.h> 481558Srgrimes 491558Srgrimes#include <setjmp.h> 501558Srgrimes#include <glob.h> 511558Srgrimes#include <stdio.h> 521558Srgrimes#include <stdlib.h> 531558Srgrimes#include <string.h> 541558Srgrimes 551558Srgrimes#include "restore.h" 561558Srgrimes#include "extern.h" 571558Srgrimes 581558Srgrimes#define round(a, b) (((a) + (b) - 1) / (b) * (b)) 591558Srgrimes 601558Srgrimes/* 611558Srgrimes * Things to handle interruptions. 621558Srgrimes */ 631558Srgrimesstatic int runshell; 641558Srgrimesstatic jmp_buf reset; 651558Srgrimesstatic char *nextarg = NULL; 661558Srgrimes 671558Srgrimes/* 681558Srgrimes * Structure and routines associated with listing directories. 691558Srgrimes */ 701558Srgrimesstruct afile { 711558Srgrimes ino_t fnum; /* inode number of file */ 721558Srgrimes char *fname; /* file name */ 731558Srgrimes short len; /* name length */ 741558Srgrimes char prefix; /* prefix character */ 751558Srgrimes char postfix; /* postfix character */ 761558Srgrimes}; 771558Srgrimesstruct arglist { 781558Srgrimes int freeglob; /* glob structure needs to be freed */ 791558Srgrimes int argcnt; /* next globbed argument to return */ 801558Srgrimes glob_t glob; /* globbing information */ 811558Srgrimes char *cmd; /* the current command */ 821558Srgrimes}; 831558Srgrimes 841558Srgrimesstatic char *copynext __P((char *, char *)); 851558Srgrimesstatic int fcmp __P((const void *, const void *)); 861558Srgrimesstatic void formatf __P((struct afile *, int)); 8721997Simpstatic void getcmd __P((char *, char *, char *, int, struct arglist *)); 881558Srgrimesstruct dirent *glob_readdir __P((RST_DIR *dirp)); 891558Srgrimesstatic int glob_stat __P((const char *, struct stat *)); 9023685Speterstatic void mkentry __P((char *, struct direct *, struct afile *)); 911558Srgrimesstatic void printlist __P((char *, char *)); 921558Srgrimes 931558Srgrimes/* 941558Srgrimes * Read and execute commands from the terminal. 951558Srgrimes */ 961558Srgrimesvoid 971558Srgrimesruncmdshell() 981558Srgrimes{ 991558Srgrimes register struct entry *np; 1001558Srgrimes ino_t ino; 1011558Srgrimes struct arglist arglist; 1021558Srgrimes char curdir[MAXPATHLEN]; 1031558Srgrimes char name[MAXPATHLEN]; 1041558Srgrimes char cmd[BUFSIZ]; 1051558Srgrimes 1061558Srgrimes arglist.freeglob = 0; 1071558Srgrimes arglist.argcnt = 0; 1081558Srgrimes arglist.glob.gl_flags = GLOB_ALTDIRFUNC; 1091558Srgrimes arglist.glob.gl_opendir = (void *)rst_opendir; 1101558Srgrimes arglist.glob.gl_readdir = (void *)glob_readdir; 1111558Srgrimes arglist.glob.gl_closedir = (void *)rst_closedir; 1121558Srgrimes arglist.glob.gl_lstat = glob_stat; 1131558Srgrimes arglist.glob.gl_stat = glob_stat; 11421174Sguido canon("/", curdir, sizeof(curdir)); 1151558Srgrimesloop: 1161558Srgrimes if (setjmp(reset) != 0) { 1171558Srgrimes if (arglist.freeglob != 0) { 1181558Srgrimes arglist.freeglob = 0; 1191558Srgrimes arglist.argcnt = 0; 1201558Srgrimes globfree(&arglist.glob); 1211558Srgrimes } 1221558Srgrimes nextarg = NULL; 1231558Srgrimes volno = 0; 1241558Srgrimes } 1251558Srgrimes runshell = 1; 12621997Simp getcmd(curdir, cmd, name, sizeof(name), &arglist); 1271558Srgrimes switch (cmd[0]) { 1281558Srgrimes /* 1291558Srgrimes * Add elements to the extraction list. 1301558Srgrimes */ 1311558Srgrimes case 'a': 1321558Srgrimes if (strncmp(cmd, "add", strlen(cmd)) != 0) 1331558Srgrimes goto bad; 1341558Srgrimes ino = dirlookup(name); 1351558Srgrimes if (ino == 0) 1361558Srgrimes break; 1371558Srgrimes if (mflag) 1381558Srgrimes pathcheck(name); 1391558Srgrimes treescan(name, ino, addfile); 1401558Srgrimes break; 1411558Srgrimes /* 1421558Srgrimes * Change working directory. 1431558Srgrimes */ 1441558Srgrimes case 'c': 1451558Srgrimes if (strncmp(cmd, "cd", strlen(cmd)) != 0) 1461558Srgrimes goto bad; 1471558Srgrimes ino = dirlookup(name); 1481558Srgrimes if (ino == 0) 1491558Srgrimes break; 1501558Srgrimes if (inodetype(ino) == LEAF) { 1511558Srgrimes fprintf(stderr, "%s: not a directory\n", name); 1521558Srgrimes break; 1531558Srgrimes } 1541558Srgrimes (void) strcpy(curdir, name); 1551558Srgrimes break; 1561558Srgrimes /* 1571558Srgrimes * Delete elements from the extraction list. 1581558Srgrimes */ 1591558Srgrimes case 'd': 1601558Srgrimes if (strncmp(cmd, "delete", strlen(cmd)) != 0) 1611558Srgrimes goto bad; 1621558Srgrimes np = lookupname(name); 1631558Srgrimes if (np == NULL || (np->e_flags & NEW) == 0) { 1641558Srgrimes fprintf(stderr, "%s: not on extraction list\n", name); 1651558Srgrimes break; 1661558Srgrimes } 1671558Srgrimes treescan(name, np->e_ino, deletefile); 1681558Srgrimes break; 1691558Srgrimes /* 1701558Srgrimes * Extract the requested list. 1711558Srgrimes */ 1721558Srgrimes case 'e': 1731558Srgrimes if (strncmp(cmd, "extract", strlen(cmd)) != 0) 1741558Srgrimes goto bad; 1751558Srgrimes createfiles(); 1761558Srgrimes createlinks(); 1771558Srgrimes setdirmodes(0); 1781558Srgrimes if (dflag) 1791558Srgrimes checkrestore(); 1801558Srgrimes volno = 0; 1811558Srgrimes break; 1821558Srgrimes /* 1831558Srgrimes * List available commands. 1841558Srgrimes */ 1851558Srgrimes case 'h': 1861558Srgrimes if (strncmp(cmd, "help", strlen(cmd)) != 0) 1871558Srgrimes goto bad; 1881558Srgrimes case '?': 1891558Srgrimes fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 1901558Srgrimes "Available commands are:\n", 1911558Srgrimes "\tls [arg] - list directory\n", 1921558Srgrimes "\tcd arg - change directory\n", 1931558Srgrimes "\tpwd - print current directory\n", 1941558Srgrimes "\tadd [arg] - add `arg' to list of", 1951558Srgrimes " files to be extracted\n", 1961558Srgrimes "\tdelete [arg] - delete `arg' from", 1971558Srgrimes " list of files to be extracted\n", 1981558Srgrimes "\textract - extract requested files\n", 1991558Srgrimes "\tsetmodes - set modes of requested directories\n", 2001558Srgrimes "\tquit - immediately exit program\n", 2011558Srgrimes "\twhat - list dump header information\n", 2021558Srgrimes "\tverbose - toggle verbose flag", 2031558Srgrimes " (useful with ``ls'')\n", 2041558Srgrimes "\thelp or `?' - print this list\n", 2051558Srgrimes "If no `arg' is supplied, the current", 2061558Srgrimes " directory is used\n"); 2071558Srgrimes break; 2081558Srgrimes /* 2091558Srgrimes * List a directory. 2101558Srgrimes */ 2111558Srgrimes case 'l': 2121558Srgrimes if (strncmp(cmd, "ls", strlen(cmd)) != 0) 2131558Srgrimes goto bad; 2141558Srgrimes printlist(name, curdir); 2151558Srgrimes break; 2161558Srgrimes /* 2171558Srgrimes * Print current directory. 2181558Srgrimes */ 2191558Srgrimes case 'p': 2201558Srgrimes if (strncmp(cmd, "pwd", strlen(cmd)) != 0) 2211558Srgrimes goto bad; 2221558Srgrimes if (curdir[1] == '\0') 2231558Srgrimes fprintf(stderr, "/\n"); 2241558Srgrimes else 2251558Srgrimes fprintf(stderr, "%s\n", &curdir[1]); 2261558Srgrimes break; 2271558Srgrimes /* 2281558Srgrimes * Quit. 2291558Srgrimes */ 2301558Srgrimes case 'q': 2311558Srgrimes if (strncmp(cmd, "quit", strlen(cmd)) != 0) 2321558Srgrimes goto bad; 2331558Srgrimes return; 2341558Srgrimes case 'x': 2351558Srgrimes if (strncmp(cmd, "xit", strlen(cmd)) != 0) 2361558Srgrimes goto bad; 2371558Srgrimes return; 2381558Srgrimes /* 2391558Srgrimes * Toggle verbose mode. 2401558Srgrimes */ 2411558Srgrimes case 'v': 2421558Srgrimes if (strncmp(cmd, "verbose", strlen(cmd)) != 0) 2431558Srgrimes goto bad; 2441558Srgrimes if (vflag) { 2451558Srgrimes fprintf(stderr, "verbose mode off\n"); 2461558Srgrimes vflag = 0; 2471558Srgrimes break; 2481558Srgrimes } 2491558Srgrimes fprintf(stderr, "verbose mode on\n"); 2501558Srgrimes vflag++; 2511558Srgrimes break; 2521558Srgrimes /* 2531558Srgrimes * Just restore requested directory modes. 2541558Srgrimes */ 2551558Srgrimes case 's': 2561558Srgrimes if (strncmp(cmd, "setmodes", strlen(cmd)) != 0) 2571558Srgrimes goto bad; 2581558Srgrimes setdirmodes(FORCE); 2591558Srgrimes break; 2601558Srgrimes /* 2611558Srgrimes * Print out dump header information. 2621558Srgrimes */ 2631558Srgrimes case 'w': 2641558Srgrimes if (strncmp(cmd, "what", strlen(cmd)) != 0) 2651558Srgrimes goto bad; 2661558Srgrimes printdumpinfo(); 2671558Srgrimes break; 2681558Srgrimes /* 2691558Srgrimes * Turn on debugging. 2701558Srgrimes */ 2711558Srgrimes case 'D': 2721558Srgrimes if (strncmp(cmd, "Debug", strlen(cmd)) != 0) 2731558Srgrimes goto bad; 2741558Srgrimes if (dflag) { 2751558Srgrimes fprintf(stderr, "debugging mode off\n"); 2761558Srgrimes dflag = 0; 2771558Srgrimes break; 2781558Srgrimes } 2791558Srgrimes fprintf(stderr, "debugging mode on\n"); 2801558Srgrimes dflag++; 2811558Srgrimes break; 2821558Srgrimes /* 2831558Srgrimes * Unknown command. 2841558Srgrimes */ 2851558Srgrimes default: 2861558Srgrimes bad: 2871558Srgrimes fprintf(stderr, "%s: unknown command; type ? for help\n", cmd); 2881558Srgrimes break; 2891558Srgrimes } 2901558Srgrimes goto loop; 2911558Srgrimes} 2921558Srgrimes 2931558Srgrimes/* 2941558Srgrimes * Read and parse an interactive command. 2951558Srgrimes * The first word on the line is assigned to "cmd". If 2961558Srgrimes * there are no arguments on the command line, then "curdir" 2971558Srgrimes * is returned as the argument. If there are arguments 2981558Srgrimes * on the line they are returned one at a time on each 2991558Srgrimes * successive call to getcmd. Each argument is first assigned 3001558Srgrimes * to "name". If it does not start with "/" the pathname in 3011558Srgrimes * "curdir" is prepended to it. Finally "canon" is called to 3021558Srgrimes * eliminate any embedded ".." components. 3031558Srgrimes */ 3041558Srgrimesstatic void 30521997Simpgetcmd(curdir, cmd, name, size, ap) 3061558Srgrimes char *curdir, *cmd, *name; 3071558Srgrimes struct arglist *ap; 30821997Simp int size; 3091558Srgrimes{ 3101558Srgrimes register char *cp; 3111558Srgrimes static char input[BUFSIZ]; 3121558Srgrimes char output[BUFSIZ]; 3131558Srgrimes# define rawname input /* save space by reusing input buffer */ 3141558Srgrimes 3151558Srgrimes /* 3161558Srgrimes * Check to see if still processing arguments. 3171558Srgrimes */ 3181558Srgrimes if (ap->argcnt > 0) 3191558Srgrimes goto retnext; 3201558Srgrimes if (nextarg != NULL) 3211558Srgrimes goto getnext; 3221558Srgrimes /* 3231558Srgrimes * Read a command line and trim off trailing white space. 3241558Srgrimes */ 3251558Srgrimes do { 3261558Srgrimes fprintf(stderr, "restore > "); 3271558Srgrimes (void) fflush(stderr); 3281558Srgrimes (void) fgets(input, BUFSIZ, terminal); 3291558Srgrimes } while (!feof(terminal) && input[0] == '\n'); 3301558Srgrimes if (feof(terminal)) { 3311558Srgrimes (void) strcpy(cmd, "quit"); 3321558Srgrimes return; 3331558Srgrimes } 3341558Srgrimes for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--) 3351558Srgrimes /* trim off trailing white space and newline */; 3361558Srgrimes *++cp = '\0'; 3371558Srgrimes /* 3381558Srgrimes * Copy the command into "cmd". 3391558Srgrimes */ 3401558Srgrimes cp = copynext(input, cmd); 3411558Srgrimes ap->cmd = cmd; 3421558Srgrimes /* 3431558Srgrimes * If no argument, use curdir as the default. 3441558Srgrimes */ 3451558Srgrimes if (*cp == '\0') { 3461558Srgrimes (void) strcpy(name, curdir); 3471558Srgrimes return; 3481558Srgrimes } 3491558Srgrimes nextarg = cp; 3501558Srgrimes /* 3511558Srgrimes * Find the next argument. 3521558Srgrimes */ 3531558Srgrimesgetnext: 3541558Srgrimes cp = copynext(nextarg, rawname); 3551558Srgrimes if (*cp == '\0') 3561558Srgrimes nextarg = NULL; 3571558Srgrimes else 3581558Srgrimes nextarg = cp; 3591558Srgrimes /* 3601558Srgrimes * If it is an absolute pathname, canonicalize it and return it. 3611558Srgrimes */ 3621558Srgrimes if (rawname[0] == '/') { 36321997Simp canon(rawname, name, size); 3641558Srgrimes } else { 3651558Srgrimes /* 3661558Srgrimes * For relative pathnames, prepend the current directory to 3671558Srgrimes * it then canonicalize and return it. 3681558Srgrimes */ 3691558Srgrimes (void) strcpy(output, curdir); 3701558Srgrimes (void) strcat(output, "/"); 3711558Srgrimes (void) strcat(output, rawname); 37221997Simp canon(output, name, size); 3731558Srgrimes } 3741558Srgrimes if (glob(name, GLOB_ALTDIRFUNC, NULL, &ap->glob) < 0) 3751558Srgrimes fprintf(stderr, "%s: out of memory\n", ap->cmd); 3761558Srgrimes if (ap->glob.gl_pathc == 0) 3771558Srgrimes return; 3781558Srgrimes ap->freeglob = 1; 3791558Srgrimes ap->argcnt = ap->glob.gl_pathc; 3801558Srgrimes 3811558Srgrimesretnext: 3821558Srgrimes strcpy(name, ap->glob.gl_pathv[ap->glob.gl_pathc - ap->argcnt]); 3831558Srgrimes if (--ap->argcnt == 0) { 3841558Srgrimes ap->freeglob = 0; 3851558Srgrimes globfree(&ap->glob); 3861558Srgrimes } 3871558Srgrimes# undef rawname 3881558Srgrimes} 3891558Srgrimes 3901558Srgrimes/* 3911558Srgrimes * Strip off the next token of the input. 3921558Srgrimes */ 3931558Srgrimesstatic char * 3941558Srgrimescopynext(input, output) 3951558Srgrimes char *input, *output; 3961558Srgrimes{ 3971558Srgrimes register char *cp, *bp; 3981558Srgrimes char quote; 3991558Srgrimes 4001558Srgrimes for (cp = input; *cp == ' ' || *cp == '\t'; cp++) 4011558Srgrimes /* skip to argument */; 4021558Srgrimes bp = output; 4031558Srgrimes while (*cp != ' ' && *cp != '\t' && *cp != '\0') { 4041558Srgrimes /* 4051558Srgrimes * Handle back slashes. 4061558Srgrimes */ 4071558Srgrimes if (*cp == '\\') { 4081558Srgrimes if (*++cp == '\0') { 4091558Srgrimes fprintf(stderr, 4101558Srgrimes "command lines cannot be continued\n"); 4111558Srgrimes continue; 4121558Srgrimes } 4131558Srgrimes *bp++ = *cp++; 4141558Srgrimes continue; 4151558Srgrimes } 4161558Srgrimes /* 4171558Srgrimes * The usual unquoted case. 4181558Srgrimes */ 4191558Srgrimes if (*cp != '\'' && *cp != '"') { 4201558Srgrimes *bp++ = *cp++; 4211558Srgrimes continue; 4221558Srgrimes } 4231558Srgrimes /* 4241558Srgrimes * Handle single and double quotes. 4251558Srgrimes */ 4261558Srgrimes quote = *cp++; 4271558Srgrimes while (*cp != quote && *cp != '\0') 4281558Srgrimes *bp++ = *cp++ | 0200; 4291558Srgrimes if (*cp++ == '\0') { 4301558Srgrimes fprintf(stderr, "missing %c\n", quote); 4311558Srgrimes cp--; 4321558Srgrimes continue; 4331558Srgrimes } 4341558Srgrimes } 4351558Srgrimes *bp = '\0'; 4361558Srgrimes return (cp); 4371558Srgrimes} 4381558Srgrimes 4391558Srgrimes/* 4401558Srgrimes * Canonicalize file names to always start with ``./'' and 44137906Scharnier * remove any embedded "." and ".." components. 4421558Srgrimes */ 4431558Srgrimesvoid 44421174Sguidocanon(rawname, canonname, len) 4451558Srgrimes char *rawname, *canonname; 44621174Sguido int len; 4471558Srgrimes{ 4481558Srgrimes register char *cp, *np; 4491558Srgrimes 4501558Srgrimes if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0) 4511558Srgrimes (void) strcpy(canonname, ""); 4521558Srgrimes else if (rawname[0] == '/') 4531558Srgrimes (void) strcpy(canonname, "."); 4541558Srgrimes else 4551558Srgrimes (void) strcpy(canonname, "./"); 45621174Sguido if (strlen(canonname) + strlen(rawname) >= len) { 45737906Scharnier fprintf(stderr, "canonname: not enough buffer space\n"); 45821174Sguido done(1); 45921174Sguido } 46021174Sguido 4611558Srgrimes (void) strcat(canonname, rawname); 4621558Srgrimes /* 4631558Srgrimes * Eliminate multiple and trailing '/'s 4641558Srgrimes */ 4651558Srgrimes for (cp = np = canonname; *np != '\0'; cp++) { 4661558Srgrimes *cp = *np++; 4671558Srgrimes while (*cp == '/' && *np == '/') 4681558Srgrimes np++; 4691558Srgrimes } 4701558Srgrimes *cp = '\0'; 4711558Srgrimes if (*--cp == '/') 4721558Srgrimes *cp = '\0'; 4731558Srgrimes /* 4741558Srgrimes * Eliminate extraneous "." and ".." from pathnames. 4751558Srgrimes */ 4761558Srgrimes for (np = canonname; *np != '\0'; ) { 4771558Srgrimes np++; 4781558Srgrimes cp = np; 4791558Srgrimes while (*np != '/' && *np != '\0') 4801558Srgrimes np++; 4811558Srgrimes if (np - cp == 1 && *cp == '.') { 4821558Srgrimes cp--; 4831558Srgrimes (void) strcpy(cp, np); 4841558Srgrimes np = cp; 4851558Srgrimes } 4861558Srgrimes if (np - cp == 2 && strncmp(cp, "..", 2) == 0) { 4871558Srgrimes cp--; 4881558Srgrimes while (cp > &canonname[1] && *--cp != '/') 4891558Srgrimes /* find beginning of name */; 4901558Srgrimes (void) strcpy(cp, np); 4911558Srgrimes np = cp; 4921558Srgrimes } 4931558Srgrimes } 4941558Srgrimes} 4951558Srgrimes 4961558Srgrimes/* 4971558Srgrimes * Do an "ls" style listing of a directory 4981558Srgrimes */ 4991558Srgrimesstatic void 5001558Srgrimesprintlist(name, basename) 5011558Srgrimes char *name; 5021558Srgrimes char *basename; 5031558Srgrimes{ 5041558Srgrimes register struct afile *fp, *list, *listp; 5051558Srgrimes register struct direct *dp; 5061558Srgrimes struct afile single; 5071558Srgrimes RST_DIR *dirp; 50823685Speter int entries, len, namelen; 50923685Speter char locname[MAXPATHLEN + 1]; 5101558Srgrimes 5111558Srgrimes dp = pathsearch(name); 51223685Speter if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) || 51323685Speter (!vflag && dp->d_ino == WINO)) 5141558Srgrimes return; 5151558Srgrimes if ((dirp = rst_opendir(name)) == NULL) { 5161558Srgrimes entries = 1; 5171558Srgrimes list = &single; 51823685Speter mkentry(name, dp, list); 5191558Srgrimes len = strlen(basename) + 1; 5201558Srgrimes if (strlen(name) - len > single.len) { 5211558Srgrimes freename(single.fname); 5221558Srgrimes single.fname = savename(&name[len]); 5231558Srgrimes single.len = strlen(single.fname); 5241558Srgrimes } 5251558Srgrimes } else { 5261558Srgrimes entries = 0; 52737906Scharnier while ((dp = rst_readdir(dirp))) 5281558Srgrimes entries++; 5291558Srgrimes rst_closedir(dirp); 5301558Srgrimes list = (struct afile *)malloc(entries * sizeof(struct afile)); 5311558Srgrimes if (list == NULL) { 5321558Srgrimes fprintf(stderr, "ls: out of memory\n"); 5331558Srgrimes return; 5341558Srgrimes } 5351558Srgrimes if ((dirp = rst_opendir(name)) == NULL) 5361558Srgrimes panic("directory reopen failed\n"); 5371558Srgrimes fprintf(stderr, "%s:\n", name); 5381558Srgrimes entries = 0; 5391558Srgrimes listp = list; 54023685Speter (void) strncpy(locname, name, MAXPATHLEN); 54123685Speter (void) strncat(locname, "/", MAXPATHLEN); 54223685Speter namelen = strlen(locname); 54337906Scharnier while ((dp = rst_readdir(dirp))) { 54423685Speter if (dp == NULL) 5451558Srgrimes break; 5461558Srgrimes if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) 5471558Srgrimes continue; 54823685Speter if (!vflag && (dp->d_ino == WINO || 54923685Speter strcmp(dp->d_name, ".") == 0 || 5501558Srgrimes strcmp(dp->d_name, "..") == 0)) 5511558Srgrimes continue; 55223685Speter locname[namelen] = '\0'; 55323685Speter if (namelen + dp->d_namlen >= MAXPATHLEN) { 55423685Speter fprintf(stderr, "%s%s: name exceeds %d char\n", 55523685Speter locname, dp->d_name, MAXPATHLEN); 55623685Speter } else { 55723685Speter (void) strncat(locname, dp->d_name, 55823685Speter (int)dp->d_namlen); 55923685Speter mkentry(locname, dp, listp++); 56023685Speter entries++; 56123685Speter } 5621558Srgrimes } 5631558Srgrimes rst_closedir(dirp); 5641558Srgrimes if (entries == 0) { 5651558Srgrimes fprintf(stderr, "\n"); 5661558Srgrimes free(list); 5671558Srgrimes return; 5681558Srgrimes } 5691558Srgrimes qsort((char *)list, entries, sizeof(struct afile), fcmp); 5701558Srgrimes } 5711558Srgrimes formatf(list, entries); 5721558Srgrimes if (dirp != NULL) { 5731558Srgrimes for (fp = listp - 1; fp >= list; fp--) 5741558Srgrimes freename(fp->fname); 5751558Srgrimes fprintf(stderr, "\n"); 5761558Srgrimes free(list); 5771558Srgrimes } 5781558Srgrimes} 5791558Srgrimes 5801558Srgrimes/* 5811558Srgrimes * Read the contents of a directory. 5821558Srgrimes */ 5831558Srgrimesstatic void 58423685Spetermkentry(name, dp, fp) 58523685Speter char *name; 5861558Srgrimes struct direct *dp; 5871558Srgrimes register struct afile *fp; 5881558Srgrimes{ 5891558Srgrimes char *cp; 5901558Srgrimes struct entry *np; 5911558Srgrimes 5921558Srgrimes fp->fnum = dp->d_ino; 5931558Srgrimes fp->fname = savename(dp->d_name); 5941558Srgrimes for (cp = fp->fname; *cp; cp++) 5951558Srgrimes if (!vflag && (*cp < ' ' || *cp >= 0177)) 5961558Srgrimes *cp = '?'; 5971558Srgrimes fp->len = cp - fp->fname; 5981558Srgrimes if (dflag && TSTINO(fp->fnum, dumpmap) == 0) 5991558Srgrimes fp->prefix = '^'; 60023685Speter else if ((np = lookupname(name)) != NULL && (np->e_flags & NEW)) 6011558Srgrimes fp->prefix = '*'; 6021558Srgrimes else 6031558Srgrimes fp->prefix = ' '; 6041558Srgrimes switch(dp->d_type) { 6051558Srgrimes 6061558Srgrimes default: 6071558Srgrimes fprintf(stderr, "Warning: undefined file type %d\n", 6081558Srgrimes dp->d_type); 6091558Srgrimes /* fall through */ 6101558Srgrimes case DT_REG: 6111558Srgrimes fp->postfix = ' '; 6121558Srgrimes break; 6131558Srgrimes 6141558Srgrimes case DT_LNK: 6151558Srgrimes fp->postfix = '@'; 6161558Srgrimes break; 6171558Srgrimes 6181558Srgrimes case DT_FIFO: 6191558Srgrimes case DT_SOCK: 6201558Srgrimes fp->postfix = '='; 6211558Srgrimes break; 6221558Srgrimes 6231558Srgrimes case DT_CHR: 6241558Srgrimes case DT_BLK: 6251558Srgrimes fp->postfix = '#'; 6261558Srgrimes break; 6271558Srgrimes 62823685Speter case DT_WHT: 62923685Speter fp->postfix = '%'; 63023685Speter break; 63123685Speter 6321558Srgrimes case DT_UNKNOWN: 6331558Srgrimes case DT_DIR: 6341558Srgrimes if (inodetype(dp->d_ino) == NODE) 6351558Srgrimes fp->postfix = '/'; 6361558Srgrimes else 6371558Srgrimes fp->postfix = ' '; 6381558Srgrimes break; 6391558Srgrimes } 6401558Srgrimes return; 6411558Srgrimes} 6421558Srgrimes 6431558Srgrimes/* 6441558Srgrimes * Print out a pretty listing of a directory 6451558Srgrimes */ 6461558Srgrimesstatic void 6471558Srgrimesformatf(list, nentry) 6481558Srgrimes register struct afile *list; 6491558Srgrimes int nentry; 6501558Srgrimes{ 6511558Srgrimes register struct afile *fp, *endlist; 6521558Srgrimes int width, bigino, haveprefix, havepostfix; 6531558Srgrimes int i, j, w, precision, columns, lines; 6541558Srgrimes 6551558Srgrimes width = 0; 6561558Srgrimes haveprefix = 0; 6571558Srgrimes havepostfix = 0; 6581558Srgrimes bigino = ROOTINO; 6591558Srgrimes endlist = &list[nentry]; 6601558Srgrimes for (fp = &list[0]; fp < endlist; fp++) { 6611558Srgrimes if (bigino < fp->fnum) 6621558Srgrimes bigino = fp->fnum; 6631558Srgrimes if (width < fp->len) 6641558Srgrimes width = fp->len; 6651558Srgrimes if (fp->prefix != ' ') 6661558Srgrimes haveprefix = 1; 6671558Srgrimes if (fp->postfix != ' ') 6681558Srgrimes havepostfix = 1; 6691558Srgrimes } 6701558Srgrimes if (haveprefix) 6711558Srgrimes width++; 6721558Srgrimes if (havepostfix) 6731558Srgrimes width++; 6741558Srgrimes if (vflag) { 6751558Srgrimes for (precision = 0, i = bigino; i > 0; i /= 10) 6761558Srgrimes precision++; 6771558Srgrimes width += precision + 1; 6781558Srgrimes } 6791558Srgrimes width++; 6801558Srgrimes columns = 81 / width; 6811558Srgrimes if (columns == 0) 6821558Srgrimes columns = 1; 6831558Srgrimes lines = (nentry + columns - 1) / columns; 6841558Srgrimes for (i = 0; i < lines; i++) { 6851558Srgrimes for (j = 0; j < columns; j++) { 6861558Srgrimes fp = &list[j * lines + i]; 6871558Srgrimes if (vflag) { 6881558Srgrimes fprintf(stderr, "%*d ", precision, fp->fnum); 6891558Srgrimes fp->len += precision + 1; 6901558Srgrimes } 6911558Srgrimes if (haveprefix) { 6921558Srgrimes putc(fp->prefix, stderr); 6931558Srgrimes fp->len++; 6941558Srgrimes } 6951558Srgrimes fprintf(stderr, "%s", fp->fname); 6961558Srgrimes if (havepostfix) { 6971558Srgrimes putc(fp->postfix, stderr); 6981558Srgrimes fp->len++; 6991558Srgrimes } 7001558Srgrimes if (fp + lines >= endlist) { 7011558Srgrimes fprintf(stderr, "\n"); 7021558Srgrimes break; 7031558Srgrimes } 7041558Srgrimes for (w = fp->len; w < width; w++) 7051558Srgrimes putc(' ', stderr); 7061558Srgrimes } 7071558Srgrimes } 7081558Srgrimes} 7091558Srgrimes 7101558Srgrimes/* 7111558Srgrimes * Skip over directory entries that are not on the tape 7121558Srgrimes * 7131558Srgrimes * First have to get definition of a dirent. 7141558Srgrimes */ 7151558Srgrimes#undef DIRBLKSIZ 7161558Srgrimes#include <dirent.h> 7171558Srgrimes#undef d_ino 7181558Srgrimes 7191558Srgrimesstruct dirent * 7201558Srgrimesglob_readdir(dirp) 7211558Srgrimes RST_DIR *dirp; 7221558Srgrimes{ 7231558Srgrimes struct direct *dp; 7241558Srgrimes static struct dirent adirent; 7251558Srgrimes 7261558Srgrimes while ((dp = rst_readdir(dirp)) != NULL) { 72723685Speter if (!vflag && dp->d_ino == WINO) 7281558Srgrimes continue; 7291558Srgrimes if (dflag || TSTINO(dp->d_ino, dumpmap)) 7301558Srgrimes break; 7311558Srgrimes } 7321558Srgrimes if (dp == NULL) 7331558Srgrimes return (NULL); 7341558Srgrimes adirent.d_fileno = dp->d_ino; 7351558Srgrimes adirent.d_namlen = dp->d_namlen; 73623685Speter memmove(adirent.d_name, dp->d_name, dp->d_namlen + 1); 7371558Srgrimes return (&adirent); 7381558Srgrimes} 7391558Srgrimes 7401558Srgrimes/* 7411558Srgrimes * Return st_mode information in response to stat or lstat calls 7421558Srgrimes */ 7431558Srgrimesstatic int 7441558Srgrimesglob_stat(name, stp) 7451558Srgrimes const char *name; 7461558Srgrimes struct stat *stp; 7471558Srgrimes{ 7481558Srgrimes register struct direct *dp; 7491558Srgrimes 7501558Srgrimes dp = pathsearch(name); 75123685Speter if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) || 75223685Speter (!vflag && dp->d_ino == WINO)) 7531558Srgrimes return (-1); 7541558Srgrimes if (inodetype(dp->d_ino) == NODE) 7551558Srgrimes stp->st_mode = IFDIR; 7561558Srgrimes else 7571558Srgrimes stp->st_mode = IFREG; 7581558Srgrimes return (0); 7591558Srgrimes} 7601558Srgrimes 7611558Srgrimes/* 7621558Srgrimes * Comparison routine for qsort. 7631558Srgrimes */ 7641558Srgrimesstatic int 7651558Srgrimesfcmp(f1, f2) 7661558Srgrimes register const void *f1, *f2; 7671558Srgrimes{ 7681558Srgrimes return (strcmp(((struct afile *)f1)->fname, 7691558Srgrimes ((struct afile *)f2)->fname)); 7701558Srgrimes} 7711558Srgrimes 7721558Srgrimes/* 7731558Srgrimes * respond to interrupts 7741558Srgrimes */ 7751558Srgrimesvoid 7761558Srgrimesonintr(signo) 7771558Srgrimes int signo; 7781558Srgrimes{ 7791558Srgrimes if (command == 'i' && runshell) 7801558Srgrimes longjmp(reset, 1); 7811558Srgrimes if (reply("restore interrupted, continue") == FAIL) 7821558Srgrimes done(1); 7831558Srgrimes} 784