provide correct exit values
[unix-history] / usr / src / sbin / restore / symtab.c
CommitLineData
8c5eec2f
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
e0519353 6
8c5eec2f 7#ifndef lint
414c4f09 8static char sccsid[] = "@(#)symtab.c 5.2 (Berkeley) %G%";
8c5eec2f 9#endif not lint
ebd1f727 10
d27b99b5
KM
11/*
12 * These routines maintain the symbol table which tracks the state
13 * of the file system being restored. They provide lookup by either
14 * name or inode number. They also provide for creation, deletion,
15 * and renaming of entries. Because of the dynamic nature of pathnames,
16 * names should not be saved, but always constructed just before they
17 * are needed, by calling "myname".
18 */
19
e0519353
KM
20#include "restore.h"
21#include <sys/stat.h>
22
d27b99b5
KM
23/*
24 * The following variables define the inode symbol table.
25 * The primary hash table is dynamically allocated based on
26 * the number of inodes in the file system (maxino), scaled by
27 * HASHFACTOR. The variable "entry" points to the hash table;
28 * the variable "entrytblsize" indicates its size (in entries).
29 */
30#define HASHFACTOR 5
a08c9679
KM
31static struct entry **entry;
32static long entrytblsize;
e0519353
KM
33
34/*
35 * Look up an entry by inode number
36 */
37struct entry *
38lookupino(inum)
39 ino_t inum;
40{
a08c9679 41 register struct entry *ep;
e0519353 42
a08c9679
KM
43 if (inum < ROOTINO || inum >= maxino)
44 return (NIL);
45 for (ep = entry[inum % entrytblsize]; ep != NIL; ep = ep->e_next)
46 if (ep->e_ino == inum)
47 return (ep);
48 return (NIL);
e0519353
KM
49}
50
51/*
52 * Add an entry into the entry table
53 */
54addino(inum, np)
a08c9679 55 ino_t inum;
e0519353
KM
56 struct entry *np;
57{
a08c9679 58 struct entry **epp;
6e466853 59
a08c9679
KM
60 if (inum < ROOTINO || inum >= maxino)
61 panic("addino: out of range %d\n", inum);
62 epp = &entry[inum % entrytblsize];
63 np->e_ino = inum;
64 np->e_next = *epp;
65 *epp = np;
66 if (dflag)
67 for (np = np->e_next; np != NIL; np = np->e_next)
68 if (np->e_ino == inum)
69 badentry(np, "duplicate inum");
e0519353
KM
70}
71
72/*
73 * Delete an entry from the entry table
74 */
75deleteino(inum)
a08c9679 76 ino_t inum;
e0519353 77{
a08c9679
KM
78 register struct entry *next;
79 struct entry **prev;
80
81 if (inum < ROOTINO || inum >= maxino)
82 panic("deleteino: out of range %d\n", inum);
83 prev = &entry[inum % entrytblsize];
84 for (next = *prev; next != NIL; next = next->e_next) {
85 if (next->e_ino == inum) {
86 next->e_ino = 0;
87 *prev = next->e_next;
88 return;
89 }
90 prev = &next->e_next;
91 }
92 panic("deleteino: %d not found\n", inum);
e0519353
KM
93}
94
95/*
96 * Look up an entry by name
97 */
98struct entry *
99lookupname(name)
100 char *name;
101{
102 register struct entry *ep;
103 register char *np, *cp;
d27b99b5 104 char buf[MAXPATHLEN];
e0519353
KM
105
106 cp = name;
107 for (ep = lookupino(ROOTINO); ep != NIL; ep = ep->e_entries) {
108 for (np = buf; *cp != '/' && *cp != '\0'; )
109 *np++ = *cp++;
110 *np = '\0';
111 for ( ; ep != NIL; ep = ep->e_sibling)
112 if (strcmp(ep->e_name, buf) == 0)
113 break;
114 if (ep == NIL)
115 break;
9f13f26d 116 if (*cp++ == '\0')
e0519353
KM
117 return (ep);
118 }
9f13f26d 119 return (NIL);
e0519353
KM
120}
121
122/*
123 * Look up the parent of a pathname
124 */
125struct entry *
126lookupparent(name)
127 char *name;
128{
129 struct entry *ep;
130 char *tailindex;
131
132 tailindex = rindex(name, '/');
133 if (tailindex == 0)
134 return (NIL);
135 *tailindex = '\0';
136 ep = lookupname(name);
9f13f26d 137 *tailindex = '/';
e0519353
KM
138 if (ep == NIL)
139 return (NIL);
140 if (ep->e_type != NODE)
141 panic("%s is not a directory\n", name);
142 return (ep);
143}
144
145/*
146 * Determine the current pathname of a node or leaf
147 */
148char *
149myname(ep)
150 register struct entry *ep;
151{
152 register char *cp;
d27b99b5 153 static char namebuf[MAXPATHLEN];
e0519353 154
d27b99b5 155 for (cp = &namebuf[MAXPATHLEN - 2]; cp > &namebuf[ep->e_namlen]; ) {
e0519353
KM
156 cp -= ep->e_namlen;
157 bcopy(ep->e_name, cp, (long)ep->e_namlen);
158 if (ep == lookupino(ROOTINO))
159 return (cp);
160 *(--cp) = '/';
161 ep = ep->e_parent;
162 }
163 panic("%s: pathname too long\n", cp);
164 return(cp);
165}
166
d27b99b5
KM
167/*
168 * Unused symbol table entries are linked together on a freelist
169 * headed by the following pointer.
170 */
171static struct entry *freelist = NIL;
172
e0519353
KM
173/*
174 * add an entry to the symbol table
175 */
176struct entry *
177addentry(name, inum, type)
178 char *name;
179 ino_t inum;
180 int type;
181{
182 register struct entry *np, *ep;
183
184 if (freelist != NIL) {
185 np = freelist;
a08c9679 186 freelist = np->e_next;
e0519353
KM
187 bzero((char *)np, (long)sizeof(struct entry));
188 } else {
189 np = (struct entry *)calloc(1, sizeof(struct entry));
ad4fabdf
KM
190 if (np == NIL)
191 panic("no memory to extend symbol table\n");
e0519353 192 }
e0519353
KM
193 np->e_type = type & ~LINK;
194 ep = lookupparent(name);
195 if (ep == NIL) {
196 if (inum != ROOTINO || lookupino(ROOTINO) != NIL)
197 panic("bad name to addentry %s\n", name);
198 np->e_name = savename(name);
199 np->e_namlen = strlen(name);
200 np->e_parent = np;
201 addino(ROOTINO, np);
202 return (np);
203 }
204 np->e_name = savename(rindex(name, '/') + 1);
205 np->e_namlen = strlen(np->e_name);
206 np->e_parent = ep;
207 np->e_sibling = ep->e_entries;
208 ep->e_entries = np;
209 if (type & LINK) {
210 ep = lookupino(inum);
211 if (ep == NIL)
212 panic("link to non-existant name\n");
b99fe9a4 213 np->e_ino = inum;
e0519353
KM
214 np->e_links = ep->e_links;
215 ep->e_links = np;
216 } else if (inum != 0) {
217 if (lookupino(inum) != NIL)
218 panic("duplicate entry\n");
219 addino(inum, np);
220 }
221 return (np);
222}
223
224/*
225 * delete an entry from the symbol table
226 */
227freeentry(ep)
228 register struct entry *ep;
229{
230 register struct entry *np;
40204072 231 ino_t inum;
e0519353 232
e0519353
KM
233 if (ep->e_flags != REMOVED)
234 badentry(ep, "not marked REMOVED");
a08c9679
KM
235 if (ep->e_type == NODE) {
236 if (ep->e_links != NIL)
e0519353
KM
237 badentry(ep, "freeing referenced directory");
238 if (ep->e_entries != NIL)
239 badentry(ep, "freeing non-empty directory");
240 }
a08c9679
KM
241 if (ep->e_ino != 0) {
242 np = lookupino(ep->e_ino);
243 if (np == NIL)
244 badentry(ep, "lookupino failed");
245 if (np == ep) {
40204072
KM
246 inum = ep->e_ino;
247 deleteino(inum);
a08c9679 248 if (ep->e_links != NIL)
40204072 249 addino(inum, ep->e_links);
a08c9679
KM
250 } else {
251 for (; np != NIL; np = np->e_links) {
252 if (np->e_links == ep) {
253 np->e_links = ep->e_links;
254 break;
255 }
e0519353 256 }
a08c9679
KM
257 if (np == NIL)
258 badentry(ep, "link not found");
e0519353 259 }
e0519353
KM
260 }
261 removeentry(ep);
d27b99b5 262 freename(ep->e_name);
a08c9679 263 ep->e_next = freelist;
e0519353
KM
264 freelist = ep;
265}
266
267/*
268 * Relocate an entry in the tree structure
269 */
270moveentry(ep, newname)
271 register struct entry *ep;
272 char *newname;
273{
274 struct entry *np;
275 char *cp;
e0519353
KM
276
277 np = lookupparent(newname);
278 if (np == NIL)
279 badentry(ep, "cannot move ROOT");
280 if (np != ep->e_parent) {
281 removeentry(ep);
282 ep->e_parent = np;
283 ep->e_sibling = np->e_entries;
284 np->e_entries = ep;
285 }
286 cp = rindex(newname, '/') + 1;
d27b99b5
KM
287 freename(ep->e_name);
288 ep->e_name = savename(cp);
289 ep->e_namlen = strlen(cp);
290 if (strcmp(gentempname(ep), ep->e_name) == 0)
e0519353
KM
291 ep->e_flags |= TMPNAME;
292 else
293 ep->e_flags &= ~TMPNAME;
294}
295
296/*
297 * Remove an entry in the tree structure
298 */
299removeentry(ep)
300 register struct entry *ep;
301{
302 register struct entry *np;
303
304 np = ep->e_parent;
305 if (np->e_entries == ep) {
306 np->e_entries = ep->e_sibling;
307 } else {
308 for (np = np->e_entries; np != NIL; np = np->e_sibling) {
309 if (np->e_sibling == ep) {
310 np->e_sibling = ep->e_sibling;
311 break;
312 }
313 }
314 if (np == NIL)
315 badentry(ep, "cannot find entry in parent list");
316 }
317}
318
319/*
d27b99b5
KM
320 * Table of unused string entries, sorted by length.
321 *
322 * Entries are allocated in STRTBLINCR sized pieces so that names
323 * of similar lengths can use the same entry. The value of STRTBLINCR
324 * is chosen so that every entry has at least enough space to hold
325 * a "struct strtbl" header. Thus every entry can be linked onto an
326 * apprpriate free list.
327 *
328 * NB. The macro "allocsize" below assumes that "struct strhdr"
329 * has a size that is a power of two.
330 */
331struct strhdr {
332 struct strhdr *next;
333};
334
335#define STRTBLINCR (sizeof(struct strhdr))
336#define allocsize(size) (((size) + 1 + STRTBLINCR - 1) & ~(STRTBLINCR - 1))
337
338static struct strhdr strtblhdr[allocsize(MAXNAMLEN) / STRTBLINCR];
339
340/*
341 * Allocate space for a name. It first looks to see if it already
342 * has an appropriate sized entry, and if not allocates a new one.
e0519353
KM
343 */
344char *
345savename(name)
346 char *name;
347{
d27b99b5 348 struct strhdr *np;
e0519353 349 long len;
9f13f26d 350 char *cp;
e0519353
KM
351
352 if (name == NULL)
353 panic("bad name\n");
d27b99b5
KM
354 len = strlen(name);
355 np = strtblhdr[len / STRTBLINCR].next;
356 if (np != NULL) {
357 strtblhdr[len / STRTBLINCR].next = np->next;
358 cp = (char *)np;
359 } else {
360 cp = malloc((unsigned)allocsize(len));
361 if (cp == NULL)
362 panic("no space for string table\n");
363 }
a08c9679 364 (void) strcpy(cp, name);
9f13f26d 365 return (cp);
e0519353
KM
366}
367
d27b99b5
KM
368/*
369 * Free space for a name. The resulting entry is linked onto the
370 * appropriate free list.
371 */
372freename(name)
373 char *name;
374{
375 struct strhdr *tp, *np;
376
377 tp = &strtblhdr[strlen(name) / STRTBLINCR];
378 np = (struct strhdr *)name;
379 np->next = tp->next;
380 tp->next = np;
381}
382
383/*
384 * Useful quantities placed at the end of a dumped symbol table.
385 */
386struct symtableheader {
387 long volno;
388 long stringsize;
389 long entrytblsize;
390 time_t dumptime;
391 time_t dumpdate;
392 ino_t maxino;
b97e998a 393 long ntrec;
d27b99b5
KM
394};
395
e0519353
KM
396/*
397 * dump a snapshot of the symbol table
398 */
399dumpsymtable(filename, checkpt)
400 char *filename;
401 long checkpt;
402{
a08c9679
KM
403 register struct entry *ep, *tep;
404 register ino_t i;
405 struct entry temp, *tentry;
406 long mynum = 1, stroff = 0;
e0519353
KM
407 FILE *fd;
408 struct symtableheader hdr;
409
410 vprintf(stdout, "Check pointing the restore\n");
414c4f09
KM
411 if (Nflag)
412 return;
e0519353
KM
413 if ((fd = fopen(filename, "w")) == NULL) {
414 perror("fopen");
415 panic("cannot create save file %s for symbol table\n",
416 filename);
417 }
418 clearerr(fd);
419 /*
420 * Assign indicies to each entry
421 * Write out the string entries
422 */
423 for (i = ROOTINO; i < maxino; i++) {
424 for (ep = lookupino(i); ep != NIL; ep = ep->e_links) {
a08c9679 425 ep->e_index = mynum++;
e9a184e3
KM
426 (void) fwrite(ep->e_name, sizeof(char),
427 (int)allocsize(ep->e_namlen), fd);
e0519353
KM
428 }
429 }
e0519353
KM
430 /*
431 * Convert pointers to indexes, and output
432 */
a08c9679
KM
433 tep = &temp;
434 stroff = 0;
e0519353 435 for (i = ROOTINO; i < maxino; i++) {
a08c9679 436 for (ep = lookupino(i); ep != NIL; ep = ep->e_links) {
e9a184e3
KM
437 bcopy((char *)ep, (char *)tep,
438 (long)sizeof(struct entry));
a08c9679 439 tep->e_name = (char *)stroff;
d27b99b5 440 stroff += allocsize(ep->e_namlen);
a08c9679
KM
441 tep->e_parent = (struct entry *)ep->e_parent->e_index;
442 if (ep->e_links != NIL)
443 tep->e_links =
444 (struct entry *)ep->e_links->e_index;
445 if (ep->e_sibling != NIL)
446 tep->e_sibling =
447 (struct entry *)ep->e_sibling->e_index;
448 if (ep->e_entries != NIL)
449 tep->e_entries =
450 (struct entry *)ep->e_entries->e_index;
451 if (ep->e_next != NIL)
452 tep->e_next =
453 (struct entry *)ep->e_next->e_index;
e9a184e3 454 (void) fwrite((char *)tep, sizeof(struct entry), 1, fd);
e0519353
KM
455 }
456 }
a08c9679
KM
457 /*
458 * Convert entry pointers to indexes, and output
459 */
460 for (i = 0; i < entrytblsize; i++) {
461 if (entry[i] == NIL)
462 tentry = NIL;
463 else
464 tentry = (struct entry *)entry[i]->e_index;
e9a184e3 465 (void) fwrite((char *)&tentry, sizeof(struct entry *), 1, fd);
a08c9679 466 }
e0519353
KM
467 hdr.volno = checkpt;
468 hdr.maxino = maxino;
a08c9679 469 hdr.entrytblsize = entrytblsize;
d27b99b5 470 hdr.stringsize = stroff;
2cb5dabb
KM
471 hdr.dumptime = dumptime;
472 hdr.dumpdate = dumpdate;
b97e998a 473 hdr.ntrec = ntrec;
e9a184e3 474 (void) fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd);
e0519353
KM
475 if (ferror(fd)) {
476 perror("fwrite");
477 panic("output error to file %s writing symbol table\n",
478 filename);
479 }
e9a184e3 480 (void) fclose(fd);
e0519353
KM
481}
482
483/*
484 * Initialize a symbol table from a file
485 */
486initsymtable(filename)
487 char *filename;
488{
489 char *base;
490 long tblsize;
491 register struct entry *ep;
492 struct entry *baseep, *lep;
493 struct symtableheader hdr;
494 struct stat stbuf;
495 register long i;
496 int fd;
497
498 vprintf(stdout, "Initialize symbol table.\n");
a08c9679
KM
499 if (filename == NULL) {
500 entrytblsize = maxino / HASHFACTOR;
501 entry = (struct entry **)
502 calloc((unsigned)entrytblsize, sizeof(struct entry *));
503 if (entry == (struct entry **)NIL)
504 panic("no memory for entry table\n");
021e989e
KM
505 ep = addentry(".", ROOTINO, NODE);
506 ep->e_flags |= NEW;
a08c9679
KM
507 return;
508 }
e0519353
KM
509 if ((fd = open(filename, 0)) < 0) {
510 perror("open");
511 panic("cannot open symbol table file %s\n", filename);
512 }
513 if (fstat(fd, &stbuf) < 0) {
514 perror("stat");
515 panic("cannot stat symbol table file %s\n", filename);
516 }
517 tblsize = stbuf.st_size - sizeof(struct symtableheader);
4b05a065 518 base = calloc(sizeof(char), (unsigned)tblsize);
e0519353
KM
519 if (base == NULL)
520 panic("cannot allocate space for symbol table\n");
521 if (read(fd, base, (int)tblsize) < 0 ||
522 read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) {
523 perror("read");
524 panic("cannot read symbol table file %s\n", filename);
525 }
2cb5dabb
KM
526 switch (command) {
527 case 'r':
528 /*
529 * For normal continuation, insure that we are using
530 * the next incremental tape
531 */
a08c9679
KM
532 if (hdr.dumpdate != dumptime) {
533 if (hdr.dumpdate < dumptime)
2cb5dabb
KM
534 fprintf(stderr, "Incremental tape too low\n");
535 else
536 fprintf(stderr, "Incremental tape too high\n");
537 done(1);
538 }
539 break;
540 case 'R':
541 /*
542 * For restart, insure that we are using the same tape
543 */
e108d3a2
KM
544 curfile.action = SKIP;
545 dumptime = hdr.dumptime;
546 dumpdate = hdr.dumpdate;
b97e998a
KM
547 if (!bflag)
548 newtapebuf(hdr.ntrec);
e108d3a2 549 getvol(hdr.volno);
2cb5dabb
KM
550 break;
551 default:
552 panic("initsymtable called from command %c\n", command);
553 break;
554 }
e0519353 555 maxino = hdr.maxino;
a08c9679
KM
556 entrytblsize = hdr.entrytblsize;
557 entry = (struct entry **)
558 (base + tblsize - (entrytblsize * sizeof(struct entry *)));
559 baseep = (struct entry *)(base + hdr.stringsize - sizeof(struct entry));
560 lep = (struct entry *)entry;
561 for (i = 0; i < entrytblsize; i++) {
e0519353
KM
562 if (entry[i] == NIL)
563 continue;
564 entry[i] = &baseep[(long)entry[i]];
565 }
a08c9679 566 for (ep = &baseep[1]; ep < lep; ep++) {
e0519353
KM
567 ep->e_name = base + (long)ep->e_name;
568 ep->e_parent = &baseep[(long)ep->e_parent];
a08c9679
KM
569 if (ep->e_sibling != NIL)
570 ep->e_sibling = &baseep[(long)ep->e_sibling];
571 if (ep->e_links != NIL)
572 ep->e_links = &baseep[(long)ep->e_links];
573 if (ep->e_entries != NIL)
574 ep->e_entries = &baseep[(long)ep->e_entries];
575 if (ep->e_next != NIL)
576 ep->e_next = &baseep[(long)ep->e_next];
e0519353
KM
577 }
578}