xref: /original-bsd/local/ukc/restore/tape.c (revision a7ce809e)
19bf6c4e8Spc /*
29bf6c4e8Spc  * Copyright (c) 1983 Regents of the University of California.
39bf6c4e8Spc  * All rights reserved.  The Berkeley software License Agreement
49bf6c4e8Spc  * specifies the terms and conditions for redistribution.
59bf6c4e8Spc  */
69bf6c4e8Spc 
79bf6c4e8Spc #ifndef lint
87b006476Spc static char sccsid[] = "@(#)tape.c	5.10 (Berkeley) 1/28/87";
99bf6c4e8Spc #endif not lint
109bf6c4e8Spc 
119bf6c4e8Spc #include "restore.h"
129bf6c4e8Spc #include <protocols/dumprestore.h>
139bf6c4e8Spc #include <sys/ioctl.h>
149bf6c4e8Spc #include <sys/mtio.h>
159bf6c4e8Spc #include <sys/file.h>
169bf6c4e8Spc #include <setjmp.h>
179bf6c4e8Spc #include <sys/stat.h>
189bf6c4e8Spc 
199bf6c4e8Spc static long	fssize = MAXBSIZE;
209bf6c4e8Spc static int	mt = -1;
219bf6c4e8Spc static int	pipein = 0;
229bf6c4e8Spc static char	magtape[BUFSIZ];
239bf6c4e8Spc static int	bct;
249bf6c4e8Spc static char	*tbf;
259bf6c4e8Spc static union	u_spcl endoftapemark;
269bf6c4e8Spc static long	blksread;
279bf6c4e8Spc static long	tapesread;
289bf6c4e8Spc static jmp_buf	restart;
299bf6c4e8Spc static int	gettingfile = 0;	/* restart has a valid frame */
309bf6c4e8Spc 
319bf6c4e8Spc static int	ofile;
329bf6c4e8Spc static char	*map;
339bf6c4e8Spc static char	lnkbuf[MAXPATHLEN + 1];
349bf6c4e8Spc static int	pathlen;
359bf6c4e8Spc 
369bf6c4e8Spc int		Bcvt;		/* Swap Bytes (for CCI or sun) */
379bf6c4e8Spc static int	Qcvt;		/* Swap quads (for sun) */
389bf6c4e8Spc /*
399bf6c4e8Spc  * Set up an input source
409bf6c4e8Spc  */
setinput(source)419bf6c4e8Spc setinput(source)
429bf6c4e8Spc 	char *source;
439bf6c4e8Spc {
449bf6c4e8Spc #ifdef RRESTORE
459bf6c4e8Spc 	char *host, *tape;
469bf6c4e8Spc #endif RRESTORE
479bf6c4e8Spc 
489bf6c4e8Spc 	flsht();
499bf6c4e8Spc 	if (bflag)
509bf6c4e8Spc 		newtapebuf(ntrec);
519bf6c4e8Spc 	else
529bf6c4e8Spc 		newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
539bf6c4e8Spc 	terminal = stdin;
549bf6c4e8Spc #ifdef RRESTORE
559bf6c4e8Spc 	host = source;
569bf6c4e8Spc 	tape = index(host, ':');
579bf6c4e8Spc 	if (tape == 0) {
589bf6c4e8Spc nohost:
599bf6c4e8Spc 		msg("need keyletter ``f'' and device ``host:tape''\n");
609bf6c4e8Spc 		done(1);
619bf6c4e8Spc 	}
629bf6c4e8Spc 	*tape++ = '\0';
639bf6c4e8Spc 	(void) strcpy(magtape, tape);
649bf6c4e8Spc 	if (rmthost(host) == 0)
659bf6c4e8Spc 		done(1);
669bf6c4e8Spc 	setuid(getuid());	/* no longer need or want root privileges */
679bf6c4e8Spc #else
689bf6c4e8Spc 	if (strcmp(source, "-") == 0) {
699bf6c4e8Spc 		/*
709bf6c4e8Spc 		 * Since input is coming from a pipe we must establish
719bf6c4e8Spc 		 * our own connection to the terminal.
729bf6c4e8Spc 		 */
739bf6c4e8Spc 		terminal = fopen("/dev/tty", "r");
749bf6c4e8Spc 		if (terminal == NULL) {
759bf6c4e8Spc 			perror("Cannot open(\"/dev/tty\")");
769bf6c4e8Spc 			terminal = fopen("/dev/null", "r");
779bf6c4e8Spc 			if (terminal == NULL) {
789bf6c4e8Spc 				perror("Cannot open(\"/dev/null\")");
799bf6c4e8Spc 				done(1);
809bf6c4e8Spc 			}
819bf6c4e8Spc 		}
829bf6c4e8Spc 		pipein++;
839bf6c4e8Spc 	}
849bf6c4e8Spc 	(void) strcpy(magtape, source);
859bf6c4e8Spc #endif RRESTORE
869bf6c4e8Spc }
879bf6c4e8Spc 
newtapebuf(size)889bf6c4e8Spc newtapebuf(size)
899bf6c4e8Spc 	long size;
909bf6c4e8Spc {
919bf6c4e8Spc 	static tbfsize = -1;
929bf6c4e8Spc 
939bf6c4e8Spc 	ntrec = size;
949bf6c4e8Spc 	if (size <= tbfsize)
959bf6c4e8Spc 		return;
969bf6c4e8Spc 	if (tbf != NULL)
979bf6c4e8Spc 		free(tbf);
989bf6c4e8Spc 	tbf = (char *)malloc(size * TP_BSIZE);
999bf6c4e8Spc 	if (tbf == NULL) {
1009bf6c4e8Spc 		fprintf(stderr, "Cannot allocate space for tape buffer\n");
1019bf6c4e8Spc 		done(1);
1029bf6c4e8Spc 	}
1039bf6c4e8Spc 	tbfsize = size;
1049bf6c4e8Spc }
1059bf6c4e8Spc 
1069bf6c4e8Spc /*
1079bf6c4e8Spc  * Verify that the tape drive can be accessed and
1089bf6c4e8Spc  * that it actually is a dump tape.
1099bf6c4e8Spc  */
setup()1109bf6c4e8Spc setup()
1119bf6c4e8Spc {
1129bf6c4e8Spc 	int i, j, *ip;
1139bf6c4e8Spc 	struct stat stbuf;
1149bf6c4e8Spc 	extern char *ctime();
1159bf6c4e8Spc 	extern int xtrmap(), xtrmapskip();
1169bf6c4e8Spc 
1179bf6c4e8Spc 	vprintf(stdout, "Verify tape and initialize maps\n");
1189bf6c4e8Spc #ifdef RRESTORE
1199bf6c4e8Spc 	if ((mt = rmtopen(magtape, 0)) < 0)
1209bf6c4e8Spc #else
1219bf6c4e8Spc 	if (pipein)
1229bf6c4e8Spc 		mt = 0;
1239bf6c4e8Spc 	else if ((mt = open(magtape, 0)) < 0)
1249bf6c4e8Spc #endif
1259bf6c4e8Spc 	{
1269bf6c4e8Spc 		perror(magtape);
1279bf6c4e8Spc 		done(1);
1289bf6c4e8Spc 	}
1299bf6c4e8Spc 	volno = 1;
1309bf6c4e8Spc 	setdumpnum();
1319bf6c4e8Spc 	flsht();
1329bf6c4e8Spc 	if (!pipein && !bflag)
1339bf6c4e8Spc 		findtapeblksize();
1349bf6c4e8Spc 	if (gethead(&spcl) == FAIL) {
1359bf6c4e8Spc 		bct--; /* push back this block */
1369bf6c4e8Spc 		cvtflag++;
1379bf6c4e8Spc 		if (gethead(&spcl) == FAIL) {
1389bf6c4e8Spc 			fprintf(stderr, "Tape is not a dump tape\n");
1399bf6c4e8Spc 			done(1);
1409bf6c4e8Spc 		}
1419bf6c4e8Spc 		fprintf(stderr, "Converting to new file system format.\n");
1429bf6c4e8Spc 	}
1439bf6c4e8Spc 	if (pipein) {
1449bf6c4e8Spc 		endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
1459bf6c4e8Spc 		endoftapemark.s_spcl.c_type = TS_END;
1469bf6c4e8Spc 		ip = (int *)&endoftapemark;
1479bf6c4e8Spc 		j = sizeof(union u_spcl) / sizeof(int);
1489bf6c4e8Spc 		i = 0;
1499bf6c4e8Spc 		do
1509bf6c4e8Spc 			i += *ip++;
1519bf6c4e8Spc 		while (--j);
1529bf6c4e8Spc 		endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
1539bf6c4e8Spc 	}
1547b006476Spc 	if (vflag || command == 't')
1557b006476Spc 		printdumpinfo();
1569bf6c4e8Spc 	dumptime = spcl.c_ddate;
1579bf6c4e8Spc 	dumpdate = spcl.c_date;
1589bf6c4e8Spc 	if (stat(".", &stbuf) < 0) {
1599bf6c4e8Spc 		perror("cannot stat .");
1609bf6c4e8Spc 		done(1);
1619bf6c4e8Spc 	}
1629bf6c4e8Spc 	if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
1639bf6c4e8Spc 		fssize = stbuf.st_blksize;
1649bf6c4e8Spc 	if (((fssize - 1) & fssize) != 0) {
1659bf6c4e8Spc 		fprintf(stderr, "bad block size %d\n", fssize);
1669bf6c4e8Spc 		done(1);
1679bf6c4e8Spc 	}
1689bf6c4e8Spc 	if (checkvol(&spcl, (long)1) == FAIL) {
1699bf6c4e8Spc 		fprintf(stderr, "Tape is not volume 1 of the dump\n");
1709bf6c4e8Spc 		done(1);
1719bf6c4e8Spc 	}
1729bf6c4e8Spc 	if (readhdr(&spcl) == FAIL)
1739bf6c4e8Spc 		panic("no header after volume mark!\n");
1747b006476Spc 	findinode(&spcl);
1759bf6c4e8Spc 	if (checktype(&spcl, TS_CLRI) == FAIL) {
1769bf6c4e8Spc 		fprintf(stderr, "Cannot find file removal list\n");
1779bf6c4e8Spc 		done(1);
1789bf6c4e8Spc 	}
1799bf6c4e8Spc 	maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
1809bf6c4e8Spc 	dprintf(stdout, "maxino = %d\n", maxino);
1819bf6c4e8Spc 	map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
1829bf6c4e8Spc 	if (map == (char *)NIL)
1839bf6c4e8Spc 		panic("no memory for file removal list\n");
1849bf6c4e8Spc 	clrimap = map;
1859bf6c4e8Spc 	curfile.action = USING;
1869bf6c4e8Spc 	getfile(xtrmap, xtrmapskip);
1879bf6c4e8Spc 	if (checktype(&spcl, TS_BITS) == FAIL) {
1889bf6c4e8Spc 		fprintf(stderr, "Cannot find file dump list\n");
1899bf6c4e8Spc 		done(1);
1909bf6c4e8Spc 	}
1919bf6c4e8Spc 	map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
1929bf6c4e8Spc 	if (map == (char *)NULL)
1939bf6c4e8Spc 		panic("no memory for file dump list\n");
1949bf6c4e8Spc 	dumpmap = map;
1959bf6c4e8Spc 	curfile.action = USING;
1969bf6c4e8Spc 	getfile(xtrmap, xtrmapskip);
1979bf6c4e8Spc }
1989bf6c4e8Spc 
1999bf6c4e8Spc /*
2009bf6c4e8Spc  * Prompt user to load a new dump volume.
2019bf6c4e8Spc  * "Nextvol" is the next suggested volume to use.
2029bf6c4e8Spc  * This suggested volume is enforced when doing full
2039bf6c4e8Spc  * or incremental restores, but can be overrridden by
2049bf6c4e8Spc  * the user when only extracting a subset of the files.
2059bf6c4e8Spc  */
getvol(nextvol)2069bf6c4e8Spc getvol(nextvol)
2079bf6c4e8Spc 	long nextvol;
2089bf6c4e8Spc {
2099bf6c4e8Spc 	long newvol;
2109bf6c4e8Spc 	long savecnt, i;
2119bf6c4e8Spc 	union u_spcl tmpspcl;
2129bf6c4e8Spc #	define tmpbuf tmpspcl.s_spcl
2137b006476Spc 	char buf[TP_BSIZE];
2149bf6c4e8Spc 
2159bf6c4e8Spc 	if (nextvol == 1) {
2169bf6c4e8Spc 		tapesread = 0;
2179bf6c4e8Spc 		gettingfile = 0;
2189bf6c4e8Spc 	}
2199bf6c4e8Spc 	if (pipein) {
2209bf6c4e8Spc 		if (nextvol != 1)
2219bf6c4e8Spc 			panic("Changing volumes on pipe input?\n");
2229bf6c4e8Spc 		if (volno == 1)
2239bf6c4e8Spc 			return;
2249bf6c4e8Spc 		goto gethdr;
2259bf6c4e8Spc 	}
2269bf6c4e8Spc 	savecnt = blksread;
2279bf6c4e8Spc again:
2289bf6c4e8Spc 	if (pipein)
2299bf6c4e8Spc 		done(1); /* pipes do not get a second chance */
2309bf6c4e8Spc 	if (command == 'R' || command == 'r' || curfile.action != SKIP)
2319bf6c4e8Spc 		newvol = nextvol;
2329bf6c4e8Spc 	else
2339bf6c4e8Spc 		newvol = 0;
2349bf6c4e8Spc 	while (newvol <= 0) {
2359bf6c4e8Spc 		if (tapesread == 0) {
2369bf6c4e8Spc 			fprintf(stderr, "%s%s%s%s%s",
2379bf6c4e8Spc 			    "You have not read any tapes yet.\n",
2389bf6c4e8Spc 			    "Unless you know which volume your",
2399bf6c4e8Spc 			    " file(s) are on you should start\n",
2409bf6c4e8Spc 			    "with the last volume and work",
2419bf6c4e8Spc 			    " towards towards the first.\n");
2429bf6c4e8Spc 		} else {
2439bf6c4e8Spc 			fprintf(stderr, "You have read volumes");
2449bf6c4e8Spc 			strcpy(tbf, ": ");
2459bf6c4e8Spc 			for (i = 1; i < 32; i++)
2469bf6c4e8Spc 				if (tapesread & (1 << i)) {
2479bf6c4e8Spc 					fprintf(stderr, "%s%d", tbf, i);
2489bf6c4e8Spc 					strcpy(tbf, ", ");
2499bf6c4e8Spc 				}
2509bf6c4e8Spc 			fprintf(stderr, "\n");
2519bf6c4e8Spc 		}
2529bf6c4e8Spc 		do	{
2539bf6c4e8Spc 			fprintf(stderr, "Specify next volume #: ");
2549bf6c4e8Spc 			(void) fflush(stderr);
2559bf6c4e8Spc 			(void) fgets(tbf, BUFSIZ, terminal);
2569bf6c4e8Spc 		} while (!feof(terminal) && tbf[0] == '\n');
2579bf6c4e8Spc 		if (feof(terminal))
2589bf6c4e8Spc 			done(1);
2599bf6c4e8Spc 		newvol = atoi(tbf);
2609bf6c4e8Spc 		if (newvol <= 0) {
2619bf6c4e8Spc 			fprintf(stderr,
2629bf6c4e8Spc 			    "Volume numbers are positive numerics\n");
2639bf6c4e8Spc 		}
2649bf6c4e8Spc 	}
2659bf6c4e8Spc 	if (newvol == volno) {
2669bf6c4e8Spc 		tapesread |= 1 << volno;
2679bf6c4e8Spc 		return;
2689bf6c4e8Spc 	}
2699bf6c4e8Spc 	closemt();
2709bf6c4e8Spc 	fprintf(stderr, "Mount tape volume %d\n", newvol);
2719bf6c4e8Spc 	fprintf(stderr, "then enter tape name (default: %s) ", magtape);
2729bf6c4e8Spc 	(void) fflush(stderr);
2739bf6c4e8Spc 	(void) fgets(tbf, BUFSIZ, terminal);
2749bf6c4e8Spc 	if (feof(terminal))
2759bf6c4e8Spc 		done(1);
2769bf6c4e8Spc 	if (tbf[0] != '\n') {
2779bf6c4e8Spc 		(void) strcpy(magtape, tbf);
2789bf6c4e8Spc 		magtape[strlen(magtape) - 1] = '\0';
2799bf6c4e8Spc 	}
2809bf6c4e8Spc #ifdef RRESTORE
2819bf6c4e8Spc 	if ((mt = rmtopen(magtape, 0)) == -1)
2829bf6c4e8Spc #else
2839bf6c4e8Spc 	if ((mt = open(magtape, 0)) == -1)
2849bf6c4e8Spc #endif
2859bf6c4e8Spc 	{
2869bf6c4e8Spc 		fprintf(stderr, "Cannot open %s\n", magtape);
2879bf6c4e8Spc 		volno = -1;
2889bf6c4e8Spc 		goto again;
2899bf6c4e8Spc 	}
2909bf6c4e8Spc gethdr:
2919bf6c4e8Spc 	volno = newvol;
2929bf6c4e8Spc 	setdumpnum();
2939bf6c4e8Spc 	flsht();
2949bf6c4e8Spc 	if (readhdr(&tmpbuf) == FAIL) {
2959bf6c4e8Spc 		fprintf(stderr, "tape is not dump tape\n");
2969bf6c4e8Spc 		volno = 0;
2979bf6c4e8Spc 		goto again;
2989bf6c4e8Spc 	}
2999bf6c4e8Spc 	if (checkvol(&tmpbuf, volno) == FAIL) {
3009bf6c4e8Spc 		fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
3019bf6c4e8Spc 		volno = 0;
3029bf6c4e8Spc 		goto again;
3039bf6c4e8Spc 	}
3049bf6c4e8Spc 	if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
3059bf6c4e8Spc 		fprintf(stderr, "Wrong dump date\n\tgot: %s",
3069bf6c4e8Spc 			ctime(&tmpbuf.c_date));
3079bf6c4e8Spc 		fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
3089bf6c4e8Spc 		volno = 0;
3099bf6c4e8Spc 		goto again;
3109bf6c4e8Spc 	}
3119bf6c4e8Spc 	tapesread |= 1 << volno;
3129bf6c4e8Spc 	blksread = savecnt;
3139bf6c4e8Spc 	if (curfile.action == USING) {
3149bf6c4e8Spc 		if (volno == 1)
3159bf6c4e8Spc 			panic("active file into volume 1\n");
3169bf6c4e8Spc 		return;
3179bf6c4e8Spc 	}
3187b006476Spc 	/*
3197b006476Spc 	 * Skip up to the beginning of the next record
3207b006476Spc 	 */
3217b006476Spc 	if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
3227b006476Spc 		for (i = tmpbuf.c_count; i > 0; i--)
3237b006476Spc 			readtape(buf);
3249bf6c4e8Spc 	(void) gethead(&spcl);
3257b006476Spc 	findinode(&spcl);
3269bf6c4e8Spc 	if (gettingfile) {
3279bf6c4e8Spc 		gettingfile = 0;
3289bf6c4e8Spc 		longjmp(restart, 1);
3299bf6c4e8Spc 	}
3309bf6c4e8Spc }
3319bf6c4e8Spc 
3329bf6c4e8Spc /*
3339bf6c4e8Spc  * handle multiple dumps per tape by skipping forward to the
3349bf6c4e8Spc  * appropriate one.
3359bf6c4e8Spc  */
setdumpnum()3369bf6c4e8Spc setdumpnum()
3379bf6c4e8Spc {
3389bf6c4e8Spc 	struct mtop tcom;
3399bf6c4e8Spc 
3409bf6c4e8Spc 	if (dumpnum == 1 || volno != 1)
3419bf6c4e8Spc 		return;
3429bf6c4e8Spc 	if (pipein) {
3439bf6c4e8Spc 		fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
3449bf6c4e8Spc 		done(1);
3459bf6c4e8Spc 	}
3469bf6c4e8Spc 	tcom.mt_op = MTFSF;
3479bf6c4e8Spc 	tcom.mt_count = dumpnum - 1;
3489bf6c4e8Spc #ifdef RRESTORE
3499bf6c4e8Spc 	rmtioctl(MTFSF, dumpnum - 1);
3509bf6c4e8Spc #else
3519bf6c4e8Spc 	if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
3529bf6c4e8Spc 		perror("ioctl MTFSF");
3539bf6c4e8Spc #endif
3549bf6c4e8Spc }
3559bf6c4e8Spc 
printdumpinfo()3567b006476Spc printdumpinfo()
3577b006476Spc {
3587b006476Spc 
3597b006476Spc 	fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
3607b006476Spc 	fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
3617b006476Spc 	if (spcl.c_host[0] == '\0')
3627b006476Spc 		return;
3637b006476Spc 	fprintf(stderr, "Level %d dump of %s on %s:%s\n",
3647b006476Spc 		spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
365*a7ce809eSpc 	printf("Volume %d of the dump, starting at inode %d\n",
366*a7ce809eSpc 			spcl.c_volume, spcl.c_inumber);
3677b006476Spc 	fprintf(stderr, "Label: %s\n", spcl.c_label);
3687b006476Spc }
3697b006476Spc 
extractfile(name)3709bf6c4e8Spc extractfile(name)
3719bf6c4e8Spc 	char *name;
3729bf6c4e8Spc {
3739bf6c4e8Spc 	int mode;
3749bf6c4e8Spc 	time_t timep[2];
3759bf6c4e8Spc 	struct entry *ep;
3769bf6c4e8Spc 	extern int xtrlnkfile(), xtrlnkskip();
3779bf6c4e8Spc 	extern int xtrfile(), xtrskip();
3789bf6c4e8Spc 
3799bf6c4e8Spc 	curfile.name = name;
3809bf6c4e8Spc 	curfile.action = USING;
3819bf6c4e8Spc 	timep[0] = curfile.dip->di_atime;
3829bf6c4e8Spc 	timep[1] = curfile.dip->di_mtime;
3839bf6c4e8Spc 	mode = curfile.dip->di_mode;
3849bf6c4e8Spc 	switch (mode & IFMT) {
3859bf6c4e8Spc 
3869bf6c4e8Spc 	default:
3879bf6c4e8Spc 		fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
3889bf6c4e8Spc 		skipfile();
3899bf6c4e8Spc 		return (FAIL);
3909bf6c4e8Spc 
3919bf6c4e8Spc 	case IFSOCK:
3929bf6c4e8Spc 		vprintf(stdout, "skipped socket %s\n", name);
3939bf6c4e8Spc 		skipfile();
3949bf6c4e8Spc 		return (GOOD);
3959bf6c4e8Spc 
3969bf6c4e8Spc 	case IFDIR:
3979bf6c4e8Spc 		if (mflag) {
3989bf6c4e8Spc 			ep = lookupname(name);
3999bf6c4e8Spc 			if (ep == NIL || ep->e_flags & EXTRACT)
4009bf6c4e8Spc 				panic("unextracted directory %s\n", name);
4019bf6c4e8Spc 			skipfile();
4029bf6c4e8Spc 			return (GOOD);
4039bf6c4e8Spc 		}
4049bf6c4e8Spc 		vprintf(stdout, "extract file %s\n", name);
4059bf6c4e8Spc 		return (genliteraldir(name, curfile.ino));
4069bf6c4e8Spc 
4079bf6c4e8Spc 	case IFLNK:
4089bf6c4e8Spc 		lnkbuf[0] = '\0';
4099bf6c4e8Spc 		pathlen = 0;
4109bf6c4e8Spc 		getfile(xtrlnkfile, xtrlnkskip);
4119bf6c4e8Spc 		if (pathlen == 0) {
4129bf6c4e8Spc 			vprintf(stdout,
4139bf6c4e8Spc 			    "%s: zero length symbolic link (ignored)\n", name);
4149bf6c4e8Spc 			return (GOOD);
4159bf6c4e8Spc 		}
4169bf6c4e8Spc 		return (linkit(lnkbuf, name, SYMLINK));
4179bf6c4e8Spc 
4189bf6c4e8Spc 	case IFCHR:
4199bf6c4e8Spc 	case IFBLK:
4209bf6c4e8Spc 		vprintf(stdout, "extract special file %s\n", name);
4219bf6c4e8Spc 		if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
4229bf6c4e8Spc 			fprintf(stderr, "%s: ", name);
4239bf6c4e8Spc 			(void) fflush(stderr);
4249bf6c4e8Spc 			perror("cannot create special file");
4259bf6c4e8Spc 			skipfile();
4269bf6c4e8Spc 			return (FAIL);
4279bf6c4e8Spc 		}
4289bf6c4e8Spc 		(void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
4299bf6c4e8Spc 		(void) chmod(name, mode);
4309bf6c4e8Spc 		skipfile();
4319bf6c4e8Spc 		utime(name, timep);
4329bf6c4e8Spc 		return (GOOD);
4339bf6c4e8Spc 
4349bf6c4e8Spc 	case IFREG:
4359bf6c4e8Spc 		vprintf(stdout, "extract file %s\n", name);
4369bf6c4e8Spc 		if ((ofile = creat(name, 0666)) < 0) {
4379bf6c4e8Spc 			fprintf(stderr, "%s: ", name);
4389bf6c4e8Spc 			(void) fflush(stderr);
4399bf6c4e8Spc 			perror("cannot create file");
4409bf6c4e8Spc 			skipfile();
4419bf6c4e8Spc 			return (FAIL);
4429bf6c4e8Spc 		}
4439bf6c4e8Spc 		(void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
4449bf6c4e8Spc 		(void) fchmod(ofile, mode);
4459bf6c4e8Spc 		getfile(xtrfile, xtrskip);
4469bf6c4e8Spc 		(void) close(ofile);
4479bf6c4e8Spc 		utime(name, timep);
4489bf6c4e8Spc 		return (GOOD);
4499bf6c4e8Spc 	}
4509bf6c4e8Spc 	/* NOTREACHED */
4519bf6c4e8Spc }
4529bf6c4e8Spc 
4539bf6c4e8Spc /*
4549bf6c4e8Spc  * skip over bit maps on the tape
4559bf6c4e8Spc  */
skipmaps()4569bf6c4e8Spc skipmaps()
4579bf6c4e8Spc {
4589bf6c4e8Spc 
4599bf6c4e8Spc 	while (checktype(&spcl, TS_CLRI) == GOOD ||
4609bf6c4e8Spc 	       checktype(&spcl, TS_BITS) == GOOD)
4619bf6c4e8Spc 		skipfile();
4629bf6c4e8Spc }
4639bf6c4e8Spc 
4649bf6c4e8Spc /*
4659bf6c4e8Spc  * skip over a file on the tape
4669bf6c4e8Spc  */
skipfile()4679bf6c4e8Spc skipfile()
4689bf6c4e8Spc {
4699bf6c4e8Spc 	extern int null();
4709bf6c4e8Spc 
4719bf6c4e8Spc 	curfile.action = SKIP;
4729bf6c4e8Spc 	getfile(null, null);
4739bf6c4e8Spc }
4749bf6c4e8Spc 
4759bf6c4e8Spc /*
4769bf6c4e8Spc  * Do the file extraction, calling the supplied functions
4779bf6c4e8Spc  * with the blocks
4789bf6c4e8Spc  */
4799bf6c4e8Spc getfile(f1, f2)
4809bf6c4e8Spc 	int	(*f2)(), (*f1)();
4819bf6c4e8Spc {
4829bf6c4e8Spc 	register int i;
4839bf6c4e8Spc 	int curblk = 0;
4849bf6c4e8Spc 	off_t size = spcl.c_dinode.di_size;
4859bf6c4e8Spc 	static char clearedbuf[MAXBSIZE];
4869bf6c4e8Spc 	char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
4879bf6c4e8Spc 	char junk[TP_BSIZE];
4889bf6c4e8Spc 
4899bf6c4e8Spc 	if (checktype(&spcl, TS_END) == GOOD)
4909bf6c4e8Spc 		panic("ran off end of tape\n");
4919bf6c4e8Spc 	if (ishead(&spcl) == FAIL)
4929bf6c4e8Spc 		panic("not at beginning of a file\n");
4939bf6c4e8Spc 	if (!gettingfile && setjmp(restart) != 0)
4949bf6c4e8Spc 		return;
4959bf6c4e8Spc 	gettingfile++;
4969bf6c4e8Spc loop:
4979bf6c4e8Spc 	for (i = 0; i < spcl.c_count; i++) {
4989bf6c4e8Spc 		if (spcl.c_addr[i]) {
4999bf6c4e8Spc 			readtape(&buf[curblk++][0]);
5009bf6c4e8Spc 			if (curblk == fssize / TP_BSIZE) {
5019bf6c4e8Spc 				(*f1)(buf, size > TP_BSIZE ?
5029bf6c4e8Spc 				     (long) (fssize) :
5039bf6c4e8Spc 				     (curblk - 1) * TP_BSIZE + size);
5049bf6c4e8Spc 				curblk = 0;
5059bf6c4e8Spc 			}
5069bf6c4e8Spc 		} else {
5079bf6c4e8Spc 			if (curblk > 0) {
5089bf6c4e8Spc 				(*f1)(buf, size > TP_BSIZE ?
5099bf6c4e8Spc 				     (long) (curblk * TP_BSIZE) :
5109bf6c4e8Spc 				     (curblk - 1) * TP_BSIZE + size);
5119bf6c4e8Spc 				curblk = 0;
5129bf6c4e8Spc 			}
5139bf6c4e8Spc 			(*f2)(clearedbuf, size > TP_BSIZE ?
5149bf6c4e8Spc 				(long) TP_BSIZE : size);
5159bf6c4e8Spc 		}
5169bf6c4e8Spc 		if ((size -= TP_BSIZE) <= 0) {
5179bf6c4e8Spc 			for (i++; i < spcl.c_count; i++)
5189bf6c4e8Spc 				if (spcl.c_addr[i])
5199bf6c4e8Spc 					readtape(junk);
5209bf6c4e8Spc 			break;
5219bf6c4e8Spc 		}
5229bf6c4e8Spc 	}
5239bf6c4e8Spc 	if (readhdr(&spcl) == GOOD && size > 0) {
5249bf6c4e8Spc 		if (checktype(&spcl, TS_ADDR) == GOOD)
5259bf6c4e8Spc 			goto loop;
5269bf6c4e8Spc 		dprintf(stdout, "Missing address (header) block for %s\n",
5279bf6c4e8Spc 			curfile.name);
5289bf6c4e8Spc 	}
5299bf6c4e8Spc 	if (curblk > 0)
5309bf6c4e8Spc 		(*f1)(buf, (curblk * TP_BSIZE) + size);
5317b006476Spc 	findinode(&spcl);
5329bf6c4e8Spc 	gettingfile = 0;
5339bf6c4e8Spc }
5349bf6c4e8Spc 
5359bf6c4e8Spc /*
5369bf6c4e8Spc  * The next routines are called during file extraction to
5379bf6c4e8Spc  * put the data into the right form and place.
5389bf6c4e8Spc  */
xtrfile(buf,size)5399bf6c4e8Spc xtrfile(buf, size)
5409bf6c4e8Spc 	char	*buf;
5419bf6c4e8Spc 	long	size;
5429bf6c4e8Spc {
5439bf6c4e8Spc 
5449bf6c4e8Spc 	if (write(ofile, buf, (int) size) == -1) {
5459bf6c4e8Spc 		fprintf(stderr, "write error extracting inode %d, name %s\n",
5469bf6c4e8Spc 			curfile.ino, curfile.name);
5479bf6c4e8Spc 		perror("write");
5489bf6c4e8Spc 		done(1);
5499bf6c4e8Spc 	}
5509bf6c4e8Spc }
5519bf6c4e8Spc 
xtrskip(buf,size)5529bf6c4e8Spc xtrskip(buf, size)
5539bf6c4e8Spc 	char *buf;
5549bf6c4e8Spc 	long size;
5559bf6c4e8Spc {
5569bf6c4e8Spc 
5579bf6c4e8Spc #ifdef lint
5589bf6c4e8Spc 	buf = buf;
5599bf6c4e8Spc #endif
5609bf6c4e8Spc 	if (lseek(ofile, size, 1) == (long)-1) {
5619bf6c4e8Spc 		fprintf(stderr, "seek error extracting inode %d, name %s\n",
5629bf6c4e8Spc 			curfile.ino, curfile.name);
5639bf6c4e8Spc 		perror("lseek");
5649bf6c4e8Spc 		done(1);
5659bf6c4e8Spc 	}
5669bf6c4e8Spc }
5679bf6c4e8Spc 
xtrlnkfile(buf,size)5689bf6c4e8Spc xtrlnkfile(buf, size)
5699bf6c4e8Spc 	char	*buf;
5709bf6c4e8Spc 	long	size;
5719bf6c4e8Spc {
5729bf6c4e8Spc 
5739bf6c4e8Spc 	pathlen += size;
5749bf6c4e8Spc 	if (pathlen > MAXPATHLEN) {
5759bf6c4e8Spc 		fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
5769bf6c4e8Spc 		    curfile.name, lnkbuf, buf, pathlen);
5779bf6c4e8Spc 		done(1);
5789bf6c4e8Spc 	}
5799bf6c4e8Spc 	(void) strcat(lnkbuf, buf);
5809bf6c4e8Spc }
5819bf6c4e8Spc 
xtrlnkskip(buf,size)5829bf6c4e8Spc xtrlnkskip(buf, size)
5839bf6c4e8Spc 	char *buf;
5849bf6c4e8Spc 	long size;
5859bf6c4e8Spc {
5869bf6c4e8Spc 
5879bf6c4e8Spc #ifdef lint
5889bf6c4e8Spc 	buf = buf, size = size;
5899bf6c4e8Spc #endif
5909bf6c4e8Spc 	fprintf(stderr, "unallocated block in symbolic link %s\n",
5919bf6c4e8Spc 		curfile.name);
5929bf6c4e8Spc 	done(1);
5939bf6c4e8Spc }
5949bf6c4e8Spc 
xtrmap(buf,size)5959bf6c4e8Spc xtrmap(buf, size)
5969bf6c4e8Spc 	char	*buf;
5979bf6c4e8Spc 	long	size;
5989bf6c4e8Spc {
5999bf6c4e8Spc 
6009bf6c4e8Spc 	bcopy(buf, map, size);
6019bf6c4e8Spc 	map += size;
6029bf6c4e8Spc }
6039bf6c4e8Spc 
xtrmapskip(buf,size)6049bf6c4e8Spc xtrmapskip(buf, size)
6059bf6c4e8Spc 	char *buf;
6069bf6c4e8Spc 	long size;
6079bf6c4e8Spc {
6089bf6c4e8Spc 
6099bf6c4e8Spc #ifdef lint
6109bf6c4e8Spc 	buf = buf;
6119bf6c4e8Spc #endif
6129bf6c4e8Spc 	panic("hole in map\n");
6139bf6c4e8Spc 	map += size;
6149bf6c4e8Spc }
6159bf6c4e8Spc 
null()6169bf6c4e8Spc null() {;}
6179bf6c4e8Spc 
6189bf6c4e8Spc /*
6199bf6c4e8Spc  * Do the tape i/o, dealing with volume changes
6209bf6c4e8Spc  * etc..
6219bf6c4e8Spc  */
readtape(b)6229bf6c4e8Spc readtape(b)
6239bf6c4e8Spc 	char *b;
6249bf6c4e8Spc {
6259bf6c4e8Spc 	register long i;
6269bf6c4e8Spc 	long rd, newvol;
6279bf6c4e8Spc 	int cnt;
6289bf6c4e8Spc 
6299bf6c4e8Spc 	if (bct < ntrec) {
6309bf6c4e8Spc 		bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
6319bf6c4e8Spc 		blksread++;
6329bf6c4e8Spc 		return;
6339bf6c4e8Spc 	}
6349bf6c4e8Spc 	for (i = 0; i < ntrec; i++)
6359bf6c4e8Spc 		((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
6369bf6c4e8Spc 	bct = 0;
6379bf6c4e8Spc 	cnt = ntrec*TP_BSIZE;
6389bf6c4e8Spc 	rd = 0;
6399bf6c4e8Spc getmore:
6409bf6c4e8Spc #ifdef RRESTORE
6419bf6c4e8Spc 	i = rmtread(&tbf[rd], cnt);
6429bf6c4e8Spc #else
6439bf6c4e8Spc 	i = read(mt, &tbf[rd], cnt);
6449bf6c4e8Spc #endif
6459bf6c4e8Spc 	if (i > 0 && i != ntrec*TP_BSIZE) {
6469bf6c4e8Spc 		if (pipein) {
6479bf6c4e8Spc 			rd += i;
6489bf6c4e8Spc 			cnt -= i;
6499bf6c4e8Spc 			if (cnt > 0)
6509bf6c4e8Spc 				goto getmore;
6519bf6c4e8Spc 			i = rd;
6529bf6c4e8Spc 		} else {
6539bf6c4e8Spc 			if (i % TP_BSIZE != 0)
6549bf6c4e8Spc 				panic("partial block read: %d should be %d\n",
6559bf6c4e8Spc 					i, ntrec * TP_BSIZE);
6569bf6c4e8Spc 			bcopy((char *)&endoftapemark, &tbf[i],
6579bf6c4e8Spc 				(long)TP_BSIZE);
6589bf6c4e8Spc 		}
6599bf6c4e8Spc 	}
6609bf6c4e8Spc 	if (i < 0) {
6619bf6c4e8Spc 		fprintf(stderr, "Tape read error while ");
6629bf6c4e8Spc 		switch (curfile.action) {
6639bf6c4e8Spc 		default:
6649bf6c4e8Spc 			fprintf(stderr, "trying to set up tape\n");
6659bf6c4e8Spc 			break;
6669bf6c4e8Spc 		case UNKNOWN:
6679bf6c4e8Spc 			fprintf(stderr, "trying to resyncronize\n");
6689bf6c4e8Spc 			break;
6699bf6c4e8Spc 		case USING:
6709bf6c4e8Spc 			fprintf(stderr, "restoring %s\n", curfile.name);
6719bf6c4e8Spc 			break;
6729bf6c4e8Spc 		case SKIP:
6739bf6c4e8Spc 			fprintf(stderr, "skipping over inode %d\n",
6749bf6c4e8Spc 				curfile.ino);
6759bf6c4e8Spc 			break;
6769bf6c4e8Spc 		}
6779bf6c4e8Spc 		if (!yflag && !reply("continue"))
6789bf6c4e8Spc 			done(1);
6799bf6c4e8Spc 		i = ntrec*TP_BSIZE;
6809bf6c4e8Spc 		bzero(tbf, i);
6819bf6c4e8Spc #ifdef RRESTORE
6829bf6c4e8Spc 		if (rmtseek(i, 1) < 0)
6839bf6c4e8Spc #else
6849bf6c4e8Spc 		if (lseek(mt, i, 1) == (long)-1)
6859bf6c4e8Spc #endif
6869bf6c4e8Spc 		{
6879bf6c4e8Spc 			perror("continuation failed");
6889bf6c4e8Spc 			done(1);
6899bf6c4e8Spc 		}
6909bf6c4e8Spc 	}
6919bf6c4e8Spc 	if (i == 0) {
6929bf6c4e8Spc 		if (!pipein) {
6939bf6c4e8Spc 			newvol = volno + 1;
6949bf6c4e8Spc 			volno = 0;
6959bf6c4e8Spc 			getvol(newvol);
6969bf6c4e8Spc 			readtape(b);
6979bf6c4e8Spc 			return;
6989bf6c4e8Spc 		}
6999bf6c4e8Spc 		if (rd % TP_BSIZE != 0)
7009bf6c4e8Spc 			panic("partial block read: %d should be %d\n",
7019bf6c4e8Spc 				rd, ntrec * TP_BSIZE);
7029bf6c4e8Spc 		bcopy((char *)&endoftapemark, &tbf[rd], (long)TP_BSIZE);
7039bf6c4e8Spc 	}
7049bf6c4e8Spc 	bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
7059bf6c4e8Spc 	blksread++;
7069bf6c4e8Spc }
7079bf6c4e8Spc 
findtapeblksize()7089bf6c4e8Spc findtapeblksize()
7099bf6c4e8Spc {
7109bf6c4e8Spc 	register long i;
7119bf6c4e8Spc 
7129bf6c4e8Spc 	for (i = 0; i < ntrec; i++)
7139bf6c4e8Spc 		((struct s_spcl *)&tbf[i * TP_BSIZE])->c_magic = 0;
7149bf6c4e8Spc 	bct = 0;
7159bf6c4e8Spc #ifdef RRESTORE
7169bf6c4e8Spc 	i = rmtread(tbf, ntrec * TP_BSIZE);
7179bf6c4e8Spc #else
7189bf6c4e8Spc 	i = read(mt, tbf, ntrec * TP_BSIZE);
7199bf6c4e8Spc #endif
7209bf6c4e8Spc 	if (i <= 0) {
7219bf6c4e8Spc 		perror("Tape read error");
7229bf6c4e8Spc 		done(1);
7239bf6c4e8Spc 	}
7249bf6c4e8Spc 	if (i % TP_BSIZE != 0) {
7259bf6c4e8Spc 		fprintf(stderr, "Tape block size (%d) %s (%d)\n",
7269bf6c4e8Spc 			i, "is not a multiple of dump block size", TP_BSIZE);
7279bf6c4e8Spc 		done(1);
7289bf6c4e8Spc 	}
7299bf6c4e8Spc 	ntrec = i / TP_BSIZE;
7309bf6c4e8Spc 	vprintf(stdout, "Tape block size is %d\n", ntrec);
7319bf6c4e8Spc }
7329bf6c4e8Spc 
flsht()7339bf6c4e8Spc flsht()
7349bf6c4e8Spc {
7359bf6c4e8Spc 
7369bf6c4e8Spc 	bct = ntrec+1;
7379bf6c4e8Spc }
7389bf6c4e8Spc 
closemt()7399bf6c4e8Spc closemt()
7409bf6c4e8Spc {
7419bf6c4e8Spc 	if (mt < 0)
7429bf6c4e8Spc 		return;
7439bf6c4e8Spc #ifdef RRESTORE
7449bf6c4e8Spc 	rmtclose();
7459bf6c4e8Spc #else
7469bf6c4e8Spc 	(void) close(mt);
7479bf6c4e8Spc #endif
7489bf6c4e8Spc }
7499bf6c4e8Spc 
7509bf6c4e8Spc checkvol(b, t)
7519bf6c4e8Spc 	struct s_spcl *b;
7529bf6c4e8Spc 	long t;
7539bf6c4e8Spc {
7549bf6c4e8Spc 
7559bf6c4e8Spc 	if (b->c_volume != t)
7569bf6c4e8Spc 		return(FAIL);
7579bf6c4e8Spc 	return(GOOD);
7589bf6c4e8Spc }
7599bf6c4e8Spc 
7609bf6c4e8Spc readhdr(b)
7619bf6c4e8Spc 	struct s_spcl *b;
7629bf6c4e8Spc {
7639bf6c4e8Spc 
7649bf6c4e8Spc 	if (gethead(b) == FAIL) {
7659bf6c4e8Spc 		dprintf(stdout, "readhdr fails at %d blocks\n", blksread);
7669bf6c4e8Spc 		return(FAIL);
7679bf6c4e8Spc 	}
7689bf6c4e8Spc 	return(GOOD);
7699bf6c4e8Spc }
7709bf6c4e8Spc 
7719bf6c4e8Spc /*
7729bf6c4e8Spc  * read the tape into buf, then return whether or
7739bf6c4e8Spc  * or not it is a header block.
7749bf6c4e8Spc  */
7759bf6c4e8Spc gethead(buf)
7769bf6c4e8Spc 	struct s_spcl *buf;
7779bf6c4e8Spc {
7789bf6c4e8Spc 	long i, *j;
7799bf6c4e8Spc 	union u_ospcl {
7809bf6c4e8Spc 		char dummy[TP_BSIZE];
7819bf6c4e8Spc 		struct	s_ospcl {
7829bf6c4e8Spc 			long	c_type;
7839bf6c4e8Spc 			long	c_date;
7849bf6c4e8Spc 			long	c_ddate;
7859bf6c4e8Spc 			long	c_volume;
7869bf6c4e8Spc 			long	c_tapea;
7879bf6c4e8Spc 			u_short	c_inumber;
7889bf6c4e8Spc 			long	c_magic;
7899bf6c4e8Spc 			long	c_checksum;
7909bf6c4e8Spc 			struct odinode {
7919bf6c4e8Spc 				unsigned short odi_mode;
7929bf6c4e8Spc 				u_short	odi_nlink;
7939bf6c4e8Spc 				u_short	odi_uid;
7949bf6c4e8Spc 				u_short	odi_gid;
7959bf6c4e8Spc 				long	odi_size;
7969bf6c4e8Spc 				long	odi_rdev;
7979bf6c4e8Spc 				char	odi_addr[36];
7989bf6c4e8Spc 				long	odi_atime;
7999bf6c4e8Spc 				long	odi_mtime;
8009bf6c4e8Spc 				long	odi_ctime;
8019bf6c4e8Spc 			} c_dinode;
8029bf6c4e8Spc 			long	c_count;
8039bf6c4e8Spc 			char	c_addr[256];
8049bf6c4e8Spc 		} s_ospcl;
8059bf6c4e8Spc 	} u_ospcl;
8069bf6c4e8Spc 
8079bf6c4e8Spc 	if (!cvtflag) {
8089bf6c4e8Spc 		readtape((char *)buf);
8099bf6c4e8Spc 		if (buf->c_magic != NFS_MAGIC) {
8109bf6c4e8Spc 			if (swabl(buf->c_magic) != NFS_MAGIC)
8119bf6c4e8Spc 				return (FAIL);
8129bf6c4e8Spc 			if (!Bcvt) {
8139bf6c4e8Spc 				vprintf(stdout, "Note: Doing Byte swapping\n");
8149bf6c4e8Spc 				Bcvt = 1;
8159bf6c4e8Spc 			}
8169bf6c4e8Spc 		}
8179bf6c4e8Spc 		if (checksum((int *)buf) == FAIL)
8189bf6c4e8Spc 			return (FAIL);
8199bf6c4e8Spc 		if (Bcvt)
8209bf6c4e8Spc 			swabst("8l4s31l", (char *)buf);
8219bf6c4e8Spc 		goto good;
8229bf6c4e8Spc 	}
8239bf6c4e8Spc 	readtape((char *)(&u_ospcl.s_ospcl));
8249bf6c4e8Spc 	bzero((char *)buf, (long)TP_BSIZE);
8259bf6c4e8Spc 	buf->c_type = u_ospcl.s_ospcl.c_type;
8269bf6c4e8Spc 	buf->c_date = u_ospcl.s_ospcl.c_date;
8279bf6c4e8Spc 	buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
8289bf6c4e8Spc 	buf->c_volume = u_ospcl.s_ospcl.c_volume;
8299bf6c4e8Spc 	buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
8309bf6c4e8Spc 	buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
8319bf6c4e8Spc 	buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
8329bf6c4e8Spc 	buf->c_magic = u_ospcl.s_ospcl.c_magic;
8339bf6c4e8Spc 	buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
8349bf6c4e8Spc 	buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
8359bf6c4e8Spc 	buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
8369bf6c4e8Spc 	buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
8379bf6c4e8Spc 	buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
8389bf6c4e8Spc 	buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
8399bf6c4e8Spc 	buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
8409bf6c4e8Spc 	buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
8419bf6c4e8Spc 	buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
8429bf6c4e8Spc 	buf->c_count = u_ospcl.s_ospcl.c_count;
8439bf6c4e8Spc 	bcopy(u_ospcl.s_ospcl.c_addr, buf->c_addr, (long)256);
8449bf6c4e8Spc 	if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
8459bf6c4e8Spc 	    checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
8469bf6c4e8Spc 		return(FAIL);
8479bf6c4e8Spc 	buf->c_magic = NFS_MAGIC;
8489bf6c4e8Spc 
8499bf6c4e8Spc good:
8509bf6c4e8Spc 	j = buf->c_dinode.di_ic.ic_size.val;
8519bf6c4e8Spc 	i = j[1];
8529bf6c4e8Spc 	if (buf->c_dinode.di_size == 0 &&
8539bf6c4e8Spc 	    (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt==0) {
8549bf6c4e8Spc 		if (*j || i) {
8559bf6c4e8Spc 			printf("Note: Doing Quad swapping\n");
8569bf6c4e8Spc 			Qcvt = 1;
8579bf6c4e8Spc 		}
8589bf6c4e8Spc 	}
8599bf6c4e8Spc 	if (Qcvt) {
8609bf6c4e8Spc 		j[1] = *j; *j = i;
8619bf6c4e8Spc 	}
8629bf6c4e8Spc 	switch (buf->c_type) {
8639bf6c4e8Spc 
8649bf6c4e8Spc 	case TS_CLRI:
8659bf6c4e8Spc 	case TS_BITS:
8669bf6c4e8Spc 		/*
8679bf6c4e8Spc 		 * Have to patch up missing information in bit map headers
8689bf6c4e8Spc 		 */
8699bf6c4e8Spc 		buf->c_inumber = 0;
8709bf6c4e8Spc 		buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
8719bf6c4e8Spc 		for (i = 0; i < buf->c_count; i++)
8729bf6c4e8Spc 			buf->c_addr[i]++;
8739bf6c4e8Spc 		break;
8749bf6c4e8Spc 
8759bf6c4e8Spc 	case TS_TAPE:
8769bf6c4e8Spc 	case TS_END:
8779bf6c4e8Spc 		buf->c_inumber = 0;
8789bf6c4e8Spc 		break;
8799bf6c4e8Spc 
8809bf6c4e8Spc 	case TS_INODE:
8819bf6c4e8Spc 	case TS_ADDR:
8829bf6c4e8Spc 		break;
8839bf6c4e8Spc 
8849bf6c4e8Spc 	default:
8859bf6c4e8Spc 		panic("gethead: unknown inode type %d\n", buf->c_type);
8869bf6c4e8Spc 		break;
8879bf6c4e8Spc 	}
8889bf6c4e8Spc 	if (dflag)
8899bf6c4e8Spc 		accthdr(buf);
8909bf6c4e8Spc 	return(GOOD);
8919bf6c4e8Spc }
8929bf6c4e8Spc 
8939bf6c4e8Spc /*
8949bf6c4e8Spc  * Check that a header is where it belongs and predict the next header
8959bf6c4e8Spc  */
8969bf6c4e8Spc accthdr(header)
8979bf6c4e8Spc 	struct s_spcl *header;
8989bf6c4e8Spc {
8999bf6c4e8Spc 	static ino_t previno = 0x7fffffff;
9009bf6c4e8Spc 	static int prevtype;
9019bf6c4e8Spc 	static long predict;
9029bf6c4e8Spc 	long blks, i;
9039bf6c4e8Spc 
9049bf6c4e8Spc 	if (header->c_type == TS_TAPE) {
9059bf6c4e8Spc 		fprintf(stderr, "Volume header\n");
9067b006476Spc 		previno = 0x7fffffff;
9079bf6c4e8Spc 		return;
9089bf6c4e8Spc 	}
9099bf6c4e8Spc 	if (previno == 0x7fffffff)
9109bf6c4e8Spc 		goto newcalc;
9119bf6c4e8Spc 	switch (prevtype) {
9129bf6c4e8Spc 	case TS_BITS:
9139bf6c4e8Spc 		fprintf(stderr, "Dump mask header");
9149bf6c4e8Spc 		break;
9159bf6c4e8Spc 	case TS_CLRI:
9169bf6c4e8Spc 		fprintf(stderr, "Remove mask header");
9179bf6c4e8Spc 		break;
9189bf6c4e8Spc 	case TS_INODE:
9199bf6c4e8Spc 		fprintf(stderr, "File header, ino %d", previno);
9209bf6c4e8Spc 		break;
9219bf6c4e8Spc 	case TS_ADDR:
9229bf6c4e8Spc 		fprintf(stderr, "File continuation header, ino %d", previno);
9239bf6c4e8Spc 		break;
9249bf6c4e8Spc 	case TS_END:
9259bf6c4e8Spc 		fprintf(stderr, "End of tape header");
9269bf6c4e8Spc 		break;
9279bf6c4e8Spc 	}
9289bf6c4e8Spc 	if (predict != blksread - 1)
9299bf6c4e8Spc 		fprintf(stderr, "; predicted %d blocks, got %d blocks",
9309bf6c4e8Spc 			predict, blksread - 1);
9319bf6c4e8Spc 	fprintf(stderr, "\n");
9329bf6c4e8Spc newcalc:
9339bf6c4e8Spc 	blks = 0;
9349bf6c4e8Spc 	if (header->c_type != TS_END)
9359bf6c4e8Spc 		for (i = 0; i < header->c_count; i++)
9369bf6c4e8Spc 			if (header->c_addr[i] != 0)
9379bf6c4e8Spc 				blks++;
9389bf6c4e8Spc 	predict = blks;
9399bf6c4e8Spc 	blksread = 0;
9409bf6c4e8Spc 	prevtype = header->c_type;
9419bf6c4e8Spc 	previno = header->c_inumber;
9429bf6c4e8Spc }
9439bf6c4e8Spc 
9449bf6c4e8Spc /*
9459bf6c4e8Spc  * Find an inode header.
9469bf6c4e8Spc  * Complain if had to skip, and complain is set.
9479bf6c4e8Spc  */
9487b006476Spc findinode(header)
9499bf6c4e8Spc 	struct s_spcl *header;
9509bf6c4e8Spc {
9519bf6c4e8Spc 	static long skipcnt = 0;
9527b006476Spc 	long i;
9537b006476Spc 	char buf[TP_BSIZE];
9549bf6c4e8Spc 
9559bf6c4e8Spc 	curfile.name = "<name unknown>";
9569bf6c4e8Spc 	curfile.action = UNKNOWN;
9579bf6c4e8Spc 	curfile.dip = (struct dinode *)NIL;
9589bf6c4e8Spc 	curfile.ino = 0;
9599bf6c4e8Spc 	if (ishead(header) == FAIL) {
9609bf6c4e8Spc 		skipcnt++;
9617b006476Spc 		while (gethead(header) == FAIL || header->c_date != dumpdate)
9629bf6c4e8Spc 			skipcnt++;
9639bf6c4e8Spc 	}
9649bf6c4e8Spc 	for (;;) {
9657b006476Spc 		if (checktype(header, TS_ADDR) == GOOD) {
9667b006476Spc 			/*
9677b006476Spc 			 * Skip up to the beginning of the next record
9687b006476Spc 			 */
9697b006476Spc 			for (i = 0; i < header->c_count; i++)
9707b006476Spc 				if (header->c_addr[i])
9717b006476Spc 					readtape(buf);
9727b006476Spc 			(void) gethead(header);
9737b006476Spc 			continue;
9747b006476Spc 		}
9759bf6c4e8Spc 		if (checktype(header, TS_INODE) == GOOD) {
9769bf6c4e8Spc 			curfile.dip = &header->c_dinode;
9779bf6c4e8Spc 			curfile.ino = header->c_inumber;
9789bf6c4e8Spc 			break;
9799bf6c4e8Spc 		}
9809bf6c4e8Spc 		if (checktype(header, TS_END) == GOOD) {
9819bf6c4e8Spc 			curfile.ino = maxino;
9829bf6c4e8Spc 			break;
9839bf6c4e8Spc 		}
9849bf6c4e8Spc 		if (checktype(header, TS_CLRI) == GOOD) {
9859bf6c4e8Spc 			curfile.name = "<file removal list>";
9869bf6c4e8Spc 			break;
9879bf6c4e8Spc 		}
9889bf6c4e8Spc 		if (checktype(header, TS_BITS) == GOOD) {
9899bf6c4e8Spc 			curfile.name = "<file dump list>";
9909bf6c4e8Spc 			break;
9919bf6c4e8Spc 		}
9929bf6c4e8Spc 		while (gethead(header) == FAIL)
9939bf6c4e8Spc 			skipcnt++;
9949bf6c4e8Spc 	}
9957b006476Spc 	if (skipcnt > 0)
9969bf6c4e8Spc 		fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
9979bf6c4e8Spc 	skipcnt = 0;
9989bf6c4e8Spc }
9999bf6c4e8Spc 
10009bf6c4e8Spc /*
10019bf6c4e8Spc  * return whether or not the buffer contains a header block
10029bf6c4e8Spc  */
10039bf6c4e8Spc ishead(buf)
10049bf6c4e8Spc 	struct s_spcl *buf;
10059bf6c4e8Spc {
10069bf6c4e8Spc 
10079bf6c4e8Spc 	if (buf->c_magic != NFS_MAGIC)
10089bf6c4e8Spc 		return(FAIL);
10099bf6c4e8Spc 	return(GOOD);
10109bf6c4e8Spc }
10119bf6c4e8Spc 
10129bf6c4e8Spc checktype(b, t)
10139bf6c4e8Spc 	struct s_spcl *b;
10149bf6c4e8Spc 	int	t;
10159bf6c4e8Spc {
10169bf6c4e8Spc 
10179bf6c4e8Spc 	if (b->c_type != t)
10189bf6c4e8Spc 		return(FAIL);
10199bf6c4e8Spc 	return(GOOD);
10209bf6c4e8Spc }
10219bf6c4e8Spc 
checksum(b)10229bf6c4e8Spc checksum(b)
10239bf6c4e8Spc 	register int *b;
10249bf6c4e8Spc {
10259bf6c4e8Spc 	register int i, j;
10269bf6c4e8Spc 
10279bf6c4e8Spc 	j = sizeof(union u_spcl) / sizeof(int);
10289bf6c4e8Spc 	i = 0;
10299bf6c4e8Spc 	if(!Bcvt) {
10309bf6c4e8Spc 		do
10319bf6c4e8Spc 			i += *b++;
10329bf6c4e8Spc 		while (--j);
10339bf6c4e8Spc 	} else {
10349bf6c4e8Spc 		/* What happens if we want to read restore tapes
10359bf6c4e8Spc 			for a 16bit int machine??? */
10369bf6c4e8Spc 		do
10379bf6c4e8Spc 			i += swabl(*b++);
10389bf6c4e8Spc 		while (--j);
10399bf6c4e8Spc 	}
10409bf6c4e8Spc 
10419bf6c4e8Spc 	if (i != CHECKSUM) {
10429bf6c4e8Spc 		fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
10439bf6c4e8Spc 			curfile.ino, curfile.name);
10449bf6c4e8Spc 		return(FAIL);
10459bf6c4e8Spc 	}
10469bf6c4e8Spc 	return(GOOD);
10479bf6c4e8Spc }
10489bf6c4e8Spc 
10499bf6c4e8Spc #ifdef RRESTORE
10509bf6c4e8Spc /* VARARGS1 */
msg(cp,a1,a2,a3)10519bf6c4e8Spc msg(cp, a1, a2, a3)
10529bf6c4e8Spc 	char *cp;
10539bf6c4e8Spc {
10549bf6c4e8Spc 
10559bf6c4e8Spc 	fprintf(stderr, cp, a1, a2, a3);
10569bf6c4e8Spc }
10579bf6c4e8Spc #endif RRESTORE
10589bf6c4e8Spc 
swabst(cp,sp)10599bf6c4e8Spc swabst(cp, sp)
10609bf6c4e8Spc register char *cp, *sp;
10619bf6c4e8Spc {
10629bf6c4e8Spc 	int n = 0;
10639bf6c4e8Spc 	char c;
10649bf6c4e8Spc 	while(*cp) {
10659bf6c4e8Spc 		switch (*cp) {
10669bf6c4e8Spc 		case '0': case '1': case '2': case '3': case '4':
10679bf6c4e8Spc 		case '5': case '6': case '7': case '8': case '9':
10689bf6c4e8Spc 			n = (n * 10) + (*cp++ - '0');
10699bf6c4e8Spc 			continue;
10709bf6c4e8Spc 
10719bf6c4e8Spc 		case 's': case 'w': case 'h':
10729bf6c4e8Spc 			c = sp[0]; sp[0] = sp[1]; sp[1] = c;
10739bf6c4e8Spc 			sp++;
10749bf6c4e8Spc 			break;
10759bf6c4e8Spc 
10769bf6c4e8Spc 		case 'l':
10779bf6c4e8Spc 			c = sp[0]; sp[0] = sp[3]; sp[3] = c;
10789bf6c4e8Spc 			c = sp[2]; sp[2] = sp[1]; sp[1] = c;
10799bf6c4e8Spc 			sp += 3;
10809bf6c4e8Spc 		}
10819bf6c4e8Spc 		sp++; /* Any other character, like 'b' counts as byte. */
10829bf6c4e8Spc 		if (n <= 1) {
10839bf6c4e8Spc 			n = 0; cp++;
10849bf6c4e8Spc 		} else
10859bf6c4e8Spc 			n--;
10869bf6c4e8Spc 	}
10879bf6c4e8Spc }
swabl(x)10889bf6c4e8Spc swabl(x) { unsigned long l = x; swabst("l", (char *)&l); return l; }
1089