|
|
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.