|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1985 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that: (1) source distributions retain this entire copyright ! 7: * notice and comment, and (2) distributions including binaries display ! 8: * the following acknowledgement: ``This product includes software ! 9: * developed by the University of California, Berkeley and its contributors'' ! 10: * in the documentation or other materials provided with the distribution ! 11: * and in all advertising materials mentioning features or use of this ! 12: * software. Neither the name of the University nor the names of its ! 13: * contributors may be used to endorse or promote products derived ! 14: * from this software without specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: static char sccsid[] = "@(#)interactive.c 5.9 (Berkeley) 6/1/90"; ! 22: #endif /* not lint */ ! 23: ! 24: #include "restore.h" ! 25: #include <protocols/dumprestore.h> ! 26: #include <setjmp.h> ! 27: #include <ufs/dir.h> ! 28: ! 29: #define round(a, b) (((a) + (b) - 1) / (b) * (b)) ! 30: ! 31: /* ! 32: * Things to handle interruptions. ! 33: */ ! 34: static jmp_buf reset; ! 35: static char *nextarg = NULL; ! 36: ! 37: /* ! 38: * Structure and routines associated with listing directories. ! 39: */ ! 40: struct afile { ! 41: ino_t fnum; /* inode number of file */ ! 42: char *fname; /* file name */ ! 43: short fflags; /* extraction flags, if any */ ! 44: char ftype; /* file type, e.g. LEAF or NODE */ ! 45: }; ! 46: struct arglist { ! 47: struct afile *head; /* start of argument list */ ! 48: struct afile *last; /* end of argument list */ ! 49: struct afile *base; /* current list arena */ ! 50: int nent; /* maximum size of list */ ! 51: char *cmd; /* the current command */ ! 52: }; ! 53: extern int fcmp(); ! 54: extern char *fmtentry(); ! 55: char *copynext(); ! 56: ! 57: /* ! 58: * Read and execute commands from the terminal. ! 59: */ ! 60: runcmdshell() ! 61: { ! 62: register struct entry *np; ! 63: ino_t ino; ! 64: static struct arglist alist = { 0, 0, 0, 0, 0 }; ! 65: char curdir[MAXPATHLEN]; ! 66: char name[MAXPATHLEN]; ! 67: char cmd[BUFSIZ]; ! 68: ! 69: canon("/", curdir); ! 70: loop: ! 71: if (setjmp(reset) != 0) { ! 72: for (; alist.head < alist.last; alist.head++) ! 73: freename(alist.head->fname); ! 74: nextarg = NULL; ! 75: volno = 0; ! 76: } ! 77: getcmd(curdir, cmd, name, &alist); ! 78: switch (cmd[0]) { ! 79: /* ! 80: * Add elements to the extraction list. ! 81: */ ! 82: case 'a': ! 83: if (strncmp(cmd, "add", strlen(cmd)) != 0) ! 84: goto bad; ! 85: ino = dirlookup(name); ! 86: if (ino == 0) ! 87: break; ! 88: if (mflag) ! 89: pathcheck(name); ! 90: treescan(name, ino, addfile); ! 91: break; ! 92: /* ! 93: * Change working directory. ! 94: */ ! 95: case 'c': ! 96: if (strncmp(cmd, "cd", strlen(cmd)) != 0) ! 97: goto bad; ! 98: ino = dirlookup(name); ! 99: if (ino == 0) ! 100: break; ! 101: if (inodetype(ino) == LEAF) { ! 102: fprintf(stderr, "%s: not a directory\n", name); ! 103: break; ! 104: } ! 105: (void) strcpy(curdir, name); ! 106: break; ! 107: /* ! 108: * Delete elements from the extraction list. ! 109: */ ! 110: case 'd': ! 111: if (strncmp(cmd, "delete", strlen(cmd)) != 0) ! 112: goto bad; ! 113: np = lookupname(name); ! 114: if (np == NIL || (np->e_flags & NEW) == 0) { ! 115: fprintf(stderr, "%s: not on extraction list\n", name); ! 116: break; ! 117: } ! 118: treescan(name, np->e_ino, deletefile); ! 119: break; ! 120: /* ! 121: * Extract the requested list. ! 122: */ ! 123: case 'e': ! 124: if (strncmp(cmd, "extract", strlen(cmd)) != 0) ! 125: goto bad; ! 126: createfiles(); ! 127: createlinks(); ! 128: setdirmodes(); ! 129: if (dflag) ! 130: checkrestore(); ! 131: volno = 0; ! 132: break; ! 133: /* ! 134: * List available commands. ! 135: */ ! 136: case 'h': ! 137: if (strncmp(cmd, "help", strlen(cmd)) != 0) ! 138: goto bad; ! 139: case '?': ! 140: fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", ! 141: "Available commands are:\n", ! 142: "\tls [arg] - list directory\n", ! 143: "\tcd arg - change directory\n", ! 144: "\tpwd - print current directory\n", ! 145: "\tadd [arg] - add `arg' to list of", ! 146: " files to be extracted\n", ! 147: "\tdelete [arg] - delete `arg' from", ! 148: " list of files to be extracted\n", ! 149: "\textract - extract requested files\n", ! 150: "\tsetmodes - set modes of requested directories\n", ! 151: "\tquit - immediately exit program\n", ! 152: "\twhat - list dump header information\n", ! 153: "\tverbose - toggle verbose flag", ! 154: " (useful with ``ls'')\n", ! 155: "\thelp or `?' - print this list\n", ! 156: "If no `arg' is supplied, the current", ! 157: " directory is used\n"); ! 158: break; ! 159: /* ! 160: * List a directory. ! 161: */ ! 162: case 'l': ! 163: if (strncmp(cmd, "ls", strlen(cmd)) != 0) ! 164: goto bad; ! 165: ino = dirlookup(name); ! 166: if (ino == 0) ! 167: break; ! 168: printlist(name, ino, curdir); ! 169: break; ! 170: /* ! 171: * Print current directory. ! 172: */ ! 173: case 'p': ! 174: if (strncmp(cmd, "pwd", strlen(cmd)) != 0) ! 175: goto bad; ! 176: if (curdir[1] == '\0') ! 177: fprintf(stderr, "/\n"); ! 178: else ! 179: fprintf(stderr, "%s\n", &curdir[1]); ! 180: break; ! 181: /* ! 182: * Quit. ! 183: */ ! 184: case 'q': ! 185: if (strncmp(cmd, "quit", strlen(cmd)) != 0) ! 186: goto bad; ! 187: return; ! 188: case 'x': ! 189: if (strncmp(cmd, "xit", strlen(cmd)) != 0) ! 190: goto bad; ! 191: return; ! 192: /* ! 193: * Toggle verbose mode. ! 194: */ ! 195: case 'v': ! 196: if (strncmp(cmd, "verbose", strlen(cmd)) != 0) ! 197: goto bad; ! 198: if (vflag) { ! 199: fprintf(stderr, "verbose mode off\n"); ! 200: vflag = 0; ! 201: break; ! 202: } ! 203: fprintf(stderr, "verbose mode on\n"); ! 204: vflag++; ! 205: break; ! 206: /* ! 207: * Just restore requested directory modes. ! 208: */ ! 209: case 's': ! 210: if (strncmp(cmd, "setmodes", strlen(cmd)) != 0) ! 211: goto bad; ! 212: setdirmodes(); ! 213: break; ! 214: /* ! 215: * Print out dump header information. ! 216: */ ! 217: case 'w': ! 218: if (strncmp(cmd, "what", strlen(cmd)) != 0) ! 219: goto bad; ! 220: printdumpinfo(); ! 221: break; ! 222: /* ! 223: * Turn on debugging. ! 224: */ ! 225: case 'D': ! 226: if (strncmp(cmd, "Debug", strlen(cmd)) != 0) ! 227: goto bad; ! 228: if (dflag) { ! 229: fprintf(stderr, "debugging mode off\n"); ! 230: dflag = 0; ! 231: break; ! 232: } ! 233: fprintf(stderr, "debugging mode on\n"); ! 234: dflag++; ! 235: break; ! 236: /* ! 237: * Unknown command. ! 238: */ ! 239: default: ! 240: bad: ! 241: fprintf(stderr, "%s: unknown command; type ? for help\n", cmd); ! 242: break; ! 243: } ! 244: goto loop; ! 245: } ! 246: ! 247: /* ! 248: * Read and parse an interactive command. ! 249: * The first word on the line is assigned to "cmd". If ! 250: * there are no arguments on the command line, then "curdir" ! 251: * is returned as the argument. If there are arguments ! 252: * on the line they are returned one at a time on each ! 253: * successive call to getcmd. Each argument is first assigned ! 254: * to "name". If it does not start with "/" the pathname in ! 255: * "curdir" is prepended to it. Finally "canon" is called to ! 256: * eliminate any embedded ".." components. ! 257: */ ! 258: getcmd(curdir, cmd, name, ap) ! 259: char *curdir, *cmd, *name; ! 260: struct arglist *ap; ! 261: { ! 262: register char *cp; ! 263: static char input[BUFSIZ]; ! 264: char output[BUFSIZ]; ! 265: # define rawname input /* save space by reusing input buffer */ ! 266: ! 267: /* ! 268: * Check to see if still processing arguments. ! 269: */ ! 270: if (ap->head != ap->last) { ! 271: strcpy(name, ap->head->fname); ! 272: freename(ap->head->fname); ! 273: ap->head++; ! 274: return; ! 275: } ! 276: if (nextarg != NULL) ! 277: goto getnext; ! 278: /* ! 279: * Read a command line and trim off trailing white space. ! 280: */ ! 281: do { ! 282: fprintf(stderr, "restore > "); ! 283: (void) fflush(stderr); ! 284: (void) fgets(input, BUFSIZ, terminal); ! 285: } while (!feof(terminal) && input[0] == '\n'); ! 286: if (feof(terminal)) { ! 287: (void) strcpy(cmd, "quit"); ! 288: return; ! 289: } ! 290: for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--) ! 291: /* trim off trailing white space and newline */; ! 292: *++cp = '\0'; ! 293: /* ! 294: * Copy the command into "cmd". ! 295: */ ! 296: cp = copynext(input, cmd); ! 297: ap->cmd = cmd; ! 298: /* ! 299: * If no argument, use curdir as the default. ! 300: */ ! 301: if (*cp == '\0') { ! 302: (void) strcpy(name, curdir); ! 303: return; ! 304: } ! 305: nextarg = cp; ! 306: /* ! 307: * Find the next argument. ! 308: */ ! 309: getnext: ! 310: cp = copynext(nextarg, rawname); ! 311: if (*cp == '\0') ! 312: nextarg = NULL; ! 313: else ! 314: nextarg = cp; ! 315: /* ! 316: * If it an absolute pathname, canonicalize it and return it. ! 317: */ ! 318: if (rawname[0] == '/') { ! 319: canon(rawname, name); ! 320: } else { ! 321: /* ! 322: * For relative pathnames, prepend the current directory to ! 323: * it then canonicalize and return it. ! 324: */ ! 325: (void) strcpy(output, curdir); ! 326: (void) strcat(output, "/"); ! 327: (void) strcat(output, rawname); ! 328: canon(output, name); ! 329: } ! 330: expandarg(name, ap); ! 331: strcpy(name, ap->head->fname); ! 332: freename(ap->head->fname); ! 333: ap->head++; ! 334: # undef rawname ! 335: } ! 336: ! 337: /* ! 338: * Strip off the next token of the input. ! 339: */ ! 340: char * ! 341: copynext(input, output) ! 342: char *input, *output; ! 343: { ! 344: register char *cp, *bp; ! 345: char quote; ! 346: ! 347: for (cp = input; *cp == ' ' || *cp == '\t'; cp++) ! 348: /* skip to argument */; ! 349: bp = output; ! 350: while (*cp != ' ' && *cp != '\t' && *cp != '\0') { ! 351: /* ! 352: * Handle back slashes. ! 353: */ ! 354: if (*cp == '\\') { ! 355: if (*++cp == '\0') { ! 356: fprintf(stderr, ! 357: "command lines cannot be continued\n"); ! 358: continue; ! 359: } ! 360: *bp++ = *cp++; ! 361: continue; ! 362: } ! 363: /* ! 364: * The usual unquoted case. ! 365: */ ! 366: if (*cp != '\'' && *cp != '"') { ! 367: *bp++ = *cp++; ! 368: continue; ! 369: } ! 370: /* ! 371: * Handle single and double quotes. ! 372: */ ! 373: quote = *cp++; ! 374: while (*cp != quote && *cp != '\0') ! 375: *bp++ = *cp++ | 0200; ! 376: if (*cp++ == '\0') { ! 377: fprintf(stderr, "missing %c\n", quote); ! 378: cp--; ! 379: continue; ! 380: } ! 381: } ! 382: *bp = '\0'; ! 383: return (cp); ! 384: } ! 385: ! 386: /* ! 387: * Canonicalize file names to always start with ``./'' and ! 388: * remove any imbedded "." and ".." components. ! 389: */ ! 390: canon(rawname, canonname) ! 391: char *rawname, *canonname; ! 392: { ! 393: register char *cp, *np; ! 394: int len; ! 395: ! 396: if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0) ! 397: (void) strcpy(canonname, ""); ! 398: else if (rawname[0] == '/') ! 399: (void) strcpy(canonname, "."); ! 400: else ! 401: (void) strcpy(canonname, "./"); ! 402: (void) strcat(canonname, rawname); ! 403: /* ! 404: * Eliminate multiple and trailing '/'s ! 405: */ ! 406: for (cp = np = canonname; *np != '\0'; cp++) { ! 407: *cp = *np++; ! 408: while (*cp == '/' && *np == '/') ! 409: np++; ! 410: } ! 411: *cp = '\0'; ! 412: if (*--cp == '/') ! 413: *cp = '\0'; ! 414: /* ! 415: * Eliminate extraneous "." and ".." from pathnames. ! 416: */ ! 417: for (np = canonname; *np != '\0'; ) { ! 418: np++; ! 419: cp = np; ! 420: while (*np != '/' && *np != '\0') ! 421: np++; ! 422: if (np - cp == 1 && *cp == '.') { ! 423: cp--; ! 424: (void) strcpy(cp, np); ! 425: np = cp; ! 426: } ! 427: if (np - cp == 2 && strncmp(cp, "..", 2) == 0) { ! 428: cp--; ! 429: while (cp > &canonname[1] && *--cp != '/') ! 430: /* find beginning of name */; ! 431: (void) strcpy(cp, np); ! 432: np = cp; ! 433: } ! 434: } ! 435: } ! 436: ! 437: /* ! 438: * globals (file name generation) ! 439: * ! 440: * "*" in params matches r.e ".*" ! 441: * "?" in params matches r.e. "." ! 442: * "[...]" in params matches character class ! 443: * "[...a-z...]" in params matches a through z. ! 444: */ ! 445: expandarg(arg, ap) ! 446: char *arg; ! 447: register struct arglist *ap; ! 448: { ! 449: static struct afile single; ! 450: struct entry *ep; ! 451: int size; ! 452: ! 453: ap->head = ap->last = (struct afile *)0; ! 454: size = expand(arg, 0, ap); ! 455: if (size == 0) { ! 456: ep = lookupname(arg); ! 457: single.fnum = ep ? ep->e_ino : 0; ! 458: single.fname = savename(arg); ! 459: ap->head = &single; ! 460: ap->last = ap->head + 1; ! 461: return; ! 462: } ! 463: qsort((char *)ap->head, ap->last - ap->head, sizeof *ap->head, fcmp); ! 464: } ! 465: ! 466: /* ! 467: * Expand a file name ! 468: */ ! 469: expand(as, rflg, ap) ! 470: char *as; ! 471: int rflg; ! 472: register struct arglist *ap; ! 473: { ! 474: int count, size; ! 475: char dir = 0; ! 476: char *rescan = 0; ! 477: DIR *dirp; ! 478: register char *s, *cs; ! 479: int sindex, rindex, lindex; ! 480: struct direct *dp; ! 481: register char slash; ! 482: register char *rs; ! 483: register char c; ! 484: ! 485: /* ! 486: * check for meta chars ! 487: */ ! 488: s = cs = as; ! 489: slash = 0; ! 490: while (*cs != '*' && *cs != '?' && *cs != '[') { ! 491: if (*cs++ == 0) { ! 492: if (rflg && slash) ! 493: break; ! 494: else ! 495: return (0) ; ! 496: } else if (*cs == '/') { ! 497: slash++; ! 498: } ! 499: } ! 500: for (;;) { ! 501: if (cs == s) { ! 502: s = ""; ! 503: break; ! 504: } else if (*--cs == '/') { ! 505: *cs = 0; ! 506: if (s == cs) ! 507: s = "/"; ! 508: break; ! 509: } ! 510: } ! 511: if ((dirp = rst_opendir(s)) != NULL) ! 512: dir++; ! 513: count = 0; ! 514: if (*cs == 0) ! 515: *cs++ = 0200; ! 516: if (dir) { ! 517: /* ! 518: * check for rescan ! 519: */ ! 520: rs = cs; ! 521: do { ! 522: if (*rs == '/') { ! 523: rescan = rs; ! 524: *rs = 0; ! 525: } ! 526: } while (*rs++); ! 527: sindex = ap->last - ap->head; ! 528: while ((dp = rst_readdir(dirp)) != NULL && dp->d_ino != 0) { ! 529: if (!dflag && BIT(dp->d_ino, dumpmap) == 0) ! 530: continue; ! 531: if ((*dp->d_name == '.' && *cs != '.')) ! 532: continue; ! 533: if (gmatch(dp->d_name, cs)) { ! 534: if (addg(dp, s, rescan, ap) < 0) ! 535: return (-1); ! 536: count++; ! 537: } ! 538: } ! 539: if (rescan) { ! 540: rindex = sindex; ! 541: lindex = ap->last - ap->head; ! 542: if (count) { ! 543: count = 0; ! 544: while (rindex < lindex) { ! 545: size = expand(ap->head[rindex].fname, ! 546: 1, ap); ! 547: if (size < 0) ! 548: return (size); ! 549: count += size; ! 550: rindex++; ! 551: } ! 552: } ! 553: bcopy((char *)&ap->head[lindex], ! 554: (char *)&ap->head[sindex], ! 555: (ap->last - &ap->head[rindex]) * sizeof *ap->head); ! 556: ap->last -= lindex - sindex; ! 557: *rescan = '/'; ! 558: } ! 559: } ! 560: s = as; ! 561: while (c = *s) ! 562: *s++ = (c&0177 ? c : '/'); ! 563: return (count); ! 564: } ! 565: ! 566: /* ! 567: * Check for a name match ! 568: */ ! 569: gmatch(s, p) ! 570: register char *s, *p; ! 571: { ! 572: register int scc; ! 573: char c; ! 574: char ok; ! 575: int lc; ! 576: ! 577: if (scc = *s++) ! 578: if ((scc &= 0177) == 0) ! 579: scc = 0200; ! 580: switch (c = *p++) { ! 581: ! 582: case '[': ! 583: ok = 0; ! 584: lc = 077777; ! 585: while (c = *p++) { ! 586: if (c == ']') { ! 587: return (ok ? gmatch(s, p) : 0); ! 588: } else if (c == '-') { ! 589: if (lc <= scc && scc <= (*p++)) ! 590: ok++ ; ! 591: } else { ! 592: if (scc == (lc = (c&0177))) ! 593: ok++ ; ! 594: } ! 595: } ! 596: return (0); ! 597: ! 598: default: ! 599: if ((c&0177) != scc) ! 600: return (0) ; ! 601: /* falls through */ ! 602: ! 603: case '?': ! 604: return (scc ? gmatch(s, p) : 0); ! 605: ! 606: case '*': ! 607: if (*p == 0) ! 608: return (1) ; ! 609: s--; ! 610: while (*s) { ! 611: if (gmatch(s++, p)) ! 612: return (1); ! 613: } ! 614: return (0); ! 615: ! 616: case 0: ! 617: return (scc == 0); ! 618: } ! 619: } ! 620: ! 621: /* ! 622: * Construct a matched name. ! 623: */ ! 624: addg(dp, as1, as3, ap) ! 625: struct direct *dp; ! 626: char *as1, *as3; ! 627: struct arglist *ap; ! 628: { ! 629: register char *s1, *s2; ! 630: register int c; ! 631: char buf[BUFSIZ]; ! 632: ! 633: s2 = buf; ! 634: s1 = as1; ! 635: while (c = *s1++) { ! 636: if ((c &= 0177) == 0) { ! 637: *s2++ = '/'; ! 638: break; ! 639: } ! 640: *s2++ = c; ! 641: } ! 642: s1 = dp->d_name; ! 643: while (*s2 = *s1++) ! 644: s2++; ! 645: if (s1 = as3) { ! 646: *s2++ = '/'; ! 647: while (*s2++ = *++s1) ! 648: /* void */; ! 649: } ! 650: if (mkentry(buf, dp->d_ino, ap) == FAIL) ! 651: return (-1); ! 652: } ! 653: ! 654: /* ! 655: * Do an "ls" style listing of a directory ! 656: */ ! 657: printlist(name, ino, basename) ! 658: char *name; ! 659: ino_t ino; ! 660: char *basename; ! 661: { ! 662: register struct afile *fp; ! 663: register struct direct *dp; ! 664: static struct arglist alist = { 0, 0, 0, 0, "ls" }; ! 665: struct afile single; ! 666: DIR *dirp; ! 667: ! 668: if ((dirp = rst_opendir(name)) == NULL) { ! 669: single.fnum = ino; ! 670: single.fname = savename(name + strlen(basename) + 1); ! 671: alist.head = &single; ! 672: alist.last = alist.head + 1; ! 673: } else { ! 674: alist.head = (struct afile *)0; ! 675: fprintf(stderr, "%s:\n", name); ! 676: while (dp = rst_readdir(dirp)) { ! 677: if (dp == NULL || dp->d_ino == 0) ! 678: break; ! 679: if (!dflag && BIT(dp->d_ino, dumpmap) == 0) ! 680: continue; ! 681: if (vflag == 0 && ! 682: (strcmp(dp->d_name, ".") == 0 || ! 683: strcmp(dp->d_name, "..") == 0)) ! 684: continue; ! 685: if (!mkentry(dp->d_name, dp->d_ino, &alist)) ! 686: return; ! 687: } ! 688: } ! 689: if (alist.head != 0) { ! 690: qsort((char *)alist.head, alist.last - alist.head, ! 691: sizeof *alist.head, fcmp); ! 692: formatf(&alist); ! 693: for (fp = alist.head; fp < alist.last; fp++) ! 694: freename(fp->fname); ! 695: } ! 696: if (dirp != NULL) ! 697: fprintf(stderr, "\n"); ! 698: } ! 699: ! 700: /* ! 701: * Read the contents of a directory. ! 702: */ ! 703: mkentry(name, ino, ap) ! 704: char *name; ! 705: ino_t ino; ! 706: register struct arglist *ap; ! 707: { ! 708: register struct afile *fp; ! 709: ! 710: if (ap->base == NULL) { ! 711: ap->nent = 20; ! 712: ap->base = (struct afile *)calloc((unsigned)ap->nent, ! 713: sizeof (struct afile)); ! 714: if (ap->base == NULL) { ! 715: fprintf(stderr, "%s: out of memory\n", ap->cmd); ! 716: return (FAIL); ! 717: } ! 718: } ! 719: if (ap->head == 0) ! 720: ap->head = ap->last = ap->base; ! 721: fp = ap->last; ! 722: fp->fnum = ino; ! 723: fp->fname = savename(name); ! 724: fp++; ! 725: if (fp == ap->head + ap->nent) { ! 726: ap->base = (struct afile *)realloc((char *)ap->base, ! 727: (unsigned)(2 * ap->nent * sizeof (struct afile))); ! 728: if (ap->base == 0) { ! 729: fprintf(stderr, "%s: out of memory\n", ap->cmd); ! 730: return (FAIL); ! 731: } ! 732: ap->head = ap->base; ! 733: fp = ap->head + ap->nent; ! 734: ap->nent *= 2; ! 735: } ! 736: ap->last = fp; ! 737: return (GOOD); ! 738: } ! 739: ! 740: /* ! 741: * Print out a pretty listing of a directory ! 742: */ ! 743: formatf(ap) ! 744: register struct arglist *ap; ! 745: { ! 746: register struct afile *fp; ! 747: struct entry *np; ! 748: int width = 0, w, nentry = ap->last - ap->head; ! 749: int i, j, len, columns, lines; ! 750: char *cp; ! 751: ! 752: if (ap->head == ap->last) ! 753: return; ! 754: for (fp = ap->head; fp < ap->last; fp++) { ! 755: fp->ftype = inodetype(fp->fnum); ! 756: np = lookupino(fp->fnum); ! 757: if (np != NIL) ! 758: fp->fflags = np->e_flags; ! 759: else ! 760: fp->fflags = 0; ! 761: len = strlen(fmtentry(fp)); ! 762: if (len > width) ! 763: width = len; ! 764: } ! 765: width += 2; ! 766: columns = 80 / width; ! 767: if (columns == 0) ! 768: columns = 1; ! 769: lines = (nentry + columns - 1) / columns; ! 770: for (i = 0; i < lines; i++) { ! 771: for (j = 0; j < columns; j++) { ! 772: fp = ap->head + j * lines + i; ! 773: cp = fmtentry(fp); ! 774: fprintf(stderr, "%s", cp); ! 775: if (fp + lines >= ap->last) { ! 776: fprintf(stderr, "\n"); ! 777: break; ! 778: } ! 779: w = strlen(cp); ! 780: while (w < width) { ! 781: w++; ! 782: fprintf(stderr, " "); ! 783: } ! 784: } ! 785: } ! 786: } ! 787: ! 788: /* ! 789: * Comparison routine for qsort. ! 790: */ ! 791: fcmp(f1, f2) ! 792: register struct afile *f1, *f2; ! 793: { ! 794: ! 795: return (strcmp(f1->fname, f2->fname)); ! 796: } ! 797: ! 798: /* ! 799: * Format a directory entry. ! 800: */ ! 801: char * ! 802: fmtentry(fp) ! 803: register struct afile *fp; ! 804: { ! 805: static char fmtres[BUFSIZ]; ! 806: static int precision = 0; ! 807: int i; ! 808: register char *cp, *dp; ! 809: ! 810: if (!vflag) { ! 811: fmtres[0] = '\0'; ! 812: } else { ! 813: if (precision == 0) ! 814: for (i = maxino; i > 0; i /= 10) ! 815: precision++; ! 816: (void) sprintf(fmtres, "%*d ", precision, fp->fnum); ! 817: } ! 818: dp = &fmtres[strlen(fmtres)]; ! 819: if (dflag && BIT(fp->fnum, dumpmap) == 0) ! 820: *dp++ = '^'; ! 821: else if ((fp->fflags & NEW) != 0) ! 822: *dp++ = '*'; ! 823: else ! 824: *dp++ = ' '; ! 825: for (cp = fp->fname; *cp; cp++) ! 826: if (!vflag && (*cp < ' ' || *cp >= 0177)) ! 827: *dp++ = '?'; ! 828: else ! 829: *dp++ = *cp; ! 830: if (fp->ftype == NODE) ! 831: *dp++ = '/'; ! 832: *dp++ = 0; ! 833: return (fmtres); ! 834: } ! 835: ! 836: /* ! 837: * respond to interrupts ! 838: */ ! 839: void ! 840: onintr() ! 841: { ! 842: if (command == 'i') ! 843: longjmp(reset, 1); ! 844: if (reply("restore interrupted, continue") == FAIL) ! 845: done(1); ! 846: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.