xref: /csrg-svn/local/ukc/restore/tape.c (revision 32048)
132022Spc /*
232022Spc  * Copyright (c) 1983 Regents of the University of California.
332022Spc  * All rights reserved.  The Berkeley software License Agreement
432022Spc  * specifies the terms and conditions for redistribution.
532022Spc  */
632022Spc 
732022Spc #ifndef lint
832025Spc static char sccsid[] = "@(#)tape.c	5.10 (Berkeley) 1/28/87";
932022Spc #endif not lint
1032022Spc 
1132022Spc #include "restore.h"
1232022Spc #include <protocols/dumprestore.h>
1332022Spc #include <sys/ioctl.h>
1432022Spc #include <sys/mtio.h>
1532022Spc #include <sys/file.h>
1632022Spc #include <setjmp.h>
1732022Spc #include <sys/stat.h>
1832022Spc 
1932022Spc static long	fssize = MAXBSIZE;
2032022Spc static int	mt = -1;
2132022Spc static int	pipein = 0;
2232022Spc static char	magtape[BUFSIZ];
2332022Spc static int	bct;
2432022Spc static char	*tbf;
2532022Spc static union	u_spcl endoftapemark;
2632022Spc static long	blksread;
2732022Spc static long	tapesread;
2832022Spc static jmp_buf	restart;
2932022Spc static int	gettingfile = 0;	/* restart has a valid frame */
3032022Spc 
3132022Spc static int	ofile;
3232022Spc static char	*map;
3332022Spc static char	lnkbuf[MAXPATHLEN + 1];
3432022Spc static int	pathlen;
3532022Spc 
3632022Spc int		Bcvt;		/* Swap Bytes (for CCI or sun) */
3732022Spc static int	Qcvt;		/* Swap quads (for sun) */
3832022Spc /*
3932022Spc  * Set up an input source
4032022Spc  */
setinput(source)4132022Spc setinput(source)
4232022Spc 	char *source;
4332022Spc {
4432022Spc #ifdef RRESTORE
4532022Spc 	char *host, *tape;
4632022Spc #endif RRESTORE
4732022Spc 
4832022Spc 	flsht();
4932022Spc 	if (bflag)
5032022Spc 		newtapebuf(ntrec);
5132022Spc 	else
5232022Spc 		newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
5332022Spc 	terminal = stdin;
5432022Spc #ifdef RRESTORE
5532022Spc 	host = source;
5632022Spc 	tape = index(host, ':');
5732022Spc 	if (tape == 0) {
5832022Spc nohost:
5932022Spc 		msg("need keyletter ``f'' and device ``host:tape''\n");
6032022Spc 		done(1);
6132022Spc 	}
6232022Spc 	*tape++ = '\0';
6332022Spc 	(void) strcpy(magtape, tape);
6432022Spc 	if (rmthost(host) == 0)
6532022Spc 		done(1);
6632022Spc 	setuid(getuid());	/* no longer need or want root privileges */
6732022Spc #else
6832022Spc 	if (strcmp(source, "-") == 0) {
6932022Spc 		/*
7032022Spc 		 * Since input is coming from a pipe we must establish
7132022Spc 		 * our own connection to the terminal.
7232022Spc 		 */
7332022Spc 		terminal = fopen("/dev/tty", "r");
7432022Spc 		if (terminal == NULL) {
7532022Spc 			perror("Cannot open(\"/dev/tty\")");
7632022Spc 			terminal = fopen("/dev/null", "r");
7732022Spc 			if (terminal == NULL) {
7832022Spc 				perror("Cannot open(\"/dev/null\")");
7932022Spc 				done(1);
8032022Spc 			}
8132022Spc 		}
8232022Spc 		pipein++;
8332022Spc 	}
8432022Spc 	(void) strcpy(magtape, source);
8532022Spc #endif RRESTORE
8632022Spc }
8732022Spc 
newtapebuf(size)8832022Spc newtapebuf(size)
8932022Spc 	long size;
9032022Spc {
9132022Spc 	static tbfsize = -1;
9232022Spc 
9332022Spc 	ntrec = size;
9432022Spc 	if (size <= tbfsize)
9532022Spc 		return;
9632022Spc 	if (tbf != NULL)
9732022Spc 		free(tbf);
9832022Spc 	tbf = (char *)malloc(size * TP_BSIZE);
9932022Spc 	if (tbf == NULL) {
10032022Spc 		fprintf(stderr, "Cannot allocate space for tape buffer\n");
10132022Spc 		done(1);
10232022Spc 	}
10332022Spc 	tbfsize = size;
10432022Spc }
10532022Spc 
10632022Spc /*
10732022Spc  * Verify that the tape drive can be accessed and
10832022Spc  * that it actually is a dump tape.
10932022Spc  */
setup()11032022Spc setup()
11132022Spc {
11232022Spc 	int i, j, *ip;
11332022Spc 	struct stat stbuf;
11432022Spc 	extern char *ctime();
11532022Spc 	extern int xtrmap(), xtrmapskip();
11632022Spc 
11732022Spc 	vprintf(stdout, "Verify tape and initialize maps\n");
11832022Spc #ifdef RRESTORE
11932022Spc 	if ((mt = rmtopen(magtape, 0)) < 0)
12032022Spc #else
12132022Spc 	if (pipein)
12232022Spc 		mt = 0;
12332022Spc 	else if ((mt = open(magtape, 0)) < 0)
12432022Spc #endif
12532022Spc 	{
12632022Spc 		perror(magtape);
12732022Spc 		done(1);
12832022Spc 	}
12932022Spc 	volno = 1;
13032022Spc 	setdumpnum();
13132022Spc 	flsht();
13232022Spc 	if (!pipein && !bflag)
13332022Spc 		findtapeblksize();
13432022Spc 	if (gethead(&spcl) == FAIL) {
13532022Spc 		bct--; /* push back this block */
13632022Spc 		cvtflag++;
13732022Spc 		if (gethead(&spcl) == FAIL) {
13832022Spc 			fprintf(stderr, "Tape is not a dump tape\n");
13932022Spc 			done(1);
14032022Spc 		}
14132022Spc 		fprintf(stderr, "Converting to new file system format.\n");
14232022Spc 	}
14332022Spc 	if (pipein) {
14432022Spc 		endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
14532022Spc 		endoftapemark.s_spcl.c_type = TS_END;
14632022Spc 		ip = (int *)&endoftapemark;
14732022Spc 		j = sizeof(union u_spcl) / sizeof(int);
14832022Spc 		i = 0;
14932022Spc 		do
15032022Spc 			i += *ip++;
15132022Spc 		while (--j);
15232022Spc 		endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
15332022Spc 	}
15432025Spc 	if (vflag || command == 't')
15532025Spc 		printdumpinfo();
15632022Spc 	dumptime = spcl.c_ddate;
15732022Spc 	dumpdate = spcl.c_date;
15832022Spc 	if (stat(".", &stbuf) < 0) {
15932022Spc 		perror("cannot stat .");
16032022Spc 		done(1);
16132022Spc 	}
16232022Spc 	if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
16332022Spc 		fssize = stbuf.st_blksize;
16432022Spc 	if (((fssize - 1) & fssize) != 0) {
16532022Spc 		fprintf(stderr, "bad block size %d\n", fssize);
16632022Spc 		done(1);
16732022Spc 	}
16832022Spc 	if (checkvol(&spcl, (long)1) == FAIL) {
16932022Spc 		fprintf(stderr, "Tape is not volume 1 of the dump\n");
17032022Spc 		done(1);
17132022Spc 	}
17232022Spc 	if (readhdr(&spcl) == FAIL)
17332022Spc 		panic("no header after volume mark!\n");
17432025Spc 	findinode(&spcl);
17532022Spc 	if (checktype(&spcl, TS_CLRI) == FAIL) {
17632022Spc 		fprintf(stderr, "Cannot find file removal list\n");
17732022Spc 		done(1);
17832022Spc 	}
17932022Spc 	maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
18032022Spc 	dprintf(stdout, "maxino = %d\n", maxino);
18132022Spc 	map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
18232022Spc 	if (map == (char *)NIL)
18332022Spc 		panic("no memory for file removal list\n");
18432022Spc 	clrimap = map;
18532022Spc 	curfile.action = USING;
18632022Spc 	getfile(xtrmap, xtrmapskip);
18732022Spc 	if (checktype(&spcl, TS_BITS) == FAIL) {
18832022Spc 		fprintf(stderr, "Cannot find file dump list\n");
18932022Spc 		done(1);
19032022Spc 	}
19132022Spc 	map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
19232022Spc 	if (map == (char *)NULL)
19332022Spc 		panic("no memory for file dump list\n");
19432022Spc 	dumpmap = map;
19532022Spc 	curfile.action = USING;
19632022Spc 	getfile(xtrmap, xtrmapskip);
19732022Spc }
19832022Spc 
19932022Spc /*
20032022Spc  * Prompt user to load a new dump volume.
20132022Spc  * "Nextvol" is the next suggested volume to use.
20232022Spc  * This suggested volume is enforced when doing full
20332022Spc  * or incremental restores, but can be overrridden by
20432022Spc  * the user when only extracting a subset of the files.
20532022Spc  */
getvol(nextvol)20632022Spc getvol(nextvol)
20732022Spc 	long nextvol;
20832022Spc {
20932022Spc 	long newvol;
21032022Spc 	long savecnt, i;
21132022Spc 	union u_spcl tmpspcl;
21232022Spc #	define tmpbuf tmpspcl.s_spcl
21332025Spc 	char buf[TP_BSIZE];
21432022Spc 
21532022Spc 	if (nextvol == 1) {
21632022Spc 		tapesread = 0;
21732022Spc 		gettingfile = 0;
21832022Spc 	}
21932022Spc 	if (pipein) {
22032022Spc 		if (nextvol != 1)
22132022Spc 			panic("Changing volumes on pipe input?\n");
22232022Spc 		if (volno == 1)
22332022Spc 			return;
22432022Spc 		goto gethdr;
22532022Spc 	}
22632022Spc 	savecnt = blksread;
22732022Spc again:
22832022Spc 	if (pipein)
22932022Spc 		done(1); /* pipes do not get a second chance */
23032022Spc 	if (command == 'R' || command == 'r' || curfile.action != SKIP)
23132022Spc 		newvol = nextvol;
23232022Spc 	else
23332022Spc 		newvol = 0;
23432022Spc 	while (newvol <= 0) {
23532022Spc 		if (tapesread == 0) {
23632022Spc 			fprintf(stderr, "%s%s%s%s%s",
23732022Spc 			    "You have not read any tapes yet.\n",
23832022Spc 			    "Unless you know which volume your",
23932022Spc 			    " file(s) are on you should start\n",
24032022Spc 			    "with the last volume and work",
24132022Spc 			    " towards towards the first.\n");
24232022Spc 		} else {
24332022Spc 			fprintf(stderr, "You have read volumes");
24432022Spc 			strcpy(tbf, ": ");
24532022Spc 			for (i = 1; i < 32; i++)
24632022Spc 				if (tapesread & (1 << i)) {
24732022Spc 					fprintf(stderr, "%s%d", tbf, i);
24832022Spc 					strcpy(tbf, ", ");
24932022Spc 				}
25032022Spc 			fprintf(stderr, "\n");
25132022Spc 		}
25232022Spc 		do	{
25332022Spc 			fprintf(stderr, "Specify next volume #: ");
25432022Spc 			(void) fflush(stderr);
25532022Spc 			(void) fgets(tbf, BUFSIZ, terminal);
25632022Spc 		} while (!feof(terminal) && tbf[0] == '\n');
25732022Spc 		if (feof(terminal))
25832022Spc 			done(1);
25932022Spc 		newvol = atoi(tbf);
26032022Spc 		if (newvol <= 0) {
26132022Spc 			fprintf(stderr,
26232022Spc 			    "Volume numbers are positive numerics\n");
26332022Spc 		}
26432022Spc 	}
26532022Spc 	if (newvol == volno) {
26632022Spc 		tapesread |= 1 << volno;
26732022Spc 		return;
26832022Spc 	}
26932022Spc 	closemt();
27032022Spc 	fprintf(stderr, "Mount tape volume %d\n", newvol);
27132022Spc 	fprintf(stderr, "then enter tape name (default: %s) ", magtape);
27232022Spc 	(void) fflush(stderr);
27332022Spc 	(void) fgets(tbf, BUFSIZ, terminal);
27432022Spc 	if (feof(terminal))
27532022Spc 		done(1);
27632022Spc 	if (tbf[0] != '\n') {
27732022Spc 		(void) strcpy(magtape, tbf);
27832022Spc 		magtape[strlen(magtape) - 1] = '\0';
27932022Spc 	}
28032022Spc #ifdef RRESTORE
28132022Spc 	if ((mt = rmtopen(magtape, 0)) == -1)
28232022Spc #else
28332022Spc 	if ((mt = open(magtape, 0)) == -1)
28432022Spc #endif
28532022Spc 	{
28632022Spc 		fprintf(stderr, "Cannot open %s\n", magtape);
28732022Spc 		volno = -1;
28832022Spc 		goto again;
28932022Spc 	}
29032022Spc gethdr:
29132022Spc 	volno = newvol;
29232022Spc 	setdumpnum();
29332022Spc 	flsht();
29432022Spc 	if (readhdr(&tmpbuf) == FAIL) {
29532022Spc 		fprintf(stderr, "tape is not dump tape\n");
29632022Spc 		volno = 0;
29732022Spc 		goto again;
29832022Spc 	}
29932022Spc 	if (checkvol(&tmpbuf, volno) == FAIL) {
30032022Spc 		fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
30132022Spc 		volno = 0;
30232022Spc 		goto again;
30332022Spc 	}
30432022Spc 	if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
30532022Spc 		fprintf(stderr, "Wrong dump date\n\tgot: %s",
30632022Spc 			ctime(&tmpbuf.c_date));
30732022Spc 		fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
30832022Spc 		volno = 0;
30932022Spc 		goto again;
31032022Spc 	}
31132022Spc 	tapesread |= 1 << volno;
31232022Spc 	blksread = savecnt;
31332022Spc 	if (curfile.action == USING) {
31432022Spc 		if (volno == 1)
31532022Spc 			panic("active file into volume 1\n");
31632022Spc 		return;
31732022Spc 	}
31832025Spc 	/*
31932025Spc 	 * Skip up to the beginning of the next record
32032025Spc 	 */
32132025Spc 	if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
32232025Spc 		for (i = tmpbuf.c_count; i > 0; i--)
32332025Spc 			readtape(buf);
32432022Spc 	(void) gethead(&spcl);
32532025Spc 	findinode(&spcl);
32632022Spc 	if (gettingfile) {
32732022Spc 		gettingfile = 0;
32832022Spc 		longjmp(restart, 1);
32932022Spc 	}
33032022Spc }
33132022Spc 
33232022Spc /*
33332022Spc  * handle multiple dumps per tape by skipping forward to the
33432022Spc  * appropriate one.
33532022Spc  */
setdumpnum()33632022Spc setdumpnum()
33732022Spc {
33832022Spc 	struct mtop tcom;
33932022Spc 
34032022Spc 	if (dumpnum == 1 || volno != 1)
34132022Spc 		return;
34232022Spc 	if (pipein) {
34332022Spc 		fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
34432022Spc 		done(1);
34532022Spc 	}
34632022Spc 	tcom.mt_op = MTFSF;
34732022Spc 	tcom.mt_count = dumpnum - 1;
34832022Spc #ifdef RRESTORE
34932022Spc 	rmtioctl(MTFSF, dumpnum - 1);
35032022Spc #else
35132022Spc 	if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
35232022Spc 		perror("ioctl MTFSF");
35332022Spc #endif
35432022Spc }
35532022Spc 
printdumpinfo()35632025Spc printdumpinfo()
35732025Spc {
35832025Spc 
35932025Spc 	fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
36032025Spc 	fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
36132025Spc 	if (spcl.c_host[0] == '\0')
36232025Spc 		return;
36332025Spc 	fprintf(stderr, "Level %d dump of %s on %s:%s\n",
36432025Spc 		spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
365*32048Spc 	printf("Volume %d of the dump, starting at inode %d\n",
366*32048Spc 			spcl.c_volume, spcl.c_inumber);
36732025Spc 	fprintf(stderr, "Label: %s\n", spcl.c_label);
36832025Spc }
36932025Spc 
extractfile(name)37032022Spc extractfile(name)
37132022Spc 	char *name;
37232022Spc {
37332022Spc 	int mode;
37432022Spc 	time_t timep[2];
37532022Spc 	struct entry *ep;
37632022Spc 	extern int xtrlnkfile(), xtrlnkskip();
37732022Spc 	extern int xtrfile(), xtrskip();
37832022Spc 
37932022Spc 	curfile.name = name;
38032022Spc 	curfile.action = USING;
38132022Spc 	timep[0] = curfile.dip->di_atime;
38232022Spc 	timep[1] = curfile.dip->di_mtime;
38332022Spc 	mode = curfile.dip->di_mode;
38432022Spc 	switch (mode & IFMT) {
38532022Spc 
38632022Spc 	default:
38732022Spc 		fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
38832022Spc 		skipfile();
38932022Spc 		return (FAIL);
39032022Spc 
39132022Spc 	case IFSOCK:
39232022Spc 		vprintf(stdout, "skipped socket %s\n", name);
39332022Spc 		skipfile();
39432022Spc 		return (GOOD);
39532022Spc 
39632022Spc 	case IFDIR:
39732022Spc 		if (mflag) {
39832022Spc 			ep = lookupname(name);
39932022Spc 			if (ep == NIL || ep->e_flags & EXTRACT)
40032022Spc 				panic("unextracted directory %s\n", name);
40132022Spc 			skipfile();
40232022Spc 			return (GOOD);
40332022Spc 		}
40432022Spc 		vprintf(stdout, "extract file %s\n", name);
40532022Spc 		return (genliteraldir(name, curfile.ino));
40632022Spc 
40732022Spc 	case IFLNK:
40832022Spc 		lnkbuf[0] = '\0';
40932022Spc 		pathlen = 0;
41032022Spc 		getfile(xtrlnkfile, xtrlnkskip);
41132022Spc 		if (pathlen == 0) {
41232022Spc 			vprintf(stdout,
41332022Spc 			    "%s: zero length symbolic link (ignored)\n", name);
41432022Spc 			return (GOOD);
41532022Spc 		}
41632022Spc 		return (linkit(lnkbuf, name, SYMLINK));
41732022Spc 
41832022Spc 	case IFCHR:
41932022Spc 	case IFBLK:
42032022Spc 		vprintf(stdout, "extract special file %s\n", name);
42132022Spc 		if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
42232022Spc 			fprintf(stderr, "%s: ", name);
42332022Spc 			(void) fflush(stderr);
42432022Spc 			perror("cannot create special file");
42532022Spc 			skipfile();
42632022Spc 			return (FAIL);
42732022Spc 		}
42832022Spc 		(void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
42932022Spc 		(void) chmod(name, mode);
43032022Spc 		skipfile();
43132022Spc 		utime(name, timep);
43232022Spc 		return (GOOD);
43332022Spc 
43432022Spc 	case IFREG:
43532022Spc 		vprintf(stdout, "extract file %s\n", name);
43632022Spc 		if ((ofile = creat(name, 0666)) < 0) {
43732022Spc 			fprintf(stderr, "%s: ", name);
43832022Spc 			(void) fflush(stderr);
43932022Spc 			perror("cannot create file");
44032022Spc 			skipfile();
44132022Spc 			return (FAIL);
44232022Spc 		}
44332022Spc 		(void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
44432022Spc 		(void) fchmod(ofile, mode);
44532022Spc 		getfile(xtrfile, xtrskip);
44632022Spc 		(void) close(ofile);
44732022Spc 		utime(name, timep);
44832022Spc 		return (GOOD);
44932022Spc 	}
45032022Spc 	/* NOTREACHED */
45132022Spc }
45232022Spc 
45332022Spc /*
45432022Spc  * skip over bit maps on the tape
45532022Spc  */
skipmaps()45632022Spc skipmaps()
45732022Spc {
45832022Spc 
45932022Spc 	while (checktype(&spcl, TS_CLRI) == GOOD ||
46032022Spc 	       checktype(&spcl, TS_BITS) == GOOD)
46132022Spc 		skipfile();
46232022Spc }
46332022Spc 
46432022Spc /*
46532022Spc  * skip over a file on the tape
46632022Spc  */
skipfile()46732022Spc skipfile()
46832022Spc {
46932022Spc 	extern int null();
47032022Spc 
47132022Spc 	curfile.action = SKIP;
47232022Spc 	getfile(null, null);
47332022Spc }
47432022Spc 
47532022Spc /*
47632022Spc  * Do the file extraction, calling the supplied functions
47732022Spc  * with the blocks
47832022Spc  */
47932022Spc getfile(f1, f2)
48032022Spc 	int	(*f2)(), (*f1)();
48132022Spc {
48232022Spc 	register int i;
48332022Spc 	int curblk = 0;
48432022Spc 	off_t size = spcl.c_dinode.di_size;
48532022Spc 	static char clearedbuf[MAXBSIZE];
48632022Spc 	char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
48732022Spc 	char junk[TP_BSIZE];
48832022Spc 
48932022Spc 	if (checktype(&spcl, TS_END) == GOOD)
49032022Spc 		panic("ran off end of tape\n");
49132022Spc 	if (ishead(&spcl) == FAIL)
49232022Spc 		panic("not at beginning of a file\n");
49332022Spc 	if (!gettingfile && setjmp(restart) != 0)
49432022Spc 		return;
49532022Spc 	gettingfile++;
49632022Spc loop:
49732022Spc 	for (i = 0; i < spcl.c_count; i++) {
49832022Spc 		if (spcl.c_addr[i]) {
49932022Spc 			readtape(&buf[curblk++][0]);
50032022Spc 			if (curblk == fssize / TP_BSIZE) {
50132022Spc 				(*f1)(buf, size > TP_BSIZE ?
50232022Spc 				     (long) (fssize) :
50332022Spc 				     (curblk - 1) * TP_BSIZE + size);
50432022Spc 				curblk = 0;
50532022Spc 			}
50632022Spc 		} else {
50732022Spc 			if (curblk > 0) {
50832022Spc 				(*f1)(buf, size > TP_BSIZE ?
50932022Spc 				     (long) (curblk * TP_BSIZE) :
51032022Spc 				     (curblk - 1) * TP_BSIZE + size);
51132022Spc 				curblk = 0;
51232022Spc 			}
51332022Spc 			(*f2)(clearedbuf, size > TP_BSIZE ?
51432022Spc 				(long) TP_BSIZE : size);
51532022Spc 		}
51632022Spc 		if ((size -= TP_BSIZE) <= 0) {
51732022Spc 			for (i++; i < spcl.c_count; i++)
51832022Spc 				if (spcl.c_addr[i])
51932022Spc 					readtape(junk);
52032022Spc 			break;
52132022Spc 		}
52232022Spc 	}
52332022Spc 	if (readhdr(&spcl) == GOOD && size > 0) {
52432022Spc 		if (checktype(&spcl, TS_ADDR) == GOOD)
52532022Spc 			goto loop;
52632022Spc 		dprintf(stdout, "Missing address (header) block for %s\n",
52732022Spc 			curfile.name);
52832022Spc 	}
52932022Spc 	if (curblk > 0)
53032022Spc 		(*f1)(buf, (curblk * TP_BSIZE) + size);
53132025Spc 	findinode(&spcl);
53232022Spc 	gettingfile = 0;
53332022Spc }
53432022Spc 
53532022Spc /*
53632022Spc  * The next routines are called during file extraction to
53732022Spc  * put the data into the right form and place.
53832022Spc  */
xtrfile(buf,size)53932022Spc xtrfile(buf, size)
54032022Spc 	char	*buf;
54132022Spc 	long	size;
54232022Spc {
54332022Spc 
54432022Spc 	if (write(ofile, buf, (int) size) == -1) {
54532022Spc 		fprintf(stderr, "write error extracting inode %d, name %s\n",
54632022Spc 			curfile.ino, curfile.name);
54732022Spc 		perror("write");
54832022Spc 		done(1);
54932022Spc 	}
55032022Spc }
55132022Spc 
xtrskip(buf,size)55232022Spc xtrskip(buf, size)
55332022Spc 	char *buf;
55432022Spc 	long size;
55532022Spc {
55632022Spc 
55732022Spc #ifdef lint
55832022Spc 	buf = buf;
55932022Spc #endif
56032022Spc 	if (lseek(ofile, size, 1) == (long)-1) {
56132022Spc 		fprintf(stderr, "seek error extracting inode %d, name %s\n",
56232022Spc 			curfile.ino, curfile.name);
56332022Spc 		perror("lseek");
56432022Spc 		done(1);
56532022Spc 	}
56632022Spc }
56732022Spc 
xtrlnkfile(buf,size)56832022Spc xtrlnkfile(buf, size)
56932022Spc 	char	*buf;
57032022Spc 	long	size;
57132022Spc {
57232022Spc 
57332022Spc 	pathlen += size;
57432022Spc 	if (pathlen > MAXPATHLEN) {
57532022Spc 		fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
57632022Spc 		    curfile.name, lnkbuf, buf, pathlen);
57732022Spc 		done(1);
57832022Spc 	}
57932022Spc 	(void) strcat(lnkbuf, buf);
58032022Spc }
58132022Spc 
xtrlnkskip(buf,size)58232022Spc xtrlnkskip(buf, size)
58332022Spc 	char *buf;
58432022Spc 	long size;
58532022Spc {
58632022Spc 
58732022Spc #ifdef lint
58832022Spc 	buf = buf, size = size;
58932022Spc #endif
59032022Spc 	fprintf(stderr, "unallocated block in symbolic link %s\n",
59132022Spc 		curfile.name);
59232022Spc 	done(1);
59332022Spc }
59432022Spc 
xtrmap(buf,size)59532022Spc xtrmap(buf, size)
59632022Spc 	char	*buf;
59732022Spc 	long	size;
59832022Spc {
59932022Spc 
60032022Spc 	bcopy(buf, map, size);
60132022Spc 	map += size;
60232022Spc }
60332022Spc 
xtrmapskip(buf,size)60432022Spc xtrmapskip(buf, size)
60532022Spc 	char *buf;
60632022Spc 	long size;
60732022Spc {
60832022Spc 
60932022Spc #ifdef lint
61032022Spc 	buf = buf;
61132022Spc #endif
61232022Spc 	panic("hole in map\n");
61332022Spc 	map += size;
61432022Spc }
61532022Spc 
null()61632022Spc null() {;}
61732022Spc 
61832022Spc /*
61932022Spc  * Do the tape i/o, dealing with volume changes
62032022Spc  * etc..
62132022Spc  */
readtape(b)62232022Spc readtape(b)
62332022Spc 	char *b;
62432022Spc {
62532022Spc 	register long i;
62632022Spc 	long rd, newvol;
62732022Spc 	int cnt;
62832022Spc 
62932022Spc 	if (bct < ntrec) {
63032022Spc 		bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
63132022Spc 		blksread++;
63232022Spc 		return;
63332022Spc 	}
63432022Spc 	for (i = 0; i < ntrec; i++)
63532022Spc 		((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
63632022Spc 	bct = 0;
63732022Spc 	cnt = ntrec*TP_BSIZE;
63832022Spc 	rd = 0;
63932022Spc getmore:
64032022Spc #ifdef RRESTORE
64132022Spc 	i = rmtread(&tbf[rd], cnt);
64232022Spc #else
64332022Spc 	i = read(mt, &tbf[rd], cnt);
64432022Spc #endif
64532022Spc 	if (i > 0 && i != ntrec*TP_BSIZE) {
64632022Spc 		if (pipein) {
64732022Spc 			rd += i;
64832022Spc 			cnt -= i;
64932022Spc 			if (cnt > 0)
65032022Spc 				goto getmore;
65132022Spc 			i = rd;
65232022Spc 		} else {
65332022Spc 			if (i % TP_BSIZE != 0)
65432022Spc 				panic("partial block read: %d should be %d\n",
65532022Spc 					i, ntrec * TP_BSIZE);
65632022Spc 			bcopy((char *)&endoftapemark, &tbf[i],
65732022Spc 				(long)TP_BSIZE);
65832022Spc 		}
65932022Spc 	}
66032022Spc 	if (i < 0) {
66132022Spc 		fprintf(stderr, "Tape read error while ");
66232022Spc 		switch (curfile.action) {
66332022Spc 		default:
66432022Spc 			fprintf(stderr, "trying to set up tape\n");
66532022Spc 			break;
66632022Spc 		case UNKNOWN:
66732022Spc 			fprintf(stderr, "trying to resyncronize\n");
66832022Spc 			break;
66932022Spc 		case USING:
67032022Spc 			fprintf(stderr, "restoring %s\n", curfile.name);
67132022Spc 			break;
67232022Spc 		case SKIP:
67332022Spc 			fprintf(stderr, "skipping over inode %d\n",
67432022Spc 				curfile.ino);
67532022Spc 			break;
67632022Spc 		}
67732022Spc 		if (!yflag && !reply("continue"))
67832022Spc 			done(1);
67932022Spc 		i = ntrec*TP_BSIZE;
68032022Spc 		bzero(tbf, i);
68132022Spc #ifdef RRESTORE
68232022Spc 		if (rmtseek(i, 1) < 0)
68332022Spc #else
68432022Spc 		if (lseek(mt, i, 1) == (long)-1)
68532022Spc #endif
68632022Spc 		{
68732022Spc 			perror("continuation failed");
68832022Spc 			done(1);
68932022Spc 		}
69032022Spc 	}
69132022Spc 	if (i == 0) {
69232022Spc 		if (!pipein) {
69332022Spc 			newvol = volno + 1;
69432022Spc 			volno = 0;
69532022Spc 			getvol(newvol);
69632022Spc 			readtape(b);
69732022Spc 			return;
69832022Spc 		}
69932022Spc 		if (rd % TP_BSIZE != 0)
70032022Spc 			panic("partial block read: %d should be %d\n",
70132022Spc 				rd, ntrec * TP_BSIZE);
70232022Spc 		bcopy((char *)&endoftapemark, &tbf[rd], (long)TP_BSIZE);
70332022Spc 	}
70432022Spc 	bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
70532022Spc 	blksread++;
70632022Spc }
70732022Spc 
findtapeblksize()70832022Spc findtapeblksize()
70932022Spc {
71032022Spc 	register long i;
71132022Spc 
71232022Spc 	for (i = 0; i < ntrec; i++)
71332022Spc 		((struct s_spcl *)&tbf[i * TP_BSIZE])->c_magic = 0;
71432022Spc 	bct = 0;
71532022Spc #ifdef RRESTORE
71632022Spc 	i = rmtread(tbf, ntrec * TP_BSIZE);
71732022Spc #else
71832022Spc 	i = read(mt, tbf, ntrec * TP_BSIZE);
71932022Spc #endif
72032022Spc 	if (i <= 0) {
72132022Spc 		perror("Tape read error");
72232022Spc 		done(1);
72332022Spc 	}
72432022Spc 	if (i % TP_BSIZE != 0) {
72532022Spc 		fprintf(stderr, "Tape block size (%d) %s (%d)\n",
72632022Spc 			i, "is not a multiple of dump block size", TP_BSIZE);
72732022Spc 		done(1);
72832022Spc 	}
72932022Spc 	ntrec = i / TP_BSIZE;
73032022Spc 	vprintf(stdout, "Tape block size is %d\n", ntrec);
73132022Spc }
73232022Spc 
flsht()73332022Spc flsht()
73432022Spc {
73532022Spc 
73632022Spc 	bct = ntrec+1;
73732022Spc }
73832022Spc 
closemt()73932022Spc closemt()
74032022Spc {
74132022Spc 	if (mt < 0)
74232022Spc 		return;
74332022Spc #ifdef RRESTORE
74432022Spc 	rmtclose();
74532022Spc #else
74632022Spc 	(void) close(mt);
74732022Spc #endif
74832022Spc }
74932022Spc 
75032022Spc checkvol(b, t)
75132022Spc 	struct s_spcl *b;
75232022Spc 	long t;
75332022Spc {
75432022Spc 
75532022Spc 	if (b->c_volume != t)
75632022Spc 		return(FAIL);
75732022Spc 	return(GOOD);
75832022Spc }
75932022Spc 
76032022Spc readhdr(b)
76132022Spc 	struct s_spcl *b;
76232022Spc {
76332022Spc 
76432022Spc 	if (gethead(b) == FAIL) {
76532022Spc 		dprintf(stdout, "readhdr fails at %d blocks\n", blksread);
76632022Spc 		return(FAIL);
76732022Spc 	}
76832022Spc 	return(GOOD);
76932022Spc }
77032022Spc 
77132022Spc /*
77232022Spc  * read the tape into buf, then return whether or
77332022Spc  * or not it is a header block.
77432022Spc  */
77532022Spc gethead(buf)
77632022Spc 	struct s_spcl *buf;
77732022Spc {
77832022Spc 	long i, *j;
77932022Spc 	union u_ospcl {
78032022Spc 		char dummy[TP_BSIZE];
78132022Spc 		struct	s_ospcl {
78232022Spc 			long	c_type;
78332022Spc 			long	c_date;
78432022Spc 			long	c_ddate;
78532022Spc 			long	c_volume;
78632022Spc 			long	c_tapea;
78732022Spc 			u_short	c_inumber;
78832022Spc 			long	c_magic;
78932022Spc 			long	c_checksum;
79032022Spc 			struct odinode {
79132022Spc 				unsigned short odi_mode;
79232022Spc 				u_short	odi_nlink;
79332022Spc 				u_short	odi_uid;
79432022Spc 				u_short	odi_gid;
79532022Spc 				long	odi_size;
79632022Spc 				long	odi_rdev;
79732022Spc 				char	odi_addr[36];
79832022Spc 				long	odi_atime;
79932022Spc 				long	odi_mtime;
80032022Spc 				long	odi_ctime;
80132022Spc 			} c_dinode;
80232022Spc 			long	c_count;
80332022Spc 			char	c_addr[256];
80432022Spc 		} s_ospcl;
80532022Spc 	} u_ospcl;
80632022Spc 
80732022Spc 	if (!cvtflag) {
80832022Spc 		readtape((char *)buf);
80932022Spc 		if (buf->c_magic != NFS_MAGIC) {
81032022Spc 			if (swabl(buf->c_magic) != NFS_MAGIC)
81132022Spc 				return (FAIL);
81232022Spc 			if (!Bcvt) {
81332022Spc 				vprintf(stdout, "Note: Doing Byte swapping\n");
81432022Spc 				Bcvt = 1;
81532022Spc 			}
81632022Spc 		}
81732022Spc 		if (checksum((int *)buf) == FAIL)
81832022Spc 			return (FAIL);
81932022Spc 		if (Bcvt)
82032022Spc 			swabst("8l4s31l", (char *)buf);
82132022Spc 		goto good;
82232022Spc 	}
82332022Spc 	readtape((char *)(&u_ospcl.s_ospcl));
82432022Spc 	bzero((char *)buf, (long)TP_BSIZE);
82532022Spc 	buf->c_type = u_ospcl.s_ospcl.c_type;
82632022Spc 	buf->c_date = u_ospcl.s_ospcl.c_date;
82732022Spc 	buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
82832022Spc 	buf->c_volume = u_ospcl.s_ospcl.c_volume;
82932022Spc 	buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
83032022Spc 	buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
83132022Spc 	buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
83232022Spc 	buf->c_magic = u_ospcl.s_ospcl.c_magic;
83332022Spc 	buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
83432022Spc 	buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
83532022Spc 	buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
83632022Spc 	buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
83732022Spc 	buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
83832022Spc 	buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
83932022Spc 	buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
84032022Spc 	buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
84132022Spc 	buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
84232022Spc 	buf->c_count = u_ospcl.s_ospcl.c_count;
84332022Spc 	bcopy(u_ospcl.s_ospcl.c_addr, buf->c_addr, (long)256);
84432022Spc 	if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
84532022Spc 	    checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
84632022Spc 		return(FAIL);
84732022Spc 	buf->c_magic = NFS_MAGIC;
84832022Spc 
84932022Spc good:
85032022Spc 	j = buf->c_dinode.di_ic.ic_size.val;
85132022Spc 	i = j[1];
85232022Spc 	if (buf->c_dinode.di_size == 0 &&
85332022Spc 	    (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt==0) {
85432022Spc 		if (*j || i) {
85532022Spc 			printf("Note: Doing Quad swapping\n");
85632022Spc 			Qcvt = 1;
85732022Spc 		}
85832022Spc 	}
85932022Spc 	if (Qcvt) {
86032022Spc 		j[1] = *j; *j = i;
86132022Spc 	}
86232022Spc 	switch (buf->c_type) {
86332022Spc 
86432022Spc 	case TS_CLRI:
86532022Spc 	case TS_BITS:
86632022Spc 		/*
86732022Spc 		 * Have to patch up missing information in bit map headers
86832022Spc 		 */
86932022Spc 		buf->c_inumber = 0;
87032022Spc 		buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
87132022Spc 		for (i = 0; i < buf->c_count; i++)
87232022Spc 			buf->c_addr[i]++;
87332022Spc 		break;
87432022Spc 
87532022Spc 	case TS_TAPE:
87632022Spc 	case TS_END:
87732022Spc 		buf->c_inumber = 0;
87832022Spc 		break;
87932022Spc 
88032022Spc 	case TS_INODE:
88132022Spc 	case TS_ADDR:
88232022Spc 		break;
88332022Spc 
88432022Spc 	default:
88532022Spc 		panic("gethead: unknown inode type %d\n", buf->c_type);
88632022Spc 		break;
88732022Spc 	}
88832022Spc 	if (dflag)
88932022Spc 		accthdr(buf);
89032022Spc 	return(GOOD);
89132022Spc }
89232022Spc 
89332022Spc /*
89432022Spc  * Check that a header is where it belongs and predict the next header
89532022Spc  */
89632022Spc accthdr(header)
89732022Spc 	struct s_spcl *header;
89832022Spc {
89932022Spc 	static ino_t previno = 0x7fffffff;
90032022Spc 	static int prevtype;
90132022Spc 	static long predict;
90232022Spc 	long blks, i;
90332022Spc 
90432022Spc 	if (header->c_type == TS_TAPE) {
90532022Spc 		fprintf(stderr, "Volume header\n");
90632025Spc 		previno = 0x7fffffff;
90732022Spc 		return;
90832022Spc 	}
90932022Spc 	if (previno == 0x7fffffff)
91032022Spc 		goto newcalc;
91132022Spc 	switch (prevtype) {
91232022Spc 	case TS_BITS:
91332022Spc 		fprintf(stderr, "Dump mask header");
91432022Spc 		break;
91532022Spc 	case TS_CLRI:
91632022Spc 		fprintf(stderr, "Remove mask header");
91732022Spc 		break;
91832022Spc 	case TS_INODE:
91932022Spc 		fprintf(stderr, "File header, ino %d", previno);
92032022Spc 		break;
92132022Spc 	case TS_ADDR:
92232022Spc 		fprintf(stderr, "File continuation header, ino %d", previno);
92332022Spc 		break;
92432022Spc 	case TS_END:
92532022Spc 		fprintf(stderr, "End of tape header");
92632022Spc 		break;
92732022Spc 	}
92832022Spc 	if (predict != blksread - 1)
92932022Spc 		fprintf(stderr, "; predicted %d blocks, got %d blocks",
93032022Spc 			predict, blksread - 1);
93132022Spc 	fprintf(stderr, "\n");
93232022Spc newcalc:
93332022Spc 	blks = 0;
93432022Spc 	if (header->c_type != TS_END)
93532022Spc 		for (i = 0; i < header->c_count; i++)
93632022Spc 			if (header->c_addr[i] != 0)
93732022Spc 				blks++;
93832022Spc 	predict = blks;
93932022Spc 	blksread = 0;
94032022Spc 	prevtype = header->c_type;
94132022Spc 	previno = header->c_inumber;
94232022Spc }
94332022Spc 
94432022Spc /*
94532022Spc  * Find an inode header.
94632022Spc  * Complain if had to skip, and complain is set.
94732022Spc  */
94832025Spc findinode(header)
94932022Spc 	struct s_spcl *header;
95032022Spc {
95132022Spc 	static long skipcnt = 0;
95232025Spc 	long i;
95332025Spc 	char buf[TP_BSIZE];
95432022Spc 
95532022Spc 	curfile.name = "<name unknown>";
95632022Spc 	curfile.action = UNKNOWN;
95732022Spc 	curfile.dip = (struct dinode *)NIL;
95832022Spc 	curfile.ino = 0;
95932022Spc 	if (ishead(header) == FAIL) {
96032022Spc 		skipcnt++;
96132025Spc 		while (gethead(header) == FAIL || header->c_date != dumpdate)
96232022Spc 			skipcnt++;
96332022Spc 	}
96432022Spc 	for (;;) {
96532025Spc 		if (checktype(header, TS_ADDR) == GOOD) {
96632025Spc 			/*
96732025Spc 			 * Skip up to the beginning of the next record
96832025Spc 			 */
96932025Spc 			for (i = 0; i < header->c_count; i++)
97032025Spc 				if (header->c_addr[i])
97132025Spc 					readtape(buf);
97232025Spc 			(void) gethead(header);
97332025Spc 			continue;
97432025Spc 		}
97532022Spc 		if (checktype(header, TS_INODE) == GOOD) {
97632022Spc 			curfile.dip = &header->c_dinode;
97732022Spc 			curfile.ino = header->c_inumber;
97832022Spc 			break;
97932022Spc 		}
98032022Spc 		if (checktype(header, TS_END) == GOOD) {
98132022Spc 			curfile.ino = maxino;
98232022Spc 			break;
98332022Spc 		}
98432022Spc 		if (checktype(header, TS_CLRI) == GOOD) {
98532022Spc 			curfile.name = "<file removal list>";
98632022Spc 			break;
98732022Spc 		}
98832022Spc 		if (checktype(header, TS_BITS) == GOOD) {
98932022Spc 			curfile.name = "<file dump list>";
99032022Spc 			break;
99132022Spc 		}
99232022Spc 		while (gethead(header) == FAIL)
99332022Spc 			skipcnt++;
99432022Spc 	}
99532025Spc 	if (skipcnt > 0)
99632022Spc 		fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
99732022Spc 	skipcnt = 0;
99832022Spc }
99932022Spc 
100032022Spc /*
100132022Spc  * return whether or not the buffer contains a header block
100232022Spc  */
100332022Spc ishead(buf)
100432022Spc 	struct s_spcl *buf;
100532022Spc {
100632022Spc 
100732022Spc 	if (buf->c_magic != NFS_MAGIC)
100832022Spc 		return(FAIL);
100932022Spc 	return(GOOD);
101032022Spc }
101132022Spc 
101232022Spc checktype(b, t)
101332022Spc 	struct s_spcl *b;
101432022Spc 	int	t;
101532022Spc {
101632022Spc 
101732022Spc 	if (b->c_type != t)
101832022Spc 		return(FAIL);
101932022Spc 	return(GOOD);
102032022Spc }
102132022Spc 
checksum(b)102232022Spc checksum(b)
102332022Spc 	register int *b;
102432022Spc {
102532022Spc 	register int i, j;
102632022Spc 
102732022Spc 	j = sizeof(union u_spcl) / sizeof(int);
102832022Spc 	i = 0;
102932022Spc 	if(!Bcvt) {
103032022Spc 		do
103132022Spc 			i += *b++;
103232022Spc 		while (--j);
103332022Spc 	} else {
103432022Spc 		/* What happens if we want to read restore tapes
103532022Spc 			for a 16bit int machine??? */
103632022Spc 		do
103732022Spc 			i += swabl(*b++);
103832022Spc 		while (--j);
103932022Spc 	}
104032022Spc 
104132022Spc 	if (i != CHECKSUM) {
104232022Spc 		fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
104332022Spc 			curfile.ino, curfile.name);
104432022Spc 		return(FAIL);
104532022Spc 	}
104632022Spc 	return(GOOD);
104732022Spc }
104832022Spc 
104932022Spc #ifdef RRESTORE
105032022Spc /* VARARGS1 */
msg(cp,a1,a2,a3)105132022Spc msg(cp, a1, a2, a3)
105232022Spc 	char *cp;
105332022Spc {
105432022Spc 
105532022Spc 	fprintf(stderr, cp, a1, a2, a3);
105632022Spc }
105732022Spc #endif RRESTORE
105832022Spc 
swabst(cp,sp)105932022Spc swabst(cp, sp)
106032022Spc register char *cp, *sp;
106132022Spc {
106232022Spc 	int n = 0;
106332022Spc 	char c;
106432022Spc 	while(*cp) {
106532022Spc 		switch (*cp) {
106632022Spc 		case '0': case '1': case '2': case '3': case '4':
106732022Spc 		case '5': case '6': case '7': case '8': case '9':
106832022Spc 			n = (n * 10) + (*cp++ - '0');
106932022Spc 			continue;
107032022Spc 
107132022Spc 		case 's': case 'w': case 'h':
107232022Spc 			c = sp[0]; sp[0] = sp[1]; sp[1] = c;
107332022Spc 			sp++;
107432022Spc 			break;
107532022Spc 
107632022Spc 		case 'l':
107732022Spc 			c = sp[0]; sp[0] = sp[3]; sp[3] = c;
107832022Spc 			c = sp[2]; sp[2] = sp[1]; sp[1] = c;
107932022Spc 			sp += 3;
108032022Spc 		}
108132022Spc 		sp++; /* Any other character, like 'b' counts as byte. */
108232022Spc 		if (n <= 1) {
108332022Spc 			n = 0; cp++;
108432022Spc 		} else
108532022Spc 			n--;
108632022Spc 	}
108732022Spc }
swabl(x)108832022Spc swabl(x) { unsigned long l = x; swabst("l", (char *)&l); return l; }
1089