xref: /onnv-gate/usr/src/cmd/backup/restore/tape.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright (c) 1983 Regents of the University of California.
3*0Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
4*0Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
5*0Sstevel@tonic-gate  */
6*0Sstevel@tonic-gate 
7*0Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
8*0Sstevel@tonic-gate /*	  All Rights Reserved	*/
9*0Sstevel@tonic-gate 
10*0Sstevel@tonic-gate /*
11*0Sstevel@tonic-gate  * Copyright 1994, 1996, 1998-2003 Sun Microsystems, Inc.  All rights reserved.
12*0Sstevel@tonic-gate  * Use is subject to license terms.
13*0Sstevel@tonic-gate  */
14*0Sstevel@tonic-gate 
15*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
16*0Sstevel@tonic-gate 
17*0Sstevel@tonic-gate #include <setjmp.h>
18*0Sstevel@tonic-gate #include "restore.h"
19*0Sstevel@tonic-gate #include <byteorder.h>
20*0Sstevel@tonic-gate #include <rmt.h>
21*0Sstevel@tonic-gate #include <sys/mtio.h>
22*0Sstevel@tonic-gate #include <utime.h>
23*0Sstevel@tonic-gate #include <sys/errno.h>
24*0Sstevel@tonic-gate #include <sys/fdio.h>
25*0Sstevel@tonic-gate #include <sys/sysmacros.h>	/* for expdev */
26*0Sstevel@tonic-gate #include <assert.h>
27*0Sstevel@tonic-gate #include <limits.h>
28*0Sstevel@tonic-gate #include <priv_utils.h>
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate #define	MAXINO	65535		/* KLUDGE */
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate #define	MAXTAPES	128
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate static size_t	fssize = MAXBSIZE; /* preferred size of writes to filesystem */
35*0Sstevel@tonic-gate int mt = -1;
36*0Sstevel@tonic-gate static int	continuemap = 0;
37*0Sstevel@tonic-gate char		magtape[BUFSIZ];
38*0Sstevel@tonic-gate int		pipein = 0;
39*0Sstevel@tonic-gate char		*host;		/* used in dumprmt.c */
40*0Sstevel@tonic-gate daddr32_t	rec_position;
41*0Sstevel@tonic-gate static char	*archivefile;	/* used in metamucil.c */
42*0Sstevel@tonic-gate static int	bct;		/* block # index into tape record buffer */
43*0Sstevel@tonic-gate static int	numtrec;	/* # of logical blocks in current tape record */
44*0Sstevel@tonic-gate static char	*tbf = NULL;
45*0Sstevel@tonic-gate static size_t	tbfsize = 0;
46*0Sstevel@tonic-gate static int	recsread;
47*0Sstevel@tonic-gate static union	u_spcl endoftapemark;
48*0Sstevel@tonic-gate static struct	s_spcl dumpinfo;
49*0Sstevel@tonic-gate static long	blksread;	/* # of logical blocks actually read/touched */
50*0Sstevel@tonic-gate static long	tapea;		/* current logical block # on tape */
51*0Sstevel@tonic-gate static uchar_t	tapesread[MAXTAPES];
52*0Sstevel@tonic-gate static jmp_buf	restart;
53*0Sstevel@tonic-gate static int	gettingfile = 0;	/* restart has a valid frame */
54*0Sstevel@tonic-gate static int	ofile;
55*0Sstevel@tonic-gate static char	*map, *beginmap;
56*0Sstevel@tonic-gate static char	*endmap;
57*0Sstevel@tonic-gate static char	lnkbuf[MAXPATHLEN + 2];
58*0Sstevel@tonic-gate static int	pathlen;
59*0Sstevel@tonic-gate static int	inodeinfo;	/* Have starting volume information */
60*0Sstevel@tonic-gate static int	hostinfo;	/* Have dump host information */
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate #ifdef __STDC__
63*0Sstevel@tonic-gate static int autoload_tape(void);
64*0Sstevel@tonic-gate static void setdumpnum(void);
65*0Sstevel@tonic-gate static void metacheck(struct s_spcl *);
66*0Sstevel@tonic-gate static void xtrmeta(char *, size_t);
67*0Sstevel@tonic-gate static void metaskip(char *, size_t);
68*0Sstevel@tonic-gate static void xtrfile(char *, size_t);
69*0Sstevel@tonic-gate static void xtrskip(char *, size_t);
70*0Sstevel@tonic-gate static void xtrlnkfile(char *, size_t);
71*0Sstevel@tonic-gate static void xtrlnkskip(char *, size_t);
72*0Sstevel@tonic-gate static void xtrmap(char *, size_t);
73*0Sstevel@tonic-gate static void xtrmapskip(char *, size_t);
74*0Sstevel@tonic-gate static void readtape(char *);
75*0Sstevel@tonic-gate static int checkvol(struct s_spcl *, int);
76*0Sstevel@tonic-gate static void accthdr(struct s_spcl *);
77*0Sstevel@tonic-gate static int ishead(struct s_spcl *);
78*0Sstevel@tonic-gate static checktype(struct s_spcl *, int);
79*0Sstevel@tonic-gate static void metaset(char *name);
80*0Sstevel@tonic-gate #else
81*0Sstevel@tonic-gate static int autoload_tape();
82*0Sstevel@tonic-gate static void setdumpnum();
83*0Sstevel@tonic-gate static void metacheck();
84*0Sstevel@tonic-gate static void xtrmeta();
85*0Sstevel@tonic-gate static void metaskip();
86*0Sstevel@tonic-gate static void xtrfile();
87*0Sstevel@tonic-gate static void xtrskip();
88*0Sstevel@tonic-gate static void xtrlnkfile();
89*0Sstevel@tonic-gate static void xtrlnkskip();
90*0Sstevel@tonic-gate static void xtrmap();
91*0Sstevel@tonic-gate static void xtrmapskip();
92*0Sstevel@tonic-gate static void readtape();
93*0Sstevel@tonic-gate static int checkvol();
94*0Sstevel@tonic-gate static void accthdr();
95*0Sstevel@tonic-gate static int ishead();
96*0Sstevel@tonic-gate static checktype();
97*0Sstevel@tonic-gate static void metaset();
98*0Sstevel@tonic-gate #endif
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate /*
101*0Sstevel@tonic-gate  * Set up an input source
102*0Sstevel@tonic-gate  */
103*0Sstevel@tonic-gate void
104*0Sstevel@tonic-gate setinput(source, archive)
105*0Sstevel@tonic-gate 	char *source;
106*0Sstevel@tonic-gate 	char *archive;
107*0Sstevel@tonic-gate {
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 	flsht();
110*0Sstevel@tonic-gate 	archivefile = archive;
111*0Sstevel@tonic-gate 	if (bflag == 0) {
112*0Sstevel@tonic-gate 		ntrec = ((CARTRIDGETREC > HIGHDENSITYTREC) ?
113*0Sstevel@tonic-gate 		    (NTREC > CARTRIDGETREC ? NTREC : CARTRIDGETREC) :
114*0Sstevel@tonic-gate 		    (NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC));
115*0Sstevel@tonic-gate 		saved_ntrec = (ntrec * (tp_bsize/DEV_BSIZE));
116*0Sstevel@tonic-gate 	}
117*0Sstevel@tonic-gate 	newtapebuf(ntrec);
118*0Sstevel@tonic-gate 	terminal = stdin;
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	if (source == NULL) {
121*0Sstevel@tonic-gate 		/* A can't-happen */
122*0Sstevel@tonic-gate 		(void) fprintf(stderr,
123*0Sstevel@tonic-gate 		    gettext("Internal consistency check failed.\n"));
124*0Sstevel@tonic-gate 		done(1);
125*0Sstevel@tonic-gate 	}
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 	if (strchr(source, ':')) {
128*0Sstevel@tonic-gate 		char *tape;
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 		host = source;
131*0Sstevel@tonic-gate 		tape = strchr(host, ':');
132*0Sstevel@tonic-gate 		*tape++ = '\0';
133*0Sstevel@tonic-gate 		if (strlen(tape) > (sizeof (magtape) - 1)) {
134*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Tape name too long\n"));
135*0Sstevel@tonic-gate 			done(1);
136*0Sstevel@tonic-gate 		}
137*0Sstevel@tonic-gate 		(void) strcpy(magtape, tape);
138*0Sstevel@tonic-gate 		if (rmthost(host, ntrec) == 0)
139*0Sstevel@tonic-gate 			done(1);
140*0Sstevel@tonic-gate 	} else {
141*0Sstevel@tonic-gate 		if (strlen(source) > (sizeof (magtape) - 1)) {
142*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Tape name too long\n"));
143*0Sstevel@tonic-gate 			done(1);
144*0Sstevel@tonic-gate 		}
145*0Sstevel@tonic-gate 		/* Not remote, no need for privileges */
146*0Sstevel@tonic-gate 		__priv_relinquish();
147*0Sstevel@tonic-gate 		host = NULL;
148*0Sstevel@tonic-gate 		if (strcmp(source, "-") == 0) {
149*0Sstevel@tonic-gate 			/*
150*0Sstevel@tonic-gate 			 * Since input is coming from a pipe we must establish
151*0Sstevel@tonic-gate 			 * our own connection to the terminal.
152*0Sstevel@tonic-gate 			 */
153*0Sstevel@tonic-gate 			terminal = fopen("/dev/tty", "r");
154*0Sstevel@tonic-gate 			if (terminal == NULL) {
155*0Sstevel@tonic-gate 				int saverr = errno;
156*0Sstevel@tonic-gate 				char *msg =
157*0Sstevel@tonic-gate 					gettext("Cannot open(\"/dev/tty\")");
158*0Sstevel@tonic-gate 				errno = saverr;
159*0Sstevel@tonic-gate 				perror(msg);
160*0Sstevel@tonic-gate 				terminal = fopen("/dev/null", "r");
161*0Sstevel@tonic-gate 				if (terminal == NULL) {
162*0Sstevel@tonic-gate 					saverr = errno;
163*0Sstevel@tonic-gate 					msg = gettext(
164*0Sstevel@tonic-gate 					    "Cannot open(\"/dev/null\")");
165*0Sstevel@tonic-gate 					errno = saverr;
166*0Sstevel@tonic-gate 					perror(msg);
167*0Sstevel@tonic-gate 					done(1);
168*0Sstevel@tonic-gate 				}
169*0Sstevel@tonic-gate 			}
170*0Sstevel@tonic-gate 			pipein++;
171*0Sstevel@tonic-gate 			if (archive) {
172*0Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
173*0Sstevel@tonic-gate 	    "Cannot specify an archive file when reading from a pipe\n"));
174*0Sstevel@tonic-gate 				done(1);
175*0Sstevel@tonic-gate 			}
176*0Sstevel@tonic-gate 		}
177*0Sstevel@tonic-gate 		(void) strcpy(magtape, source);
178*0Sstevel@tonic-gate 	}
179*0Sstevel@tonic-gate }
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate void
182*0Sstevel@tonic-gate newtapebuf(size)
183*0Sstevel@tonic-gate 	size_t size;
184*0Sstevel@tonic-gate {
185*0Sstevel@tonic-gate 	size_t nsize;
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	nsize = size * tp_bsize;
188*0Sstevel@tonic-gate 	ntrec = size;
189*0Sstevel@tonic-gate 	if (nsize <= tbfsize)
190*0Sstevel@tonic-gate 		return;
191*0Sstevel@tonic-gate 	if (tbf != NULL)
192*0Sstevel@tonic-gate 		free(tbf);
193*0Sstevel@tonic-gate 	tbf = (char *)malloc(nsize);
194*0Sstevel@tonic-gate 	if (tbf == NULL) {
195*0Sstevel@tonic-gate 		(void) fprintf(stderr,
196*0Sstevel@tonic-gate 		    gettext("Cannot allocate space for buffer\n"));
197*0Sstevel@tonic-gate 		done(1);
198*0Sstevel@tonic-gate 	}
199*0Sstevel@tonic-gate 	tbfsize = nsize;
200*0Sstevel@tonic-gate }
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate /*
203*0Sstevel@tonic-gate  * Verify that the tape drive can be accessed and
204*0Sstevel@tonic-gate  * that it actually is a dump tape.
205*0Sstevel@tonic-gate  */
206*0Sstevel@tonic-gate void
207*0Sstevel@tonic-gate #ifdef __STDC__
208*0Sstevel@tonic-gate setup(void)
209*0Sstevel@tonic-gate #else
210*0Sstevel@tonic-gate setup()
211*0Sstevel@tonic-gate #endif
212*0Sstevel@tonic-gate {
213*0Sstevel@tonic-gate 	int i, j;
214*0Sstevel@tonic-gate 	int32_t *ip;
215*0Sstevel@tonic-gate 	struct stat stbuf;
216*0Sstevel@tonic-gate 	size_t mapsize;
217*0Sstevel@tonic-gate 	char *syment = RESTORESYMTABLE;
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate 	vprintf(stdout, gettext("Verify volume and initialize maps\n"));
220*0Sstevel@tonic-gate 	if (archivefile) {
221*0Sstevel@tonic-gate 		mt = open(archivefile, O_RDONLY|O_LARGEFILE);
222*0Sstevel@tonic-gate 		if (mt < 0) {
223*0Sstevel@tonic-gate 			perror(archivefile);
224*0Sstevel@tonic-gate 			done(1);
225*0Sstevel@tonic-gate 		}
226*0Sstevel@tonic-gate 		volno = 0;
227*0Sstevel@tonic-gate 	} else if (host) {
228*0Sstevel@tonic-gate 		if ((mt = rmtopen(magtape, O_RDONLY)) < 0) {
229*0Sstevel@tonic-gate 			perror(magtape);
230*0Sstevel@tonic-gate 			done(1);
231*0Sstevel@tonic-gate 		}
232*0Sstevel@tonic-gate 		volno = 1;
233*0Sstevel@tonic-gate 	} else {
234*0Sstevel@tonic-gate 		if (pipein)
235*0Sstevel@tonic-gate 			mt = 0;
236*0Sstevel@tonic-gate 		else if ((mt = open(magtape, O_RDONLY|O_LARGEFILE)) < 0) {
237*0Sstevel@tonic-gate 			perror(magtape);
238*0Sstevel@tonic-gate 			done(1);
239*0Sstevel@tonic-gate 		}
240*0Sstevel@tonic-gate 		volno = 1;
241*0Sstevel@tonic-gate 	}
242*0Sstevel@tonic-gate 	setdumpnum();
243*0Sstevel@tonic-gate 	flsht();
244*0Sstevel@tonic-gate 	if (!pipein && !bflag)
245*0Sstevel@tonic-gate 		if (archivefile)
246*0Sstevel@tonic-gate 			findtapeblksize(ARCHIVE_FILE);
247*0Sstevel@tonic-gate 		else
248*0Sstevel@tonic-gate 			findtapeblksize(TAPE_FILE);
249*0Sstevel@tonic-gate 	if (bflag == 1) {
250*0Sstevel@tonic-gate 		tape_rec_size = saved_ntrec * DEV_BSIZE;
251*0Sstevel@tonic-gate 	}
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	/*
254*0Sstevel@tonic-gate 	 * Get the first header.  If c_magic is NOT NFS_MAGIC or if
255*0Sstevel@tonic-gate 	 * the checksum is in error, it will fail.  The magic could then
256*0Sstevel@tonic-gate 	 * be either OFS_MAGIC or MTB_MAGIC.  If OFS_MAGIC, assume we
257*0Sstevel@tonic-gate 	 * have an old dump, and try to convert it.  If it is MTB_MAGIC, we
258*0Sstevel@tonic-gate 	 * procees this after.
259*0Sstevel@tonic-gate 	 */
260*0Sstevel@tonic-gate 	if ((gethead(&spcl) == FAIL) && (spcl.c_magic != MTB_MAGIC)) {
261*0Sstevel@tonic-gate 		bct--; /* push back this block */
262*0Sstevel@tonic-gate 		blksread--;
263*0Sstevel@tonic-gate 		tapea--;
264*0Sstevel@tonic-gate 		cvtflag++;
265*0Sstevel@tonic-gate 		if (gethead(&spcl) == FAIL) {
266*0Sstevel@tonic-gate 			(void) fprintf(stderr,
267*0Sstevel@tonic-gate 			    gettext("Volume is not in dump format\n"));
268*0Sstevel@tonic-gate 			done(1);
269*0Sstevel@tonic-gate 		}
270*0Sstevel@tonic-gate 		(void) fprintf(stderr,
271*0Sstevel@tonic-gate 		    gettext("Converting to new file system format.\n"));
272*0Sstevel@tonic-gate 	}
273*0Sstevel@tonic-gate 	/*
274*0Sstevel@tonic-gate 	 * The above gethead will have failed if the magic is
275*0Sstevel@tonic-gate 	 * MTB_MAGIC. If that is true, we need to adjust tp_bsize.
276*0Sstevel@tonic-gate 	 * We have assumed to this time that tp_bsize was 1024, if
277*0Sstevel@tonic-gate 	 * this is a newer dump, get the real tp_bsize from the header,
278*0Sstevel@tonic-gate 	 * and recalculate ntrec, numtrec.
279*0Sstevel@tonic-gate 	 */
280*0Sstevel@tonic-gate 	if (spcl.c_magic == MTB_MAGIC) {
281*0Sstevel@tonic-gate 		tp_bsize = spcl.c_tpbsize;
282*0Sstevel@tonic-gate 		if ((tp_bsize % TP_BSIZE_MIN != 0) ||
283*0Sstevel@tonic-gate 		    (tp_bsize > TP_BSIZE_MAX)) {
284*0Sstevel@tonic-gate 			(void) fprintf(stderr,
285*0Sstevel@tonic-gate 			    gettext("Volume is not in dump format\n"));
286*0Sstevel@tonic-gate 			done(1);
287*0Sstevel@tonic-gate 		}
288*0Sstevel@tonic-gate 		ntrec = (tape_rec_size/tp_bsize);
289*0Sstevel@tonic-gate 		numtrec = ntrec;
290*0Sstevel@tonic-gate 		newtapebuf(ntrec);
291*0Sstevel@tonic-gate 		bct--; /* push back this block */
292*0Sstevel@tonic-gate 		blksread--;
293*0Sstevel@tonic-gate 		tapea--;
294*0Sstevel@tonic-gate 		/* we have to re-do this in case checksum is wrong */
295*0Sstevel@tonic-gate 		if (gethead(&spcl) == FAIL) {
296*0Sstevel@tonic-gate 			(void) fprintf(stderr,
297*0Sstevel@tonic-gate 			    gettext("Volume is not in dump format\n"));
298*0Sstevel@tonic-gate 			done(1);
299*0Sstevel@tonic-gate 		}
300*0Sstevel@tonic-gate 	}
301*0Sstevel@tonic-gate 	if (vflag)
302*0Sstevel@tonic-gate 		byteorder_banner(byteorder, stdout);
303*0Sstevel@tonic-gate 	if (pipein) {
304*0Sstevel@tonic-gate 		endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC :
305*0Sstevel@tonic-gate 		    ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC);
306*0Sstevel@tonic-gate 		endoftapemark.s_spcl.c_type = TS_END;
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 		/*
309*0Sstevel@tonic-gate 		 * include this since the `resync' loop in findinode
310*0Sstevel@tonic-gate 		 * expects to find a header with the c_date field
311*0Sstevel@tonic-gate 		 * filled in.
312*0Sstevel@tonic-gate 		 */
313*0Sstevel@tonic-gate 		endoftapemark.s_spcl.c_date = spcl.c_date;
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 		ip = (int32_t *)&endoftapemark;
316*0Sstevel@tonic-gate 		/*LINTED [assertion always true]*/
317*0Sstevel@tonic-gate 		assert((sizeof (endoftapemark) % sizeof (int32_t)) == 0);
318*0Sstevel@tonic-gate 		j = sizeof (endoftapemark) / sizeof (int32_t);
319*0Sstevel@tonic-gate 		i = 0;
320*0Sstevel@tonic-gate 		do
321*0Sstevel@tonic-gate 			i += *ip++;
322*0Sstevel@tonic-gate 		while (--j);
323*0Sstevel@tonic-gate 		endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
324*0Sstevel@tonic-gate 	}
325*0Sstevel@tonic-gate 	if (vflag && command != 't')
326*0Sstevel@tonic-gate 		printdumpinfo();
327*0Sstevel@tonic-gate 	dumptime = spcl.c_ddate;
328*0Sstevel@tonic-gate 	dumpdate = spcl.c_date;
329*0Sstevel@tonic-gate 	if (stat(".", &stbuf) < 0) {
330*0Sstevel@tonic-gate 		perror(gettext("cannot stat ."));
331*0Sstevel@tonic-gate 		done(1);
332*0Sstevel@tonic-gate 	}
333*0Sstevel@tonic-gate 	if (stbuf.st_blksize >= tp_bsize && stbuf.st_blksize <= MAXBSIZE) {
334*0Sstevel@tonic-gate 		/* LINTED: value fits in a size_t */
335*0Sstevel@tonic-gate 		fssize = stbuf.st_blksize;
336*0Sstevel@tonic-gate 	}
337*0Sstevel@tonic-gate 	if (((fssize - 1) & fssize) != 0) {
338*0Sstevel@tonic-gate 		(void) fprintf(stderr,
339*0Sstevel@tonic-gate 		    gettext("bad filesystem block size %d\n"), fssize);
340*0Sstevel@tonic-gate 		done(1);
341*0Sstevel@tonic-gate 	}
342*0Sstevel@tonic-gate 	if (checkvol(&spcl, 1) == FAIL) {
343*0Sstevel@tonic-gate 		(void) fprintf(stderr,
344*0Sstevel@tonic-gate 		    gettext("This is not volume 1 of the dump\n"));
345*0Sstevel@tonic-gate 		done(1);
346*0Sstevel@tonic-gate 	}
347*0Sstevel@tonic-gate 	if (readhdr(&spcl) == FAIL)
348*0Sstevel@tonic-gate 		panic(gettext("no header after volume mark!\n"));
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	findinode(&spcl);	/* sets curfile, resyncs the tape if need be */
351*0Sstevel@tonic-gate 	if (checktype(&spcl, TS_CLRI) == FAIL) {
352*0Sstevel@tonic-gate 		(void) fprintf(stderr,
353*0Sstevel@tonic-gate 		    gettext("Cannot find file removal list\n"));
354*0Sstevel@tonic-gate 		done(1);
355*0Sstevel@tonic-gate 	}
356*0Sstevel@tonic-gate 	maxino = (unsigned)((spcl.c_count * tp_bsize * NBBY) + 1);
357*0Sstevel@tonic-gate 	dprintf(stdout, "maxino = %lu\n", maxino);
358*0Sstevel@tonic-gate 	/*
359*0Sstevel@tonic-gate 	 * Allocate space for at least MAXINO inodes to allow us
360*0Sstevel@tonic-gate 	 * to restore partial dump tapes written before dump was
361*0Sstevel@tonic-gate 	 * fixed to write out the entire inode map.
362*0Sstevel@tonic-gate 	 */
363*0Sstevel@tonic-gate 	if (maxino > ULONG_MAX) {
364*0Sstevel@tonic-gate 		(void) fprintf(stderr,
365*0Sstevel@tonic-gate 		    gettext("file system too large\n"));
366*0Sstevel@tonic-gate 		done(1);
367*0Sstevel@tonic-gate 	}
368*0Sstevel@tonic-gate 	/* LINTED maxino size-checked above */
369*0Sstevel@tonic-gate 	mapsize = (size_t)d_howmany(maxino > MAXINO ? maxino : MAXINO, NBBY);
370*0Sstevel@tonic-gate 	beginmap = map = calloc((size_t)1, mapsize);
371*0Sstevel@tonic-gate 	if (map == (char *)NIL) {
372*0Sstevel@tonic-gate 		(void) fprintf(stderr,
373*0Sstevel@tonic-gate 		    gettext("no memory for file removal list\n"));
374*0Sstevel@tonic-gate 		done(1);
375*0Sstevel@tonic-gate 	}
376*0Sstevel@tonic-gate 	endmap = map + mapsize;
377*0Sstevel@tonic-gate 	clrimap = map;
378*0Sstevel@tonic-gate 	curfile.action = USING;
379*0Sstevel@tonic-gate 	continuemap = 1;
380*0Sstevel@tonic-gate 	getfile(xtrmap, xtrmapskip);
381*0Sstevel@tonic-gate 	if (MAXINO > maxino)
382*0Sstevel@tonic-gate 		maxino = MAXINO;
383*0Sstevel@tonic-gate 	if (checktype(&spcl, TS_BITS) == FAIL) {
384*0Sstevel@tonic-gate 		/* if we have TS_CLRI then no TS_BITS then a TS_END */
385*0Sstevel@tonic-gate 		/* then we have an empty dump file */
386*0Sstevel@tonic-gate 		if (gethead(&spcl) == GOOD && checktype(&spcl, TS_END) == GOOD)
387*0Sstevel@tonic-gate 		{
388*0Sstevel@tonic-gate 			if ((command == 'r') || (command == 'R')) {
389*0Sstevel@tonic-gate 				initsymtable(syment);
390*0Sstevel@tonic-gate 				dumpsymtable(syment, volno);
391*0Sstevel@tonic-gate 			}
392*0Sstevel@tonic-gate 			done(0);
393*0Sstevel@tonic-gate 		}
394*0Sstevel@tonic-gate 		/* otherwise we have an error */
395*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot find file dump list\n"));
396*0Sstevel@tonic-gate 		done(1);
397*0Sstevel@tonic-gate 	}
398*0Sstevel@tonic-gate 	/* LINTED maxino size-checked above */
399*0Sstevel@tonic-gate 	mapsize = (size_t)d_howmany(maxino, NBBY);
400*0Sstevel@tonic-gate 	beginmap = map = calloc((size_t)1, mapsize);
401*0Sstevel@tonic-gate 	if (map == (char *)NULL) {
402*0Sstevel@tonic-gate 		(void) fprintf(stderr,
403*0Sstevel@tonic-gate 		    gettext("no memory for file dump list\n"));
404*0Sstevel@tonic-gate 		done(1);
405*0Sstevel@tonic-gate 	}
406*0Sstevel@tonic-gate 	endmap = map + mapsize;
407*0Sstevel@tonic-gate 	dumpmap = map;
408*0Sstevel@tonic-gate 	curfile.action = USING;
409*0Sstevel@tonic-gate 	continuemap = 1;
410*0Sstevel@tonic-gate 	getfile(xtrmap, xtrmapskip);
411*0Sstevel@tonic-gate 	continuemap = 0;
412*0Sstevel@tonic-gate }
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate /*
415*0Sstevel@tonic-gate  * Initialize fssize variable for 'R' command to work.
416*0Sstevel@tonic-gate  */
417*0Sstevel@tonic-gate void
418*0Sstevel@tonic-gate #ifdef __STDC__
419*0Sstevel@tonic-gate setupR(void)
420*0Sstevel@tonic-gate #else
421*0Sstevel@tonic-gate setupR()
422*0Sstevel@tonic-gate #endif
423*0Sstevel@tonic-gate {
424*0Sstevel@tonic-gate 	struct stat stbuf;
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 	if (stat(".", &stbuf) < 0) {
427*0Sstevel@tonic-gate 		perror(gettext("cannot stat ."));
428*0Sstevel@tonic-gate 		done(1);
429*0Sstevel@tonic-gate 	}
430*0Sstevel@tonic-gate 	if (stbuf.st_blksize >= tp_bsize && stbuf.st_blksize <= MAXBSIZE) {
431*0Sstevel@tonic-gate 		/* LINTED: value fits in a size_t */
432*0Sstevel@tonic-gate 		fssize = stbuf.st_blksize;
433*0Sstevel@tonic-gate 	}
434*0Sstevel@tonic-gate 	if (((fssize - 1) & fssize) != 0) {
435*0Sstevel@tonic-gate 		(void) fprintf(stderr,
436*0Sstevel@tonic-gate 		    gettext("bad filesystem block size %d\n"), fssize);
437*0Sstevel@tonic-gate 		done(1);
438*0Sstevel@tonic-gate 	}
439*0Sstevel@tonic-gate }
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate /*
442*0Sstevel@tonic-gate  * Prompt user to load a new dump volume.
443*0Sstevel@tonic-gate  * "Nextvol" is the next suggested volume to use.
444*0Sstevel@tonic-gate  * This suggested volume is enforced when doing full
445*0Sstevel@tonic-gate  * or incremental restores, but can be overrridden by
446*0Sstevel@tonic-gate  * the user when only extracting a subset of the files.
447*0Sstevel@tonic-gate  *
448*0Sstevel@tonic-gate  * first_time is used with archive files and can have 1 of 3 states:
449*0Sstevel@tonic-gate  *	FT_STATE_1	Tape has not been read yet
450*0Sstevel@tonic-gate  *	FT_STATE_2	Tape has been read but not positioned past directory
451*0Sstevel@tonic-gate  *			information
452*0Sstevel@tonic-gate  *	FT_STATE_3	Tape has been read and is reading file information
453*0Sstevel@tonic-gate  */
454*0Sstevel@tonic-gate #define	FT_STATE_1	1
455*0Sstevel@tonic-gate #define	FT_STATE_2	2
456*0Sstevel@tonic-gate #define	FT_STATE_3	3
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate void
459*0Sstevel@tonic-gate getvol(nextvol)
460*0Sstevel@tonic-gate 	int nextvol;
461*0Sstevel@tonic-gate {
462*0Sstevel@tonic-gate 	int newvol;
463*0Sstevel@tonic-gate 	long savecnt, savetapea, wantnext;
464*0Sstevel@tonic-gate 	long i;
465*0Sstevel@tonic-gate 	union u_spcl tmpspcl;
466*0Sstevel@tonic-gate #define	tmpbuf tmpspcl.s_spcl
467*0Sstevel@tonic-gate 	char buf[TP_BSIZE_MAX];
468*0Sstevel@tonic-gate 	static int first_time = FT_STATE_1;
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 	if (tbf == NULL) {
471*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
472*0Sstevel@tonic-gate 		    "Internal consistency failure in getvol: tbf is NULL\n"));
473*0Sstevel@tonic-gate 		done(1);
474*0Sstevel@tonic-gate 	}
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 	if (nextvol == 1) {
477*0Sstevel@tonic-gate 		for (i = 0;  i < MAXTAPES;  i++)
478*0Sstevel@tonic-gate 			tapesread[i] = 0;
479*0Sstevel@tonic-gate 		gettingfile = 0;
480*0Sstevel@tonic-gate 	}
481*0Sstevel@tonic-gate 	if (pipein) {
482*0Sstevel@tonic-gate 		if (nextvol != 1)
483*0Sstevel@tonic-gate 			panic(gettext("changing volumes on pipe input\n"));
484*0Sstevel@tonic-gate 		if (volno == 1)
485*0Sstevel@tonic-gate 			return;
486*0Sstevel@tonic-gate 		goto gethdr;
487*0Sstevel@tonic-gate 	}
488*0Sstevel@tonic-gate 	savecnt = blksread;	/* ignore volume verification tape i/o */
489*0Sstevel@tonic-gate 	savetapea = tapea;
490*0Sstevel@tonic-gate again:
491*0Sstevel@tonic-gate 	if (pipein)
492*0Sstevel@tonic-gate 		done(1); /* pipes do not get a second chance */
493*0Sstevel@tonic-gate 	if (command == 'R' || command == 'r' || curfile.action != SKIP) {
494*0Sstevel@tonic-gate 		wantnext = 1;
495*0Sstevel@tonic-gate 		newvol = nextvol;
496*0Sstevel@tonic-gate 	} else {
497*0Sstevel@tonic-gate 		wantnext = 0;
498*0Sstevel@tonic-gate 		newvol = 0;
499*0Sstevel@tonic-gate 	}
500*0Sstevel@tonic-gate 
501*0Sstevel@tonic-gate 	if (autoload) {
502*0Sstevel@tonic-gate 		if ((volno == 1) && (nextvol == 1)) {
503*0Sstevel@tonic-gate 			tapesread[volno-1]++;
504*0Sstevel@tonic-gate 			return;
505*0Sstevel@tonic-gate 		}
506*0Sstevel@tonic-gate 		if (autoload_tape()) {
507*0Sstevel@tonic-gate 			goto gethdr;
508*0Sstevel@tonic-gate 		}
509*0Sstevel@tonic-gate 	}
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	while (newvol <= 0) {
512*0Sstevel@tonic-gate 		int n = 0;
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 		for (i = 0;  i < MAXTAPES;  i++)
515*0Sstevel@tonic-gate 			if (tapesread[i])
516*0Sstevel@tonic-gate 				n++;
517*0Sstevel@tonic-gate 		if (n == 0) {
518*0Sstevel@tonic-gate 			(void) fprintf(stderr, "%s", gettext(
519*0Sstevel@tonic-gate "You have not read any volumes yet.\n\
520*0Sstevel@tonic-gate Unless you know which volume your file(s) are on you should start\n\
521*0Sstevel@tonic-gate with the last volume and work towards the first.\n"));
522*0Sstevel@tonic-gate 		} else {
523*0Sstevel@tonic-gate 			(void) fprintf(stderr,
524*0Sstevel@tonic-gate 			    gettext("You have read volumes"));
525*0Sstevel@tonic-gate 			(void) strcpy(tbf, ": ");
526*0Sstevel@tonic-gate 			for (i = 0; i < MAXTAPES; i++)
527*0Sstevel@tonic-gate 				if (tapesread[i]) {
528*0Sstevel@tonic-gate 					(void) fprintf(stderr, "%s%ld",
529*0Sstevel@tonic-gate 					    tbf, i+1);
530*0Sstevel@tonic-gate 					(void) strcpy(tbf, ", ");
531*0Sstevel@tonic-gate 				}
532*0Sstevel@tonic-gate 			(void) fprintf(stderr, "\n");
533*0Sstevel@tonic-gate 		}
534*0Sstevel@tonic-gate 		do {
535*0Sstevel@tonic-gate 			(void) fprintf(stderr,
536*0Sstevel@tonic-gate 			    gettext("Specify next volume #: "));
537*0Sstevel@tonic-gate 			(void) fflush(stderr);
538*0Sstevel@tonic-gate 			/* LINTED tbfsize is limited to a few MB */
539*0Sstevel@tonic-gate 			(void) fgets(tbf, (int)tbfsize, terminal);
540*0Sstevel@tonic-gate 		} while (!feof(terminal) && tbf[0] == '\n');
541*0Sstevel@tonic-gate 		if (feof(terminal))
542*0Sstevel@tonic-gate 			done(1);
543*0Sstevel@tonic-gate 		newvol = atoi(tbf);
544*0Sstevel@tonic-gate 		if (newvol <= 0) {
545*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
546*0Sstevel@tonic-gate 			    "Volume numbers are positive numerics\n"));
547*0Sstevel@tonic-gate 		}
548*0Sstevel@tonic-gate 		if (newvol > MAXTAPES) {
549*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
550*0Sstevel@tonic-gate 			    "This program can only deal with %d volumes\n"),
551*0Sstevel@tonic-gate 			    MAXTAPES);
552*0Sstevel@tonic-gate 			newvol = 0;
553*0Sstevel@tonic-gate 		}
554*0Sstevel@tonic-gate 	}
555*0Sstevel@tonic-gate 	if (newvol == volno) {
556*0Sstevel@tonic-gate 		tapesread[volno-1]++;
557*0Sstevel@tonic-gate 		return;
558*0Sstevel@tonic-gate 	}
559*0Sstevel@tonic-gate 	closemt();
560*0Sstevel@tonic-gate 	/*
561*0Sstevel@tonic-gate 	 * XXX: if we are switching devices, we should probably try
562*0Sstevel@tonic-gate 	 * the device once without prompting to enable unattended
563*0Sstevel@tonic-gate 	 * operation.
564*0Sstevel@tonic-gate 	 */
565*0Sstevel@tonic-gate 	if (host)
566*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
567*0Sstevel@tonic-gate "Mount volume %d\nthen enter volume name on host %s (default: %s) "),
568*0Sstevel@tonic-gate 		    newvol, host,  magtape);
569*0Sstevel@tonic-gate 	else
570*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
571*0Sstevel@tonic-gate 		    "Mount volume %d\nthen enter volume name (default: %s) "),
572*0Sstevel@tonic-gate 		    newvol, magtape);
573*0Sstevel@tonic-gate 	(void) fflush(stderr);
574*0Sstevel@tonic-gate 	/* LINTED tbfsize is limited to a few MB */
575*0Sstevel@tonic-gate 	(void) fgets(tbf, (int)tbfsize, terminal);
576*0Sstevel@tonic-gate 	if (feof(terminal))
577*0Sstevel@tonic-gate 		done(1);
578*0Sstevel@tonic-gate 	/*
579*0Sstevel@tonic-gate 	 * XXX We don't allow rotating among tape hosts, just drives.
580*0Sstevel@tonic-gate 	 */
581*0Sstevel@tonic-gate 	if (tbf[0] != '\n') {
582*0Sstevel@tonic-gate 		(void) strncpy(magtape, tbf, sizeof (magtape));
583*0Sstevel@tonic-gate 		magtape[sizeof (magtape) - 1] = '\0';
584*0Sstevel@tonic-gate 		/* LINTED unsigned -> signed conversion ok */
585*0Sstevel@tonic-gate 		i = (int)strlen(magtape);
586*0Sstevel@tonic-gate 		if (magtape[i - 1] == '\n')
587*0Sstevel@tonic-gate 			magtape[i - 1] = '\0';
588*0Sstevel@tonic-gate 	}
589*0Sstevel@tonic-gate 	if ((host != NULL && (mt = rmtopen(magtape, O_RDONLY)) == -1) ||
590*0Sstevel@tonic-gate 	    (host == NULL &&
591*0Sstevel@tonic-gate 		(mt = open(magtape, O_RDONLY|O_LARGEFILE)) == -1)) {
592*0Sstevel@tonic-gate 		int error = errno;
593*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot open %s: %s\n"),
594*0Sstevel@tonic-gate 		    magtape, strerror(error));
595*0Sstevel@tonic-gate 		volno = -1;
596*0Sstevel@tonic-gate 		goto again;
597*0Sstevel@tonic-gate 	}
598*0Sstevel@tonic-gate gethdr:
599*0Sstevel@tonic-gate 	volno = newvol;
600*0Sstevel@tonic-gate 	setdumpnum();
601*0Sstevel@tonic-gate 	flsht();
602*0Sstevel@tonic-gate 	if (!pipein && !bflag && archivefile && (first_time == FT_STATE_1)) {
603*0Sstevel@tonic-gate 		first_time = FT_STATE_2;
604*0Sstevel@tonic-gate 		findtapeblksize(TAPE_FILE);
605*0Sstevel@tonic-gate 	}
606*0Sstevel@tonic-gate 	if (readhdr(&tmpbuf) == FAIL) {
607*0Sstevel@tonic-gate 		(void) fprintf(stderr,
608*0Sstevel@tonic-gate 		    gettext("volume is not in dump format\n"));
609*0Sstevel@tonic-gate 		volno = 0;
610*0Sstevel@tonic-gate 		goto again;
611*0Sstevel@tonic-gate 	}
612*0Sstevel@tonic-gate 	if (checkvol(&tmpbuf, volno) == FAIL) {
613*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Wrong volume (%d)\n"),
614*0Sstevel@tonic-gate 		    tmpbuf.c_volume);
615*0Sstevel@tonic-gate 		volno = 0;
616*0Sstevel@tonic-gate 		goto again;
617*0Sstevel@tonic-gate 	}
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	if (((time_t)(tmpbuf.c_date) != dumpdate) ||
620*0Sstevel@tonic-gate 	    ((time_t)(tmpbuf.c_ddate) != dumptime)) {
621*0Sstevel@tonic-gate 		char *tmp_ct;
622*0Sstevel@tonic-gate 		time_t lc_date = (time_t)tmpbuf.c_date;
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 		/*
625*0Sstevel@tonic-gate 		 * This is used to save the return value from lctime(),
626*0Sstevel@tonic-gate 		 * since that's volatile across lctime() invocations.
627*0Sstevel@tonic-gate 		 */
628*0Sstevel@tonic-gate 		tmp_ct = strdup(lctime(&lc_date));
629*0Sstevel@tonic-gate 		if (tmp_ct == (char *)0) {
630*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
631*0Sstevel@tonic-gate 			    "Cannot allocate space for time string\n"));
632*0Sstevel@tonic-gate 			done(1);
633*0Sstevel@tonic-gate 		}
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 		(void) fprintf(stderr,
636*0Sstevel@tonic-gate 		    gettext("Wrong dump date\n\tgot: %s\twanted: %s"),
637*0Sstevel@tonic-gate 		    tmp_ct,  lctime(&dumpdate));
638*0Sstevel@tonic-gate 		volno = 0;
639*0Sstevel@tonic-gate 		free(tmp_ct);
640*0Sstevel@tonic-gate 		goto again;
641*0Sstevel@tonic-gate 	}
642*0Sstevel@tonic-gate 	tapesread[volno-1]++;
643*0Sstevel@tonic-gate 	blksread = savecnt;
644*0Sstevel@tonic-gate 	tapea = savetapea;
645*0Sstevel@tonic-gate 	/*
646*0Sstevel@tonic-gate 	 * If continuing from the previous volume, skip over any
647*0Sstevel@tonic-gate 	 * blocks read already at the end of the previous volume.
648*0Sstevel@tonic-gate 	 *
649*0Sstevel@tonic-gate 	 * If coming to this volume at random, skip to the beginning
650*0Sstevel@tonic-gate 	 * of the next record.
651*0Sstevel@tonic-gate 	 */
652*0Sstevel@tonic-gate 	if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
653*0Sstevel@tonic-gate 		if (!wantnext) {
654*0Sstevel@tonic-gate 			if (archivefile && first_time == FT_STATE_2) {
655*0Sstevel@tonic-gate 				first_time = FT_STATE_3;
656*0Sstevel@tonic-gate 			}
657*0Sstevel@tonic-gate 			recsread = tmpbuf.c_firstrec;
658*0Sstevel@tonic-gate 			tapea = tmpbuf.c_tapea;
659*0Sstevel@tonic-gate 			dprintf(stdout,
660*0Sstevel@tonic-gate 			    "restore skipping %d records\n",
661*0Sstevel@tonic-gate 			    tmpbuf.c_count);
662*0Sstevel@tonic-gate 			for (i = tmpbuf.c_count; i > 0; i--)
663*0Sstevel@tonic-gate 				readtape(buf);
664*0Sstevel@tonic-gate 		} else if (tmpbuf.c_firstrec != 0) {
665*0Sstevel@tonic-gate 			savecnt = blksread;
666*0Sstevel@tonic-gate 			savetapea = tapea;
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate 			if (archivefile && first_time == FT_STATE_2) {
669*0Sstevel@tonic-gate 				/*
670*0Sstevel@tonic-gate 				 * subtract 2, 1 for archive file's TS_END
671*0Sstevel@tonic-gate 				 * and 1 for tape's TS_TAPE
672*0Sstevel@tonic-gate 				 */
673*0Sstevel@tonic-gate 				first_time = FT_STATE_3;
674*0Sstevel@tonic-gate 				i = tapea - tmpbuf.c_tapea - 2;
675*0Sstevel@tonic-gate 			} else {
676*0Sstevel@tonic-gate 				i = tapea - tmpbuf.c_tapea;
677*0Sstevel@tonic-gate 			}
678*0Sstevel@tonic-gate 			if (i > 0)
679*0Sstevel@tonic-gate 				dprintf(stdout, gettext(
680*0Sstevel@tonic-gate 				    "restore skipping %d duplicate records\n"),
681*0Sstevel@tonic-gate 					i);
682*0Sstevel@tonic-gate 			else if (i < 0)
683*0Sstevel@tonic-gate 				dprintf(stdout, gettext(
684*0Sstevel@tonic-gate 				    "restore duplicate record botch (%d)\n"),
685*0Sstevel@tonic-gate 					i);
686*0Sstevel@tonic-gate 			while (--i >= 0)
687*0Sstevel@tonic-gate 				readtape(buf);
688*0Sstevel@tonic-gate 			blksread = savecnt;
689*0Sstevel@tonic-gate 			tapea = savetapea + 1; /* <= (void) gethead() below */
690*0Sstevel@tonic-gate 		}
691*0Sstevel@tonic-gate 	}
692*0Sstevel@tonic-gate 	if (curfile.action == USING) {
693*0Sstevel@tonic-gate 		if (volno == 1)
694*0Sstevel@tonic-gate 			panic(gettext("active file into volume 1\n"));
695*0Sstevel@tonic-gate 		return;
696*0Sstevel@tonic-gate 	}
697*0Sstevel@tonic-gate 	(void) gethead(&spcl);
698*0Sstevel@tonic-gate 	findinode(&spcl); /* do we always restart files in full? */
699*0Sstevel@tonic-gate 	if (gettingfile) { /* i.e. will we lose metadata? */
700*0Sstevel@tonic-gate 		gettingfile = 0;
701*0Sstevel@tonic-gate 		longjmp(restart, 1); /* will this set f1 & f2? */
702*0Sstevel@tonic-gate 	}
703*0Sstevel@tonic-gate }
704*0Sstevel@tonic-gate 
705*0Sstevel@tonic-gate /*
706*0Sstevel@tonic-gate  * handle multiple dumps per tape by skipping forward to the
707*0Sstevel@tonic-gate  * appropriate one.  Note we don't use absolute positioning,
708*0Sstevel@tonic-gate  * as that may take a very long time.
709*0Sstevel@tonic-gate  */
710*0Sstevel@tonic-gate static void
711*0Sstevel@tonic-gate #ifdef __STDC__
712*0Sstevel@tonic-gate setdumpnum(void)
713*0Sstevel@tonic-gate #else
714*0Sstevel@tonic-gate setdumpnum()
715*0Sstevel@tonic-gate #endif
716*0Sstevel@tonic-gate {
717*0Sstevel@tonic-gate 	struct mtop tcom;
718*0Sstevel@tonic-gate 	int retval;
719*0Sstevel@tonic-gate 
720*0Sstevel@tonic-gate 	if (dumpnum == 1 || volno != 1)
721*0Sstevel@tonic-gate 		return;
722*0Sstevel@tonic-gate 	if (pipein) {
723*0Sstevel@tonic-gate 		(void) fprintf(stderr,
724*0Sstevel@tonic-gate 		    gettext("Cannot have multiple dumps on pipe input\n"));
725*0Sstevel@tonic-gate 		done(1);
726*0Sstevel@tonic-gate 	}
727*0Sstevel@tonic-gate 	tcom.mt_op = MTFSF;
728*0Sstevel@tonic-gate 	tcom.mt_count = dumpnum - 1;
729*0Sstevel@tonic-gate 	if (host)
730*0Sstevel@tonic-gate 		retval = rmtioctl(MTFSF, dumpnum - 1);
731*0Sstevel@tonic-gate 	else
732*0Sstevel@tonic-gate 		retval = ioctl(mt, (int)MTIOCTOP, (char *)&tcom);
733*0Sstevel@tonic-gate 	if (retval < 0)
734*0Sstevel@tonic-gate 		perror("ioctl MTFSF");
735*0Sstevel@tonic-gate }
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate void
738*0Sstevel@tonic-gate #ifdef __STDC__
739*0Sstevel@tonic-gate printdumpinfo(void)
740*0Sstevel@tonic-gate #else
741*0Sstevel@tonic-gate printdumpinfo()
742*0Sstevel@tonic-gate #endif
743*0Sstevel@tonic-gate {
744*0Sstevel@tonic-gate 	int i;
745*0Sstevel@tonic-gate 	time_t date;
746*0Sstevel@tonic-gate 	static char *epoch = NULL;
747*0Sstevel@tonic-gate 
748*0Sstevel@tonic-gate 	if (epoch == NULL) {
749*0Sstevel@tonic-gate 		epoch = strdup(gettext("the epoch\n"));
750*0Sstevel@tonic-gate 		if (epoch == NULL) {
751*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Out of memory\n"));
752*0Sstevel@tonic-gate 			return;
753*0Sstevel@tonic-gate 		}
754*0Sstevel@tonic-gate 	}
755*0Sstevel@tonic-gate 
756*0Sstevel@tonic-gate 	date = (time_t)dumpinfo.c_date;
757*0Sstevel@tonic-gate 	(void) fprintf(stdout,
758*0Sstevel@tonic-gate 	    gettext("Dump   date: %s"), lctime(&date));
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 	date = (time_t)dumpinfo.c_ddate;
761*0Sstevel@tonic-gate 	(void) fprintf(stdout, gettext("Dumped from: %s"),
762*0Sstevel@tonic-gate 	    (dumpinfo.c_ddate == 0) ? epoch : lctime(&date));
763*0Sstevel@tonic-gate 	if (hostinfo) {
764*0Sstevel@tonic-gate 		(void) fprintf(stdout,
765*0Sstevel@tonic-gate 		    gettext("Level %d dump of %s on %.*s:%s\n"),
766*0Sstevel@tonic-gate 		    dumpinfo.c_level, dumpinfo.c_filesys,
767*0Sstevel@tonic-gate 		    sizeof (dumpinfo.c_host), dumpinfo.c_host, dumpinfo.c_dev);
768*0Sstevel@tonic-gate 		(void) fprintf(stdout,
769*0Sstevel@tonic-gate 		    gettext("Label: %.*s\n"),
770*0Sstevel@tonic-gate 		    sizeof (dumpinfo.c_label), dumpinfo.c_label);
771*0Sstevel@tonic-gate 	}
772*0Sstevel@tonic-gate 	if (inodeinfo) {
773*0Sstevel@tonic-gate 		(void) fprintf(stdout,
774*0Sstevel@tonic-gate 		    gettext("Starting inode numbers by volume:\n"));
775*0Sstevel@tonic-gate 		for (i = 1; i <= dumpinfo.c_volume; i++)
776*0Sstevel@tonic-gate 			(void) fprintf(stdout, gettext("\tVolume %d: %6d\n"),
777*0Sstevel@tonic-gate 			    i, dumpinfo.c_inos[i]);
778*0Sstevel@tonic-gate 	}
779*0Sstevel@tonic-gate }
780*0Sstevel@tonic-gate 
781*0Sstevel@tonic-gate extractfile(name)
782*0Sstevel@tonic-gate 	char *name;
783*0Sstevel@tonic-gate {
784*0Sstevel@tonic-gate 	static int complained_chown = 0;
785*0Sstevel@tonic-gate 	static int complained_lchown = 0;
786*0Sstevel@tonic-gate 	static int complained_chmod = 0;
787*0Sstevel@tonic-gate 	static int complained_utime = 0;
788*0Sstevel@tonic-gate 	static int complained_mknod = 0;
789*0Sstevel@tonic-gate 	mode_t mode;
790*0Sstevel@tonic-gate 	time_t timep[2];
791*0Sstevel@tonic-gate 	struct entry *ep;
792*0Sstevel@tonic-gate 	uid_t uid;
793*0Sstevel@tonic-gate 	gid_t gid;
794*0Sstevel@tonic-gate 	char *errmsg;
795*0Sstevel@tonic-gate 	int result, saverr;
796*0Sstevel@tonic-gate 	dev_t full_dev;
797*0Sstevel@tonic-gate 	int dfd;
798*0Sstevel@tonic-gate 	char *rname;
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate 	curfile.name = name;
801*0Sstevel@tonic-gate 	curfile.action = USING;
802*0Sstevel@tonic-gate 	timep[0] = (time_t)curfile.dip->di_atime;
803*0Sstevel@tonic-gate 	timep[1] = (time_t)curfile.dip->di_mtime;
804*0Sstevel@tonic-gate 	mode = curfile.dip->di_mode;
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate 	uid = curfile.dip->di_suid == UID_LONG ?
807*0Sstevel@tonic-gate 		    curfile.dip->di_uid : (uid_t)curfile.dip->di_suid;
808*0Sstevel@tonic-gate 	gid = curfile.dip->di_sgid == GID_LONG ?
809*0Sstevel@tonic-gate 		    curfile.dip->di_gid : (gid_t)curfile.dip->di_sgid;
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate 	resolve(name, &dfd, &rname);
812*0Sstevel@tonic-gate 	if (dfd != AT_FDCWD) {
813*0Sstevel@tonic-gate 		if (fchdir(dfd) < 0) {
814*0Sstevel@tonic-gate 			saverr = errno;
815*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
816*0Sstevel@tonic-gate 				"%s: unable to set attribute context: %s\n"),
817*0Sstevel@tonic-gate 				rname, strerror(saverr));
818*0Sstevel@tonic-gate 			skipfile();
819*0Sstevel@tonic-gate 			(void) close(dfd);
820*0Sstevel@tonic-gate 			return (FAIL);
821*0Sstevel@tonic-gate 		}
822*0Sstevel@tonic-gate 	}
823*0Sstevel@tonic-gate 
824*0Sstevel@tonic-gate 	switch (mode & IFMT) {
825*0Sstevel@tonic-gate 
826*0Sstevel@tonic-gate 	default:
827*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: unknown file mode 0%lo\n"),
828*0Sstevel@tonic-gate 		    rname, (ulong_t)(mode&IFMT));
829*0Sstevel@tonic-gate 		skipfile();
830*0Sstevel@tonic-gate 		result = FAIL;
831*0Sstevel@tonic-gate 		break;
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate 	case IFSOCK:
834*0Sstevel@tonic-gate 		vprintf(stdout, gettext("skipped socket %s\n"), rname);
835*0Sstevel@tonic-gate 		skipfile();
836*0Sstevel@tonic-gate 		result = GOOD;
837*0Sstevel@tonic-gate 		break;
838*0Sstevel@tonic-gate 
839*0Sstevel@tonic-gate 	case IFDIR:
840*0Sstevel@tonic-gate 		if (mflag) {
841*0Sstevel@tonic-gate 			ep = lookupname(name);
842*0Sstevel@tonic-gate 			if (ep == NIL || ep->e_flags & EXTRACT) {
843*0Sstevel@tonic-gate 				panic(gettext(
844*0Sstevel@tonic-gate 				    "directory %s was not restored\n"),
845*0Sstevel@tonic-gate 				    rname);
846*0Sstevel@tonic-gate 				skipfile();
847*0Sstevel@tonic-gate 				result = FAIL;
848*0Sstevel@tonic-gate 				break;
849*0Sstevel@tonic-gate 			}
850*0Sstevel@tonic-gate 			skipfile();
851*0Sstevel@tonic-gate 			result = GOOD;
852*0Sstevel@tonic-gate 			break;
853*0Sstevel@tonic-gate 		}
854*0Sstevel@tonic-gate 		vprintf(stdout, gettext("extract file %s\n"), rname);
855*0Sstevel@tonic-gate 		result = genliteraldir(rname, curfile.ino);
856*0Sstevel@tonic-gate 		break;
857*0Sstevel@tonic-gate 
858*0Sstevel@tonic-gate 	case IFLNK:
859*0Sstevel@tonic-gate 		lnkbuf[0] = '\0';
860*0Sstevel@tonic-gate 		pathlen = 0;
861*0Sstevel@tonic-gate 		getfile(xtrlnkfile, xtrlnkskip);
862*0Sstevel@tonic-gate 		if (pathlen == 0) {
863*0Sstevel@tonic-gate 			vprintf(stdout, gettext(
864*0Sstevel@tonic-gate 				"%s: zero length symbolic link (ignored)\n"),
865*0Sstevel@tonic-gate 				rname);
866*0Sstevel@tonic-gate 			result = GOOD;
867*0Sstevel@tonic-gate 			break;
868*0Sstevel@tonic-gate 		}
869*0Sstevel@tonic-gate 		if ((result = lf_linkit(lnkbuf, rname, SYMLINK)) != GOOD)
870*0Sstevel@tonic-gate 			break;
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate 		/* 1254700: set uid/gid (previously missing)  */
873*0Sstevel@tonic-gate 		if (lchown(rname, uid, gid) < 0 && !complained_lchown) {
874*0Sstevel@tonic-gate 			/* Just a warning */
875*0Sstevel@tonic-gate 			saverr = errno;
876*0Sstevel@tonic-gate 			errmsg = gettext(
877*0Sstevel@tonic-gate 			    "Unable to restore ownership of symlink %s: %s\n");
878*0Sstevel@tonic-gate 			(void) fprintf(stderr, errmsg,
879*0Sstevel@tonic-gate 			    rname, strerror(saverr));
880*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
881*0Sstevel@tonic-gate 			    "Additional such failures will be ignored.\n"));
882*0Sstevel@tonic-gate 			complained_lchown = 1;
883*0Sstevel@tonic-gate 		}
884*0Sstevel@tonic-gate 		metaset(rname);
885*0Sstevel@tonic-gate 		result = GOOD;
886*0Sstevel@tonic-gate 		break;
887*0Sstevel@tonic-gate 
888*0Sstevel@tonic-gate 	case IFCHR:
889*0Sstevel@tonic-gate 	case IFBLK:
890*0Sstevel@tonic-gate 	case IFIFO:
891*0Sstevel@tonic-gate 		vprintf(stdout, gettext("extract special file %s\n"), rname);
892*0Sstevel@tonic-gate 		/* put device rdev into dev_t expanded format */
893*0Sstevel@tonic-gate 		/* XXX does this always do the right thing? */
894*0Sstevel@tonic-gate 		/* XXX does dump do the right thing? */
895*0Sstevel@tonic-gate 		if (((curfile.dip->di_ordev & 0xFFFF0000) == 0) ||
896*0Sstevel@tonic-gate 		    ((curfile.dip->di_ordev & 0xFFFF0000) == 0xFFFF0000)) {
897*0Sstevel@tonic-gate 			full_dev = expdev((unsigned)(curfile.dip->di_ordev));
898*0Sstevel@tonic-gate 		} else {
899*0Sstevel@tonic-gate 			/* LINTED sign extension ok */
900*0Sstevel@tonic-gate 			full_dev = (unsigned)(curfile.dip->di_ordev);
901*0Sstevel@tonic-gate 		}
902*0Sstevel@tonic-gate 
903*0Sstevel@tonic-gate 		if (mknod(rname, mode, full_dev) < 0)
904*0Sstevel@tonic-gate 		{
905*0Sstevel@tonic-gate 			struct stat64 s[1];
906*0Sstevel@tonic-gate 
907*0Sstevel@tonic-gate 			saverr = errno;
908*0Sstevel@tonic-gate 			if ((stat64(rname, s)) ||
909*0Sstevel@tonic-gate 			    ((s->st_mode & S_IFMT) != (mode & S_IFMT)) ||
910*0Sstevel@tonic-gate 			    (s->st_rdev != full_dev)) {
911*0Sstevel@tonic-gate 				if (saverr != EPERM || !complained_mknod) {
912*0Sstevel@tonic-gate 					(void) fprintf(stderr, "%s: ", rname);
913*0Sstevel@tonic-gate 					(void) fflush(stderr);
914*0Sstevel@tonic-gate 					errno = saverr;
915*0Sstevel@tonic-gate 					perror(gettext(
916*0Sstevel@tonic-gate 					    "cannot create special file"));
917*0Sstevel@tonic-gate 					if (saverr == EPERM) {
918*0Sstevel@tonic-gate 						(void) fprintf(stderr, gettext(
919*0Sstevel@tonic-gate 			    "Additional such failures will be ignored.\n"));
920*0Sstevel@tonic-gate 						complained_mknod = 1;
921*0Sstevel@tonic-gate 					}
922*0Sstevel@tonic-gate 				}
923*0Sstevel@tonic-gate 				skipfile();
924*0Sstevel@tonic-gate 				result = FAIL;
925*0Sstevel@tonic-gate 				break;
926*0Sstevel@tonic-gate 			}
927*0Sstevel@tonic-gate 		}
928*0Sstevel@tonic-gate 		if (chown(rname, uid, gid) < 0 && !complained_chown) {
929*0Sstevel@tonic-gate 			/* Just a warning */
930*0Sstevel@tonic-gate 			saverr = errno;
931*0Sstevel@tonic-gate 			errmsg = gettext(
932*0Sstevel@tonic-gate 			    "Unable to restore ownership of %s: %s\n");
933*0Sstevel@tonic-gate 			(void) fprintf(stderr, errmsg,
934*0Sstevel@tonic-gate 			    rname, strerror(saverr));
935*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
936*0Sstevel@tonic-gate 			    "Additional such failures will be ignored.\n"));
937*0Sstevel@tonic-gate 			complained_chown = 1;
938*0Sstevel@tonic-gate 		}
939*0Sstevel@tonic-gate 		if (chmod(rname, mode) < 0 && !complained_chmod) {
940*0Sstevel@tonic-gate 			saverr = errno;
941*0Sstevel@tonic-gate 			errmsg = gettext(
942*0Sstevel@tonic-gate 			    "Unable to restore permissions on %s: %s\n");
943*0Sstevel@tonic-gate 			(void) fprintf(stderr, errmsg,
944*0Sstevel@tonic-gate 			    rname, strerror(saverr));
945*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
946*0Sstevel@tonic-gate 			    "Additional such failures will be ignored.\n"));
947*0Sstevel@tonic-gate 			complained_chmod = 1;
948*0Sstevel@tonic-gate 		}
949*0Sstevel@tonic-gate 		skipfile();
950*0Sstevel@tonic-gate 		metaset(rname); /* skipfile() got the metadata, if any */
951*0Sstevel@tonic-gate 		if (utime(rname, (struct utimbuf *)timep) < 0 &&
952*0Sstevel@tonic-gate 		    !complained_utime) {
953*0Sstevel@tonic-gate 			saverr = errno;
954*0Sstevel@tonic-gate 			errmsg = gettext(
955*0Sstevel@tonic-gate 			    "Unable to restore times on %s: %s\n");
956*0Sstevel@tonic-gate 			(void) fprintf(stderr, errmsg,
957*0Sstevel@tonic-gate 			    rname, strerror(saverr));
958*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
959*0Sstevel@tonic-gate 			    "Additional such failures will be ignored.\n"));
960*0Sstevel@tonic-gate 			complained_utime = 1;
961*0Sstevel@tonic-gate 		}
962*0Sstevel@tonic-gate 		result = GOOD;
963*0Sstevel@tonic-gate 		break;
964*0Sstevel@tonic-gate 
965*0Sstevel@tonic-gate 	case IFREG:
966*0Sstevel@tonic-gate 		vprintf(stdout, gettext("extract file %s\n"), rname);
967*0Sstevel@tonic-gate 		ofile = creat64(rname, 0666);
968*0Sstevel@tonic-gate 
969*0Sstevel@tonic-gate 		if (ofile < 0) {
970*0Sstevel@tonic-gate 			saverr = errno;
971*0Sstevel@tonic-gate 			errmsg = gettext("cannot create file");
972*0Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: ", rname);
973*0Sstevel@tonic-gate 			(void) fflush(stderr);
974*0Sstevel@tonic-gate 			errno = saverr;
975*0Sstevel@tonic-gate 			perror(errmsg);
976*0Sstevel@tonic-gate 			skipfile();
977*0Sstevel@tonic-gate 			result = FAIL;
978*0Sstevel@tonic-gate 			break;
979*0Sstevel@tonic-gate 		}
980*0Sstevel@tonic-gate 		if (fchown(ofile, uid, gid) < 0 && !complained_chown) {
981*0Sstevel@tonic-gate 			/* Just a warning */
982*0Sstevel@tonic-gate 			saverr = errno;
983*0Sstevel@tonic-gate 			errmsg = gettext(
984*0Sstevel@tonic-gate 			    "Unable to restore ownership of %s: %s\n");
985*0Sstevel@tonic-gate 			(void) fprintf(stderr, errmsg,
986*0Sstevel@tonic-gate 			    rname, strerror(saverr));
987*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
988*0Sstevel@tonic-gate 			    "Additional such failures will be ignored.\n"));
989*0Sstevel@tonic-gate 			complained_chown = 1;
990*0Sstevel@tonic-gate 		}
991*0Sstevel@tonic-gate 		if (fchmod(ofile, mode) < 0 && !complained_chmod) {
992*0Sstevel@tonic-gate 			saverr = errno;
993*0Sstevel@tonic-gate 			errmsg = gettext(
994*0Sstevel@tonic-gate 			    "Unable to restore permissions on %s: %s\n");
995*0Sstevel@tonic-gate 			(void) fprintf(stderr, errmsg,
996*0Sstevel@tonic-gate 			    rname, strerror(saverr));
997*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
998*0Sstevel@tonic-gate 			    "Additional such failures will be ignored.\n"));
999*0Sstevel@tonic-gate 			complained_chmod = 1;
1000*0Sstevel@tonic-gate 		}
1001*0Sstevel@tonic-gate 		getfile(xtrfile, xtrskip);
1002*0Sstevel@tonic-gate 		metaset(rname);	/* we don't have metadata until after */
1003*0Sstevel@tonic-gate 				/* getfile() - maybe fchmod(0) then */
1004*0Sstevel@tonic-gate 				/* fchmod(real) after this? */
1005*0Sstevel@tonic-gate 
1006*0Sstevel@tonic-gate 		/*
1007*0Sstevel@tonic-gate 		 * Some errors don't get reported until we close(2), so
1008*0Sstevel@tonic-gate 		 * check for them.
1009*0Sstevel@tonic-gate 		 * XXX unlink the file if an error is reported?
1010*0Sstevel@tonic-gate 		 */
1011*0Sstevel@tonic-gate 		if (close(ofile) < 0) {
1012*0Sstevel@tonic-gate 			saverr = errno;
1013*0Sstevel@tonic-gate 			errmsg = gettext("error closing file");
1014*0Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: ", rname);
1015*0Sstevel@tonic-gate 			(void) fflush(stderr);
1016*0Sstevel@tonic-gate 			errno = saverr;
1017*0Sstevel@tonic-gate 			perror(errmsg);
1018*0Sstevel@tonic-gate 			result = FAIL;
1019*0Sstevel@tonic-gate 			break;
1020*0Sstevel@tonic-gate 		}
1021*0Sstevel@tonic-gate 		if (utime(rname, (struct utimbuf *)timep) < 0 &&
1022*0Sstevel@tonic-gate 		    !complained_utime) {
1023*0Sstevel@tonic-gate 			saverr = errno;
1024*0Sstevel@tonic-gate 			errmsg = gettext(
1025*0Sstevel@tonic-gate 			    "Unable to restore times on %s: %s\n");
1026*0Sstevel@tonic-gate 			(void) fprintf(stderr, errmsg,
1027*0Sstevel@tonic-gate 			    rname, strerror(saverr));
1028*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
1029*0Sstevel@tonic-gate 			    "Additional such failures will be ignored.\n"));
1030*0Sstevel@tonic-gate 			complained_utime = 1;
1031*0Sstevel@tonic-gate 		}
1032*0Sstevel@tonic-gate 
1033*0Sstevel@tonic-gate 		result = GOOD;
1034*0Sstevel@tonic-gate 		break;
1035*0Sstevel@tonic-gate 	}
1036*0Sstevel@tonic-gate 	if (dfd != AT_FDCWD) {
1037*0Sstevel@tonic-gate 		fchdir(savepwd);
1038*0Sstevel@tonic-gate 		(void) close(dfd);
1039*0Sstevel@tonic-gate 	}
1040*0Sstevel@tonic-gate 	return (result);
1041*0Sstevel@tonic-gate }
1042*0Sstevel@tonic-gate 
1043*0Sstevel@tonic-gate /*
1044*0Sstevel@tonic-gate  * skip over bit maps on the tape
1045*0Sstevel@tonic-gate  */
1046*0Sstevel@tonic-gate void
1047*0Sstevel@tonic-gate #ifdef __STDC__
1048*0Sstevel@tonic-gate skipmaps(void)
1049*0Sstevel@tonic-gate #else
1050*0Sstevel@tonic-gate skipmaps()
1051*0Sstevel@tonic-gate #endif
1052*0Sstevel@tonic-gate {
1053*0Sstevel@tonic-gate 	continuemap = 1;
1054*0Sstevel@tonic-gate 	while (checktype(&spcl, TS_CLRI) == GOOD ||
1055*0Sstevel@tonic-gate 	    checktype(&spcl, TS_BITS) == GOOD)
1056*0Sstevel@tonic-gate 		skipfile();
1057*0Sstevel@tonic-gate 	continuemap = 0;
1058*0Sstevel@tonic-gate }
1059*0Sstevel@tonic-gate 
1060*0Sstevel@tonic-gate /*
1061*0Sstevel@tonic-gate  * skip over a file on the tape
1062*0Sstevel@tonic-gate  */
1063*0Sstevel@tonic-gate void
1064*0Sstevel@tonic-gate #ifdef __STDC__
1065*0Sstevel@tonic-gate skipfile(void)
1066*0Sstevel@tonic-gate #else
1067*0Sstevel@tonic-gate skipfile()
1068*0Sstevel@tonic-gate #endif
1069*0Sstevel@tonic-gate {
1070*0Sstevel@tonic-gate 	curfile.action = SKIP;
1071*0Sstevel@tonic-gate 	getfile(null, null);
1072*0Sstevel@tonic-gate }
1073*0Sstevel@tonic-gate /*
1074*0Sstevel@tonic-gate  * Do the file extraction, calling the supplied functions
1075*0Sstevel@tonic-gate  * with the blocks
1076*0Sstevel@tonic-gate  */
1077*0Sstevel@tonic-gate void
1078*0Sstevel@tonic-gate getfile(f1, f2)
1079*0Sstevel@tonic-gate 	void	(*f2)(), (*f1)();
1080*0Sstevel@tonic-gate {
1081*0Sstevel@tonic-gate 	int i;
1082*0Sstevel@tonic-gate 	size_t curblk = 0;
1083*0Sstevel@tonic-gate 	offset_t size = (offset_t)spcl.c_dinode.di_size;
1084*0Sstevel@tonic-gate 	static char clearedbuf[MAXBSIZE];
1085*0Sstevel@tonic-gate 	char buf[TP_BSIZE_MAX];
1086*0Sstevel@tonic-gate 	char *bufptr;
1087*0Sstevel@tonic-gate 	char junk[TP_BSIZE_MAX];
1088*0Sstevel@tonic-gate 
1089*0Sstevel@tonic-gate 	assert(MAXBSIZE >= tp_bsize);
1090*0Sstevel@tonic-gate 
1091*0Sstevel@tonic-gate 	metaset(NULL);	/* flush old metadata */
1092*0Sstevel@tonic-gate 	if (checktype(&spcl, TS_END) == GOOD) {
1093*0Sstevel@tonic-gate 		panic(gettext("ran off end of volume\n"));
1094*0Sstevel@tonic-gate 		return;
1095*0Sstevel@tonic-gate 	}
1096*0Sstevel@tonic-gate 	if (ishead(&spcl) == FAIL) {
1097*0Sstevel@tonic-gate 		panic(gettext("not at beginning of a file\n"));
1098*0Sstevel@tonic-gate 		return;
1099*0Sstevel@tonic-gate 	}
1100*0Sstevel@tonic-gate 	metacheck(&spcl); /* check for metadata in header */
1101*0Sstevel@tonic-gate 	if (!gettingfile && setjmp(restart) != 0) {
1102*0Sstevel@tonic-gate 		gettingfile = 0;	/* paranoia; longjmp'er should do */
1103*0Sstevel@tonic-gate 		return;
1104*0Sstevel@tonic-gate 	}
1105*0Sstevel@tonic-gate 	gettingfile++;
1106*0Sstevel@tonic-gate loop:
1107*0Sstevel@tonic-gate 	if ((spcl.c_dinode.di_mode & IFMT) == IFSHAD) {
1108*0Sstevel@tonic-gate 		f1 = xtrmeta;
1109*0Sstevel@tonic-gate 		f2 = metaskip;
1110*0Sstevel@tonic-gate 	}
1111*0Sstevel@tonic-gate 	for (i = 0, bufptr = buf; i < spcl.c_count; i++) {
1112*0Sstevel@tonic-gate 		if ((i >= TP_NINDIR) || (spcl.c_addr[i])) {
1113*0Sstevel@tonic-gate 			readtape(bufptr);
1114*0Sstevel@tonic-gate 			bufptr += tp_bsize;
1115*0Sstevel@tonic-gate 			curblk++;
1116*0Sstevel@tonic-gate 			if (curblk == (fssize / tp_bsize)) {
1117*0Sstevel@tonic-gate 				(*f1)(buf, size > tp_bsize ?
1118*0Sstevel@tonic-gate 				    (size_t)(fssize) :
1119*0Sstevel@tonic-gate 					/* LINTED size <= tp_bsize */
1120*0Sstevel@tonic-gate 				    (curblk - 1) * tp_bsize + (size_t)size);
1121*0Sstevel@tonic-gate 				curblk = 0;
1122*0Sstevel@tonic-gate 				bufptr = buf;
1123*0Sstevel@tonic-gate 			}
1124*0Sstevel@tonic-gate 		} else {
1125*0Sstevel@tonic-gate 			if (curblk > 0) {
1126*0Sstevel@tonic-gate 				(*f1)(buf, size > tp_bsize ?
1127*0Sstevel@tonic-gate 				    (size_t)(curblk * tp_bsize) :
1128*0Sstevel@tonic-gate 					/* LINTED size <= tp_bsize */
1129*0Sstevel@tonic-gate 				    (curblk - 1) * tp_bsize + (size_t)size);
1130*0Sstevel@tonic-gate 				curblk = 0;
1131*0Sstevel@tonic-gate 				bufptr = buf;
1132*0Sstevel@tonic-gate 			}
1133*0Sstevel@tonic-gate 			(*f2)(clearedbuf, size > tp_bsize ?
1134*0Sstevel@tonic-gate 					/* LINTED size <= tp_bsize */
1135*0Sstevel@tonic-gate 				(long)tp_bsize : (size_t)size);
1136*0Sstevel@tonic-gate 		}
1137*0Sstevel@tonic-gate 		if ((size -= tp_bsize) <= 0) {
1138*0Sstevel@tonic-gate 			for (i++; i < spcl.c_count; i++)
1139*0Sstevel@tonic-gate 				if ((i >= TP_NINDIR) || (spcl.c_addr[i]))
1140*0Sstevel@tonic-gate 					readtape(junk);
1141*0Sstevel@tonic-gate 			break;
1142*0Sstevel@tonic-gate 		}
1143*0Sstevel@tonic-gate 	}
1144*0Sstevel@tonic-gate 	if (curblk > 0) {
1145*0Sstevel@tonic-gate 		/*
1146*0Sstevel@tonic-gate 		 * Ok to cast size to size_t here. The above for loop reads
1147*0Sstevel@tonic-gate 		 * data into the buffer then writes it to the output file. The
1148*0Sstevel@tonic-gate 		 * call to f1 here is to write out the data that's in the
1149*0Sstevel@tonic-gate 		 * buffer that has not yet been written to the file.
1150*0Sstevel@tonic-gate 		 * This will be less than N-KB of data, since the
1151*0Sstevel@tonic-gate 		 * above loop writes to the file in filesystem-
1152*0Sstevel@tonic-gate 		 * blocksize chunks.
1153*0Sstevel@tonic-gate 		 */
1154*0Sstevel@tonic-gate 		/* LINTED: size fits into a size_t at this point */
1155*0Sstevel@tonic-gate 		(*f1)(buf, (curblk * tp_bsize) + (size_t)size);
1156*0Sstevel@tonic-gate 
1157*0Sstevel@tonic-gate 		curblk = 0;
1158*0Sstevel@tonic-gate 		bufptr = buf;
1159*0Sstevel@tonic-gate 	}
1160*0Sstevel@tonic-gate 	if ((readhdr(&spcl) == GOOD) && (checktype(&spcl, TS_ADDR) == GOOD)) {
1161*0Sstevel@tonic-gate 		if (continuemap)
1162*0Sstevel@tonic-gate 			size = (offset_t)spcl.c_count * tp_bsize;
1163*0Sstevel@tonic-gate 							/* big bitmap */
1164*0Sstevel@tonic-gate 		else if ((size <= 0) &&
1165*0Sstevel@tonic-gate 		    ((spcl.c_dinode.di_mode & IFMT) == IFSHAD)) {
1166*0Sstevel@tonic-gate 			/* LINTED unsigned to signed conversion ok */
1167*0Sstevel@tonic-gate 			size = spcl.c_dinode.di_size;
1168*0Sstevel@tonic-gate 		}
1169*0Sstevel@tonic-gate 		if (size > 0)
1170*0Sstevel@tonic-gate 			goto loop;
1171*0Sstevel@tonic-gate 	}
1172*0Sstevel@tonic-gate 	if (size > 0)
1173*0Sstevel@tonic-gate 		dprintf(stdout,
1174*0Sstevel@tonic-gate 		    gettext("Missing address (header) block for %s\n"),
1175*0Sstevel@tonic-gate 		    curfile.name);
1176*0Sstevel@tonic-gate 	findinode(&spcl);
1177*0Sstevel@tonic-gate 	gettingfile = 0;
1178*0Sstevel@tonic-gate }
1179*0Sstevel@tonic-gate 
1180*0Sstevel@tonic-gate /*
1181*0Sstevel@tonic-gate  * The next routines are called during file extraction to
1182*0Sstevel@tonic-gate  * put the data into the right form and place.
1183*0Sstevel@tonic-gate  */
1184*0Sstevel@tonic-gate static void
1185*0Sstevel@tonic-gate xtrfile(buf, size)
1186*0Sstevel@tonic-gate 	char	*buf;
1187*0Sstevel@tonic-gate 	size_t	size;
1188*0Sstevel@tonic-gate {
1189*0Sstevel@tonic-gate 	if (write(ofile, buf, (size_t)size) == -1) {
1190*0Sstevel@tonic-gate 		int saverr = errno;
1191*0Sstevel@tonic-gate 		(void) fprintf(stderr,
1192*0Sstevel@tonic-gate 		    gettext("write error extracting inode %d, name %s\n"),
1193*0Sstevel@tonic-gate 		    curfile.ino, curfile.name);
1194*0Sstevel@tonic-gate 		errno = saverr;
1195*0Sstevel@tonic-gate 		perror("write");
1196*0Sstevel@tonic-gate 		done(1);
1197*0Sstevel@tonic-gate 	}
1198*0Sstevel@tonic-gate }
1199*0Sstevel@tonic-gate 
1200*0Sstevel@tonic-gate /*
1201*0Sstevel@tonic-gate  * Even though size is a size_t, it's seeking to a relative
1202*0Sstevel@tonic-gate  * offset.  Thus, the seek could go beyond 2 GB, so lseek64 is needed.
1203*0Sstevel@tonic-gate  */
1204*0Sstevel@tonic-gate 
1205*0Sstevel@tonic-gate /*ARGSUSED*/
1206*0Sstevel@tonic-gate static void
1207*0Sstevel@tonic-gate xtrskip(buf, size)
1208*0Sstevel@tonic-gate 	char *buf;
1209*0Sstevel@tonic-gate 	size_t size;
1210*0Sstevel@tonic-gate {
1211*0Sstevel@tonic-gate 	if (lseek64(ofile, (offset_t)size, 1) == -1) {
1212*0Sstevel@tonic-gate 		int saverr = errno;
1213*0Sstevel@tonic-gate 		(void) fprintf(stderr,
1214*0Sstevel@tonic-gate 		    gettext("seek error extracting inode %d, name %s\n"),
1215*0Sstevel@tonic-gate 		    curfile.ino, curfile.name);
1216*0Sstevel@tonic-gate 		errno = saverr;
1217*0Sstevel@tonic-gate 		perror("lseek64");
1218*0Sstevel@tonic-gate 		done(1);
1219*0Sstevel@tonic-gate 	}
1220*0Sstevel@tonic-gate }
1221*0Sstevel@tonic-gate 
1222*0Sstevel@tonic-gate /* these are local to the next five functions */
1223*0Sstevel@tonic-gate static char *metadata = NULL;
1224*0Sstevel@tonic-gate static size_t metasize = 0;
1225*0Sstevel@tonic-gate 
1226*0Sstevel@tonic-gate static void
1227*0Sstevel@tonic-gate metacheck(head)
1228*0Sstevel@tonic-gate 	struct s_spcl *head;
1229*0Sstevel@tonic-gate {
1230*0Sstevel@tonic-gate 	if (! (head->c_flags & DR_HASMETA))
1231*0Sstevel@tonic-gate 		return;
1232*0Sstevel@tonic-gate 	if ((metadata = malloc(metasize = (size_t)sizeof (head->c_shadow)))
1233*0Sstevel@tonic-gate 	    == NULL) {
1234*0Sstevel@tonic-gate 		(void) fprintf(stderr,
1235*0Sstevel@tonic-gate 		    gettext("Cannot malloc for metadata\n"));
1236*0Sstevel@tonic-gate 		done(1);
1237*0Sstevel@tonic-gate 	}
1238*0Sstevel@tonic-gate 	bcopy(&(head->c_shadow), metadata, metasize);
1239*0Sstevel@tonic-gate }
1240*0Sstevel@tonic-gate 
1241*0Sstevel@tonic-gate static void
1242*0Sstevel@tonic-gate xtrmeta(buf, size)
1243*0Sstevel@tonic-gate 	char *buf;
1244*0Sstevel@tonic-gate 	size_t size;
1245*0Sstevel@tonic-gate {
1246*0Sstevel@tonic-gate 	if ((metadata == NULL) && ((spcl.c_dinode.di_mode & IFMT) != IFSHAD))
1247*0Sstevel@tonic-gate 		return;
1248*0Sstevel@tonic-gate 	if ((metadata = realloc(metadata, metasize + size)) == NULL) {
1249*0Sstevel@tonic-gate 		(void) fprintf(stderr,
1250*0Sstevel@tonic-gate 		    gettext("Cannot malloc for metadata\n"));
1251*0Sstevel@tonic-gate 		done(1);
1252*0Sstevel@tonic-gate 	}
1253*0Sstevel@tonic-gate 	bcopy(buf, metadata + metasize, size);
1254*0Sstevel@tonic-gate 	metasize += size;
1255*0Sstevel@tonic-gate }
1256*0Sstevel@tonic-gate 
1257*0Sstevel@tonic-gate /* ARGSUSED */
1258*0Sstevel@tonic-gate static void
1259*0Sstevel@tonic-gate metaskip(buf, size)
1260*0Sstevel@tonic-gate 	char *buf;
1261*0Sstevel@tonic-gate 	size_t size;
1262*0Sstevel@tonic-gate {
1263*0Sstevel@tonic-gate 	if (metadata == NULL)
1264*0Sstevel@tonic-gate 		return;
1265*0Sstevel@tonic-gate 	if ((metadata = realloc(metadata, metasize + size)) == NULL) {
1266*0Sstevel@tonic-gate 		(void) fprintf(stderr,
1267*0Sstevel@tonic-gate 		    gettext("Cannot malloc for metadata\n"));
1268*0Sstevel@tonic-gate 		done(1);
1269*0Sstevel@tonic-gate 	}
1270*0Sstevel@tonic-gate 	bzero(metadata + metasize, size);
1271*0Sstevel@tonic-gate 	metasize += size;
1272*0Sstevel@tonic-gate }
1273*0Sstevel@tonic-gate 
1274*0Sstevel@tonic-gate static void
1275*0Sstevel@tonic-gate metaset(name)
1276*0Sstevel@tonic-gate 	char *name;
1277*0Sstevel@tonic-gate {
1278*0Sstevel@tonic-gate 	if (metadata == NULL)
1279*0Sstevel@tonic-gate 		return;
1280*0Sstevel@tonic-gate 	if (name != NULL)
1281*0Sstevel@tonic-gate 		metaproc(name, metadata, metasize);
1282*0Sstevel@tonic-gate 	(void) free(metadata);
1283*0Sstevel@tonic-gate 	metadata = NULL;
1284*0Sstevel@tonic-gate 	metasize = 0;
1285*0Sstevel@tonic-gate }
1286*0Sstevel@tonic-gate 
1287*0Sstevel@tonic-gate void
1288*0Sstevel@tonic-gate metaget(data, size)
1289*0Sstevel@tonic-gate 	char **data;
1290*0Sstevel@tonic-gate 	size_t *size;
1291*0Sstevel@tonic-gate {
1292*0Sstevel@tonic-gate 	*data = metadata;
1293*0Sstevel@tonic-gate 	*size = metasize;
1294*0Sstevel@tonic-gate }
1295*0Sstevel@tonic-gate 
1296*0Sstevel@tonic-gate static void
1297*0Sstevel@tonic-gate fsd_acl(name, aclp, size)
1298*0Sstevel@tonic-gate 	char *name, *aclp;
1299*0Sstevel@tonic-gate 	unsigned size;
1300*0Sstevel@tonic-gate {
1301*0Sstevel@tonic-gate 	static aclent_t *aclent = NULL;
1302*0Sstevel@tonic-gate 	ufs_acl_t *diskacl;
1303*0Sstevel@tonic-gate 	static int n = 0;
1304*0Sstevel@tonic-gate 	uint_t i;
1305*0Sstevel@tonic-gate 	int saverr, j;
1306*0Sstevel@tonic-gate 
1307*0Sstevel@tonic-gate 	if (aclp == NULL) {
1308*0Sstevel@tonic-gate 		if (aclent != NULL)
1309*0Sstevel@tonic-gate 			free(aclent);
1310*0Sstevel@tonic-gate 		aclent = NULL;
1311*0Sstevel@tonic-gate 		n = 0;
1312*0Sstevel@tonic-gate 		return;
1313*0Sstevel@tonic-gate 	}
1314*0Sstevel@tonic-gate 
1315*0Sstevel@tonic-gate 	/*LINTED [aclp is malloc'd]*/
1316*0Sstevel@tonic-gate 	diskacl = (ufs_acl_t *)aclp;
1317*0Sstevel@tonic-gate 	/* LINTED: result fits in an int */
1318*0Sstevel@tonic-gate 	j = size / sizeof (*diskacl);
1319*0Sstevel@tonic-gate 	normacls(byteorder, diskacl, j);
1320*0Sstevel@tonic-gate 
1321*0Sstevel@tonic-gate 	i = n;
1322*0Sstevel@tonic-gate 	n += j;
1323*0Sstevel@tonic-gate 	aclent = realloc(aclent, n * (size_t)sizeof (*aclent));
1324*0Sstevel@tonic-gate 	if (aclent == NULL) {
1325*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Cannot malloc acl list\n"));
1326*0Sstevel@tonic-gate 		done(1);
1327*0Sstevel@tonic-gate 	}
1328*0Sstevel@tonic-gate 
1329*0Sstevel@tonic-gate 	j = 0;
1330*0Sstevel@tonic-gate 	while (i < n) {
1331*0Sstevel@tonic-gate 		aclent[i].a_type = diskacl[j].acl_tag;
1332*0Sstevel@tonic-gate 		aclent[i].a_id = diskacl[j].acl_who;
1333*0Sstevel@tonic-gate 		aclent[i].a_perm = diskacl[j].acl_perm;
1334*0Sstevel@tonic-gate 		++i;
1335*0Sstevel@tonic-gate 		++j;
1336*0Sstevel@tonic-gate 	}
1337*0Sstevel@tonic-gate 
1338*0Sstevel@tonic-gate 	if (acl(name, SETACL, n, aclent) == -1) {
1339*0Sstevel@tonic-gate 		static int once = 0;
1340*0Sstevel@tonic-gate 
1341*0Sstevel@tonic-gate 		/*
1342*0Sstevel@tonic-gate 		 * Treat some errors from the acl subsystem specially to
1343*0Sstevel@tonic-gate 		 * avoid being too noisy:
1344*0Sstevel@tonic-gate 		 *
1345*0Sstevel@tonic-gate 		 * ENOSYS - ACLs not supported on this file system
1346*0Sstevel@tonic-gate 		 * EPERM  - not the owner or not privileged
1347*0Sstevel@tonic-gate 		 *
1348*0Sstevel@tonic-gate 		 * The following is also supported for backwards compat.
1349*0Sstevel@tonic-gate 		 * since acl(2) used to return the wrong errno:
1350*0Sstevel@tonic-gate 		 *
1351*0Sstevel@tonic-gate 		 * EINVAL - not the owner of the object
1352*0Sstevel@tonic-gate 		 */
1353*0Sstevel@tonic-gate 		if (errno == ENOSYS || errno == EPERM || errno == EINVAL) {
1354*0Sstevel@tonic-gate 			if (once == 0) {
1355*0Sstevel@tonic-gate 				saverr = errno;
1356*0Sstevel@tonic-gate 				++once;
1357*0Sstevel@tonic-gate 				fprintf(stderr,
1358*0Sstevel@tonic-gate 				    gettext("setacl failed: %s\n"),
1359*0Sstevel@tonic-gate 				    strerror(saverr));
1360*0Sstevel@tonic-gate 			}
1361*0Sstevel@tonic-gate 		} else {
1362*0Sstevel@tonic-gate 			saverr = errno;
1363*0Sstevel@tonic-gate 			fprintf(stderr, gettext("setacl on %s failed: %s\n"),
1364*0Sstevel@tonic-gate 			    name, strerror(saverr));
1365*0Sstevel@tonic-gate 		}
1366*0Sstevel@tonic-gate 	}
1367*0Sstevel@tonic-gate }
1368*0Sstevel@tonic-gate 
1369*0Sstevel@tonic-gate static struct fsdtypes {
1370*0Sstevel@tonic-gate 	int type;
1371*0Sstevel@tonic-gate 	void (*function)();
1372*0Sstevel@tonic-gate } fsdtypes[] = {
1373*0Sstevel@tonic-gate 	{FSD_ACL, fsd_acl},
1374*0Sstevel@tonic-gate 	{FSD_DFACL, fsd_acl},
1375*0Sstevel@tonic-gate 	{0, NULL}
1376*0Sstevel@tonic-gate };
1377*0Sstevel@tonic-gate 
1378*0Sstevel@tonic-gate void
1379*0Sstevel@tonic-gate metaproc(name, mdata, msize)
1380*0Sstevel@tonic-gate 	char *name, *mdata;
1381*0Sstevel@tonic-gate 	size_t msize;
1382*0Sstevel@tonic-gate {
1383*0Sstevel@tonic-gate 	struct fsdtypes *fsdtype;
1384*0Sstevel@tonic-gate 	ufs_fsd_t *fsd;
1385*0Sstevel@tonic-gate 	char *c;
1386*0Sstevel@tonic-gate 
1387*0Sstevel@tonic-gate 	/*
1388*0Sstevel@tonic-gate 	 * for the whole shadow inode, dispatch each piece
1389*0Sstevel@tonic-gate 	 * to the appropriate function.
1390*0Sstevel@tonic-gate 	 */
1391*0Sstevel@tonic-gate 	c = mdata;
1392*0Sstevel@tonic-gate 	/* LINTED (c - mdata) fits into a size_t */
1393*0Sstevel@tonic-gate 	while ((size_t)(c - mdata) < msize) {
1394*0Sstevel@tonic-gate 		/*LINTED [mdata is malloc'd]*/
1395*0Sstevel@tonic-gate 		fsd = (ufs_fsd_t *)c;
1396*0Sstevel@tonic-gate 		assert((fsd->fsd_size % 4) == 0);
1397*0Sstevel@tonic-gate 		/* LINTED: lint thinks pointers are signed */
1398*0Sstevel@tonic-gate 		c += FSD_RECSZ(fsd, fsd->fsd_size);
1399*0Sstevel@tonic-gate 		if ((fsd->fsd_type == FSD_FREE) ||
1400*0Sstevel@tonic-gate 		    ((unsigned)(fsd->fsd_size) <= sizeof (ufs_fsd_t)) ||
1401*0Sstevel@tonic-gate 		    (c > (mdata + msize)))
1402*0Sstevel@tonic-gate 			break;
1403*0Sstevel@tonic-gate 		for (fsdtype = fsdtypes; fsdtype->type; fsdtype++)
1404*0Sstevel@tonic-gate 			if (fsdtype->type == fsd->fsd_type)
1405*0Sstevel@tonic-gate 				(*fsdtype->function)(name, fsd->fsd_data,
1406*0Sstevel@tonic-gate 				    (unsigned)(fsd->fsd_size) -
1407*0Sstevel@tonic-gate 				    sizeof (fsd->fsd_type) -
1408*0Sstevel@tonic-gate 				    sizeof (fsd->fsd_size));
1409*0Sstevel@tonic-gate 		/* ^^^ be sure to change if fsd ever changes ^^^ */
1410*0Sstevel@tonic-gate 	}
1411*0Sstevel@tonic-gate 
1412*0Sstevel@tonic-gate 	/* reset the state of all the functions */
1413*0Sstevel@tonic-gate 	for (fsdtype = fsdtypes; fsdtype->type; fsdtype++)
1414*0Sstevel@tonic-gate 		(*fsdtype->function)(NULL, NULL, 0);
1415*0Sstevel@tonic-gate }
1416*0Sstevel@tonic-gate 
1417*0Sstevel@tonic-gate static void
1418*0Sstevel@tonic-gate xtrlnkfile(buf, size)
1419*0Sstevel@tonic-gate 	char	*buf;
1420*0Sstevel@tonic-gate 	size_t	size;
1421*0Sstevel@tonic-gate {
1422*0Sstevel@tonic-gate 	/* LINTED: signed/unsigned mix ok */
1423*0Sstevel@tonic-gate 	pathlen += size;
1424*0Sstevel@tonic-gate 	if (pathlen > MAXPATHLEN) {
1425*0Sstevel@tonic-gate 		(void) fprintf(stderr,
1426*0Sstevel@tonic-gate 		    gettext("symbolic link name: %s->%s%s; too long %d\n"),
1427*0Sstevel@tonic-gate 		    curfile.name, lnkbuf, buf, pathlen);
1428*0Sstevel@tonic-gate 		done(1);
1429*0Sstevel@tonic-gate 	}
1430*0Sstevel@tonic-gate 	buf[size] = '\0';
1431*0Sstevel@tonic-gate 	(void) strcat(lnkbuf, buf);
1432*0Sstevel@tonic-gate 	/* add an extra NULL to make this a legal complex string */
1433*0Sstevel@tonic-gate 	lnkbuf[pathlen+1] = '\0';
1434*0Sstevel@tonic-gate }
1435*0Sstevel@tonic-gate 
1436*0Sstevel@tonic-gate /*ARGSUSED*/
1437*0Sstevel@tonic-gate static void
1438*0Sstevel@tonic-gate xtrlnkskip(buf, size)
1439*0Sstevel@tonic-gate 	char *buf;
1440*0Sstevel@tonic-gate 	size_t size;
1441*0Sstevel@tonic-gate {
1442*0Sstevel@tonic-gate 	(void) fprintf(stderr,
1443*0Sstevel@tonic-gate 	    gettext("unallocated block in symbolic link %s\n"),
1444*0Sstevel@tonic-gate 	    curfile.name);
1445*0Sstevel@tonic-gate 	done(1);
1446*0Sstevel@tonic-gate }
1447*0Sstevel@tonic-gate 
1448*0Sstevel@tonic-gate static void
1449*0Sstevel@tonic-gate xtrmap(buf, size)
1450*0Sstevel@tonic-gate 	char	*buf;
1451*0Sstevel@tonic-gate 	size_t	size;
1452*0Sstevel@tonic-gate {
1453*0Sstevel@tonic-gate 	if ((map+size) > endmap) {
1454*0Sstevel@tonic-gate 		int64_t mapsize, increment;
1455*0Sstevel@tonic-gate 		int64_t diff;
1456*0Sstevel@tonic-gate 
1457*0Sstevel@tonic-gate 		if (spcl.c_type != TS_ADDR) {
1458*0Sstevel@tonic-gate 			(void) fprintf(stderr,
1459*0Sstevel@tonic-gate 			    gettext("xtrmap: current record not TS_ADDR\n"));
1460*0Sstevel@tonic-gate 			done(1);
1461*0Sstevel@tonic-gate 		}
1462*0Sstevel@tonic-gate 		if ((spcl.c_count < 0) || (spcl.c_count > TP_NINDIR)) {
1463*0Sstevel@tonic-gate 			(void) fprintf(stderr,
1464*0Sstevel@tonic-gate 			    gettext("xtrmap: illegal c_count field (%d)\n"),
1465*0Sstevel@tonic-gate 			    spcl.c_count);
1466*0Sstevel@tonic-gate 			done(1);
1467*0Sstevel@tonic-gate 		}
1468*0Sstevel@tonic-gate 
1469*0Sstevel@tonic-gate 		increment = d_howmany(
1470*0Sstevel@tonic-gate 			((spcl.c_count * tp_bsize * NBBY) + 1), NBBY);
1471*0Sstevel@tonic-gate 		mapsize = endmap - beginmap + increment;
1472*0Sstevel@tonic-gate 		if (mapsize > UINT_MAX) {
1473*0Sstevel@tonic-gate 			(void) fprintf(stderr,
1474*0Sstevel@tonic-gate 			    gettext("xtrmap: maximum bitmap size exceeded"));
1475*0Sstevel@tonic-gate 			done(1);
1476*0Sstevel@tonic-gate 		}
1477*0Sstevel@tonic-gate 
1478*0Sstevel@tonic-gate 		diff = map - beginmap;
1479*0Sstevel@tonic-gate 		/* LINTED mapsize checked above */
1480*0Sstevel@tonic-gate 		beginmap = realloc(beginmap, (size_t)mapsize);
1481*0Sstevel@tonic-gate 		if (beginmap == NULL) {
1482*0Sstevel@tonic-gate 			(void) fprintf(stderr,
1483*0Sstevel@tonic-gate 			    gettext("xtrmap: realloc failed\n"));
1484*0Sstevel@tonic-gate 			done(1);
1485*0Sstevel@tonic-gate 		}
1486*0Sstevel@tonic-gate 		map = beginmap + diff;
1487*0Sstevel@tonic-gate 		endmap = beginmap + mapsize;
1488*0Sstevel@tonic-gate 		/* LINTED endmap - map cannot exceed 32 bits */
1489*0Sstevel@tonic-gate 		bzero(map, (size_t)(endmap - map));
1490*0Sstevel@tonic-gate 		maxino = NBBY * mapsize + 1;
1491*0Sstevel@tonic-gate 	}
1492*0Sstevel@tonic-gate 
1493*0Sstevel@tonic-gate 	bcopy(buf, map, size);
1494*0Sstevel@tonic-gate 	/* LINTED character pointers aren't signed */
1495*0Sstevel@tonic-gate 	map += size;
1496*0Sstevel@tonic-gate }
1497*0Sstevel@tonic-gate 
1498*0Sstevel@tonic-gate /*ARGSUSED*/
1499*0Sstevel@tonic-gate static void
1500*0Sstevel@tonic-gate xtrmapskip(buf, size)
1501*0Sstevel@tonic-gate 	char *buf;
1502*0Sstevel@tonic-gate 	size_t size;
1503*0Sstevel@tonic-gate {
1504*0Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("hole in map\n"));
1505*0Sstevel@tonic-gate 	done(1);
1506*0Sstevel@tonic-gate }
1507*0Sstevel@tonic-gate 
1508*0Sstevel@tonic-gate /*ARGSUSED*/
1509*0Sstevel@tonic-gate void
1510*0Sstevel@tonic-gate null(buf, size)
1511*0Sstevel@tonic-gate 	char *buf;
1512*0Sstevel@tonic-gate 	size_t size;
1513*0Sstevel@tonic-gate {
1514*0Sstevel@tonic-gate }
1515*0Sstevel@tonic-gate 
1516*0Sstevel@tonic-gate /*
1517*0Sstevel@tonic-gate  * Do the tape i/o, dealing with volume changes
1518*0Sstevel@tonic-gate  * etc..
1519*0Sstevel@tonic-gate  */
1520*0Sstevel@tonic-gate static void
1521*0Sstevel@tonic-gate readtape(b)
1522*0Sstevel@tonic-gate 	char *b;
1523*0Sstevel@tonic-gate {
1524*0Sstevel@tonic-gate 	int i;
1525*0Sstevel@tonic-gate 	int rd, newvol;
1526*0Sstevel@tonic-gate 	int cnt;
1527*0Sstevel@tonic-gate 	struct s_spcl *sp;
1528*0Sstevel@tonic-gate 	int32_t	expected_magic;
1529*0Sstevel@tonic-gate 
1530*0Sstevel@tonic-gate 	if (tbf == NULL) {
1531*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
1532*0Sstevel@tonic-gate 		    "Internal consistency failure in readtape: tbf is NULL\n"));
1533*0Sstevel@tonic-gate 		done(1);
1534*0Sstevel@tonic-gate 	}
1535*0Sstevel@tonic-gate 	expected_magic = ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC);
1536*0Sstevel@tonic-gate 
1537*0Sstevel@tonic-gate top:
1538*0Sstevel@tonic-gate 	if (bct < numtrec) {
1539*0Sstevel@tonic-gate 		/*
1540*0Sstevel@tonic-gate 		 * check for old-dump floppy EOM -- it may appear in
1541*0Sstevel@tonic-gate 		 * the middle of a buffer.  The Dflag used to be used for
1542*0Sstevel@tonic-gate 		 * this, but since it doesn't hurt to always do this we
1543*0Sstevel@tonic-gate 		 * got rid of the Dflag.
1544*0Sstevel@tonic-gate 		 */
1545*0Sstevel@tonic-gate 		/*LINTED [tbf = malloc()]*/
1546*0Sstevel@tonic-gate 		sp = &((union u_spcl *)&tbf[bct*tp_bsize])->s_spcl;
1547*0Sstevel@tonic-gate 		if (sp->c_magic == expected_magic && sp->c_type == TS_EOM &&
1548*0Sstevel@tonic-gate 		    (time_t)(sp->c_date) == dumpdate &&
1549*0Sstevel@tonic-gate 		    (time_t)(sp->c_ddate) == dumptime) {
1550*0Sstevel@tonic-gate 			for (i = 0; i < ntrec; i++)
1551*0Sstevel@tonic-gate 				/*LINTED [tbf = malloc()]*/
1552*0Sstevel@tonic-gate 				((struct s_spcl *)
1553*0Sstevel@tonic-gate 					&tbf[i*tp_bsize])->c_magic = 0;
1554*0Sstevel@tonic-gate 			bct = 0;
1555*0Sstevel@tonic-gate 			rd = 0;
1556*0Sstevel@tonic-gate 			i = 0;
1557*0Sstevel@tonic-gate 			goto nextvol;
1558*0Sstevel@tonic-gate 		}
1559*0Sstevel@tonic-gate 		bcopy(&tbf[(bct++*tp_bsize)], b, (size_t)tp_bsize);
1560*0Sstevel@tonic-gate 		blksread++;
1561*0Sstevel@tonic-gate 		tapea++;
1562*0Sstevel@tonic-gate 		return;
1563*0Sstevel@tonic-gate 	}
1564*0Sstevel@tonic-gate 	/*LINTED [assertion always true]*/
1565*0Sstevel@tonic-gate 	assert(sizeof (union u_spcl) == TP_BSIZE_MAX);
1566*0Sstevel@tonic-gate 	for (i = 0; i < ntrec; i++)
1567*0Sstevel@tonic-gate 		/*LINTED [tbf = malloc()]*/
1568*0Sstevel@tonic-gate 		((struct s_spcl *)&tbf[i*sizeof (struct s_spcl)])->c_magic = 0;
1569*0Sstevel@tonic-gate 	if (numtrec == 0) {
1570*0Sstevel@tonic-gate 		/* LINTED unsigned/signed assignment ok */
1571*0Sstevel@tonic-gate 		numtrec = ntrec;
1572*0Sstevel@tonic-gate 	}
1573*0Sstevel@tonic-gate 	/* LINTED unsigned/signed assignment ok */
1574*0Sstevel@tonic-gate 	cnt = ntrec*tp_bsize;
1575*0Sstevel@tonic-gate 	rd = 0;
1576*0Sstevel@tonic-gate getmore:
1577*0Sstevel@tonic-gate 	if (host)
1578*0Sstevel@tonic-gate 		i = rmtread(&tbf[rd], cnt);
1579*0Sstevel@tonic-gate 	else
1580*0Sstevel@tonic-gate 		i = read(mt, &tbf[rd], cnt);
1581*0Sstevel@tonic-gate 	/*
1582*0Sstevel@tonic-gate 	 * Check for mid-tape short read error.
1583*0Sstevel@tonic-gate 	 * If found, return rest of buffer.
1584*0Sstevel@tonic-gate 	 */
1585*0Sstevel@tonic-gate 	if (numtrec < ntrec && i != 0) {
1586*0Sstevel@tonic-gate 		/* LINTED unsigned/signed assignment ok */
1587*0Sstevel@tonic-gate 		numtrec = ntrec;
1588*0Sstevel@tonic-gate 		goto top;
1589*0Sstevel@tonic-gate 	}
1590*0Sstevel@tonic-gate 	/*
1591*0Sstevel@tonic-gate 	 * Handle partial block read.
1592*0Sstevel@tonic-gate 	 */
1593*0Sstevel@tonic-gate 	if (i > 0 && i != ntrec*tp_bsize) {
1594*0Sstevel@tonic-gate 		if (pipein) {
1595*0Sstevel@tonic-gate 			rd += i;
1596*0Sstevel@tonic-gate 			cnt -= i;
1597*0Sstevel@tonic-gate 			if (cnt > 0)
1598*0Sstevel@tonic-gate 				goto getmore;
1599*0Sstevel@tonic-gate 			i = rd;
1600*0Sstevel@tonic-gate 		} else {
1601*0Sstevel@tonic-gate 			if (i % tp_bsize != 0)
1602*0Sstevel@tonic-gate 				panic(gettext(
1603*0Sstevel@tonic-gate 				    "partial block read: %d should be %d\n"),
1604*0Sstevel@tonic-gate 					i, ntrec * tp_bsize);
1605*0Sstevel@tonic-gate 			numtrec = i / tp_bsize;
1606*0Sstevel@tonic-gate 			if (numtrec == 0)
1607*0Sstevel@tonic-gate 				/*
1608*0Sstevel@tonic-gate 				 * it's possible to read only 512 bytes
1609*0Sstevel@tonic-gate 				 * from a QIC device...
1610*0Sstevel@tonic-gate 				 */
1611*0Sstevel@tonic-gate 				i = 0;
1612*0Sstevel@tonic-gate 		}
1613*0Sstevel@tonic-gate 	}
1614*0Sstevel@tonic-gate 	/*
1615*0Sstevel@tonic-gate 	 * Handle read error.
1616*0Sstevel@tonic-gate 	 */
1617*0Sstevel@tonic-gate 	if (i < 0) {
1618*0Sstevel@tonic-gate 		switch (curfile.action) {
1619*0Sstevel@tonic-gate 		default:
1620*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
1621*0Sstevel@tonic-gate 			    "Read error while trying to set up volume\n"));
1622*0Sstevel@tonic-gate 			break;
1623*0Sstevel@tonic-gate 		case UNKNOWN:
1624*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
1625*0Sstevel@tonic-gate 			    "Read error while trying to resynchronize\n"));
1626*0Sstevel@tonic-gate 			break;
1627*0Sstevel@tonic-gate 		case USING:
1628*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
1629*0Sstevel@tonic-gate 			    "Read error while restoring %s\n"),
1630*0Sstevel@tonic-gate 			    curfile.name);
1631*0Sstevel@tonic-gate 			break;
1632*0Sstevel@tonic-gate 		case SKIP:
1633*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
1634*0Sstevel@tonic-gate 			    "Read error while skipping over inode %d\n"),
1635*0Sstevel@tonic-gate 			    curfile.ino);
1636*0Sstevel@tonic-gate 			break;
1637*0Sstevel@tonic-gate 		}
1638*0Sstevel@tonic-gate 		if (!yflag && !reply(gettext("continue")))
1639*0Sstevel@tonic-gate 			done(1);
1640*0Sstevel@tonic-gate 		/* LINTED: unsigned->signed conversion ok */
1641*0Sstevel@tonic-gate 		i = (int)(ntrec*tp_bsize);
1642*0Sstevel@tonic-gate 		bzero(tbf, (size_t)i);
1643*0Sstevel@tonic-gate 		if ((host != 0 && rmtseek(i, 1) < 0) ||
1644*0Sstevel@tonic-gate 		    (host == 0 && (lseek64(mt, (offset_t)i, 1) ==
1645*0Sstevel@tonic-gate 		    (off64_t)-1))) {
1646*0Sstevel@tonic-gate 			perror(gettext("continuation failed"));
1647*0Sstevel@tonic-gate 			done(1);
1648*0Sstevel@tonic-gate 		}
1649*0Sstevel@tonic-gate 	}
1650*0Sstevel@tonic-gate 	/*
1651*0Sstevel@tonic-gate 	 * Handle end of tape.  The Dflag used to be used, but since it doesn't
1652*0Sstevel@tonic-gate 	 * hurt to always check we got rid if it.
1653*0Sstevel@tonic-gate 	 */
1654*0Sstevel@tonic-gate 
1655*0Sstevel@tonic-gate 	/*
1656*0Sstevel@tonic-gate 	 * if the first record in the buffer just read is EOM,
1657*0Sstevel@tonic-gate 	 * change volumes.
1658*0Sstevel@tonic-gate 	 */
1659*0Sstevel@tonic-gate 	/*LINTED [tbf = malloc()]*/
1660*0Sstevel@tonic-gate 	sp = &((union u_spcl *)tbf)->s_spcl;
1661*0Sstevel@tonic-gate 	if (i != 0 && sp->c_magic == expected_magic && sp->c_type == TS_EOM &&
1662*0Sstevel@tonic-gate 	    (time_t)(sp->c_date) == dumpdate &&
1663*0Sstevel@tonic-gate 	    (time_t)(sp->c_ddate) == dumptime) {
1664*0Sstevel@tonic-gate 		i = 0;
1665*0Sstevel@tonic-gate 	}
1666*0Sstevel@tonic-gate nextvol:
1667*0Sstevel@tonic-gate 	if (i == 0) {
1668*0Sstevel@tonic-gate 		if (!pipein) {
1669*0Sstevel@tonic-gate 			newvol = volno + 1;
1670*0Sstevel@tonic-gate 			volno = 0;
1671*0Sstevel@tonic-gate 			numtrec = 0;
1672*0Sstevel@tonic-gate 			getvol(newvol);
1673*0Sstevel@tonic-gate 			readtape(b); /* XXX tail recursion, not goto top? */
1674*0Sstevel@tonic-gate 			return;
1675*0Sstevel@tonic-gate 		}
1676*0Sstevel@tonic-gate 		/* XXX if panic returns, should we round rd up? */
1677*0Sstevel@tonic-gate 		/* XXX if we do, then we should zero the intervening space */
1678*0Sstevel@tonic-gate 		if (rd % tp_bsize != 0)
1679*0Sstevel@tonic-gate 			panic(gettext("partial block read: %d should be %d\n"),
1680*0Sstevel@tonic-gate 				rd, ntrec * tp_bsize);
1681*0Sstevel@tonic-gate 		bcopy((char *)&endoftapemark, &tbf[rd], (size_t)tp_bsize);
1682*0Sstevel@tonic-gate 	}
1683*0Sstevel@tonic-gate 	bct = 0;
1684*0Sstevel@tonic-gate 	bcopy(&tbf[(bct++*tp_bsize)], b, (size_t)tp_bsize);
1685*0Sstevel@tonic-gate 	blksread++;
1686*0Sstevel@tonic-gate 	recsread++;
1687*0Sstevel@tonic-gate 	tapea++;
1688*0Sstevel@tonic-gate 	rec_position++;
1689*0Sstevel@tonic-gate }
1690*0Sstevel@tonic-gate 
1691*0Sstevel@tonic-gate void
1692*0Sstevel@tonic-gate #ifdef __STDC__
1693*0Sstevel@tonic-gate findtapeblksize(int arfile)
1694*0Sstevel@tonic-gate #else
1695*0Sstevel@tonic-gate findtapeblksize(arfile)
1696*0Sstevel@tonic-gate int arfile;
1697*0Sstevel@tonic-gate #endif
1698*0Sstevel@tonic-gate {
1699*0Sstevel@tonic-gate 	int	i;
1700*0Sstevel@tonic-gate 
1701*0Sstevel@tonic-gate 	if (tbf == NULL) {
1702*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
1703*0Sstevel@tonic-gate 		    "Internal consistency failure in findtapeblksize: "
1704*0Sstevel@tonic-gate 		    "tbf is NULL\n"));
1705*0Sstevel@tonic-gate 		assert(tbf != NULL);
1706*0Sstevel@tonic-gate 		done(1);
1707*0Sstevel@tonic-gate 	}
1708*0Sstevel@tonic-gate 
1709*0Sstevel@tonic-gate 	for (i = 0; i < ntrec; i++)
1710*0Sstevel@tonic-gate 		/*LINTED [tbf = malloc()]*/
1711*0Sstevel@tonic-gate 		((struct s_spcl *)&tbf[i * tp_bsize])->c_magic = 0;
1712*0Sstevel@tonic-gate 	bct = 0;
1713*0Sstevel@tonic-gate 	if (host && arfile == TAPE_FILE)
1714*0Sstevel@tonic-gate 		tape_rec_size = rmtread(tbf, ntrec * tp_bsize);
1715*0Sstevel@tonic-gate 	else
1716*0Sstevel@tonic-gate 		tape_rec_size = read(mt, tbf, ntrec * tp_bsize);
1717*0Sstevel@tonic-gate 	recsread++;
1718*0Sstevel@tonic-gate 	rec_position++;
1719*0Sstevel@tonic-gate 	if (tape_rec_size == (ssize_t)-1) {
1720*0Sstevel@tonic-gate 		int saverr = errno;
1721*0Sstevel@tonic-gate 		char *errmsg = gettext("Media read error");
1722*0Sstevel@tonic-gate 		errno = saverr;
1723*0Sstevel@tonic-gate 		perror(errmsg);
1724*0Sstevel@tonic-gate 		done(1);
1725*0Sstevel@tonic-gate 	}
1726*0Sstevel@tonic-gate 	if (tape_rec_size % tp_bsize != 0) {
1727*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
1728*0Sstevel@tonic-gate 	    "Record size (%d) is not a multiple of dump block size (%d)\n"),
1729*0Sstevel@tonic-gate 		    tape_rec_size, tp_bsize);
1730*0Sstevel@tonic-gate 		done(1);
1731*0Sstevel@tonic-gate 	}
1732*0Sstevel@tonic-gate 	ntrec = (int)tape_rec_size / tp_bsize;
1733*0Sstevel@tonic-gate 	/* LINTED unsigned/signed assignment ok */
1734*0Sstevel@tonic-gate 	numtrec = ntrec;
1735*0Sstevel@tonic-gate 	vprintf(stdout, gettext("Media block size is %d\n"), ntrec*2);
1736*0Sstevel@tonic-gate }
1737*0Sstevel@tonic-gate 
1738*0Sstevel@tonic-gate void
1739*0Sstevel@tonic-gate #ifdef __STDC__
1740*0Sstevel@tonic-gate flsht(void)
1741*0Sstevel@tonic-gate #else
1742*0Sstevel@tonic-gate flsht()
1743*0Sstevel@tonic-gate #endif
1744*0Sstevel@tonic-gate {
1745*0Sstevel@tonic-gate 	/* LINTED unsigned/signed assignment ok */
1746*0Sstevel@tonic-gate 	bct = ntrec+1;
1747*0Sstevel@tonic-gate }
1748*0Sstevel@tonic-gate 
1749*0Sstevel@tonic-gate void
1750*0Sstevel@tonic-gate #ifdef __STDC__
1751*0Sstevel@tonic-gate closemt(void)
1752*0Sstevel@tonic-gate #else
1753*0Sstevel@tonic-gate closemt()
1754*0Sstevel@tonic-gate #endif
1755*0Sstevel@tonic-gate {
1756*0Sstevel@tonic-gate 	static struct mtop mtop = { MTOFFL, 0 };
1757*0Sstevel@tonic-gate 
1758*0Sstevel@tonic-gate 	if (mt < 0)
1759*0Sstevel@tonic-gate 		return;
1760*0Sstevel@tonic-gate 	if (offline)
1761*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Rewinding tape\n"));
1762*0Sstevel@tonic-gate 	if (host) {
1763*0Sstevel@tonic-gate 		if (offline)
1764*0Sstevel@tonic-gate 			(void) rmtioctl(MTOFFL, 1);
1765*0Sstevel@tonic-gate 		rmtclose();
1766*0Sstevel@tonic-gate 	} else if (pipein) {
1767*0Sstevel@tonic-gate 		char buffy[MAXBSIZE];
1768*0Sstevel@tonic-gate 
1769*0Sstevel@tonic-gate 		while (read(mt, buffy, sizeof (buffy)) > 0) {
1770*0Sstevel@tonic-gate 			continue;
1771*0Sstevel@tonic-gate 			/*LINTED [assertion always true]*/
1772*0Sstevel@tonic-gate 		}
1773*0Sstevel@tonic-gate 		(void) close(mt);
1774*0Sstevel@tonic-gate 	} else {
1775*0Sstevel@tonic-gate 		/*
1776*0Sstevel@tonic-gate 		 * Only way to tell if this is a floppy is to issue an ioctl
1777*0Sstevel@tonic-gate 		 * but why waste one - if the eject fails, tough!
1778*0Sstevel@tonic-gate 		 */
1779*0Sstevel@tonic-gate 		if (offline)
1780*0Sstevel@tonic-gate 			(void) ioctl(mt, MTIOCTOP, &mtop);
1781*0Sstevel@tonic-gate 		(void) ioctl(mt, FDEJECT, 0);
1782*0Sstevel@tonic-gate 		(void) close(mt);
1783*0Sstevel@tonic-gate 	}
1784*0Sstevel@tonic-gate 	mt = -1;
1785*0Sstevel@tonic-gate }
1786*0Sstevel@tonic-gate 
1787*0Sstevel@tonic-gate static int
1788*0Sstevel@tonic-gate checkvol(b, t)
1789*0Sstevel@tonic-gate 	struct s_spcl *b;
1790*0Sstevel@tonic-gate 	int t;
1791*0Sstevel@tonic-gate {
1792*0Sstevel@tonic-gate 
1793*0Sstevel@tonic-gate 	if (b->c_volume != t)
1794*0Sstevel@tonic-gate 		return (FAIL);
1795*0Sstevel@tonic-gate 	return (GOOD);
1796*0Sstevel@tonic-gate }
1797*0Sstevel@tonic-gate 
1798*0Sstevel@tonic-gate readhdr(b)
1799*0Sstevel@tonic-gate 	struct s_spcl *b;
1800*0Sstevel@tonic-gate {
1801*0Sstevel@tonic-gate 
1802*0Sstevel@tonic-gate 	if (gethead(b) == FAIL) {
1803*0Sstevel@tonic-gate 		dprintf(stdout, gettext("readhdr fails at %ld blocks\n"),
1804*0Sstevel@tonic-gate 			blksread);
1805*0Sstevel@tonic-gate 		return (FAIL);
1806*0Sstevel@tonic-gate 	}
1807*0Sstevel@tonic-gate 	return (GOOD);
1808*0Sstevel@tonic-gate }
1809*0Sstevel@tonic-gate 
1810*0Sstevel@tonic-gate /*
1811*0Sstevel@tonic-gate  * read the tape into buf, then return whether or
1812*0Sstevel@tonic-gate  * or not it is a header block.
1813*0Sstevel@tonic-gate  */
1814*0Sstevel@tonic-gate gethead(buf)
1815*0Sstevel@tonic-gate 	struct s_spcl *buf;
1816*0Sstevel@tonic-gate {
1817*0Sstevel@tonic-gate 	int i;
1818*0Sstevel@tonic-gate 	union u_ospcl {
1819*0Sstevel@tonic-gate 		char dummy[TP_BSIZE_MIN];
1820*0Sstevel@tonic-gate 		struct	s_ospcl {
1821*0Sstevel@tonic-gate 			int32_t	c_type;
1822*0Sstevel@tonic-gate 			int32_t	c_date;
1823*0Sstevel@tonic-gate 			int32_t	c_ddate;
1824*0Sstevel@tonic-gate 			int32_t	c_volume;
1825*0Sstevel@tonic-gate 			int32_t	c_tapea;
1826*0Sstevel@tonic-gate 			ushort_t c_inumber;
1827*0Sstevel@tonic-gate 			int32_t	c_magic;
1828*0Sstevel@tonic-gate 			int32_t	c_checksum;
1829*0Sstevel@tonic-gate 			struct odinode {
1830*0Sstevel@tonic-gate 				unsigned short odi_mode;
1831*0Sstevel@tonic-gate 				ushort_t odi_nlink;
1832*0Sstevel@tonic-gate 				ushort_t odi_uid;
1833*0Sstevel@tonic-gate 				ushort_t odi_gid;
1834*0Sstevel@tonic-gate 				int32_t	odi_size;
1835*0Sstevel@tonic-gate 				int32_t	odi_rdev;
1836*0Sstevel@tonic-gate 				char	odi_addr[36];
1837*0Sstevel@tonic-gate 				int32_t	odi_atime;
1838*0Sstevel@tonic-gate 				int32_t	odi_mtime;
1839*0Sstevel@tonic-gate 				int32_t	odi_ctime;
1840*0Sstevel@tonic-gate 			} c_dinode;
1841*0Sstevel@tonic-gate 			int32_t	c_count;
1842*0Sstevel@tonic-gate 			char	c_baddr[256];
1843*0Sstevel@tonic-gate 		} s_ospcl;
1844*0Sstevel@tonic-gate 	} u_ospcl;
1845*0Sstevel@tonic-gate 
1846*0Sstevel@tonic-gate 	if (cvtflag) {
1847*0Sstevel@tonic-gate 		readtape((char *)(&u_ospcl.s_ospcl));
1848*0Sstevel@tonic-gate 		bzero((char *)buf, (size_t)TP_BSIZE_MIN);
1849*0Sstevel@tonic-gate 		buf->c_type = u_ospcl.s_ospcl.c_type;
1850*0Sstevel@tonic-gate 		buf->c_date = u_ospcl.s_ospcl.c_date;
1851*0Sstevel@tonic-gate 		buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1852*0Sstevel@tonic-gate 		buf->c_volume = u_ospcl.s_ospcl.c_volume;
1853*0Sstevel@tonic-gate 		buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1854*0Sstevel@tonic-gate 		buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1855*0Sstevel@tonic-gate 		buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1856*0Sstevel@tonic-gate 		buf->c_magic = u_ospcl.s_ospcl.c_magic;
1857*0Sstevel@tonic-gate 		buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1858*0Sstevel@tonic-gate 		/* LINTED: unsigned/signed combination ok */
1859*0Sstevel@tonic-gate 		buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1860*0Sstevel@tonic-gate 		buf->c_dinode.di_size =
1861*0Sstevel@tonic-gate 		    (unsigned)(u_ospcl.s_ospcl.c_dinode.odi_size);
1862*0Sstevel@tonic-gate 		buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1863*0Sstevel@tonic-gate 		buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1864*0Sstevel@tonic-gate 		buf->c_dinode.di_suid = UID_LONG;
1865*0Sstevel@tonic-gate 		buf->c_dinode.di_sgid = GID_LONG;
1866*0Sstevel@tonic-gate 		buf->c_dinode.di_ordev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1867*0Sstevel@tonic-gate 		buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
1868*0Sstevel@tonic-gate 		buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1869*0Sstevel@tonic-gate 		buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1870*0Sstevel@tonic-gate 		buf->c_count = u_ospcl.s_ospcl.c_count;
1871*0Sstevel@tonic-gate 		bcopy(u_ospcl.s_ospcl.c_baddr, buf->c_addr,
1872*0Sstevel@tonic-gate 		    sizeof (u_ospcl.s_ospcl.c_baddr));
1873*0Sstevel@tonic-gate 
1874*0Sstevel@tonic-gate 		/*CONSTANTCONDITION*/
1875*0Sstevel@tonic-gate 		assert(sizeof (u_ospcl.s_ospcl) < sizeof (union u_spcl));
1876*0Sstevel@tonic-gate 
1877*0Sstevel@tonic-gate 		/* we byte-swap the new spclrec, but checksum the old	*/
1878*0Sstevel@tonic-gate 		/* (see comments in normspcl())				*/
1879*0Sstevel@tonic-gate 		if (normspcl(byteorder, buf,
1880*0Sstevel@tonic-gate 		    (int *)(&u_ospcl.s_ospcl), sizeof (u_ospcl.s_ospcl),
1881*0Sstevel@tonic-gate 		    OFS_MAGIC))
1882*0Sstevel@tonic-gate 			return (FAIL);
1883*0Sstevel@tonic-gate 		buf->c_magic =
1884*0Sstevel@tonic-gate 		    ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC);
1885*0Sstevel@tonic-gate 	} else {
1886*0Sstevel@tonic-gate 		readtape((char *)buf);
1887*0Sstevel@tonic-gate 		if (normspcl(byteorder, buf, (int *)buf, tp_bsize,
1888*0Sstevel@tonic-gate 		    ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC)))
1889*0Sstevel@tonic-gate 			return (FAIL);
1890*0Sstevel@tonic-gate 	}
1891*0Sstevel@tonic-gate 
1892*0Sstevel@tonic-gate 	switch (buf->c_type) {
1893*0Sstevel@tonic-gate 
1894*0Sstevel@tonic-gate 	case TS_CLRI:
1895*0Sstevel@tonic-gate 	case TS_BITS:
1896*0Sstevel@tonic-gate 		/*
1897*0Sstevel@tonic-gate 		 * Have to patch up missing information in bit map headers
1898*0Sstevel@tonic-gate 		 */
1899*0Sstevel@tonic-gate 		buf->c_inumber = 0;
1900*0Sstevel@tonic-gate 		buf->c_dinode.di_size = (offset_t)buf->c_count * tp_bsize;
1901*0Sstevel@tonic-gate 		for (i = 0; i < buf->c_count && i < TP_NINDIR; i++)
1902*0Sstevel@tonic-gate 			buf->c_addr[i] = 1;
1903*0Sstevel@tonic-gate 		break;
1904*0Sstevel@tonic-gate 
1905*0Sstevel@tonic-gate 	case TS_TAPE:
1906*0Sstevel@tonic-gate 	case TS_END:
1907*0Sstevel@tonic-gate 		if (dumpinfo.c_date == 0) {
1908*0Sstevel@tonic-gate 			dumpinfo.c_date = spcl.c_date;
1909*0Sstevel@tonic-gate 			dumpinfo.c_ddate = spcl.c_ddate;
1910*0Sstevel@tonic-gate 		}
1911*0Sstevel@tonic-gate 		if (!hostinfo && spcl.c_host[0] != '\0') {
1912*0Sstevel@tonic-gate 			bcopy(spcl.c_label, dumpinfo.c_label,
1913*0Sstevel@tonic-gate 			    sizeof (spcl.c_label));
1914*0Sstevel@tonic-gate 			bcopy(spcl.c_filesys, dumpinfo.c_filesys,
1915*0Sstevel@tonic-gate 			    sizeof (spcl.c_filesys));
1916*0Sstevel@tonic-gate 			bcopy(spcl.c_dev, dumpinfo.c_dev,
1917*0Sstevel@tonic-gate 			    sizeof (spcl.c_dev));
1918*0Sstevel@tonic-gate 			bcopy(spcl.c_host, dumpinfo.c_host,
1919*0Sstevel@tonic-gate 			    sizeof (spcl.c_host));
1920*0Sstevel@tonic-gate 			dumpinfo.c_level = spcl.c_level;
1921*0Sstevel@tonic-gate 			hostinfo++;
1922*0Sstevel@tonic-gate 			if (c_label != NULL &&
1923*0Sstevel@tonic-gate 			    strncmp(c_label, spcl.c_label,
1924*0Sstevel@tonic-gate 				sizeof (spcl.c_label))
1925*0Sstevel@tonic-gate 			    != 0) {
1926*0Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1927*0Sstevel@tonic-gate 		    "Incorrect tape label.  Expected `%s', got `%.*s'\n"),
1928*0Sstevel@tonic-gate 				    c_label,
1929*0Sstevel@tonic-gate 				    sizeof (spcl.c_label), spcl.c_label);
1930*0Sstevel@tonic-gate 				done(1);
1931*0Sstevel@tonic-gate 			}
1932*0Sstevel@tonic-gate 		}
1933*0Sstevel@tonic-gate 		if (!inodeinfo && (spcl.c_flags & DR_INODEINFO)) {
1934*0Sstevel@tonic-gate 			dumpinfo.c_volume = spcl.c_volume;
1935*0Sstevel@tonic-gate 			bcopy(spcl.c_inos, dumpinfo.c_inos,
1936*0Sstevel@tonic-gate 			    sizeof (spcl.c_inos));
1937*0Sstevel@tonic-gate 			inodeinfo++;
1938*0Sstevel@tonic-gate 		}
1939*0Sstevel@tonic-gate 		buf->c_inumber = 0;
1940*0Sstevel@tonic-gate 		break;
1941*0Sstevel@tonic-gate 
1942*0Sstevel@tonic-gate 	case TS_INODE:
1943*0Sstevel@tonic-gate 	case TS_ADDR:
1944*0Sstevel@tonic-gate 		break;
1945*0Sstevel@tonic-gate 
1946*0Sstevel@tonic-gate 	default:
1947*0Sstevel@tonic-gate 		panic(gettext("%s: unknown inode type %d\n"),
1948*0Sstevel@tonic-gate 			"gethead", buf->c_type);
1949*0Sstevel@tonic-gate 		return (FAIL);
1950*0Sstevel@tonic-gate 	}
1951*0Sstevel@tonic-gate 	if (dflag)
1952*0Sstevel@tonic-gate 		accthdr(buf);
1953*0Sstevel@tonic-gate 	return (GOOD);
1954*0Sstevel@tonic-gate }
1955*0Sstevel@tonic-gate 
1956*0Sstevel@tonic-gate /*
1957*0Sstevel@tonic-gate  * Check that a header is where it belongs and predict the next header
1958*0Sstevel@tonic-gate  */
1959*0Sstevel@tonic-gate static void
1960*0Sstevel@tonic-gate accthdr(header)
1961*0Sstevel@tonic-gate 	struct s_spcl *header;
1962*0Sstevel@tonic-gate {
1963*0Sstevel@tonic-gate 	static ino_t previno = (ino_t)(unsigned)-1;
1964*0Sstevel@tonic-gate 	static int prevtype;
1965*0Sstevel@tonic-gate 	static long predict;
1966*0Sstevel@tonic-gate 	int blks, i;
1967*0Sstevel@tonic-gate 
1968*0Sstevel@tonic-gate 	if (header->c_type == TS_TAPE) {
1969*0Sstevel@tonic-gate 		if (header->c_firstrec)
1970*0Sstevel@tonic-gate 			(void) fprintf(stderr,
1971*0Sstevel@tonic-gate 			    gettext("Volume header begins with record %d"),
1972*0Sstevel@tonic-gate 			    header->c_firstrec);
1973*0Sstevel@tonic-gate 		else
1974*0Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("Volume header"));
1975*0Sstevel@tonic-gate 		(void) fprintf(stderr, "\n");
1976*0Sstevel@tonic-gate 		previno = (ino_t)(unsigned)-1;
1977*0Sstevel@tonic-gate 		return;
1978*0Sstevel@tonic-gate 	}
1979*0Sstevel@tonic-gate 	if (previno == (ino_t)(unsigned)-1)
1980*0Sstevel@tonic-gate 		goto newcalc;
1981*0Sstevel@tonic-gate 	switch (prevtype) {
1982*0Sstevel@tonic-gate 	case TS_BITS:
1983*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Dump mask header"));
1984*0Sstevel@tonic-gate 		break;
1985*0Sstevel@tonic-gate 	case TS_CLRI:
1986*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Remove mask header"));
1987*0Sstevel@tonic-gate 		break;
1988*0Sstevel@tonic-gate 	case TS_INODE:
1989*0Sstevel@tonic-gate 		(void) fprintf(stderr,
1990*0Sstevel@tonic-gate 		    gettext("File header, ino %d at record %d"),
1991*0Sstevel@tonic-gate 		    previno, rec_position);
1992*0Sstevel@tonic-gate 		break;
1993*0Sstevel@tonic-gate 	case TS_ADDR:
1994*0Sstevel@tonic-gate 		(void) fprintf(stderr,
1995*0Sstevel@tonic-gate 		    gettext("File continuation header, ino %d"),
1996*0Sstevel@tonic-gate 		    previno);
1997*0Sstevel@tonic-gate 		break;
1998*0Sstevel@tonic-gate 	case TS_END:
1999*0Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("End of media header"));
2000*0Sstevel@tonic-gate 		break;
2001*0Sstevel@tonic-gate 	}
2002*0Sstevel@tonic-gate 	if (predict != blksread - 1)
2003*0Sstevel@tonic-gate 		(void) fprintf(stderr,
2004*0Sstevel@tonic-gate 		    gettext("; predicted %ld blocks, got %ld blocks"),
2005*0Sstevel@tonic-gate 		    predict, blksread - 1);
2006*0Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");
2007*0Sstevel@tonic-gate newcalc:
2008*0Sstevel@tonic-gate 	blks = 0;
2009*0Sstevel@tonic-gate 	if (header->c_type != TS_END)
2010*0Sstevel@tonic-gate 		for (i = 0; i < header->c_count; i++)
2011*0Sstevel@tonic-gate 			if ((i >= TP_NINDIR) || (header->c_addr[i] != 0))
2012*0Sstevel@tonic-gate 				blks++;
2013*0Sstevel@tonic-gate 	predict = blks;
2014*0Sstevel@tonic-gate 	blksread = 0;
2015*0Sstevel@tonic-gate 	prevtype = header->c_type;
2016*0Sstevel@tonic-gate 	previno = header->c_inumber;
2017*0Sstevel@tonic-gate }
2018*0Sstevel@tonic-gate 
2019*0Sstevel@tonic-gate /*
2020*0Sstevel@tonic-gate  * Try to determine which volume a file resides on.
2021*0Sstevel@tonic-gate  */
2022*0Sstevel@tonic-gate volnumber(inum)
2023*0Sstevel@tonic-gate 	ino_t inum;
2024*0Sstevel@tonic-gate {
2025*0Sstevel@tonic-gate 	int i;
2026*0Sstevel@tonic-gate 
2027*0Sstevel@tonic-gate 	if (inodeinfo == 0)
2028*0Sstevel@tonic-gate 		return (0);
2029*0Sstevel@tonic-gate 	for (i = 1; i <= dumpinfo.c_volume; i++)
2030*0Sstevel@tonic-gate 		if (inum < (ino_t)(unsigned)(dumpinfo.c_inos[i]))
2031*0Sstevel@tonic-gate 			break;
2032*0Sstevel@tonic-gate 	return (i - 1);
2033*0Sstevel@tonic-gate }
2034*0Sstevel@tonic-gate 
2035*0Sstevel@tonic-gate /*
2036*0Sstevel@tonic-gate  * Find an inode header.
2037*0Sstevel@tonic-gate  * Note that *header must be stable storage, as curfile will end up with
2038*0Sstevel@tonic-gate  * pointers into it.
2039*0Sstevel@tonic-gate  */
2040*0Sstevel@tonic-gate void
2041*0Sstevel@tonic-gate findinode(header)
2042*0Sstevel@tonic-gate 	struct s_spcl *header;
2043*0Sstevel@tonic-gate {
2044*0Sstevel@tonic-gate 	long skipcnt = 0;
2045*0Sstevel@tonic-gate 	int i;
2046*0Sstevel@tonic-gate 	char buf[TP_BSIZE_MAX];
2047*0Sstevel@tonic-gate 
2048*0Sstevel@tonic-gate 	curfile.name = gettext("<name unknown>");
2049*0Sstevel@tonic-gate 	curfile.action = UNKNOWN;
2050*0Sstevel@tonic-gate 	curfile.dip = (struct dinode *)NULL;
2051*0Sstevel@tonic-gate 	curfile.ino = 0;
2052*0Sstevel@tonic-gate 	curfile.ts = 0;
2053*0Sstevel@tonic-gate 	if (ishead(header) == FAIL) {
2054*0Sstevel@tonic-gate 		skipcnt++;
2055*0Sstevel@tonic-gate 		while (gethead(header) == FAIL ||
2056*0Sstevel@tonic-gate 		    (time_t)(header->c_date) != dumpdate)
2057*0Sstevel@tonic-gate 			skipcnt++;
2058*0Sstevel@tonic-gate 	}
2059*0Sstevel@tonic-gate 	for (;;) {
2060*0Sstevel@tonic-gate 		if (checktype(header, TS_ADDR) == GOOD) {
2061*0Sstevel@tonic-gate 			/*
2062*0Sstevel@tonic-gate 			 * Skip up to the beginning of the next record
2063*0Sstevel@tonic-gate 			 */
2064*0Sstevel@tonic-gate 			for (i = 0; i < header->c_count; i++)
2065*0Sstevel@tonic-gate 				if ((i >= TP_NINDIR) || (header->c_addr[i]))
2066*0Sstevel@tonic-gate 					readtape(buf);
2067*0Sstevel@tonic-gate 			(void) gethead(header);
2068*0Sstevel@tonic-gate 			continue;
2069*0Sstevel@tonic-gate 		}
2070*0Sstevel@tonic-gate 		if (checktype(header, TS_INODE) == GOOD) {
2071*0Sstevel@tonic-gate 			curfile.dip = &header->c_dinode;
2072*0Sstevel@tonic-gate 			if (curfile.dip->di_suid != UID_LONG)
2073*0Sstevel@tonic-gate 				curfile.dip->di_uid = curfile.dip->di_suid;
2074*0Sstevel@tonic-gate 			if (curfile.dip->di_sgid != GID_LONG)
2075*0Sstevel@tonic-gate 				curfile.dip->di_gid = curfile.dip->di_sgid;
2076*0Sstevel@tonic-gate 			curfile.ino = header->c_inumber;
2077*0Sstevel@tonic-gate 			curfile.ts = TS_INODE;
2078*0Sstevel@tonic-gate 			break;
2079*0Sstevel@tonic-gate 		}
2080*0Sstevel@tonic-gate 		if (checktype(header, TS_END) == GOOD) {
2081*0Sstevel@tonic-gate 			curfile.ino = maxino;
2082*0Sstevel@tonic-gate 			curfile.ts = TS_END;
2083*0Sstevel@tonic-gate 			break;
2084*0Sstevel@tonic-gate 		}
2085*0Sstevel@tonic-gate 		if (checktype(header, TS_CLRI) == GOOD) {
2086*0Sstevel@tonic-gate 			curfile.name = gettext("<file removal list>");
2087*0Sstevel@tonic-gate 			curfile.ts = TS_CLRI;
2088*0Sstevel@tonic-gate 			break;
2089*0Sstevel@tonic-gate 		}
2090*0Sstevel@tonic-gate 		if (checktype(header, TS_BITS) == GOOD) {
2091*0Sstevel@tonic-gate 			curfile.name = gettext("<file dump list>");
2092*0Sstevel@tonic-gate 			curfile.ts = TS_BITS;
2093*0Sstevel@tonic-gate 			break;
2094*0Sstevel@tonic-gate 		}
2095*0Sstevel@tonic-gate 		while (gethead(header) == FAIL)
2096*0Sstevel@tonic-gate 			skipcnt++;
2097*0Sstevel@tonic-gate 	}
2098*0Sstevel@tonic-gate 	if (skipcnt > 0)
2099*0Sstevel@tonic-gate 		(void) fprintf(stderr,
2100*0Sstevel@tonic-gate 		    gettext("resync restore, skipped %d blocks\n"),
2101*0Sstevel@tonic-gate 		    skipcnt);
2102*0Sstevel@tonic-gate }
2103*0Sstevel@tonic-gate 
2104*0Sstevel@tonic-gate /*
2105*0Sstevel@tonic-gate  * return whether or not the buffer contains a header block
2106*0Sstevel@tonic-gate  */
2107*0Sstevel@tonic-gate static int
2108*0Sstevel@tonic-gate ishead(buf)
2109*0Sstevel@tonic-gate 	struct s_spcl *buf;
2110*0Sstevel@tonic-gate {
2111*0Sstevel@tonic-gate 	if (buf->c_magic !=
2112*0Sstevel@tonic-gate 	    ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC))
2113*0Sstevel@tonic-gate 		return (FAIL);
2114*0Sstevel@tonic-gate 	return (GOOD);
2115*0Sstevel@tonic-gate }
2116*0Sstevel@tonic-gate 
2117*0Sstevel@tonic-gate static
2118*0Sstevel@tonic-gate checktype(b, t)
2119*0Sstevel@tonic-gate 	struct s_spcl *b;
2120*0Sstevel@tonic-gate 	int	t;
2121*0Sstevel@tonic-gate {
2122*0Sstevel@tonic-gate 	if (b->c_type != t)
2123*0Sstevel@tonic-gate 		return (FAIL);
2124*0Sstevel@tonic-gate 	return (GOOD);
2125*0Sstevel@tonic-gate }
2126*0Sstevel@tonic-gate 
2127*0Sstevel@tonic-gate /*
2128*0Sstevel@tonic-gate  * If autoloading is enabled, attempt to do it.  If we succeed,
2129*0Sstevel@tonic-gate  * return non-zero.
2130*0Sstevel@tonic-gate  */
2131*0Sstevel@tonic-gate static int
2132*0Sstevel@tonic-gate #ifdef __STDC__
2133*0Sstevel@tonic-gate autoload_tape(void)
2134*0Sstevel@tonic-gate #else
2135*0Sstevel@tonic-gate autoload_tape()
2136*0Sstevel@tonic-gate #endif
2137*0Sstevel@tonic-gate {
2138*0Sstevel@tonic-gate 	int result = 0;		/* assume failure */
2139*0Sstevel@tonic-gate 	int tries;
2140*0Sstevel@tonic-gate 	int fd;
2141*0Sstevel@tonic-gate 
2142*0Sstevel@tonic-gate 	if (autoload) {
2143*0Sstevel@tonic-gate 		/*
2144*0Sstevel@tonic-gate 		 * Wait for the tape to autoload.  Note that the delay
2145*0Sstevel@tonic-gate 		 * period doesn't take into account however long it takes
2146*0Sstevel@tonic-gate 		 * for the open to fail (measured at 21 seconds for an
2147*0Sstevel@tonic-gate 		 * Exabyte 8200 under 2.7 on an Ultra 2).
2148*0Sstevel@tonic-gate 		 */
2149*0Sstevel@tonic-gate 		closemt();
2150*0Sstevel@tonic-gate 		(void) fprintf(stderr,
2151*0Sstevel@tonic-gate 		    gettext("Attempting to autoload next volume\n"));
2152*0Sstevel@tonic-gate 		for (tries = 0; tries < autoload_tries; tries++) {
2153*0Sstevel@tonic-gate 			if (host) {
2154*0Sstevel@tonic-gate 				if (rmtopen(magtape, O_RDONLY) >= 0) {
2155*0Sstevel@tonic-gate 					rmtclose();
2156*0Sstevel@tonic-gate 					result = 1;
2157*0Sstevel@tonic-gate 					break;
2158*0Sstevel@tonic-gate 				}
2159*0Sstevel@tonic-gate 			} else {
2160*0Sstevel@tonic-gate 				if ((fd = open(magtape, O_RDONLY|O_LARGEFILE,
2161*0Sstevel@tonic-gate 				    0600)) >= 0) {
2162*0Sstevel@tonic-gate 					(void) close(fd);
2163*0Sstevel@tonic-gate 					result = 1;
2164*0Sstevel@tonic-gate 					break;
2165*0Sstevel@tonic-gate 				}
2166*0Sstevel@tonic-gate 			}
2167*0Sstevel@tonic-gate 			(void) sleep(autoload_period);
2168*0Sstevel@tonic-gate 		}
2169*0Sstevel@tonic-gate 		if (result == 0) {
2170*0Sstevel@tonic-gate 			/* Assume caller will deal with manual change-over */
2171*0Sstevel@tonic-gate 			(void) fprintf(stderr,
2172*0Sstevel@tonic-gate 			    gettext("Autoload timed out\n"));
2173*0Sstevel@tonic-gate 		} else {
2174*0Sstevel@tonic-gate 			if ((host != NULL &&
2175*0Sstevel@tonic-gate 			    (mt = rmtopen(magtape, O_RDONLY)) == -1) ||
2176*0Sstevel@tonic-gate 			    (host == NULL &&
2177*0Sstevel@tonic-gate 			    (mt = open(magtape, O_RDONLY|O_LARGEFILE)) == -1)) {
2178*0Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
2179*0Sstevel@tonic-gate 				    "Autoload could not re-open tape\n"));
2180*0Sstevel@tonic-gate 				result = 0;
2181*0Sstevel@tonic-gate 			} else {
2182*0Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
2183*0Sstevel@tonic-gate 				    "Tape loaded\n"));
2184*0Sstevel@tonic-gate 			}
2185*0Sstevel@tonic-gate 		}
2186*0Sstevel@tonic-gate 	}
2187*0Sstevel@tonic-gate 
2188*0Sstevel@tonic-gate 	return (result);
2189*0Sstevel@tonic-gate }
2190