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