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