xref: /csrg-svn/sbin/restore/tape.c (revision 69155)
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