Annotation of src/sbin/restore/tape.c, Revision 1.12
1.10 cgd 1: /*
1.11 mycroft 2: * Copyright (c) 1983, 1993
3: * The Regents of the University of California. All rights reserved.
1.10 cgd 4: * (c) UNIX System Laboratories, Inc.
5: * All or some portions of this file are derived from material licensed
6: * to the University of California by American Telephone and Telegraph
7: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8: * the permission of UNIX System Laboratories, Inc.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the University of
21: * California, Berkeley and its contributors.
22: * 4. Neither the name of the University nor the names of its contributors
23: * may be used to endorse or promote products derived from this software
24: * without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36: * SUCH DAMAGE.
37: */
38:
39: #ifndef lint
1.11 mycroft 40: /*static char sccsid[] = "from: @(#)tape.c 8.3 (Berkeley) 4/1/94";*/
1.12 ! mycroft 41: static char *rcsid = "$Id: tape.c,v 1.11 1994/06/08 19:33:45 mycroft Exp $";
1.10 cgd 42: #endif /* not lint */
43:
44: #include <sys/param.h>
45: #include <sys/file.h>
46: #include <sys/ioctl.h>
47: #include <sys/mtio.h>
48: #include <sys/stat.h>
49:
1.11 mycroft 50: #include <ufs/ufs/dinode.h>
1.10 cgd 51: #include <protocols/dumprestore.h>
52:
53: #include <errno.h>
54: #include <setjmp.h>
55: #include <stdio.h>
56: #include <stdlib.h>
57: #include <string.h>
58: #include <unistd.h>
59:
60: #include "restore.h"
61: #include "extern.h"
62: #include "pathnames.h"
63:
64: static long fssize = MAXBSIZE;
65: static int mt = -1;
66: static int pipein = 0;
67: static char magtape[BUFSIZ];
68: static int blkcnt;
69: static int numtrec;
70: static char *tapebuf;
71: static union u_spcl endoftapemark;
72: static long blksread; /* blocks read since last header */
73: static long tpblksread = 0; /* TP_BSIZE blocks read */
74: static long tapesread;
75: static jmp_buf restart;
76: static int gettingfile = 0; /* restart has a valid frame */
77: static char *host = NULL;
78:
79: static int ofile;
80: static char *map;
81: static char lnkbuf[MAXPATHLEN + 1];
82: static int pathlen;
83:
84: int oldinofmt; /* old inode format conversion required */
85: int Bcvt; /* Swap Bytes (for CCI or sun) */
86: static int Qcvt; /* Swap quads (for sun) */
87:
88: #define FLUSHTAPEBUF() blkcnt = ntrec + 1
89:
90: static void accthdr __P((struct s_spcl *));
91: static int checksum __P((int *));
92: static void findinode __P((struct s_spcl *));
93: static void findtapeblksize __P((void));
94: static int gethead __P((struct s_spcl *));
95: static void readtape __P((char *));
96: static void setdumpnum __P((void));
97: static u_long swabl __P((u_long));
98: static u_char *swablong __P((u_char *, int));
99: static u_char *swabshort __P((u_char *, int));
100: static void terminateinput __P((void));
101: static void xtrfile __P((char *, long));
102: static void xtrlnkfile __P((char *, long));
103: static void xtrlnkskip __P((char *, long));
104: static void xtrmap __P((char *, long));
105: static void xtrmapskip __P((char *, long));
106: static void xtrskip __P((char *, long));
107:
108: /*
109: * Set up an input source
110: */
111: void
112: setinput(source)
113: char *source;
114: {
115: FLUSHTAPEBUF();
116: if (bflag)
117: newtapebuf(ntrec);
118: else
119: newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
120: terminal = stdin;
121:
122: #ifdef RRESTORE
123: if (index(source, ':')) {
124: host = source;
125: source = index(host, ':');
126: *source++ = '\0';
127: if (rmthost(host) == 0)
128: done(1);
129: } else
130: #endif
131: if (strcmp(source, "-") == 0) {
132: /*
133: * Since input is coming from a pipe we must establish
134: * our own connection to the terminal.
135: */
136: terminal = fopen(_PATH_TTY, "r");
137: if (terminal == NULL) {
138: (void)fprintf(stderr, "cannot open %s: %s\n",
139: _PATH_TTY, strerror(errno));
140: terminal = fopen(_PATH_DEVNULL, "r");
141: if (terminal == NULL) {
142: (void)fprintf(stderr, "cannot open %s: %s\n",
143: _PATH_DEVNULL, strerror(errno));
144: done(1);
145: }
146: }
147: pipein++;
148: }
149: setuid(getuid()); /* no longer need or want root privileges */
150: (void) strcpy(magtape, source);
151: }
152:
153: void
154: newtapebuf(size)
155: long size;
156: {
157: static tapebufsize = -1;
158:
159: ntrec = size;
160: if (size <= tapebufsize)
161: return;
162: if (tapebuf != NULL)
163: free(tapebuf);
164: tapebuf = malloc(size * TP_BSIZE);
165: if (tapebuf == NULL) {
166: fprintf(stderr, "Cannot allocate space for tape buffer\n");
167: done(1);
168: }
169: tapebufsize = size;
170: }
171:
172: /*
173: * Verify that the tape drive can be accessed and
174: * that it actually is a dump tape.
175: */
176: void
177: setup()
178: {
179: int i, j, *ip;
180: struct stat stbuf;
181:
182: vprintf(stdout, "Verify tape and initialize maps\n");
183: #ifdef RRESTORE
184: if (host)
1.11 mycroft 185: mt = rmtopen(magtape, 0);
1.10 cgd 186: else
187: #endif
188: if (pipein)
189: mt = 0;
190: else
191: mt = open(magtape, O_RDONLY, 0);
192: if (mt < 0) {
193: fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
194: done(1);
195: }
196: volno = 1;
197: setdumpnum();
198: FLUSHTAPEBUF();
199: if (!pipein && !bflag)
200: findtapeblksize();
201: if (gethead(&spcl) == FAIL) {
202: blkcnt--; /* push back this block */
203: blksread--;
204: tpblksread--;
205: cvtflag++;
206: if (gethead(&spcl) == FAIL) {
207: fprintf(stderr, "Tape is not a dump tape\n");
208: done(1);
209: }
210: fprintf(stderr, "Converting to new file system format.\n");
211: }
212: if (pipein) {
213: endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
214: endoftapemark.s_spcl.c_type = TS_END;
215: ip = (int *)&endoftapemark;
216: j = sizeof(union u_spcl) / sizeof(int);
217: i = 0;
218: do
219: i += *ip++;
220: while (--j);
221: endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
222: }
223: if (vflag || command == 't')
224: printdumpinfo();
225: dumptime = spcl.c_ddate;
226: dumpdate = spcl.c_date;
227: if (stat(".", &stbuf) < 0) {
228: fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
229: done(1);
230: }
231: if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
232: fssize = stbuf.st_blksize;
233: if (((fssize - 1) & fssize) != 0) {
234: fprintf(stderr, "bad block size %d\n", fssize);
235: done(1);
236: }
237: if (spcl.c_volume != 1) {
238: fprintf(stderr, "Tape is not volume 1 of the dump\n");
239: done(1);
240: }
241: if (gethead(&spcl) == FAIL) {
242: dprintf(stdout, "header read failed at %d blocks\n", blksread);
243: panic("no header after volume mark!\n");
244: }
245: findinode(&spcl);
246: if (spcl.c_type != TS_CLRI) {
247: fprintf(stderr, "Cannot find file removal list\n");
248: done(1);
249: }
250: maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
251: dprintf(stdout, "maxino = %d\n", maxino);
252: map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
253: if (map == NULL)
254: panic("no memory for file removal list\n");
255: clrimap = map;
256: curfile.action = USING;
257: getfile(xtrmap, xtrmapskip);
258: if (spcl.c_type != TS_BITS) {
259: fprintf(stderr, "Cannot find file dump list\n");
260: done(1);
261: }
262: map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
263: if (map == (char *)NULL)
264: panic("no memory for file dump list\n");
265: dumpmap = map;
266: curfile.action = USING;
267: getfile(xtrmap, xtrmapskip);
268: }
269:
270: /*
271: * Prompt user to load a new dump volume.
272: * "Nextvol" is the next suggested volume to use.
273: * This suggested volume is enforced when doing full
274: * or incremental restores, but can be overrridden by
275: * the user when only extracting a subset of the files.
276: */
277: void
278: getvol(nextvol)
279: long nextvol;
280: {
281: long newvol, savecnt, wantnext, i;
282: union u_spcl tmpspcl;
283: # define tmpbuf tmpspcl.s_spcl
284: char buf[TP_BSIZE];
285:
286: if (nextvol == 1) {
287: tapesread = 0;
288: gettingfile = 0;
289: }
290: if (pipein) {
291: if (nextvol != 1)
292: panic("Changing volumes on pipe input?\n");
293: if (volno == 1)
294: return;
295: goto gethdr;
296: }
297: savecnt = blksread;
298: again:
299: if (pipein)
300: done(1); /* pipes do not get a second chance */
301: if (command == 'R' || command == 'r' || curfile.action != SKIP) {
302: newvol = nextvol;
303: wantnext = 1;
304: } else {
305: newvol = 0;
306: wantnext = 0;
307: }
308: while (newvol <= 0) {
309: if (tapesread == 0) {
310: fprintf(stderr, "%s%s%s%s%s",
311: "You have not read any tapes yet.\n",
312: "Unless you know which volume your",
313: " file(s) are on you should start\n",
314: "with the last volume and work",
315: " towards towards the first.\n");
316: } else {
317: fprintf(stderr, "You have read volumes");
318: strcpy(buf, ": ");
319: for (i = 1; i < 32; i++)
320: if (tapesread & (1 << i)) {
321: fprintf(stderr, "%s%d", buf, i);
322: strcpy(buf, ", ");
323: }
324: fprintf(stderr, "\n");
325: }
326: do {
327: fprintf(stderr, "Specify next volume #: ");
328: (void) fflush(stderr);
329: (void) fgets(buf, BUFSIZ, terminal);
330: } while (!feof(terminal) && buf[0] == '\n');
331: if (feof(terminal))
332: done(1);
333: newvol = atoi(buf);
334: if (newvol <= 0) {
335: fprintf(stderr,
336: "Volume numbers are positive numerics\n");
337: }
338: }
339: if (newvol == volno) {
340: tapesread |= 1 << volno;
341: return;
342: }
343: closemt();
344: fprintf(stderr, "Mount tape volume %d\n", newvol);
345: fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
346: fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
347: (void) fflush(stderr);
348: (void) fgets(buf, BUFSIZ, terminal);
349: if (feof(terminal))
350: done(1);
351: if (!strcmp(buf, "none\n")) {
352: terminateinput();
353: return;
354: }
355: if (buf[0] != '\n') {
356: (void) strcpy(magtape, buf);
357: magtape[strlen(magtape) - 1] = '\0';
358: }
359: #ifdef RRESTORE
360: if (host)
361: mt = rmtopen(magtape, 0);
362: else
363: #endif
364: mt = open(magtape, O_RDONLY, 0);
365:
366: if (mt == -1) {
367: fprintf(stderr, "Cannot open %s\n", magtape);
368: volno = -1;
369: goto again;
370: }
371: gethdr:
372: volno = newvol;
373: setdumpnum();
374: FLUSHTAPEBUF();
375: if (gethead(&tmpbuf) == FAIL) {
376: dprintf(stdout, "header read failed at %d blocks\n", blksread);
377: fprintf(stderr, "tape is not dump tape\n");
378: volno = 0;
379: goto again;
380: }
381: if (tmpbuf.c_volume != volno) {
382: fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
383: volno = 0;
384: goto again;
385: }
386: if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
387: fprintf(stderr, "Wrong dump date\n\tgot: %s",
388: ctime(&tmpbuf.c_date));
389: fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
390: volno = 0;
391: goto again;
392: }
393: tapesread |= 1 << volno;
394: blksread = savecnt;
395: /*
396: * If continuing from the previous volume, skip over any
397: * blocks read already at the end of the previous volume.
398: *
399: * If coming to this volume at random, skip to the beginning
400: * of the next record.
401: */
402: dprintf(stdout, "read %ld recs, tape starts with %ld\n",
403: tpblksread, tmpbuf.c_firstrec);
404: if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
405: if (!wantnext) {
406: tpblksread = tmpbuf.c_firstrec;
407: for (i = tmpbuf.c_count; i > 0; i--)
408: readtape(buf);
409: } else if (tmpbuf.c_firstrec > 0 &&
410: tmpbuf.c_firstrec < tpblksread - 1) {
411: /*
412: * -1 since we've read the volume header
413: */
414: i = tpblksread - tmpbuf.c_firstrec - 1;
415: dprintf(stderr, "Skipping %d duplicate record%s.\n",
416: i, i > 1 ? "s" : "");
417: while (--i >= 0)
418: readtape(buf);
419: }
420: }
421: if (curfile.action == USING) {
422: if (volno == 1)
423: panic("active file into volume 1\n");
424: return;
425: }
426: /*
427: * Skip up to the beginning of the next record
428: */
429: if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
430: for (i = tmpbuf.c_count; i > 0; i--)
431: readtape(buf);
432: (void) gethead(&spcl);
433: findinode(&spcl);
434: if (gettingfile) {
435: gettingfile = 0;
436: longjmp(restart, 1);
437: }
438: }
439:
440: /*
441: * Handle unexpected EOF.
442: */
443: static void
444: terminateinput()
445: {
446:
447: if (gettingfile && curfile.action == USING) {
448: printf("Warning: %s %s\n",
449: "End-of-input encountered while extracting", curfile.name);
450: }
451: curfile.name = "<name unknown>";
452: curfile.action = UNKNOWN;
453: curfile.dip = NULL;
454: curfile.ino = maxino;
455: if (gettingfile) {
456: gettingfile = 0;
457: longjmp(restart, 1);
458: }
459: }
460:
461: /*
462: * handle multiple dumps per tape by skipping forward to the
463: * appropriate one.
464: */
465: static void
466: setdumpnum()
467: {
468: struct mtop tcom;
469:
470: if (dumpnum == 1 || volno != 1)
471: return;
472: if (pipein) {
473: fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
474: done(1);
475: }
476: tcom.mt_op = MTFSF;
477: tcom.mt_count = dumpnum - 1;
478: #ifdef RRESTORE
479: if (host)
480: rmtioctl(MTFSF, dumpnum - 1);
481: else
482: #endif
483: if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
484: fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
485: }
486:
487: void
488: printdumpinfo()
489: {
490: fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date));
491: fprintf(stdout, "Dumped from: %s",
492: (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
493: if (spcl.c_host[0] == '\0')
494: return;
495: fprintf(stderr, "Level %d dump of %s on %s:%s\n",
496: spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
497: fprintf(stderr, "Label: %s\n", spcl.c_label);
498: }
499:
500: int
501: extractfile(name)
502: char *name;
503: {
504: int mode;
505: struct timeval timep[2];
506: struct entry *ep;
507:
508: curfile.name = name;
509: curfile.action = USING;
510: timep[0].tv_sec = curfile.dip->di_atime.ts_sec;
511: timep[0].tv_usec = curfile.dip->di_atime.ts_nsec / 1000;
512: timep[1].tv_sec = curfile.dip->di_mtime.ts_sec;
513: timep[1].tv_usec = curfile.dip->di_mtime.ts_nsec / 1000;
514: mode = curfile.dip->di_mode;
515: switch (mode & IFMT) {
516:
517: default:
518: fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
519: skipfile();
520: return (FAIL);
521:
522: case IFSOCK:
523: vprintf(stdout, "skipped socket %s\n", name);
524: skipfile();
525: return (GOOD);
526:
527: case IFDIR:
528: if (mflag) {
529: ep = lookupname(name);
530: if (ep == NULL || ep->e_flags & EXTRACT)
531: panic("unextracted directory %s\n", name);
532: skipfile();
533: return (GOOD);
534: }
535: vprintf(stdout, "extract file %s\n", name);
536: return (genliteraldir(name, curfile.ino));
537:
538: case IFLNK:
539: lnkbuf[0] = '\0';
540: pathlen = 0;
541: getfile(xtrlnkfile, xtrlnkskip);
542: if (pathlen == 0) {
543: vprintf(stdout,
544: "%s: zero length symbolic link (ignored)\n", name);
545: return (GOOD);
546: }
547: return (linkit(lnkbuf, name, SYMLINK));
1.12 ! mycroft 548:
! 549: case IFIFO:
! 550: vprintf(stdout, "extract fifo %s\n", name);
! 551: if (Nflag) {
! 552: skipfile();
! 553: return (GOOD);
! 554: }
! 555: if (mkfifo(name, mode) < 0) {
! 556: fprintf(stderr, "%s: cannot create fifo: %s\n",
! 557: name, strerror(errno));
! 558: skipfile();
! 559: return (FAIL);
! 560: }
! 561: (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
! 562: (void) chmod(name, mode);
! 563: skipfile();
! 564: utimes(name, timep);
! 565: return (GOOD);
1.10 cgd 566:
567: case IFCHR:
568: case IFBLK:
569: vprintf(stdout, "extract special file %s\n", name);
570: if (Nflag) {
571: skipfile();
572: return (GOOD);
573: }
574: if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
575: fprintf(stderr, "%s: cannot create special file: %s\n",
576: name, strerror(errno));
577: skipfile();
578: return (FAIL);
579: }
580: (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
581: (void) chmod(name, mode);
582: skipfile();
583: utimes(name, timep);
584: return (GOOD);
585:
586: case IFREG:
587: vprintf(stdout, "extract file %s\n", name);
588: if (Nflag) {
589: skipfile();
590: return (GOOD);
591: }
592: if ((ofile = creat(name, 0666)) < 0) {
593: fprintf(stderr, "%s: cannot create file: %s\n",
594: name, strerror(errno));
595: skipfile();
596: return (FAIL);
597: }
598: (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
599: (void) fchmod(ofile, mode);
600: getfile(xtrfile, xtrskip);
601: (void) close(ofile);
602: utimes(name, timep);
603: return (GOOD);
604: }
605: /* NOTREACHED */
606: }
607:
608: /*
609: * skip over bit maps on the tape
610: */
611: void
612: skipmaps()
613: {
614:
615: while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
616: skipfile();
617: }
618:
619: /*
620: * skip over a file on the tape
621: */
622: void
623: skipfile()
624: {
625:
626: curfile.action = SKIP;
627: getfile(xtrnull, xtrnull);
628: }
629:
630: /*
631: * Extract a file from the tape.
632: * When an allocated block is found it is passed to the fill function;
633: * when an unallocated block (hole) is found, a zeroed buffer is passed
634: * to the skip function.
635: */
636: void
637: getfile(fill, skip)
638: void (*fill) __P((char *, long));
639: void (*skip) __P((char *, long));
640: {
641: register int i;
642: int curblk = 0;
643: long size = spcl.c_dinode.di_size;
644: static char clearedbuf[MAXBSIZE];
645: char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
646: char junk[TP_BSIZE];
647:
648: if (spcl.c_type == TS_END)
649: panic("ran off end of tape\n");
650: if (spcl.c_magic != NFS_MAGIC)
651: panic("not at beginning of a file\n");
652: if (!gettingfile && setjmp(restart) != 0)
653: return;
654: gettingfile++;
655: loop:
656: for (i = 0; i < spcl.c_count; i++) {
657: if (spcl.c_addr[i]) {
658: readtape(&buf[curblk++][0]);
659: if (curblk == fssize / TP_BSIZE) {
660: (*fill)((char *)buf, size > TP_BSIZE ?
661: (long) (fssize) :
662: (curblk - 1) * TP_BSIZE + size);
663: curblk = 0;
664: }
665: } else {
666: if (curblk > 0) {
667: (*fill)((char *)buf, size > TP_BSIZE ?
668: (long) (curblk * TP_BSIZE) :
669: (curblk - 1) * TP_BSIZE + size);
670: curblk = 0;
671: }
672: (*skip)(clearedbuf, size > TP_BSIZE ?
673: (long) TP_BSIZE : size);
674: }
675: if ((size -= TP_BSIZE) <= 0) {
676: for (i++; i < spcl.c_count; i++)
677: if (spcl.c_addr[i])
678: readtape(junk);
679: break;
680: }
681: }
682: if (gethead(&spcl) == GOOD && size > 0) {
683: if (spcl.c_type == TS_ADDR)
684: goto loop;
685: dprintf(stdout,
686: "Missing address (header) block for %s at %d blocks\n",
687: curfile.name, blksread);
688: }
689: if (curblk > 0)
690: (*fill)((char *)buf, (curblk * TP_BSIZE) + size);
691: findinode(&spcl);
692: gettingfile = 0;
693: }
694:
695: /*
696: * Write out the next block of a file.
697: */
698: static void
699: xtrfile(buf, size)
700: char *buf;
701: long size;
702: {
703:
704: if (Nflag)
705: return;
706: if (write(ofile, buf, (int) size) == -1) {
707: fprintf(stderr,
708: "write error extracting inode %d, name %s\nwrite: %s\n",
709: curfile.ino, curfile.name, strerror(errno));
710: done(1);
711: }
712: }
713:
714: /*
715: * Skip over a hole in a file.
716: */
717: /* ARGSUSED */
718: static void
719: xtrskip(buf, size)
720: char *buf;
721: long size;
722: {
723:
724: if (lseek(ofile, size, SEEK_CUR) == -1) {
725: fprintf(stderr,
726: "seek error extracting inode %d, name %s\nlseek: %s\n",
727: curfile.ino, curfile.name, strerror(errno));
728: done(1);
729: }
730: }
731:
732: /*
733: * Collect the next block of a symbolic link.
734: */
735: static void
736: xtrlnkfile(buf, size)
737: char *buf;
738: long size;
739: {
740:
741: pathlen += size;
742: if (pathlen > MAXPATHLEN) {
743: fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
744: curfile.name, lnkbuf, buf, pathlen);
745: done(1);
746: }
747: (void) strcat(lnkbuf, buf);
748: }
749:
750: /*
751: * Skip over a hole in a symbolic link (should never happen).
752: */
753: /* ARGSUSED */
754: static void
755: xtrlnkskip(buf, size)
756: char *buf;
757: long size;
758: {
759:
760: fprintf(stderr, "unallocated block in symbolic link %s\n",
761: curfile.name);
762: done(1);
763: }
764:
765: /*
766: * Collect the next block of a bit map.
767: */
768: static void
769: xtrmap(buf, size)
770: char *buf;
771: long size;
772: {
773:
774: bcopy(buf, map, size);
775: map += size;
776: }
777:
778: /*
779: * Skip over a hole in a bit map (should never happen).
780: */
781: /* ARGSUSED */
782: static void
783: xtrmapskip(buf, size)
784: char *buf;
785: long size;
786: {
787:
788: panic("hole in map\n");
789: map += size;
790: }
791:
792: /*
793: * Noop, when an extraction function is not needed.
794: */
795: /* ARGSUSED */
796: void
797: xtrnull(buf, size)
798: char *buf;
799: long size;
800: {
801:
802: return;
803: }
804:
805: /*
806: * Read TP_BSIZE blocks from the input.
807: * Handle read errors, and end of media.
808: */
809: static void
810: readtape(buf)
811: char *buf;
812: {
813: long rd, newvol, i;
814: int cnt, seek_failed;
815:
816: if (blkcnt < numtrec) {
817: bcopy(&tapebuf[(blkcnt++ * TP_BSIZE)], buf, (long)TP_BSIZE);
818: blksread++;
819: tpblksread++;
820: return;
821: }
822: for (i = 0; i < ntrec; i++)
823: ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
824: if (numtrec == 0)
825: numtrec = ntrec;
826: cnt = ntrec * TP_BSIZE;
827: rd = 0;
828: getmore:
829: #ifdef RRESTORE
830: if (host)
831: i = rmtread(&tapebuf[rd], cnt);
832: else
833: #endif
834: i = read(mt, &tapebuf[rd], cnt);
835: /*
836: * Check for mid-tape short read error.
837: * If found, skip rest of buffer and start with the next.
838: */
839: if (!pipein && numtrec < ntrec && i > 0) {
840: dprintf(stdout, "mid-media short read error.\n");
841: numtrec = ntrec;
842: }
843: /*
844: * Handle partial block read.
845: */
846: if (pipein && i == 0 && rd > 0)
847: i = rd;
848: else if (i > 0 && i != ntrec * TP_BSIZE) {
849: if (pipein) {
850: rd += i;
851: cnt -= i;
852: if (cnt > 0)
853: goto getmore;
854: i = rd;
855: } else {
856: /*
857: * Short read. Process the blocks read.
858: */
859: if (i % TP_BSIZE != 0)
860: vprintf(stdout,
861: "partial block read: %d should be %d\n",
862: i, ntrec * TP_BSIZE);
863: numtrec = i / TP_BSIZE;
864: }
865: }
866: /*
867: * Handle read error.
868: */
869: if (i < 0) {
870: fprintf(stderr, "Tape read error while ");
871: switch (curfile.action) {
872: default:
873: fprintf(stderr, "trying to set up tape\n");
874: break;
875: case UNKNOWN:
876: fprintf(stderr, "trying to resynchronize\n");
877: break;
878: case USING:
879: fprintf(stderr, "restoring %s\n", curfile.name);
880: break;
881: case SKIP:
882: fprintf(stderr, "skipping over inode %d\n",
883: curfile.ino);
884: break;
885: }
886: if (!yflag && !reply("continue"))
887: done(1);
888: i = ntrec * TP_BSIZE;
889: bzero(tapebuf, i);
890: #ifdef RRESTORE
891: if (host)
892: seek_failed = (rmtseek(i, 1) < 0);
893: else
894: #endif
895: seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
896:
897: if (seek_failed) {
898: fprintf(stderr,
899: "continuation failed: %s\n", strerror(errno));
900: done(1);
901: }
902: }
903: /*
904: * Handle end of tape.
905: */
906: if (i == 0) {
907: vprintf(stdout, "End-of-tape encountered\n");
908: if (!pipein) {
909: newvol = volno + 1;
910: volno = 0;
911: numtrec = 0;
912: getvol(newvol);
913: readtape(buf);
914: return;
915: }
916: if (rd % TP_BSIZE != 0)
917: panic("partial block read: %d should be %d\n",
918: rd, ntrec * TP_BSIZE);
919: terminateinput();
920: bcopy((char *)&endoftapemark, &tapebuf[rd], (long)TP_BSIZE);
921: }
922: blkcnt = 0;
923: bcopy(&tapebuf[(blkcnt++ * TP_BSIZE)], buf, (long)TP_BSIZE);
924: blksread++;
925: tpblksread++;
926: }
927:
928: static void
929: findtapeblksize()
930: {
931: register long i;
932:
933: for (i = 0; i < ntrec; i++)
934: ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
935: blkcnt = 0;
936: #ifdef RRESTORE
937: if (host)
938: i = rmtread(tapebuf, ntrec * TP_BSIZE);
939: else
940: #endif
941: i = read(mt, tapebuf, ntrec * TP_BSIZE);
942:
943: if (i <= 0) {
944: fprintf(stderr, "tape read error: %s\n", strerror(errno));
945: done(1);
946: }
947: if (i % TP_BSIZE != 0) {
948: fprintf(stderr, "Tape block size (%d) %s (%d)\n",
949: i, "is not a multiple of dump block size", TP_BSIZE);
950: done(1);
951: }
952: ntrec = i / TP_BSIZE;
953: numtrec = ntrec;
954: vprintf(stdout, "Tape block size is %d\n", ntrec);
955: }
956:
957: void
958: closemt()
959: {
960:
961: if (mt < 0)
962: return;
963: #ifdef RRESTORE
964: if (host)
965: rmtclose();
966: else
967: #endif
968: (void) close(mt);
969: }
970:
971: /*
972: * Read the next block from the tape.
973: * Check to see if it is one of several vintage headers.
974: * If it is an old style header, convert it to a new style header.
975: * If it is not any valid header, return an error.
976: */
977: static int
978: gethead(buf)
979: struct s_spcl *buf;
980: {
981: long i;
982: union {
983: quad_t qval;
984: long val[2];
985: } qcvt;
986: union u_ospcl {
987: char dummy[TP_BSIZE];
988: struct s_ospcl {
989: long c_type;
990: long c_date;
991: long c_ddate;
992: long c_volume;
993: long c_tapea;
994: u_short c_inumber;
995: long c_magic;
996: long c_checksum;
997: struct odinode {
998: unsigned short odi_mode;
999: u_short odi_nlink;
1000: u_short odi_uid;
1001: u_short odi_gid;
1002: long odi_size;
1003: long odi_rdev;
1004: char odi_addr[36];
1005: long odi_atime;
1006: long odi_mtime;
1007: long odi_ctime;
1008: } c_dinode;
1009: long c_count;
1010: char c_addr[256];
1011: } s_ospcl;
1012: } u_ospcl;
1013:
1014: if (!cvtflag) {
1015: readtape((char *)buf);
1016: if (buf->c_magic != NFS_MAGIC) {
1017: if (swabl(buf->c_magic) != NFS_MAGIC)
1018: return (FAIL);
1019: if (!Bcvt) {
1020: vprintf(stdout, "Note: Doing Byte swapping\n");
1021: Bcvt = 1;
1022: }
1023: }
1024: if (checksum((int *)buf) == FAIL)
1025: return (FAIL);
1026: if (Bcvt)
1027: swabst((u_char *)"8l4s31l", (u_char *)buf);
1028: goto good;
1029: }
1030: readtape((char *)(&u_ospcl.s_ospcl));
1031: bzero((char *)buf, (long)TP_BSIZE);
1032: buf->c_type = u_ospcl.s_ospcl.c_type;
1033: buf->c_date = u_ospcl.s_ospcl.c_date;
1034: buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1035: buf->c_volume = u_ospcl.s_ospcl.c_volume;
1036: buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1037: buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1038: buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1039: buf->c_magic = u_ospcl.s_ospcl.c_magic;
1040: buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1041: buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1042: buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1043: buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1044: buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
1045: buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1046: buf->c_dinode.di_atime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_atime;
1047: buf->c_dinode.di_mtime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1048: buf->c_dinode.di_ctime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1049: buf->c_count = u_ospcl.s_ospcl.c_count;
1050: bcopy(u_ospcl.s_ospcl.c_addr, buf->c_addr, (long)256);
1051: if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
1052: checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
1053: return(FAIL);
1054: buf->c_magic = NFS_MAGIC;
1055:
1056: good:
1057: if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
1058: (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
1059: qcvt.qval = buf->c_dinode.di_size;
1060: if (qcvt.val[0] || qcvt.val[1]) {
1061: printf("Note: Doing Quad swapping\n");
1062: Qcvt = 1;
1063: }
1064: }
1065: if (Qcvt) {
1066: qcvt.qval = buf->c_dinode.di_size;
1067: i = qcvt.val[1];
1068: qcvt.val[1] = qcvt.val[0];
1069: qcvt.val[0] = i;
1070: buf->c_dinode.di_size = qcvt.qval;
1071: }
1072:
1073: switch (buf->c_type) {
1074:
1075: case TS_CLRI:
1076: case TS_BITS:
1077: /*
1078: * Have to patch up missing information in bit map headers
1079: */
1080: buf->c_inumber = 0;
1081: buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
1082: for (i = 0; i < buf->c_count; i++)
1083: buf->c_addr[i]++;
1084: break;
1085:
1086: case TS_TAPE:
1087: if ((buf->c_flags & DR_NEWINODEFMT) == 0)
1088: oldinofmt = 1;
1089: /* fall through */
1090: case TS_END:
1091: buf->c_inumber = 0;
1092: break;
1093:
1094: case TS_INODE:
1095: case TS_ADDR:
1096: break;
1097:
1098: default:
1099: panic("gethead: unknown inode type %d\n", buf->c_type);
1100: break;
1101: }
1102: /*
1103: * If we are restoring a filesystem with old format inodes,
1104: * copy the uid/gid to the new location.
1105: */
1106: if (oldinofmt) {
1107: buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
1108: buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
1109: }
1110: if (dflag)
1111: accthdr(buf);
1112: return(GOOD);
1113: }
1114:
1115: /*
1116: * Check that a header is where it belongs and predict the next header
1117: */
1118: static void
1119: accthdr(header)
1120: struct s_spcl *header;
1121: {
1122: static ino_t previno = 0x7fffffff;
1123: static int prevtype;
1124: static long predict;
1125: long blks, i;
1126:
1127: if (header->c_type == TS_TAPE) {
1128: fprintf(stderr, "Volume header (%s inode format) ",
1129: oldinofmt ? "old" : "new");
1130: if (header->c_firstrec)
1131: fprintf(stderr, "begins with record %d",
1132: header->c_firstrec);
1133: fprintf(stderr, "\n");
1134: previno = 0x7fffffff;
1135: return;
1136: }
1137: if (previno == 0x7fffffff)
1138: goto newcalc;
1139: switch (prevtype) {
1140: case TS_BITS:
1141: fprintf(stderr, "Dump mask header");
1142: break;
1143: case TS_CLRI:
1144: fprintf(stderr, "Remove mask header");
1145: break;
1146: case TS_INODE:
1147: fprintf(stderr, "File header, ino %d", previno);
1148: break;
1149: case TS_ADDR:
1150: fprintf(stderr, "File continuation header, ino %d", previno);
1151: break;
1152: case TS_END:
1153: fprintf(stderr, "End of tape header");
1154: break;
1155: }
1156: if (predict != blksread - 1)
1157: fprintf(stderr, "; predicted %d blocks, got %d blocks",
1158: predict, blksread - 1);
1159: fprintf(stderr, "\n");
1160: newcalc:
1161: blks = 0;
1162: if (header->c_type != TS_END)
1163: for (i = 0; i < header->c_count; i++)
1164: if (header->c_addr[i] != 0)
1165: blks++;
1166: predict = blks;
1167: blksread = 0;
1168: prevtype = header->c_type;
1169: previno = header->c_inumber;
1170: }
1171:
1172: /*
1173: * Find an inode header.
1174: * Complain if had to skip, and complain is set.
1175: */
1176: static void
1177: findinode(header)
1178: struct s_spcl *header;
1179: {
1180: static long skipcnt = 0;
1181: long i;
1182: char buf[TP_BSIZE];
1183:
1184: curfile.name = "<name unknown>";
1185: curfile.action = UNKNOWN;
1186: curfile.dip = NULL;
1187: curfile.ino = 0;
1188: do {
1189: if (header->c_magic != NFS_MAGIC) {
1190: skipcnt++;
1191: while (gethead(header) == FAIL ||
1192: header->c_date != dumpdate)
1193: skipcnt++;
1194: }
1195: switch (header->c_type) {
1196:
1197: case TS_ADDR:
1198: /*
1199: * Skip up to the beginning of the next record
1200: */
1201: for (i = 0; i < header->c_count; i++)
1202: if (header->c_addr[i])
1203: readtape(buf);
1204: while (gethead(header) == FAIL ||
1205: header->c_date != dumpdate)
1206: skipcnt++;
1207: break;
1208:
1209: case TS_INODE:
1210: curfile.dip = &header->c_dinode;
1211: curfile.ino = header->c_inumber;
1212: break;
1213:
1214: case TS_END:
1215: curfile.ino = maxino;
1216: break;
1217:
1218: case TS_CLRI:
1219: curfile.name = "<file removal list>";
1220: break;
1221:
1222: case TS_BITS:
1223: curfile.name = "<file dump list>";
1224: break;
1225:
1226: case TS_TAPE:
1227: panic("unexpected tape header\n");
1228: /* NOTREACHED */
1229:
1230: default:
1231: panic("unknown tape header type %d\n", spcl.c_type);
1232: /* NOTREACHED */
1233:
1234: }
1235: } while (header->c_type == TS_ADDR);
1236: if (skipcnt > 0)
1237: fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
1238: skipcnt = 0;
1239: }
1240:
1241: static int
1242: checksum(buf)
1243: register int *buf;
1244: {
1245: register int i, j;
1246:
1247: j = sizeof(union u_spcl) / sizeof(int);
1248: i = 0;
1249: if(!Bcvt) {
1250: do
1251: i += *buf++;
1252: while (--j);
1253: } else {
1254: /* What happens if we want to read restore tapes
1255: for a 16bit int machine??? */
1256: do
1257: i += swabl(*buf++);
1258: while (--j);
1259: }
1260:
1261: if (i != CHECKSUM) {
1262: fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1263: curfile.ino, curfile.name);
1264: return(FAIL);
1265: }
1266: return(GOOD);
1267: }
1268:
1269: #ifdef RRESTORE
1270: #if __STDC__
1271: #include <stdarg.h>
1272: #else
1273: #include <varargs.h>
1274: #endif
1275:
1276: void
1277: #if __STDC__
1278: msg(const char *fmt, ...)
1279: #else
1280: msg(fmt, va_alist)
1281: char *fmt;
1282: va_dcl
1283: #endif
1284: {
1285: va_list ap;
1286: #if __STDC__
1287: va_start(ap, fmt);
1288: #else
1289: va_start(ap);
1290: #endif
1291: (void)vfprintf(stderr, fmt, ap);
1292: va_end(ap);
1293: }
1294: #endif /* RRESTORE */
1295:
1296: static u_char *
1297: swabshort(sp, n)
1298: register u_char *sp;
1299: register int n;
1300: {
1301: char c;
1302:
1303: while (--n >= 0) {
1304: c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1305: sp += 2;
1306: }
1307: return (sp);
1308: }
1309:
1310: static u_char *
1311: swablong(sp, n)
1312: register u_char *sp;
1313: register int n;
1314: {
1315: char c;
1316:
1317: while (--n >= 0) {
1318: c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1319: c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1320: sp += 4;
1321: }
1322: return (sp);
1323: }
1324:
1325: void
1326: swabst(cp, sp)
1327: register u_char *cp, *sp;
1328: {
1329: int n = 0;
1330:
1331: while (*cp) {
1332: switch (*cp) {
1333: case '0': case '1': case '2': case '3': case '4':
1334: case '5': case '6': case '7': case '8': case '9':
1335: n = (n * 10) + (*cp++ - '0');
1336: continue;
1337:
1338: case 's': case 'w': case 'h':
1339: if (n == 0)
1340: n = 1;
1341: sp = swabshort(sp, n);
1342: break;
1343:
1344: case 'l':
1345: if (n == 0)
1346: n = 1;
1347: sp = swablong(sp, n);
1348: break;
1349:
1350: default: /* Any other character, like 'b' counts as byte. */
1351: if (n == 0)
1352: n = 1;
1353: sp += n;
1354: break;
1355: }
1356: cp++;
1357: n = 0;
1358: }
1359: }
1360:
1361: static u_long
1362: swabl(x)
1363: u_long x;
1364: {
1365: swabst((u_char *)"l", (u_char *)&x);
1366: return (x);
1367: }
CVSweb <webmaster@jp.NetBSD.org>