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