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