|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)utilities.c 3.15 (Berkeley) 83/08/11"; ! 3: #endif ! 4: ! 5: /* Copyright (c) 1983 Regents of the University of California */ ! 6: ! 7: #include "restore.h" ! 8: ! 9: char *copynext(); ! 10: ! 11: /* ! 12: * Insure that all the components of a pathname exist. ! 13: */ ! 14: pathcheck(name) ! 15: char *name; ! 16: { ! 17: register char *cp; ! 18: struct entry *ep; ! 19: char *start; ! 20: ! 21: start = index(name, '/'); ! 22: if (start == 0) ! 23: return; ! 24: for (cp = start; *cp != '\0'; cp++) { ! 25: if (*cp != '/') ! 26: continue; ! 27: *cp = '\0'; ! 28: ep = lookupname(name); ! 29: if (ep == NIL) { ! 30: ep = addentry(name, psearch(name), NODE); ! 31: newnode(ep); ! 32: ep->e_flags |= NEW|KEEP; ! 33: } ! 34: *cp = '/'; ! 35: } ! 36: } ! 37: ! 38: /* ! 39: * Change a name to a unique temporary name. ! 40: */ ! 41: mktempname(ep) ! 42: register struct entry *ep; ! 43: { ! 44: char oldname[MAXPATHLEN]; ! 45: ! 46: if (ep->e_flags & TMPNAME) ! 47: badentry(ep, "mktempname: called with TMPNAME"); ! 48: ep->e_flags |= TMPNAME; ! 49: (void) strcpy(oldname, myname(ep)); ! 50: freename(ep->e_name); ! 51: ep->e_name = savename(gentempname(ep)); ! 52: ep->e_namlen = strlen(ep->e_name); ! 53: renameit(oldname, myname(ep)); ! 54: } ! 55: ! 56: /* ! 57: * Generate a temporary name for an entry. ! 58: */ ! 59: char * ! 60: gentempname(ep) ! 61: struct entry *ep; ! 62: { ! 63: static char name[MAXPATHLEN]; ! 64: struct entry *np; ! 65: long i = 0; ! 66: ! 67: for (np = lookupino(ep->e_ino); np != NIL && np != ep; np = np->e_links) ! 68: i++; ! 69: if (np == NIL) ! 70: badentry(ep, "not on ino list"); ! 71: (void) sprintf(name, "%s%d%d", TMPHDR, i, ep->e_ino); ! 72: return (name); ! 73: } ! 74: ! 75: /* ! 76: * Rename a file or directory. ! 77: */ ! 78: renameit(from, to) ! 79: char *from, *to; ! 80: { ! 81: if (rename(from, to) < 0) { ! 82: fprintf(stderr, "Warning: cannot rename %s to %s", from, to); ! 83: (void) fflush(stderr); ! 84: perror(""); ! 85: return; ! 86: } ! 87: vprintf(stdout, "rename %s to %s\n", from, to); ! 88: } ! 89: ! 90: /* ! 91: * Create a new node (directory). ! 92: */ ! 93: newnode(np) ! 94: struct entry *np; ! 95: { ! 96: char *cp; ! 97: ! 98: if (np->e_type != NODE) ! 99: badentry(np, "newnode: not a node"); ! 100: cp = myname(np); ! 101: if (mkdir(cp, 0777) < 0) { ! 102: fprintf(stderr, "Warning: "); ! 103: (void) fflush(stderr); ! 104: perror(cp); ! 105: return; ! 106: } ! 107: vprintf(stdout, "Make node %s\n", cp); ! 108: } ! 109: ! 110: /* ! 111: * Remove an old node (directory). ! 112: */ ! 113: removenode(ep) ! 114: register struct entry *ep; ! 115: { ! 116: char *cp; ! 117: ! 118: if (ep->e_type != NODE) ! 119: badentry(ep, "removenode: not a node"); ! 120: if (ep->e_entries != NIL) ! 121: badentry(ep, "removenode: non-empty directory"); ! 122: ep->e_flags |= REMOVED; ! 123: ep->e_flags &= ~TMPNAME; ! 124: cp = myname(ep); ! 125: if (rmdir(cp) < 0) { ! 126: fprintf(stderr, "Warning: "); ! 127: (void) fflush(stderr); ! 128: perror(cp); ! 129: return; ! 130: } ! 131: vprintf(stdout, "Remove node %s\n", cp); ! 132: } ! 133: ! 134: /* ! 135: * Remove a leaf. ! 136: */ ! 137: removeleaf(ep) ! 138: register struct entry *ep; ! 139: { ! 140: char *cp; ! 141: ! 142: if (ep->e_type != LEAF) ! 143: badentry(ep, "removeleaf: not a leaf"); ! 144: ep->e_flags |= REMOVED; ! 145: ep->e_flags &= ~TMPNAME; ! 146: cp = myname(ep); ! 147: if (unlink(cp) < 0) { ! 148: fprintf(stderr, "Warning: "); ! 149: (void) fflush(stderr); ! 150: perror(cp); ! 151: return; ! 152: } ! 153: vprintf(stdout, "Remove leaf %s\n", cp); ! 154: } ! 155: ! 156: /* ! 157: * Create a link. ! 158: */ ! 159: linkit(existing, new, type) ! 160: char *existing, *new; ! 161: int type; ! 162: { ! 163: ! 164: if (type == SYMLINK) { ! 165: if (symlink(existing, new) < 0) { ! 166: fprintf(stderr, ! 167: "Warning: cannot create symbolic link %s->%s", ! 168: new, existing); ! 169: (void) fflush(stderr); ! 170: perror(""); ! 171: return; ! 172: } ! 173: } else if (type == HARDLINK) { ! 174: if (link(existing, new) < 0) { ! 175: fprintf(stderr, ! 176: "Warning: cannot create hard link %s->%s", ! 177: new, existing); ! 178: (void) fflush(stderr); ! 179: perror(""); ! 180: return; ! 181: } ! 182: } else { ! 183: panic("linkit: unknown type %d\n", type); ! 184: } ! 185: vprintf(stdout, "Create %s link %s->%s\n", ! 186: type == SYMLINK ? "symbolic" : "hard", new, existing); ! 187: } ! 188: ! 189: /* ! 190: * find lowest number file (above "start") that needs to be extracted ! 191: */ ! 192: ino_t ! 193: lowerbnd(start) ! 194: ino_t start; ! 195: { ! 196: register struct entry *ep; ! 197: ! 198: for ( ; start < maxino; start++) { ! 199: ep = lookupino(start); ! 200: if (ep == NIL || ep->e_type == NODE) ! 201: continue; ! 202: if (ep->e_flags & (NEW|EXTRACT)) ! 203: return (start); ! 204: } ! 205: return (start); ! 206: } ! 207: ! 208: /* ! 209: * find highest number file (below "start") that needs to be extracted ! 210: */ ! 211: ino_t ! 212: upperbnd(start) ! 213: ino_t start; ! 214: { ! 215: register struct entry *ep; ! 216: ! 217: for ( ; start > ROOTINO; start--) { ! 218: ep = lookupino(start); ! 219: if (ep == NIL || ep->e_type == NODE) ! 220: continue; ! 221: if (ep->e_flags & (NEW|EXTRACT)) ! 222: return (start); ! 223: } ! 224: return (start); ! 225: } ! 226: ! 227: /* ! 228: * report on a badly formed entry ! 229: */ ! 230: badentry(ep, msg) ! 231: register struct entry *ep; ! 232: char *msg; ! 233: { ! 234: ! 235: fprintf(stderr, "bad entry: %s\n", msg); ! 236: fprintf(stderr, "name: %s\n", myname(ep)); ! 237: fprintf(stderr, "parent name %s\n", myname(ep->e_parent)); ! 238: if (ep->e_sibling != NIL) ! 239: fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling)); ! 240: if (ep->e_entries != NIL) ! 241: fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries)); ! 242: if (ep->e_links != NIL) ! 243: fprintf(stderr, "next link name: %s\n", myname(ep->e_links)); ! 244: if (ep->e_next != NIL) ! 245: fprintf(stderr, "next hashchain name: %s\n", myname(ep->e_next)); ! 246: fprintf(stderr, "entry type: %s\n", ! 247: ep->e_type == NODE ? "NODE" : "LEAF"); ! 248: fprintf(stderr, "inode number: %ld\n", ep->e_ino); ! 249: panic("flags: %s\n", flagvalues(ep)); ! 250: } ! 251: ! 252: /* ! 253: * Construct a string indicating the active flag bits of an entry. ! 254: */ ! 255: char * ! 256: flagvalues(ep) ! 257: register struct entry *ep; ! 258: { ! 259: static char flagbuf[BUFSIZ]; ! 260: ! 261: (void) strcpy(flagbuf, "|NIL"); ! 262: flagbuf[0] = '\0'; ! 263: if (ep->e_flags & REMOVED) ! 264: (void) strcat(flagbuf, "|REMOVED"); ! 265: if (ep->e_flags & TMPNAME) ! 266: (void) strcat(flagbuf, "|TMPNAME"); ! 267: if (ep->e_flags & EXTRACT) ! 268: (void) strcat(flagbuf, "|EXTRACT"); ! 269: if (ep->e_flags & NEW) ! 270: (void) strcat(flagbuf, "|NEW"); ! 271: if (ep->e_flags & KEEP) ! 272: (void) strcat(flagbuf, "|KEEP"); ! 273: return (&flagbuf[1]); ! 274: } ! 275: ! 276: /* ! 277: * Check to see if a name is on a dump tape. ! 278: */ ! 279: ino_t ! 280: dirlookup(name) ! 281: char *name; ! 282: { ! 283: ino_t ino; ! 284: ! 285: ino = psearch(name); ! 286: if (ino == 0 || BIT(ino, dumpmap) == 0) ! 287: fprintf(stderr, "%s is not on tape\n", name); ! 288: return (ino); ! 289: } ! 290: ! 291: /* ! 292: * Canonicalize file names to always start with ``./'' and ! 293: * remove any imbedded ".." components. ! 294: */ ! 295: canon(rawname, canonname) ! 296: char *rawname, *canonname; ! 297: { ! 298: register char *cp, *np; ! 299: int len; ! 300: ! 301: if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0) ! 302: (void) strcpy(canonname, ""); ! 303: else if (rawname[0] == '/') ! 304: (void) strcpy(canonname, "."); ! 305: else ! 306: (void) strcpy(canonname, "./"); ! 307: (void) strcat(canonname, rawname); ! 308: len = strlen(canonname) - 1; ! 309: if (canonname[len] == '/') ! 310: canonname[len] = '\0'; ! 311: /* ! 312: * Eliminate extraneous ".." from pathnames. ! 313: */ ! 314: for (np = canonname; *np != '\0'; ) { ! 315: np++; ! 316: cp = np; ! 317: while (*np != '/' && *np != '\0') ! 318: np++; ! 319: if (np - cp == 2 && strncmp(cp, "..", 2) == 0) { ! 320: cp--; ! 321: while (cp > &canonname[1] && *--cp != '/') ! 322: /* find beginning of name */; ! 323: (void) strcpy(cp, np); ! 324: np = cp; ! 325: } ! 326: } ! 327: } ! 328: ! 329: /* ! 330: * Elicit a reply. ! 331: */ ! 332: reply(question) ! 333: char *question; ! 334: { ! 335: char c; ! 336: ! 337: fprintf(stderr, "%s? ", question); ! 338: do { ! 339: fprintf(stderr, "[yn] "); ! 340: (void) fflush(stderr); ! 341: c = getc(terminal); ! 342: while (c != '\n' && getc(terminal) != '\n') ! 343: /* void */; ! 344: } while (c != 'y' && c != 'n'); ! 345: if (c == 'y') ! 346: return (GOOD); ! 347: return (FAIL); ! 348: } ! 349: ! 350: /* ! 351: * Read and parse an interactive command. ! 352: * The first word on the line is assigned to "cmd". If ! 353: * there are no arguments on the command line, then "curdir" ! 354: * is returned as the argument. If there are arguments ! 355: * on the line they are returned one at a time on each ! 356: * successive call to getcmd. Each argument is first assigned ! 357: * to "name". If it does not start with "/" the pathname in ! 358: * "curdir" is prepended to it. Finally "canon" is called to ! 359: * eliminate any embedded ".." components. ! 360: */ ! 361: getcmd(curdir, cmd, name) ! 362: char *curdir, *cmd, *name; ! 363: { ! 364: register char *cp; ! 365: static char *nextarg = NULL; ! 366: static char input[BUFSIZ]; ! 367: char output[BUFSIZ]; ! 368: # define rawname input /* save space by reusing input buffer */ ! 369: ! 370: /* ! 371: * Check to see if still processing arguments. ! 372: */ ! 373: if (nextarg != NULL) ! 374: goto getnext; ! 375: /* ! 376: * Read a command line and trim off trailing white space. ! 377: */ ! 378: do { ! 379: fprintf(stderr, "restore > "); ! 380: (void) fflush(stderr); ! 381: (void) fgets(input, BUFSIZ, terminal); ! 382: } while (!feof(terminal) && input[0] == '\n'); ! 383: if (feof(terminal)) { ! 384: (void) strcpy(cmd, "quit"); ! 385: return; ! 386: } ! 387: for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--) ! 388: /* trim off trailing white space and newline */; ! 389: *++cp = '\0'; ! 390: /* ! 391: * Copy the command into "cmd". ! 392: */ ! 393: cp = copynext(input, cmd); ! 394: /* ! 395: * If no argument, use curdir as the default. ! 396: */ ! 397: if (*cp == '\0') { ! 398: (void) strcpy(name, curdir); ! 399: return; ! 400: } ! 401: nextarg = cp; ! 402: /* ! 403: * Find the next argument. ! 404: */ ! 405: getnext: ! 406: cp = copynext(nextarg, rawname); ! 407: if (*cp == '\0') ! 408: nextarg = NULL; ! 409: else ! 410: nextarg = cp; ! 411: /* ! 412: * If it an absolute pathname, canonicalize it and return it. ! 413: */ ! 414: if (rawname[0] == '/') { ! 415: canon(rawname, name); ! 416: return; ! 417: } ! 418: /* ! 419: * For relative pathnames, prepend the current directory to ! 420: * it then canonicalize and return it. ! 421: */ ! 422: (void) strcpy(output, curdir); ! 423: (void) strcat(output, "/"); ! 424: (void) strcat(output, rawname); ! 425: canon(output, name); ! 426: # undef rawname ! 427: } ! 428: ! 429: /* ! 430: * Strip off the next token of the input. ! 431: */ ! 432: char * ! 433: copynext(input, output) ! 434: char *input, *output; ! 435: { ! 436: register char *cp, *bp; ! 437: char quote; ! 438: ! 439: for (cp = input; *cp == ' ' || *cp == '\t'; cp++) ! 440: /* skip to argument */; ! 441: bp = output; ! 442: while (*cp != ' ' && *cp != '\t' && *cp != '\0') { ! 443: /* ! 444: * Handle back slashes. ! 445: */ ! 446: if (*cp == '\\') { ! 447: if (*++cp == '\0') { ! 448: fprintf(stderr, ! 449: "command lines cannot be continued\n"); ! 450: continue; ! 451: } ! 452: *bp++ = *cp++; ! 453: continue; ! 454: } ! 455: /* ! 456: * The usual unquoted case. ! 457: */ ! 458: if (*cp != '\'' && *cp != '"') { ! 459: *bp++ = *cp++; ! 460: continue; ! 461: } ! 462: /* ! 463: * Handle single and double quotes. ! 464: */ ! 465: quote = *cp++; ! 466: while (*cp != quote && *cp != '\0') ! 467: *bp++ = *cp++; ! 468: if (*cp++ == '\0') { ! 469: fprintf(stderr, "missing %c\n", quote); ! 470: cp--; ! 471: continue; ! 472: } ! 473: } ! 474: *bp = '\0'; ! 475: return (cp); ! 476: } ! 477: ! 478: /* ! 479: * respond to interrupts ! 480: */ ! 481: onintr() ! 482: { ! 483: if (reply("restore interrupted, continue") == FAIL) ! 484: done(1); ! 485: if (signal(SIGINT, onintr) == SIG_IGN) ! 486: (void) signal(SIGINT, SIG_IGN); ! 487: if (signal(SIGTERM, onintr) == SIG_IGN) ! 488: (void) signal(SIGTERM, SIG_IGN); ! 489: } ! 490: ! 491: /* ! 492: * handle unexpected inconsistencies ! 493: */ ! 494: /* VARARGS1 */ ! 495: panic(msg, d1, d2) ! 496: char *msg; ! 497: long d1, d2; ! 498: { ! 499: ! 500: fprintf(stderr, msg, d1, d2); ! 501: if (reply("abort") == GOOD) { ! 502: if (reply("dump core") == GOOD) ! 503: abort(); ! 504: done(1); ! 505: } ! 506: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.