xref: /onnv-gate/usr/src/cmd/backup/restore/tape.c (revision 8137:f78933a315cb)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * Copyright (c) 1983 Regents of the University of California.
30Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
40Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
50Sstevel@tonic-gate  */
60Sstevel@tonic-gate 
70Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
80Sstevel@tonic-gate /*	  All Rights Reserved	*/
90Sstevel@tonic-gate 
100Sstevel@tonic-gate /*
11*8137SFrank.Batschulat@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
120Sstevel@tonic-gate  * Use is subject to license terms.
130Sstevel@tonic-gate  */
140Sstevel@tonic-gate 
150Sstevel@tonic-gate #include <setjmp.h>
160Sstevel@tonic-gate #include "restore.h"
170Sstevel@tonic-gate #include <byteorder.h>
180Sstevel@tonic-gate #include <rmt.h>
190Sstevel@tonic-gate #include <sys/mtio.h>
200Sstevel@tonic-gate #include <utime.h>
210Sstevel@tonic-gate #include <sys/errno.h>
220Sstevel@tonic-gate #include <sys/fdio.h>
230Sstevel@tonic-gate #include <sys/sysmacros.h>	/* for expdev */
240Sstevel@tonic-gate #include <assert.h>
250Sstevel@tonic-gate #include <limits.h>
260Sstevel@tonic-gate #include <priv_utils.h>
271953Smarks #include <aclutils.h>
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #define	MAXINO	65535		/* KLUDGE */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #define	MAXTAPES	128
320Sstevel@tonic-gate 
330Sstevel@tonic-gate static size_t	fssize = MAXBSIZE; /* preferred size of writes to filesystem */
340Sstevel@tonic-gate int mt = -1;
350Sstevel@tonic-gate static int	continuemap = 0;
360Sstevel@tonic-gate char		magtape[BUFSIZ];
370Sstevel@tonic-gate int		pipein = 0;
380Sstevel@tonic-gate char		*host;		/* used in dumprmt.c */
390Sstevel@tonic-gate daddr32_t	rec_position;
400Sstevel@tonic-gate static char	*archivefile;	/* used in metamucil.c */
410Sstevel@tonic-gate static int	bct;		/* block # index into tape record buffer */
420Sstevel@tonic-gate static int	numtrec;	/* # of logical blocks in current tape record */
430Sstevel@tonic-gate static char	*tbf = NULL;
440Sstevel@tonic-gate static size_t	tbfsize = 0;
450Sstevel@tonic-gate static int	recsread;
460Sstevel@tonic-gate static union	u_spcl endoftapemark;
470Sstevel@tonic-gate static struct	s_spcl dumpinfo;
480Sstevel@tonic-gate static long	blksread;	/* # of logical blocks actually read/touched */
490Sstevel@tonic-gate static long	tapea;		/* current logical block # on tape */
500Sstevel@tonic-gate static uchar_t	tapesread[MAXTAPES];
510Sstevel@tonic-gate static jmp_buf	restart;
520Sstevel@tonic-gate static int	gettingfile = 0;	/* restart has a valid frame */
530Sstevel@tonic-gate static int	ofile;
540Sstevel@tonic-gate static char	*map, *beginmap;
550Sstevel@tonic-gate static char	*endmap;
560Sstevel@tonic-gate static char	lnkbuf[MAXPATHLEN + 2];
570Sstevel@tonic-gate static int	pathlen;
580Sstevel@tonic-gate static int	inodeinfo;	/* Have starting volume information */
590Sstevel@tonic-gate static int	hostinfo;	/* Have dump host information */
600Sstevel@tonic-gate 
610Sstevel@tonic-gate static int autoload_tape(void);
620Sstevel@tonic-gate static void setdumpnum(void);
630Sstevel@tonic-gate static void metacheck(struct s_spcl *);
640Sstevel@tonic-gate static void xtrmeta(char *, size_t);
650Sstevel@tonic-gate static void metaskip(char *, size_t);
660Sstevel@tonic-gate static void xtrfile(char *, size_t);
670Sstevel@tonic-gate static void xtrskip(char *, size_t);
680Sstevel@tonic-gate static void xtrlnkfile(char *, size_t);
690Sstevel@tonic-gate static void xtrlnkskip(char *, size_t);
700Sstevel@tonic-gate static void xtrmap(char *, size_t);
710Sstevel@tonic-gate static void xtrmapskip(char *, size_t);
720Sstevel@tonic-gate static void readtape(char *);
730Sstevel@tonic-gate static int checkvol(struct s_spcl *, int);
740Sstevel@tonic-gate static void accthdr(struct s_spcl *);
750Sstevel@tonic-gate static int ishead(struct s_spcl *);
761053Smaheshvs static int checktype(struct s_spcl *, int);
770Sstevel@tonic-gate static void metaset(char *name);
780Sstevel@tonic-gate 
790Sstevel@tonic-gate /*
800Sstevel@tonic-gate  * Set up an input source
810Sstevel@tonic-gate  */
820Sstevel@tonic-gate void
setinput(char * source,char * archive)831053Smaheshvs setinput(char *source, char *archive)
840Sstevel@tonic-gate {
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	flsht();
870Sstevel@tonic-gate 	archivefile = archive;
880Sstevel@tonic-gate 	if (bflag == 0) {
890Sstevel@tonic-gate 		ntrec = ((CARTRIDGETREC > HIGHDENSITYTREC) ?
900Sstevel@tonic-gate 		    (NTREC > CARTRIDGETREC ? NTREC : CARTRIDGETREC) :
910Sstevel@tonic-gate 		    (NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC));
920Sstevel@tonic-gate 		saved_ntrec = (ntrec * (tp_bsize/DEV_BSIZE));
930Sstevel@tonic-gate 	}
940Sstevel@tonic-gate 	newtapebuf(ntrec);
950Sstevel@tonic-gate 	terminal = stdin;
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 	if (source == NULL) {
980Sstevel@tonic-gate 		/* A can't-happen */
990Sstevel@tonic-gate 		(void) fprintf(stderr,
1000Sstevel@tonic-gate 		    gettext("Internal consistency check failed.\n"));
1010Sstevel@tonic-gate 		done(1);
1020Sstevel@tonic-gate 	}
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	if (strchr(source, ':')) {
1050Sstevel@tonic-gate 		char *tape;
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 		host = source;
1080Sstevel@tonic-gate 		tape = strchr(host, ':');
1090Sstevel@tonic-gate 		*tape++ = '\0';
1100Sstevel@tonic-gate 		if (strlen(tape) > (sizeof (magtape) - 1)) {
1110Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Tape name too long\n"));
1120Sstevel@tonic-gate 			done(1);
1130Sstevel@tonic-gate 		}
1140Sstevel@tonic-gate 		(void) strcpy(magtape, tape);
1150Sstevel@tonic-gate 		if (rmthost(host, ntrec) == 0)
1160Sstevel@tonic-gate 			done(1);
1170Sstevel@tonic-gate 	} else {
1180Sstevel@tonic-gate 		if (strlen(source) > (sizeof (magtape) - 1)) {
1190Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Tape name too long\n"));
1200Sstevel@tonic-gate 			done(1);
1210Sstevel@tonic-gate 		}
1220Sstevel@tonic-gate 		/* Not remote, no need for privileges */
1230Sstevel@tonic-gate 		__priv_relinquish();
1240Sstevel@tonic-gate 		host = NULL;
1250Sstevel@tonic-gate 		if (strcmp(source, "-") == 0) {
1260Sstevel@tonic-gate 			/*
1270Sstevel@tonic-gate 			 * Since input is coming from a pipe we must establish
1280Sstevel@tonic-gate 			 * our own connection to the terminal.
1290Sstevel@tonic-gate 			 */
1300Sstevel@tonic-gate 			terminal = fopen("/dev/tty", "r");
1310Sstevel@tonic-gate 			if (terminal == NULL) {
1320Sstevel@tonic-gate 				int saverr = errno;
1330Sstevel@tonic-gate 				char *msg =
1344639Svk154806 				    gettext("Cannot open(\"/dev/tty\")");
1350Sstevel@tonic-gate 				errno = saverr;
1360Sstevel@tonic-gate 				perror(msg);
1370Sstevel@tonic-gate 				terminal = fopen("/dev/null", "r");
1380Sstevel@tonic-gate 				if (terminal == NULL) {
1390Sstevel@tonic-gate 					saverr = errno;
1400Sstevel@tonic-gate 					msg = gettext(
1410Sstevel@tonic-gate 					    "Cannot open(\"/dev/null\")");
1420Sstevel@tonic-gate 					errno = saverr;
1430Sstevel@tonic-gate 					perror(msg);
1440Sstevel@tonic-gate 					done(1);
1450Sstevel@tonic-gate 				}
1460Sstevel@tonic-gate 			}
1470Sstevel@tonic-gate 			pipein++;
1480Sstevel@tonic-gate 			if (archive) {
1490Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1500Sstevel@tonic-gate 	    "Cannot specify an archive file when reading from a pipe\n"));
1510Sstevel@tonic-gate 				done(1);
1520Sstevel@tonic-gate 			}
1530Sstevel@tonic-gate 		}
1540Sstevel@tonic-gate 		(void) strcpy(magtape, source);
1550Sstevel@tonic-gate 	}
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate void
newtapebuf(size_t size)1591053Smaheshvs newtapebuf(size_t size)
1600Sstevel@tonic-gate {
1610Sstevel@tonic-gate 	size_t nsize;
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	nsize = size * tp_bsize;
1640Sstevel@tonic-gate 	ntrec = size;
1650Sstevel@tonic-gate 	if (nsize <= tbfsize)
1660Sstevel@tonic-gate 		return;
1670Sstevel@tonic-gate 	if (tbf != NULL)
1680Sstevel@tonic-gate 		free(tbf);
1690Sstevel@tonic-gate 	tbf = (char *)malloc(nsize);
1700Sstevel@tonic-gate 	if (tbf == NULL) {
1710Sstevel@tonic-gate 		(void) fprintf(stderr,
1720Sstevel@tonic-gate 		    gettext("Cannot allocate space for buffer\n"));
1730Sstevel@tonic-gate 		done(1);
1740Sstevel@tonic-gate 	}
1750Sstevel@tonic-gate 	tbfsize = nsize;
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate /*
1790Sstevel@tonic-gate  * Verify that the tape drive can be accessed and
1800Sstevel@tonic-gate  * that it actually is a dump tape.
1810Sstevel@tonic-gate  */
1820Sstevel@tonic-gate void
setup(void)1830Sstevel@tonic-gate setup(void)
1840Sstevel@tonic-gate {
1850Sstevel@tonic-gate 	int i, j;
1860Sstevel@tonic-gate 	int32_t *ip;
1870Sstevel@tonic-gate 	struct stat stbuf;
1880Sstevel@tonic-gate 	size_t mapsize;
1890Sstevel@tonic-gate 	char *syment = RESTORESYMTABLE;
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	vprintf(stdout, gettext("Verify volume and initialize maps\n"));
1920Sstevel@tonic-gate 	if (archivefile) {
1930Sstevel@tonic-gate 		mt = open(archivefile, O_RDONLY|O_LARGEFILE);
1940Sstevel@tonic-gate 		if (mt < 0) {
1950Sstevel@tonic-gate 			perror(archivefile);
1960Sstevel@tonic-gate 			done(1);
1970Sstevel@tonic-gate 		}
1980Sstevel@tonic-gate 		volno = 0;
1990Sstevel@tonic-gate 	} else if (host) {
2000Sstevel@tonic-gate 		if ((mt = rmtopen(magtape, O_RDONLY)) < 0) {
2010Sstevel@tonic-gate 			perror(magtape);
2020Sstevel@tonic-gate 			done(1);
2030Sstevel@tonic-gate 		}
2040Sstevel@tonic-gate 		volno = 1;
2050Sstevel@tonic-gate 	} else {
2060Sstevel@tonic-gate 		if (pipein)
2070Sstevel@tonic-gate 			mt = 0;
2080Sstevel@tonic-gate 		else if ((mt = open(magtape, O_RDONLY|O_LARGEFILE)) < 0) {
2090Sstevel@tonic-gate 			perror(magtape);
2100Sstevel@tonic-gate 			done(1);
2110Sstevel@tonic-gate 		}
2120Sstevel@tonic-gate 		volno = 1;
2130Sstevel@tonic-gate 	}
2140Sstevel@tonic-gate 	setdumpnum();
2150Sstevel@tonic-gate 	flsht();
2160Sstevel@tonic-gate 	if (!pipein && !bflag)
2170Sstevel@tonic-gate 		if (archivefile)
2180Sstevel@tonic-gate 			findtapeblksize(ARCHIVE_FILE);
2190Sstevel@tonic-gate 		else
2200Sstevel@tonic-gate 			findtapeblksize(TAPE_FILE);
2210Sstevel@tonic-gate 	if (bflag == 1) {
2220Sstevel@tonic-gate 		tape_rec_size = saved_ntrec * DEV_BSIZE;
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	/*
2260Sstevel@tonic-gate 	 * Get the first header.  If c_magic is NOT NFS_MAGIC or if
2270Sstevel@tonic-gate 	 * the checksum is in error, it will fail.  The magic could then
2280Sstevel@tonic-gate 	 * be either OFS_MAGIC or MTB_MAGIC.  If OFS_MAGIC, assume we
2290Sstevel@tonic-gate 	 * have an old dump, and try to convert it.  If it is MTB_MAGIC, we
2300Sstevel@tonic-gate 	 * procees this after.
2310Sstevel@tonic-gate 	 */
2320Sstevel@tonic-gate 	if ((gethead(&spcl) == FAIL) && (spcl.c_magic != MTB_MAGIC)) {
2330Sstevel@tonic-gate 		bct--; /* push back this block */
2340Sstevel@tonic-gate 		blksread--;
2350Sstevel@tonic-gate 		tapea--;
2360Sstevel@tonic-gate 		cvtflag++;
2370Sstevel@tonic-gate 		if (gethead(&spcl) == FAIL) {
2380Sstevel@tonic-gate 			(void) fprintf(stderr,
2390Sstevel@tonic-gate 			    gettext("Volume is not in dump format\n"));
2400Sstevel@tonic-gate 			done(1);
2410Sstevel@tonic-gate 		}
2420Sstevel@tonic-gate 		(void) fprintf(stderr,
2430Sstevel@tonic-gate 		    gettext("Converting to new file system format.\n"));
2440Sstevel@tonic-gate 	}
2450Sstevel@tonic-gate 	/*
2460Sstevel@tonic-gate 	 * The above gethead will have failed if the magic is
2470Sstevel@tonic-gate 	 * MTB_MAGIC. If that is true, we need to adjust tp_bsize.
2480Sstevel@tonic-gate 	 * We have assumed to this time that tp_bsize was 1024, if
2490Sstevel@tonic-gate 	 * this is a newer dump, get the real tp_bsize from the header,
2500Sstevel@tonic-gate 	 * and recalculate ntrec, numtrec.
2510Sstevel@tonic-gate 	 */
2520Sstevel@tonic-gate 	if (spcl.c_magic == MTB_MAGIC) {
2530Sstevel@tonic-gate 		tp_bsize = spcl.c_tpbsize;
2540Sstevel@tonic-gate 		if ((tp_bsize % TP_BSIZE_MIN != 0) ||
2550Sstevel@tonic-gate 		    (tp_bsize > TP_BSIZE_MAX)) {
2560Sstevel@tonic-gate 			(void) fprintf(stderr,
2570Sstevel@tonic-gate 			    gettext("Volume is not in dump format\n"));
2580Sstevel@tonic-gate 			done(1);
2590Sstevel@tonic-gate 		}
2600Sstevel@tonic-gate 		ntrec = (tape_rec_size/tp_bsize);
2610Sstevel@tonic-gate 		numtrec = ntrec;
2620Sstevel@tonic-gate 		newtapebuf(ntrec);
2630Sstevel@tonic-gate 		bct--; /* push back this block */
2640Sstevel@tonic-gate 		blksread--;
2650Sstevel@tonic-gate 		tapea--;
2660Sstevel@tonic-gate 		/* we have to re-do this in case checksum is wrong */
2670Sstevel@tonic-gate 		if (gethead(&spcl) == FAIL) {
2680Sstevel@tonic-gate 			(void) fprintf(stderr,
2690Sstevel@tonic-gate 			    gettext("Volume is not in dump format\n"));
2700Sstevel@tonic-gate 			done(1);
2710Sstevel@tonic-gate 		}
2720Sstevel@tonic-gate 	}
2730Sstevel@tonic-gate 	if (vflag)
2740Sstevel@tonic-gate 		byteorder_banner(byteorder, stdout);
2750Sstevel@tonic-gate 	if (pipein) {
2760Sstevel@tonic-gate 		endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC :
2770Sstevel@tonic-gate 		    ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC);
2780Sstevel@tonic-gate 		endoftapemark.s_spcl.c_type = TS_END;
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 		/*
2810Sstevel@tonic-gate 		 * include this since the `resync' loop in findinode
2820Sstevel@tonic-gate 		 * expects to find a header with the c_date field
2830Sstevel@tonic-gate 		 * filled in.
2840Sstevel@tonic-gate 		 */
2850Sstevel@tonic-gate 		endoftapemark.s_spcl.c_date = spcl.c_date;
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 		ip = (int32_t *)&endoftapemark;
2880Sstevel@tonic-gate 		/*LINTED [assertion always true]*/
2890Sstevel@tonic-gate 		assert((sizeof (endoftapemark) % sizeof (int32_t)) == 0);
2900Sstevel@tonic-gate 		j = sizeof (endoftapemark) / sizeof (int32_t);
2910Sstevel@tonic-gate 		i = 0;
2920Sstevel@tonic-gate 		do
2930Sstevel@tonic-gate 			i += *ip++;
294*8137SFrank.Batschulat@Sun.COM 		while (--j)
295*8137SFrank.Batschulat@Sun.COM 			;
2960Sstevel@tonic-gate 		endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
2970Sstevel@tonic-gate 	}
2980Sstevel@tonic-gate 	if (vflag && command != 't')
2990Sstevel@tonic-gate 		printdumpinfo();
3000Sstevel@tonic-gate 	dumptime = spcl.c_ddate;
3010Sstevel@tonic-gate 	dumpdate = spcl.c_date;
3020Sstevel@tonic-gate 	if (stat(".", &stbuf) < 0) {
3030Sstevel@tonic-gate 		perror(gettext("cannot stat ."));
3040Sstevel@tonic-gate 		done(1);
3050Sstevel@tonic-gate 	}
3060Sstevel@tonic-gate 	if (stbuf.st_blksize >= tp_bsize && stbuf.st_blksize <= MAXBSIZE) {
3070Sstevel@tonic-gate 		/* LINTED: value fits in a size_t */
3080Sstevel@tonic-gate 		fssize = stbuf.st_blksize;
309*8137SFrank.Batschulat@Sun.COM 	} else {
310*8137SFrank.Batschulat@Sun.COM 		fssize = MAXBSIZE;
3110Sstevel@tonic-gate 	}
312*8137SFrank.Batschulat@Sun.COM 
3130Sstevel@tonic-gate 	if (checkvol(&spcl, 1) == FAIL) {
3140Sstevel@tonic-gate 		(void) fprintf(stderr,
3150Sstevel@tonic-gate 		    gettext("This is not volume 1 of the dump\n"));
3160Sstevel@tonic-gate 		done(1);
3170Sstevel@tonic-gate 	}
3180Sstevel@tonic-gate 	if (readhdr(&spcl) == FAIL)
3190Sstevel@tonic-gate 		panic(gettext("no header after volume mark!\n"));
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	findinode(&spcl);	/* sets curfile, resyncs the tape if need be */
3220Sstevel@tonic-gate 	if (checktype(&spcl, TS_CLRI) == FAIL) {
3230Sstevel@tonic-gate 		(void) fprintf(stderr,
3240Sstevel@tonic-gate 		    gettext("Cannot find file removal list\n"));
3250Sstevel@tonic-gate 		done(1);
3260Sstevel@tonic-gate 	}
3270Sstevel@tonic-gate 	maxino = (unsigned)((spcl.c_count * tp_bsize * NBBY) + 1);
3280Sstevel@tonic-gate 	dprintf(stdout, "maxino = %lu\n", maxino);
3290Sstevel@tonic-gate 	/*
3300Sstevel@tonic-gate 	 * Allocate space for at least MAXINO inodes to allow us
3310Sstevel@tonic-gate 	 * to restore partial dump tapes written before dump was
3320Sstevel@tonic-gate 	 * fixed to write out the entire inode map.
3330Sstevel@tonic-gate 	 */
3340Sstevel@tonic-gate 	if (maxino > ULONG_MAX) {
3350Sstevel@tonic-gate 		(void) fprintf(stderr,
3360Sstevel@tonic-gate 		    gettext("file system too large\n"));
3370Sstevel@tonic-gate 		done(1);
3380Sstevel@tonic-gate 	}
3390Sstevel@tonic-gate 	/* LINTED maxino size-checked above */
3400Sstevel@tonic-gate 	mapsize = (size_t)d_howmany(maxino > MAXINO ? maxino : MAXINO, NBBY);
3410Sstevel@tonic-gate 	beginmap = map = calloc((size_t)1, mapsize);
3420Sstevel@tonic-gate 	if (map == (char *)NIL) {
3430Sstevel@tonic-gate 		(void) fprintf(stderr,
3440Sstevel@tonic-gate 		    gettext("no memory for file removal list\n"));
3450Sstevel@tonic-gate 		done(1);
3460Sstevel@tonic-gate 	}
3470Sstevel@tonic-gate 	endmap = map + mapsize;
3480Sstevel@tonic-gate 	clrimap = map;
3490Sstevel@tonic-gate 	curfile.action = USING;
3500Sstevel@tonic-gate 	continuemap = 1;
3510Sstevel@tonic-gate 	getfile(xtrmap, xtrmapskip);
3520Sstevel@tonic-gate 	if (MAXINO > maxino)
3530Sstevel@tonic-gate 		maxino = MAXINO;
3540Sstevel@tonic-gate 	if (checktype(&spcl, TS_BITS) == FAIL) {
3550Sstevel@tonic-gate 		/* if we have TS_CLRI then no TS_BITS then a TS_END */
3560Sstevel@tonic-gate 		/* then we have an empty dump file */
357*8137SFrank.Batschulat@Sun.COM 		if (gethead(&spcl) == GOOD &&
358*8137SFrank.Batschulat@Sun.COM 		    checktype(&spcl, TS_END) == GOOD) {
3590Sstevel@tonic-gate 			if ((command == 'r') || (command == 'R')) {
3600Sstevel@tonic-gate 				initsymtable(syment);
3610Sstevel@tonic-gate 				dumpsymtable(syment, volno);
3620Sstevel@tonic-gate 			}
3630Sstevel@tonic-gate 			done(0);
3640Sstevel@tonic-gate 		}
3650Sstevel@tonic-gate 		/* otherwise we have an error */
3660Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot find file dump list\n"));
3670Sstevel@tonic-gate 		done(1);
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate 	/* LINTED maxino size-checked above */
3700Sstevel@tonic-gate 	mapsize = (size_t)d_howmany(maxino, NBBY);
3710Sstevel@tonic-gate 	beginmap = map = calloc((size_t)1, mapsize);
3720Sstevel@tonic-gate 	if (map == (char *)NULL) {
3730Sstevel@tonic-gate 		(void) fprintf(stderr,
3740Sstevel@tonic-gate 		    gettext("no memory for file dump list\n"));
3750Sstevel@tonic-gate 		done(1);
3760Sstevel@tonic-gate 	}
3770Sstevel@tonic-gate 	endmap = map + mapsize;
3780Sstevel@tonic-gate 	dumpmap = map;
3790Sstevel@tonic-gate 	curfile.action = USING;
3800Sstevel@tonic-gate 	continuemap = 1;
3810Sstevel@tonic-gate 	getfile(xtrmap, xtrmapskip);
3820Sstevel@tonic-gate 	continuemap = 0;
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate /*
3860Sstevel@tonic-gate  * Initialize fssize variable for 'R' command to work.
3870Sstevel@tonic-gate  */
3880Sstevel@tonic-gate void
setupR(void)3890Sstevel@tonic-gate setupR(void)
3900Sstevel@tonic-gate {
3910Sstevel@tonic-gate 	struct stat stbuf;
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	if (stat(".", &stbuf) < 0) {
3940Sstevel@tonic-gate 		perror(gettext("cannot stat ."));
3950Sstevel@tonic-gate 		done(1);
3960Sstevel@tonic-gate 	}
3970Sstevel@tonic-gate 	if (stbuf.st_blksize >= tp_bsize && stbuf.st_blksize <= MAXBSIZE) {
3980Sstevel@tonic-gate 		/* LINTED: value fits in a size_t */
3990Sstevel@tonic-gate 		fssize = stbuf.st_blksize;
400*8137SFrank.Batschulat@Sun.COM 	} else {
401*8137SFrank.Batschulat@Sun.COM 		fssize = MAXBSIZE;
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate }
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate /*
4060Sstevel@tonic-gate  * Prompt user to load a new dump volume.
4070Sstevel@tonic-gate  * "Nextvol" is the next suggested volume to use.
4080Sstevel@tonic-gate  * This suggested volume is enforced when doing full
4090Sstevel@tonic-gate  * or incremental restores, but can be overrridden by
4100Sstevel@tonic-gate  * the user when only extracting a subset of the files.
4110Sstevel@tonic-gate  *
4120Sstevel@tonic-gate  * first_time is used with archive files and can have 1 of 3 states:
4130Sstevel@tonic-gate  *	FT_STATE_1	Tape has not been read yet
4140Sstevel@tonic-gate  *	FT_STATE_2	Tape has been read but not positioned past directory
4150Sstevel@tonic-gate  *			information
4160Sstevel@tonic-gate  *	FT_STATE_3	Tape has been read and is reading file information
4170Sstevel@tonic-gate  */
4180Sstevel@tonic-gate #define	FT_STATE_1	1
4190Sstevel@tonic-gate #define	FT_STATE_2	2
4200Sstevel@tonic-gate #define	FT_STATE_3	3
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate void
getvol(int nextvol)4231053Smaheshvs getvol(int nextvol)
4240Sstevel@tonic-gate {
4250Sstevel@tonic-gate 	int newvol;
4260Sstevel@tonic-gate 	long savecnt, savetapea, wantnext;
4270Sstevel@tonic-gate 	long i;
4280Sstevel@tonic-gate 	union u_spcl tmpspcl;
4290Sstevel@tonic-gate #define	tmpbuf tmpspcl.s_spcl
4300Sstevel@tonic-gate 	char buf[TP_BSIZE_MAX];
4310Sstevel@tonic-gate 	static int first_time = FT_STATE_1;
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	if (tbf == NULL) {
4340Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
4350Sstevel@tonic-gate 		    "Internal consistency failure in getvol: tbf is NULL\n"));
4360Sstevel@tonic-gate 		done(1);
4370Sstevel@tonic-gate 	}
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	if (nextvol == 1) {
4400Sstevel@tonic-gate 		for (i = 0;  i < MAXTAPES;  i++)
4410Sstevel@tonic-gate 			tapesread[i] = 0;
4420Sstevel@tonic-gate 		gettingfile = 0;
4430Sstevel@tonic-gate 	}
4440Sstevel@tonic-gate 	if (pipein) {
4450Sstevel@tonic-gate 		if (nextvol != 1)
4460Sstevel@tonic-gate 			panic(gettext("changing volumes on pipe input\n"));
4470Sstevel@tonic-gate 		if (volno == 1)
4480Sstevel@tonic-gate 			return;
4490Sstevel@tonic-gate 		goto gethdr;
4500Sstevel@tonic-gate 	}
4510Sstevel@tonic-gate 	savecnt = blksread;	/* ignore volume verification tape i/o */
4520Sstevel@tonic-gate 	savetapea = tapea;
4530Sstevel@tonic-gate again:
4540Sstevel@tonic-gate 	if (pipein)
4550Sstevel@tonic-gate 		done(1); /* pipes do not get a second chance */
4560Sstevel@tonic-gate 	if (command == 'R' || command == 'r' || curfile.action != SKIP) {
4570Sstevel@tonic-gate 		wantnext = 1;
4580Sstevel@tonic-gate 		newvol = nextvol;
4590Sstevel@tonic-gate 	} else {
4600Sstevel@tonic-gate 		wantnext = 0;
4610Sstevel@tonic-gate 		newvol = 0;
4620Sstevel@tonic-gate 	}
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 	if (autoload) {
4650Sstevel@tonic-gate 		if ((volno == 1) && (nextvol == 1)) {
4660Sstevel@tonic-gate 			tapesread[volno-1]++;
4670Sstevel@tonic-gate 			return;
4680Sstevel@tonic-gate 		}
4690Sstevel@tonic-gate 		if (autoload_tape()) {
4704639Svk154806 			wantnext = 1;
4714639Svk154806 			newvol = nextvol;
4720Sstevel@tonic-gate 			goto gethdr;
4730Sstevel@tonic-gate 		}
4740Sstevel@tonic-gate 	}
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	while (newvol <= 0) {
4770Sstevel@tonic-gate 		int n = 0;
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 		for (i = 0;  i < MAXTAPES;  i++)
4800Sstevel@tonic-gate 			if (tapesread[i])
4810Sstevel@tonic-gate 				n++;
4820Sstevel@tonic-gate 		if (n == 0) {
4830Sstevel@tonic-gate 			(void) fprintf(stderr, "%s", gettext(
4840Sstevel@tonic-gate "You have not read any volumes yet.\n\
4850Sstevel@tonic-gate Unless you know which volume your file(s) are on you should start\n\
4860Sstevel@tonic-gate with the last volume and work towards the first.\n"));
4870Sstevel@tonic-gate 		} else {
4880Sstevel@tonic-gate 			(void) fprintf(stderr,
4890Sstevel@tonic-gate 			    gettext("You have read volumes"));
4900Sstevel@tonic-gate 			(void) strcpy(tbf, ": ");
4910Sstevel@tonic-gate 			for (i = 0; i < MAXTAPES; i++)
4920Sstevel@tonic-gate 				if (tapesread[i]) {
4930Sstevel@tonic-gate 					(void) fprintf(stderr, "%s%ld",
4940Sstevel@tonic-gate 					    tbf, i+1);
4950Sstevel@tonic-gate 					(void) strcpy(tbf, ", ");
4960Sstevel@tonic-gate 				}
4970Sstevel@tonic-gate 			(void) fprintf(stderr, "\n");
4980Sstevel@tonic-gate 		}
4990Sstevel@tonic-gate 		do {
5000Sstevel@tonic-gate 			(void) fprintf(stderr,
5010Sstevel@tonic-gate 			    gettext("Specify next volume #: "));
5020Sstevel@tonic-gate 			(void) fflush(stderr);
5030Sstevel@tonic-gate 			/* LINTED tbfsize is limited to a few MB */
5040Sstevel@tonic-gate 			(void) fgets(tbf, (int)tbfsize, terminal);
5050Sstevel@tonic-gate 		} while (!feof(terminal) && tbf[0] == '\n');
5060Sstevel@tonic-gate 		if (feof(terminal))
5070Sstevel@tonic-gate 			done(1);
5080Sstevel@tonic-gate 		newvol = atoi(tbf);
5090Sstevel@tonic-gate 		if (newvol <= 0) {
5100Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
5110Sstevel@tonic-gate 			    "Volume numbers are positive numerics\n"));
5120Sstevel@tonic-gate 		}
5130Sstevel@tonic-gate 		if (newvol > MAXTAPES) {
5140Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
5150Sstevel@tonic-gate 			    "This program can only deal with %d volumes\n"),
5160Sstevel@tonic-gate 			    MAXTAPES);
5170Sstevel@tonic-gate 			newvol = 0;
5180Sstevel@tonic-gate 		}
5190Sstevel@tonic-gate 	}
5200Sstevel@tonic-gate 	if (newvol == volno) {
5210Sstevel@tonic-gate 		tapesread[volno-1]++;
5220Sstevel@tonic-gate 		return;
5230Sstevel@tonic-gate 	}
524426Srm88369 	closemt(ALLOW_OFFLINE);
5250Sstevel@tonic-gate 	/*
5260Sstevel@tonic-gate 	 * XXX: if we are switching devices, we should probably try
5270Sstevel@tonic-gate 	 * the device once without prompting to enable unattended
5280Sstevel@tonic-gate 	 * operation.
5290Sstevel@tonic-gate 	 */
5300Sstevel@tonic-gate 	if (host)
5310Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
5320Sstevel@tonic-gate "Mount volume %d\nthen enter volume name on host %s (default: %s) "),
5330Sstevel@tonic-gate 		    newvol, host,  magtape);
5340Sstevel@tonic-gate 	else
5350Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
5360Sstevel@tonic-gate 		    "Mount volume %d\nthen enter volume name (default: %s) "),
5370Sstevel@tonic-gate 		    newvol, magtape);
5380Sstevel@tonic-gate 	(void) fflush(stderr);
5390Sstevel@tonic-gate 	/* LINTED tbfsize is limited to a few MB */
5400Sstevel@tonic-gate 	(void) fgets(tbf, (int)tbfsize, terminal);
5410Sstevel@tonic-gate 	if (feof(terminal))
5420Sstevel@tonic-gate 		done(1);
5430Sstevel@tonic-gate 	/*
5440Sstevel@tonic-gate 	 * XXX We don't allow rotating among tape hosts, just drives.
5450Sstevel@tonic-gate 	 */
5460Sstevel@tonic-gate 	if (tbf[0] != '\n') {
5470Sstevel@tonic-gate 		(void) strncpy(magtape, tbf, sizeof (magtape));
5480Sstevel@tonic-gate 		magtape[sizeof (magtape) - 1] = '\0';
5490Sstevel@tonic-gate 		/* LINTED unsigned -> signed conversion ok */
5500Sstevel@tonic-gate 		i = (int)strlen(magtape);
5510Sstevel@tonic-gate 		if (magtape[i - 1] == '\n')
5520Sstevel@tonic-gate 			magtape[i - 1] = '\0';
5530Sstevel@tonic-gate 	}
5540Sstevel@tonic-gate 	if ((host != NULL && (mt = rmtopen(magtape, O_RDONLY)) == -1) ||
5550Sstevel@tonic-gate 	    (host == NULL &&
5564639Svk154806 	    (mt = open(magtape, O_RDONLY|O_LARGEFILE)) == -1)) {
5570Sstevel@tonic-gate 		int error = errno;
5580Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot open %s: %s\n"),
5590Sstevel@tonic-gate 		    magtape, strerror(error));
5600Sstevel@tonic-gate 		volno = -1;
5610Sstevel@tonic-gate 		goto again;
5620Sstevel@tonic-gate 	}
5630Sstevel@tonic-gate gethdr:
5640Sstevel@tonic-gate 	volno = newvol;
5650Sstevel@tonic-gate 	setdumpnum();
5660Sstevel@tonic-gate 	flsht();
5670Sstevel@tonic-gate 	if (!pipein && !bflag && archivefile && (first_time == FT_STATE_1)) {
5680Sstevel@tonic-gate 		first_time = FT_STATE_2;
5690Sstevel@tonic-gate 		findtapeblksize(TAPE_FILE);
5700Sstevel@tonic-gate 	}
5710Sstevel@tonic-gate 	if (readhdr(&tmpbuf) == FAIL) {
5720Sstevel@tonic-gate 		(void) fprintf(stderr,
5730Sstevel@tonic-gate 		    gettext("volume is not in dump format\n"));
5740Sstevel@tonic-gate 		volno = 0;
5750Sstevel@tonic-gate 		goto again;
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate 	if (checkvol(&tmpbuf, volno) == FAIL) {
5780Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Wrong volume (%d)\n"),
5790Sstevel@tonic-gate 		    tmpbuf.c_volume);
5800Sstevel@tonic-gate 		volno = 0;
5810Sstevel@tonic-gate 		goto again;
5820Sstevel@tonic-gate 	}
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	if (((time_t)(tmpbuf.c_date) != dumpdate) ||
5850Sstevel@tonic-gate 	    ((time_t)(tmpbuf.c_ddate) != dumptime)) {
5860Sstevel@tonic-gate 		char *tmp_ct;
5870Sstevel@tonic-gate 		time_t lc_date = (time_t)tmpbuf.c_date;
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 		/*
5900Sstevel@tonic-gate 		 * This is used to save the return value from lctime(),
5910Sstevel@tonic-gate 		 * since that's volatile across lctime() invocations.
5920Sstevel@tonic-gate 		 */
5930Sstevel@tonic-gate 		tmp_ct = strdup(lctime(&lc_date));
5940Sstevel@tonic-gate 		if (tmp_ct == (char *)0) {
5950Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
5960Sstevel@tonic-gate 			    "Cannot allocate space for time string\n"));
5970Sstevel@tonic-gate 			done(1);
5980Sstevel@tonic-gate 		}
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 		(void) fprintf(stderr,
6010Sstevel@tonic-gate 		    gettext("Wrong dump date\n\tgot: %s\twanted: %s"),
6020Sstevel@tonic-gate 		    tmp_ct,  lctime(&dumpdate));
6030Sstevel@tonic-gate 		volno = 0;
6040Sstevel@tonic-gate 		free(tmp_ct);
6050Sstevel@tonic-gate 		goto again;
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 	tapesread[volno-1]++;
6080Sstevel@tonic-gate 	blksread = savecnt;
6090Sstevel@tonic-gate 	tapea = savetapea;
6100Sstevel@tonic-gate 	/*
6110Sstevel@tonic-gate 	 * If continuing from the previous volume, skip over any
6120Sstevel@tonic-gate 	 * blocks read already at the end of the previous volume.
6130Sstevel@tonic-gate 	 *
6140Sstevel@tonic-gate 	 * If coming to this volume at random, skip to the beginning
6150Sstevel@tonic-gate 	 * of the next record.
6160Sstevel@tonic-gate 	 */
6170Sstevel@tonic-gate 	if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
6180Sstevel@tonic-gate 		if (!wantnext) {
6190Sstevel@tonic-gate 			if (archivefile && first_time == FT_STATE_2) {
6200Sstevel@tonic-gate 				first_time = FT_STATE_3;
6210Sstevel@tonic-gate 			}
6220Sstevel@tonic-gate 			recsread = tmpbuf.c_firstrec;
6230Sstevel@tonic-gate 			tapea = tmpbuf.c_tapea;
6240Sstevel@tonic-gate 			dprintf(stdout,
6250Sstevel@tonic-gate 			    "restore skipping %d records\n",
6260Sstevel@tonic-gate 			    tmpbuf.c_count);
6270Sstevel@tonic-gate 			for (i = tmpbuf.c_count; i > 0; i--)
6280Sstevel@tonic-gate 				readtape(buf);
6290Sstevel@tonic-gate 		} else if (tmpbuf.c_firstrec != 0) {
6300Sstevel@tonic-gate 			savecnt = blksread;
6310Sstevel@tonic-gate 			savetapea = tapea;
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 			if (archivefile && first_time == FT_STATE_2) {
6340Sstevel@tonic-gate 				/*
6350Sstevel@tonic-gate 				 * subtract 2, 1 for archive file's TS_END
6360Sstevel@tonic-gate 				 * and 1 for tape's TS_TAPE
6370Sstevel@tonic-gate 				 */
6380Sstevel@tonic-gate 				first_time = FT_STATE_3;
6390Sstevel@tonic-gate 				i = tapea - tmpbuf.c_tapea - 2;
6400Sstevel@tonic-gate 			} else {
6410Sstevel@tonic-gate 				i = tapea - tmpbuf.c_tapea;
6420Sstevel@tonic-gate 			}
6430Sstevel@tonic-gate 			if (i > 0)
6440Sstevel@tonic-gate 				dprintf(stdout, gettext(
6450Sstevel@tonic-gate 				    "restore skipping %d duplicate records\n"),
6464639Svk154806 				    i);
6470Sstevel@tonic-gate 			else if (i < 0)
6480Sstevel@tonic-gate 				dprintf(stdout, gettext(
6490Sstevel@tonic-gate 				    "restore duplicate record botch (%d)\n"),
6504639Svk154806 				    i);
6510Sstevel@tonic-gate 			while (--i >= 0)
6520Sstevel@tonic-gate 				readtape(buf);
6530Sstevel@tonic-gate 			blksread = savecnt;
6540Sstevel@tonic-gate 			tapea = savetapea + 1; /* <= (void) gethead() below */
6550Sstevel@tonic-gate 		}
6560Sstevel@tonic-gate 	}
6570Sstevel@tonic-gate 	if (curfile.action == USING) {
6580Sstevel@tonic-gate 		if (volno == 1)
6590Sstevel@tonic-gate 			panic(gettext("active file into volume 1\n"));
6600Sstevel@tonic-gate 		return;
6610Sstevel@tonic-gate 	}
6620Sstevel@tonic-gate 	(void) gethead(&spcl);
6630Sstevel@tonic-gate 	findinode(&spcl); /* do we always restart files in full? */
6640Sstevel@tonic-gate 	if (gettingfile) { /* i.e. will we lose metadata? */
6650Sstevel@tonic-gate 		gettingfile = 0;
6660Sstevel@tonic-gate 		longjmp(restart, 1); /* will this set f1 & f2? */
6670Sstevel@tonic-gate 	}
6680Sstevel@tonic-gate }
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate /*
6710Sstevel@tonic-gate  * handle multiple dumps per tape by skipping forward to the
6720Sstevel@tonic-gate  * appropriate one.  Note we don't use absolute positioning,
6730Sstevel@tonic-gate  * as that may take a very long time.
6740Sstevel@tonic-gate  */
6750Sstevel@tonic-gate static void
setdumpnum(void)6760Sstevel@tonic-gate setdumpnum(void)
6770Sstevel@tonic-gate {
6780Sstevel@tonic-gate 	struct mtop tcom;
6790Sstevel@tonic-gate 	int retval;
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	if (dumpnum == 1 || volno != 1)
6820Sstevel@tonic-gate 		return;
6830Sstevel@tonic-gate 	if (pipein) {
6840Sstevel@tonic-gate 		(void) fprintf(stderr,
6850Sstevel@tonic-gate 		    gettext("Cannot have multiple dumps on pipe input\n"));
6860Sstevel@tonic-gate 		done(1);
6870Sstevel@tonic-gate 	}
6880Sstevel@tonic-gate 	tcom.mt_op = MTFSF;
6890Sstevel@tonic-gate 	tcom.mt_count = dumpnum - 1;
6900Sstevel@tonic-gate 	if (host)
6910Sstevel@tonic-gate 		retval = rmtioctl(MTFSF, dumpnum - 1);
6920Sstevel@tonic-gate 	else
6930Sstevel@tonic-gate 		retval = ioctl(mt, (int)MTIOCTOP, (char *)&tcom);
6940Sstevel@tonic-gate 	if (retval < 0)
6950Sstevel@tonic-gate 		perror("ioctl MTFSF");
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate void
printdumpinfo(void)6990Sstevel@tonic-gate printdumpinfo(void)
7000Sstevel@tonic-gate {
7010Sstevel@tonic-gate 	int i;
7020Sstevel@tonic-gate 	time_t date;
7030Sstevel@tonic-gate 	static char *epoch = NULL;
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	if (epoch == NULL) {
7060Sstevel@tonic-gate 		epoch = strdup(gettext("the epoch\n"));
7070Sstevel@tonic-gate 		if (epoch == NULL) {
7080Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Out of memory\n"));
7090Sstevel@tonic-gate 			return;
7100Sstevel@tonic-gate 		}
7110Sstevel@tonic-gate 	}
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	date = (time_t)dumpinfo.c_date;
7140Sstevel@tonic-gate 	(void) fprintf(stdout,
7150Sstevel@tonic-gate 	    gettext("Dump   date: %s"), lctime(&date));
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	date = (time_t)dumpinfo.c_ddate;
7180Sstevel@tonic-gate 	(void) fprintf(stdout, gettext("Dumped from: %s"),
7190Sstevel@tonic-gate 	    (dumpinfo.c_ddate == 0) ? epoch : lctime(&date));
7200Sstevel@tonic-gate 	if (hostinfo) {
7210Sstevel@tonic-gate 		(void) fprintf(stdout,
7220Sstevel@tonic-gate 		    gettext("Level %d dump of %s on %.*s:%s\n"),
7230Sstevel@tonic-gate 		    dumpinfo.c_level, dumpinfo.c_filesys,
7240Sstevel@tonic-gate 		    sizeof (dumpinfo.c_host), dumpinfo.c_host, dumpinfo.c_dev);
7250Sstevel@tonic-gate 		(void) fprintf(stdout,
7260Sstevel@tonic-gate 		    gettext("Label: %.*s\n"),
7270Sstevel@tonic-gate 		    sizeof (dumpinfo.c_label), dumpinfo.c_label);
7280Sstevel@tonic-gate 	}
7290Sstevel@tonic-gate 	if (inodeinfo) {
7300Sstevel@tonic-gate 		(void) fprintf(stdout,
7310Sstevel@tonic-gate 		    gettext("Starting inode numbers by volume:\n"));
7320Sstevel@tonic-gate 		for (i = 1; i <= dumpinfo.c_volume; i++)
7330Sstevel@tonic-gate 			(void) fprintf(stdout, gettext("\tVolume %d: %6d\n"),
7340Sstevel@tonic-gate 			    i, dumpinfo.c_inos[i]);
7350Sstevel@tonic-gate 	}
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate 
7381053Smaheshvs int
extractfile(char * name)7391053Smaheshvs extractfile(char *name)
7400Sstevel@tonic-gate {
7410Sstevel@tonic-gate 	static int complained_chown = 0;
7420Sstevel@tonic-gate 	static int complained_lchown = 0;
7430Sstevel@tonic-gate 	static int complained_chmod = 0;
7440Sstevel@tonic-gate 	static int complained_utime = 0;
7450Sstevel@tonic-gate 	static int complained_mknod = 0;
7460Sstevel@tonic-gate 	mode_t mode;
7470Sstevel@tonic-gate 	time_t timep[2];
7480Sstevel@tonic-gate 	struct entry *ep;
7490Sstevel@tonic-gate 	uid_t uid;
7500Sstevel@tonic-gate 	gid_t gid;
7510Sstevel@tonic-gate 	char *errmsg;
7520Sstevel@tonic-gate 	int result, saverr;
7530Sstevel@tonic-gate 	dev_t full_dev;
7540Sstevel@tonic-gate 	int dfd;
7550Sstevel@tonic-gate 	char *rname;
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	curfile.name = name;
7580Sstevel@tonic-gate 	curfile.action = USING;
7590Sstevel@tonic-gate 	timep[0] = (time_t)curfile.dip->di_atime;
7600Sstevel@tonic-gate 	timep[1] = (time_t)curfile.dip->di_mtime;
7610Sstevel@tonic-gate 	mode = curfile.dip->di_mode;
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	uid = curfile.dip->di_suid == UID_LONG ?
7644639Svk154806 	    curfile.dip->di_uid : (uid_t)curfile.dip->di_suid;
7650Sstevel@tonic-gate 	gid = curfile.dip->di_sgid == GID_LONG ?
7664639Svk154806 	    curfile.dip->di_gid : (gid_t)curfile.dip->di_sgid;
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	resolve(name, &dfd, &rname);
7690Sstevel@tonic-gate 	if (dfd != AT_FDCWD) {
7700Sstevel@tonic-gate 		if (fchdir(dfd) < 0) {
7710Sstevel@tonic-gate 			saverr = errno;
7720Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
7734639Svk154806 			    "%s: unable to set attribute context: %s\n"),
7744639Svk154806 			    rname, strerror(saverr));
7750Sstevel@tonic-gate 			skipfile();
7760Sstevel@tonic-gate 			(void) close(dfd);
7770Sstevel@tonic-gate 			return (FAIL);
7780Sstevel@tonic-gate 		}
7790Sstevel@tonic-gate 	}
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	switch (mode & IFMT) {
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 	default:
7840Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: unknown file mode 0%lo\n"),
7850Sstevel@tonic-gate 		    rname, (ulong_t)(mode&IFMT));
7860Sstevel@tonic-gate 		skipfile();
7870Sstevel@tonic-gate 		result = FAIL;
7880Sstevel@tonic-gate 		break;
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	case IFSOCK:
7910Sstevel@tonic-gate 		vprintf(stdout, gettext("skipped socket %s\n"), rname);
7920Sstevel@tonic-gate 		skipfile();
7930Sstevel@tonic-gate 		result = GOOD;
7940Sstevel@tonic-gate 		break;
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	case IFDIR:
7970Sstevel@tonic-gate 		if (mflag) {
7980Sstevel@tonic-gate 			ep = lookupname(name);
7990Sstevel@tonic-gate 			if (ep == NIL || ep->e_flags & EXTRACT) {
8000Sstevel@tonic-gate 				panic(gettext(
8010Sstevel@tonic-gate 				    "directory %s was not restored\n"),
8020Sstevel@tonic-gate 				    rname);
8030Sstevel@tonic-gate 				skipfile();
8040Sstevel@tonic-gate 				result = FAIL;
8050Sstevel@tonic-gate 				break;
8060Sstevel@tonic-gate 			}
8070Sstevel@tonic-gate 			skipfile();
8080Sstevel@tonic-gate 			result = GOOD;
8090Sstevel@tonic-gate 			break;
8100Sstevel@tonic-gate 		}
8110Sstevel@tonic-gate 		vprintf(stdout, gettext("extract file %s\n"), rname);
8120Sstevel@tonic-gate 		result = genliteraldir(rname, curfile.ino);
8130Sstevel@tonic-gate 		break;
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	case IFLNK:
8160Sstevel@tonic-gate 		lnkbuf[0] = '\0';
8170Sstevel@tonic-gate 		pathlen = 0;
8180Sstevel@tonic-gate 		getfile(xtrlnkfile, xtrlnkskip);
8190Sstevel@tonic-gate 		if (pathlen == 0) {
8200Sstevel@tonic-gate 			vprintf(stdout, gettext(
8214639Svk154806 			    "%s: zero length symbolic link (ignored)\n"),
8224639Svk154806 			    rname);
8230Sstevel@tonic-gate 			result = GOOD;
8240Sstevel@tonic-gate 			break;
8250Sstevel@tonic-gate 		}
8260Sstevel@tonic-gate 		if ((result = lf_linkit(lnkbuf, rname, SYMLINK)) != GOOD)
8270Sstevel@tonic-gate 			break;
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 		/* 1254700: set uid/gid (previously missing)  */
8300Sstevel@tonic-gate 		if (lchown(rname, uid, gid) < 0 && !complained_lchown) {
8310Sstevel@tonic-gate 			/* Just a warning */
8320Sstevel@tonic-gate 			saverr = errno;
8330Sstevel@tonic-gate 			errmsg = gettext(
8340Sstevel@tonic-gate 			    "Unable to restore ownership of symlink %s: %s\n");
8350Sstevel@tonic-gate 			(void) fprintf(stderr, errmsg,
8360Sstevel@tonic-gate 			    rname, strerror(saverr));
8370Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
8380Sstevel@tonic-gate 			    "Additional such failures will be ignored.\n"));
8390Sstevel@tonic-gate 			complained_lchown = 1;
8400Sstevel@tonic-gate 		}
8410Sstevel@tonic-gate 		metaset(rname);
8420Sstevel@tonic-gate 		result = GOOD;
8430Sstevel@tonic-gate 		break;
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	case IFCHR:
8460Sstevel@tonic-gate 	case IFBLK:
8470Sstevel@tonic-gate 	case IFIFO:
8480Sstevel@tonic-gate 		vprintf(stdout, gettext("extract special file %s\n"), rname);
8490Sstevel@tonic-gate 		/* put device rdev into dev_t expanded format */
8500Sstevel@tonic-gate 		/* XXX does this always do the right thing? */
8510Sstevel@tonic-gate 		/* XXX does dump do the right thing? */
8520Sstevel@tonic-gate 		if (((curfile.dip->di_ordev & 0xFFFF0000) == 0) ||
8530Sstevel@tonic-gate 		    ((curfile.dip->di_ordev & 0xFFFF0000) == 0xFFFF0000)) {
8540Sstevel@tonic-gate 			full_dev = expdev((unsigned)(curfile.dip->di_ordev));
8550Sstevel@tonic-gate 		} else {
8560Sstevel@tonic-gate 			/* LINTED sign extension ok */
8570Sstevel@tonic-gate 			full_dev = (unsigned)(curfile.dip->di_ordev);
8580Sstevel@tonic-gate 		}
8590Sstevel@tonic-gate 
8601053Smaheshvs 		if (mknod(rname, mode, full_dev) < 0) {
8610Sstevel@tonic-gate 			struct stat64 s[1];
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 			saverr = errno;
8640Sstevel@tonic-gate 			if ((stat64(rname, s)) ||
8650Sstevel@tonic-gate 			    ((s->st_mode & S_IFMT) != (mode & S_IFMT)) ||
8660Sstevel@tonic-gate 			    (s->st_rdev != full_dev)) {
8670Sstevel@tonic-gate 				if (saverr != EPERM || !complained_mknod) {
8680Sstevel@tonic-gate 					(void) fprintf(stderr, "%s: ", rname);
8690Sstevel@tonic-gate 					(void) fflush(stderr);
8700Sstevel@tonic-gate 					errno = saverr;
8710Sstevel@tonic-gate 					perror(gettext(
8720Sstevel@tonic-gate 					    "cannot create special file"));
8730Sstevel@tonic-gate 					if (saverr == EPERM) {
8740Sstevel@tonic-gate 						(void) fprintf(stderr, gettext(
8750Sstevel@tonic-gate 			    "Additional such failures will be ignored.\n"));
8760Sstevel@tonic-gate 						complained_mknod = 1;
8770Sstevel@tonic-gate 					}
8780Sstevel@tonic-gate 				}
8790Sstevel@tonic-gate 				skipfile();
8800Sstevel@tonic-gate 				result = FAIL;
8810Sstevel@tonic-gate 				break;
8820Sstevel@tonic-gate 			}
8830Sstevel@tonic-gate 		}
8840Sstevel@tonic-gate 		if (chown(rname, uid, gid) < 0 && !complained_chown) {
8850Sstevel@tonic-gate 			/* Just a warning */
8860Sstevel@tonic-gate 			saverr = errno;
8870Sstevel@tonic-gate 			errmsg = gettext(
8880Sstevel@tonic-gate 			    "Unable to restore ownership of %s: %s\n");
8890Sstevel@tonic-gate 			(void) fprintf(stderr, errmsg,
8900Sstevel@tonic-gate 			    rname, strerror(saverr));
8910Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
8920Sstevel@tonic-gate 			    "Additional such failures will be ignored.\n"));
8930Sstevel@tonic-gate 			complained_chown = 1;
8940Sstevel@tonic-gate 		}
8950Sstevel@tonic-gate 		if (chmod(rname, mode) < 0 && !complained_chmod) {
8960Sstevel@tonic-gate 			saverr = errno;
8970Sstevel@tonic-gate 			errmsg = gettext(
8980Sstevel@tonic-gate 			    "Unable to restore permissions on %s: %s\n");
8990Sstevel@tonic-gate 			(void) fprintf(stderr, errmsg,
9000Sstevel@tonic-gate 			    rname, strerror(saverr));
9010Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
9020Sstevel@tonic-gate 			    "Additional such failures will be ignored.\n"));
9030Sstevel@tonic-gate 			complained_chmod = 1;
9040Sstevel@tonic-gate 		}
9050Sstevel@tonic-gate 		skipfile();
9060Sstevel@tonic-gate 		metaset(rname); /* skipfile() got the metadata, if any */
9070Sstevel@tonic-gate 		if (utime(rname, (struct utimbuf *)timep) < 0 &&
9080Sstevel@tonic-gate 		    !complained_utime) {
9090Sstevel@tonic-gate 			saverr = errno;
9100Sstevel@tonic-gate 			errmsg = gettext(
9110Sstevel@tonic-gate 			    "Unable to restore times on %s: %s\n");
9120Sstevel@tonic-gate 			(void) fprintf(stderr, errmsg,
9130Sstevel@tonic-gate 			    rname, strerror(saverr));
9140Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
9150Sstevel@tonic-gate 			    "Additional such failures will be ignored.\n"));
9160Sstevel@tonic-gate 			complained_utime = 1;
9170Sstevel@tonic-gate 		}
9180Sstevel@tonic-gate 		result = GOOD;
9190Sstevel@tonic-gate 		break;
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 	case IFREG:
9220Sstevel@tonic-gate 		vprintf(stdout, gettext("extract file %s\n"), rname);
923*8137SFrank.Batschulat@Sun.COM 
924*8137SFrank.Batschulat@Sun.COM 		/*
925*8137SFrank.Batschulat@Sun.COM 		 * perform a restrictive creat(2) initally, we'll
926*8137SFrank.Batschulat@Sun.COM 		 * fchmod(2) according to the archive later after
927*8137SFrank.Batschulat@Sun.COM 		 * we've written the blocks.
928*8137SFrank.Batschulat@Sun.COM 		 */
929*8137SFrank.Batschulat@Sun.COM 		ofile = creat64(rname, 0600);
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 		if (ofile < 0) {
9320Sstevel@tonic-gate 			saverr = errno;
9330Sstevel@tonic-gate 			errmsg = gettext("cannot create file");
9340Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: ", rname);
9350Sstevel@tonic-gate 			(void) fflush(stderr);
9360Sstevel@tonic-gate 			errno = saverr;
9370Sstevel@tonic-gate 			perror(errmsg);
9380Sstevel@tonic-gate 			skipfile();
9390Sstevel@tonic-gate 			result = FAIL;
9400Sstevel@tonic-gate 			break;
9410Sstevel@tonic-gate 		}
9420Sstevel@tonic-gate 		if (fchown(ofile, uid, gid) < 0 && !complained_chown) {
9430Sstevel@tonic-gate 			/* Just a warning */
9440Sstevel@tonic-gate 			saverr = errno;
9450Sstevel@tonic-gate 			errmsg = gettext(
9460Sstevel@tonic-gate 			    "Unable to restore ownership of %s: %s\n");
9470Sstevel@tonic-gate 			(void) fprintf(stderr, errmsg,
9480Sstevel@tonic-gate 			    rname, strerror(saverr));
9490Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
9500Sstevel@tonic-gate 			    "Additional such failures will be ignored.\n"));
9510Sstevel@tonic-gate 			complained_chown = 1;
9520Sstevel@tonic-gate 		}
953*8137SFrank.Batschulat@Sun.COM 
954*8137SFrank.Batschulat@Sun.COM 		getfile(xtrfile, xtrskip);
955*8137SFrank.Batschulat@Sun.COM 		metaset(rname);
956*8137SFrank.Batschulat@Sun.COM 
957*8137SFrank.Batschulat@Sun.COM 		/*
958*8137SFrank.Batschulat@Sun.COM 		 * the fchmod(2) has to come after getfile() as some POSIX
959*8137SFrank.Batschulat@Sun.COM 		 * implementations clear the S_ISUID and S_ISGID bits of the
960*8137SFrank.Batschulat@Sun.COM 		 * file after every write(2).
961*8137SFrank.Batschulat@Sun.COM 		 */
9620Sstevel@tonic-gate 		if (fchmod(ofile, mode) < 0 && !complained_chmod) {
9630Sstevel@tonic-gate 			saverr = errno;
9640Sstevel@tonic-gate 			errmsg = gettext(
9650Sstevel@tonic-gate 			    "Unable to restore permissions on %s: %s\n");
9660Sstevel@tonic-gate 			(void) fprintf(stderr, errmsg,
9670Sstevel@tonic-gate 			    rname, strerror(saverr));
9680Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
9690Sstevel@tonic-gate 			    "Additional such failures will be ignored.\n"));
9700Sstevel@tonic-gate 			complained_chmod = 1;
9710Sstevel@tonic-gate 		}
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 		/*
9740Sstevel@tonic-gate 		 * Some errors don't get reported until we close(2), so
9750Sstevel@tonic-gate 		 * check for them.
9760Sstevel@tonic-gate 		 * XXX unlink the file if an error is reported?
9770Sstevel@tonic-gate 		 */
9780Sstevel@tonic-gate 		if (close(ofile) < 0) {
9790Sstevel@tonic-gate 			saverr = errno;
9800Sstevel@tonic-gate 			errmsg = gettext("error closing file");
9810Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: ", rname);
9820Sstevel@tonic-gate 			(void) fflush(stderr);
9830Sstevel@tonic-gate 			errno = saverr;
9840Sstevel@tonic-gate 			perror(errmsg);
9850Sstevel@tonic-gate 			result = FAIL;
9860Sstevel@tonic-gate 			break;
9870Sstevel@tonic-gate 		}
9880Sstevel@tonic-gate 		if (utime(rname, (struct utimbuf *)timep) < 0 &&
9890Sstevel@tonic-gate 		    !complained_utime) {
9900Sstevel@tonic-gate 			saverr = errno;
9910Sstevel@tonic-gate 			errmsg = gettext(
9920Sstevel@tonic-gate 			    "Unable to restore times on %s: %s\n");
9930Sstevel@tonic-gate 			(void) fprintf(stderr, errmsg,
9940Sstevel@tonic-gate 			    rname, strerror(saverr));
9950Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
9960Sstevel@tonic-gate 			    "Additional such failures will be ignored.\n"));
9970Sstevel@tonic-gate 			complained_utime = 1;
9980Sstevel@tonic-gate 		}
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 		result = GOOD;
10010Sstevel@tonic-gate 		break;
10020Sstevel@tonic-gate 	}
10030Sstevel@tonic-gate 	if (dfd != AT_FDCWD) {
10040Sstevel@tonic-gate 		fchdir(savepwd);
10050Sstevel@tonic-gate 		(void) close(dfd);
10060Sstevel@tonic-gate 	}
10070Sstevel@tonic-gate 	return (result);
10080Sstevel@tonic-gate }
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate /*
10110Sstevel@tonic-gate  * skip over bit maps on the tape
10120Sstevel@tonic-gate  */
10130Sstevel@tonic-gate void
skipmaps(void)10140Sstevel@tonic-gate skipmaps(void)
10150Sstevel@tonic-gate {
10160Sstevel@tonic-gate 	continuemap = 1;
10170Sstevel@tonic-gate 	while (checktype(&spcl, TS_CLRI) == GOOD ||
10180Sstevel@tonic-gate 	    checktype(&spcl, TS_BITS) == GOOD)
10190Sstevel@tonic-gate 		skipfile();
10200Sstevel@tonic-gate 	continuemap = 0;
10210Sstevel@tonic-gate }
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate /*
10240Sstevel@tonic-gate  * skip over a file on the tape
10250Sstevel@tonic-gate  */
10260Sstevel@tonic-gate void
skipfile(void)10270Sstevel@tonic-gate skipfile(void)
10280Sstevel@tonic-gate {
10290Sstevel@tonic-gate 	curfile.action = SKIP;
10300Sstevel@tonic-gate 	getfile(null, null);
10310Sstevel@tonic-gate }
10320Sstevel@tonic-gate /*
10330Sstevel@tonic-gate  * Do the file extraction, calling the supplied functions
10340Sstevel@tonic-gate  * with the blocks
10350Sstevel@tonic-gate  */
10360Sstevel@tonic-gate void
getfile(void (* f1)(),void (* f2)())10371053Smaheshvs getfile(void (*f1)(), void (*f2)())
10380Sstevel@tonic-gate {
10390Sstevel@tonic-gate 	int i;
10400Sstevel@tonic-gate 	size_t curblk = 0;
10410Sstevel@tonic-gate 	offset_t size = (offset_t)spcl.c_dinode.di_size;
10420Sstevel@tonic-gate 	static char clearedbuf[MAXBSIZE];
10430Sstevel@tonic-gate 	char buf[TP_BSIZE_MAX];
10440Sstevel@tonic-gate 	char *bufptr;
10450Sstevel@tonic-gate 	char junk[TP_BSIZE_MAX];
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	assert(MAXBSIZE >= tp_bsize);
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate 	metaset(NULL);	/* flush old metadata */
10500Sstevel@tonic-gate 	if (checktype(&spcl, TS_END) == GOOD) {
10510Sstevel@tonic-gate 		panic(gettext("ran off end of volume\n"));
10520Sstevel@tonic-gate 		return;
10530Sstevel@tonic-gate 	}
10540Sstevel@tonic-gate 	if (ishead(&spcl) == FAIL) {
10550Sstevel@tonic-gate 		panic(gettext("not at beginning of a file\n"));
10560Sstevel@tonic-gate 		return;
10570Sstevel@tonic-gate 	}
10580Sstevel@tonic-gate 	metacheck(&spcl); /* check for metadata in header */
10590Sstevel@tonic-gate 	if (!gettingfile && setjmp(restart) != 0) {
10600Sstevel@tonic-gate 		gettingfile = 0;	/* paranoia; longjmp'er should do */
10610Sstevel@tonic-gate 		return;
10620Sstevel@tonic-gate 	}
10630Sstevel@tonic-gate 	gettingfile++;
10640Sstevel@tonic-gate loop:
10650Sstevel@tonic-gate 	if ((spcl.c_dinode.di_mode & IFMT) == IFSHAD) {
10660Sstevel@tonic-gate 		f1 = xtrmeta;
10670Sstevel@tonic-gate 		f2 = metaskip;
10680Sstevel@tonic-gate 	}
10690Sstevel@tonic-gate 	for (i = 0, bufptr = buf; i < spcl.c_count; i++) {
10700Sstevel@tonic-gate 		if ((i >= TP_NINDIR) || (spcl.c_addr[i])) {
10710Sstevel@tonic-gate 			readtape(bufptr);
10720Sstevel@tonic-gate 			bufptr += tp_bsize;
10730Sstevel@tonic-gate 			curblk++;
10740Sstevel@tonic-gate 			if (curblk == (fssize / tp_bsize)) {
10750Sstevel@tonic-gate 				(*f1)(buf, size > tp_bsize ?
10760Sstevel@tonic-gate 				    (size_t)(fssize) :
10770Sstevel@tonic-gate 					/* LINTED size <= tp_bsize */
10780Sstevel@tonic-gate 				    (curblk - 1) * tp_bsize + (size_t)size);
10790Sstevel@tonic-gate 				curblk = 0;
10800Sstevel@tonic-gate 				bufptr = buf;
10810Sstevel@tonic-gate 			}
10820Sstevel@tonic-gate 		} else {
10830Sstevel@tonic-gate 			if (curblk > 0) {
10840Sstevel@tonic-gate 				(*f1)(buf, size > tp_bsize ?
10850Sstevel@tonic-gate 				    (size_t)(curblk * tp_bsize) :
10860Sstevel@tonic-gate 					/* LINTED size <= tp_bsize */
10870Sstevel@tonic-gate 				    (curblk - 1) * tp_bsize + (size_t)size);
10880Sstevel@tonic-gate 				curblk = 0;
10890Sstevel@tonic-gate 				bufptr = buf;
10900Sstevel@tonic-gate 			}
10910Sstevel@tonic-gate 			(*f2)(clearedbuf, size > tp_bsize ?
10920Sstevel@tonic-gate 					/* LINTED size <= tp_bsize */
10934639Svk154806 			    (long)tp_bsize : (size_t)size);
10940Sstevel@tonic-gate 		}
10950Sstevel@tonic-gate 		if ((size -= tp_bsize) <= 0) {
10960Sstevel@tonic-gate 			for (i++; i < spcl.c_count; i++)
10970Sstevel@tonic-gate 				if ((i >= TP_NINDIR) || (spcl.c_addr[i]))
10980Sstevel@tonic-gate 					readtape(junk);
10990Sstevel@tonic-gate 			break;
11000Sstevel@tonic-gate 		}
11010Sstevel@tonic-gate 	}
11020Sstevel@tonic-gate 	if (curblk > 0) {
11030Sstevel@tonic-gate 		/*
11040Sstevel@tonic-gate 		 * Ok to cast size to size_t here. The above for loop reads
11050Sstevel@tonic-gate 		 * data into the buffer then writes it to the output file. The
11060Sstevel@tonic-gate 		 * call to f1 here is to write out the data that's in the
11070Sstevel@tonic-gate 		 * buffer that has not yet been written to the file.
11080Sstevel@tonic-gate 		 * This will be less than N-KB of data, since the
11090Sstevel@tonic-gate 		 * above loop writes to the file in filesystem-
11100Sstevel@tonic-gate 		 * blocksize chunks.
11110Sstevel@tonic-gate 		 */
11120Sstevel@tonic-gate 		/* LINTED: size fits into a size_t at this point */
11130Sstevel@tonic-gate 		(*f1)(buf, (curblk * tp_bsize) + (size_t)size);
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate 		curblk = 0;
11160Sstevel@tonic-gate 		bufptr = buf;
11170Sstevel@tonic-gate 	}
11180Sstevel@tonic-gate 	if ((readhdr(&spcl) == GOOD) && (checktype(&spcl, TS_ADDR) == GOOD)) {
11190Sstevel@tonic-gate 		if (continuemap)
11200Sstevel@tonic-gate 			size = (offset_t)spcl.c_count * tp_bsize;
11210Sstevel@tonic-gate 							/* big bitmap */
11220Sstevel@tonic-gate 		else if ((size <= 0) &&
11230Sstevel@tonic-gate 		    ((spcl.c_dinode.di_mode & IFMT) == IFSHAD)) {
11240Sstevel@tonic-gate 			/* LINTED unsigned to signed conversion ok */
11250Sstevel@tonic-gate 			size = spcl.c_dinode.di_size;
11260Sstevel@tonic-gate 		}
11270Sstevel@tonic-gate 		if (size > 0)
11280Sstevel@tonic-gate 			goto loop;
11290Sstevel@tonic-gate 	}
11300Sstevel@tonic-gate 	if (size > 0)
11310Sstevel@tonic-gate 		dprintf(stdout,
11320Sstevel@tonic-gate 		    gettext("Missing address (header) block for %s\n"),
11330Sstevel@tonic-gate 		    curfile.name);
11340Sstevel@tonic-gate 	findinode(&spcl);
11350Sstevel@tonic-gate 	gettingfile = 0;
11360Sstevel@tonic-gate }
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate /*
11390Sstevel@tonic-gate  * The next routines are called during file extraction to
11400Sstevel@tonic-gate  * put the data into the right form and place.
11410Sstevel@tonic-gate  */
11420Sstevel@tonic-gate static void
xtrfile(char * buf,size_t size)11431053Smaheshvs xtrfile(char *buf, size_t size)
11440Sstevel@tonic-gate {
11450Sstevel@tonic-gate 	if (write(ofile, buf, (size_t)size) == -1) {
11460Sstevel@tonic-gate 		int saverr = errno;
11470Sstevel@tonic-gate 		(void) fprintf(stderr,
11480Sstevel@tonic-gate 		    gettext("write error extracting inode %d, name %s\n"),
11490Sstevel@tonic-gate 		    curfile.ino, curfile.name);
11500Sstevel@tonic-gate 		errno = saverr;
11510Sstevel@tonic-gate 		perror("write");
11520Sstevel@tonic-gate 		done(1);
11530Sstevel@tonic-gate 	}
11540Sstevel@tonic-gate }
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate /*
11570Sstevel@tonic-gate  * Even though size is a size_t, it's seeking to a relative
11580Sstevel@tonic-gate  * offset.  Thus, the seek could go beyond 2 GB, so lseek64 is needed.
11590Sstevel@tonic-gate  */
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate /*ARGSUSED*/
11620Sstevel@tonic-gate static void
xtrskip(char * buf,size_t size)11631053Smaheshvs xtrskip(char *buf, size_t size)
11640Sstevel@tonic-gate {
11650Sstevel@tonic-gate 	if (lseek64(ofile, (offset_t)size, 1) == -1) {
11660Sstevel@tonic-gate 		int saverr = errno;
11670Sstevel@tonic-gate 		(void) fprintf(stderr,
11680Sstevel@tonic-gate 		    gettext("seek error extracting inode %d, name %s\n"),
11690Sstevel@tonic-gate 		    curfile.ino, curfile.name);
11700Sstevel@tonic-gate 		errno = saverr;
11710Sstevel@tonic-gate 		perror("lseek64");
11720Sstevel@tonic-gate 		done(1);
11730Sstevel@tonic-gate 	}
11740Sstevel@tonic-gate }
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate /* these are local to the next five functions */
11770Sstevel@tonic-gate static char *metadata = NULL;
11780Sstevel@tonic-gate static size_t metasize = 0;
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate static void
metacheck(struct s_spcl * head)11811053Smaheshvs metacheck(struct s_spcl *head)
11820Sstevel@tonic-gate {
11830Sstevel@tonic-gate 	if (! (head->c_flags & DR_HASMETA))
11840Sstevel@tonic-gate 		return;
11850Sstevel@tonic-gate 	if ((metadata = malloc(metasize = (size_t)sizeof (head->c_shadow)))
11860Sstevel@tonic-gate 	    == NULL) {
11870Sstevel@tonic-gate 		(void) fprintf(stderr,
11880Sstevel@tonic-gate 		    gettext("Cannot malloc for metadata\n"));
11890Sstevel@tonic-gate 		done(1);
11900Sstevel@tonic-gate 	}
11910Sstevel@tonic-gate 	bcopy(&(head->c_shadow), metadata, metasize);
11920Sstevel@tonic-gate }
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate static void
xtrmeta(char * buf,size_t size)11951053Smaheshvs xtrmeta(char *buf, size_t size)
11960Sstevel@tonic-gate {
11970Sstevel@tonic-gate 	if ((metadata == NULL) && ((spcl.c_dinode.di_mode & IFMT) != IFSHAD))
11980Sstevel@tonic-gate 		return;
11990Sstevel@tonic-gate 	if ((metadata = realloc(metadata, metasize + size)) == NULL) {
12000Sstevel@tonic-gate 		(void) fprintf(stderr,
12010Sstevel@tonic-gate 		    gettext("Cannot malloc for metadata\n"));
12020Sstevel@tonic-gate 		done(1);
12030Sstevel@tonic-gate 	}
12040Sstevel@tonic-gate 	bcopy(buf, metadata + metasize, size);
12050Sstevel@tonic-gate 	metasize += size;
12060Sstevel@tonic-gate }
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate /* ARGSUSED */
12090Sstevel@tonic-gate static void
metaskip(char * buf,size_t size)12101053Smaheshvs metaskip(char *buf, size_t size)
12110Sstevel@tonic-gate {
12120Sstevel@tonic-gate 	if (metadata == NULL)
12130Sstevel@tonic-gate 		return;
12140Sstevel@tonic-gate 	if ((metadata = realloc(metadata, metasize + size)) == NULL) {
12150Sstevel@tonic-gate 		(void) fprintf(stderr,
12160Sstevel@tonic-gate 		    gettext("Cannot malloc for metadata\n"));
12170Sstevel@tonic-gate 		done(1);
12180Sstevel@tonic-gate 	}
12190Sstevel@tonic-gate 	bzero(metadata + metasize, size);
12200Sstevel@tonic-gate 	metasize += size;
12210Sstevel@tonic-gate }
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate static void
metaset(char * name)12241053Smaheshvs metaset(char *name)
12250Sstevel@tonic-gate {
12260Sstevel@tonic-gate 	if (metadata == NULL)
12270Sstevel@tonic-gate 		return;
12280Sstevel@tonic-gate 	if (name != NULL)
12290Sstevel@tonic-gate 		metaproc(name, metadata, metasize);
12300Sstevel@tonic-gate 	(void) free(metadata);
12310Sstevel@tonic-gate 	metadata = NULL;
12320Sstevel@tonic-gate 	metasize = 0;
12330Sstevel@tonic-gate }
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate void
metaget(data,size)12360Sstevel@tonic-gate metaget(data, size)
12370Sstevel@tonic-gate 	char **data;
12380Sstevel@tonic-gate 	size_t *size;
12390Sstevel@tonic-gate {
12400Sstevel@tonic-gate 	*data = metadata;
12410Sstevel@tonic-gate 	*size = metasize;
12420Sstevel@tonic-gate }
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate static void
fsd_acl(name,aclp,size)12450Sstevel@tonic-gate fsd_acl(name, aclp, size)
12460Sstevel@tonic-gate 	char *name, *aclp;
12470Sstevel@tonic-gate 	unsigned size;
12480Sstevel@tonic-gate {
12490Sstevel@tonic-gate 	static aclent_t *aclent = NULL;
12500Sstevel@tonic-gate 	ufs_acl_t *diskacl;
12510Sstevel@tonic-gate 	static int n = 0;
12521953Smarks 	acl_t *set_aclp;
12530Sstevel@tonic-gate 	uint_t i;
12540Sstevel@tonic-gate 	int saverr, j;
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate 	if (aclp == NULL) {
12570Sstevel@tonic-gate 		if (aclent != NULL)
12580Sstevel@tonic-gate 			free(aclent);
12590Sstevel@tonic-gate 		aclent = NULL;
12600Sstevel@tonic-gate 		n = 0;
12610Sstevel@tonic-gate 		return;
12620Sstevel@tonic-gate 	}
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate 	/*LINTED [aclp is malloc'd]*/
12650Sstevel@tonic-gate 	diskacl = (ufs_acl_t *)aclp;
12660Sstevel@tonic-gate 	/* LINTED: result fits in an int */
12670Sstevel@tonic-gate 	j = size / sizeof (*diskacl);
12680Sstevel@tonic-gate 	normacls(byteorder, diskacl, j);
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	i = n;
12710Sstevel@tonic-gate 	n += j;
12720Sstevel@tonic-gate 	aclent = realloc(aclent, n * (size_t)sizeof (*aclent));
12730Sstevel@tonic-gate 	if (aclent == NULL) {
12740Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot malloc acl list\n"));
12750Sstevel@tonic-gate 		done(1);
12760Sstevel@tonic-gate 	}
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 	j = 0;
12790Sstevel@tonic-gate 	while (i < n) {
12800Sstevel@tonic-gate 		aclent[i].a_type = diskacl[j].acl_tag;
12810Sstevel@tonic-gate 		aclent[i].a_id = diskacl[j].acl_who;
12820Sstevel@tonic-gate 		aclent[i].a_perm = diskacl[j].acl_perm;
12830Sstevel@tonic-gate 		++i;
12840Sstevel@tonic-gate 		++j;
12850Sstevel@tonic-gate 	}
12860Sstevel@tonic-gate 
12871953Smarks 	set_aclp = acl_to_aclp(ACLENT_T, aclent, n);
12881953Smarks 	if (set_aclp == NULL) {
12891953Smarks 		(void) fprintf(stderr, gettext("Cannot build acl_t\n"));
12901953Smarks 		done(1);
12911953Smarks 	}
12921953Smarks 
12931953Smarks 	if (acl_set(name, set_aclp) == -1) {
12940Sstevel@tonic-gate 		static int once = 0;
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 		/*
12970Sstevel@tonic-gate 		 * Treat some errors from the acl subsystem specially to
12980Sstevel@tonic-gate 		 * avoid being too noisy:
12990Sstevel@tonic-gate 		 *
13000Sstevel@tonic-gate 		 * ENOSYS - ACLs not supported on this file system
13010Sstevel@tonic-gate 		 * EPERM  - not the owner or not privileged
13020Sstevel@tonic-gate 		 *
13030Sstevel@tonic-gate 		 * The following is also supported for backwards compat.
13040Sstevel@tonic-gate 		 * since acl(2) used to return the wrong errno:
13050Sstevel@tonic-gate 		 *
13060Sstevel@tonic-gate 		 * EINVAL - not the owner of the object
13070Sstevel@tonic-gate 		 */
13080Sstevel@tonic-gate 		if (errno == ENOSYS || errno == EPERM || errno == EINVAL) {
13090Sstevel@tonic-gate 			if (once == 0) {
13100Sstevel@tonic-gate 				saverr = errno;
13110Sstevel@tonic-gate 				++once;
13120Sstevel@tonic-gate 				fprintf(stderr,
13130Sstevel@tonic-gate 				    gettext("setacl failed: %s\n"),
13140Sstevel@tonic-gate 				    strerror(saverr));
13150Sstevel@tonic-gate 			}
13160Sstevel@tonic-gate 		} else {
13170Sstevel@tonic-gate 			saverr = errno;
13180Sstevel@tonic-gate 			fprintf(stderr, gettext("setacl on %s failed: %s\n"),
13190Sstevel@tonic-gate 			    name, strerror(saverr));
13200Sstevel@tonic-gate 		}
13210Sstevel@tonic-gate 	}
13221953Smarks 	acl_free(set_aclp);
13230Sstevel@tonic-gate }
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate static struct fsdtypes {
13260Sstevel@tonic-gate 	int type;
13270Sstevel@tonic-gate 	void (*function)();
13280Sstevel@tonic-gate } fsdtypes[] = {
13290Sstevel@tonic-gate 	{FSD_ACL, fsd_acl},
13300Sstevel@tonic-gate 	{FSD_DFACL, fsd_acl},
13310Sstevel@tonic-gate 	{0, NULL}
13320Sstevel@tonic-gate };
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate void
metaproc(char * name,char * mdata,size_t msize)13351053Smaheshvs metaproc(char *name, char *mdata, size_t msize)
13360Sstevel@tonic-gate {
13370Sstevel@tonic-gate 	struct fsdtypes *fsdtype;
13380Sstevel@tonic-gate 	ufs_fsd_t *fsd;
13390Sstevel@tonic-gate 	char *c;
13400Sstevel@tonic-gate 
13410Sstevel@tonic-gate 	/*
13420Sstevel@tonic-gate 	 * for the whole shadow inode, dispatch each piece
13430Sstevel@tonic-gate 	 * to the appropriate function.
13440Sstevel@tonic-gate 	 */
13450Sstevel@tonic-gate 	c = mdata;
13460Sstevel@tonic-gate 	/* LINTED (c - mdata) fits into a size_t */
13470Sstevel@tonic-gate 	while ((size_t)(c - mdata) < msize) {
13480Sstevel@tonic-gate 		/*LINTED [mdata is malloc'd]*/
13490Sstevel@tonic-gate 		fsd = (ufs_fsd_t *)c;
13500Sstevel@tonic-gate 		assert((fsd->fsd_size % 4) == 0);
13510Sstevel@tonic-gate 		/* LINTED: lint thinks pointers are signed */
13520Sstevel@tonic-gate 		c += FSD_RECSZ(fsd, fsd->fsd_size);
13530Sstevel@tonic-gate 		if ((fsd->fsd_type == FSD_FREE) ||
13540Sstevel@tonic-gate 		    ((unsigned)(fsd->fsd_size) <= sizeof (ufs_fsd_t)) ||
13550Sstevel@tonic-gate 		    (c > (mdata + msize)))
13560Sstevel@tonic-gate 			break;
13570Sstevel@tonic-gate 		for (fsdtype = fsdtypes; fsdtype->type; fsdtype++)
13580Sstevel@tonic-gate 			if (fsdtype->type == fsd->fsd_type)
13590Sstevel@tonic-gate 				(*fsdtype->function)(name, fsd->fsd_data,
13600Sstevel@tonic-gate 				    (unsigned)(fsd->fsd_size) -
13610Sstevel@tonic-gate 				    sizeof (fsd->fsd_type) -
13620Sstevel@tonic-gate 				    sizeof (fsd->fsd_size));
13630Sstevel@tonic-gate 		/* ^^^ be sure to change if fsd ever changes ^^^ */
13640Sstevel@tonic-gate 	}
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate 	/* reset the state of all the functions */
13670Sstevel@tonic-gate 	for (fsdtype = fsdtypes; fsdtype->type; fsdtype++)
13680Sstevel@tonic-gate 		(*fsdtype->function)(NULL, NULL, 0);
13690Sstevel@tonic-gate }
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate static void
xtrlnkfile(char * buf,size_t size)13721053Smaheshvs xtrlnkfile(char *buf, size_t size)
13730Sstevel@tonic-gate {
13740Sstevel@tonic-gate 	/* LINTED: signed/unsigned mix ok */
13750Sstevel@tonic-gate 	pathlen += size;
13760Sstevel@tonic-gate 	if (pathlen > MAXPATHLEN) {
13770Sstevel@tonic-gate 		(void) fprintf(stderr,
13780Sstevel@tonic-gate 		    gettext("symbolic link name: %s->%s%s; too long %d\n"),
13790Sstevel@tonic-gate 		    curfile.name, lnkbuf, buf, pathlen);
13800Sstevel@tonic-gate 		done(1);
13810Sstevel@tonic-gate 	}
13820Sstevel@tonic-gate 	buf[size] = '\0';
13830Sstevel@tonic-gate 	(void) strcat(lnkbuf, buf);
13840Sstevel@tonic-gate 	/* add an extra NULL to make this a legal complex string */
13850Sstevel@tonic-gate 	lnkbuf[pathlen+1] = '\0';
13860Sstevel@tonic-gate }
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate /*ARGSUSED*/
13890Sstevel@tonic-gate static void
xtrlnkskip(char * buf,size_t size)13901053Smaheshvs xtrlnkskip(char *buf, size_t size)
13910Sstevel@tonic-gate {
13920Sstevel@tonic-gate 	(void) fprintf(stderr,
13930Sstevel@tonic-gate 	    gettext("unallocated block in symbolic link %s\n"),
13940Sstevel@tonic-gate 	    curfile.name);
13950Sstevel@tonic-gate 	done(1);
13960Sstevel@tonic-gate }
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate static void
xtrmap(char * buf,size_t size)13991053Smaheshvs xtrmap(char *buf, size_t size)
14000Sstevel@tonic-gate {
14010Sstevel@tonic-gate 	if ((map+size) > endmap) {
14020Sstevel@tonic-gate 		int64_t mapsize, increment;
14030Sstevel@tonic-gate 		int64_t diff;
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 		if (spcl.c_type != TS_ADDR) {
14060Sstevel@tonic-gate 			(void) fprintf(stderr,
14070Sstevel@tonic-gate 			    gettext("xtrmap: current record not TS_ADDR\n"));
14080Sstevel@tonic-gate 			done(1);
14090Sstevel@tonic-gate 		}
14100Sstevel@tonic-gate 		if ((spcl.c_count < 0) || (spcl.c_count > TP_NINDIR)) {
14110Sstevel@tonic-gate 			(void) fprintf(stderr,
14120Sstevel@tonic-gate 			    gettext("xtrmap: illegal c_count field (%d)\n"),
14130Sstevel@tonic-gate 			    spcl.c_count);
14140Sstevel@tonic-gate 			done(1);
14150Sstevel@tonic-gate 		}
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 		increment = d_howmany(
14184639Svk154806 		    ((spcl.c_count * tp_bsize * NBBY) + 1), NBBY);
14190Sstevel@tonic-gate 		mapsize = endmap - beginmap + increment;
14200Sstevel@tonic-gate 		if (mapsize > UINT_MAX) {
14210Sstevel@tonic-gate 			(void) fprintf(stderr,
14220Sstevel@tonic-gate 			    gettext("xtrmap: maximum bitmap size exceeded"));
14230Sstevel@tonic-gate 			done(1);
14240Sstevel@tonic-gate 		}
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 		diff = map - beginmap;
14270Sstevel@tonic-gate 		/* LINTED mapsize checked above */
14280Sstevel@tonic-gate 		beginmap = realloc(beginmap, (size_t)mapsize);
14290Sstevel@tonic-gate 		if (beginmap == NULL) {
14300Sstevel@tonic-gate 			(void) fprintf(stderr,
14310Sstevel@tonic-gate 			    gettext("xtrmap: realloc failed\n"));
14320Sstevel@tonic-gate 			done(1);
14330Sstevel@tonic-gate 		}
14340Sstevel@tonic-gate 		map = beginmap + diff;
14350Sstevel@tonic-gate 		endmap = beginmap + mapsize;
14360Sstevel@tonic-gate 		/* LINTED endmap - map cannot exceed 32 bits */
14370Sstevel@tonic-gate 		bzero(map, (size_t)(endmap - map));
14380Sstevel@tonic-gate 		maxino = NBBY * mapsize + 1;
14390Sstevel@tonic-gate 	}
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 	bcopy(buf, map, size);
14420Sstevel@tonic-gate 	/* LINTED character pointers aren't signed */
14430Sstevel@tonic-gate 	map += size;
14440Sstevel@tonic-gate }
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate /*ARGSUSED*/
14470Sstevel@tonic-gate static void
xtrmapskip(char * buf,size_t size)14481053Smaheshvs xtrmapskip(char *buf, size_t size)
14490Sstevel@tonic-gate {
14500Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("hole in map\n"));
14510Sstevel@tonic-gate 	done(1);
14520Sstevel@tonic-gate }
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate /*ARGSUSED*/
14550Sstevel@tonic-gate void
null(char * buf,size_t size)14561053Smaheshvs null(char *buf, size_t size)
14570Sstevel@tonic-gate {
14580Sstevel@tonic-gate }
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate /*
14610Sstevel@tonic-gate  * Do the tape i/o, dealing with volume changes
14620Sstevel@tonic-gate  * etc..
14630Sstevel@tonic-gate  */
14640Sstevel@tonic-gate static void
readtape(char * b)14651053Smaheshvs readtape(char *b)
14660Sstevel@tonic-gate {
14670Sstevel@tonic-gate 	int i;
14680Sstevel@tonic-gate 	int rd, newvol;
14690Sstevel@tonic-gate 	int cnt;
14700Sstevel@tonic-gate 	struct s_spcl *sp;
14710Sstevel@tonic-gate 	int32_t	expected_magic;
14720Sstevel@tonic-gate 
14730Sstevel@tonic-gate 	if (tbf == NULL) {
14740Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
14750Sstevel@tonic-gate 		    "Internal consistency failure in readtape: tbf is NULL\n"));
14760Sstevel@tonic-gate 		done(1);
14770Sstevel@tonic-gate 	}
14780Sstevel@tonic-gate 	expected_magic = ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC);
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate top:
14810Sstevel@tonic-gate 	if (bct < numtrec) {
14820Sstevel@tonic-gate 		/*
14830Sstevel@tonic-gate 		 * check for old-dump floppy EOM -- it may appear in
14840Sstevel@tonic-gate 		 * the middle of a buffer.  The Dflag used to be used for
14850Sstevel@tonic-gate 		 * this, but since it doesn't hurt to always do this we
14860Sstevel@tonic-gate 		 * got rid of the Dflag.
14870Sstevel@tonic-gate 		 */
14880Sstevel@tonic-gate 		/*LINTED [tbf = malloc()]*/
14890Sstevel@tonic-gate 		sp = &((union u_spcl *)&tbf[bct*tp_bsize])->s_spcl;
14900Sstevel@tonic-gate 		if (sp->c_magic == expected_magic && sp->c_type == TS_EOM &&
14910Sstevel@tonic-gate 		    (time_t)(sp->c_date) == dumpdate &&
14920Sstevel@tonic-gate 		    (time_t)(sp->c_ddate) == dumptime) {
14930Sstevel@tonic-gate 			for (i = 0; i < ntrec; i++)
14940Sstevel@tonic-gate 				/*LINTED [tbf = malloc()]*/
14950Sstevel@tonic-gate 				((struct s_spcl *)
14964639Svk154806 				    &tbf[i*tp_bsize])->c_magic = 0;
14970Sstevel@tonic-gate 			bct = 0;
14980Sstevel@tonic-gate 			rd = 0;
14990Sstevel@tonic-gate 			i = 0;
15000Sstevel@tonic-gate 			goto nextvol;
15010Sstevel@tonic-gate 		}
15020Sstevel@tonic-gate 		bcopy(&tbf[(bct++*tp_bsize)], b, (size_t)tp_bsize);
15030Sstevel@tonic-gate 		blksread++;
15040Sstevel@tonic-gate 		tapea++;
15050Sstevel@tonic-gate 		return;
15060Sstevel@tonic-gate 	}
15070Sstevel@tonic-gate 	/*LINTED [assertion always true]*/
15080Sstevel@tonic-gate 	assert(sizeof (union u_spcl) == TP_BSIZE_MAX);
15090Sstevel@tonic-gate 	for (i = 0; i < ntrec; i++)
15100Sstevel@tonic-gate 		/*LINTED [tbf = malloc()]*/
15110Sstevel@tonic-gate 		((struct s_spcl *)&tbf[i*sizeof (struct s_spcl)])->c_magic = 0;
15120Sstevel@tonic-gate 	if (numtrec == 0) {
15130Sstevel@tonic-gate 		/* LINTED unsigned/signed assignment ok */
15140Sstevel@tonic-gate 		numtrec = ntrec;
15150Sstevel@tonic-gate 	}
15160Sstevel@tonic-gate 	/* LINTED unsigned/signed assignment ok */
15170Sstevel@tonic-gate 	cnt = ntrec*tp_bsize;
15180Sstevel@tonic-gate 	rd = 0;
15190Sstevel@tonic-gate getmore:
15200Sstevel@tonic-gate 	if (host)
15210Sstevel@tonic-gate 		i = rmtread(&tbf[rd], cnt);
15220Sstevel@tonic-gate 	else
15230Sstevel@tonic-gate 		i = read(mt, &tbf[rd], cnt);
15240Sstevel@tonic-gate 	/*
15250Sstevel@tonic-gate 	 * Check for mid-tape short read error.
15260Sstevel@tonic-gate 	 * If found, return rest of buffer.
15270Sstevel@tonic-gate 	 */
15280Sstevel@tonic-gate 	if (numtrec < ntrec && i != 0) {
15290Sstevel@tonic-gate 		/* LINTED unsigned/signed assignment ok */
15300Sstevel@tonic-gate 		numtrec = ntrec;
15310Sstevel@tonic-gate 		goto top;
15320Sstevel@tonic-gate 	}
15330Sstevel@tonic-gate 	/*
15340Sstevel@tonic-gate 	 * Handle partial block read.
15350Sstevel@tonic-gate 	 */
15360Sstevel@tonic-gate 	if (i > 0 && i != ntrec*tp_bsize) {
15370Sstevel@tonic-gate 		if (pipein) {
15380Sstevel@tonic-gate 			rd += i;
15390Sstevel@tonic-gate 			cnt -= i;
15400Sstevel@tonic-gate 			if (cnt > 0)
15410Sstevel@tonic-gate 				goto getmore;
15420Sstevel@tonic-gate 			i = rd;
15430Sstevel@tonic-gate 		} else {
15440Sstevel@tonic-gate 			if (i % tp_bsize != 0)
15450Sstevel@tonic-gate 				panic(gettext(
15460Sstevel@tonic-gate 				    "partial block read: %d should be %d\n"),
15474639Svk154806 				    i, ntrec * tp_bsize);
15480Sstevel@tonic-gate 			numtrec = i / tp_bsize;
15490Sstevel@tonic-gate 			if (numtrec == 0)
15500Sstevel@tonic-gate 				/*
15510Sstevel@tonic-gate 				 * it's possible to read only 512 bytes
15520Sstevel@tonic-gate 				 * from a QIC device...
15530Sstevel@tonic-gate 				 */
15540Sstevel@tonic-gate 				i = 0;
15550Sstevel@tonic-gate 		}
15560Sstevel@tonic-gate 	}
15570Sstevel@tonic-gate 	/*
15580Sstevel@tonic-gate 	 * Handle read error.
15590Sstevel@tonic-gate 	 */
15600Sstevel@tonic-gate 	if (i < 0) {
15610Sstevel@tonic-gate 		switch (curfile.action) {
15620Sstevel@tonic-gate 		default:
15630Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
15640Sstevel@tonic-gate 			    "Read error while trying to set up volume\n"));
15650Sstevel@tonic-gate 			break;
15660Sstevel@tonic-gate 		case UNKNOWN:
15670Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
15680Sstevel@tonic-gate 			    "Read error while trying to resynchronize\n"));
15690Sstevel@tonic-gate 			break;
15700Sstevel@tonic-gate 		case USING:
15710Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
15720Sstevel@tonic-gate 			    "Read error while restoring %s\n"),
15730Sstevel@tonic-gate 			    curfile.name);
15740Sstevel@tonic-gate 			break;
15750Sstevel@tonic-gate 		case SKIP:
15760Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
15770Sstevel@tonic-gate 			    "Read error while skipping over inode %d\n"),
15780Sstevel@tonic-gate 			    curfile.ino);
15790Sstevel@tonic-gate 			break;
15800Sstevel@tonic-gate 		}
15810Sstevel@tonic-gate 		if (!yflag && !reply(gettext("continue")))
15820Sstevel@tonic-gate 			done(1);
15830Sstevel@tonic-gate 		/* LINTED: unsigned->signed conversion ok */
15840Sstevel@tonic-gate 		i = (int)(ntrec*tp_bsize);
15850Sstevel@tonic-gate 		bzero(tbf, (size_t)i);
15860Sstevel@tonic-gate 		if ((host != 0 && rmtseek(i, 1) < 0) ||
15870Sstevel@tonic-gate 		    (host == 0 && (lseek64(mt, (offset_t)i, 1) ==
15880Sstevel@tonic-gate 		    (off64_t)-1))) {
15890Sstevel@tonic-gate 			perror(gettext("continuation failed"));
15900Sstevel@tonic-gate 			done(1);
15910Sstevel@tonic-gate 		}
15920Sstevel@tonic-gate 	}
15930Sstevel@tonic-gate 	/*
15940Sstevel@tonic-gate 	 * Handle end of tape.  The Dflag used to be used, but since it doesn't
15950Sstevel@tonic-gate 	 * hurt to always check we got rid if it.
15960Sstevel@tonic-gate 	 */
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 	/*
15990Sstevel@tonic-gate 	 * if the first record in the buffer just read is EOM,
16000Sstevel@tonic-gate 	 * change volumes.
16010Sstevel@tonic-gate 	 */
16020Sstevel@tonic-gate 	/*LINTED [tbf = malloc()]*/
16030Sstevel@tonic-gate 	sp = &((union u_spcl *)tbf)->s_spcl;
16040Sstevel@tonic-gate 	if (i != 0 && sp->c_magic == expected_magic && sp->c_type == TS_EOM &&
16050Sstevel@tonic-gate 	    (time_t)(sp->c_date) == dumpdate &&
16060Sstevel@tonic-gate 	    (time_t)(sp->c_ddate) == dumptime) {
16070Sstevel@tonic-gate 		i = 0;
16080Sstevel@tonic-gate 	}
16090Sstevel@tonic-gate nextvol:
16100Sstevel@tonic-gate 	if (i == 0) {
16110Sstevel@tonic-gate 		if (!pipein) {
16120Sstevel@tonic-gate 			newvol = volno + 1;
16130Sstevel@tonic-gate 			volno = 0;
16140Sstevel@tonic-gate 			numtrec = 0;
16150Sstevel@tonic-gate 			getvol(newvol);
16160Sstevel@tonic-gate 			readtape(b); /* XXX tail recursion, not goto top? */
16170Sstevel@tonic-gate 			return;
16180Sstevel@tonic-gate 		}
16190Sstevel@tonic-gate 		/* XXX if panic returns, should we round rd up? */
16200Sstevel@tonic-gate 		/* XXX if we do, then we should zero the intervening space */
16210Sstevel@tonic-gate 		if (rd % tp_bsize != 0)
16220Sstevel@tonic-gate 			panic(gettext("partial block read: %d should be %d\n"),
16234639Svk154806 			    rd, ntrec * tp_bsize);
16240Sstevel@tonic-gate 		bcopy((char *)&endoftapemark, &tbf[rd], (size_t)tp_bsize);
16250Sstevel@tonic-gate 	}
16260Sstevel@tonic-gate 	bct = 0;
16270Sstevel@tonic-gate 	bcopy(&tbf[(bct++*tp_bsize)], b, (size_t)tp_bsize);
16280Sstevel@tonic-gate 	blksread++;
16290Sstevel@tonic-gate 	recsread++;
16300Sstevel@tonic-gate 	tapea++;
16310Sstevel@tonic-gate 	rec_position++;
16320Sstevel@tonic-gate }
16330Sstevel@tonic-gate 
16340Sstevel@tonic-gate void
findtapeblksize(int arfile)16350Sstevel@tonic-gate findtapeblksize(int arfile)
16360Sstevel@tonic-gate {
16370Sstevel@tonic-gate 	int	i;
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate 	if (tbf == NULL) {
16400Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
16410Sstevel@tonic-gate 		    "Internal consistency failure in findtapeblksize: "
16420Sstevel@tonic-gate 		    "tbf is NULL\n"));
16430Sstevel@tonic-gate 		assert(tbf != NULL);
16440Sstevel@tonic-gate 		done(1);
16450Sstevel@tonic-gate 	}
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 	for (i = 0; i < ntrec; i++)
16480Sstevel@tonic-gate 		/*LINTED [tbf = malloc()]*/
16490Sstevel@tonic-gate 		((struct s_spcl *)&tbf[i * tp_bsize])->c_magic = 0;
16500Sstevel@tonic-gate 	bct = 0;
16510Sstevel@tonic-gate 	if (host && arfile == TAPE_FILE)
16520Sstevel@tonic-gate 		tape_rec_size = rmtread(tbf, ntrec * tp_bsize);
16530Sstevel@tonic-gate 	else
16540Sstevel@tonic-gate 		tape_rec_size = read(mt, tbf, ntrec * tp_bsize);
16550Sstevel@tonic-gate 	recsread++;
16560Sstevel@tonic-gate 	rec_position++;
16570Sstevel@tonic-gate 	if (tape_rec_size == (ssize_t)-1) {
16580Sstevel@tonic-gate 		int saverr = errno;
16590Sstevel@tonic-gate 		char *errmsg = gettext("Media read error");
16600Sstevel@tonic-gate 		errno = saverr;
16610Sstevel@tonic-gate 		perror(errmsg);
16620Sstevel@tonic-gate 		done(1);
16630Sstevel@tonic-gate 	}
16640Sstevel@tonic-gate 	if (tape_rec_size % tp_bsize != 0) {
16650Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
16660Sstevel@tonic-gate 	    "Record size (%d) is not a multiple of dump block size (%d)\n"),
16670Sstevel@tonic-gate 		    tape_rec_size, tp_bsize);
16680Sstevel@tonic-gate 		done(1);
16690Sstevel@tonic-gate 	}
16700Sstevel@tonic-gate 	ntrec = (int)tape_rec_size / tp_bsize;
16710Sstevel@tonic-gate 	/* LINTED unsigned/signed assignment ok */
16720Sstevel@tonic-gate 	numtrec = ntrec;
16730Sstevel@tonic-gate 	vprintf(stdout, gettext("Media block size is %d\n"), ntrec*2);
16740Sstevel@tonic-gate }
16750Sstevel@tonic-gate 
16760Sstevel@tonic-gate void
flsht(void)16770Sstevel@tonic-gate flsht(void)
16780Sstevel@tonic-gate {
16790Sstevel@tonic-gate 	/* LINTED unsigned/signed assignment ok */
16800Sstevel@tonic-gate 	bct = ntrec+1;
16810Sstevel@tonic-gate }
16820Sstevel@tonic-gate 
16830Sstevel@tonic-gate void
closemt(int mode)1684426Srm88369 closemt(int mode)
16850Sstevel@tonic-gate {
1686426Srm88369 	/*
1687426Srm88369 	 * If mode == FORCE_OFFLINE then we're not done but
1688426Srm88369 	 * we need to change tape. So, rewind and unload current
1689426Srm88369 	 * tape before loading the new one.
1690426Srm88369 	 */
1691426Srm88369 
16920Sstevel@tonic-gate 	static struct mtop mtop = { MTOFFL, 0 };
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate 	if (mt < 0)
16950Sstevel@tonic-gate 		return;
1696426Srm88369 	if (offline || mode == FORCE_OFFLINE)
16970Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Rewinding tape\n"));
16980Sstevel@tonic-gate 	if (host) {
1699426Srm88369 		if (offline || mode == FORCE_OFFLINE)
17000Sstevel@tonic-gate 			(void) rmtioctl(MTOFFL, 1);
17010Sstevel@tonic-gate 		rmtclose();
17020Sstevel@tonic-gate 	} else if (pipein) {
17030Sstevel@tonic-gate 		char buffy[MAXBSIZE];
17040Sstevel@tonic-gate 
17050Sstevel@tonic-gate 		while (read(mt, buffy, sizeof (buffy)) > 0) {
17060Sstevel@tonic-gate 			continue;
17070Sstevel@tonic-gate 			/*LINTED [assertion always true]*/
17080Sstevel@tonic-gate 		}
17090Sstevel@tonic-gate 		(void) close(mt);
17100Sstevel@tonic-gate 	} else {
17110Sstevel@tonic-gate 		/*
17120Sstevel@tonic-gate 		 * Only way to tell if this is a floppy is to issue an ioctl
17130Sstevel@tonic-gate 		 * but why waste one - if the eject fails, tough!
17140Sstevel@tonic-gate 		 */
1715426Srm88369 		if (offline || mode == FORCE_OFFLINE)
17160Sstevel@tonic-gate 			(void) ioctl(mt, MTIOCTOP, &mtop);
17170Sstevel@tonic-gate 		(void) ioctl(mt, FDEJECT, 0);
17180Sstevel@tonic-gate 		(void) close(mt);
17190Sstevel@tonic-gate 	}
17200Sstevel@tonic-gate 	mt = -1;
17210Sstevel@tonic-gate }
17220Sstevel@tonic-gate 
17230Sstevel@tonic-gate static int
checkvol(struct s_spcl * b,int t)17241053Smaheshvs checkvol(struct s_spcl *b, int t)
17250Sstevel@tonic-gate {
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate 	if (b->c_volume != t)
17280Sstevel@tonic-gate 		return (FAIL);
17290Sstevel@tonic-gate 	return (GOOD);
17300Sstevel@tonic-gate }
17310Sstevel@tonic-gate 
17321053Smaheshvs int
readhdr(struct s_spcl * b)17331053Smaheshvs readhdr(struct s_spcl *b)
17340Sstevel@tonic-gate {
17350Sstevel@tonic-gate 
17360Sstevel@tonic-gate 	if (gethead(b) == FAIL) {
17370Sstevel@tonic-gate 		dprintf(stdout, gettext("readhdr fails at %ld blocks\n"),
17384639Svk154806 		    blksread);
17390Sstevel@tonic-gate 		return (FAIL);
17400Sstevel@tonic-gate 	}
17410Sstevel@tonic-gate 	return (GOOD);
17420Sstevel@tonic-gate }
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate /*
17450Sstevel@tonic-gate  * read the tape into buf, then return whether or
17460Sstevel@tonic-gate  * or not it is a header block.
17470Sstevel@tonic-gate  */
17481053Smaheshvs int
gethead(struct s_spcl * buf)17491053Smaheshvs gethead(struct s_spcl *buf)
17500Sstevel@tonic-gate {
17510Sstevel@tonic-gate 	int i;
17520Sstevel@tonic-gate 	union u_ospcl {
17530Sstevel@tonic-gate 		char dummy[TP_BSIZE_MIN];
17540Sstevel@tonic-gate 		struct	s_ospcl {
17550Sstevel@tonic-gate 			int32_t	c_type;
17560Sstevel@tonic-gate 			int32_t	c_date;
17570Sstevel@tonic-gate 			int32_t	c_ddate;
17580Sstevel@tonic-gate 			int32_t	c_volume;
17590Sstevel@tonic-gate 			int32_t	c_tapea;
17600Sstevel@tonic-gate 			ushort_t c_inumber;
17610Sstevel@tonic-gate 			int32_t	c_magic;
17620Sstevel@tonic-gate 			int32_t	c_checksum;
17630Sstevel@tonic-gate 			struct odinode {
17640Sstevel@tonic-gate 				unsigned short odi_mode;
17650Sstevel@tonic-gate 				ushort_t odi_nlink;
17660Sstevel@tonic-gate 				ushort_t odi_uid;
17670Sstevel@tonic-gate 				ushort_t odi_gid;
17680Sstevel@tonic-gate 				int32_t	odi_size;
17690Sstevel@tonic-gate 				int32_t	odi_rdev;
17700Sstevel@tonic-gate 				char	odi_addr[36];
17710Sstevel@tonic-gate 				int32_t	odi_atime;
17720Sstevel@tonic-gate 				int32_t	odi_mtime;
17730Sstevel@tonic-gate 				int32_t	odi_ctime;
17740Sstevel@tonic-gate 			} c_dinode;
17750Sstevel@tonic-gate 			int32_t	c_count;
17760Sstevel@tonic-gate 			char	c_baddr[256];
17770Sstevel@tonic-gate 		} s_ospcl;
17780Sstevel@tonic-gate 	} u_ospcl;
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate 	if (cvtflag) {
17810Sstevel@tonic-gate 		readtape((char *)(&u_ospcl.s_ospcl));
17820Sstevel@tonic-gate 		bzero((char *)buf, (size_t)TP_BSIZE_MIN);
17830Sstevel@tonic-gate 		buf->c_type = u_ospcl.s_ospcl.c_type;
17840Sstevel@tonic-gate 		buf->c_date = u_ospcl.s_ospcl.c_date;
17850Sstevel@tonic-gate 		buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
17860Sstevel@tonic-gate 		buf->c_volume = u_ospcl.s_ospcl.c_volume;
17870Sstevel@tonic-gate 		buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
17880Sstevel@tonic-gate 		buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
17890Sstevel@tonic-gate 		buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
17900Sstevel@tonic-gate 		buf->c_magic = u_ospcl.s_ospcl.c_magic;
17910Sstevel@tonic-gate 		buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
17920Sstevel@tonic-gate 		/* LINTED: unsigned/signed combination ok */
17930Sstevel@tonic-gate 		buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
17940Sstevel@tonic-gate 		buf->c_dinode.di_size =
17950Sstevel@tonic-gate 		    (unsigned)(u_ospcl.s_ospcl.c_dinode.odi_size);
17960Sstevel@tonic-gate 		buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
17970Sstevel@tonic-gate 		buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
17980Sstevel@tonic-gate 		buf->c_dinode.di_suid = UID_LONG;
17990Sstevel@tonic-gate 		buf->c_dinode.di_sgid = GID_LONG;
18000Sstevel@tonic-gate 		buf->c_dinode.di_ordev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
18010Sstevel@tonic-gate 		buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
18020Sstevel@tonic-gate 		buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
18030Sstevel@tonic-gate 		buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
18040Sstevel@tonic-gate 		buf->c_count = u_ospcl.s_ospcl.c_count;
18050Sstevel@tonic-gate 		bcopy(u_ospcl.s_ospcl.c_baddr, buf->c_addr,
18060Sstevel@tonic-gate 		    sizeof (u_ospcl.s_ospcl.c_baddr));
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate 		/*CONSTANTCONDITION*/
18090Sstevel@tonic-gate 		assert(sizeof (u_ospcl.s_ospcl) < sizeof (union u_spcl));
18100Sstevel@tonic-gate 
18110Sstevel@tonic-gate 		/* we byte-swap the new spclrec, but checksum the old	*/
18120Sstevel@tonic-gate 		/* (see comments in normspcl())				*/
18130Sstevel@tonic-gate 		if (normspcl(byteorder, buf,
18140Sstevel@tonic-gate 		    (int *)(&u_ospcl.s_ospcl), sizeof (u_ospcl.s_ospcl),
18150Sstevel@tonic-gate 		    OFS_MAGIC))
18160Sstevel@tonic-gate 			return (FAIL);
18170Sstevel@tonic-gate 		buf->c_magic =
18180Sstevel@tonic-gate 		    ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC);
18190Sstevel@tonic-gate 	} else {
18200Sstevel@tonic-gate 		readtape((char *)buf);
18210Sstevel@tonic-gate 		if (normspcl(byteorder, buf, (int *)buf, tp_bsize,
18220Sstevel@tonic-gate 		    ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC)))
18230Sstevel@tonic-gate 			return (FAIL);
18240Sstevel@tonic-gate 	}
18250Sstevel@tonic-gate 
18260Sstevel@tonic-gate 	switch (buf->c_type) {
18270Sstevel@tonic-gate 
18280Sstevel@tonic-gate 	case TS_CLRI:
18290Sstevel@tonic-gate 	case TS_BITS:
18300Sstevel@tonic-gate 		/*
18310Sstevel@tonic-gate 		 * Have to patch up missing information in bit map headers
18320Sstevel@tonic-gate 		 */
18330Sstevel@tonic-gate 		buf->c_inumber = 0;
18340Sstevel@tonic-gate 		buf->c_dinode.di_size = (offset_t)buf->c_count * tp_bsize;
18350Sstevel@tonic-gate 		for (i = 0; i < buf->c_count && i < TP_NINDIR; i++)
18360Sstevel@tonic-gate 			buf->c_addr[i] = 1;
18370Sstevel@tonic-gate 		break;
18380Sstevel@tonic-gate 
18390Sstevel@tonic-gate 	case TS_TAPE:
18400Sstevel@tonic-gate 	case TS_END:
18410Sstevel@tonic-gate 		if (dumpinfo.c_date == 0) {
18420Sstevel@tonic-gate 			dumpinfo.c_date = spcl.c_date;
18430Sstevel@tonic-gate 			dumpinfo.c_ddate = spcl.c_ddate;
18440Sstevel@tonic-gate 		}
18450Sstevel@tonic-gate 		if (!hostinfo && spcl.c_host[0] != '\0') {
18460Sstevel@tonic-gate 			bcopy(spcl.c_label, dumpinfo.c_label,
18470Sstevel@tonic-gate 			    sizeof (spcl.c_label));
18480Sstevel@tonic-gate 			bcopy(spcl.c_filesys, dumpinfo.c_filesys,
18490Sstevel@tonic-gate 			    sizeof (spcl.c_filesys));
18500Sstevel@tonic-gate 			bcopy(spcl.c_dev, dumpinfo.c_dev,
18510Sstevel@tonic-gate 			    sizeof (spcl.c_dev));
18520Sstevel@tonic-gate 			bcopy(spcl.c_host, dumpinfo.c_host,
18530Sstevel@tonic-gate 			    sizeof (spcl.c_host));
18540Sstevel@tonic-gate 			dumpinfo.c_level = spcl.c_level;
18550Sstevel@tonic-gate 			hostinfo++;
18560Sstevel@tonic-gate 			if (c_label != NULL &&
18570Sstevel@tonic-gate 			    strncmp(c_label, spcl.c_label,
18584639Svk154806 			    sizeof (spcl.c_label))
18590Sstevel@tonic-gate 			    != 0) {
18600Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
18610Sstevel@tonic-gate 		    "Incorrect tape label.  Expected `%s', got `%.*s'\n"),
18620Sstevel@tonic-gate 				    c_label,
18630Sstevel@tonic-gate 				    sizeof (spcl.c_label), spcl.c_label);
18640Sstevel@tonic-gate 				done(1);
18650Sstevel@tonic-gate 			}
18660Sstevel@tonic-gate 		}
18670Sstevel@tonic-gate 		if (!inodeinfo && (spcl.c_flags & DR_INODEINFO)) {
18680Sstevel@tonic-gate 			dumpinfo.c_volume = spcl.c_volume;
18690Sstevel@tonic-gate 			bcopy(spcl.c_inos, dumpinfo.c_inos,
18700Sstevel@tonic-gate 			    sizeof (spcl.c_inos));
18710Sstevel@tonic-gate 			inodeinfo++;
18720Sstevel@tonic-gate 		}
18730Sstevel@tonic-gate 		buf->c_inumber = 0;
18740Sstevel@tonic-gate 		break;
18750Sstevel@tonic-gate 
18760Sstevel@tonic-gate 	case TS_INODE:
18770Sstevel@tonic-gate 	case TS_ADDR:
18780Sstevel@tonic-gate 		break;
18790Sstevel@tonic-gate 
18800Sstevel@tonic-gate 	default:
18810Sstevel@tonic-gate 		panic(gettext("%s: unknown inode type %d\n"),
18824639Svk154806 		    "gethead", buf->c_type);
18830Sstevel@tonic-gate 		return (FAIL);
18840Sstevel@tonic-gate 	}
18850Sstevel@tonic-gate 	if (dflag)
18860Sstevel@tonic-gate 		accthdr(buf);
18870Sstevel@tonic-gate 	return (GOOD);
18880Sstevel@tonic-gate }
18890Sstevel@tonic-gate 
18900Sstevel@tonic-gate /*
18910Sstevel@tonic-gate  * Check that a header is where it belongs and predict the next header
18920Sstevel@tonic-gate  */
18930Sstevel@tonic-gate static void
accthdr(struct s_spcl * header)18941053Smaheshvs accthdr(struct s_spcl *header)
18950Sstevel@tonic-gate {
18960Sstevel@tonic-gate 	static ino_t previno = (ino_t)(unsigned)-1;
18970Sstevel@tonic-gate 	static int prevtype;
18980Sstevel@tonic-gate 	static long predict;
18990Sstevel@tonic-gate 	int blks, i;
19000Sstevel@tonic-gate 
19010Sstevel@tonic-gate 	if (header->c_type == TS_TAPE) {
19020Sstevel@tonic-gate 		if (header->c_firstrec)
19030Sstevel@tonic-gate 			(void) fprintf(stderr,
19040Sstevel@tonic-gate 			    gettext("Volume header begins with record %d"),
19050Sstevel@tonic-gate 			    header->c_firstrec);
19060Sstevel@tonic-gate 		else
19070Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Volume header"));
19080Sstevel@tonic-gate 		(void) fprintf(stderr, "\n");
19090Sstevel@tonic-gate 		previno = (ino_t)(unsigned)-1;
19100Sstevel@tonic-gate 		return;
19110Sstevel@tonic-gate 	}
19120Sstevel@tonic-gate 	if (previno == (ino_t)(unsigned)-1)
19130Sstevel@tonic-gate 		goto newcalc;
19140Sstevel@tonic-gate 	switch (prevtype) {
19150Sstevel@tonic-gate 	case TS_BITS:
19160Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Dump mask header"));
19170Sstevel@tonic-gate 		break;
19180Sstevel@tonic-gate 	case TS_CLRI:
19190Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Remove mask header"));
19200Sstevel@tonic-gate 		break;
19210Sstevel@tonic-gate 	case TS_INODE:
19220Sstevel@tonic-gate 		(void) fprintf(stderr,
19230Sstevel@tonic-gate 		    gettext("File header, ino %d at record %d"),
19240Sstevel@tonic-gate 		    previno, rec_position);
19250Sstevel@tonic-gate 		break;
19260Sstevel@tonic-gate 	case TS_ADDR:
19270Sstevel@tonic-gate 		(void) fprintf(stderr,
19280Sstevel@tonic-gate 		    gettext("File continuation header, ino %d"),
19290Sstevel@tonic-gate 		    previno);
19300Sstevel@tonic-gate 		break;
19310Sstevel@tonic-gate 	case TS_END:
19320Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("End of media header"));
19330Sstevel@tonic-gate 		break;
19340Sstevel@tonic-gate 	}
19350Sstevel@tonic-gate 	if (predict != blksread - 1)
19360Sstevel@tonic-gate 		(void) fprintf(stderr,
19370Sstevel@tonic-gate 		    gettext("; predicted %ld blocks, got %ld blocks"),
19380Sstevel@tonic-gate 		    predict, blksread - 1);
19390Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");
19400Sstevel@tonic-gate newcalc:
19410Sstevel@tonic-gate 	blks = 0;
19420Sstevel@tonic-gate 	if (header->c_type != TS_END)
19430Sstevel@tonic-gate 		for (i = 0; i < header->c_count; i++)
19440Sstevel@tonic-gate 			if ((i >= TP_NINDIR) || (header->c_addr[i] != 0))
19450Sstevel@tonic-gate 				blks++;
19460Sstevel@tonic-gate 	predict = blks;
19470Sstevel@tonic-gate 	blksread = 0;
19480Sstevel@tonic-gate 	prevtype = header->c_type;
19490Sstevel@tonic-gate 	previno = header->c_inumber;
19500Sstevel@tonic-gate }
19510Sstevel@tonic-gate 
19520Sstevel@tonic-gate /*
19530Sstevel@tonic-gate  * Try to determine which volume a file resides on.
19540Sstevel@tonic-gate  */
19551053Smaheshvs int
volnumber(ino_t inum)19561053Smaheshvs volnumber(ino_t inum)
19570Sstevel@tonic-gate {
19580Sstevel@tonic-gate 	int i;
19590Sstevel@tonic-gate 
19600Sstevel@tonic-gate 	if (inodeinfo == 0)
19610Sstevel@tonic-gate 		return (0);
19620Sstevel@tonic-gate 	for (i = 1; i <= dumpinfo.c_volume; i++)
19630Sstevel@tonic-gate 		if (inum < (ino_t)(unsigned)(dumpinfo.c_inos[i]))
19640Sstevel@tonic-gate 			break;
19650Sstevel@tonic-gate 	return (i - 1);
19660Sstevel@tonic-gate }
19670Sstevel@tonic-gate 
19680Sstevel@tonic-gate /*
19690Sstevel@tonic-gate  * Find an inode header.
19700Sstevel@tonic-gate  * Note that *header must be stable storage, as curfile will end up with
19710Sstevel@tonic-gate  * pointers into it.
19720Sstevel@tonic-gate  */
19730Sstevel@tonic-gate void
findinode(struct s_spcl * header)19741053Smaheshvs findinode(struct s_spcl *header)
19750Sstevel@tonic-gate {
19760Sstevel@tonic-gate 	long skipcnt = 0;
19770Sstevel@tonic-gate 	int i;
19780Sstevel@tonic-gate 	char buf[TP_BSIZE_MAX];
19790Sstevel@tonic-gate 
19800Sstevel@tonic-gate 	curfile.name = gettext("<name unknown>");
19810Sstevel@tonic-gate 	curfile.action = UNKNOWN;
19820Sstevel@tonic-gate 	curfile.dip = (struct dinode *)NULL;
19830Sstevel@tonic-gate 	curfile.ino = 0;
19840Sstevel@tonic-gate 	curfile.ts = 0;
19850Sstevel@tonic-gate 	if (ishead(header) == FAIL) {
19860Sstevel@tonic-gate 		skipcnt++;
19870Sstevel@tonic-gate 		while (gethead(header) == FAIL ||
19880Sstevel@tonic-gate 		    (time_t)(header->c_date) != dumpdate)
19890Sstevel@tonic-gate 			skipcnt++;
19900Sstevel@tonic-gate 	}
19910Sstevel@tonic-gate 	for (;;) {
19920Sstevel@tonic-gate 		if (checktype(header, TS_ADDR) == GOOD) {
19930Sstevel@tonic-gate 			/*
19940Sstevel@tonic-gate 			 * Skip up to the beginning of the next record
19950Sstevel@tonic-gate 			 */
19960Sstevel@tonic-gate 			for (i = 0; i < header->c_count; i++)
19970Sstevel@tonic-gate 				if ((i >= TP_NINDIR) || (header->c_addr[i]))
19980Sstevel@tonic-gate 					readtape(buf);
19990Sstevel@tonic-gate 			(void) gethead(header);
20000Sstevel@tonic-gate 			continue;
20010Sstevel@tonic-gate 		}
20020Sstevel@tonic-gate 		if (checktype(header, TS_INODE) == GOOD) {
20030Sstevel@tonic-gate 			curfile.dip = &header->c_dinode;
20040Sstevel@tonic-gate 			if (curfile.dip->di_suid != UID_LONG)
20050Sstevel@tonic-gate 				curfile.dip->di_uid = curfile.dip->di_suid;
20060Sstevel@tonic-gate 			if (curfile.dip->di_sgid != GID_LONG)
20070Sstevel@tonic-gate 				curfile.dip->di_gid = curfile.dip->di_sgid;
20080Sstevel@tonic-gate 			curfile.ino = header->c_inumber;
20090Sstevel@tonic-gate 			curfile.ts = TS_INODE;
20100Sstevel@tonic-gate 			break;
20110Sstevel@tonic-gate 		}
20120Sstevel@tonic-gate 		if (checktype(header, TS_END) == GOOD) {
20130Sstevel@tonic-gate 			curfile.ino = maxino;
20140Sstevel@tonic-gate 			curfile.ts = TS_END;
20150Sstevel@tonic-gate 			break;
20160Sstevel@tonic-gate 		}
20170Sstevel@tonic-gate 		if (checktype(header, TS_CLRI) == GOOD) {
20180Sstevel@tonic-gate 			curfile.name = gettext("<file removal list>");
20190Sstevel@tonic-gate 			curfile.ts = TS_CLRI;
20200Sstevel@tonic-gate 			break;
20210Sstevel@tonic-gate 		}
20220Sstevel@tonic-gate 		if (checktype(header, TS_BITS) == GOOD) {
20230Sstevel@tonic-gate 			curfile.name = gettext("<file dump list>");
20240Sstevel@tonic-gate 			curfile.ts = TS_BITS;
20250Sstevel@tonic-gate 			break;
20260Sstevel@tonic-gate 		}
20270Sstevel@tonic-gate 		while (gethead(header) == FAIL)
20280Sstevel@tonic-gate 			skipcnt++;
20290Sstevel@tonic-gate 	}
20300Sstevel@tonic-gate 	if (skipcnt > 0)
20310Sstevel@tonic-gate 		(void) fprintf(stderr,
20320Sstevel@tonic-gate 		    gettext("resync restore, skipped %d blocks\n"),
20330Sstevel@tonic-gate 		    skipcnt);
20340Sstevel@tonic-gate }
20350Sstevel@tonic-gate 
20360Sstevel@tonic-gate /*
20370Sstevel@tonic-gate  * return whether or not the buffer contains a header block
20380Sstevel@tonic-gate  */
20390Sstevel@tonic-gate static int
ishead(struct s_spcl * buf)20401053Smaheshvs ishead(struct s_spcl *buf)
20410Sstevel@tonic-gate {
20420Sstevel@tonic-gate 	if (buf->c_magic !=
20430Sstevel@tonic-gate 	    ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC))
20440Sstevel@tonic-gate 		return (FAIL);
20450Sstevel@tonic-gate 	return (GOOD);
20460Sstevel@tonic-gate }
20470Sstevel@tonic-gate 
20481053Smaheshvs static int
checktype(struct s_spcl * b,int t)20491053Smaheshvs checktype(struct s_spcl *b, int t)
20500Sstevel@tonic-gate {
20510Sstevel@tonic-gate 	if (b->c_type != t)
20520Sstevel@tonic-gate 		return (FAIL);
20530Sstevel@tonic-gate 	return (GOOD);
20540Sstevel@tonic-gate }
20550Sstevel@tonic-gate 
20560Sstevel@tonic-gate /*
20570Sstevel@tonic-gate  * If autoloading is enabled, attempt to do it.  If we succeed,
20580Sstevel@tonic-gate  * return non-zero.
20590Sstevel@tonic-gate  */
20600Sstevel@tonic-gate static int
autoload_tape(void)20610Sstevel@tonic-gate autoload_tape(void)
20620Sstevel@tonic-gate {
20630Sstevel@tonic-gate 	int result = 0;		/* assume failure */
20640Sstevel@tonic-gate 	int tries;
20650Sstevel@tonic-gate 	int fd;
20660Sstevel@tonic-gate 
20670Sstevel@tonic-gate 	if (autoload) {
20680Sstevel@tonic-gate 		/*
20690Sstevel@tonic-gate 		 * Wait for the tape to autoload.  Note that the delay
20700Sstevel@tonic-gate 		 * period doesn't take into account however long it takes
20710Sstevel@tonic-gate 		 * for the open to fail (measured at 21 seconds for an
20720Sstevel@tonic-gate 		 * Exabyte 8200 under 2.7 on an Ultra 2).
20730Sstevel@tonic-gate 		 */
2074426Srm88369 
2075426Srm88369 		/* rewind tape and offline drive before loading new tape */
2076426Srm88369 		closemt(FORCE_OFFLINE);
20770Sstevel@tonic-gate 		(void) fprintf(stderr,
20780Sstevel@tonic-gate 		    gettext("Attempting to autoload next volume\n"));
20790Sstevel@tonic-gate 		for (tries = 0; tries < autoload_tries; tries++) {
20800Sstevel@tonic-gate 			if (host) {
20810Sstevel@tonic-gate 				if (rmtopen(magtape, O_RDONLY) >= 0) {
20820Sstevel@tonic-gate 					rmtclose();
20830Sstevel@tonic-gate 					result = 1;
20840Sstevel@tonic-gate 					break;
20850Sstevel@tonic-gate 				}
20860Sstevel@tonic-gate 			} else {
20870Sstevel@tonic-gate 				if ((fd = open(magtape, O_RDONLY|O_LARGEFILE,
20880Sstevel@tonic-gate 				    0600)) >= 0) {
20890Sstevel@tonic-gate 					(void) close(fd);
20900Sstevel@tonic-gate 					result = 1;
20910Sstevel@tonic-gate 					break;
20920Sstevel@tonic-gate 				}
20930Sstevel@tonic-gate 			}
20940Sstevel@tonic-gate 			(void) sleep(autoload_period);
20950Sstevel@tonic-gate 		}
20960Sstevel@tonic-gate 		if (result == 0) {
20970Sstevel@tonic-gate 			/* Assume caller will deal with manual change-over */
20980Sstevel@tonic-gate 			(void) fprintf(stderr,
20990Sstevel@tonic-gate 			    gettext("Autoload timed out\n"));
21000Sstevel@tonic-gate 		} else {
21010Sstevel@tonic-gate 			if ((host != NULL &&
21020Sstevel@tonic-gate 			    (mt = rmtopen(magtape, O_RDONLY)) == -1) ||
21030Sstevel@tonic-gate 			    (host == NULL &&
21040Sstevel@tonic-gate 			    (mt = open(magtape, O_RDONLY|O_LARGEFILE)) == -1)) {
21050Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
21060Sstevel@tonic-gate 				    "Autoload could not re-open tape\n"));
21070Sstevel@tonic-gate 				result = 0;
21080Sstevel@tonic-gate 			} else {
21090Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
21100Sstevel@tonic-gate 				    "Tape loaded\n"));
21110Sstevel@tonic-gate 			}
21120Sstevel@tonic-gate 		}
21130Sstevel@tonic-gate 	}
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 	return (result);
21160Sstevel@tonic-gate }
2117