parameterize BSIZE, FSIZE, and FRAG into fs_bsize, fs_fsize, and fs_frag
[unix-history] / usr / src / sbin / restore / main.c
CommitLineData
7d4dda01
KM
1/* Copyright (c) 1981 Regents of the University of California */
2
b6407c9d 3char version[] = "@(#)main.c 1.8 %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);
504 for (ino = 1; ino <= maxi; ino++)
505 if (BIT(ino, clrimap) == 0) {
506 if (!iexist(dev, ino))
507 continue;
508 ip = iget(dev, ino);
509 if (ip == NULL) {
510 fprintf(stderr, "can't find inode %u\n", ino);
511 done(1);
7d4dda01 512 }
0841dbb0
KM
513 ip->i_nlink = 0;
514 ip->i_flag |= ICHG;
515 iput(ip);
003a2a9e 516 }
0841dbb0
KM
517 goto ragain;
518 }
519 if (checktype(&spcl, TS_BITS) == 1) {
520 readbits(dumpmap);
521 goto ragain;
522 }
523 if (checktype(&spcl, TS_INODE) == 0) {
524 fprintf(stderr, "Unknown header type\n");
525 eflag++;
526 gethead(&spcl);
527 goto ragain;
528 }
529 ino = spcl.c_inumber;
530 if (eflag)
531 fprintf(stderr, "Resynced at inode %u\n", ino);
532 eflag = 0;
533 if (ino > maxi) {
534 fprintf(stderr, "%u: ilist too small\n", ino);
535 gethead(&spcl);
536 goto ragain;
537 }
538 if (iexist(dev, ino)) {
539 ip = iget(dev, ino);
540 if (ip == NULL) {
541 fprintf(stderr, "can't find inode %u\n",
542 ino);
003a2a9e
KM
543 done(1);
544 }
0841dbb0 545 ip->i_nlink = 0;
003a2a9e
KM
546 ip->i_flag |= ICHG;
547 iput(ip);
7d4dda01 548 }
0841dbb0
KM
549 dp = &spcl.c_dinode;
550 ip = ialloc(dev, ino, dp->di_mode);
551 if (ip == NULL || ip->i_number != ino) {
552 fprintf(stderr, "can't create inode %u\n", ino);
553 done(1);
554 }
555 ip->i_mode = mode = dp->di_mode;
556 ip->i_nlink = dp->di_nlink;
557 ip->i_uid = dp->di_uid;
558 ip->i_gid = dp->di_gid;
559 ip->i_atime = dp->di_atime;
560 ip->i_mtime = dp->di_mtime;
561 ip->i_ctime = dp->di_ctime;
b88e54cb
KM
562 type = ip->i_mode & IFMT;
563 if (type == IFCHR || type == IFBLK)
0841dbb0
KM
564 ip->i_rdev = dp->di_rdev;
565 ip->i_size = 0;
566 cur_ip = ip;
567 u.u_offset = 0;
568 u.u_segflg = 1;
b88e54cb
KM
569 if (cvtdir && type == IFDIR)
570 getfile(rstrcvtdir, rstrcvtskip, dp->di_size);
571 else
572 getfile(rstrfile, rstrskip, dp->di_size);
0841dbb0
KM
573 ip->i_mode = mode;
574 ip->i_flag &= ~(IUPD|IACC);
575 ip->i_flag |= ICHG;
576 iput(ip);
7d4dda01
KM
577 }
578}
579
580/*
581 * Read the tape, bulding up a directory structure for extraction
582 * by name
583 */
584#ifndef STANDALONE
b88e54cb
KM
585pass1(savedir)
586 int savedir;
7d4dda01 587{
19ac1bc8 588 register int i;
0841dbb0
KM
589 register struct dinode *ip;
590 struct direct nulldir;
b88e54cb
KM
591 char buf[TP_BSIZE];
592 int putdir(), null();
7d4dda01 593
0841dbb0
KM
594 nulldir.d_ino = 0;
595 strncpy(nulldir.d_name, "/", DIRSIZ);
7d4dda01 596 while (gethead(&spcl) == 0) {
003a2a9e 597 fprintf(stderr, "Can't find directory header!\n");
7d4dda01
KM
598 }
599 for (;;) {
600 if (checktype(&spcl, TS_BITS) == 1) {
601 readbits(dumpmap);
602 continue;
603 }
604 if (checktype(&spcl, TS_CLRI) == 1) {
605 readbits(clrimap);
606 continue;
607 }
608 if (checktype(&spcl, TS_INODE) == 0) {
609finish:
b88e54cb
KM
610 if (savedir)
611 freopen(dirfile, "r", df);
612 resetmt();
7d4dda01
KM
613 return;
614 }
615 ip = &spcl.c_dinode;
616 i = ip->di_mode & IFMT;
617 if (i != IFDIR) {
618 goto finish;
619 }
b88e54cb
KM
620 if (spcl.c_inumber == ROOTINO) {
621 readtape(buf);
622 bct--; /* push back this block */
623 if (((struct direct *)buf)->d_ino != ROOTINO) {
624 if (((struct odirect *)buf)->d_ino != ROOTINO) {
625 fprintf(stderr, "bad root directory\n");
626 done(1);
627 }
628 fprintf(stderr, "converting to new directory format\n");
629 cvtdir = 1;
630 }
631 if (!savedir && !cvtdir) {
632 /* if no conversion, just return */
633 goto finish;
634 }
635 }
bcfabedf 636 allocinotab(spcl.c_inumber, seekpt);
b88e54cb
KM
637 if (savedir) {
638 getfile(putdir, null, spcl.c_dinode.di_size);
639 putent(&nulldir);
640 } else {
641 getfile(null, null, spcl.c_dinode.di_size);
642 }
7d4dda01
KM
643 }
644}
645#endif
646
bcfabedf
KM
647/*
648 * Put the directory entries in the directory file
649 */
650#ifndef STANDALONE
651putdir(buf, size)
652 char *buf;
653 int size;
654{
b88e54cb
KM
655 struct direct cvtbuf;
656 register struct odirect *odp;
657 struct odirect *eodp;
bcfabedf 658 register struct direct *dp;
b88e54cb
KM
659 struct direct *edp;
660
661 if (cvtdir) {
662 eodp = (struct odirect *)&buf[size];
663 for (odp = (struct odirect *)buf; odp < eodp; odp++)
664 if (odp->d_ino != 0) {
665 dcvt(odp, &cvtbuf);
666 putent(&cvtbuf);
667 }
668 } else {
669 edp = (struct direct *)&buf[size];
670 for (dp = (struct direct *)buf; dp < edp; dp++)
671 if (dp->d_ino != 0)
672 putent(dp);
673 }
bcfabedf
KM
674}
675
676putent(dp)
677 struct direct *dp;
678{
679 fwrite(dp, 1, sizeof(struct direct), df);
680 seekpt = ftell(df);
681}
682
b88e54cb
KM
683dcvt(odp, ndp)
684 register struct odirect *odp;
685 register struct direct *ndp;
686{
687 register struct inotab *itp;
688
689 blkclr(ndp, sizeof *ndp);
690 ndp->d_ino = odp->d_ino;
691 strncpy(ndp->d_name, odp->d_name, DIRSIZ);
692 for (itp = inotab[INOHASH(odp->d_ino)]; itp; itp = itp->t_next) {
693 if (itp->t_ino != odp->d_ino)
694 continue;
695 ndp->d_mode = IFDIR;
696 break;
697 }
698}
699
bcfabedf
KM
700/*
701 * Recursively find names and inumbers of all files in subtree
702 * pname and put them in xtrlist[]
703 */
704getleaves(ino, pname)
705 ino_t ino;
706 char *pname;
707{
708 register struct inotab *itp;
709 int namelen;
710 daddr_t bpt;
711 struct direct dir;
712 char locname[BUFSIZ + 1];
713
714 if (BIT(ino, dumpmap) == 0) {
715 fprintf(stdout, "%s: not on the tape\n", pname);
716 return;
717 }
718 for (itp = inotab[INOHASH(ino)]; itp; itp = itp->t_next) {
719 if (itp->t_ino != ino)
720 continue;
721 /*
722 * pname is a directory name
723 */
724 allocxtr(ino, pname, XISDIR);
725 /*
726 * begin search through the directory
727 * skipping over "." and ".."
728 */
729 strncpy(locname, pname, BUFSIZ);
730 strncat(locname, "/", BUFSIZ);
731 namelen = strlen(locname);
732 fseek(df, itp->t_seekpt, 0);
733 fread(&dir, 1, sizeof(struct direct), df);
734 fread(&dir, 1, sizeof(struct direct), df);
735 fread(&dir, 1, sizeof(struct direct), df);
736 bpt = ftell(df);
737 /*
738 * "/" signals end of directory
739 */
740 while (strncmp(dir.d_name, "/", DIRSIZ)) {
741 locname[namelen] = '\0';
742 strncat(locname, dir.d_name, DIRSIZ);
743 if (strlen(locname) >= BUFSIZ) {
744 fprintf(stderr, "%s: name exceedes %d char\n",
745 locname, BUFSIZ);
746 continue;
747 }
748 getleaves(dir.d_ino, locname);
749 fseek(df, bpt, 0);
750 fread(&dir, 1, sizeof(struct direct), df);
751 bpt = ftell(df);
752 }
753 return;
754 }
755 /*
756 * locname is name of a simple file
757 */
758 allocxtr(ino, pname, XINUSE);
759}
760
761/*
762 * Search the directory tree rooted at inode ROOTINO
763 * for the path pointed at by n
764 */
765psearch(n)
766 char *n;
767{
768 register char *cp, *cp1;
769 char c;
770
771 ino = ROOTINO;
772 if (*(cp = n) == '/')
773 cp++;
774next:
775 cp1 = cp + 1;
776 while (*cp1 != '/' && *cp1)
777 cp1++;
778 c = *cp1;
779 *cp1 = 0;
780 ino = search(ino, cp);
781 if (ino == 0) {
782 *cp1 = c;
783 return(0);
784 }
785 *cp1 = c;
786 if (c == '/') {
787 cp = cp1+1;
788 goto next;
789 }
790 return(ino);
791}
792
793/*
794 * search the directory inode ino
795 * looking for entry cp
796 */
797ino_t
798search(inum, cp)
799 ino_t inum;
800 char *cp;
801{
802 struct direct dir;
803 register struct inotab *itp;
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:
810 fseek(df, itp->t_seekpt, 0);
811 do {
812 fread(&dir, 1, sizeof(struct direct), df);
813 if (!strncmp(dir.d_name, "/", DIRSIZ))
814 return(0);
815 } while (strncmp(dir.d_name, cp, DIRSIZ));
816 return(dir.d_ino);
817}
818#endif
819
7d4dda01
KM
820/*
821 * Do the file extraction, calling the supplied functions
822 * with the blocks
823 */
003a2a9e
KM
824getfile(f1, f2, size)
825 int (*f2)(), (*f1)();
826 long size;
7d4dda01 827{
19ac1bc8 828 register int i;
b6407c9d 829 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
0841dbb0 830 union u_spcl addrblk;
b6407c9d 831 register struct fs *fs;
0841dbb0 832# define addrblock addrblk.s_spcl
7d4dda01 833
0841dbb0 834 addrblock = spcl;
b6407c9d 835 fs = getfs(dev);
7d4dda01 836 for (;;) {
0841dbb0
KM
837 for (i = 0; i < addrblock.c_count; i++) {
838 if (addrblock.c_addr[i]) {
19ac1bc8 839 readtape(&buf[curblk++][0]);
b6407c9d 840 if (curblk == BLKING(fs) * fs->fs_frag) {
19ac1bc8 841 (*f1)(buf, size > TP_BSIZE ?
b6407c9d 842 (long) (BLKING(fs) * fs->fs_frag * TP_BSIZE) :
19ac1bc8
KM
843 (curblk - 1) * TP_BSIZE + size);
844 curblk = 0;
845 }
b6407c9d 846 } else {
19ac1bc8
KM
847 if (curblk > 0) {
848 (*f1)(buf, size > TP_BSIZE ?
849 (long) (curblk * TP_BSIZE) :
850 (curblk - 1) * TP_BSIZE + size);
851 curblk = 0;
852 }
b6407c9d
KM
853 (*f2)(clearedbuf, size > TP_BSIZE ?
854 (long) TP_BSIZE : size);
7d4dda01 855 }
19ac1bc8 856 if ((size -= TP_BSIZE) <= 0) {
7d4dda01
KM
857eloop:
858 while (gethead(&spcl) == 0)
859 ;
860 if (checktype(&spcl, TS_ADDR) == 1)
861 goto eloop;
19ac1bc8 862 goto out;
7d4dda01
KM
863 }
864 }
0841dbb0 865 if (gethead(&addrblock) == 0) {
19ac1bc8 866 fprintf(stderr, "Missing address (header) block, ino%u\n", ino);
003a2a9e
KM
867 goto eloop;
868 }
0841dbb0
KM
869 if (checktype(&addrblock, TS_ADDR) == 0) {
870 spcl = addrblock;
19ac1bc8 871 goto out;
003a2a9e 872 }
7d4dda01 873 }
19ac1bc8
KM
874out:
875 if (curblk > 0) {
876 (*f1)(buf, (curblk * TP_BSIZE) + size);
877 curblk = 0;
878 }
7d4dda01
KM
879}
880
bcfabedf
KM
881/*
882 * The next routines are called during file extraction to
883 * put the data into the right form and place.
884 */
885#ifndef STANDALONE
886xtrfile(buf, size)
887 char *buf;
888 long size;
889{
890 if (xwrite(ofile, buf, (int) size) == -1) {
b88e54cb 891 perror("extract write");
bcfabedf
KM
892 done(1);
893 }
894}
895
b88e54cb 896xtrskip(buf, size)
bcfabedf
KM
897 char *buf;
898 long size;
899{
900 if (xseek(ofile, size, 1) == -1) {
b88e54cb 901 perror("extract seek");
bcfabedf
KM
902 done(1);
903 }
904}
bcfabedf 905
b88e54cb
KM
906xtrcvtdir(buf, size)
907 struct odirect *buf;
908 long size;
909{
b6407c9d
KM
910 struct direct
911 cvtbuf[MAXBSIZE / sizeof(struct odirect)];
b88e54cb
KM
912 struct odirect *odp, *edp;
913 struct direct *dp;
914
915 edp = &buf[size / sizeof(struct odirect)];
916 for (odp = buf, dp = cvtbuf; odp < edp; odp++, dp++)
917 dcvt(odp, dp);
918 size = size * sizeof(struct direct) / sizeof(struct odirect);
919 if (xwrite(ofile, cvtbuf, (int) size) == -1) {
920 perror("extract write");
921 done(1);
922 }
923}
924
925xtrcvtskip(buf, size)
926 char *buf;
927 long size;
928{
929 fprintf(stderr, "unallocated block in directory\n");
930 if (xseek(ofile, size, 1) == -1) {
931 perror("extract seek");
932 done(1);
933 }
934}
935#endif
bcfabedf
KM
936
937rstrfile(buf, size)
938 char *buf;
939 long size;
940{
941 u.u_base = buf;
942 u.u_count = size;
943 writei(cur_ip);
944 if (u.u_error) {
b88e54cb 945 perror("restor write");
bcfabedf
KM
946 done(1);
947 }
948}
949
950rstrskip(buf, size)
951 char *buf;
952 long size;
953{
954 u.u_offset += size;
955}
956
b88e54cb
KM
957rstrcvtdir(buf, size)
958 struct odirect *buf;
959 long size;
960{
b6407c9d
KM
961 struct direct
962 cvtbuf[MAXBSIZE / sizeof(struct odirect)];
b88e54cb
KM
963 struct odirect *odp, *edp;
964 struct direct *dp;
965
966 edp = &buf[size / sizeof(struct odirect)];
967 for (odp = buf, dp = cvtbuf; odp < edp; odp++, dp++)
968 dcvt(odp, dp);
969 u.u_base = (char *)cvtbuf;
970 u.u_count = size * sizeof(struct direct) / sizeof(struct odirect);
971 writei(cur_ip);
972 if (u.u_error) {
973 perror("restor write");
974 done(1);
975 }
976}
977
978rstrcvtskip(buf, size)
979 char *buf;
980 long size;
981{
982 fprintf(stderr, "unallocated block in directory\n");
983 u.u_offset += size;
984}
985
bcfabedf
KM
986null() {;}
987
7d4dda01 988/*
19ac1bc8 989 * Do the tape i/o, dealing with volume changes
7d4dda01
KM
990 * etc..
991 */
992readtape(b)
003a2a9e 993 char *b;
7d4dda01 994{
19ac1bc8 995 register int i;
0841dbb0 996 struct s_spcl tmpbuf;
7d4dda01
KM
997
998 if (bct >= NTREC) {
999 for (i = 0; i < NTREC; i++)
19ac1bc8 1000 ((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
7d4dda01 1001 bct = 0;
19ac1bc8 1002 if ((i = read(mt, tbf, NTREC*TP_BSIZE)) < 0) {
003a2a9e 1003 perror("Tape read error");
7d4dda01 1004 eflag++;
003a2a9e 1005 done(1);
7d4dda01
KM
1006 }
1007 if (i == 0) {
1008 bct = NTREC + 1;
1009 volno++;
1010loop:
1011 flsht();
1012 close(mt);
003a2a9e 1013 fprintf(stderr, "Mount volume %d\n", volno);
7d4dda01
KM
1014 while (getchar() != '\n')
1015 ;
1016 if ((mt = open(magtape, 0)) == -1) {
003a2a9e 1017 fprintf(stderr, "Cannot open tape!\n");
7d4dda01
KM
1018 goto loop;
1019 }
1020 if (readhdr(&tmpbuf) == 0) {
003a2a9e 1021 fprintf(stderr, "Not a dump tape.Try again\n");
7d4dda01
KM
1022 goto loop;
1023 }
1024 if (checkvol(&tmpbuf, volno) == 0) {
003a2a9e 1025 fprintf(stderr, "Wrong tape. Try again\n");
7d4dda01
KM
1026 goto loop;
1027 }
1028 readtape(b);
1029 return;
1030 }
1031 }
19ac1bc8 1032 copy(&tbf[(bct++*TP_BSIZE)], b, TP_BSIZE);
7d4dda01
KM
1033}
1034
1035flsht()
1036{
1037 bct = NTREC+1;
1038}
1039
1040copy(f, t, s)
003a2a9e 1041 register char *f, *t;
7d4dda01 1042{
19ac1bc8 1043 register int i;
7d4dda01
KM
1044
1045 i = s;
1046 do
1047 *t++ = *f++;
1048 while (--i);
1049}
1050
b88e54cb
KM
1051blkclr(buf, size)
1052 char *buf;
1053 int size;
1054{
1055 asm("movc5 $0,(r0),$0,8(ap),*4(ap)");
1056}
1057
1058resetmt()
1059{
1060 struct mtop tcom;
1061
1062 if(dumpnum > 1)
1063 tcom.mt_op = MTBSF;
1064 else
1065 tcom.mt_op = MTREW;
1066 tcom.mt_count = 1;
1067 flsht();
1068 if (ioctl(mt,MTIOCTOP,&tcom) == -1) {
1069 /* kludge for disk dumps */
1070 lseek(mt, (long)0, 0);
1071 }
1072 if (dumpnum > 1) {
1073 tcom.mt_op = MTFSF;
1074 tcom.mt_count = 1;
1075 ioctl(mt,MTIOCTOP,&tcom);
1076 }
1077}
1078
bcfabedf
KM
1079checkvol(b, t)
1080 struct s_spcl *b;
1081 int t;
7d4dda01 1082{
bcfabedf
KM
1083 if (b->c_volume == t)
1084 return(1);
7d4dda01 1085 return(0);
7d4dda01
KM
1086}
1087
bcfabedf
KM
1088readhdr(b)
1089 struct s_spcl *b;
7d4dda01 1090{
bcfabedf 1091 if (gethead(b) == 0)
7d4dda01 1092 return(0);
bcfabedf
KM
1093 if (checktype(b, TS_TAPE) == 0)
1094 return(0);
1095 return(1);
7d4dda01 1096}
7d4dda01 1097
7d4dda01
KM
1098/*
1099 * read the tape into buf, then return whether or
1100 * or not it is a header block.
1101 */
1102gethead(buf)
0841dbb0 1103 struct s_spcl *buf;
7d4dda01
KM
1104{
1105 readtape((char *)buf);
0841dbb0 1106 if (buf->c_magic != MAGIC || checksum((int *)buf) == 0)
7d4dda01
KM
1107 return(0);
1108 return(1);
1109}
1110
1111/*
1112 * return whether or not the buffer contains a header block
1113 */
1114ishead(buf)
0841dbb0 1115 struct s_spcl *buf;
7d4dda01 1116{
0841dbb0 1117 if (buf->c_magic != MAGIC || checksum((int *)buf) == 0)
7d4dda01
KM
1118 return(0);
1119 return(1);
1120}
1121
1122checktype(b, t)
0841dbb0 1123 struct s_spcl *b;
003a2a9e 1124 int t;
7d4dda01 1125{
0841dbb0 1126 return(b->c_type == t);
7d4dda01
KM
1127}
1128
b88e54cb
KM
1129/*
1130 * read a bit mask from the tape into m.
1131 */
1132readbits(m)
b6407c9d 1133 char *m;
b88e54cb
KM
1134{
1135 register int i;
1136
1137 i = spcl.c_count;
1138
1139 while (i--) {
1140 readtape((char *) m);
b6407c9d 1141 m += (TP_BSIZE/(NBBY/BITS));
b88e54cb
KM
1142 }
1143 while (gethead(&spcl) == 0)
1144 ;
1145}
7d4dda01
KM
1146
1147checksum(b)
003a2a9e 1148 int *b;
7d4dda01 1149{
19ac1bc8 1150 register int i, j;
7d4dda01 1151
19ac1bc8 1152 j = sizeof(union u_spcl) / sizeof(int);
7d4dda01
KM
1153 i = 0;
1154 do
1155 i += *b++;
1156 while (--j);
1157 if (i != CHECKSUM) {
19ac1bc8 1158 fprintf(stderr, "Checksum error %o, ino %u\n", i, ino);
7d4dda01
KM
1159 return(0);
1160 }
1161 return(1);
1162}
1163
b88e54cb
KM
1164/*
1165 * Check for access into each directory in the pathname of an extracted
1166 * file and create such a directory if needed in preparation for moving
1167 * the file to its proper home.
1168 */
1169checkdir(name)
1170 register char *name;
1171{
1172 register char *cp;
1173 int i;
1174
1175 for (cp = name; *cp; cp++) {
1176 if (*cp == '/') {
1177 *cp = '\0';
1178 if (xaccess(name, 01) < 0) {
1179 register int pid, rp;
1180
1181 xumount();
1182 if ((pid = fork()) == 0) {
1183 execl("/bin/xmkdir", "xmkdir", name, 0);
1184 execl("/usr/bin/xmkdir", "xmkdir", name, 0);
1185 execl("./xmkdir", "xmkdir", name, 0);
1186 fprintf(stderr, "xrestor: cannot find xmkdir!\n");
1187 done(0);
1188 }
1189 while ((rp = wait(&i)) >= 0 && rp != pid)
1190 ;
1191 xmount(envp);
1192 }
1193 *cp = '/';
1194 }
1195 }
1196}
1197
003a2a9e
KM
1198/*
1199 * tell whether an inode is allocated
1200 * this is drawn from ialloccg in sys/alloc.c
1201 */
1202iexist(dev, ino)
1203 dev_t dev;
1204 ino_t ino;
7d4dda01 1205{
003a2a9e
KM
1206 register struct fs *fs;
1207 register struct cg *cgp;
1208 register struct buf *bp;
1209 int cg;
1210
1211 fs = getfs(dev);
1212 if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg)
1213 return (0);
1214 cg = itog(ino, fs);
b6407c9d 1215 bp = bread(dev, fsbtodb(fs, cgtod(cg, fs)), fs->fs_bsize);
003a2a9e
KM
1216 if (bp->b_flags & B_ERROR)
1217 return(0);
1218 cgp = bp->b_un.b_cg;
1219 ino %= fs->fs_ipg;
1220 if (isclr(cgp->cg_iused, ino)) {
1221 brelse(bp);
1222 return(0);
1223 }
1224 brelse(bp);
1225 return (1);
7d4dda01
KM
1226}
1227
bcfabedf 1228allocinotab(ino, seekpt)
0841dbb0 1229 ino_t ino;
bcfabedf 1230 daddr_t seekpt;
7d4dda01 1231{
0841dbb0 1232 register struct inotab *itp;
19ac1bc8 1233
0841dbb0
KM
1234 itp = (struct inotab *)calloc(1, sizeof(struct inotab));
1235 itp->t_next = inotab[INOHASH(ino)];
1236 inotab[INOHASH(ino)] = itp;
1237 itp->t_ino = ino;
bcfabedf 1238 itp->t_seekpt = seekpt;
7d4dda01
KM
1239}
1240
bcfabedf 1241allocxtr(ino, name, flags)
0841dbb0 1242 ino_t ino;
bcfabedf
KM
1243 char *name;
1244 char flags;
7d4dda01 1245{
bcfabedf 1246 register struct xtrlist *xp, *pxp;
0841dbb0 1247
bcfabedf 1248 xp = (struct xtrlist *)calloc(1, sizeof(struct xtrlist) + strlen(name));
0841dbb0
KM
1249 xp->x_next = xtrlist[INOHASH(ino)];
1250 xtrlist[INOHASH(ino)] = xp;
1251 xp->x_ino = ino;
bcfabedf 1252 strcpy(xp->x_name, name);
0841dbb0 1253 xtrcnt++;
bcfabedf
KM
1254 xp->x_flags = flags;
1255 for (pxp = xp->x_next; pxp; pxp = pxp->x_next)
1256 if (pxp->x_ino == ino && (pxp->x_flags & XLINKED) == 0) {
1257 xp->x_flags |= XLINKED;
1258 xp->x_linkedto = pxp;
1259 xtrcnt--;
1260 break;
1261 }
1262 if (xp->x_flags & XLINKED)
1263 fprintf(stdout, "%s: linked to %s\n", xp->x_name, pxp->x_name);
1264 else if (xp->x_flags & XISDIR)
1265 fprintf(stdout, "%s: directory inode %u\n", xp->x_name, ino);
1266 else
1267 fprintf(stdout, "%s: inode %u\n", xp->x_name, ino);
7d4dda01
KM
1268}
1269
b88e54cb
KM
1270done(exitcode)
1271 int exitcode;
7d4dda01 1272{
b88e54cb
KM
1273#ifndef STANDALONE
1274 unlink(dirfile);
1275#endif
1276 if (mounted)
1277 xumount();
1278 exit(exitcode);
7d4dda01 1279}