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