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