121166Sdist /* 236105Sbostic * Copyright (c) 1985 The Regents of the University of California. 336105Sbostic * All rights reserved. 436105Sbostic * 536105Sbostic * Redistribution and use in source and binary forms are permitted 636105Sbostic * provided that the above copyright notice and this paragraph are 736105Sbostic * duplicated in all such forms and that any documentation, 836105Sbostic * advertising materials, and other materials related to such 936105Sbostic * distribution and use acknowledge that the software was developed 1036105Sbostic * by the University of California, Berkeley. The name of the 1136105Sbostic * University may not be used to endorse or promote products derived 1236105Sbostic * from this software without specific prior written permission. 1336105Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1436105Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1536105Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621166Sdist */ 1717752Smckusick 1817752Smckusick #ifndef lint 19*39942Sbostic static char sccsid[] = "@(#)interactive.c 5.7 (Berkeley) 01/19/90"; 2036105Sbostic #endif /* not lint */ 2117752Smckusick 2217752Smckusick #include "restore.h" 2323546Smckusick #include <protocols/dumprestore.h> 2417752Smckusick #include <setjmp.h> 2517752Smckusick 2617756Smckusick #define round(a, b) (((a) + (b) - 1) / (b) * (b)) 2717756Smckusick 2817752Smckusick /* 2917752Smckusick * Things to handle interruptions. 3017752Smckusick */ 3117752Smckusick static jmp_buf reset; 3217752Smckusick static char *nextarg = NULL; 3317752Smckusick 3417752Smckusick /* 3517752Smckusick * Structure and routines associated with listing directories. 3617752Smckusick */ 3717752Smckusick struct afile { 3817752Smckusick ino_t fnum; /* inode number of file */ 3917752Smckusick char *fname; /* file name */ 4017752Smckusick short fflags; /* extraction flags, if any */ 4117752Smckusick char ftype; /* file type, e.g. LEAF or NODE */ 4217752Smckusick }; 4318003Smckusick struct arglist { 4418003Smckusick struct afile *head; /* start of argument list */ 4518003Smckusick struct afile *last; /* end of argument list */ 4618003Smckusick struct afile *base; /* current list arena */ 4718003Smckusick int nent; /* maximum size of list */ 4818003Smckusick char *cmd; /* the current command */ 4918003Smckusick }; 5017752Smckusick extern int fcmp(); 5117752Smckusick extern char *fmtentry(); 5217752Smckusick char *copynext(); 5317752Smckusick 5417752Smckusick /* 5517752Smckusick * Read and execute commands from the terminal. 5617752Smckusick */ 5717752Smckusick runcmdshell() 5817752Smckusick { 5917752Smckusick register struct entry *np; 6017752Smckusick ino_t ino; 6118003Smckusick static struct arglist alist = { 0, 0, 0, 0, 0 }; 6217752Smckusick char curdir[MAXPATHLEN]; 6317752Smckusick char name[MAXPATHLEN]; 6417752Smckusick char cmd[BUFSIZ]; 6517752Smckusick 6617752Smckusick canon("/", curdir); 6717752Smckusick loop: 6817752Smckusick if (setjmp(reset) != 0) { 6918003Smckusick for (; alist.head < alist.last; alist.head++) 7018003Smckusick freename(alist.head->fname); 7117752Smckusick nextarg = NULL; 7217752Smckusick volno = 0; 7317752Smckusick } 7418003Smckusick getcmd(curdir, cmd, name, &alist); 7517752Smckusick switch (cmd[0]) { 7617752Smckusick /* 7717752Smckusick * Add elements to the extraction list. 7817752Smckusick */ 7917752Smckusick case 'a': 8029903Smckusick if (strncmp(cmd, "add", strlen(cmd)) != 0) 8129903Smckusick goto bad; 8217752Smckusick ino = dirlookup(name); 8317752Smckusick if (ino == 0) 8417752Smckusick break; 8517752Smckusick if (mflag) 8617752Smckusick pathcheck(name); 8717752Smckusick treescan(name, ino, addfile); 8817752Smckusick break; 8917752Smckusick /* 9017752Smckusick * Change working directory. 9117752Smckusick */ 9217752Smckusick case 'c': 9329903Smckusick if (strncmp(cmd, "cd", strlen(cmd)) != 0) 9429903Smckusick goto bad; 9517752Smckusick ino = dirlookup(name); 9617752Smckusick if (ino == 0) 9717752Smckusick break; 9817752Smckusick if (inodetype(ino) == LEAF) { 9917752Smckusick fprintf(stderr, "%s: not a directory\n", name); 10017752Smckusick break; 10117752Smckusick } 10217752Smckusick (void) strcpy(curdir, name); 10317752Smckusick break; 10417752Smckusick /* 10517752Smckusick * Delete elements from the extraction list. 10617752Smckusick */ 10717752Smckusick case 'd': 10829903Smckusick if (strncmp(cmd, "delete", strlen(cmd)) != 0) 10929903Smckusick goto bad; 11017752Smckusick np = lookupname(name); 11117752Smckusick if (np == NIL || (np->e_flags & NEW) == 0) { 11217752Smckusick fprintf(stderr, "%s: not on extraction list\n", name); 11317752Smckusick break; 11417752Smckusick } 11517752Smckusick treescan(name, np->e_ino, deletefile); 11617752Smckusick break; 11717752Smckusick /* 11817752Smckusick * Extract the requested list. 11917752Smckusick */ 12017752Smckusick case 'e': 12129903Smckusick if (strncmp(cmd, "extract", strlen(cmd)) != 0) 12229903Smckusick goto bad; 12317752Smckusick createfiles(); 12417752Smckusick createlinks(); 12517752Smckusick setdirmodes(); 12617752Smckusick if (dflag) 12717752Smckusick checkrestore(); 12817752Smckusick volno = 0; 12917752Smckusick break; 13017752Smckusick /* 13117752Smckusick * List available commands. 13217752Smckusick */ 13317752Smckusick case 'h': 13429903Smckusick if (strncmp(cmd, "help", strlen(cmd)) != 0) 13529903Smckusick goto bad; 13617752Smckusick case '?': 13729903Smckusick fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 13817752Smckusick "Available commands are:\n", 13917752Smckusick "\tls [arg] - list directory\n", 14017752Smckusick "\tcd arg - change directory\n", 14117752Smckusick "\tpwd - print current directory\n", 14217752Smckusick "\tadd [arg] - add `arg' to list of", 14317752Smckusick " files to be extracted\n", 14417752Smckusick "\tdelete [arg] - delete `arg' from", 14517752Smckusick " list of files to be extracted\n", 14617752Smckusick "\textract - extract requested files\n", 14721096Smckusick "\tsetmodes - set modes of requested directories\n", 14817752Smckusick "\tquit - immediately exit program\n", 14929903Smckusick "\twhat - list dump header information\n", 15017752Smckusick "\tverbose - toggle verbose flag", 15117752Smckusick " (useful with ``ls'')\n", 15217752Smckusick "\thelp or `?' - print this list\n", 15317752Smckusick "If no `arg' is supplied, the current", 15417752Smckusick " directory is used\n"); 15517752Smckusick break; 15617752Smckusick /* 15717752Smckusick * List a directory. 15817752Smckusick */ 15917752Smckusick case 'l': 16029903Smckusick if (strncmp(cmd, "ls", strlen(cmd)) != 0) 16129903Smckusick goto bad; 16217752Smckusick ino = dirlookup(name); 16317752Smckusick if (ino == 0) 16417752Smckusick break; 16517752Smckusick printlist(name, ino, curdir); 16617752Smckusick break; 16717752Smckusick /* 16817752Smckusick * Print current directory. 16917752Smckusick */ 17017752Smckusick case 'p': 17129903Smckusick if (strncmp(cmd, "pwd", strlen(cmd)) != 0) 17229903Smckusick goto bad; 17317752Smckusick if (curdir[1] == '\0') 17417752Smckusick fprintf(stderr, "/\n"); 17517752Smckusick else 17617752Smckusick fprintf(stderr, "%s\n", &curdir[1]); 17717752Smckusick break; 17817752Smckusick /* 17917752Smckusick * Quit. 18017752Smckusick */ 18117752Smckusick case 'q': 18229903Smckusick if (strncmp(cmd, "quit", strlen(cmd)) != 0) 18329903Smckusick goto bad; 18429903Smckusick return; 18517752Smckusick case 'x': 18629903Smckusick if (strncmp(cmd, "xit", strlen(cmd)) != 0) 18729903Smckusick goto bad; 18817752Smckusick return; 18917752Smckusick /* 19017752Smckusick * Toggle verbose mode. 19117752Smckusick */ 19217752Smckusick case 'v': 19329903Smckusick if (strncmp(cmd, "verbose", strlen(cmd)) != 0) 19429903Smckusick goto bad; 19517752Smckusick if (vflag) { 19617752Smckusick fprintf(stderr, "verbose mode off\n"); 19717752Smckusick vflag = 0; 19817752Smckusick break; 19917752Smckusick } 20017752Smckusick fprintf(stderr, "verbose mode on\n"); 20117752Smckusick vflag++; 20217752Smckusick break; 20317752Smckusick /* 20417752Smckusick * Just restore requested directory modes. 20517752Smckusick */ 20621096Smckusick case 's': 20729903Smckusick if (strncmp(cmd, "setmodes", strlen(cmd)) != 0) 20829903Smckusick goto bad; 20917752Smckusick setdirmodes(); 21017752Smckusick break; 21117752Smckusick /* 21229903Smckusick * Print out dump header information. 21329903Smckusick */ 21429903Smckusick case 'w': 21529903Smckusick if (strncmp(cmd, "what", strlen(cmd)) != 0) 21629903Smckusick goto bad; 21729903Smckusick printdumpinfo(); 21829903Smckusick break; 21929903Smckusick /* 22017752Smckusick * Turn on debugging. 22117752Smckusick */ 22217752Smckusick case 'D': 22329903Smckusick if (strncmp(cmd, "Debug", strlen(cmd)) != 0) 22429903Smckusick goto bad; 22517752Smckusick if (dflag) { 22617752Smckusick fprintf(stderr, "debugging mode off\n"); 22717752Smckusick dflag = 0; 22817752Smckusick break; 22917752Smckusick } 23017752Smckusick fprintf(stderr, "debugging mode on\n"); 23117752Smckusick dflag++; 23217752Smckusick break; 23317752Smckusick /* 23417752Smckusick * Unknown command. 23517752Smckusick */ 23617752Smckusick default: 23729903Smckusick bad: 23817752Smckusick fprintf(stderr, "%s: unknown command; type ? for help\n", cmd); 23917752Smckusick break; 24017752Smckusick } 24117752Smckusick goto loop; 24217752Smckusick } 24317752Smckusick 24417752Smckusick /* 24517752Smckusick * Read and parse an interactive command. 24617752Smckusick * The first word on the line is assigned to "cmd". If 24717752Smckusick * there are no arguments on the command line, then "curdir" 24817752Smckusick * is returned as the argument. If there are arguments 24917752Smckusick * on the line they are returned one at a time on each 25017752Smckusick * successive call to getcmd. Each argument is first assigned 25117752Smckusick * to "name". If it does not start with "/" the pathname in 25217752Smckusick * "curdir" is prepended to it. Finally "canon" is called to 25317752Smckusick * eliminate any embedded ".." components. 25417752Smckusick */ 25518003Smckusick getcmd(curdir, cmd, name, ap) 25617752Smckusick char *curdir, *cmd, *name; 25718003Smckusick struct arglist *ap; 25817752Smckusick { 25917752Smckusick register char *cp; 26017752Smckusick static char input[BUFSIZ]; 26117752Smckusick char output[BUFSIZ]; 26217752Smckusick # define rawname input /* save space by reusing input buffer */ 26317752Smckusick 26417752Smckusick /* 26517752Smckusick * Check to see if still processing arguments. 26617752Smckusick */ 26718003Smckusick if (ap->head != ap->last) { 26818003Smckusick strcpy(name, ap->head->fname); 26918003Smckusick freename(ap->head->fname); 27018003Smckusick ap->head++; 27118003Smckusick return; 27218003Smckusick } 27317752Smckusick if (nextarg != NULL) 27417752Smckusick goto getnext; 27517752Smckusick /* 27617752Smckusick * Read a command line and trim off trailing white space. 27717752Smckusick */ 27817752Smckusick do { 27917752Smckusick fprintf(stderr, "restore > "); 28017752Smckusick (void) fflush(stderr); 28117752Smckusick (void) fgets(input, BUFSIZ, terminal); 28217752Smckusick } while (!feof(terminal) && input[0] == '\n'); 28317752Smckusick if (feof(terminal)) { 28417752Smckusick (void) strcpy(cmd, "quit"); 28517752Smckusick return; 28617752Smckusick } 28717752Smckusick for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--) 28817752Smckusick /* trim off trailing white space and newline */; 28917752Smckusick *++cp = '\0'; 29017752Smckusick /* 29117752Smckusick * Copy the command into "cmd". 29217752Smckusick */ 29317752Smckusick cp = copynext(input, cmd); 29418003Smckusick ap->cmd = cmd; 29517752Smckusick /* 29617752Smckusick * If no argument, use curdir as the default. 29717752Smckusick */ 29817752Smckusick if (*cp == '\0') { 29917752Smckusick (void) strcpy(name, curdir); 30017752Smckusick return; 30117752Smckusick } 30217752Smckusick nextarg = cp; 30317752Smckusick /* 30417752Smckusick * Find the next argument. 30517752Smckusick */ 30617752Smckusick getnext: 30717752Smckusick cp = copynext(nextarg, rawname); 30817752Smckusick if (*cp == '\0') 30917752Smckusick nextarg = NULL; 31017752Smckusick else 31117752Smckusick nextarg = cp; 31217752Smckusick /* 31317752Smckusick * If it an absolute pathname, canonicalize it and return it. 31417752Smckusick */ 31517752Smckusick if (rawname[0] == '/') { 31617752Smckusick canon(rawname, name); 31717752Smckusick } else { 31817752Smckusick /* 31917752Smckusick * For relative pathnames, prepend the current directory to 32017752Smckusick * it then canonicalize and return it. 32117752Smckusick */ 32217752Smckusick (void) strcpy(output, curdir); 32317752Smckusick (void) strcat(output, "/"); 32417752Smckusick (void) strcat(output, rawname); 32517752Smckusick canon(output, name); 32617752Smckusick } 32718003Smckusick expandarg(name, ap); 32818003Smckusick strcpy(name, ap->head->fname); 32918003Smckusick freename(ap->head->fname); 33018003Smckusick ap->head++; 33117752Smckusick # undef rawname 33217752Smckusick } 33317752Smckusick 33417752Smckusick /* 33517752Smckusick * Strip off the next token of the input. 33617752Smckusick */ 33717752Smckusick char * 33817752Smckusick copynext(input, output) 33917752Smckusick char *input, *output; 34017752Smckusick { 34117752Smckusick register char *cp, *bp; 34217752Smckusick char quote; 34317752Smckusick 34417752Smckusick for (cp = input; *cp == ' ' || *cp == '\t'; cp++) 34517752Smckusick /* skip to argument */; 34617752Smckusick bp = output; 34717752Smckusick while (*cp != ' ' && *cp != '\t' && *cp != '\0') { 34817752Smckusick /* 34917752Smckusick * Handle back slashes. 35017752Smckusick */ 35117752Smckusick if (*cp == '\\') { 35217752Smckusick if (*++cp == '\0') { 35317752Smckusick fprintf(stderr, 35417752Smckusick "command lines cannot be continued\n"); 35517752Smckusick continue; 35617752Smckusick } 35717752Smckusick *bp++ = *cp++; 35817752Smckusick continue; 35917752Smckusick } 36017752Smckusick /* 36117752Smckusick * The usual unquoted case. 36217752Smckusick */ 36317752Smckusick if (*cp != '\'' && *cp != '"') { 36417752Smckusick *bp++ = *cp++; 36517752Smckusick continue; 36617752Smckusick } 36717752Smckusick /* 36817752Smckusick * Handle single and double quotes. 36917752Smckusick */ 37017752Smckusick quote = *cp++; 37117752Smckusick while (*cp != quote && *cp != '\0') 37217752Smckusick *bp++ = *cp++ | 0200; 37317752Smckusick if (*cp++ == '\0') { 37417752Smckusick fprintf(stderr, "missing %c\n", quote); 37517752Smckusick cp--; 37617752Smckusick continue; 37717752Smckusick } 37817752Smckusick } 37917752Smckusick *bp = '\0'; 38017752Smckusick return (cp); 38117752Smckusick } 38217752Smckusick 38317752Smckusick /* 38417752Smckusick * Canonicalize file names to always start with ``./'' and 38518003Smckusick * remove any imbedded "." and ".." components. 38617752Smckusick */ 38717752Smckusick canon(rawname, canonname) 38817752Smckusick char *rawname, *canonname; 38917752Smckusick { 39017752Smckusick register char *cp, *np; 39117752Smckusick int len; 39217752Smckusick 39317752Smckusick if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0) 39417752Smckusick (void) strcpy(canonname, ""); 39517752Smckusick else if (rawname[0] == '/') 39617752Smckusick (void) strcpy(canonname, "."); 39717752Smckusick else 39817752Smckusick (void) strcpy(canonname, "./"); 39917752Smckusick (void) strcat(canonname, rawname); 40017752Smckusick /* 40118003Smckusick * Eliminate multiple and trailing '/'s 40217752Smckusick */ 40318003Smckusick for (cp = np = canonname; *np != '\0'; cp++) { 40418003Smckusick *cp = *np++; 40518003Smckusick while (*cp == '/' && *np == '/') 40618003Smckusick np++; 40718003Smckusick } 40818003Smckusick *cp = '\0'; 40918003Smckusick if (*--cp == '/') 41018003Smckusick *cp = '\0'; 41118003Smckusick /* 41218003Smckusick * Eliminate extraneous "." and ".." from pathnames. 41318003Smckusick */ 41417752Smckusick for (np = canonname; *np != '\0'; ) { 41517752Smckusick np++; 41617752Smckusick cp = np; 41717752Smckusick while (*np != '/' && *np != '\0') 41817752Smckusick np++; 41918003Smckusick if (np - cp == 1 && *cp == '.') { 42018003Smckusick cp--; 42118003Smckusick (void) strcpy(cp, np); 42218003Smckusick np = cp; 42318003Smckusick } 42417752Smckusick if (np - cp == 2 && strncmp(cp, "..", 2) == 0) { 42517752Smckusick cp--; 42617752Smckusick while (cp > &canonname[1] && *--cp != '/') 42717752Smckusick /* find beginning of name */; 42817752Smckusick (void) strcpy(cp, np); 42917752Smckusick np = cp; 43017752Smckusick } 43117752Smckusick } 43217752Smckusick } 43317752Smckusick 43417752Smckusick /* 43517756Smckusick * globals (file name generation) 43617756Smckusick * 43717756Smckusick * "*" in params matches r.e ".*" 43817756Smckusick * "?" in params matches r.e. "." 43917756Smckusick * "[...]" in params matches character class 44017756Smckusick * "[...a-z...]" in params matches a through z. 44117756Smckusick */ 44218003Smckusick expandarg(arg, ap) 44317756Smckusick char *arg; 44418003Smckusick register struct arglist *ap; 44517756Smckusick { 44620850Smckusick static struct afile single; 44730950Smckusick struct entry *ep; 44817756Smckusick int size; 44917756Smckusick 45018003Smckusick ap->head = ap->last = (struct afile *)0; 45118003Smckusick size = expand(arg, 0, ap); 45217756Smckusick if (size == 0) { 45330950Smckusick ep = lookupname(arg); 45430950Smckusick single.fnum = ep ? ep->e_ino : 0; 45518003Smckusick single.fname = savename(arg); 45618003Smckusick ap->head = &single; 45718003Smckusick ap->last = ap->head + 1; 45818003Smckusick return; 45917756Smckusick } 46018003Smckusick qsort((char *)ap->head, ap->last - ap->head, sizeof *ap->head, fcmp); 46117756Smckusick } 46217756Smckusick 46317756Smckusick /* 46417756Smckusick * Expand a file name 46517756Smckusick */ 46618003Smckusick expand(as, rflg, ap) 46717756Smckusick char *as; 46817756Smckusick int rflg; 46918003Smckusick register struct arglist *ap; 47017756Smckusick { 47117756Smckusick int count, size; 47217756Smckusick char dir = 0; 47317756Smckusick char *rescan = 0; 47417756Smckusick DIR *dirp; 47517756Smckusick register char *s, *cs; 47618003Smckusick int sindex, rindex, lindex; 47717756Smckusick struct direct *dp; 47817756Smckusick register char slash; 47917756Smckusick register char *rs; 48017756Smckusick register char c; 48117756Smckusick 48217756Smckusick /* 48317756Smckusick * check for meta chars 48417756Smckusick */ 48517756Smckusick s = cs = as; 48617756Smckusick slash = 0; 48717756Smckusick while (*cs != '*' && *cs != '?' && *cs != '[') { 48818003Smckusick if (*cs++ == 0) { 48917756Smckusick if (rflg && slash) 49017756Smckusick break; 49117756Smckusick else 49217756Smckusick return (0) ; 49318003Smckusick } else if (*cs == '/') { 49417756Smckusick slash++; 49517756Smckusick } 49617756Smckusick } 49717756Smckusick for (;;) { 49817756Smckusick if (cs == s) { 49918003Smckusick s = ""; 50017756Smckusick break; 50117756Smckusick } else if (*--cs == '/') { 50217756Smckusick *cs = 0; 50317756Smckusick if (s == cs) 50417756Smckusick s = "/"; 50517756Smckusick break; 50617756Smckusick } 50717756Smckusick } 50817756Smckusick if ((dirp = rst_opendir(s)) != NULL) 50917756Smckusick dir++; 51017756Smckusick count = 0; 51117756Smckusick if (*cs == 0) 51218003Smckusick *cs++ = 0200; 51317756Smckusick if (dir) { 51417756Smckusick /* 51517756Smckusick * check for rescan 51617756Smckusick */ 51717756Smckusick rs = cs; 51817756Smckusick do { 51917756Smckusick if (*rs == '/') { 52017756Smckusick rescan = rs; 52117756Smckusick *rs = 0; 52217756Smckusick } 52317756Smckusick } while (*rs++); 52418003Smckusick sindex = ap->last - ap->head; 52517756Smckusick while ((dp = rst_readdir(dirp)) != NULL && dp->d_ino != 0) { 52617756Smckusick if (!dflag && BIT(dp->d_ino, dumpmap) == 0) 52717756Smckusick continue; 52817756Smckusick if ((*dp->d_name == '.' && *cs != '.')) 52917756Smckusick continue; 53017756Smckusick if (gmatch(dp->d_name, cs)) { 53118003Smckusick if (addg(dp, s, rescan, ap) < 0) 53217756Smckusick return (-1); 53317756Smckusick count++; 53417756Smckusick } 53517756Smckusick } 53617756Smckusick if (rescan) { 53718003Smckusick rindex = sindex; 53818003Smckusick lindex = ap->last - ap->head; 53917756Smckusick if (count) { 54017756Smckusick count = 0; 54118003Smckusick while (rindex < lindex) { 54218003Smckusick size = expand(ap->head[rindex].fname, 54318003Smckusick 1, ap); 54417756Smckusick if (size < 0) 54517756Smckusick return (size); 54617756Smckusick count += size; 54718003Smckusick rindex++; 54817756Smckusick } 54917756Smckusick } 55018003Smckusick bcopy((char *)&ap->head[lindex], 55118003Smckusick (char *)&ap->head[sindex], 55218003Smckusick (ap->last - &ap->head[rindex]) * sizeof *ap->head); 55318003Smckusick ap->last -= lindex - sindex; 55417756Smckusick *rescan = '/'; 55517756Smckusick } 55617756Smckusick } 55717756Smckusick s = as; 55817756Smckusick while (c = *s) 55917756Smckusick *s++ = (c&0177 ? c : '/'); 56017756Smckusick return (count); 56117756Smckusick } 56217756Smckusick 56317756Smckusick /* 56417756Smckusick * Check for a name match 56517756Smckusick */ 56617756Smckusick gmatch(s, p) 56717756Smckusick register char *s, *p; 56817756Smckusick { 56917756Smckusick register int scc; 57017756Smckusick char c; 57117756Smckusick char ok; 57217756Smckusick int lc; 57317756Smckusick 57417756Smckusick if (scc = *s++) 57517756Smckusick if ((scc &= 0177) == 0) 57617756Smckusick scc = 0200; 57717756Smckusick switch (c = *p++) { 57817756Smckusick 57917756Smckusick case '[': 58017756Smckusick ok = 0; 58117756Smckusick lc = 077777; 58217756Smckusick while (c = *p++) { 58318003Smckusick if (c == ']') { 58417756Smckusick return (ok ? gmatch(s, p) : 0); 58517756Smckusick } else if (c == '-') { 58617756Smckusick if (lc <= scc && scc <= (*p++)) 58717756Smckusick ok++ ; 58817756Smckusick } else { 58917756Smckusick if (scc == (lc = (c&0177))) 59017756Smckusick ok++ ; 59117756Smckusick } 59217756Smckusick } 59317756Smckusick return (0); 59417756Smckusick 59517756Smckusick default: 59617756Smckusick if ((c&0177) != scc) 59717756Smckusick return (0) ; 59817756Smckusick /* falls through */ 59917756Smckusick 60017756Smckusick case '?': 60117756Smckusick return (scc ? gmatch(s, p) : 0); 60217756Smckusick 60317756Smckusick case '*': 60417756Smckusick if (*p == 0) 60517756Smckusick return (1) ; 60617756Smckusick s--; 60717756Smckusick while (*s) { 60817756Smckusick if (gmatch(s++, p)) 60917756Smckusick return (1); 61017756Smckusick } 61117756Smckusick return (0); 61217756Smckusick 61317756Smckusick case 0: 61417756Smckusick return (scc == 0); 61517756Smckusick } 61617756Smckusick } 61717756Smckusick 61817756Smckusick /* 61917756Smckusick * Construct a matched name. 62017756Smckusick */ 62118003Smckusick addg(dp, as1, as3, ap) 62218003Smckusick struct direct *dp; 62318003Smckusick char *as1, *as3; 62418003Smckusick struct arglist *ap; 62517756Smckusick { 62617756Smckusick register char *s1, *s2; 62717756Smckusick register int c; 62818003Smckusick char buf[BUFSIZ]; 62917756Smckusick 63018003Smckusick s2 = buf; 63117756Smckusick s1 = as1; 63217756Smckusick while (c = *s1++) { 63317756Smckusick if ((c &= 0177) == 0) { 63418003Smckusick *s2++ = '/'; 63517756Smckusick break; 63617756Smckusick } 63717756Smckusick *s2++ = c; 63817756Smckusick } 63918003Smckusick s1 = dp->d_name; 64017756Smckusick while (*s2 = *s1++) 64117756Smckusick s2++; 64217756Smckusick if (s1 = as3) { 64317756Smckusick *s2++ = '/'; 64417756Smckusick while (*s2++ = *++s1) 64517756Smckusick /* void */; 64617756Smckusick } 64718003Smckusick if (mkentry(buf, dp->d_ino, ap) == FAIL) 64818003Smckusick return (-1); 64917756Smckusick } 65017756Smckusick 65117756Smckusick /* 65217752Smckusick * Do an "ls" style listing of a directory 65317752Smckusick */ 65417752Smckusick printlist(name, ino, basename) 65517752Smckusick char *name; 65617752Smckusick ino_t ino; 65717752Smckusick char *basename; 65817752Smckusick { 65917752Smckusick register struct afile *fp; 66018003Smckusick register struct direct *dp; 66118003Smckusick static struct arglist alist = { 0, 0, 0, 0, "ls" }; 66217752Smckusick struct afile single; 66317752Smckusick DIR *dirp; 66417752Smckusick 66517752Smckusick if ((dirp = rst_opendir(name)) == NULL) { 66617752Smckusick single.fnum = ino; 66718003Smckusick single.fname = savename(name + strlen(basename) + 1); 66818003Smckusick alist.head = &single; 66918003Smckusick alist.last = alist.head + 1; 67017752Smckusick } else { 67118003Smckusick alist.head = (struct afile *)0; 67218003Smckusick fprintf(stderr, "%s:\n", name); 67318003Smckusick while (dp = rst_readdir(dirp)) { 67418003Smckusick if (dp == NULL || dp->d_ino == 0) 67518003Smckusick break; 67618003Smckusick if (!dflag && BIT(dp->d_ino, dumpmap) == 0) 67718003Smckusick continue; 67818003Smckusick if (vflag == 0 && 67918003Smckusick (strcmp(dp->d_name, ".") == 0 || 68018003Smckusick strcmp(dp->d_name, "..") == 0)) 68118003Smckusick continue; 68218003Smckusick if (!mkentry(dp->d_name, dp->d_ino, &alist)) 68318003Smckusick return; 68418003Smckusick } 68517752Smckusick } 68618003Smckusick if (alist.head != 0) { 68718003Smckusick qsort((char *)alist.head, alist.last - alist.head, 68818003Smckusick sizeof *alist.head, fcmp); 68918003Smckusick formatf(&alist); 69018003Smckusick for (fp = alist.head; fp < alist.last; fp++) 69118003Smckusick freename(fp->fname); 69218003Smckusick } 69318003Smckusick if (dirp != NULL) 69418003Smckusick fprintf(stderr, "\n"); 69517752Smckusick } 69617752Smckusick 69717752Smckusick /* 69817752Smckusick * Read the contents of a directory. 69917752Smckusick */ 70018003Smckusick mkentry(name, ino, ap) 70118003Smckusick char *name; 70218003Smckusick ino_t ino; 70318003Smckusick register struct arglist *ap; 70417752Smckusick { 70517752Smckusick register struct afile *fp; 70617752Smckusick 70718003Smckusick if (ap->base == NULL) { 70818003Smckusick ap->nent = 20; 70918003Smckusick ap->base = (struct afile *)calloc((unsigned)ap->nent, 71017752Smckusick sizeof (struct afile)); 71118003Smckusick if (ap->base == NULL) { 71218003Smckusick fprintf(stderr, "%s: out of memory\n", ap->cmd); 71317752Smckusick return (FAIL); 71417752Smckusick } 71517752Smckusick } 71618003Smckusick if (ap->head == 0) 71718003Smckusick ap->head = ap->last = ap->base; 71818003Smckusick fp = ap->last; 71918003Smckusick fp->fnum = ino; 72018003Smckusick fp->fname = savename(name); 72118003Smckusick fp++; 72218003Smckusick if (fp == ap->head + ap->nent) { 72318003Smckusick ap->base = (struct afile *)realloc((char *)ap->base, 72418003Smckusick (unsigned)(2 * ap->nent * sizeof (struct afile))); 72518003Smckusick if (ap->base == 0) { 72618003Smckusick fprintf(stderr, "%s: out of memory\n", ap->cmd); 72718003Smckusick return (FAIL); 72817752Smckusick } 72918003Smckusick ap->head = ap->base; 73018003Smckusick fp = ap->head + ap->nent; 73118003Smckusick ap->nent *= 2; 73217752Smckusick } 73318003Smckusick ap->last = fp; 73417752Smckusick return (GOOD); 73517752Smckusick } 73617752Smckusick 73717752Smckusick /* 73817752Smckusick * Print out a pretty listing of a directory 73917752Smckusick */ 74018003Smckusick formatf(ap) 74118003Smckusick register struct arglist *ap; 74217752Smckusick { 74317752Smckusick register struct afile *fp; 74417752Smckusick struct entry *np; 74518003Smckusick int width = 0, w, nentry = ap->last - ap->head; 74617752Smckusick int i, j, len, columns, lines; 74717752Smckusick char *cp; 74817752Smckusick 74918003Smckusick if (ap->head == ap->last) 75017752Smckusick return; 75118003Smckusick for (fp = ap->head; fp < ap->last; fp++) { 75217752Smckusick fp->ftype = inodetype(fp->fnum); 75317752Smckusick np = lookupino(fp->fnum); 75417752Smckusick if (np != NIL) 75517752Smckusick fp->fflags = np->e_flags; 75617752Smckusick else 75717752Smckusick fp->fflags = 0; 75817752Smckusick len = strlen(fmtentry(fp)); 75917752Smckusick if (len > width) 76017752Smckusick width = len; 76117752Smckusick } 76217752Smckusick width += 2; 76317752Smckusick columns = 80 / width; 76417752Smckusick if (columns == 0) 76517752Smckusick columns = 1; 76617752Smckusick lines = (nentry + columns - 1) / columns; 76717752Smckusick for (i = 0; i < lines; i++) { 76817752Smckusick for (j = 0; j < columns; j++) { 76918003Smckusick fp = ap->head + j * lines + i; 77017752Smckusick cp = fmtentry(fp); 77117752Smckusick fprintf(stderr, "%s", cp); 77218003Smckusick if (fp + lines >= ap->last) { 77317752Smckusick fprintf(stderr, "\n"); 77417752Smckusick break; 77517752Smckusick } 77617752Smckusick w = strlen(cp); 77717752Smckusick while (w < width) { 77817752Smckusick w++; 77917752Smckusick fprintf(stderr, " "); 78017752Smckusick } 78117752Smckusick } 78217752Smckusick } 78317752Smckusick } 78417752Smckusick 78517752Smckusick /* 78617752Smckusick * Comparison routine for qsort. 78717752Smckusick */ 78817752Smckusick fcmp(f1, f2) 78917752Smckusick register struct afile *f1, *f2; 79017752Smckusick { 79117752Smckusick 79217752Smckusick return (strcmp(f1->fname, f2->fname)); 79317752Smckusick } 79417752Smckusick 79517752Smckusick /* 79617752Smckusick * Format a directory entry. 79717752Smckusick */ 79817752Smckusick char * 79917752Smckusick fmtentry(fp) 80017752Smckusick register struct afile *fp; 80117752Smckusick { 80217752Smckusick static char fmtres[BUFSIZ]; 80323982Smckusick static int precision = 0; 80423982Smckusick int i; 80517752Smckusick register char *cp, *dp; 80617752Smckusick 80723982Smckusick if (!vflag) { 80817752Smckusick fmtres[0] = '\0'; 80923982Smckusick } else { 81023982Smckusick if (precision == 0) 81123982Smckusick for (i = maxino; i > 0; i /= 10) 81223982Smckusick precision++; 81323982Smckusick (void) sprintf(fmtres, "%*d ", precision, fp->fnum); 81423982Smckusick } 81517752Smckusick dp = &fmtres[strlen(fmtres)]; 81617752Smckusick if (dflag && BIT(fp->fnum, dumpmap) == 0) 81717752Smckusick *dp++ = '^'; 81817752Smckusick else if ((fp->fflags & NEW) != 0) 81917752Smckusick *dp++ = '*'; 82017752Smckusick else 82117752Smckusick *dp++ = ' '; 82217752Smckusick for (cp = fp->fname; *cp; cp++) 82317752Smckusick if (!vflag && (*cp < ' ' || *cp >= 0177)) 82417752Smckusick *dp++ = '?'; 82517752Smckusick else 82617752Smckusick *dp++ = *cp; 82717752Smckusick if (fp->ftype == NODE) 82817752Smckusick *dp++ = '/'; 82917752Smckusick *dp++ = 0; 83017752Smckusick return (fmtres); 83117752Smckusick } 83217752Smckusick 83317752Smckusick /* 83417752Smckusick * respond to interrupts 83517752Smckusick */ 836*39942Sbostic void 83717752Smckusick onintr() 83817752Smckusick { 83917752Smckusick if (command == 'i') 84017752Smckusick longjmp(reset, 1); 84117752Smckusick if (reply("restore interrupted, continue") == FAIL) 84217752Smckusick done(1); 84317752Smckusick } 844