require keep-alive
[unix-history] / usr / src / sbin / restore / main.c
CommitLineData
7d4dda01
KM
1/* Copyright (c) 1981 Regents of the University of California */
2
f7287e4b 3char version[] = "@(#)main.c 1.14 %G%";
7d4dda01
KM
4
5/* Modified to include h option (recursively extract all files within
6 * a subtree) and m option (recreate the heirarchical structure of
7 * that subtree and move extracted files to their proper homes).
8 * 8/29/80 by Mike Litzkow
9 *
10 * Includes the s (skip files) option for use with multiple dumps on
11 * a single tape.
12 */
13
e077bab5 14/* static char *sccsid = "@(#)restor.c 4.3 (Berkeley) 6/3/81"; */
7d4dda01
KM
15
16#define MAXINO 3000
17#define BITS 8
18#define NCACHE 3
7d4dda01
KM
19#define SIZEINC 10
20
21#ifndef STANDALONE
22#include <stdio.h>
23#include <signal.h>
24#endif
003a2a9e
KM
25#include "../h/param.h"
26#include "../h/inode.h"
27#include "../h/fs.h"
28#include "../h/buf.h"
003a2a9e
KM
29#include "../h/user.h"
30#include "../h/dumprestor.h"
b88e54cb
KM
31#include <sys/mtio.h>
32
b45e25c0 33#define ODIRSIZ 14
b88e54cb
KM
34struct odirect {
35 u_short d_ino;
b45e25c0 36 char d_name[ODIRSIZ];
b88e54cb 37};
7d4dda01 38
b6407c9d
KM
39#define MWORD(m,i) (m[(unsigned)(i-1)/NBBY])
40#define MBIT(i) (1<<((unsigned)(i-1)%NBBY))
7d4dda01
KM
41#define BIS(i,w) (MWORD(w,i) |= MBIT(i))
42#define BIC(i,w) (MWORD(w,i) &= ~MBIT(i))
43#define BIT(i,w) (MWORD(w,i) & MBIT(i))
44
003a2a9e 45ino_t ino, maxi;
b88e54cb 46struct inode *cur_ip;
7d4dda01 47
b88e54cb 48int eflag = 0, hflag = 0, mflag = 0, cvtdir = 0;
7d4dda01 49
003a2a9e
KM
50char mounted = 0;
51dev_t dev = 0;
f7287e4b
KM
52struct fs *fsptr;
53struct inode parentino;
7d4dda01
KM
54char tapename[] = "/dev/rmt8";
55char *magtape = tapename;
b88e54cb
KM
56int mt;
57int dumpnum = 1;
58int volno = 1;
59int curblk = 0;
60int bct = NTREC+1;
61char tbf[NTREC*TP_BSIZE];
7d4dda01
KM
62
63#ifdef STANDALONE
64char mbuf[50];
65#endif
66
7d4dda01 67daddr_t seekpt;
0841dbb0 68FILE *df;
b45e25c0 69DIR *dirp;
0841dbb0 70int ofile;
7d4dda01
KM
71char dirfile[] = "rstXXXXXX";
72
0841dbb0
KM
73#define INOHASH(val) (val % MAXINO)
74struct inotab {
75 struct inotab *t_next;
7d4dda01
KM
76 ino_t t_ino;
77 daddr_t t_seekpt;
0841dbb0 78} *inotab[MAXINO];
7d4dda01 79
0841dbb0 80#define XISDIR 1
7d4dda01
KM
81#define XTRACTD 2
82#define XINUSE 4
0841dbb0 83#define XLINKED 8
7d4dda01 84struct xtrlist {
0841dbb0
KM
85 struct xtrlist *x_next;
86 struct xtrlist *x_linkedto;
0841dbb0 87 time_t x_timep[2];
bcfabedf 88 ino_t x_ino;
0841dbb0 89 char x_flags;
bcfabedf
KM
90 char x_name[1];
91 /* actually longer */
0841dbb0 92} *xtrlist[MAXINO];
19ac1bc8 93int xtrcnt = 0;
7d4dda01 94
b6407c9d
KM
95#ifdef STANDALONE
96#define msiz 8192
97char dumpmap[msiz];
98char clrimap[msiz];
99#else
100int msiz;
101char *dumpmap;
102char *clrimap;
103#endif
104
105char clearedbuf[MAXBSIZE];
7d4dda01 106
0841dbb0 107extern char *ctime();
bcfabedf 108ino_t search();
b45e25c0 109int dirwrite();
003a2a9e 110char **envp;
7d4dda01 111
003a2a9e
KM
112main(argc, argv, arge)
113 int argc;
114 char *argv[];
115 char **arge;
7d4dda01
KM
116{
117 register char *cp;
118 char command;
003a2a9e 119 int (*signal())();
7d4dda01
KM
120 int done();
121
bcfabedf
KM
122 if (signal(SIGINT, done) == SIG_IGN)
123 signal(SIGINT, SIG_IGN);
124 if (signal(SIGTERM, done) == SIG_IGN)
125 signal(SIGTERM, SIG_IGN);
7d4dda01 126#ifndef STANDALONE
003a2a9e
KM
127 envp = arge;
128 mktmp(dirfile);
7d4dda01
KM
129 if (argc < 2) {
130usage:
0841dbb0 131 fprintf(stderr, "Usage: restor x[s|m|h|v] file file..., restor r|R filesys, or restor t\n");
003a2a9e 132 done(1);
7d4dda01
KM
133 }
134 argv++;
135 argc -= 2;
136 for (cp = *argv++; *cp; cp++) {
137 switch (*cp) {
138 case '-':
139 break;
140 case 'f':
141 magtape = *argv++;
142 argc--;
143 break;
144 /* s dumpnum (skip to) for multifile dump tapes */
145 case 's':
146 dumpnum = atoi(*argv++);
147 if(dumpnum <= 0) {
003a2a9e
KM
148 fprintf(stderr, "Dump number must be a positive integer\n");
149 done(1);
7d4dda01
KM
150 }
151 argc--;
152 break;
153 case 'h':
154 hflag++;
155 break;
156 case 'm':
157 mflag++;
158 break;
159 case 'r':
160 case 'R':
161 case 't':
162 case 'x':
163 command = *cp;
164 break;
165 default:
003a2a9e 166 fprintf(stderr, "Bad key character %c\n", *cp);
7d4dda01
KM
167 goto usage;
168 }
169 }
170 if (command == 'x') {
0841dbb0
KM
171 df = fopen(dirfile, "w");
172 if (df == 0) {
003a2a9e
KM
173 fprintf(stderr, "restor: %s - cannot create directory temporary\n", dirfile);
174 done(1);
7d4dda01 175 }
003a2a9e
KM
176 xmount(envp);
177 mounted++;
7d4dda01
KM
178 }
179 doit(command, argc, argv);
003a2a9e 180 done(0);
7d4dda01
KM
181#else
182 magtape = "tape";
183 doit('r', 1, 0);
184#endif
185}
186
187doit(command, argc, argv)
003a2a9e
KM
188 char command;
189 int argc;
190 char *argv[];
7d4dda01 191{
b88e54cb
KM
192 struct mtop tcom;
193
7d4dda01 194#ifndef STANDALONE
7d4dda01 195 if ((mt = open(magtape, 0)) < 0) {
003a2a9e
KM
196 fprintf(stderr, "%s: cannot open tape\n", magtape);
197 done(1);
7d4dda01 198 }
bcfabedf 199 if (dumpnum != 1) {
7d4dda01
KM
200 tcom.mt_op = MTFSF;
201 tcom.mt_count = dumpnum -1;
bcfabedf 202 if (ioctl(mt,MTIOCTOP,&tcom) < 0)
7d4dda01
KM
203 perror("ioctl MTFSF");
204 }
205#else
206 do {
003a2a9e 207 fprintf(stderr, "Tape? ");
7d4dda01
KM
208 gets(mbuf);
209 mt = open(mbuf, 0);
210 } while (mt == -1);
211 magtape = mbuf;
212#endif
b6407c9d 213 blkclr(clearedbuf, MAXBSIZE);
7d4dda01
KM
214 switch(command) {
215#ifndef STANDALONE
216 case 't':
217 if (readhdr(&spcl) == 0) {
003a2a9e
KM
218 fprintf(stderr, "Tape is not a dump tape\n");
219 done(1);
7d4dda01 220 }
bcfabedf
KM
221 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date));
222 fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
7d4dda01
KM
223 return;
224 case 'x':
0841dbb0
KM
225 extractfiles(argc, argv);
226 return;
b6407c9d 227#endif
0841dbb0
KM
228 case 'r':
229 case 'R':
230 restorfiles(command, argv);
231 return;
232 }
0841dbb0
KM
233}
234
235#ifndef STANDALONE
236extractfiles(argc, argv)
237 int argc;
238 char **argv;
239{
bcfabedf 240 char *ststore();
0841dbb0
KM
241 register struct xtrlist *xp;
242 struct xtrlist **xpp;
243 ino_t d;
b88e54cb 244 int xtrfile(), xtrskip(), xtrcvtdir(), xtrcvtskip(), null();
bcfabedf
KM
245 int mode;
246 char name[BUFSIZ + 1];
0841dbb0
KM
247
248 if (readhdr(&spcl) == 0) {
249 fprintf(stderr, "Tape is not a dump tape\n");
250 done(1);
251 }
252 if (checkvol(&spcl, 1) == 0) {
253 fprintf(stderr, "Tape is not volume 1 of the dump\n");
254 }
f7287e4b
KM
255 fsptr = getfs(dev);
256 msiz = roundup(howmany(fsptr->fs_ipg * fsptr->fs_ncg, NBBY), TP_BSIZE);
b6407c9d
KM
257 clrimap = (char *)calloc(msiz, sizeof(char));
258 dumpmap = (char *)calloc(msiz, sizeof(char));
b88e54cb 259 pass1(1); /* This sets the various maps on the way by */
bcfabedf 260 while (argc--) {
0841dbb0 261 if ((d = psearch(*argv)) == 0 || BIT(d,dumpmap) == 0) {
bcfabedf 262 fprintf(stdout, "%s: not on tape\n", *argv++);
0841dbb0 263 continue;
7d4dda01 264 }
bcfabedf
KM
265 if (mflag)
266 checkdir(*argv);
0841dbb0
KM
267 if(hflag)
268 getleaves(d, *argv++);
bcfabedf
KM
269 else
270 allocxtr(d, *argv++, XINUSE);
0841dbb0 271 }
bcfabedf 272 if (dumpnum > 1) {
b88e54cb
KM
273 /*
274 * if this is a multi-dump tape we always start with
275 * volume 1, so as to avoid accidentally restoring
276 * from a different dump!
277 */
278 resetmt();
279 dumpnum = 1;
280 volno = 1;
281 readhdr(&spcl);
282 goto rbits;
0841dbb0 283 }
b88e54cb
KM
284newvol:
285 resetmt();
7d4dda01 286getvol:
b88e54cb 287 fprintf(stderr, "Mount desired tape volume; Specify volume #: ");
0841dbb0
KM
288 if (gets(tbf) == NULL)
289 return;
290 volno = atoi(tbf);
291 if (volno <= 0) {
292 fprintf(stderr, "Volume numbers are positive numerics\n");
293 goto getvol;
294 }
295 if (readhdr(&spcl) == 0) {
296 fprintf(stderr, "tape is not dump tape\n");
297 goto newvol;
298 }
299 if (checkvol(&spcl, volno) == 0) {
300 fprintf(stderr, "Wrong volume (%d)\n", spcl.c_volume);
301 goto newvol;
302 }
7d4dda01 303rbits:
0841dbb0
KM
304 while (gethead(&spcl) == 0)
305 ;
306 if (checktype(&spcl, TS_INODE) == 1) {
307 fprintf(stderr, "Can't find inode mask!\n");
308 goto newvol;
309 }
310 if (checktype(&spcl, TS_BITS) == 0)
311 goto rbits;
312 readbits(dumpmap);
313 while (xtrcnt > 0) {
314again:
315 if (ishead(&spcl) == 0)
316 while(gethead(&spcl) == 0)
317 ;
318 if (checktype(&spcl, TS_END) == 1) {
319 fprintf(stderr, "end of tape\n");
320 break;
7d4dda01 321 }
0841dbb0
KM
322 if (checktype(&spcl, TS_INODE) == 0) {
323 gethead(&spcl);
324 goto again;
7d4dda01 325 }
0841dbb0
KM
326 d = spcl.c_inumber;
327 for (xp = xtrlist[INOHASH(d)]; xp; xp = xp->x_next) {
328 if (d != xp->x_ino)
329 continue;
330 if (xp->x_flags & XLINKED)
331 continue;
332 xp->x_timep[0] = spcl.c_dinode.di_atime;
333 xp->x_timep[1] = spcl.c_dinode.di_mtime;
334 mode = spcl.c_dinode.di_mode;
335 if (mflag)
bcfabedf 336 strcpy(name, xp->x_name);
0841dbb0
KM
337 else
338 sprintf(name, "%u", xp->x_ino);
339 switch (mode & IFMT) {
340 default:
bcfabedf 341 fprintf(stderr, "%s: unknown file type\n", name);
0841dbb0
KM
342 xp->x_flags |= XTRACTD;
343 xtrcnt--;
344 goto skipfile;
345 case IFCHR:
346 case IFBLK:
bcfabedf 347 fprintf(stdout, "extract special file %s\n", name);
0841dbb0
KM
348 if (xmknod(name, mode, spcl.c_dinode.di_rdev)) {
349 fprintf(stderr, "%s: cannot create special file\n", name);
350 xp->x_flags |= XTRACTD;
351 xtrcnt--;
352 goto skipfile;
19ac1bc8 353 }
0841dbb0
KM
354 getfile(null, null, spcl.c_dinode.di_size);
355 break;
356 case IFDIR:
357 if (mflag) {
bcfabedf 358 fprintf(stdout, "extract directory %s\n", name);
0841dbb0 359 strncat(name, "/.", BUFSIZ);
bcfabedf
KM
360 checkdir(name);
361 xchown(xp->x_name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
0841dbb0
KM
362 getfile(null, null, spcl.c_dinode.di_size);
363 break;
364 }
b88e54cb
KM
365 fprintf(stdout, "extract file %s\n", name);
366 if ((ofile = xcreat(name, 0666)) < 0) {
367 fprintf(stderr, "%s: cannot create file\n", name);
368 xp->x_flags |= XTRACTD;
369 xtrcnt--;
370 goto skipfile;
371 }
372 xchown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
b45e25c0 373 if (cvtdir) {
b88e54cb
KM
374 getfile(xtrcvtdir, xtrcvtskip,
375 spcl.c_dinode.di_size);
b45e25c0
KM
376 flushent(xtrfile);
377 } else
b88e54cb
KM
378 getfile(xtrfile, xtrskip,
379 spcl.c_dinode.di_size);
380 xclose(ofile);
381 break;
0841dbb0 382 case IFREG:
bcfabedf 383 fprintf(stdout, "extract file %s\n", name);
0841dbb0
KM
384 if ((ofile = xcreat(name, 0666)) < 0) {
385 fprintf(stderr, "%s: cannot create file\n", name);
386 xp->x_flags |= XTRACTD;
387 xtrcnt--;
388 goto skipfile;
7d4dda01 389 }
0841dbb0 390 xchown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
b88e54cb 391 getfile(xtrfile, xtrskip, spcl.c_dinode.di_size);
0841dbb0
KM
392 xclose(ofile);
393 break;
7d4dda01 394 }
0841dbb0
KM
395 xchmod(name, mode);
396 xutime(name, xp->x_timep);
397 xp->x_flags |= XTRACTD;
398 xtrcnt--;
399 goto finished;
400 }
401skipfile:
402 getfile(null, null, spcl.c_dinode.di_size);
003a2a9e 403finished:
0841dbb0
KM
404 ;
405 }
406 if (xtrcnt == 0 && !mflag)
407 return;
408 for (xpp = xtrlist; xpp < &xtrlist[MAXINO]; xpp++) {
409 for (xp = *xpp; xp; xp = xp->x_next) {
410 if (mflag && (xp->x_flags & XISDIR))
411 xutime(xp->x_name, xp->x_timep);
412 if (xp->x_flags & XTRACTD)
413 continue;
414 if ((xp->x_flags & XLINKED) == 0) {
415 fprintf(stderr, "cannot find file %s\n",
416 xp->x_name);
417 continue;
418 }
bcfabedf
KM
419 if (!mflag)
420 continue;
421 fprintf(stdout, "link %s to %s\n",
422 xp->x_linkedto->x_name, xp->x_name);
0841dbb0 423 if (xlink(xp->x_linkedto->x_name, xp->x_name) < 0)
bcfabedf
KM
424 fprintf(stderr, "link %s to %s failed\n",
425 xp->x_linkedto->x_name, xp->x_name);
7d4dda01 426 }
0841dbb0
KM
427 }
428}
7d4dda01 429#endif
0841dbb0
KM
430
431restorfiles(command, argv)
432 char command;
433 char **argv;
434{
b45e25c0 435 int null(), rstrfile(), rstrskip(), rstrcvtdir(), rstrcvtskip();
0841dbb0
KM
436 register struct dinode *dp;
437 register struct inode *ip;
b88e54cb 438 int mode, type;
0841dbb0
KM
439 char mount[BUFSIZ + 1];
440 char *ptr[2];
441
0841dbb0
KM
442 mount[0] = '\0';
443 strcpy(mount, "MOUNT=");
b6407c9d 444#ifndef STANDALONE
0841dbb0 445 strncat(mount, *argv, BUFSIZ);
b6407c9d
KM
446#else
447 fprintf(stderr, "Disk? ");
448 gets(&mount[6]);
449#endif
0841dbb0
KM
450 ptr[0] = mount;
451 ptr[1] = 0;
452 xmount(ptr);
b6407c9d 453 mounted++;
0841dbb0
KM
454 iput(u.u_cdir); /* release root inode */
455 iput(u.u_rdir); /* release root inode */
f7287e4b
KM
456 fsptr = getfs(dev);
457 parentino.i_fs = fsptr;
458 parentino.i_dev = dev;
459 maxi = fsptr->fs_ipg * fsptr->fs_ncg;
7d4dda01 460#ifndef STANDALONE
b6407c9d
KM
461 msiz = roundup(howmany(maxi, NBBY), TP_BSIZE);
462 clrimap = (char *)calloc(msiz, sizeof(char));
463 dumpmap = (char *)calloc(msiz, sizeof(char));
0841dbb0
KM
464 if (command == 'R') {
465 fprintf(stderr, "Enter starting volume number: ");
466 if (gets(tbf) == EOF) {
467 volno = 1;
468 fprintf(stderr, "\n");
7d4dda01
KM
469 }
470 else
0841dbb0
KM
471 volno = atoi(tbf);
472 }
473 else
7d4dda01 474#endif
0841dbb0
KM
475 volno = 1;
476 fprintf(stderr, "Last chance before scribbling on %s. ",
7d4dda01 477#ifdef STANDALONE
0841dbb0 478 "disk");
7d4dda01 479#else
0841dbb0 480 *argv);
7d4dda01 481#endif
0841dbb0 482 while (getchar() != '\n');
0841dbb0
KM
483 if (readhdr(&spcl) == 0) {
484 fprintf(stderr, "Missing volume record\n");
485 done(1);
486 }
487 if (checkvol(&spcl, volno) == 0) {
488 fprintf(stderr, "Tape is not volume %d\n", volno);
489 done(1);
490 }
b88e54cb
KM
491 pass1(0);
492 gethead(&spcl); /* volume header already checked above */
0841dbb0
KM
493 gethead(&spcl);
494 for (;;) {
0841dbb0
KM
495 if (ishead(&spcl) == 0) {
496 fprintf(stderr, "Missing header block\n");
497 while (gethead(&spcl) == 0)
498 ;
499 eflag++;
7d4dda01 500 }
0841dbb0
KM
501 if (checktype(&spcl, TS_END) == 1) {
502 fprintf(stderr, "End of tape\n");
503 close(mt);
504 return;
7d4dda01 505 }
0841dbb0
KM
506 if (checktype(&spcl, TS_CLRI) == 1) {
507 readbits(clrimap);
9c2d09b1
KM
508 /*
509 * if throwing away the root inode, must also
510 * discard the predefined lost+found directory.
511 */
512 if (BIT(ROOTINO, clrimap))
513 BIS(LOSTFOUNDINO + 1, clrimap);
c312eebd 514 for (ino = ROOTINO; ino <= maxi; ino++)
0841dbb0 515 if (BIT(ino, clrimap) == 0) {
f7287e4b 516 if (!iexist(&parentino, ino))
0841dbb0 517 continue;
f7287e4b 518 ip = iget(dev, fsptr, ino);
0841dbb0
KM
519 if (ip == NULL) {
520 fprintf(stderr, "can't find inode %u\n", ino);
521 done(1);
7d4dda01 522 }
0841dbb0
KM
523 ip->i_nlink = 0;
524 ip->i_flag |= ICHG;
525 iput(ip);
003a2a9e 526 }
b45e25c0 527 continue;
0841dbb0
KM
528 }
529 if (checktype(&spcl, TS_BITS) == 1) {
530 readbits(dumpmap);
b45e25c0 531 continue;
0841dbb0
KM
532 }
533 if (checktype(&spcl, TS_INODE) == 0) {
534 fprintf(stderr, "Unknown header type\n");
535 eflag++;
536 gethead(&spcl);
b45e25c0 537 continue;
0841dbb0
KM
538 }
539 ino = spcl.c_inumber;
540 if (eflag)
541 fprintf(stderr, "Resynced at inode %u\n", ino);
542 eflag = 0;
543 if (ino > maxi) {
544 fprintf(stderr, "%u: ilist too small\n", ino);
545 gethead(&spcl);
b45e25c0
KM
546 continue;
547 }
548 dp = &spcl.c_dinode;
549 if (ino < ROOTINO) {
550 getfile(null, null, dp->di_size);
551 continue;
0841dbb0 552 }
f7287e4b
KM
553 if (iexist(&parentino, ino)) {
554 ip = iget(dev, fsptr, ino);
0841dbb0
KM
555 if (ip == NULL) {
556 fprintf(stderr, "can't find inode %u\n",
557 ino);
003a2a9e
KM
558 done(1);
559 }
0841dbb0 560 ip->i_nlink = 0;
003a2a9e
KM
561 ip->i_flag |= ICHG;
562 iput(ip);
7d4dda01 563 }
f7287e4b 564 ip = ialloc(&parentino, ino, dp->di_mode);
0841dbb0
KM
565 if (ip == NULL || ip->i_number != ino) {
566 fprintf(stderr, "can't create inode %u\n", ino);
567 done(1);
568 }
569 ip->i_mode = mode = dp->di_mode;
570 ip->i_nlink = dp->di_nlink;
571 ip->i_uid = dp->di_uid;
572 ip->i_gid = dp->di_gid;
573 ip->i_atime = dp->di_atime;
574 ip->i_mtime = dp->di_mtime;
575 ip->i_ctime = dp->di_ctime;
b88e54cb
KM
576 type = ip->i_mode & IFMT;
577 if (type == IFCHR || type == IFBLK)
0841dbb0
KM
578 ip->i_rdev = dp->di_rdev;
579 ip->i_size = 0;
580 cur_ip = ip;
581 u.u_offset = 0;
582 u.u_segflg = 1;
b45e25c0 583 if (cvtdir && type == IFDIR) {
b88e54cb 584 getfile(rstrcvtdir, rstrcvtskip, dp->di_size);
b45e25c0
KM
585 flushent(rstrfile);
586 } else
b88e54cb 587 getfile(rstrfile, rstrskip, dp->di_size);
0841dbb0
KM
588 ip->i_mode = mode;
589 ip->i_flag &= ~(IUPD|IACC);
590 ip->i_flag |= ICHG;
591 iput(ip);
7d4dda01
KM
592 }
593}
594
595/*
596 * Read the tape, bulding up a directory structure for extraction
597 * by name
598 */
599#ifndef STANDALONE
b88e54cb
KM
600pass1(savedir)
601 int savedir;
7d4dda01 602{
19ac1bc8 603 register int i;
0841dbb0
KM
604 register struct dinode *ip;
605 struct direct nulldir;
b88e54cb 606 char buf[TP_BSIZE];
b45e25c0 607 int putdir(), null(), dirwrite();
7d4dda01 608
b45e25c0
KM
609 nulldir.d_ino = 1;
610 nulldir.d_namlen = 1;
611 strncpy(nulldir.d_name, "/", nulldir.d_namlen);
612 nulldir.d_reclen = DIRSIZ(&nulldir);
7d4dda01 613 while (gethead(&spcl) == 0) {
003a2a9e 614 fprintf(stderr, "Can't find directory header!\n");
7d4dda01
KM
615 }
616 for (;;) {
617 if (checktype(&spcl, TS_BITS) == 1) {
618 readbits(dumpmap);
619 continue;
620 }
621 if (checktype(&spcl, TS_CLRI) == 1) {
622 readbits(clrimap);
623 continue;
624 }
625 if (checktype(&spcl, TS_INODE) == 0) {
626finish:
b45e25c0
KM
627 if (savedir) {
628 fclose(df);
629 dirp = opendir(dirfile);
630 if (dirp == NULL)
631 perror("opendir");
632 }
b88e54cb 633 resetmt();
7d4dda01
KM
634 return;
635 }
636 ip = &spcl.c_dinode;
637 i = ip->di_mode & IFMT;
638 if (i != IFDIR) {
639 goto finish;
640 }
b88e54cb
KM
641 if (spcl.c_inumber == ROOTINO) {
642 readtape(buf);
643 bct--; /* push back this block */
644 if (((struct direct *)buf)->d_ino != ROOTINO) {
645 if (((struct odirect *)buf)->d_ino != ROOTINO) {
646 fprintf(stderr, "bad root directory\n");
647 done(1);
648 }
649 fprintf(stderr, "converting to new directory format\n");
650 cvtdir = 1;
651 }
652 if (!savedir && !cvtdir) {
653 /* if no conversion, just return */
654 goto finish;
655 }
656 }
bcfabedf 657 allocinotab(spcl.c_inumber, seekpt);
b88e54cb
KM
658 if (savedir) {
659 getfile(putdir, null, spcl.c_dinode.di_size);
b45e25c0
KM
660 putent(&nulldir, dirwrite);
661 flushent(dirwrite);
b88e54cb
KM
662 } else {
663 getfile(null, null, spcl.c_dinode.di_size);
664 }
7d4dda01
KM
665 }
666}
667#endif
668
bcfabedf
KM
669/*
670 * Put the directory entries in the directory file
671 */
672#ifndef STANDALONE
673putdir(buf, size)
674 char *buf;
675 int size;
676{
b88e54cb
KM
677 struct direct cvtbuf;
678 register struct odirect *odp;
679 struct odirect *eodp;
bcfabedf 680 register struct direct *dp;
b45e25c0 681 long loc;
b88e54cb
KM
682
683 if (cvtdir) {
684 eodp = (struct odirect *)&buf[size];
685 for (odp = (struct odirect *)buf; odp < eodp; odp++)
686 if (odp->d_ino != 0) {
687 dcvt(odp, &cvtbuf);
b45e25c0 688 putent(&cvtbuf, dirwrite);
b88e54cb
KM
689 }
690 } else {
b45e25c0
KM
691 for (loc = 0; loc < size; ) {
692 dp = (struct direct *)(buf + loc);
b88e54cb 693 if (dp->d_ino != 0)
b45e25c0
KM
694 putent(dp, dirwrite);
695 }
b88e54cb
KM
696 }
697}
698
bcfabedf
KM
699/*
700 * Recursively find names and inumbers of all files in subtree
701 * pname and put them in xtrlist[]
702 */
703getleaves(ino, pname)
704 ino_t ino;
705 char *pname;
706{
707 register struct inotab *itp;
708 int namelen;
b45e25c0
KM
709 long bpt;
710 register struct direct *dp;
711 char locname[BUFSIZ + 1];
bcfabedf
KM
712
713 if (BIT(ino, dumpmap) == 0) {
714 fprintf(stdout, "%s: not on the tape\n", pname);
715 return;
716 }
717 for (itp = inotab[INOHASH(ino)]; itp; itp = itp->t_next) {
718 if (itp->t_ino != ino)
719 continue;
720 /*
721 * pname is a directory name
722 */
723 allocxtr(ino, pname, XISDIR);
724 /*
725 * begin search through the directory
726 * skipping over "." and ".."
727 */
728 strncpy(locname, pname, BUFSIZ);
729 strncat(locname, "/", BUFSIZ);
730 namelen = strlen(locname);
b45e25c0
KM
731 seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
732 dp = readdir(dirp);
733 dp = readdir(dirp);
734 dp = readdir(dirp);
735 bpt = telldir(dirp);
bcfabedf
KM
736 /*
737 * "/" signals end of directory
738 */
b45e25c0 739 while (dp->d_namlen != 1 || dp->d_name[0] != '/') {
bcfabedf 740 locname[namelen] = '\0';
b45e25c0
KM
741 if (namelen + dp->d_namlen >= BUFSIZ) {
742 fprintf(stderr, "%s%s: name exceedes %d char\n",
743 locname, dp->d_name, BUFSIZ);
bcfabedf
KM
744 continue;
745 }
b45e25c0
KM
746 strncat(locname, dp->d_name, dp->d_namlen);
747 getleaves(dp->d_ino, locname);
748 seekdir(dirp, bpt, itp->t_seekpt);
749 dp = readdir(dirp);
750 bpt = telldir(dirp);
bcfabedf
KM
751 }
752 return;
753 }
754 /*
755 * locname is name of a simple file
756 */
757 allocxtr(ino, pname, XINUSE);
758}
759
760/*
761 * Search the directory tree rooted at inode ROOTINO
762 * for the path pointed at by n
763 */
764psearch(n)
765 char *n;
766{
767 register char *cp, *cp1;
768 char c;
769
770 ino = ROOTINO;
771 if (*(cp = n) == '/')
772 cp++;
773next:
774 cp1 = cp + 1;
775 while (*cp1 != '/' && *cp1)
776 cp1++;
777 c = *cp1;
778 *cp1 = 0;
779 ino = search(ino, cp);
780 if (ino == 0) {
781 *cp1 = c;
782 return(0);
783 }
784 *cp1 = c;
785 if (c == '/') {
786 cp = cp1+1;
787 goto next;
788 }
789 return(ino);
790}
791
792/*
793 * search the directory inode ino
794 * looking for entry cp
795 */
796ino_t
797search(inum, cp)
798 ino_t inum;
799 char *cp;
800{
b45e25c0 801 register struct direct *dp;
bcfabedf 802 register struct inotab *itp;
b45e25c0 803 int len;
bcfabedf
KM
804
805 for (itp = inotab[INOHASH(inum)]; itp; itp = itp->t_next)
806 if (itp->t_ino == inum)
807 goto found;
808 return(0);
809found:
b45e25c0
KM
810 seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
811 len = strlen(cp);
bcfabedf 812 do {
b45e25c0
KM
813 dp = readdir(dirp);
814 if (dp->d_namlen == 1 && dp->d_name[0] == '/')
bcfabedf 815 return(0);
b45e25c0
KM
816 } while (dp->d_namlen != len || strncmp(dp->d_name, cp, len));
817 return(dp->d_ino);
bcfabedf
KM
818}
819#endif
820
7d4dda01
KM
821/*
822 * Do the file extraction, calling the supplied functions
823 * with the blocks
824 */
003a2a9e
KM
825getfile(f1, f2, size)
826 int (*f2)(), (*f1)();
827 long size;
7d4dda01 828{
19ac1bc8 829 register int i;
b6407c9d 830 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
0841dbb0
KM
831 union u_spcl addrblk;
832# define addrblock addrblk.s_spcl
7d4dda01 833
0841dbb0 834 addrblock = spcl;
7d4dda01 835 for (;;) {
0841dbb0
KM
836 for (i = 0; i < addrblock.c_count; i++) {
837 if (addrblock.c_addr[i]) {
19ac1bc8 838 readtape(&buf[curblk++][0]);
f7287e4b 839 if (curblk == BLKING(fsptr) * fsptr->fs_frag) {
19ac1bc8 840 (*f1)(buf, size > TP_BSIZE ?
f7287e4b 841 (long) (BLKING(fsptr) * fsptr->fs_frag * TP_BSIZE) :
19ac1bc8
KM
842 (curblk - 1) * TP_BSIZE + size);
843 curblk = 0;
844 }
b6407c9d 845 } else {
19ac1bc8
KM
846 if (curblk > 0) {
847 (*f1)(buf, size > TP_BSIZE ?
848 (long) (curblk * TP_BSIZE) :
849 (curblk - 1) * TP_BSIZE + size);
850 curblk = 0;
851 }
b6407c9d
KM
852 (*f2)(clearedbuf, size > TP_BSIZE ?
853 (long) TP_BSIZE : size);
7d4dda01 854 }
19ac1bc8 855 if ((size -= TP_BSIZE) <= 0) {
7d4dda01
KM
856eloop:
857 while (gethead(&spcl) == 0)
858 ;
859 if (checktype(&spcl, TS_ADDR) == 1)
860 goto eloop;
19ac1bc8 861 goto out;
7d4dda01
KM
862 }
863 }
0841dbb0 864 if (gethead(&addrblock) == 0) {
19ac1bc8 865 fprintf(stderr, "Missing address (header) block, ino%u\n", ino);
003a2a9e
KM
866 goto eloop;
867 }
0841dbb0
KM
868 if (checktype(&addrblock, TS_ADDR) == 0) {
869 spcl = addrblock;
19ac1bc8 870 goto out;
003a2a9e 871 }
7d4dda01 872 }
19ac1bc8
KM
873out:
874 if (curblk > 0) {
875 (*f1)(buf, (curblk * TP_BSIZE) + size);
876 curblk = 0;
877 }
7d4dda01
KM
878}
879
bcfabedf
KM
880/*
881 * The next routines are called during file extraction to
882 * put the data into the right form and place.
883 */
884#ifndef STANDALONE
885xtrfile(buf, size)
886 char *buf;
887 long size;
888{
889 if (xwrite(ofile, buf, (int) size) == -1) {
b88e54cb 890 perror("extract write");
bcfabedf
KM
891 done(1);
892 }
893}
894
b88e54cb 895xtrskip(buf, size)
bcfabedf
KM
896 char *buf;
897 long size;
898{
899 if (xseek(ofile, size, 1) == -1) {
b88e54cb 900 perror("extract seek");
bcfabedf
KM
901 done(1);
902 }
903}
bcfabedf 904
b88e54cb
KM
905xtrcvtdir(buf, size)
906 struct odirect *buf;
907 long size;
908{
b88e54cb 909 struct odirect *odp, *edp;
b45e25c0 910 struct direct *dp, cvtbuf;
b88e54cb
KM
911
912 edp = &buf[size / sizeof(struct odirect)];
b45e25c0
KM
913 for (odp = buf; odp < edp; odp++) {
914 dcvt(odp, &cvtbuf);
915 putent(&cvtbuf, xtrfile);
b88e54cb
KM
916 }
917}
918
919xtrcvtskip(buf, size)
920 char *buf;
921 long size;
922{
923 fprintf(stderr, "unallocated block in directory\n");
b45e25c0 924 xtrskip(buf, size);
b88e54cb
KM
925}
926#endif
bcfabedf
KM
927
928rstrfile(buf, size)
929 char *buf;
930 long size;
931{
932 u.u_base = buf;
933 u.u_count = size;
934 writei(cur_ip);
935 if (u.u_error) {
b88e54cb 936 perror("restor write");
bcfabedf
KM
937 done(1);
938 }
939}
940
941rstrskip(buf, size)
942 char *buf;
943 long size;
944{
945 u.u_offset += size;
946}
947
b88e54cb
KM
948rstrcvtdir(buf, size)
949 struct odirect *buf;
950 long size;
951{
b88e54cb 952 struct odirect *odp, *edp;
b45e25c0 953 struct direct *dp, cvtbuf;
b88e54cb
KM
954
955 edp = &buf[size / sizeof(struct odirect)];
b45e25c0
KM
956 for (odp = buf; odp < edp; odp++) {
957 dcvt(odp, &cvtbuf);
958 putent(&cvtbuf, rstrfile);
b88e54cb
KM
959 }
960}
961
962rstrcvtskip(buf, size)
963 char *buf;
964 long size;
965{
966 fprintf(stderr, "unallocated block in directory\n");
b45e25c0 967 rstrskip(buf, size);
b88e54cb
KM
968}
969
bcfabedf
KM
970null() {;}
971
7d4dda01 972/*
19ac1bc8 973 * Do the tape i/o, dealing with volume changes
7d4dda01
KM
974 * etc..
975 */
976readtape(b)
003a2a9e 977 char *b;
7d4dda01 978{
19ac1bc8 979 register int i;
0841dbb0 980 struct s_spcl tmpbuf;
7d4dda01
KM
981
982 if (bct >= NTREC) {
983 for (i = 0; i < NTREC; i++)
19ac1bc8 984 ((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
7d4dda01 985 bct = 0;
19ac1bc8 986 if ((i = read(mt, tbf, NTREC*TP_BSIZE)) < 0) {
003a2a9e 987 perror("Tape read error");
7d4dda01 988 eflag++;
003a2a9e 989 done(1);
7d4dda01
KM
990 }
991 if (i == 0) {
992 bct = NTREC + 1;
993 volno++;
994loop:
995 flsht();
996 close(mt);
003a2a9e 997 fprintf(stderr, "Mount volume %d\n", volno);
7d4dda01
KM
998 while (getchar() != '\n')
999 ;
1000 if ((mt = open(magtape, 0)) == -1) {
003a2a9e 1001 fprintf(stderr, "Cannot open tape!\n");
7d4dda01
KM
1002 goto loop;
1003 }
1004 if (readhdr(&tmpbuf) == 0) {
003a2a9e 1005 fprintf(stderr, "Not a dump tape.Try again\n");
7d4dda01
KM
1006 goto loop;
1007 }
1008 if (checkvol(&tmpbuf, volno) == 0) {
003a2a9e 1009 fprintf(stderr, "Wrong tape. Try again\n");
7d4dda01
KM
1010 goto loop;
1011 }
1012 readtape(b);
1013 return;
1014 }
1015 }
b45e25c0 1016 blkcpy(&tbf[(bct++*TP_BSIZE)], b, TP_BSIZE);
7d4dda01
KM
1017}
1018
1019flsht()
1020{
1021 bct = NTREC+1;
1022}
1023
b45e25c0
KM
1024blkcpy(from, to, size)
1025 char *from, *to;
1026 int size;
7d4dda01 1027{
b45e25c0 1028 asm(" movc3 12(ap),*4(ap),*8(ap)");
7d4dda01
KM
1029}
1030
b88e54cb
KM
1031blkclr(buf, size)
1032 char *buf;
1033 int size;
1034{
1035 asm("movc5 $0,(r0),$0,8(ap),*4(ap)");
1036}
1037
1038resetmt()
1039{
1040 struct mtop tcom;
1041
1042 if(dumpnum > 1)
1043 tcom.mt_op = MTBSF;
1044 else
1045 tcom.mt_op = MTREW;
1046 tcom.mt_count = 1;
1047 flsht();
1048 if (ioctl(mt,MTIOCTOP,&tcom) == -1) {
1049 /* kludge for disk dumps */
1050 lseek(mt, (long)0, 0);
1051 }
1052 if (dumpnum > 1) {
1053 tcom.mt_op = MTFSF;
1054 tcom.mt_count = 1;
1055 ioctl(mt,MTIOCTOP,&tcom);
1056 }
1057}
1058
bcfabedf
KM
1059checkvol(b, t)
1060 struct s_spcl *b;
1061 int t;
7d4dda01 1062{
bcfabedf
KM
1063 if (b->c_volume == t)
1064 return(1);
7d4dda01 1065 return(0);
7d4dda01
KM
1066}
1067
bcfabedf
KM
1068readhdr(b)
1069 struct s_spcl *b;
7d4dda01 1070{
bcfabedf 1071 if (gethead(b) == 0)
7d4dda01 1072 return(0);
bcfabedf
KM
1073 if (checktype(b, TS_TAPE) == 0)
1074 return(0);
1075 return(1);
7d4dda01 1076}
7d4dda01 1077
7d4dda01
KM
1078/*
1079 * read the tape into buf, then return whether or
1080 * or not it is a header block.
1081 */
1082gethead(buf)
0841dbb0 1083 struct s_spcl *buf;
7d4dda01
KM
1084{
1085 readtape((char *)buf);
0841dbb0 1086 if (buf->c_magic != MAGIC || checksum((int *)buf) == 0)
7d4dda01
KM
1087 return(0);
1088 return(1);
1089}
1090
1091/*
1092 * return whether or not the buffer contains a header block
1093 */
1094ishead(buf)
0841dbb0 1095 struct s_spcl *buf;
7d4dda01 1096{
0841dbb0 1097 if (buf->c_magic != MAGIC || checksum((int *)buf) == 0)
7d4dda01
KM
1098 return(0);
1099 return(1);
1100}
1101
1102checktype(b, t)
0841dbb0 1103 struct s_spcl *b;
003a2a9e 1104 int t;
7d4dda01 1105{
0841dbb0 1106 return(b->c_type == t);
7d4dda01
KM
1107}
1108
b88e54cb
KM
1109/*
1110 * read a bit mask from the tape into m.
1111 */
1112readbits(m)
b6407c9d 1113 char *m;
b88e54cb
KM
1114{
1115 register int i;
1116
1117 i = spcl.c_count;
1118
1119 while (i--) {
1120 readtape((char *) m);
b6407c9d 1121 m += (TP_BSIZE/(NBBY/BITS));
b88e54cb
KM
1122 }
1123 while (gethead(&spcl) == 0)
1124 ;
1125}
7d4dda01
KM
1126
1127checksum(b)
003a2a9e 1128 int *b;
7d4dda01 1129{
19ac1bc8 1130 register int i, j;
7d4dda01 1131
19ac1bc8 1132 j = sizeof(union u_spcl) / sizeof(int);
7d4dda01
KM
1133 i = 0;
1134 do
1135 i += *b++;
1136 while (--j);
1137 if (i != CHECKSUM) {
19ac1bc8 1138 fprintf(stderr, "Checksum error %o, ino %u\n", i, ino);
7d4dda01
KM
1139 return(0);
1140 }
1141 return(1);
1142}
1143
b88e54cb
KM
1144/*
1145 * Check for access into each directory in the pathname of an extracted
1146 * file and create such a directory if needed in preparation for moving
1147 * the file to its proper home.
1148 */
1149checkdir(name)
1150 register char *name;
1151{
1152 register char *cp;
1153 int i;
1154
1155 for (cp = name; *cp; cp++) {
1156 if (*cp == '/') {
1157 *cp = '\0';
1158 if (xaccess(name, 01) < 0) {
1159 register int pid, rp;
1160
1161 xumount();
1162 if ((pid = fork()) == 0) {
1163 execl("/bin/xmkdir", "xmkdir", name, 0);
1164 execl("/usr/bin/xmkdir", "xmkdir", name, 0);
1165 execl("./xmkdir", "xmkdir", name, 0);
1166 fprintf(stderr, "xrestor: cannot find xmkdir!\n");
1167 done(0);
1168 }
1169 while ((rp = wait(&i)) >= 0 && rp != pid)
1170 ;
1171 xmount(envp);
f7287e4b
KM
1172 fsptr = getfs(dev);
1173 parentino.i_fs = fsptr;
b88e54cb
KM
1174 }
1175 *cp = '/';
1176 }
1177 }
1178}
1179
b45e25c0
KM
1180/*
1181 * These variables are "local" to the following two functions.
1182 */
1183char dirbuf[DIRBLKSIZ];
1184long dirloc = 0;
1185long prev = 0;
1186
1187/*
1188 * add a new directory entry to a file.
1189 */
1190putent(dp, wrtfunc)
1191 struct direct *dp;
1192 int (*wrtfunc)();
1193{
1194 if (dp->d_ino == 0)
1195 return;
1196 for (;;) {
1197 if (dp->d_reclen < DIRBLKSIZ - dirloc) {
1198 blkcpy(dp, dirbuf + dirloc, dp->d_reclen);
1199 prev = dirloc;
1200 dirloc += dp->d_reclen;
1201 return;
1202 }
1203 ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
1204 (*wrtfunc)(dirbuf, DIRBLKSIZ);
1205 dirloc = 0;
1206 }
1207}
1208
1209/*
1210 * flush out a directory that is finished.
1211 */
1212flushent(wrtfunc)
1213 int (*wrtfunc)();
1214{
1215 ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
1216 (*wrtfunc)(dirbuf, dirloc);
1217 dirloc = 0;
1218}
1219
1220dirwrite(buf, size)
1221 char *buf;
1222 int size;
1223{
1224 fwrite(buf, 1, size, df);
1225 seekpt = ftell(df);
1226}
1227
1228dcvt(odp, ndp)
1229 register struct odirect *odp;
1230 register struct direct *ndp;
1231{
1232 struct inotab *itp;
1233
1234 blkclr(ndp, sizeof *ndp);
1235 ndp->d_ino = odp->d_ino;
1236 strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
1237 ndp->d_namlen = strlen(ndp->d_name);
1238 ndp->d_reclen = DIRSIZ(ndp);
1239 /*
1240 * this quickly calculates if this inode is a directory.
1241 * Currently not maintained.
1242 *
1243 for (itp = inotab[INOHASH(odp->d_ino)]; itp; itp = itp->t_next) {
1244 if (itp->t_ino != odp->d_ino)
1245 continue;
1246 ndp->d_fmt = IFDIR;
1247 break;
1248 }
1249 */
1250}
1251
1252/*
1253 * seek to an entry in a directory.
1254 * Only values returned by ``telldir'' should be passed to seekdir.
1255 * Modified to have many directories based in one file.
1256 */
1257void
1258seekdir(dirp, loc, base)
1259 register DIR *dirp;
1260 long loc, base;
1261{
1262 if (loc == telldir(dirp))
1263 return;
1264 loc -= base;
1265 if (loc < 0)
1266 fprintf(stderr, "bad seek pointer to seekdir %d\n", loc);
1267 lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0);
1268 dirp->dd_loc = loc & (DIRBLKSIZ - 1);
1269 if (dirp->dd_loc != 0)
1270 dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
1271}
1272
003a2a9e
KM
1273/*
1274 * tell whether an inode is allocated
1275 * this is drawn from ialloccg in sys/alloc.c
1276 */
f7287e4b
KM
1277iexist(ip, ino)
1278 struct inode *ip;
003a2a9e 1279 ino_t ino;
7d4dda01 1280{
003a2a9e
KM
1281 register struct fs *fs;
1282 register struct cg *cgp;
1283 register struct buf *bp;
1284 int cg;
1285
f7287e4b 1286 fs = ip->i_fs;
003a2a9e
KM
1287 if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg)
1288 return (0);
6994bf5d 1289 cg = itog(fs, ino);
f7287e4b 1290 bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), fs->fs_bsize);
d258ca7e
KM
1291 if (bp->b_flags & B_ERROR) {
1292 brelse(bp);
003a2a9e 1293 return(0);
d258ca7e 1294 }
003a2a9e
KM
1295 cgp = bp->b_un.b_cg;
1296 ino %= fs->fs_ipg;
1297 if (isclr(cgp->cg_iused, ino)) {
1298 brelse(bp);
1299 return(0);
1300 }
1301 brelse(bp);
1302 return (1);
7d4dda01
KM
1303}
1304
bcfabedf 1305allocinotab(ino, seekpt)
0841dbb0 1306 ino_t ino;
bcfabedf 1307 daddr_t seekpt;
7d4dda01 1308{
0841dbb0 1309 register struct inotab *itp;
19ac1bc8 1310
0841dbb0
KM
1311 itp = (struct inotab *)calloc(1, sizeof(struct inotab));
1312 itp->t_next = inotab[INOHASH(ino)];
1313 inotab[INOHASH(ino)] = itp;
1314 itp->t_ino = ino;
bcfabedf 1315 itp->t_seekpt = seekpt;
7d4dda01
KM
1316}
1317
bcfabedf 1318allocxtr(ino, name, flags)
0841dbb0 1319 ino_t ino;
bcfabedf
KM
1320 char *name;
1321 char flags;
7d4dda01 1322{
bcfabedf 1323 register struct xtrlist *xp, *pxp;
0841dbb0 1324
bcfabedf 1325 xp = (struct xtrlist *)calloc(1, sizeof(struct xtrlist) + strlen(name));
0841dbb0
KM
1326 xp->x_next = xtrlist[INOHASH(ino)];
1327 xtrlist[INOHASH(ino)] = xp;
1328 xp->x_ino = ino;
bcfabedf 1329 strcpy(xp->x_name, name);
0841dbb0 1330 xtrcnt++;
bcfabedf
KM
1331 xp->x_flags = flags;
1332 for (pxp = xp->x_next; pxp; pxp = pxp->x_next)
1333 if (pxp->x_ino == ino && (pxp->x_flags & XLINKED) == 0) {
1334 xp->x_flags |= XLINKED;
1335 xp->x_linkedto = pxp;
1336 xtrcnt--;
1337 break;
1338 }
1339 if (xp->x_flags & XLINKED)
1340 fprintf(stdout, "%s: linked to %s\n", xp->x_name, pxp->x_name);
1341 else if (xp->x_flags & XISDIR)
1342 fprintf(stdout, "%s: directory inode %u\n", xp->x_name, ino);
1343 else
1344 fprintf(stdout, "%s: inode %u\n", xp->x_name, ino);
7d4dda01
KM
1345}
1346
b88e54cb
KM
1347done(exitcode)
1348 int exitcode;
7d4dda01 1349{
b88e54cb
KM
1350#ifndef STANDALONE
1351 unlink(dirfile);
1352#endif
1353 if (mounted)
1354 xumount();
1355 exit(exitcode);
7d4dda01 1356}