121170Sdist /*
261536Sbostic * Copyright (c) 1983, 1993
361536Sbostic * The Regents of the University of California. All rights reserved.
465767Sbostic * (c) UNIX System Laboratories, Inc.
565767Sbostic * All or some portions of this file are derived from material licensed
665767Sbostic * to the University of California by American Telephone and Telegraph
765767Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865767Sbostic * the permission of UNIX System Laboratories, Inc.
936105Sbostic *
1042709Sbostic * %sccs.include.redist.c%
1121170Sdist */
1221170Sdist
1311130Smckusick #ifndef lint
14*69155Smckusick static char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 05/01/95";
1536105Sbostic #endif /* not lint */
1611130Smckusick
1756567Sbostic #include <sys/param.h>
1856567Sbostic #include <sys/file.h>
1911130Smckusick #include <sys/ioctl.h>
2011130Smckusick #include <sys/mtio.h>
2156567Sbostic #include <sys/stat.h>
2256567Sbostic
2356567Sbostic #include <ufs/ufs/dinode.h>
2456567Sbostic #include <protocols/dumprestore.h>
2556567Sbostic
2656567Sbostic #include <errno.h>
2711130Smckusick #include <setjmp.h>
2856567Sbostic #include <stdio.h>
2956567Sbostic #include <stdlib.h>
3056567Sbostic #include <string.h>
3156567Sbostic #include <unistd.h>
3256567Sbostic
3356567Sbostic #include "restore.h"
3456567Sbostic #include "extern.h"
3537952Sbostic #include "pathnames.h"
3611130Smckusick
3715781Smckusick static long fssize = MAXBSIZE;
3811303Smckusick static int mt = -1;
3911303Smckusick static int pipein = 0;
4018010Smckusick static char magtape[BUFSIZ];
4156430Smckusick static int blkcnt;
4245424Smckusick static int numtrec;
4356430Smckusick static char *tapebuf;
4411303Smckusick static union u_spcl endoftapemark;
4550672Smckusick static long blksread; /* blocks read since last header */
4650673Smckusick static long tpblksread = 0; /* TP_BSIZE blocks read */
4713207Smckusick static long tapesread;
4811303Smckusick static jmp_buf restart;
4911303Smckusick static int gettingfile = 0; /* restart has a valid frame */
5050672Smckusick static char *host = NULL;
5111130Smckusick
5211303Smckusick static int ofile;
5311303Smckusick static char *map;
5411303Smckusick static char lnkbuf[MAXPATHLEN + 1];
5511303Smckusick static int pathlen;
5611130Smckusick
5754580Smckusick int oldinofmt; /* old inode format conversion required */
5826942Ssklower int Bcvt; /* Swap Bytes (for CCI or sun) */
5926942Ssklower static int Qcvt; /* Swap quads (for sun) */
6050672Smckusick
6156430Smckusick #define FLUSHTAPEBUF() blkcnt = ntrec + 1
6256430Smckusick
6356567Sbostic static void accthdr __P((struct s_spcl *));
6456567Sbostic static int checksum __P((int *));
6556567Sbostic static void findinode __P((struct s_spcl *));
6656567Sbostic static void findtapeblksize __P((void));
6756567Sbostic static int gethead __P((struct s_spcl *));
6856567Sbostic static void readtape __P((char *));
6956567Sbostic static void setdumpnum __P((void));
7056567Sbostic static u_long swabl __P((u_long));
7156567Sbostic static u_char *swablong __P((u_char *, int));
7256567Sbostic static u_char *swabshort __P((u_char *, int));
7356567Sbostic static void terminateinput __P((void));
7456567Sbostic static void xtrfile __P((char *, long));
7556567Sbostic static void xtrlnkfile __P((char *, long));
7656567Sbostic static void xtrlnkskip __P((char *, long));
7756567Sbostic static void xtrmap __P((char *, long));
7856567Sbostic static void xtrmapskip __P((char *, long));
7956567Sbostic static void xtrskip __P((char *, long));
8056567Sbostic
8111130Smckusick /*
8211130Smckusick * Set up an input source
8311130Smckusick */
8456567Sbostic void
setinput(source)8511130Smckusick setinput(source)
8611130Smckusick char *source;
8711130Smckusick {
8856430Smckusick FLUSHTAPEBUF();
8918495Smckusick if (bflag)
9018495Smckusick newtapebuf(ntrec);
9118495Smckusick else
9218495Smckusick newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
9312444Smckusick terminal = stdin;
9450672Smckusick
9512555Smckusick #ifdef RRESTORE
9669001Sbostic if (strchr(source, ':')) {
9750672Smckusick host = source;
9869001Sbostic source = strchr(host, ':');
9950672Smckusick *source++ = '\0';
10050672Smckusick if (rmthost(host) == 0)
10150672Smckusick done(1);
10250672Smckusick } else
10350672Smckusick #endif
10412444Smckusick if (strcmp(source, "-") == 0) {
10511991Smckusick /*
10611991Smckusick * Since input is coming from a pipe we must establish
10711991Smckusick * our own connection to the terminal.
10811991Smckusick */
10937952Sbostic terminal = fopen(_PATH_TTY, "r");
11011991Smckusick if (terminal == NULL) {
11156567Sbostic (void)fprintf(stderr, "cannot open %s: %s\n",
11256567Sbostic _PATH_TTY, strerror(errno));
11337952Sbostic terminal = fopen(_PATH_DEVNULL, "r");
11417710Smckusick if (terminal == NULL) {
11556567Sbostic (void)fprintf(stderr, "cannot open %s: %s\n",
11656567Sbostic _PATH_DEVNULL, strerror(errno));
11717710Smckusick done(1);
11817710Smckusick }
11911991Smckusick }
12011303Smckusick pipein++;
12111303Smckusick }
12250672Smckusick setuid(getuid()); /* no longer need or want root privileges */
12318010Smckusick (void) strcpy(magtape, source);
12411130Smckusick }
12511130Smckusick
12656567Sbostic void
newtapebuf(size)12718495Smckusick newtapebuf(size)
12818495Smckusick long size;
12918495Smckusick {
13056430Smckusick static tapebufsize = -1;
13118495Smckusick
13218495Smckusick ntrec = size;
13356430Smckusick if (size <= tapebufsize)
13418495Smckusick return;
13556430Smckusick if (tapebuf != NULL)
13656430Smckusick free(tapebuf);
13756567Sbostic tapebuf = malloc(size * TP_BSIZE);
13856430Smckusick if (tapebuf == NULL) {
13918495Smckusick fprintf(stderr, "Cannot allocate space for tape buffer\n");
14018495Smckusick done(1);
14118495Smckusick }
14256430Smckusick tapebufsize = size;
14318495Smckusick }
14418495Smckusick
14511130Smckusick /*
14611130Smckusick * Verify that the tape drive can be accessed and
14711130Smckusick * that it actually is a dump tape.
14811130Smckusick */
14956567Sbostic void
setup()15011130Smckusick setup()
15111130Smckusick {
15211303Smckusick int i, j, *ip;
15311130Smckusick struct stat stbuf;
15411130Smckusick
15511130Smckusick vprintf(stdout, "Verify tape and initialize maps\n");
15612555Smckusick #ifdef RRESTORE
15750672Smckusick if (host)
15857930Sbostic mt = rmtopen(magtape, 0);
15950672Smckusick else
16050672Smckusick #endif
16111303Smckusick if (pipein)
16211303Smckusick mt = 0;
16350672Smckusick else
16456567Sbostic mt = open(magtape, O_RDONLY, 0);
16550672Smckusick if (mt < 0) {
16656567Sbostic fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
16711130Smckusick done(1);
16811130Smckusick }
16911746Smckusick volno = 1;
17011746Smckusick setdumpnum();
17156430Smckusick FLUSHTAPEBUF();
17218495Smckusick if (!pipein && !bflag)
17318495Smckusick findtapeblksize();
17411401Smckusick if (gethead(&spcl) == FAIL) {
17556430Smckusick blkcnt--; /* push back this block */
17650672Smckusick blksread--;
17750673Smckusick tpblksread--;
17811130Smckusick cvtflag++;
17911401Smckusick if (gethead(&spcl) == FAIL) {
18011130Smckusick fprintf(stderr, "Tape is not a dump tape\n");
18111130Smckusick done(1);
18211130Smckusick }
18311130Smckusick fprintf(stderr, "Converting to new file system format.\n");
18411130Smckusick }
18511303Smckusick if (pipein) {
18611303Smckusick endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
18711303Smckusick endoftapemark.s_spcl.c_type = TS_END;
18811303Smckusick ip = (int *)&endoftapemark;
18911303Smckusick j = sizeof(union u_spcl) / sizeof(int);
19011303Smckusick i = 0;
19111303Smckusick do
19211303Smckusick i += *ip++;
19311303Smckusick while (--j);
19411303Smckusick endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
19511303Smckusick }
19629902Smckusick if (vflag || command == 't')
19729902Smckusick printdumpinfo();
19811130Smckusick dumptime = spcl.c_ddate;
19911303Smckusick dumpdate = spcl.c_date;
20011130Smckusick if (stat(".", &stbuf) < 0) {
20156567Sbostic fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
20211130Smckusick done(1);
20311130Smckusick }
20415781Smckusick if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
20515781Smckusick fssize = stbuf.st_blksize;
20615781Smckusick if (((fssize - 1) & fssize) != 0) {
20711130Smckusick fprintf(stderr, "bad block size %d\n", fssize);
20811130Smckusick done(1);
20911130Smckusick }
21056430Smckusick if (spcl.c_volume != 1) {
21111130Smckusick fprintf(stderr, "Tape is not volume 1 of the dump\n");
21211130Smckusick done(1);
21311130Smckusick }
21456430Smckusick if (gethead(&spcl) == FAIL) {
21556430Smckusick dprintf(stdout, "header read failed at %d blocks\n", blksread);
21611303Smckusick panic("no header after volume mark!\n");
21756430Smckusick }
21829902Smckusick findinode(&spcl);
21956430Smckusick if (spcl.c_type != TS_CLRI) {
22011130Smckusick fprintf(stderr, "Cannot find file removal list\n");
22111130Smckusick done(1);
22211130Smckusick }
22311303Smckusick maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
22411746Smckusick dprintf(stdout, "maxino = %d\n", maxino);
22511420Smckusick map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
22656567Sbostic if (map == NULL)
22767776Smckusick panic("no memory for active inode map\n");
22867776Smckusick usedinomap = map;
22911130Smckusick curfile.action = USING;
23011130Smckusick getfile(xtrmap, xtrmapskip);
23156430Smckusick if (spcl.c_type != TS_BITS) {
23211130Smckusick fprintf(stderr, "Cannot find file dump list\n");
23311130Smckusick done(1);
23411130Smckusick }
23511420Smckusick map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
23611130Smckusick if (map == (char *)NULL)
23711130Smckusick panic("no memory for file dump list\n");
23811747Smckusick dumpmap = map;
23911130Smckusick curfile.action = USING;
24011130Smckusick getfile(xtrmap, xtrmapskip);
24167777Smckusick /*
24267777Smckusick * If there may be whiteout entries on the tape, pretend that the
24367777Smckusick * whiteout inode exists, so that the whiteout entries can be
24467777Smckusick * extracted.
24567777Smckusick */
24667777Smckusick if (oldinofmt == 0)
24767777Smckusick SETINO(WINO, dumpmap);
24811130Smckusick }
24911130Smckusick
25013207Smckusick /*
25113207Smckusick * Prompt user to load a new dump volume.
25213207Smckusick * "Nextvol" is the next suggested volume to use.
25313207Smckusick * This suggested volume is enforced when doing full
25413207Smckusick * or incremental restores, but can be overrridden by
25513207Smckusick * the user when only extracting a subset of the files.
25613207Smckusick */
25756567Sbostic void
getvol(nextvol)25811130Smckusick getvol(nextvol)
25911130Smckusick long nextvol;
26011130Smckusick {
26150673Smckusick long newvol, savecnt, wantnext, i;
26211130Smckusick union u_spcl tmpspcl;
26311130Smckusick # define tmpbuf tmpspcl.s_spcl
26429902Smckusick char buf[TP_BSIZE];
26511130Smckusick
26617751Smckusick if (nextvol == 1) {
26713207Smckusick tapesread = 0;
26817751Smckusick gettingfile = 0;
26917751Smckusick }
27011303Smckusick if (pipein) {
27111324Smckusick if (nextvol != 1)
27211303Smckusick panic("Changing volumes on pipe input?\n");
27311324Smckusick if (volno == 1)
27411324Smckusick return;
27511324Smckusick goto gethdr;
27611303Smckusick }
27711303Smckusick savecnt = blksread;
27811130Smckusick again:
27911324Smckusick if (pipein)
28011324Smckusick done(1); /* pipes do not get a second chance */
28150673Smckusick if (command == 'R' || command == 'r' || curfile.action != SKIP) {
28211130Smckusick newvol = nextvol;
28350673Smckusick wantnext = 1;
28450673Smckusick } else {
28511130Smckusick newvol = 0;
28650673Smckusick wantnext = 0;
28750673Smckusick }
28811130Smckusick while (newvol <= 0) {
28913207Smckusick if (tapesread == 0) {
29013207Smckusick fprintf(stderr, "%s%s%s%s%s",
29113207Smckusick "You have not read any tapes yet.\n",
29213207Smckusick "Unless you know which volume your",
29313207Smckusick " file(s) are on you should start\n",
29413207Smckusick "with the last volume and work",
29526942Ssklower " towards towards the first.\n");
29613207Smckusick } else {
29713207Smckusick fprintf(stderr, "You have read volumes");
29856430Smckusick strcpy(buf, ": ");
29913207Smckusick for (i = 1; i < 32; i++)
30013207Smckusick if (tapesread & (1 << i)) {
30156430Smckusick fprintf(stderr, "%s%d", buf, i);
30256430Smckusick strcpy(buf, ", ");
30313207Smckusick }
30413207Smckusick fprintf(stderr, "\n");
30513207Smckusick }
30611943Smckusick do {
30711991Smckusick fprintf(stderr, "Specify next volume #: ");
30811991Smckusick (void) fflush(stderr);
30956430Smckusick (void) fgets(buf, BUFSIZ, terminal);
31056430Smckusick } while (!feof(terminal) && buf[0] == '\n');
31111991Smckusick if (feof(terminal))
31211943Smckusick done(1);
31356430Smckusick newvol = atoi(buf);
31411130Smckusick if (newvol <= 0) {
31511130Smckusick fprintf(stderr,
31611130Smckusick "Volume numbers are positive numerics\n");
31711130Smckusick }
31811130Smckusick }
31913207Smckusick if (newvol == volno) {
32013207Smckusick tapesread |= 1 << volno;
32111130Smckusick return;
32213207Smckusick }
32311130Smckusick closemt();
32418010Smckusick fprintf(stderr, "Mount tape volume %d\n", newvol);
32542488Smckusick fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
32642488Smckusick fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
32711991Smckusick (void) fflush(stderr);
32856430Smckusick (void) fgets(buf, BUFSIZ, terminal);
32918010Smckusick if (feof(terminal))
33018010Smckusick done(1);
33156430Smckusick if (!strcmp(buf, "none\n")) {
33253614Smckusick terminateinput();
33353614Smckusick return;
33442488Smckusick }
33556430Smckusick if (buf[0] != '\n') {
33656430Smckusick (void) strcpy(magtape, buf);
33718010Smckusick magtape[strlen(magtape) - 1] = '\0';
33818010Smckusick }
33912555Smckusick #ifdef RRESTORE
34050672Smckusick if (host)
34150672Smckusick mt = rmtopen(magtape, 0);
34250672Smckusick else
34311130Smckusick #endif
34456567Sbostic mt = open(magtape, O_RDONLY, 0);
34550672Smckusick
34650672Smckusick if (mt == -1) {
34718010Smckusick fprintf(stderr, "Cannot open %s\n", magtape);
34818010Smckusick volno = -1;
34911130Smckusick goto again;
35011130Smckusick }
35111324Smckusick gethdr:
35211130Smckusick volno = newvol;
35311746Smckusick setdumpnum();
35456430Smckusick FLUSHTAPEBUF();
35556430Smckusick if (gethead(&tmpbuf) == FAIL) {
35656430Smckusick dprintf(stdout, "header read failed at %d blocks\n", blksread);
35711130Smckusick fprintf(stderr, "tape is not dump tape\n");
35811130Smckusick volno = 0;
35911130Smckusick goto again;
36011130Smckusick }
36159796Smckusick if (tmpbuf.c_volume != volno) {
36211130Smckusick fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
36311130Smckusick volno = 0;
36411130Smckusick goto again;
36511130Smckusick }
36611303Smckusick if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
36712250Smckusick fprintf(stderr, "Wrong dump date\n\tgot: %s",
36812250Smckusick ctime(&tmpbuf.c_date));
36912250Smckusick fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
37011303Smckusick volno = 0;
37111303Smckusick goto again;
37211303Smckusick }
37313207Smckusick tapesread |= 1 << volno;
37411401Smckusick blksread = savecnt;
37550673Smckusick /*
37650673Smckusick * If continuing from the previous volume, skip over any
37750673Smckusick * blocks read already at the end of the previous volume.
37850673Smckusick *
37950673Smckusick * If coming to this volume at random, skip to the beginning
38050673Smckusick * of the next record.
38150673Smckusick */
38250673Smckusick dprintf(stdout, "read %ld recs, tape starts with %ld\n",
38350673Smckusick tpblksread, tmpbuf.c_firstrec);
38450673Smckusick if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
38550673Smckusick if (!wantnext) {
38650673Smckusick tpblksread = tmpbuf.c_firstrec;
38750673Smckusick for (i = tmpbuf.c_count; i > 0; i--)
38850673Smckusick readtape(buf);
38950673Smckusick } else if (tmpbuf.c_firstrec > 0 &&
39050673Smckusick tmpbuf.c_firstrec < tpblksread - 1) {
39150673Smckusick /*
39250673Smckusick * -1 since we've read the volume header
39350673Smckusick */
39450673Smckusick i = tpblksread - tmpbuf.c_firstrec - 1;
39550673Smckusick dprintf(stderr, "Skipping %d duplicate record%s.\n",
39650673Smckusick i, i > 1 ? "s" : "");
39750673Smckusick while (--i >= 0)
39850673Smckusick readtape(buf);
39950673Smckusick }
40050673Smckusick }
40111130Smckusick if (curfile.action == USING) {
40211130Smckusick if (volno == 1)
40311130Smckusick panic("active file into volume 1\n");
40411130Smckusick return;
40511130Smckusick }
40629902Smckusick /*
40729902Smckusick * Skip up to the beginning of the next record
40829902Smckusick */
40930429Smckusick if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
41029902Smckusick for (i = tmpbuf.c_count; i > 0; i--)
41129902Smckusick readtape(buf);
41211401Smckusick (void) gethead(&spcl);
41329902Smckusick findinode(&spcl);
41411130Smckusick if (gettingfile) {
41511130Smckusick gettingfile = 0;
41611130Smckusick longjmp(restart, 1);
41711130Smckusick }
41811130Smckusick }
41911130Smckusick
42011746Smckusick /*
42153614Smckusick * Handle unexpected EOF.
42253614Smckusick */
42356567Sbostic static void
terminateinput()42453614Smckusick terminateinput()
42553614Smckusick {
42653614Smckusick
42753614Smckusick if (gettingfile && curfile.action == USING) {
42853614Smckusick printf("Warning: %s %s\n",
42953614Smckusick "End-of-input encountered while extracting", curfile.name);
43053614Smckusick }
43153614Smckusick curfile.name = "<name unknown>";
43253614Smckusick curfile.action = UNKNOWN;
43356567Sbostic curfile.dip = NULL;
43453614Smckusick curfile.ino = maxino;
43553614Smckusick if (gettingfile) {
43653614Smckusick gettingfile = 0;
43753614Smckusick longjmp(restart, 1);
43853614Smckusick }
43953614Smckusick }
44053614Smckusick
44153614Smckusick /*
44211746Smckusick * handle multiple dumps per tape by skipping forward to the
44311746Smckusick * appropriate one.
44411746Smckusick */
44556567Sbostic static void
setdumpnum()44611746Smckusick setdumpnum()
44711746Smckusick {
44811746Smckusick struct mtop tcom;
44911746Smckusick
45011746Smckusick if (dumpnum == 1 || volno != 1)
45111746Smckusick return;
45211746Smckusick if (pipein) {
45311746Smckusick fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
45411746Smckusick done(1);
45511746Smckusick }
45611746Smckusick tcom.mt_op = MTFSF;
45711746Smckusick tcom.mt_count = dumpnum - 1;
45812555Smckusick #ifdef RRESTORE
45950672Smckusick if (host)
46050672Smckusick rmtioctl(MTFSF, dumpnum - 1);
46150672Smckusick else
46211746Smckusick #endif
46350672Smckusick if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
46456567Sbostic fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
46511746Smckusick }
46611746Smckusick
46756567Sbostic void
printdumpinfo()46829902Smckusick printdumpinfo()
46929902Smckusick {
47029902Smckusick fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date));
47132102Smckusick fprintf(stdout, "Dumped from: %s",
47232102Smckusick (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
47329902Smckusick if (spcl.c_host[0] == '\0')
47429902Smckusick return;
47529902Smckusick fprintf(stderr, "Level %d dump of %s on %s:%s\n",
47629902Smckusick spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
47729902Smckusick fprintf(stderr, "Label: %s\n", spcl.c_label);
47829902Smckusick }
47929902Smckusick
48056567Sbostic int
extractfile(name)48111130Smckusick extractfile(name)
48211130Smckusick char *name;
48311130Smckusick {
48467739Smckusick int flags;
48567739Smckusick mode_t mode;
48639472Smckusick struct timeval timep[2];
48711130Smckusick struct entry *ep;
48811130Smckusick
48911130Smckusick curfile.name = name;
49011130Smckusick curfile.action = USING;
491*69155Smckusick timep[0].tv_sec = curfile.dip->di_atime;
492*69155Smckusick timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
493*69155Smckusick timep[1].tv_sec = curfile.dip->di_mtime;
494*69155Smckusick timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
49511130Smckusick mode = curfile.dip->di_mode;
49667739Smckusick flags = curfile.dip->di_flags;
49711130Smckusick switch (mode & IFMT) {
49811130Smckusick
49911130Smckusick default:
50011130Smckusick fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
50111130Smckusick skipfile();
50211130Smckusick return (FAIL);
50311130Smckusick
50427670Smckusick case IFSOCK:
50527670Smckusick vprintf(stdout, "skipped socket %s\n", name);
50627670Smckusick skipfile();
50727670Smckusick return (GOOD);
50827670Smckusick
50911130Smckusick case IFDIR:
51011130Smckusick if (mflag) {
51111130Smckusick ep = lookupname(name);
51256567Sbostic if (ep == NULL || ep->e_flags & EXTRACT)
51311130Smckusick panic("unextracted directory %s\n", name);
51411130Smckusick skipfile();
51511130Smckusick return (GOOD);
51611130Smckusick }
51711130Smckusick vprintf(stdout, "extract file %s\n", name);
51811130Smckusick return (genliteraldir(name, curfile.ino));
51911130Smckusick
52011130Smckusick case IFLNK:
52111130Smckusick lnkbuf[0] = '\0';
52211130Smckusick pathlen = 0;
52311130Smckusick getfile(xtrlnkfile, xtrlnkskip);
52411130Smckusick if (pathlen == 0) {
52511130Smckusick vprintf(stdout,
52611130Smckusick "%s: zero length symbolic link (ignored)\n", name);
52715781Smckusick return (GOOD);
52815781Smckusick }
52915781Smckusick return (linkit(lnkbuf, name, SYMLINK));
53011130Smckusick
53111130Smckusick case IFCHR:
53211130Smckusick case IFBLK:
53311130Smckusick vprintf(stdout, "extract special file %s\n", name);
53434268Smckusick if (Nflag) {
53534268Smckusick skipfile();
53634268Smckusick return (GOOD);
53734268Smckusick }
53811130Smckusick if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
53956567Sbostic fprintf(stderr, "%s: cannot create special file: %s\n",
54056567Sbostic name, strerror(errno));
54111130Smckusick skipfile();
54211130Smckusick return (FAIL);
54311130Smckusick }
54411746Smckusick (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
54511746Smckusick (void) chmod(name, mode);
54667739Smckusick (void) chflags(name, flags);
54711130Smckusick skipfile();
54839472Smckusick utimes(name, timep);
54911130Smckusick return (GOOD);
55011130Smckusick
55167739Smckusick case IFIFO:
55267739Smckusick vprintf(stdout, "extract fifo %s\n", name);
55367739Smckusick if (Nflag) {
55467739Smckusick skipfile();
55567739Smckusick return (GOOD);
55667739Smckusick }
55767739Smckusick if (mkfifo(name, mode) < 0) {
55867739Smckusick fprintf(stderr, "%s: cannot create fifo: %s\n",
55967739Smckusick name, strerror(errno));
56067739Smckusick skipfile();
56167739Smckusick return (FAIL);
56267739Smckusick }
56367739Smckusick (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
56467739Smckusick (void) chmod(name, mode);
56567739Smckusick (void) chflags(name, flags);
56667739Smckusick skipfile();
56767739Smckusick utimes(name, timep);
56867739Smckusick return (GOOD);
56967739Smckusick
57011130Smckusick case IFREG:
57111130Smckusick vprintf(stdout, "extract file %s\n", name);
57234268Smckusick if (Nflag) {
57334268Smckusick skipfile();
57434268Smckusick return (GOOD);
57534268Smckusick }
57669001Sbostic if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
57769001Sbostic 0666)) < 0) {
57856567Sbostic fprintf(stderr, "%s: cannot create file: %s\n",
57956567Sbostic name, strerror(errno));
58011130Smckusick skipfile();
58111130Smckusick return (FAIL);
58211130Smckusick }
58311746Smckusick (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
58411746Smckusick (void) fchmod(ofile, mode);
58567739Smckusick (void) fchflags(ofile, flags);
58611130Smckusick getfile(xtrfile, xtrskip);
58711746Smckusick (void) close(ofile);
58839472Smckusick utimes(name, timep);
58911130Smckusick return (GOOD);
59011130Smckusick }
59111130Smckusick /* NOTREACHED */
59211130Smckusick }
59311130Smckusick
59411324Smckusick /*
59511324Smckusick * skip over bit maps on the tape
59611324Smckusick */
59756567Sbostic void
skipmaps()59811324Smckusick skipmaps()
59911324Smckusick {
60011324Smckusick
60156430Smckusick while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
60211324Smckusick skipfile();
60311324Smckusick }
60411324Smckusick
60511324Smckusick /*
60611324Smckusick * skip over a file on the tape
60711324Smckusick */
60856567Sbostic void
skipfile()60911130Smckusick skipfile()
61011130Smckusick {
61111130Smckusick
61211130Smckusick curfile.action = SKIP;
61356430Smckusick getfile(xtrnull, xtrnull);
61411130Smckusick }
61511130Smckusick
61611130Smckusick /*
61756430Smckusick * Extract a file from the tape.
61856430Smckusick * When an allocated block is found it is passed to the fill function;
61956430Smckusick * when an unallocated block (hole) is found, a zeroed buffer is passed
62056430Smckusick * to the skip function.
62111130Smckusick */
62256567Sbostic void
62356430Smckusick getfile(fill, skip)
62456567Sbostic void (*fill) __P((char *, long));
62556567Sbostic void (*skip) __P((char *, long));
62611130Smckusick {
62711130Smckusick register int i;
62811130Smckusick int curblk = 0;
62968250Smckusick quad_t size = spcl.c_dinode.di_size;
63011130Smckusick static char clearedbuf[MAXBSIZE];
63111130Smckusick char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
63223866Smckusick char junk[TP_BSIZE];
63311130Smckusick
63456430Smckusick if (spcl.c_type == TS_END)
63511130Smckusick panic("ran off end of tape\n");
63656430Smckusick if (spcl.c_magic != NFS_MAGIC)
63711130Smckusick panic("not at beginning of a file\n");
63811324Smckusick if (!gettingfile && setjmp(restart) != 0)
63911130Smckusick return;
64011130Smckusick gettingfile++;
64111130Smckusick loop:
64211130Smckusick for (i = 0; i < spcl.c_count; i++) {
64311130Smckusick if (spcl.c_addr[i]) {
64411130Smckusick readtape(&buf[curblk++][0]);
64511130Smckusick if (curblk == fssize / TP_BSIZE) {
64668250Smckusick (*fill)((char *)buf, (long)(size > TP_BSIZE ?
64768250Smckusick fssize : (curblk - 1) * TP_BSIZE + size));
64811130Smckusick curblk = 0;
64911130Smckusick }
65011130Smckusick } else {
65111130Smckusick if (curblk > 0) {
65268250Smckusick (*fill)((char *)buf, (long)(size > TP_BSIZE ?
65368250Smckusick curblk * TP_BSIZE :
65468250Smckusick (curblk - 1) * TP_BSIZE + size));
65511130Smckusick curblk = 0;
65611130Smckusick }
65768250Smckusick (*skip)(clearedbuf, (long)(size > TP_BSIZE ?
65868250Smckusick TP_BSIZE : size));
65911130Smckusick }
66023866Smckusick if ((size -= TP_BSIZE) <= 0) {
66123866Smckusick for (i++; i < spcl.c_count; i++)
66223866Smckusick if (spcl.c_addr[i])
66323866Smckusick readtape(junk);
66411311Smckusick break;
66523866Smckusick }
66611130Smckusick }
66756430Smckusick if (gethead(&spcl) == GOOD && size > 0) {
66856430Smckusick if (spcl.c_type == TS_ADDR)
66911311Smckusick goto loop;
67056430Smckusick dprintf(stdout,
67156430Smckusick "Missing address (header) block for %s at %d blocks\n",
67256430Smckusick curfile.name, blksread);
67311130Smckusick }
67411311Smckusick if (curblk > 0)
67568250Smckusick (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
67629902Smckusick findinode(&spcl);
67711130Smckusick gettingfile = 0;
67811130Smckusick }
67911130Smckusick
68011130Smckusick /*
68156430Smckusick * Write out the next block of a file.
68211130Smckusick */
68356567Sbostic static void
xtrfile(buf,size)68411130Smckusick xtrfile(buf, size)
68511130Smckusick char *buf;
68611130Smckusick long size;
68711130Smckusick {
68811130Smckusick
68934268Smckusick if (Nflag)
69034268Smckusick return;
69111130Smckusick if (write(ofile, buf, (int) size) == -1) {
69256567Sbostic fprintf(stderr,
69356567Sbostic "write error extracting inode %d, name %s\nwrite: %s\n",
69456567Sbostic curfile.ino, curfile.name, strerror(errno));
69511130Smckusick done(1);
69611130Smckusick }
69711130Smckusick }
69811130Smckusick
69956430Smckusick /*
70056430Smckusick * Skip over a hole in a file.
70156430Smckusick */
70256430Smckusick /* ARGSUSED */
70356567Sbostic static void
xtrskip(buf,size)70411130Smckusick xtrskip(buf, size)
70511130Smckusick char *buf;
70611130Smckusick long size;
70711130Smckusick {
70811130Smckusick
70966571Sbostic if (lseek(ofile, size, SEEK_CUR) == -1) {
71056567Sbostic fprintf(stderr,
71156567Sbostic "seek error extracting inode %d, name %s\nlseek: %s\n",
71256567Sbostic curfile.ino, curfile.name, strerror(errno));
71311130Smckusick done(1);
71411130Smckusick }
71511130Smckusick }
71611130Smckusick
71756430Smckusick /*
71856430Smckusick * Collect the next block of a symbolic link.
71956430Smckusick */
72056567Sbostic static void
xtrlnkfile(buf,size)72111130Smckusick xtrlnkfile(buf, size)
72211130Smckusick char *buf;
72311130Smckusick long size;
72411130Smckusick {
72511130Smckusick
72611130Smckusick pathlen += size;
72711130Smckusick if (pathlen > MAXPATHLEN) {
72811130Smckusick fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
72911130Smckusick curfile.name, lnkbuf, buf, pathlen);
73011130Smckusick done(1);
73111130Smckusick }
73211943Smckusick (void) strcat(lnkbuf, buf);
73311130Smckusick }
73411130Smckusick
73556430Smckusick /*
73656430Smckusick * Skip over a hole in a symbolic link (should never happen).
73756430Smckusick */
73856430Smckusick /* ARGSUSED */
73956567Sbostic static void
xtrlnkskip(buf,size)74011130Smckusick xtrlnkskip(buf, size)
74111130Smckusick char *buf;
74211130Smckusick long size;
74311130Smckusick {
74411130Smckusick
74511130Smckusick fprintf(stderr, "unallocated block in symbolic link %s\n",
74611130Smckusick curfile.name);
74711130Smckusick done(1);
74811130Smckusick }
74911130Smckusick
75056430Smckusick /*
75156430Smckusick * Collect the next block of a bit map.
75256430Smckusick */
75356567Sbostic static void
xtrmap(buf,size)75411130Smckusick xtrmap(buf, size)
75511130Smckusick char *buf;
75611130Smckusick long size;
75711130Smckusick {
75811130Smckusick
75969001Sbostic memmove(map, buf, size);
76011747Smckusick map += size;
76111130Smckusick }
76211130Smckusick
76356430Smckusick /*
76456430Smckusick * Skip over a hole in a bit map (should never happen).
76556430Smckusick */
76656430Smckusick /* ARGSUSED */
76756567Sbostic static void
xtrmapskip(buf,size)76811130Smckusick xtrmapskip(buf, size)
76911130Smckusick char *buf;
77011130Smckusick long size;
77111130Smckusick {
77211130Smckusick
77311130Smckusick panic("hole in map\n");
77411747Smckusick map += size;
77511130Smckusick }
77611130Smckusick
77756430Smckusick /*
77856430Smckusick * Noop, when an extraction function is not needed.
77956430Smckusick */
78056430Smckusick /* ARGSUSED */
78156567Sbostic void
xtrnull(buf,size)78256430Smckusick xtrnull(buf, size)
78356430Smckusick char *buf;
78456430Smckusick long size;
78556430Smckusick {
78611130Smckusick
78756430Smckusick return;
78856430Smckusick }
78956430Smckusick
79011130Smckusick /*
79156430Smckusick * Read TP_BSIZE blocks from the input.
79256430Smckusick * Handle read errors, and end of media.
79311130Smckusick */
79456567Sbostic static void
readtape(buf)79556430Smckusick readtape(buf)
79656430Smckusick char *buf;
79711130Smckusick {
79856430Smckusick long rd, newvol, i;
79956430Smckusick int cnt, seek_failed;
80011130Smckusick
80156430Smckusick if (blkcnt < numtrec) {
80269001Sbostic memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
80318495Smckusick blksread++;
80450673Smckusick tpblksread++;
80518495Smckusick return;
80618495Smckusick }
80718495Smckusick for (i = 0; i < ntrec; i++)
80856430Smckusick ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
80945424Smckusick if (numtrec == 0)
81045424Smckusick numtrec = ntrec;
81150672Smckusick cnt = ntrec * TP_BSIZE;
81218495Smckusick rd = 0;
81318495Smckusick getmore:
81412555Smckusick #ifdef RRESTORE
81550672Smckusick if (host)
81656430Smckusick i = rmtread(&tapebuf[rd], cnt);
81750672Smckusick else
81811130Smckusick #endif
81956430Smckusick i = read(mt, &tapebuf[rd], cnt);
82045424Smckusick /*
82145424Smckusick * Check for mid-tape short read error.
82250672Smckusick * If found, skip rest of buffer and start with the next.
82345424Smckusick */
82450672Smckusick if (!pipein && numtrec < ntrec && i > 0) {
82550672Smckusick dprintf(stdout, "mid-media short read error.\n");
82645424Smckusick numtrec = ntrec;
82745424Smckusick }
82845424Smckusick /*
82945424Smckusick * Handle partial block read.
83045424Smckusick */
83154157Smckusick if (pipein && i == 0 && rd > 0)
83254157Smckusick i = rd;
83354157Smckusick else if (i > 0 && i != ntrec * TP_BSIZE) {
83418495Smckusick if (pipein) {
83511313Smckusick rd += i;
83611313Smckusick cnt -= i;
83711313Smckusick if (cnt > 0)
83811313Smckusick goto getmore;
83911313Smckusick i = rd;
84018495Smckusick } else {
84150672Smckusick /*
84250672Smckusick * Short read. Process the blocks read.
84350672Smckusick */
84418495Smckusick if (i % TP_BSIZE != 0)
84550672Smckusick vprintf(stdout,
84650672Smckusick "partial block read: %d should be %d\n",
84750672Smckusick i, ntrec * TP_BSIZE);
84845424Smckusick numtrec = i / TP_BSIZE;
84911313Smckusick }
85018495Smckusick }
85145424Smckusick /*
85245424Smckusick * Handle read error.
85345424Smckusick */
85418495Smckusick if (i < 0) {
85518495Smckusick fprintf(stderr, "Tape read error while ");
85618495Smckusick switch (curfile.action) {
85718495Smckusick default:
85818495Smckusick fprintf(stderr, "trying to set up tape\n");
85918495Smckusick break;
86018495Smckusick case UNKNOWN:
86133535Smckusick fprintf(stderr, "trying to resynchronize\n");
86218495Smckusick break;
86318495Smckusick case USING:
86418495Smckusick fprintf(stderr, "restoring %s\n", curfile.name);
86518495Smckusick break;
86618495Smckusick case SKIP:
86718495Smckusick fprintf(stderr, "skipping over inode %d\n",
86818495Smckusick curfile.ino);
86918495Smckusick break;
87018495Smckusick }
87118495Smckusick if (!yflag && !reply("continue"))
87218495Smckusick done(1);
87356430Smckusick i = ntrec * TP_BSIZE;
87469001Sbostic memset(tapebuf, 0, i);
87512555Smckusick #ifdef RRESTORE
87650672Smckusick if (host)
87750672Smckusick seek_failed = (rmtseek(i, 1) < 0);
87850672Smckusick else
87911130Smckusick #endif
88056567Sbostic seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
88150672Smckusick
88250672Smckusick if (seek_failed) {
88356567Sbostic fprintf(stderr,
88456567Sbostic "continuation failed: %s\n", strerror(errno));
88518495Smckusick done(1);
88611130Smckusick }
88718495Smckusick }
88845424Smckusick /*
88945424Smckusick * Handle end of tape.
89045424Smckusick */
89118495Smckusick if (i == 0) {
89250672Smckusick vprintf(stdout, "End-of-tape encountered\n");
89318690Smckusick if (!pipein) {
89418690Smckusick newvol = volno + 1;
89518690Smckusick volno = 0;
89645424Smckusick numtrec = 0;
89718690Smckusick getvol(newvol);
89856430Smckusick readtape(buf);
89911130Smckusick return;
90011130Smckusick }
90118690Smckusick if (rd % TP_BSIZE != 0)
90218690Smckusick panic("partial block read: %d should be %d\n",
90318690Smckusick rd, ntrec * TP_BSIZE);
90453614Smckusick terminateinput();
90569001Sbostic memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
90611130Smckusick }
90756430Smckusick blkcnt = 0;
90869001Sbostic memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
90911303Smckusick blksread++;
91050673Smckusick tpblksread++;
91111130Smckusick }
91211130Smckusick
91356567Sbostic static void
findtapeblksize()91418495Smckusick findtapeblksize()
91518495Smckusick {
91618495Smckusick register long i;
91718495Smckusick
91818495Smckusick for (i = 0; i < ntrec; i++)
91956430Smckusick ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
92056430Smckusick blkcnt = 0;
92118495Smckusick #ifdef RRESTORE
92250672Smckusick if (host)
92356430Smckusick i = rmtread(tapebuf, ntrec * TP_BSIZE);
92450672Smckusick else
92518495Smckusick #endif
92656430Smckusick i = read(mt, tapebuf, ntrec * TP_BSIZE);
92750672Smckusick
92818495Smckusick if (i <= 0) {
92956567Sbostic fprintf(stderr, "tape read error: %s\n", strerror(errno));
93018495Smckusick done(1);
93118495Smckusick }
93218495Smckusick if (i % TP_BSIZE != 0) {
93318495Smckusick fprintf(stderr, "Tape block size (%d) %s (%d)\n",
93418495Smckusick i, "is not a multiple of dump block size", TP_BSIZE);
93518495Smckusick done(1);
93618495Smckusick }
93718495Smckusick ntrec = i / TP_BSIZE;
93845424Smckusick numtrec = ntrec;
93918495Smckusick vprintf(stdout, "Tape block size is %d\n", ntrec);
94018495Smckusick }
94118495Smckusick
94256567Sbostic void
closemt()94356430Smckusick closemt()
94411130Smckusick {
94511130Smckusick
94611130Smckusick if (mt < 0)
94711130Smckusick return;
94812555Smckusick #ifdef RRESTORE
94950672Smckusick if (host)
95050672Smckusick rmtclose();
95150672Smckusick else
95211130Smckusick #endif
95350672Smckusick (void) close(mt);
95411130Smckusick }
95511130Smckusick
95611130Smckusick /*
95756430Smckusick * Read the next block from the tape.
95856430Smckusick * Check to see if it is one of several vintage headers.
95956430Smckusick * If it is an old style header, convert it to a new style header.
96056430Smckusick * If it is not any valid header, return an error.
96111130Smckusick */
96256567Sbostic static int
gethead(buf)96311130Smckusick gethead(buf)
96411130Smckusick struct s_spcl *buf;
96511130Smckusick {
96642488Smckusick long i;
96752266Smckusick union {
96852266Smckusick quad_t qval;
96952266Smckusick long val[2];
97052266Smckusick } qcvt;
97111130Smckusick union u_ospcl {
97211130Smckusick char dummy[TP_BSIZE];
97311130Smckusick struct s_ospcl {
97411303Smckusick long c_type;
97511303Smckusick long c_date;
97611303Smckusick long c_ddate;
97711303Smckusick long c_volume;
97811303Smckusick long c_tapea;
97911747Smckusick u_short c_inumber;
98011303Smckusick long c_magic;
98111303Smckusick long c_checksum;
98211130Smckusick struct odinode {
98311130Smckusick unsigned short odi_mode;
98411747Smckusick u_short odi_nlink;
98511747Smckusick u_short odi_uid;
98611747Smckusick u_short odi_gid;
98711303Smckusick long odi_size;
98811303Smckusick long odi_rdev;
98911130Smckusick char odi_addr[36];
99011303Smckusick long odi_atime;
99111303Smckusick long odi_mtime;
99211303Smckusick long odi_ctime;
99311130Smckusick } c_dinode;
99411303Smckusick long c_count;
99511303Smckusick char c_addr[256];
99611130Smckusick } s_ospcl;
99711130Smckusick } u_ospcl;
99811130Smckusick
99911130Smckusick if (!cvtflag) {
100011130Smckusick readtape((char *)buf);
100126942Ssklower if (buf->c_magic != NFS_MAGIC) {
100226942Ssklower if (swabl(buf->c_magic) != NFS_MAGIC)
100326942Ssklower return (FAIL);
100426942Ssklower if (!Bcvt) {
100526942Ssklower vprintf(stdout, "Note: Doing Byte swapping\n");
100626942Ssklower Bcvt = 1;
100726942Ssklower }
100826942Ssklower }
100926942Ssklower if (checksum((int *)buf) == FAIL)
101026942Ssklower return (FAIL);
101126942Ssklower if (Bcvt)
101256567Sbostic swabst((u_char *)"8l4s31l", (u_char *)buf);
101311401Smckusick goto good;
101411130Smckusick }
101511130Smckusick readtape((char *)(&u_ospcl.s_ospcl));
101669001Sbostic memset(buf, 0, (long)TP_BSIZE);
101711130Smckusick buf->c_type = u_ospcl.s_ospcl.c_type;
101811130Smckusick buf->c_date = u_ospcl.s_ospcl.c_date;
101911130Smckusick buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
102011130Smckusick buf->c_volume = u_ospcl.s_ospcl.c_volume;
102111130Smckusick buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
102211130Smckusick buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
102311130Smckusick buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
102411130Smckusick buf->c_magic = u_ospcl.s_ospcl.c_magic;
102511130Smckusick buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
102611130Smckusick buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
102711130Smckusick buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
102811130Smckusick buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
102911130Smckusick buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
103011130Smckusick buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1031*69155Smckusick buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
1032*69155Smckusick buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1033*69155Smckusick buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
103411130Smckusick buf->c_count = u_ospcl.s_ospcl.c_count;
103569001Sbostic memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256);
103611130Smckusick if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
103711401Smckusick checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
103811303Smckusick return(FAIL);
103911401Smckusick buf->c_magic = NFS_MAGIC;
104011401Smckusick
104111401Smckusick good:
104252267Smckusick if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
104346565Smckusick (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
104452266Smckusick qcvt.qval = buf->c_dinode.di_size;
104552266Smckusick if (qcvt.val[0] || qcvt.val[1]) {
104626942Ssklower printf("Note: Doing Quad swapping\n");
104726942Ssklower Qcvt = 1;
104826942Ssklower }
104926942Ssklower }
105026942Ssklower if (Qcvt) {
105152266Smckusick qcvt.qval = buf->c_dinode.di_size;
105252266Smckusick i = qcvt.val[1];
105352266Smckusick qcvt.val[1] = qcvt.val[0];
105452266Smckusick qcvt.val[0] = i;
105556717Smckusick buf->c_dinode.di_size = qcvt.qval;
105626942Ssklower }
105750672Smckusick
105811401Smckusick switch (buf->c_type) {
105911401Smckusick
106011401Smckusick case TS_CLRI:
106111401Smckusick case TS_BITS:
106211401Smckusick /*
106311401Smckusick * Have to patch up missing information in bit map headers
106411401Smckusick */
106511401Smckusick buf->c_inumber = 0;
106611401Smckusick buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
106711401Smckusick for (i = 0; i < buf->c_count; i++)
106811401Smckusick buf->c_addr[i]++;
106911401Smckusick break;
107011401Smckusick
107111401Smckusick case TS_TAPE:
107254580Smckusick if ((buf->c_flags & DR_NEWINODEFMT) == 0)
107354580Smckusick oldinofmt = 1;
107454580Smckusick /* fall through */
107511401Smckusick case TS_END:
107611401Smckusick buf->c_inumber = 0;
107711401Smckusick break;
107811401Smckusick
107911401Smckusick case TS_INODE:
108011401Smckusick case TS_ADDR:
108111401Smckusick break;
108211401Smckusick
108311401Smckusick default:
108411401Smckusick panic("gethead: unknown inode type %d\n", buf->c_type);
108511401Smckusick break;
108611303Smckusick }
108754580Smckusick /*
108854580Smckusick * If we are restoring a filesystem with old format inodes,
108954580Smckusick * copy the uid/gid to the new location.
109054580Smckusick */
109154580Smckusick if (oldinofmt) {
109254580Smckusick buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
109354580Smckusick buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
109454580Smckusick }
109511303Smckusick if (dflag)
109611303Smckusick accthdr(buf);
109711303Smckusick return(GOOD);
109811130Smckusick }
109911130Smckusick
110011130Smckusick /*
110111303Smckusick * Check that a header is where it belongs and predict the next header
110211303Smckusick */
110356567Sbostic static void
accthdr(header)110411303Smckusick accthdr(header)
110511303Smckusick struct s_spcl *header;
110611303Smckusick {
110711420Smckusick static ino_t previno = 0x7fffffff;
110811303Smckusick static int prevtype;
110911303Smckusick static long predict;
111011303Smckusick long blks, i;
111111303Smckusick
111230429Smckusick if (header->c_type == TS_TAPE) {
111354592Smckusick fprintf(stderr, "Volume header (%s inode format) ",
111454592Smckusick oldinofmt ? "old" : "new");
111550673Smckusick if (header->c_firstrec)
111654592Smckusick fprintf(stderr, "begins with record %d",
111750673Smckusick header->c_firstrec);
111850673Smckusick fprintf(stderr, "\n");
111929897Smckusick previno = 0x7fffffff;
112011401Smckusick return;
112111401Smckusick }
112211420Smckusick if (previno == 0x7fffffff)
112311303Smckusick goto newcalc;
112411303Smckusick switch (prevtype) {
112511303Smckusick case TS_BITS:
112667776Smckusick fprintf(stderr, "Dumped inodes map header");
112711303Smckusick break;
112811303Smckusick case TS_CLRI:
112967776Smckusick fprintf(stderr, "Used inodes map header");
113011303Smckusick break;
113111303Smckusick case TS_INODE:
113211401Smckusick fprintf(stderr, "File header, ino %d", previno);
113311303Smckusick break;
113411303Smckusick case TS_ADDR:
113511401Smckusick fprintf(stderr, "File continuation header, ino %d", previno);
113611303Smckusick break;
113711303Smckusick case TS_END:
113811401Smckusick fprintf(stderr, "End of tape header");
113911303Smckusick break;
114011303Smckusick }
114111303Smckusick if (predict != blksread - 1)
114211303Smckusick fprintf(stderr, "; predicted %d blocks, got %d blocks",
114311303Smckusick predict, blksread - 1);
114411303Smckusick fprintf(stderr, "\n");
114511303Smckusick newcalc:
114611303Smckusick blks = 0;
114711401Smckusick if (header->c_type != TS_END)
114811303Smckusick for (i = 0; i < header->c_count; i++)
114911303Smckusick if (header->c_addr[i] != 0)
115011303Smckusick blks++;
115111303Smckusick predict = blks;
115211303Smckusick blksread = 0;
115311303Smckusick prevtype = header->c_type;
115411303Smckusick previno = header->c_inumber;
115511303Smckusick }
115611303Smckusick
115711303Smckusick /*
115811130Smckusick * Find an inode header.
115911130Smckusick * Complain if had to skip, and complain is set.
116011130Smckusick */
116156567Sbostic static void
findinode(header)116229902Smckusick findinode(header)
116311130Smckusick struct s_spcl *header;
116411130Smckusick {
116511303Smckusick static long skipcnt = 0;
116629897Smckusick long i;
116729897Smckusick char buf[TP_BSIZE];
116811130Smckusick
116911130Smckusick curfile.name = "<name unknown>";
117011130Smckusick curfile.action = UNKNOWN;
117156567Sbostic curfile.dip = NULL;
117211130Smckusick curfile.ino = 0;
117356430Smckusick do {
117456430Smckusick if (header->c_magic != NFS_MAGIC) {
117511130Smckusick skipcnt++;
117656430Smckusick while (gethead(header) == FAIL ||
117756430Smckusick header->c_date != dumpdate)
117856430Smckusick skipcnt++;
117956430Smckusick }
118056430Smckusick switch (header->c_type) {
118156430Smckusick
118256430Smckusick case TS_ADDR:
118329897Smckusick /*
118429897Smckusick * Skip up to the beginning of the next record
118529897Smckusick */
118629897Smckusick for (i = 0; i < header->c_count; i++)
118729897Smckusick if (header->c_addr[i])
118829897Smckusick readtape(buf);
118956430Smckusick while (gethead(header) == FAIL ||
119056430Smckusick header->c_date != dumpdate)
119156430Smckusick skipcnt++;
119256430Smckusick break;
119356430Smckusick
119456430Smckusick case TS_INODE:
119511130Smckusick curfile.dip = &header->c_dinode;
119611130Smckusick curfile.ino = header->c_inumber;
119711130Smckusick break;
119856430Smckusick
119956430Smckusick case TS_END:
120011130Smckusick curfile.ino = maxino;
120111130Smckusick break;
120256430Smckusick
120356430Smckusick case TS_CLRI:
120411130Smckusick curfile.name = "<file removal list>";
120511324Smckusick break;
120656430Smckusick
120756430Smckusick case TS_BITS:
120811130Smckusick curfile.name = "<file dump list>";
120911324Smckusick break;
121056430Smckusick
121156430Smckusick case TS_TAPE:
121256430Smckusick panic("unexpected tape header\n");
121356430Smckusick /* NOTREACHED */
121456430Smckusick
121556430Smckusick default:
121656430Smckusick panic("unknown tape header type %d\n", spcl.c_type);
121756430Smckusick /* NOTREACHED */
121856430Smckusick
121911130Smckusick }
122056430Smckusick } while (header->c_type == TS_ADDR);
122129902Smckusick if (skipcnt > 0)
122212243Smckusick fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
122311130Smckusick skipcnt = 0;
122411130Smckusick }
122511130Smckusick
122656567Sbostic static int
checksum(buf)122756430Smckusick checksum(buf)
122856430Smckusick register int *buf;
122911130Smckusick {
123011130Smckusick register int i, j;
123111130Smckusick
123211130Smckusick j = sizeof(union u_spcl) / sizeof(int);
123311130Smckusick i = 0;
123426942Ssklower if(!Bcvt) {
123526942Ssklower do
123656430Smckusick i += *buf++;
123726942Ssklower while (--j);
123826942Ssklower } else {
123926942Ssklower /* What happens if we want to read restore tapes
124026942Ssklower for a 16bit int machine??? */
124126942Ssklower do
124256430Smckusick i += swabl(*buf++);
124326942Ssklower while (--j);
124426942Ssklower }
124526942Ssklower
124611130Smckusick if (i != CHECKSUM) {
124711130Smckusick fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
124811130Smckusick curfile.ino, curfile.name);
124911303Smckusick return(FAIL);
125011130Smckusick }
125111303Smckusick return(GOOD);
125211130Smckusick }
125311130Smckusick
125412555Smckusick #ifdef RRESTORE
125556567Sbostic #if __STDC__
125656567Sbostic #include <stdarg.h>
125756567Sbostic #else
125856567Sbostic #include <varargs.h>
125956567Sbostic #endif
126056567Sbostic
126156567Sbostic void
126256567Sbostic #if __STDC__
msg(const char * fmt,...)126356567Sbostic msg(const char *fmt, ...)
126456567Sbostic #else
126556567Sbostic msg(fmt, va_alist)
126656567Sbostic char *fmt;
126756567Sbostic va_dcl
126856567Sbostic #endif
126911130Smckusick {
127056567Sbostic va_list ap;
127156567Sbostic #if __STDC__
127256567Sbostic va_start(ap, fmt);
127356567Sbostic #else
127456567Sbostic va_start(ap);
127556567Sbostic #endif
127656567Sbostic (void)vfprintf(stderr, fmt, ap);
127756567Sbostic va_end(ap);
127811130Smckusick }
127950672Smckusick #endif /* RRESTORE */
128026942Ssklower
128156567Sbostic static u_char *
swabshort(sp,n)128246565Smckusick swabshort(sp, n)
128346565Smckusick register u_char *sp;
128446565Smckusick register int n;
128546565Smckusick {
128646565Smckusick char c;
128746565Smckusick
128846565Smckusick while (--n >= 0) {
128946565Smckusick c = sp[0]; sp[0] = sp[1]; sp[1] = c;
129046565Smckusick sp += 2;
129146565Smckusick }
129246565Smckusick return (sp);
129346565Smckusick }
129446565Smckusick
129556567Sbostic static u_char *
swablong(sp,n)129646565Smckusick swablong(sp, n)
129746565Smckusick register u_char *sp;
129846565Smckusick register int n;
129946565Smckusick {
130046565Smckusick char c;
130146565Smckusick
130246565Smckusick while (--n >= 0) {
130346565Smckusick c = sp[0]; sp[0] = sp[3]; sp[3] = c;
130446565Smckusick c = sp[2]; sp[2] = sp[1]; sp[1] = c;
130546565Smckusick sp += 4;
130646565Smckusick }
130746565Smckusick return (sp);
130846565Smckusick }
130946565Smckusick
131056567Sbostic void
swabst(cp,sp)131126942Ssklower swabst(cp, sp)
131246565Smckusick register u_char *cp, *sp;
131326942Ssklower {
131426942Ssklower int n = 0;
131546565Smckusick
131646565Smckusick while (*cp) {
131726942Ssklower switch (*cp) {
131826942Ssklower case '0': case '1': case '2': case '3': case '4':
131926942Ssklower case '5': case '6': case '7': case '8': case '9':
132026942Ssklower n = (n * 10) + (*cp++ - '0');
132126942Ssklower continue;
132226942Ssklower
132326942Ssklower case 's': case 'w': case 'h':
132446565Smckusick if (n == 0)
132546565Smckusick n = 1;
132646565Smckusick sp = swabshort(sp, n);
132726942Ssklower break;
132826942Ssklower
132926942Ssklower case 'l':
133046565Smckusick if (n == 0)
133146565Smckusick n = 1;
133246565Smckusick sp = swablong(sp, n);
133346565Smckusick break;
133446565Smckusick
133546565Smckusick default: /* Any other character, like 'b' counts as byte. */
133646565Smckusick if (n == 0)
133746565Smckusick n = 1;
133846565Smckusick sp += n;
133946565Smckusick break;
134026942Ssklower }
134146565Smckusick cp++;
134246565Smckusick n = 0;
134326942Ssklower }
134426942Ssklower }
134546565Smckusick
134656567Sbostic static u_long
swabl(x)134746565Smckusick swabl(x)
134846565Smckusick u_long x;
134946565Smckusick {
135056567Sbostic swabst((u_char *)"l", (u_char *)&x);
135146565Smckusick return (x);
135246565Smckusick }
1353