117752Smckusick /* Copyright (c) 1985 Regents of the University of California */ 217752Smckusick 317752Smckusick #ifndef lint 4*17756Smckusick static char sccsid[] = "@(#)interactive.c 3.2 (Berkeley) 01/18/85"; 517752Smckusick #endif not lint 617752Smckusick 717752Smckusick #include "restore.h" 817752Smckusick #include <dumprestor.h> 917752Smckusick #include <setjmp.h> 1017752Smckusick 11*17756Smckusick #define round(a, b) (((a) + (b) - 1) / (b) * (b)) 12*17756Smckusick 1317752Smckusick /* 1417752Smckusick * Things to handle interruptions. 1517752Smckusick */ 1617752Smckusick static jmp_buf reset; 1717752Smckusick static char *nextarg = NULL; 1817752Smckusick 1917752Smckusick /* 20*17756Smckusick * Structure associated with file name globbing. 21*17756Smckusick */ 22*17756Smckusick struct argnod { 23*17756Smckusick struct argnod *argnxt; 24*17756Smckusick char argval[1]; 25*17756Smckusick }; 26*17756Smckusick static struct argnod *gchain, *stakbot, *staktop; 27*17756Smckusick static char *brkend, *nullstr = ""; 28*17756Smckusick struct argnod *locstak(), *endstak(); 29*17756Smckusick 30*17756Smckusick /* 3117752Smckusick * Structure and routines associated with listing directories. 3217752Smckusick */ 3317752Smckusick struct afile { 3417752Smckusick ino_t fnum; /* inode number of file */ 3517752Smckusick char *fname; /* file name */ 3617752Smckusick short fflags; /* extraction flags, if any */ 3717752Smckusick char ftype; /* file type, e.g. LEAF or NODE */ 3817752Smckusick }; 3917752Smckusick extern int fcmp(); 4017752Smckusick extern char *fmtentry(); 4117752Smckusick char *copynext(); 4217752Smckusick 4317752Smckusick /* 4417752Smckusick * Read and execute commands from the terminal. 4517752Smckusick */ 4617752Smckusick runcmdshell() 4717752Smckusick { 4817752Smckusick register struct entry *np; 4917752Smckusick ino_t ino; 5017752Smckusick char curdir[MAXPATHLEN]; 5117752Smckusick char name[MAXPATHLEN]; 5217752Smckusick char cmd[BUFSIZ]; 5317752Smckusick 5417752Smckusick canon("/", curdir); 5517752Smckusick loop: 5617752Smckusick if (setjmp(reset) != 0) { 57*17756Smckusick gchain = 0; 5817752Smckusick nextarg = NULL; 5917752Smckusick volno = 0; 6017752Smckusick } 6117752Smckusick getcmd(curdir, cmd, name); 6217752Smckusick switch (cmd[0]) { 6317752Smckusick /* 6417752Smckusick * Add elements to the extraction list. 6517752Smckusick */ 6617752Smckusick case 'a': 6717752Smckusick ino = dirlookup(name); 6817752Smckusick if (ino == 0) 6917752Smckusick break; 7017752Smckusick if (mflag) 7117752Smckusick pathcheck(name); 7217752Smckusick treescan(name, ino, addfile); 7317752Smckusick break; 7417752Smckusick /* 7517752Smckusick * Change working directory. 7617752Smckusick */ 7717752Smckusick case 'c': 7817752Smckusick ino = dirlookup(name); 7917752Smckusick if (ino == 0) 8017752Smckusick break; 8117752Smckusick if (inodetype(ino) == LEAF) { 8217752Smckusick fprintf(stderr, "%s: not a directory\n", name); 8317752Smckusick break; 8417752Smckusick } 8517752Smckusick (void) strcpy(curdir, name); 8617752Smckusick break; 8717752Smckusick /* 8817752Smckusick * Delete elements from the extraction list. 8917752Smckusick */ 9017752Smckusick case 'd': 9117752Smckusick np = lookupname(name); 9217752Smckusick if (np == NIL || (np->e_flags & NEW) == 0) { 9317752Smckusick fprintf(stderr, "%s: not on extraction list\n", name); 9417752Smckusick break; 9517752Smckusick } 9617752Smckusick treescan(name, np->e_ino, deletefile); 9717752Smckusick break; 9817752Smckusick /* 9917752Smckusick * Extract the requested list. 10017752Smckusick */ 10117752Smckusick case 'e': 10217752Smckusick createfiles(); 10317752Smckusick createlinks(); 10417752Smckusick setdirmodes(); 10517752Smckusick if (dflag) 10617752Smckusick checkrestore(); 10717752Smckusick volno = 0; 10817752Smckusick break; 10917752Smckusick /* 11017752Smckusick * List available commands. 11117752Smckusick */ 11217752Smckusick case 'h': 11317752Smckusick case '?': 11417752Smckusick fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 11517752Smckusick "Available commands are:\n", 11617752Smckusick "\tls [arg] - list directory\n", 11717752Smckusick "\tcd arg - change directory\n", 11817752Smckusick "\tpwd - print current directory\n", 11917752Smckusick "\tadd [arg] - add `arg' to list of", 12017752Smckusick " files to be extracted\n", 12117752Smckusick "\tdelete [arg] - delete `arg' from", 12217752Smckusick " list of files to be extracted\n", 12317752Smckusick "\textract - extract requested files\n", 12417752Smckusick "\tquit - immediately exit program\n", 12517752Smckusick "\tverbose - toggle verbose flag", 12617752Smckusick " (useful with ``ls'')\n", 12717752Smckusick "\thelp or `?' - print this list\n", 12817752Smckusick "If no `arg' is supplied, the current", 12917752Smckusick " directory is used\n"); 13017752Smckusick break; 13117752Smckusick /* 13217752Smckusick * List a directory. 13317752Smckusick */ 13417752Smckusick case 'l': 13517752Smckusick ino = dirlookup(name); 13617752Smckusick if (ino == 0) 13717752Smckusick break; 13817752Smckusick printlist(name, ino, curdir); 13917752Smckusick break; 14017752Smckusick /* 14117752Smckusick * Print current directory. 14217752Smckusick */ 14317752Smckusick case 'p': 14417752Smckusick if (curdir[1] == '\0') 14517752Smckusick fprintf(stderr, "/\n"); 14617752Smckusick else 14717752Smckusick fprintf(stderr, "%s\n", &curdir[1]); 14817752Smckusick break; 14917752Smckusick /* 15017752Smckusick * Quit. 15117752Smckusick */ 15217752Smckusick case 'q': 15317752Smckusick case 'x': 15417752Smckusick return; 15517752Smckusick /* 15617752Smckusick * Toggle verbose mode. 15717752Smckusick */ 15817752Smckusick case 'v': 15917752Smckusick if (vflag) { 16017752Smckusick fprintf(stderr, "verbose mode off\n"); 16117752Smckusick vflag = 0; 16217752Smckusick break; 16317752Smckusick } 16417752Smckusick fprintf(stderr, "verbose mode on\n"); 16517752Smckusick vflag++; 16617752Smckusick break; 16717752Smckusick /* 16817752Smckusick * Just restore requested directory modes. 16917752Smckusick */ 17017752Smckusick case 'R': 17117752Smckusick setdirmodes(); 17217752Smckusick break; 17317752Smckusick /* 17417752Smckusick * Turn on debugging. 17517752Smckusick */ 17617752Smckusick case 'D': 17717752Smckusick if (dflag) { 17817752Smckusick fprintf(stderr, "debugging mode off\n"); 17917752Smckusick dflag = 0; 18017752Smckusick break; 18117752Smckusick } 18217752Smckusick fprintf(stderr, "debugging mode on\n"); 18317752Smckusick dflag++; 18417752Smckusick break; 18517752Smckusick /* 18617752Smckusick * Unknown command. 18717752Smckusick */ 18817752Smckusick default: 18917752Smckusick fprintf(stderr, "%s: unknown command; type ? for help\n", cmd); 19017752Smckusick break; 19117752Smckusick } 19217752Smckusick goto loop; 19317752Smckusick } 19417752Smckusick 19517752Smckusick /* 19617752Smckusick * Read and parse an interactive command. 19717752Smckusick * The first word on the line is assigned to "cmd". If 19817752Smckusick * there are no arguments on the command line, then "curdir" 19917752Smckusick * is returned as the argument. If there are arguments 20017752Smckusick * on the line they are returned one at a time on each 20117752Smckusick * successive call to getcmd. Each argument is first assigned 20217752Smckusick * to "name". If it does not start with "/" the pathname in 20317752Smckusick * "curdir" is prepended to it. Finally "canon" is called to 20417752Smckusick * eliminate any embedded ".." components. 20517752Smckusick */ 20617752Smckusick getcmd(curdir, cmd, name) 20717752Smckusick char *curdir, *cmd, *name; 20817752Smckusick { 20917752Smckusick register char *cp; 21017752Smckusick static char input[BUFSIZ]; 21117752Smckusick char output[BUFSIZ]; 21217752Smckusick # define rawname input /* save space by reusing input buffer */ 21317752Smckusick 21417752Smckusick /* 21517752Smckusick * Check to see if still processing arguments. 21617752Smckusick */ 217*17756Smckusick if (gchain != 0) 218*17756Smckusick goto getnextexp; 21917752Smckusick if (nextarg != NULL) 22017752Smckusick goto getnext; 22117752Smckusick /* 22217752Smckusick * Read a command line and trim off trailing white space. 22317752Smckusick */ 22417752Smckusick do { 22517752Smckusick fprintf(stderr, "restore > "); 22617752Smckusick (void) fflush(stderr); 22717752Smckusick (void) fgets(input, BUFSIZ, terminal); 22817752Smckusick } while (!feof(terminal) && input[0] == '\n'); 22917752Smckusick if (feof(terminal)) { 23017752Smckusick (void) strcpy(cmd, "quit"); 23117752Smckusick return; 23217752Smckusick } 23317752Smckusick for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--) 23417752Smckusick /* trim off trailing white space and newline */; 23517752Smckusick *++cp = '\0'; 23617752Smckusick /* 23717752Smckusick * Copy the command into "cmd". 23817752Smckusick */ 23917752Smckusick cp = copynext(input, cmd); 24017752Smckusick /* 24117752Smckusick * If no argument, use curdir as the default. 24217752Smckusick */ 24317752Smckusick if (*cp == '\0') { 24417752Smckusick (void) strcpy(name, curdir); 24517752Smckusick return; 24617752Smckusick } 24717752Smckusick nextarg = cp; 24817752Smckusick /* 24917752Smckusick * Find the next argument. 25017752Smckusick */ 25117752Smckusick getnext: 25217752Smckusick cp = copynext(nextarg, rawname); 25317752Smckusick if (*cp == '\0') 25417752Smckusick nextarg = NULL; 25517752Smckusick else 25617752Smckusick nextarg = cp; 25717752Smckusick /* 25817752Smckusick * If it an absolute pathname, canonicalize it and return it. 25917752Smckusick */ 26017752Smckusick if (rawname[0] == '/') { 26117752Smckusick canon(rawname, name); 26217752Smckusick } else { 26317752Smckusick /* 26417752Smckusick * For relative pathnames, prepend the current directory to 26517752Smckusick * it then canonicalize and return it. 26617752Smckusick */ 26717752Smckusick (void) strcpy(output, curdir); 26817752Smckusick (void) strcat(output, "/"); 26917752Smckusick (void) strcat(output, rawname); 27017752Smckusick canon(output, name); 27117752Smckusick } 272*17756Smckusick expandarg(name); 273*17756Smckusick getnextexp: 274*17756Smckusick strcpy(name, gchain->argval); 275*17756Smckusick gchain = gchain->argnxt; 27617752Smckusick # undef rawname 27717752Smckusick } 27817752Smckusick 27917752Smckusick /* 28017752Smckusick * Strip off the next token of the input. 28117752Smckusick */ 28217752Smckusick char * 28317752Smckusick copynext(input, output) 28417752Smckusick char *input, *output; 28517752Smckusick { 28617752Smckusick register char *cp, *bp; 28717752Smckusick char quote; 28817752Smckusick 28917752Smckusick for (cp = input; *cp == ' ' || *cp == '\t'; cp++) 29017752Smckusick /* skip to argument */; 29117752Smckusick bp = output; 29217752Smckusick while (*cp != ' ' && *cp != '\t' && *cp != '\0') { 29317752Smckusick /* 29417752Smckusick * Handle back slashes. 29517752Smckusick */ 29617752Smckusick if (*cp == '\\') { 29717752Smckusick if (*++cp == '\0') { 29817752Smckusick fprintf(stderr, 29917752Smckusick "command lines cannot be continued\n"); 30017752Smckusick continue; 30117752Smckusick } 30217752Smckusick *bp++ = *cp++; 30317752Smckusick continue; 30417752Smckusick } 30517752Smckusick /* 30617752Smckusick * The usual unquoted case. 30717752Smckusick */ 30817752Smckusick if (*cp != '\'' && *cp != '"') { 30917752Smckusick *bp++ = *cp++; 31017752Smckusick continue; 31117752Smckusick } 31217752Smckusick /* 31317752Smckusick * Handle single and double quotes. 31417752Smckusick */ 31517752Smckusick quote = *cp++; 31617752Smckusick while (*cp != quote && *cp != '\0') 31717752Smckusick *bp++ = *cp++ | 0200; 31817752Smckusick if (*cp++ == '\0') { 31917752Smckusick fprintf(stderr, "missing %c\n", quote); 32017752Smckusick cp--; 32117752Smckusick continue; 32217752Smckusick } 32317752Smckusick } 32417752Smckusick *bp = '\0'; 32517752Smckusick return (cp); 32617752Smckusick } 32717752Smckusick 32817752Smckusick /* 32917752Smckusick * Canonicalize file names to always start with ``./'' and 33017752Smckusick * remove any imbedded ".." components. 33117752Smckusick */ 33217752Smckusick canon(rawname, canonname) 33317752Smckusick char *rawname, *canonname; 33417752Smckusick { 33517752Smckusick register char *cp, *np; 33617752Smckusick int len; 33717752Smckusick 33817752Smckusick if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0) 33917752Smckusick (void) strcpy(canonname, ""); 34017752Smckusick else if (rawname[0] == '/') 34117752Smckusick (void) strcpy(canonname, "."); 34217752Smckusick else 34317752Smckusick (void) strcpy(canonname, "./"); 34417752Smckusick (void) strcat(canonname, rawname); 34517752Smckusick len = strlen(canonname) - 1; 34617752Smckusick if (canonname[len] == '/') 34717752Smckusick canonname[len] = '\0'; 34817752Smckusick /* 34917752Smckusick * Eliminate extraneous ".." from pathnames. 35017752Smckusick */ 35117752Smckusick for (np = canonname; *np != '\0'; ) { 35217752Smckusick np++; 35317752Smckusick cp = np; 35417752Smckusick while (*np != '/' && *np != '\0') 35517752Smckusick np++; 35617752Smckusick if (np - cp == 2 && strncmp(cp, "..", 2) == 0) { 35717752Smckusick cp--; 35817752Smckusick while (cp > &canonname[1] && *--cp != '/') 35917752Smckusick /* find beginning of name */; 36017752Smckusick (void) strcpy(cp, np); 36117752Smckusick np = cp; 36217752Smckusick } 36317752Smckusick } 36417752Smckusick } 36517752Smckusick 36617752Smckusick /* 367*17756Smckusick * globals (file name generation) 368*17756Smckusick * 369*17756Smckusick * "*" in params matches r.e ".*" 370*17756Smckusick * "?" in params matches r.e. "." 371*17756Smckusick * "[...]" in params matches character class 372*17756Smckusick * "[...a-z...]" in params matches a through z. 373*17756Smckusick */ 374*17756Smckusick expandarg(arg) 375*17756Smckusick char *arg; 376*17756Smckusick { 377*17756Smckusick static char *expbuf = NULL; 378*17756Smckusick static unsigned expsize = BUFSIZ; 379*17756Smckusick int size; 380*17756Smckusick char argbuf[BUFSIZ]; 381*17756Smckusick 382*17756Smckusick do { 383*17756Smckusick if (expbuf != NULL) 384*17756Smckusick free(expbuf); 385*17756Smckusick expbuf = malloc(expsize); 386*17756Smckusick brkend = expbuf + expsize; 387*17756Smckusick expsize <<= 1; 388*17756Smckusick stakbot = (struct argnod *)expbuf; 389*17756Smckusick gchain = 0; 390*17756Smckusick (void)strcpy(argbuf, arg); 391*17756Smckusick size = expand(argbuf, 0); 392*17756Smckusick } while (size < 0); 393*17756Smckusick if (size == 0) { 394*17756Smckusick gchain = (struct argnod *)expbuf; 395*17756Smckusick gchain->argnxt = 0; 396*17756Smckusick (void)strcpy(gchain->argval, arg); 397*17756Smckusick } 398*17756Smckusick } 399*17756Smckusick 400*17756Smckusick /* 401*17756Smckusick * Expand a file name 402*17756Smckusick */ 403*17756Smckusick expand(as, rflg) 404*17756Smckusick char *as; 405*17756Smckusick int rflg; 406*17756Smckusick { 407*17756Smckusick int count, size; 408*17756Smckusick char dir = 0; 409*17756Smckusick char *rescan = 0; 410*17756Smckusick DIR *dirp; 411*17756Smckusick register char *s, *cs; 412*17756Smckusick struct argnod *schain = gchain; 413*17756Smckusick struct direct *dp; 414*17756Smckusick register char slash; 415*17756Smckusick register char *rs; 416*17756Smckusick struct argnod *rchain; 417*17756Smckusick register char c; 418*17756Smckusick 419*17756Smckusick /* 420*17756Smckusick * check for meta chars 421*17756Smckusick */ 422*17756Smckusick s = cs = as; 423*17756Smckusick slash = 0; 424*17756Smckusick while (*cs != '*' && *cs != '?' && *cs != '[') { 425*17756Smckusick if (*cs++==0) { 426*17756Smckusick if (rflg && slash) 427*17756Smckusick break; 428*17756Smckusick else 429*17756Smckusick return (0) ; 430*17756Smckusick } else if (*cs=='/') { 431*17756Smckusick slash++; 432*17756Smckusick } 433*17756Smckusick } 434*17756Smckusick for (;;) { 435*17756Smckusick if (cs == s) { 436*17756Smckusick s = nullstr; 437*17756Smckusick break; 438*17756Smckusick } else if (*--cs == '/') { 439*17756Smckusick *cs = 0; 440*17756Smckusick if (s == cs) 441*17756Smckusick s = "/"; 442*17756Smckusick break; 443*17756Smckusick } 444*17756Smckusick } 445*17756Smckusick if ((dirp = rst_opendir(s)) != NULL) 446*17756Smckusick dir++; 447*17756Smckusick count = 0; 448*17756Smckusick if (*cs == 0) 449*17756Smckusick *cs++=0200 ; 450*17756Smckusick if (dir) { 451*17756Smckusick /* 452*17756Smckusick * check for rescan 453*17756Smckusick */ 454*17756Smckusick rs = cs; 455*17756Smckusick do { 456*17756Smckusick if (*rs == '/') { 457*17756Smckusick rescan = rs; 458*17756Smckusick *rs = 0; 459*17756Smckusick gchain = 0 ; 460*17756Smckusick } 461*17756Smckusick } while (*rs++); 462*17756Smckusick while ((dp = rst_readdir(dirp)) != NULL && dp->d_ino != 0) { 463*17756Smckusick if (!dflag && BIT(dp->d_ino, dumpmap) == 0) 464*17756Smckusick continue; 465*17756Smckusick if ((*dp->d_name == '.' && *cs != '.')) 466*17756Smckusick continue; 467*17756Smckusick if (gmatch(dp->d_name, cs)) { 468*17756Smckusick if (addg(s, dp->d_name, rescan) < 0) 469*17756Smckusick return (-1); 470*17756Smckusick count++; 471*17756Smckusick } 472*17756Smckusick } 473*17756Smckusick if (rescan) { 474*17756Smckusick rchain = gchain; 475*17756Smckusick gchain = schain; 476*17756Smckusick if (count) { 477*17756Smckusick count = 0; 478*17756Smckusick while (rchain) { 479*17756Smckusick size = expand(rchain->argval, 1); 480*17756Smckusick if (size < 0) 481*17756Smckusick return (size); 482*17756Smckusick count += size; 483*17756Smckusick rchain = rchain->argnxt; 484*17756Smckusick } 485*17756Smckusick } 486*17756Smckusick *rescan = '/'; 487*17756Smckusick } 488*17756Smckusick } 489*17756Smckusick s = as; 490*17756Smckusick while (c = *s) 491*17756Smckusick *s++ = (c&0177 ? c : '/'); 492*17756Smckusick return (count); 493*17756Smckusick } 494*17756Smckusick 495*17756Smckusick /* 496*17756Smckusick * Check for a name match 497*17756Smckusick */ 498*17756Smckusick gmatch(s, p) 499*17756Smckusick register char *s, *p; 500*17756Smckusick { 501*17756Smckusick register int scc; 502*17756Smckusick char c; 503*17756Smckusick char ok; 504*17756Smckusick int lc; 505*17756Smckusick 506*17756Smckusick if (scc = *s++) 507*17756Smckusick if ((scc &= 0177) == 0) 508*17756Smckusick scc = 0200; 509*17756Smckusick switch (c = *p++) { 510*17756Smckusick 511*17756Smckusick case '[': 512*17756Smckusick ok = 0; 513*17756Smckusick lc = 077777; 514*17756Smckusick while (c = *p++) { 515*17756Smckusick if (c==']') { 516*17756Smckusick return (ok ? gmatch(s, p) : 0); 517*17756Smckusick } else if (c == '-') { 518*17756Smckusick if (lc <= scc && scc <= (*p++)) 519*17756Smckusick ok++ ; 520*17756Smckusick } else { 521*17756Smckusick if (scc == (lc = (c&0177))) 522*17756Smckusick ok++ ; 523*17756Smckusick } 524*17756Smckusick } 525*17756Smckusick return (0); 526*17756Smckusick 527*17756Smckusick default: 528*17756Smckusick if ((c&0177) != scc) 529*17756Smckusick return (0) ; 530*17756Smckusick /* falls through */ 531*17756Smckusick 532*17756Smckusick case '?': 533*17756Smckusick return (scc ? gmatch(s, p) : 0); 534*17756Smckusick 535*17756Smckusick case '*': 536*17756Smckusick if (*p == 0) 537*17756Smckusick return (1) ; 538*17756Smckusick s--; 539*17756Smckusick while (*s) { 540*17756Smckusick if (gmatch(s++, p)) 541*17756Smckusick return (1); 542*17756Smckusick } 543*17756Smckusick return (0); 544*17756Smckusick 545*17756Smckusick case 0: 546*17756Smckusick return (scc == 0); 547*17756Smckusick } 548*17756Smckusick } 549*17756Smckusick 550*17756Smckusick /* 551*17756Smckusick * Construct a matched name. 552*17756Smckusick */ 553*17756Smckusick addg(as1, as2, as3) 554*17756Smckusick char *as1, *as2, *as3; 555*17756Smckusick { 556*17756Smckusick register char *s1, *s2; 557*17756Smckusick register int c; 558*17756Smckusick 559*17756Smckusick if ((s2 = (char *)locstak()) == 0) 560*17756Smckusick return (-1); 561*17756Smckusick s2 += sizeof(char *); 562*17756Smckusick s1 = as1; 563*17756Smckusick while (c = *s1++) { 564*17756Smckusick if ((c &= 0177) == 0) { 565*17756Smckusick *s2++='/'; 566*17756Smckusick break; 567*17756Smckusick } 568*17756Smckusick *s2++ = c; 569*17756Smckusick } 570*17756Smckusick s1 = as2; 571*17756Smckusick while (*s2 = *s1++) 572*17756Smckusick s2++; 573*17756Smckusick if (s1 = as3) { 574*17756Smckusick *s2++ = '/'; 575*17756Smckusick while (*s2++ = *++s1) 576*17756Smckusick /* void */; 577*17756Smckusick } 578*17756Smckusick makearg(endstak(s2)); 579*17756Smckusick return (0); 580*17756Smckusick } 581*17756Smckusick 582*17756Smckusick /* 583*17756Smckusick * Add a matched name to the list. 584*17756Smckusick */ 585*17756Smckusick makearg(args) 586*17756Smckusick register struct argnod *args; 587*17756Smckusick { 588*17756Smckusick args->argnxt = gchain; 589*17756Smckusick gchain = args; 590*17756Smckusick } 591*17756Smckusick 592*17756Smckusick /* 593*17756Smckusick * set up stack for local use 594*17756Smckusick * should be followed by `endstak' 595*17756Smckusick */ 596*17756Smckusick struct argnod * 597*17756Smckusick locstak() 598*17756Smckusick { 599*17756Smckusick if (brkend - (char *)stakbot < 100) { 600*17756Smckusick fprintf(stderr, "ran out of arg space\n"); 601*17756Smckusick return (0); 602*17756Smckusick } 603*17756Smckusick return (stakbot); 604*17756Smckusick } 605*17756Smckusick 606*17756Smckusick /* 607*17756Smckusick * tidy up after `locstak' 608*17756Smckusick */ 609*17756Smckusick struct argnod * 610*17756Smckusick endstak(argp) 611*17756Smckusick register char *argp; 612*17756Smckusick { 613*17756Smckusick register struct argnod *oldstak; 614*17756Smckusick 615*17756Smckusick *argp++ = 0; 616*17756Smckusick oldstak = stakbot; 617*17756Smckusick stakbot = staktop = (struct argnod *)round((int)argp, sizeof(char *)); 618*17756Smckusick return (oldstak); 619*17756Smckusick } 620*17756Smckusick 621*17756Smckusick /* 62217752Smckusick * Do an "ls" style listing of a directory 62317752Smckusick */ 62417752Smckusick printlist(name, ino, basename) 62517752Smckusick char *name; 62617752Smckusick ino_t ino; 62717752Smckusick char *basename; 62817752Smckusick { 62917752Smckusick register struct afile *fp; 63017752Smckusick struct afile *dfp0, *dfplast; 63117752Smckusick struct afile single; 63217752Smckusick DIR *dirp; 63317752Smckusick 63417752Smckusick if ((dirp = rst_opendir(name)) == NULL) { 63517752Smckusick single.fnum = ino; 63617752Smckusick single.fname = savename(name + strlen(basename)); 63717752Smckusick dfp0 = &single; 63817752Smckusick dfplast = dfp0 + 1; 63917752Smckusick } else { 64017752Smckusick if (getdir(dirp, &dfp0, &dfplast) == FAIL) 64117752Smckusick return; 64217752Smckusick } 64317752Smckusick qsort((char *)dfp0, dfplast - dfp0, sizeof (struct afile), fcmp); 64417752Smckusick formatf(dfp0, dfplast); 64517752Smckusick for (fp = dfp0; fp < dfplast; fp++) 64617752Smckusick freename(fp->fname); 64717752Smckusick } 64817752Smckusick 64917752Smckusick /* 65017752Smckusick * Read the contents of a directory. 65117752Smckusick */ 65217752Smckusick getdir(dirp, pfp0, pfplast) 65317752Smckusick DIR *dirp; 65417752Smckusick struct afile **pfp0, **pfplast; 65517752Smckusick { 65617752Smckusick register struct afile *fp; 65717752Smckusick register struct direct *dp; 65817752Smckusick static struct afile *basefp = NULL; 65917752Smckusick static long nent = 20; 66017752Smckusick 66117752Smckusick if (basefp == NULL) { 66217752Smckusick basefp = (struct afile *)calloc((unsigned)nent, 66317752Smckusick sizeof (struct afile)); 66417752Smckusick if (basefp == NULL) { 66517752Smckusick fprintf(stderr, "ls: out of memory\n"); 66617752Smckusick return (FAIL); 66717752Smckusick } 66817752Smckusick } 66917752Smckusick fp = *pfp0 = basefp; 67017752Smckusick *pfplast = *pfp0 + nent; 67117752Smckusick while (dp = rst_readdir(dirp)) { 67217752Smckusick if (dp == NULL || dp->d_ino == 0) 67317752Smckusick break; 67417752Smckusick if (!dflag && BIT(dp->d_ino, dumpmap) == 0) 67517752Smckusick continue; 67617752Smckusick if (vflag == 0 && 67717752Smckusick (strcmp(dp->d_name, ".") == 0 || 67817752Smckusick strcmp(dp->d_name, "..") == 0)) 67917752Smckusick continue; 68017752Smckusick fp->fnum = dp->d_ino; 68117752Smckusick fp->fname = savename(dp->d_name); 68217752Smckusick fp++; 68317752Smckusick if (fp == *pfplast) { 68417752Smckusick basefp = (struct afile *)realloc((char *)basefp, 68517752Smckusick (unsigned)(2 * nent * sizeof (struct afile))); 68617752Smckusick if (basefp == 0) { 68717752Smckusick fprintf(stderr, "ls: out of memory\n"); 68817752Smckusick return (FAIL); 68917752Smckusick } 69017752Smckusick *pfp0 = basefp; 69117752Smckusick fp = *pfp0 + nent; 69217752Smckusick *pfplast = fp + nent; 69317752Smckusick nent *= 2; 69417752Smckusick } 69517752Smckusick } 69617752Smckusick *pfplast = fp; 69717752Smckusick return (GOOD); 69817752Smckusick } 69917752Smckusick 70017752Smckusick /* 70117752Smckusick * Print out a pretty listing of a directory 70217752Smckusick */ 70317752Smckusick formatf(fp0, fplast) 70417752Smckusick struct afile *fp0, *fplast; 70517752Smckusick { 70617752Smckusick register struct afile *fp; 70717752Smckusick struct entry *np; 70817752Smckusick int width = 0, w, nentry = fplast - fp0; 70917752Smckusick int i, j, len, columns, lines; 71017752Smckusick char *cp; 71117752Smckusick 71217752Smckusick if (fp0 == fplast) 71317752Smckusick return; 71417752Smckusick for (fp = fp0; fp < fplast; fp++) { 71517752Smckusick fp->ftype = inodetype(fp->fnum); 71617752Smckusick np = lookupino(fp->fnum); 71717752Smckusick if (np != NIL) 71817752Smckusick fp->fflags = np->e_flags; 71917752Smckusick else 72017752Smckusick fp->fflags = 0; 72117752Smckusick len = strlen(fmtentry(fp)); 72217752Smckusick if (len > width) 72317752Smckusick width = len; 72417752Smckusick } 72517752Smckusick width += 2; 72617752Smckusick columns = 80 / width; 72717752Smckusick if (columns == 0) 72817752Smckusick columns = 1; 72917752Smckusick lines = (nentry + columns - 1) / columns; 73017752Smckusick for (i = 0; i < lines; i++) { 73117752Smckusick for (j = 0; j < columns; j++) { 73217752Smckusick fp = fp0 + j * lines + i; 73317752Smckusick cp = fmtentry(fp); 73417752Smckusick fprintf(stderr, "%s", cp); 73517752Smckusick if (fp + lines >= fplast) { 73617752Smckusick fprintf(stderr, "\n"); 73717752Smckusick break; 73817752Smckusick } 73917752Smckusick w = strlen(cp); 74017752Smckusick while (w < width) { 74117752Smckusick w++; 74217752Smckusick fprintf(stderr, " "); 74317752Smckusick } 74417752Smckusick } 74517752Smckusick } 74617752Smckusick } 74717752Smckusick 74817752Smckusick /* 74917752Smckusick * Comparison routine for qsort. 75017752Smckusick */ 75117752Smckusick fcmp(f1, f2) 75217752Smckusick register struct afile *f1, *f2; 75317752Smckusick { 75417752Smckusick 75517752Smckusick return (strcmp(f1->fname, f2->fname)); 75617752Smckusick } 75717752Smckusick 75817752Smckusick /* 75917752Smckusick * Format a directory entry. 76017752Smckusick */ 76117752Smckusick char * 76217752Smckusick fmtentry(fp) 76317752Smckusick register struct afile *fp; 76417752Smckusick { 76517752Smckusick static char fmtres[BUFSIZ]; 76617752Smckusick register char *cp, *dp; 76717752Smckusick 76817752Smckusick if (vflag) 76917752Smckusick (void) sprintf(fmtres, "%5d ", fp->fnum); 77017752Smckusick else 77117752Smckusick fmtres[0] = '\0'; 77217752Smckusick dp = &fmtres[strlen(fmtres)]; 77317752Smckusick if (dflag && BIT(fp->fnum, dumpmap) == 0) 77417752Smckusick *dp++ = '^'; 77517752Smckusick else if ((fp->fflags & NEW) != 0) 77617752Smckusick *dp++ = '*'; 77717752Smckusick else 77817752Smckusick *dp++ = ' '; 77917752Smckusick for (cp = fp->fname; *cp; cp++) 78017752Smckusick if (!vflag && (*cp < ' ' || *cp >= 0177)) 78117752Smckusick *dp++ = '?'; 78217752Smckusick else 78317752Smckusick *dp++ = *cp; 78417752Smckusick if (fp->ftype == NODE) 78517752Smckusick *dp++ = '/'; 78617752Smckusick *dp++ = 0; 78717752Smckusick return (fmtres); 78817752Smckusick } 78917752Smckusick 79017752Smckusick /* 79117752Smckusick * respond to interrupts 79217752Smckusick */ 79317752Smckusick onintr() 79417752Smckusick { 79517752Smckusick if (command == 'i') 79617752Smckusick longjmp(reset, 1); 79717752Smckusick if (reply("restore interrupted, continue") == FAIL) 79817752Smckusick done(1); 79917752Smckusick } 800