1 /*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7 #ifndef lint
8 static char sccsid[] = "@(#)tape.c 5.10 (Berkeley) 1/28/87";
9 #endif not lint
10
11 #include "restore.h"
12 #include <protocols/dumprestore.h>
13 #include <sys/ioctl.h>
14 #include <sys/mtio.h>
15 #include <sys/file.h>
16 #include <setjmp.h>
17 #include <sys/stat.h>
18
19 static long fssize = MAXBSIZE;
20 static int mt = -1;
21 static int pipein = 0;
22 static char magtape[BUFSIZ];
23 static int bct;
24 static char *tbf;
25 static union u_spcl endoftapemark;
26 static long blksread;
27 static long tapesread;
28 static jmp_buf restart;
29 static int gettingfile = 0; /* restart has a valid frame */
30
31 static int ofile;
32 static char *map;
33 static char lnkbuf[MAXPATHLEN + 1];
34 static int pathlen;
35
36 int Bcvt; /* Swap Bytes (for CCI or sun) */
37 static int Qcvt; /* Swap quads (for sun) */
38 /*
39 * Set up an input source
40 */
setinput(source)41 setinput(source)
42 char *source;
43 {
44 #ifdef RRESTORE
45 char *host, *tape;
46 #endif RRESTORE
47
48 flsht();
49 if (bflag)
50 newtapebuf(ntrec);
51 else
52 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
53 terminal = stdin;
54 #ifdef RRESTORE
55 host = source;
56 tape = index(host, ':');
57 if (tape == 0) {
58 nohost:
59 msg("need keyletter ``f'' and device ``host:tape''\n");
60 done(1);
61 }
62 *tape++ = '\0';
63 (void) strcpy(magtape, tape);
64 if (rmthost(host) == 0)
65 done(1);
66 setuid(getuid()); /* no longer need or want root privileges */
67 #else
68 if (strcmp(source, "-") == 0) {
69 /*
70 * Since input is coming from a pipe we must establish
71 * our own connection to the terminal.
72 */
73 terminal = fopen("/dev/tty", "r");
74 if (terminal == NULL) {
75 perror("Cannot open(\"/dev/tty\")");
76 terminal = fopen("/dev/null", "r");
77 if (terminal == NULL) {
78 perror("Cannot open(\"/dev/null\")");
79 done(1);
80 }
81 }
82 pipein++;
83 }
84 (void) strcpy(magtape, source);
85 #endif RRESTORE
86 }
87
newtapebuf(size)88 newtapebuf(size)
89 long size;
90 {
91 static tbfsize = -1;
92
93 ntrec = size;
94 if (size <= tbfsize)
95 return;
96 if (tbf != NULL)
97 free(tbf);
98 tbf = (char *)malloc(size * TP_BSIZE);
99 if (tbf == NULL) {
100 fprintf(stderr, "Cannot allocate space for tape buffer\n");
101 done(1);
102 }
103 tbfsize = size;
104 }
105
106 /*
107 * Verify that the tape drive can be accessed and
108 * that it actually is a dump tape.
109 */
setup()110 setup()
111 {
112 int i, j, *ip;
113 struct stat stbuf;
114 extern char *ctime();
115 extern int xtrmap(), xtrmapskip();
116
117 vprintf(stdout, "Verify tape and initialize maps\n");
118 #ifdef RRESTORE
119 if ((mt = rmtopen(magtape, 0)) < 0)
120 #else
121 if (pipein)
122 mt = 0;
123 else if ((mt = open(magtape, 0)) < 0)
124 #endif
125 {
126 perror(magtape);
127 done(1);
128 }
129 volno = 1;
130 setdumpnum();
131 flsht();
132 if (!pipein && !bflag)
133 findtapeblksize();
134 if (gethead(&spcl) == FAIL) {
135 bct--; /* push back this block */
136 cvtflag++;
137 if (gethead(&spcl) == FAIL) {
138 fprintf(stderr, "Tape is not a dump tape\n");
139 done(1);
140 }
141 fprintf(stderr, "Converting to new file system format.\n");
142 }
143 if (pipein) {
144 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
145 endoftapemark.s_spcl.c_type = TS_END;
146 ip = (int *)&endoftapemark;
147 j = sizeof(union u_spcl) / sizeof(int);
148 i = 0;
149 do
150 i += *ip++;
151 while (--j);
152 endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
153 }
154 if (vflag || command == 't')
155 printdumpinfo();
156 dumptime = spcl.c_ddate;
157 dumpdate = spcl.c_date;
158 if (stat(".", &stbuf) < 0) {
159 perror("cannot stat .");
160 done(1);
161 }
162 if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
163 fssize = stbuf.st_blksize;
164 if (((fssize - 1) & fssize) != 0) {
165 fprintf(stderr, "bad block size %d\n", fssize);
166 done(1);
167 }
168 if (checkvol(&spcl, (long)1) == FAIL) {
169 fprintf(stderr, "Tape is not volume 1 of the dump\n");
170 done(1);
171 }
172 if (readhdr(&spcl) == FAIL)
173 panic("no header after volume mark!\n");
174 findinode(&spcl);
175 if (checktype(&spcl, TS_CLRI) == FAIL) {
176 fprintf(stderr, "Cannot find file removal list\n");
177 done(1);
178 }
179 maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
180 dprintf(stdout, "maxino = %d\n", maxino);
181 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
182 if (map == (char *)NIL)
183 panic("no memory for file removal list\n");
184 clrimap = map;
185 curfile.action = USING;
186 getfile(xtrmap, xtrmapskip);
187 if (checktype(&spcl, TS_BITS) == FAIL) {
188 fprintf(stderr, "Cannot find file dump list\n");
189 done(1);
190 }
191 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
192 if (map == (char *)NULL)
193 panic("no memory for file dump list\n");
194 dumpmap = map;
195 curfile.action = USING;
196 getfile(xtrmap, xtrmapskip);
197 }
198
199 /*
200 * Prompt user to load a new dump volume.
201 * "Nextvol" is the next suggested volume to use.
202 * This suggested volume is enforced when doing full
203 * or incremental restores, but can be overrridden by
204 * the user when only extracting a subset of the files.
205 */
getvol(nextvol)206 getvol(nextvol)
207 long nextvol;
208 {
209 long newvol;
210 long savecnt, i;
211 union u_spcl tmpspcl;
212 # define tmpbuf tmpspcl.s_spcl
213 char buf[TP_BSIZE];
214
215 if (nextvol == 1) {
216 tapesread = 0;
217 gettingfile = 0;
218 }
219 if (pipein) {
220 if (nextvol != 1)
221 panic("Changing volumes on pipe input?\n");
222 if (volno == 1)
223 return;
224 goto gethdr;
225 }
226 savecnt = blksread;
227 again:
228 if (pipein)
229 done(1); /* pipes do not get a second chance */
230 if (command == 'R' || command == 'r' || curfile.action != SKIP)
231 newvol = nextvol;
232 else
233 newvol = 0;
234 while (newvol <= 0) {
235 if (tapesread == 0) {
236 fprintf(stderr, "%s%s%s%s%s",
237 "You have not read any tapes yet.\n",
238 "Unless you know which volume your",
239 " file(s) are on you should start\n",
240 "with the last volume and work",
241 " towards towards the first.\n");
242 } else {
243 fprintf(stderr, "You have read volumes");
244 strcpy(tbf, ": ");
245 for (i = 1; i < 32; i++)
246 if (tapesread & (1 << i)) {
247 fprintf(stderr, "%s%d", tbf, i);
248 strcpy(tbf, ", ");
249 }
250 fprintf(stderr, "\n");
251 }
252 do {
253 fprintf(stderr, "Specify next volume #: ");
254 (void) fflush(stderr);
255 (void) fgets(tbf, BUFSIZ, terminal);
256 } while (!feof(terminal) && tbf[0] == '\n');
257 if (feof(terminal))
258 done(1);
259 newvol = atoi(tbf);
260 if (newvol <= 0) {
261 fprintf(stderr,
262 "Volume numbers are positive numerics\n");
263 }
264 }
265 if (newvol == volno) {
266 tapesread |= 1 << volno;
267 return;
268 }
269 closemt();
270 fprintf(stderr, "Mount tape volume %d\n", newvol);
271 fprintf(stderr, "then enter tape name (default: %s) ", magtape);
272 (void) fflush(stderr);
273 (void) fgets(tbf, BUFSIZ, terminal);
274 if (feof(terminal))
275 done(1);
276 if (tbf[0] != '\n') {
277 (void) strcpy(magtape, tbf);
278 magtape[strlen(magtape) - 1] = '\0';
279 }
280 #ifdef RRESTORE
281 if ((mt = rmtopen(magtape, 0)) == -1)
282 #else
283 if ((mt = open(magtape, 0)) == -1)
284 #endif
285 {
286 fprintf(stderr, "Cannot open %s\n", magtape);
287 volno = -1;
288 goto again;
289 }
290 gethdr:
291 volno = newvol;
292 setdumpnum();
293 flsht();
294 if (readhdr(&tmpbuf) == FAIL) {
295 fprintf(stderr, "tape is not dump tape\n");
296 volno = 0;
297 goto again;
298 }
299 if (checkvol(&tmpbuf, volno) == FAIL) {
300 fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
301 volno = 0;
302 goto again;
303 }
304 if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
305 fprintf(stderr, "Wrong dump date\n\tgot: %s",
306 ctime(&tmpbuf.c_date));
307 fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
308 volno = 0;
309 goto again;
310 }
311 tapesread |= 1 << volno;
312 blksread = savecnt;
313 if (curfile.action == USING) {
314 if (volno == 1)
315 panic("active file into volume 1\n");
316 return;
317 }
318 /*
319 * Skip up to the beginning of the next record
320 */
321 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
322 for (i = tmpbuf.c_count; i > 0; i--)
323 readtape(buf);
324 (void) gethead(&spcl);
325 findinode(&spcl);
326 if (gettingfile) {
327 gettingfile = 0;
328 longjmp(restart, 1);
329 }
330 }
331
332 /*
333 * handle multiple dumps per tape by skipping forward to the
334 * appropriate one.
335 */
setdumpnum()336 setdumpnum()
337 {
338 struct mtop tcom;
339
340 if (dumpnum == 1 || volno != 1)
341 return;
342 if (pipein) {
343 fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
344 done(1);
345 }
346 tcom.mt_op = MTFSF;
347 tcom.mt_count = dumpnum - 1;
348 #ifdef RRESTORE
349 rmtioctl(MTFSF, dumpnum - 1);
350 #else
351 if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
352 perror("ioctl MTFSF");
353 #endif
354 }
355
printdumpinfo()356 printdumpinfo()
357 {
358
359 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date));
360 fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
361 if (spcl.c_host[0] == '\0')
362 return;
363 fprintf(stderr, "Level %d dump of %s on %s:%s\n",
364 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
365 printf("Volume %d of the dump, starting at inode %d\n",
366 spcl.c_volume, spcl.c_inumber);
367 fprintf(stderr, "Label: %s\n", spcl.c_label);
368 }
369
extractfile(name)370 extractfile(name)
371 char *name;
372 {
373 int mode;
374 time_t timep[2];
375 struct entry *ep;
376 extern int xtrlnkfile(), xtrlnkskip();
377 extern int xtrfile(), xtrskip();
378
379 curfile.name = name;
380 curfile.action = USING;
381 timep[0] = curfile.dip->di_atime;
382 timep[1] = curfile.dip->di_mtime;
383 mode = curfile.dip->di_mode;
384 switch (mode & IFMT) {
385
386 default:
387 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
388 skipfile();
389 return (FAIL);
390
391 case IFSOCK:
392 vprintf(stdout, "skipped socket %s\n", name);
393 skipfile();
394 return (GOOD);
395
396 case IFDIR:
397 if (mflag) {
398 ep = lookupname(name);
399 if (ep == NIL || ep->e_flags & EXTRACT)
400 panic("unextracted directory %s\n", name);
401 skipfile();
402 return (GOOD);
403 }
404 vprintf(stdout, "extract file %s\n", name);
405 return (genliteraldir(name, curfile.ino));
406
407 case IFLNK:
408 lnkbuf[0] = '\0';
409 pathlen = 0;
410 getfile(xtrlnkfile, xtrlnkskip);
411 if (pathlen == 0) {
412 vprintf(stdout,
413 "%s: zero length symbolic link (ignored)\n", name);
414 return (GOOD);
415 }
416 return (linkit(lnkbuf, name, SYMLINK));
417
418 case IFCHR:
419 case IFBLK:
420 vprintf(stdout, "extract special file %s\n", name);
421 if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
422 fprintf(stderr, "%s: ", name);
423 (void) fflush(stderr);
424 perror("cannot create special file");
425 skipfile();
426 return (FAIL);
427 }
428 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
429 (void) chmod(name, mode);
430 skipfile();
431 utime(name, timep);
432 return (GOOD);
433
434 case IFREG:
435 vprintf(stdout, "extract file %s\n", name);
436 if ((ofile = creat(name, 0666)) < 0) {
437 fprintf(stderr, "%s: ", name);
438 (void) fflush(stderr);
439 perror("cannot create file");
440 skipfile();
441 return (FAIL);
442 }
443 (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
444 (void) fchmod(ofile, mode);
445 getfile(xtrfile, xtrskip);
446 (void) close(ofile);
447 utime(name, timep);
448 return (GOOD);
449 }
450 /* NOTREACHED */
451 }
452
453 /*
454 * skip over bit maps on the tape
455 */
skipmaps()456 skipmaps()
457 {
458
459 while (checktype(&spcl, TS_CLRI) == GOOD ||
460 checktype(&spcl, TS_BITS) == GOOD)
461 skipfile();
462 }
463
464 /*
465 * skip over a file on the tape
466 */
skipfile()467 skipfile()
468 {
469 extern int null();
470
471 curfile.action = SKIP;
472 getfile(null, null);
473 }
474
475 /*
476 * Do the file extraction, calling the supplied functions
477 * with the blocks
478 */
479 getfile(f1, f2)
480 int (*f2)(), (*f1)();
481 {
482 register int i;
483 int curblk = 0;
484 off_t size = spcl.c_dinode.di_size;
485 static char clearedbuf[MAXBSIZE];
486 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
487 char junk[TP_BSIZE];
488
489 if (checktype(&spcl, TS_END) == GOOD)
490 panic("ran off end of tape\n");
491 if (ishead(&spcl) == FAIL)
492 panic("not at beginning of a file\n");
493 if (!gettingfile && setjmp(restart) != 0)
494 return;
495 gettingfile++;
496 loop:
497 for (i = 0; i < spcl.c_count; i++) {
498 if (spcl.c_addr[i]) {
499 readtape(&buf[curblk++][0]);
500 if (curblk == fssize / TP_BSIZE) {
501 (*f1)(buf, size > TP_BSIZE ?
502 (long) (fssize) :
503 (curblk - 1) * TP_BSIZE + size);
504 curblk = 0;
505 }
506 } else {
507 if (curblk > 0) {
508 (*f1)(buf, size > TP_BSIZE ?
509 (long) (curblk * TP_BSIZE) :
510 (curblk - 1) * TP_BSIZE + size);
511 curblk = 0;
512 }
513 (*f2)(clearedbuf, size > TP_BSIZE ?
514 (long) TP_BSIZE : size);
515 }
516 if ((size -= TP_BSIZE) <= 0) {
517 for (i++; i < spcl.c_count; i++)
518 if (spcl.c_addr[i])
519 readtape(junk);
520 break;
521 }
522 }
523 if (readhdr(&spcl) == GOOD && size > 0) {
524 if (checktype(&spcl, TS_ADDR) == GOOD)
525 goto loop;
526 dprintf(stdout, "Missing address (header) block for %s\n",
527 curfile.name);
528 }
529 if (curblk > 0)
530 (*f1)(buf, (curblk * TP_BSIZE) + size);
531 findinode(&spcl);
532 gettingfile = 0;
533 }
534
535 /*
536 * The next routines are called during file extraction to
537 * put the data into the right form and place.
538 */
xtrfile(buf,size)539 xtrfile(buf, size)
540 char *buf;
541 long size;
542 {
543
544 if (write(ofile, buf, (int) size) == -1) {
545 fprintf(stderr, "write error extracting inode %d, name %s\n",
546 curfile.ino, curfile.name);
547 perror("write");
548 done(1);
549 }
550 }
551
xtrskip(buf,size)552 xtrskip(buf, size)
553 char *buf;
554 long size;
555 {
556
557 #ifdef lint
558 buf = buf;
559 #endif
560 if (lseek(ofile, size, 1) == (long)-1) {
561 fprintf(stderr, "seek error extracting inode %d, name %s\n",
562 curfile.ino, curfile.name);
563 perror("lseek");
564 done(1);
565 }
566 }
567
xtrlnkfile(buf,size)568 xtrlnkfile(buf, size)
569 char *buf;
570 long size;
571 {
572
573 pathlen += size;
574 if (pathlen > MAXPATHLEN) {
575 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
576 curfile.name, lnkbuf, buf, pathlen);
577 done(1);
578 }
579 (void) strcat(lnkbuf, buf);
580 }
581
xtrlnkskip(buf,size)582 xtrlnkskip(buf, size)
583 char *buf;
584 long size;
585 {
586
587 #ifdef lint
588 buf = buf, size = size;
589 #endif
590 fprintf(stderr, "unallocated block in symbolic link %s\n",
591 curfile.name);
592 done(1);
593 }
594
xtrmap(buf,size)595 xtrmap(buf, size)
596 char *buf;
597 long size;
598 {
599
600 bcopy(buf, map, size);
601 map += size;
602 }
603
xtrmapskip(buf,size)604 xtrmapskip(buf, size)
605 char *buf;
606 long size;
607 {
608
609 #ifdef lint
610 buf = buf;
611 #endif
612 panic("hole in map\n");
613 map += size;
614 }
615
null()616 null() {;}
617
618 /*
619 * Do the tape i/o, dealing with volume changes
620 * etc..
621 */
readtape(b)622 readtape(b)
623 char *b;
624 {
625 register long i;
626 long rd, newvol;
627 int cnt;
628
629 if (bct < ntrec) {
630 bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
631 blksread++;
632 return;
633 }
634 for (i = 0; i < ntrec; i++)
635 ((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
636 bct = 0;
637 cnt = ntrec*TP_BSIZE;
638 rd = 0;
639 getmore:
640 #ifdef RRESTORE
641 i = rmtread(&tbf[rd], cnt);
642 #else
643 i = read(mt, &tbf[rd], cnt);
644 #endif
645 if (i > 0 && i != ntrec*TP_BSIZE) {
646 if (pipein) {
647 rd += i;
648 cnt -= i;
649 if (cnt > 0)
650 goto getmore;
651 i = rd;
652 } else {
653 if (i % TP_BSIZE != 0)
654 panic("partial block read: %d should be %d\n",
655 i, ntrec * TP_BSIZE);
656 bcopy((char *)&endoftapemark, &tbf[i],
657 (long)TP_BSIZE);
658 }
659 }
660 if (i < 0) {
661 fprintf(stderr, "Tape read error while ");
662 switch (curfile.action) {
663 default:
664 fprintf(stderr, "trying to set up tape\n");
665 break;
666 case UNKNOWN:
667 fprintf(stderr, "trying to resyncronize\n");
668 break;
669 case USING:
670 fprintf(stderr, "restoring %s\n", curfile.name);
671 break;
672 case SKIP:
673 fprintf(stderr, "skipping over inode %d\n",
674 curfile.ino);
675 break;
676 }
677 if (!yflag && !reply("continue"))
678 done(1);
679 i = ntrec*TP_BSIZE;
680 bzero(tbf, i);
681 #ifdef RRESTORE
682 if (rmtseek(i, 1) < 0)
683 #else
684 if (lseek(mt, i, 1) == (long)-1)
685 #endif
686 {
687 perror("continuation failed");
688 done(1);
689 }
690 }
691 if (i == 0) {
692 if (!pipein) {
693 newvol = volno + 1;
694 volno = 0;
695 getvol(newvol);
696 readtape(b);
697 return;
698 }
699 if (rd % TP_BSIZE != 0)
700 panic("partial block read: %d should be %d\n",
701 rd, ntrec * TP_BSIZE);
702 bcopy((char *)&endoftapemark, &tbf[rd], (long)TP_BSIZE);
703 }
704 bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
705 blksread++;
706 }
707
findtapeblksize()708 findtapeblksize()
709 {
710 register long i;
711
712 for (i = 0; i < ntrec; i++)
713 ((struct s_spcl *)&tbf[i * TP_BSIZE])->c_magic = 0;
714 bct = 0;
715 #ifdef RRESTORE
716 i = rmtread(tbf, ntrec * TP_BSIZE);
717 #else
718 i = read(mt, tbf, ntrec * TP_BSIZE);
719 #endif
720 if (i <= 0) {
721 perror("Tape read error");
722 done(1);
723 }
724 if (i % TP_BSIZE != 0) {
725 fprintf(stderr, "Tape block size (%d) %s (%d)\n",
726 i, "is not a multiple of dump block size", TP_BSIZE);
727 done(1);
728 }
729 ntrec = i / TP_BSIZE;
730 vprintf(stdout, "Tape block size is %d\n", ntrec);
731 }
732
flsht()733 flsht()
734 {
735
736 bct = ntrec+1;
737 }
738
closemt()739 closemt()
740 {
741 if (mt < 0)
742 return;
743 #ifdef RRESTORE
744 rmtclose();
745 #else
746 (void) close(mt);
747 #endif
748 }
749
750 checkvol(b, t)
751 struct s_spcl *b;
752 long t;
753 {
754
755 if (b->c_volume != t)
756 return(FAIL);
757 return(GOOD);
758 }
759
760 readhdr(b)
761 struct s_spcl *b;
762 {
763
764 if (gethead(b) == FAIL) {
765 dprintf(stdout, "readhdr fails at %d blocks\n", blksread);
766 return(FAIL);
767 }
768 return(GOOD);
769 }
770
771 /*
772 * read the tape into buf, then return whether or
773 * or not it is a header block.
774 */
775 gethead(buf)
776 struct s_spcl *buf;
777 {
778 long i, *j;
779 union u_ospcl {
780 char dummy[TP_BSIZE];
781 struct s_ospcl {
782 long c_type;
783 long c_date;
784 long c_ddate;
785 long c_volume;
786 long c_tapea;
787 u_short c_inumber;
788 long c_magic;
789 long c_checksum;
790 struct odinode {
791 unsigned short odi_mode;
792 u_short odi_nlink;
793 u_short odi_uid;
794 u_short odi_gid;
795 long odi_size;
796 long odi_rdev;
797 char odi_addr[36];
798 long odi_atime;
799 long odi_mtime;
800 long odi_ctime;
801 } c_dinode;
802 long c_count;
803 char c_addr[256];
804 } s_ospcl;
805 } u_ospcl;
806
807 if (!cvtflag) {
808 readtape((char *)buf);
809 if (buf->c_magic != NFS_MAGIC) {
810 if (swabl(buf->c_magic) != NFS_MAGIC)
811 return (FAIL);
812 if (!Bcvt) {
813 vprintf(stdout, "Note: Doing Byte swapping\n");
814 Bcvt = 1;
815 }
816 }
817 if (checksum((int *)buf) == FAIL)
818 return (FAIL);
819 if (Bcvt)
820 swabst("8l4s31l", (char *)buf);
821 goto good;
822 }
823 readtape((char *)(&u_ospcl.s_ospcl));
824 bzero((char *)buf, (long)TP_BSIZE);
825 buf->c_type = u_ospcl.s_ospcl.c_type;
826 buf->c_date = u_ospcl.s_ospcl.c_date;
827 buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
828 buf->c_volume = u_ospcl.s_ospcl.c_volume;
829 buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
830 buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
831 buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
832 buf->c_magic = u_ospcl.s_ospcl.c_magic;
833 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
834 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
835 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
836 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
837 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
838 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
839 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
840 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
841 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
842 buf->c_count = u_ospcl.s_ospcl.c_count;
843 bcopy(u_ospcl.s_ospcl.c_addr, buf->c_addr, (long)256);
844 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
845 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
846 return(FAIL);
847 buf->c_magic = NFS_MAGIC;
848
849 good:
850 j = buf->c_dinode.di_ic.ic_size.val;
851 i = j[1];
852 if (buf->c_dinode.di_size == 0 &&
853 (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt==0) {
854 if (*j || i) {
855 printf("Note: Doing Quad swapping\n");
856 Qcvt = 1;
857 }
858 }
859 if (Qcvt) {
860 j[1] = *j; *j = i;
861 }
862 switch (buf->c_type) {
863
864 case TS_CLRI:
865 case TS_BITS:
866 /*
867 * Have to patch up missing information in bit map headers
868 */
869 buf->c_inumber = 0;
870 buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
871 for (i = 0; i < buf->c_count; i++)
872 buf->c_addr[i]++;
873 break;
874
875 case TS_TAPE:
876 case TS_END:
877 buf->c_inumber = 0;
878 break;
879
880 case TS_INODE:
881 case TS_ADDR:
882 break;
883
884 default:
885 panic("gethead: unknown inode type %d\n", buf->c_type);
886 break;
887 }
888 if (dflag)
889 accthdr(buf);
890 return(GOOD);
891 }
892
893 /*
894 * Check that a header is where it belongs and predict the next header
895 */
896 accthdr(header)
897 struct s_spcl *header;
898 {
899 static ino_t previno = 0x7fffffff;
900 static int prevtype;
901 static long predict;
902 long blks, i;
903
904 if (header->c_type == TS_TAPE) {
905 fprintf(stderr, "Volume header\n");
906 previno = 0x7fffffff;
907 return;
908 }
909 if (previno == 0x7fffffff)
910 goto newcalc;
911 switch (prevtype) {
912 case TS_BITS:
913 fprintf(stderr, "Dump mask header");
914 break;
915 case TS_CLRI:
916 fprintf(stderr, "Remove mask header");
917 break;
918 case TS_INODE:
919 fprintf(stderr, "File header, ino %d", previno);
920 break;
921 case TS_ADDR:
922 fprintf(stderr, "File continuation header, ino %d", previno);
923 break;
924 case TS_END:
925 fprintf(stderr, "End of tape header");
926 break;
927 }
928 if (predict != blksread - 1)
929 fprintf(stderr, "; predicted %d blocks, got %d blocks",
930 predict, blksread - 1);
931 fprintf(stderr, "\n");
932 newcalc:
933 blks = 0;
934 if (header->c_type != TS_END)
935 for (i = 0; i < header->c_count; i++)
936 if (header->c_addr[i] != 0)
937 blks++;
938 predict = blks;
939 blksread = 0;
940 prevtype = header->c_type;
941 previno = header->c_inumber;
942 }
943
944 /*
945 * Find an inode header.
946 * Complain if had to skip, and complain is set.
947 */
948 findinode(header)
949 struct s_spcl *header;
950 {
951 static long skipcnt = 0;
952 long i;
953 char buf[TP_BSIZE];
954
955 curfile.name = "<name unknown>";
956 curfile.action = UNKNOWN;
957 curfile.dip = (struct dinode *)NIL;
958 curfile.ino = 0;
959 if (ishead(header) == FAIL) {
960 skipcnt++;
961 while (gethead(header) == FAIL || header->c_date != dumpdate)
962 skipcnt++;
963 }
964 for (;;) {
965 if (checktype(header, TS_ADDR) == GOOD) {
966 /*
967 * Skip up to the beginning of the next record
968 */
969 for (i = 0; i < header->c_count; i++)
970 if (header->c_addr[i])
971 readtape(buf);
972 (void) gethead(header);
973 continue;
974 }
975 if (checktype(header, TS_INODE) == GOOD) {
976 curfile.dip = &header->c_dinode;
977 curfile.ino = header->c_inumber;
978 break;
979 }
980 if (checktype(header, TS_END) == GOOD) {
981 curfile.ino = maxino;
982 break;
983 }
984 if (checktype(header, TS_CLRI) == GOOD) {
985 curfile.name = "<file removal list>";
986 break;
987 }
988 if (checktype(header, TS_BITS) == GOOD) {
989 curfile.name = "<file dump list>";
990 break;
991 }
992 while (gethead(header) == FAIL)
993 skipcnt++;
994 }
995 if (skipcnt > 0)
996 fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
997 skipcnt = 0;
998 }
999
1000 /*
1001 * return whether or not the buffer contains a header block
1002 */
1003 ishead(buf)
1004 struct s_spcl *buf;
1005 {
1006
1007 if (buf->c_magic != NFS_MAGIC)
1008 return(FAIL);
1009 return(GOOD);
1010 }
1011
1012 checktype(b, t)
1013 struct s_spcl *b;
1014 int t;
1015 {
1016
1017 if (b->c_type != t)
1018 return(FAIL);
1019 return(GOOD);
1020 }
1021
checksum(b)1022 checksum(b)
1023 register int *b;
1024 {
1025 register int i, j;
1026
1027 j = sizeof(union u_spcl) / sizeof(int);
1028 i = 0;
1029 if(!Bcvt) {
1030 do
1031 i += *b++;
1032 while (--j);
1033 } else {
1034 /* What happens if we want to read restore tapes
1035 for a 16bit int machine??? */
1036 do
1037 i += swabl(*b++);
1038 while (--j);
1039 }
1040
1041 if (i != CHECKSUM) {
1042 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1043 curfile.ino, curfile.name);
1044 return(FAIL);
1045 }
1046 return(GOOD);
1047 }
1048
1049 #ifdef RRESTORE
1050 /* VARARGS1 */
msg(cp,a1,a2,a3)1051 msg(cp, a1, a2, a3)
1052 char *cp;
1053 {
1054
1055 fprintf(stderr, cp, a1, a2, a3);
1056 }
1057 #endif RRESTORE
1058
swabst(cp,sp)1059 swabst(cp, sp)
1060 register char *cp, *sp;
1061 {
1062 int n = 0;
1063 char c;
1064 while(*cp) {
1065 switch (*cp) {
1066 case '0': case '1': case '2': case '3': case '4':
1067 case '5': case '6': case '7': case '8': case '9':
1068 n = (n * 10) + (*cp++ - '0');
1069 continue;
1070
1071 case 's': case 'w': case 'h':
1072 c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1073 sp++;
1074 break;
1075
1076 case 'l':
1077 c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1078 c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1079 sp += 3;
1080 }
1081 sp++; /* Any other character, like 'b' counts as byte. */
1082 if (n <= 1) {
1083 n = 0; cp++;
1084 } else
1085 n--;
1086 }
1087 }
swabl(x)1088 swabl(x) { unsigned long l = x; swabst("l", (char *)&l); return l; }
1089