xref: /titanic_50/usr/src/cmd/backup/restore/tape.c (revision d29f5a711240f866521445b1656d114da090335e)
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 2007 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 			wantnext = 1;
505 			newvol = nextvol;
506 			goto gethdr;
507 		}
508 	}
509 
510 	while (newvol <= 0) {
511 		int n = 0;
512 
513 		for (i = 0;  i < MAXTAPES;  i++)
514 			if (tapesread[i])
515 				n++;
516 		if (n == 0) {
517 			(void) fprintf(stderr, "%s", gettext(
518 "You have not read any volumes yet.\n\
519 Unless you know which volume your file(s) are on you should start\n\
520 with the last volume and work towards the first.\n"));
521 		} else {
522 			(void) fprintf(stderr,
523 			    gettext("You have read volumes"));
524 			(void) strcpy(tbf, ": ");
525 			for (i = 0; i < MAXTAPES; i++)
526 				if (tapesread[i]) {
527 					(void) fprintf(stderr, "%s%ld",
528 					    tbf, i+1);
529 					(void) strcpy(tbf, ", ");
530 				}
531 			(void) fprintf(stderr, "\n");
532 		}
533 		do {
534 			(void) fprintf(stderr,
535 			    gettext("Specify next volume #: "));
536 			(void) fflush(stderr);
537 			/* LINTED tbfsize is limited to a few MB */
538 			(void) fgets(tbf, (int)tbfsize, terminal);
539 		} while (!feof(terminal) && tbf[0] == '\n');
540 		if (feof(terminal))
541 			done(1);
542 		newvol = atoi(tbf);
543 		if (newvol <= 0) {
544 			(void) fprintf(stderr, gettext(
545 			    "Volume numbers are positive numerics\n"));
546 		}
547 		if (newvol > MAXTAPES) {
548 			(void) fprintf(stderr, gettext(
549 			    "This program can only deal with %d volumes\n"),
550 			    MAXTAPES);
551 			newvol = 0;
552 		}
553 	}
554 	if (newvol == volno) {
555 		tapesread[volno-1]++;
556 		return;
557 	}
558 	closemt(ALLOW_OFFLINE);
559 	/*
560 	 * XXX: if we are switching devices, we should probably try
561 	 * the device once without prompting to enable unattended
562 	 * operation.
563 	 */
564 	if (host)
565 		(void) fprintf(stderr, gettext(
566 "Mount volume %d\nthen enter volume name on host %s (default: %s) "),
567 		    newvol, host,  magtape);
568 	else
569 		(void) fprintf(stderr, gettext(
570 		    "Mount volume %d\nthen enter volume name (default: %s) "),
571 		    newvol, magtape);
572 	(void) fflush(stderr);
573 	/* LINTED tbfsize is limited to a few MB */
574 	(void) fgets(tbf, (int)tbfsize, terminal);
575 	if (feof(terminal))
576 		done(1);
577 	/*
578 	 * XXX We don't allow rotating among tape hosts, just drives.
579 	 */
580 	if (tbf[0] != '\n') {
581 		(void) strncpy(magtape, tbf, sizeof (magtape));
582 		magtape[sizeof (magtape) - 1] = '\0';
583 		/* LINTED unsigned -> signed conversion ok */
584 		i = (int)strlen(magtape);
585 		if (magtape[i - 1] == '\n')
586 			magtape[i - 1] = '\0';
587 	}
588 	if ((host != NULL && (mt = rmtopen(magtape, O_RDONLY)) == -1) ||
589 	    (host == NULL &&
590 	    (mt = open(magtape, O_RDONLY|O_LARGEFILE)) == -1)) {
591 		int error = errno;
592 		(void) fprintf(stderr, gettext("Cannot open %s: %s\n"),
593 		    magtape, strerror(error));
594 		volno = -1;
595 		goto again;
596 	}
597 gethdr:
598 	volno = newvol;
599 	setdumpnum();
600 	flsht();
601 	if (!pipein && !bflag && archivefile && (first_time == FT_STATE_1)) {
602 		first_time = FT_STATE_2;
603 		findtapeblksize(TAPE_FILE);
604 	}
605 	if (readhdr(&tmpbuf) == FAIL) {
606 		(void) fprintf(stderr,
607 		    gettext("volume is not in dump format\n"));
608 		volno = 0;
609 		goto again;
610 	}
611 	if (checkvol(&tmpbuf, volno) == FAIL) {
612 		(void) fprintf(stderr, gettext("Wrong volume (%d)\n"),
613 		    tmpbuf.c_volume);
614 		volno = 0;
615 		goto again;
616 	}
617 
618 	if (((time_t)(tmpbuf.c_date) != dumpdate) ||
619 	    ((time_t)(tmpbuf.c_ddate) != dumptime)) {
620 		char *tmp_ct;
621 		time_t lc_date = (time_t)tmpbuf.c_date;
622 
623 		/*
624 		 * This is used to save the return value from lctime(),
625 		 * since that's volatile across lctime() invocations.
626 		 */
627 		tmp_ct = strdup(lctime(&lc_date));
628 		if (tmp_ct == (char *)0) {
629 			(void) fprintf(stderr, gettext(
630 			    "Cannot allocate space for time string\n"));
631 			done(1);
632 		}
633 
634 		(void) fprintf(stderr,
635 		    gettext("Wrong dump date\n\tgot: %s\twanted: %s"),
636 		    tmp_ct,  lctime(&dumpdate));
637 		volno = 0;
638 		free(tmp_ct);
639 		goto again;
640 	}
641 	tapesread[volno-1]++;
642 	blksread = savecnt;
643 	tapea = savetapea;
644 	/*
645 	 * If continuing from the previous volume, skip over any
646 	 * blocks read already at the end of the previous volume.
647 	 *
648 	 * If coming to this volume at random, skip to the beginning
649 	 * of the next record.
650 	 */
651 	if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
652 		if (!wantnext) {
653 			if (archivefile && first_time == FT_STATE_2) {
654 				first_time = FT_STATE_3;
655 			}
656 			recsread = tmpbuf.c_firstrec;
657 			tapea = tmpbuf.c_tapea;
658 			dprintf(stdout,
659 			    "restore skipping %d records\n",
660 			    tmpbuf.c_count);
661 			for (i = tmpbuf.c_count; i > 0; i--)
662 				readtape(buf);
663 		} else if (tmpbuf.c_firstrec != 0) {
664 			savecnt = blksread;
665 			savetapea = tapea;
666 
667 			if (archivefile && first_time == FT_STATE_2) {
668 				/*
669 				 * subtract 2, 1 for archive file's TS_END
670 				 * and 1 for tape's TS_TAPE
671 				 */
672 				first_time = FT_STATE_3;
673 				i = tapea - tmpbuf.c_tapea - 2;
674 			} else {
675 				i = tapea - tmpbuf.c_tapea;
676 			}
677 			if (i > 0)
678 				dprintf(stdout, gettext(
679 				    "restore skipping %d duplicate records\n"),
680 				    i);
681 			else if (i < 0)
682 				dprintf(stdout, gettext(
683 				    "restore duplicate record botch (%d)\n"),
684 				    i);
685 			while (--i >= 0)
686 				readtape(buf);
687 			blksread = savecnt;
688 			tapea = savetapea + 1; /* <= (void) gethead() below */
689 		}
690 	}
691 	if (curfile.action == USING) {
692 		if (volno == 1)
693 			panic(gettext("active file into volume 1\n"));
694 		return;
695 	}
696 	(void) gethead(&spcl);
697 	findinode(&spcl); /* do we always restart files in full? */
698 	if (gettingfile) { /* i.e. will we lose metadata? */
699 		gettingfile = 0;
700 		longjmp(restart, 1); /* will this set f1 & f2? */
701 	}
702 }
703 
704 /*
705  * handle multiple dumps per tape by skipping forward to the
706  * appropriate one.  Note we don't use absolute positioning,
707  * as that may take a very long time.
708  */
709 static void
710 #ifdef __STDC__
711 setdumpnum(void)
712 #else
713 setdumpnum()
714 #endif
715 {
716 	struct mtop tcom;
717 	int retval;
718 
719 	if (dumpnum == 1 || volno != 1)
720 		return;
721 	if (pipein) {
722 		(void) fprintf(stderr,
723 		    gettext("Cannot have multiple dumps on pipe input\n"));
724 		done(1);
725 	}
726 	tcom.mt_op = MTFSF;
727 	tcom.mt_count = dumpnum - 1;
728 	if (host)
729 		retval = rmtioctl(MTFSF, dumpnum - 1);
730 	else
731 		retval = ioctl(mt, (int)MTIOCTOP, (char *)&tcom);
732 	if (retval < 0)
733 		perror("ioctl MTFSF");
734 }
735 
736 void
737 #ifdef __STDC__
738 printdumpinfo(void)
739 #else
740 printdumpinfo()
741 #endif
742 {
743 	int i;
744 	time_t date;
745 	static char *epoch = NULL;
746 
747 	if (epoch == NULL) {
748 		epoch = strdup(gettext("the epoch\n"));
749 		if (epoch == NULL) {
750 			(void) fprintf(stderr, gettext("Out of memory\n"));
751 			return;
752 		}
753 	}
754 
755 	date = (time_t)dumpinfo.c_date;
756 	(void) fprintf(stdout,
757 	    gettext("Dump   date: %s"), lctime(&date));
758 
759 	date = (time_t)dumpinfo.c_ddate;
760 	(void) fprintf(stdout, gettext("Dumped from: %s"),
761 	    (dumpinfo.c_ddate == 0) ? epoch : lctime(&date));
762 	if (hostinfo) {
763 		(void) fprintf(stdout,
764 		    gettext("Level %d dump of %s on %.*s:%s\n"),
765 		    dumpinfo.c_level, dumpinfo.c_filesys,
766 		    sizeof (dumpinfo.c_host), dumpinfo.c_host, dumpinfo.c_dev);
767 		(void) fprintf(stdout,
768 		    gettext("Label: %.*s\n"),
769 		    sizeof (dumpinfo.c_label), dumpinfo.c_label);
770 	}
771 	if (inodeinfo) {
772 		(void) fprintf(stdout,
773 		    gettext("Starting inode numbers by volume:\n"));
774 		for (i = 1; i <= dumpinfo.c_volume; i++)
775 			(void) fprintf(stdout, gettext("\tVolume %d: %6d\n"),
776 			    i, dumpinfo.c_inos[i]);
777 	}
778 }
779 
780 int
781 extractfile(char *name)
782 {
783 	static int complained_chown = 0;
784 	static int complained_lchown = 0;
785 	static int complained_chmod = 0;
786 	static int complained_utime = 0;
787 	static int complained_mknod = 0;
788 	mode_t mode;
789 	time_t timep[2];
790 	struct entry *ep;
791 	uid_t uid;
792 	gid_t gid;
793 	char *errmsg;
794 	int result, saverr;
795 	dev_t full_dev;
796 	int dfd;
797 	char *rname;
798 
799 	curfile.name = name;
800 	curfile.action = USING;
801 	timep[0] = (time_t)curfile.dip->di_atime;
802 	timep[1] = (time_t)curfile.dip->di_mtime;
803 	mode = curfile.dip->di_mode;
804 
805 	uid = curfile.dip->di_suid == UID_LONG ?
806 	    curfile.dip->di_uid : (uid_t)curfile.dip->di_suid;
807 	gid = curfile.dip->di_sgid == GID_LONG ?
808 	    curfile.dip->di_gid : (gid_t)curfile.dip->di_sgid;
809 
810 	resolve(name, &dfd, &rname);
811 	if (dfd != AT_FDCWD) {
812 		if (fchdir(dfd) < 0) {
813 			saverr = errno;
814 			(void) fprintf(stderr, gettext(
815 			    "%s: unable to set attribute context: %s\n"),
816 			    rname, strerror(saverr));
817 			skipfile();
818 			(void) close(dfd);
819 			return (FAIL);
820 		}
821 	}
822 
823 	switch (mode & IFMT) {
824 
825 	default:
826 		(void) fprintf(stderr, gettext("%s: unknown file mode 0%lo\n"),
827 		    rname, (ulong_t)(mode&IFMT));
828 		skipfile();
829 		result = FAIL;
830 		break;
831 
832 	case IFSOCK:
833 		vprintf(stdout, gettext("skipped socket %s\n"), rname);
834 		skipfile();
835 		result = GOOD;
836 		break;
837 
838 	case IFDIR:
839 		if (mflag) {
840 			ep = lookupname(name);
841 			if (ep == NIL || ep->e_flags & EXTRACT) {
842 				panic(gettext(
843 				    "directory %s was not restored\n"),
844 				    rname);
845 				skipfile();
846 				result = FAIL;
847 				break;
848 			}
849 			skipfile();
850 			result = GOOD;
851 			break;
852 		}
853 		vprintf(stdout, gettext("extract file %s\n"), rname);
854 		result = genliteraldir(rname, curfile.ino);
855 		break;
856 
857 	case IFLNK:
858 		lnkbuf[0] = '\0';
859 		pathlen = 0;
860 		getfile(xtrlnkfile, xtrlnkskip);
861 		if (pathlen == 0) {
862 			vprintf(stdout, gettext(
863 			    "%s: zero length symbolic link (ignored)\n"),
864 			    rname);
865 			result = GOOD;
866 			break;
867 		}
868 		if ((result = lf_linkit(lnkbuf, rname, SYMLINK)) != GOOD)
869 			break;
870 
871 		/* 1254700: set uid/gid (previously missing)  */
872 		if (lchown(rname, uid, gid) < 0 && !complained_lchown) {
873 			/* Just a warning */
874 			saverr = errno;
875 			errmsg = gettext(
876 			    "Unable to restore ownership of symlink %s: %s\n");
877 			(void) fprintf(stderr, errmsg,
878 			    rname, strerror(saverr));
879 			(void) fprintf(stderr, gettext(
880 			    "Additional such failures will be ignored.\n"));
881 			complained_lchown = 1;
882 		}
883 		metaset(rname);
884 		result = GOOD;
885 		break;
886 
887 	case IFCHR:
888 	case IFBLK:
889 	case IFIFO:
890 		vprintf(stdout, gettext("extract special file %s\n"), rname);
891 		/* put device rdev into dev_t expanded format */
892 		/* XXX does this always do the right thing? */
893 		/* XXX does dump do the right thing? */
894 		if (((curfile.dip->di_ordev & 0xFFFF0000) == 0) ||
895 		    ((curfile.dip->di_ordev & 0xFFFF0000) == 0xFFFF0000)) {
896 			full_dev = expdev((unsigned)(curfile.dip->di_ordev));
897 		} else {
898 			/* LINTED sign extension ok */
899 			full_dev = (unsigned)(curfile.dip->di_ordev);
900 		}
901 
902 		if (mknod(rname, mode, full_dev) < 0) {
903 			struct stat64 s[1];
904 
905 			saverr = errno;
906 			if ((stat64(rname, s)) ||
907 			    ((s->st_mode & S_IFMT) != (mode & S_IFMT)) ||
908 			    (s->st_rdev != full_dev)) {
909 				if (saverr != EPERM || !complained_mknod) {
910 					(void) fprintf(stderr, "%s: ", rname);
911 					(void) fflush(stderr);
912 					errno = saverr;
913 					perror(gettext(
914 					    "cannot create special file"));
915 					if (saverr == EPERM) {
916 						(void) fprintf(stderr, gettext(
917 			    "Additional such failures will be ignored.\n"));
918 						complained_mknod = 1;
919 					}
920 				}
921 				skipfile();
922 				result = FAIL;
923 				break;
924 			}
925 		}
926 		if (chown(rname, uid, gid) < 0 && !complained_chown) {
927 			/* Just a warning */
928 			saverr = errno;
929 			errmsg = gettext(
930 			    "Unable to restore ownership of %s: %s\n");
931 			(void) fprintf(stderr, errmsg,
932 			    rname, strerror(saverr));
933 			(void) fprintf(stderr, gettext(
934 			    "Additional such failures will be ignored.\n"));
935 			complained_chown = 1;
936 		}
937 		if (chmod(rname, mode) < 0 && !complained_chmod) {
938 			saverr = errno;
939 			errmsg = gettext(
940 			    "Unable to restore permissions on %s: %s\n");
941 			(void) fprintf(stderr, errmsg,
942 			    rname, strerror(saverr));
943 			(void) fprintf(stderr, gettext(
944 			    "Additional such failures will be ignored.\n"));
945 			complained_chmod = 1;
946 		}
947 		skipfile();
948 		metaset(rname); /* skipfile() got the metadata, if any */
949 		if (utime(rname, (struct utimbuf *)timep) < 0 &&
950 		    !complained_utime) {
951 			saverr = errno;
952 			errmsg = gettext(
953 			    "Unable to restore times on %s: %s\n");
954 			(void) fprintf(stderr, errmsg,
955 			    rname, strerror(saverr));
956 			(void) fprintf(stderr, gettext(
957 			    "Additional such failures will be ignored.\n"));
958 			complained_utime = 1;
959 		}
960 		result = GOOD;
961 		break;
962 
963 	case IFREG:
964 		vprintf(stdout, gettext("extract file %s\n"), rname);
965 		ofile = creat64(rname, 0666);
966 
967 		if (ofile < 0) {
968 			saverr = errno;
969 			errmsg = gettext("cannot create file");
970 			(void) fprintf(stderr, "%s: ", rname);
971 			(void) fflush(stderr);
972 			errno = saverr;
973 			perror(errmsg);
974 			skipfile();
975 			result = FAIL;
976 			break;
977 		}
978 		if (fchown(ofile, uid, gid) < 0 && !complained_chown) {
979 			/* Just a warning */
980 			saverr = errno;
981 			errmsg = gettext(
982 			    "Unable to restore ownership of %s: %s\n");
983 			(void) fprintf(stderr, errmsg,
984 			    rname, strerror(saverr));
985 			(void) fprintf(stderr, gettext(
986 			    "Additional such failures will be ignored.\n"));
987 			complained_chown = 1;
988 		}
989 		if (fchmod(ofile, mode) < 0 && !complained_chmod) {
990 			saverr = errno;
991 			errmsg = gettext(
992 			    "Unable to restore permissions on %s: %s\n");
993 			(void) fprintf(stderr, errmsg,
994 			    rname, strerror(saverr));
995 			(void) fprintf(stderr, gettext(
996 			    "Additional such failures will be ignored.\n"));
997 			complained_chmod = 1;
998 		}
999 		getfile(xtrfile, xtrskip);
1000 		metaset(rname);	/* we don't have metadata until after */
1001 				/* getfile() - maybe fchmod(0) then */
1002 				/* fchmod(real) after this? */
1003 
1004 		/*
1005 		 * Some errors don't get reported until we close(2), so
1006 		 * check for them.
1007 		 * XXX unlink the file if an error is reported?
1008 		 */
1009 		if (close(ofile) < 0) {
1010 			saverr = errno;
1011 			errmsg = gettext("error closing file");
1012 			(void) fprintf(stderr, "%s: ", rname);
1013 			(void) fflush(stderr);
1014 			errno = saverr;
1015 			perror(errmsg);
1016 			result = FAIL;
1017 			break;
1018 		}
1019 		if (utime(rname, (struct utimbuf *)timep) < 0 &&
1020 		    !complained_utime) {
1021 			saverr = errno;
1022 			errmsg = gettext(
1023 			    "Unable to restore times on %s: %s\n");
1024 			(void) fprintf(stderr, errmsg,
1025 			    rname, strerror(saverr));
1026 			(void) fprintf(stderr, gettext(
1027 			    "Additional such failures will be ignored.\n"));
1028 			complained_utime = 1;
1029 		}
1030 
1031 		result = GOOD;
1032 		break;
1033 	}
1034 	if (dfd != AT_FDCWD) {
1035 		fchdir(savepwd);
1036 		(void) close(dfd);
1037 	}
1038 	return (result);
1039 }
1040 
1041 /*
1042  * skip over bit maps on the tape
1043  */
1044 void
1045 #ifdef __STDC__
1046 skipmaps(void)
1047 #else
1048 skipmaps()
1049 #endif
1050 {
1051 	continuemap = 1;
1052 	while (checktype(&spcl, TS_CLRI) == GOOD ||
1053 	    checktype(&spcl, TS_BITS) == GOOD)
1054 		skipfile();
1055 	continuemap = 0;
1056 }
1057 
1058 /*
1059  * skip over a file on the tape
1060  */
1061 void
1062 #ifdef __STDC__
1063 skipfile(void)
1064 #else
1065 skipfile()
1066 #endif
1067 {
1068 	curfile.action = SKIP;
1069 	getfile(null, null);
1070 }
1071 /*
1072  * Do the file extraction, calling the supplied functions
1073  * with the blocks
1074  */
1075 void
1076 getfile(void (*f1)(), void (*f2)())
1077 {
1078 	int i;
1079 	size_t curblk = 0;
1080 	offset_t size = (offset_t)spcl.c_dinode.di_size;
1081 	static char clearedbuf[MAXBSIZE];
1082 	char buf[TP_BSIZE_MAX];
1083 	char *bufptr;
1084 	char junk[TP_BSIZE_MAX];
1085 
1086 	assert(MAXBSIZE >= tp_bsize);
1087 
1088 	metaset(NULL);	/* flush old metadata */
1089 	if (checktype(&spcl, TS_END) == GOOD) {
1090 		panic(gettext("ran off end of volume\n"));
1091 		return;
1092 	}
1093 	if (ishead(&spcl) == FAIL) {
1094 		panic(gettext("not at beginning of a file\n"));
1095 		return;
1096 	}
1097 	metacheck(&spcl); /* check for metadata in header */
1098 	if (!gettingfile && setjmp(restart) != 0) {
1099 		gettingfile = 0;	/* paranoia; longjmp'er should do */
1100 		return;
1101 	}
1102 	gettingfile++;
1103 loop:
1104 	if ((spcl.c_dinode.di_mode & IFMT) == IFSHAD) {
1105 		f1 = xtrmeta;
1106 		f2 = metaskip;
1107 	}
1108 	for (i = 0, bufptr = buf; i < spcl.c_count; i++) {
1109 		if ((i >= TP_NINDIR) || (spcl.c_addr[i])) {
1110 			readtape(bufptr);
1111 			bufptr += tp_bsize;
1112 			curblk++;
1113 			if (curblk == (fssize / tp_bsize)) {
1114 				(*f1)(buf, size > tp_bsize ?
1115 				    (size_t)(fssize) :
1116 					/* LINTED size <= tp_bsize */
1117 				    (curblk - 1) * tp_bsize + (size_t)size);
1118 				curblk = 0;
1119 				bufptr = buf;
1120 			}
1121 		} else {
1122 			if (curblk > 0) {
1123 				(*f1)(buf, size > tp_bsize ?
1124 				    (size_t)(curblk * tp_bsize) :
1125 					/* LINTED size <= tp_bsize */
1126 				    (curblk - 1) * tp_bsize + (size_t)size);
1127 				curblk = 0;
1128 				bufptr = buf;
1129 			}
1130 			(*f2)(clearedbuf, size > tp_bsize ?
1131 					/* LINTED size <= tp_bsize */
1132 			    (long)tp_bsize : (size_t)size);
1133 		}
1134 		if ((size -= tp_bsize) <= 0) {
1135 			for (i++; i < spcl.c_count; i++)
1136 				if ((i >= TP_NINDIR) || (spcl.c_addr[i]))
1137 					readtape(junk);
1138 			break;
1139 		}
1140 	}
1141 	if (curblk > 0) {
1142 		/*
1143 		 * Ok to cast size to size_t here. The above for loop reads
1144 		 * data into the buffer then writes it to the output file. The
1145 		 * call to f1 here is to write out the data that's in the
1146 		 * buffer that has not yet been written to the file.
1147 		 * This will be less than N-KB of data, since the
1148 		 * above loop writes to the file in filesystem-
1149 		 * blocksize chunks.
1150 		 */
1151 		/* LINTED: size fits into a size_t at this point */
1152 		(*f1)(buf, (curblk * tp_bsize) + (size_t)size);
1153 
1154 		curblk = 0;
1155 		bufptr = buf;
1156 	}
1157 	if ((readhdr(&spcl) == GOOD) && (checktype(&spcl, TS_ADDR) == GOOD)) {
1158 		if (continuemap)
1159 			size = (offset_t)spcl.c_count * tp_bsize;
1160 							/* big bitmap */
1161 		else if ((size <= 0) &&
1162 		    ((spcl.c_dinode.di_mode & IFMT) == IFSHAD)) {
1163 			/* LINTED unsigned to signed conversion ok */
1164 			size = spcl.c_dinode.di_size;
1165 		}
1166 		if (size > 0)
1167 			goto loop;
1168 	}
1169 	if (size > 0)
1170 		dprintf(stdout,
1171 		    gettext("Missing address (header) block for %s\n"),
1172 		    curfile.name);
1173 	findinode(&spcl);
1174 	gettingfile = 0;
1175 }
1176 
1177 /*
1178  * The next routines are called during file extraction to
1179  * put the data into the right form and place.
1180  */
1181 static void
1182 xtrfile(char *buf, size_t size)
1183 {
1184 	if (write(ofile, buf, (size_t)size) == -1) {
1185 		int saverr = errno;
1186 		(void) fprintf(stderr,
1187 		    gettext("write error extracting inode %d, name %s\n"),
1188 		    curfile.ino, curfile.name);
1189 		errno = saverr;
1190 		perror("write");
1191 		done(1);
1192 	}
1193 }
1194 
1195 /*
1196  * Even though size is a size_t, it's seeking to a relative
1197  * offset.  Thus, the seek could go beyond 2 GB, so lseek64 is needed.
1198  */
1199 
1200 /*ARGSUSED*/
1201 static void
1202 xtrskip(char *buf, size_t size)
1203 {
1204 	if (lseek64(ofile, (offset_t)size, 1) == -1) {
1205 		int saverr = errno;
1206 		(void) fprintf(stderr,
1207 		    gettext("seek error extracting inode %d, name %s\n"),
1208 		    curfile.ino, curfile.name);
1209 		errno = saverr;
1210 		perror("lseek64");
1211 		done(1);
1212 	}
1213 }
1214 
1215 /* these are local to the next five functions */
1216 static char *metadata = NULL;
1217 static size_t metasize = 0;
1218 
1219 static void
1220 metacheck(struct s_spcl *head)
1221 {
1222 	if (! (head->c_flags & DR_HASMETA))
1223 		return;
1224 	if ((metadata = malloc(metasize = (size_t)sizeof (head->c_shadow)))
1225 	    == NULL) {
1226 		(void) fprintf(stderr,
1227 		    gettext("Cannot malloc for metadata\n"));
1228 		done(1);
1229 	}
1230 	bcopy(&(head->c_shadow), metadata, metasize);
1231 }
1232 
1233 static void
1234 xtrmeta(char *buf, size_t size)
1235 {
1236 	if ((metadata == NULL) && ((spcl.c_dinode.di_mode & IFMT) != IFSHAD))
1237 		return;
1238 	if ((metadata = realloc(metadata, metasize + size)) == NULL) {
1239 		(void) fprintf(stderr,
1240 		    gettext("Cannot malloc for metadata\n"));
1241 		done(1);
1242 	}
1243 	bcopy(buf, metadata + metasize, size);
1244 	metasize += size;
1245 }
1246 
1247 /* ARGSUSED */
1248 static void
1249 metaskip(char *buf, size_t size)
1250 {
1251 	if (metadata == NULL)
1252 		return;
1253 	if ((metadata = realloc(metadata, metasize + size)) == NULL) {
1254 		(void) fprintf(stderr,
1255 		    gettext("Cannot malloc for metadata\n"));
1256 		done(1);
1257 	}
1258 	bzero(metadata + metasize, size);
1259 	metasize += size;
1260 }
1261 
1262 static void
1263 metaset(char *name)
1264 {
1265 	if (metadata == NULL)
1266 		return;
1267 	if (name != NULL)
1268 		metaproc(name, metadata, metasize);
1269 	(void) free(metadata);
1270 	metadata = NULL;
1271 	metasize = 0;
1272 }
1273 
1274 void
1275 metaget(data, size)
1276 	char **data;
1277 	size_t *size;
1278 {
1279 	*data = metadata;
1280 	*size = metasize;
1281 }
1282 
1283 static void
1284 fsd_acl(name, aclp, size)
1285 	char *name, *aclp;
1286 	unsigned size;
1287 {
1288 	static aclent_t *aclent = NULL;
1289 	ufs_acl_t *diskacl;
1290 	static int n = 0;
1291 	acl_t *set_aclp;
1292 	uint_t i;
1293 	int saverr, j;
1294 
1295 	if (aclp == NULL) {
1296 		if (aclent != NULL)
1297 			free(aclent);
1298 		aclent = NULL;
1299 		n = 0;
1300 		return;
1301 	}
1302 
1303 	/*LINTED [aclp is malloc'd]*/
1304 	diskacl = (ufs_acl_t *)aclp;
1305 	/* LINTED: result fits in an int */
1306 	j = size / sizeof (*diskacl);
1307 	normacls(byteorder, diskacl, j);
1308 
1309 	i = n;
1310 	n += j;
1311 	aclent = realloc(aclent, n * (size_t)sizeof (*aclent));
1312 	if (aclent == NULL) {
1313 		(void) fprintf(stderr, gettext("Cannot malloc acl list\n"));
1314 		done(1);
1315 	}
1316 
1317 	j = 0;
1318 	while (i < n) {
1319 		aclent[i].a_type = diskacl[j].acl_tag;
1320 		aclent[i].a_id = diskacl[j].acl_who;
1321 		aclent[i].a_perm = diskacl[j].acl_perm;
1322 		++i;
1323 		++j;
1324 	}
1325 
1326 	set_aclp = acl_to_aclp(ACLENT_T, aclent, n);
1327 	if (set_aclp == NULL) {
1328 		(void) fprintf(stderr, gettext("Cannot build acl_t\n"));
1329 		done(1);
1330 	}
1331 
1332 	if (acl_set(name, set_aclp) == -1) {
1333 		static int once = 0;
1334 
1335 		/*
1336 		 * Treat some errors from the acl subsystem specially to
1337 		 * avoid being too noisy:
1338 		 *
1339 		 * ENOSYS - ACLs not supported on this file system
1340 		 * EPERM  - not the owner or not privileged
1341 		 *
1342 		 * The following is also supported for backwards compat.
1343 		 * since acl(2) used to return the wrong errno:
1344 		 *
1345 		 * EINVAL - not the owner of the object
1346 		 */
1347 		if (errno == ENOSYS || errno == EPERM || errno == EINVAL) {
1348 			if (once == 0) {
1349 				saverr = errno;
1350 				++once;
1351 				fprintf(stderr,
1352 				    gettext("setacl failed: %s\n"),
1353 				    strerror(saverr));
1354 			}
1355 		} else {
1356 			saverr = errno;
1357 			fprintf(stderr, gettext("setacl on %s failed: %s\n"),
1358 			    name, strerror(saverr));
1359 		}
1360 	}
1361 	acl_free(set_aclp);
1362 }
1363 
1364 static struct fsdtypes {
1365 	int type;
1366 	void (*function)();
1367 } fsdtypes[] = {
1368 	{FSD_ACL, fsd_acl},
1369 	{FSD_DFACL, fsd_acl},
1370 	{0, NULL}
1371 };
1372 
1373 void
1374 metaproc(char *name, char *mdata, size_t msize)
1375 {
1376 	struct fsdtypes *fsdtype;
1377 	ufs_fsd_t *fsd;
1378 	char *c;
1379 
1380 	/*
1381 	 * for the whole shadow inode, dispatch each piece
1382 	 * to the appropriate function.
1383 	 */
1384 	c = mdata;
1385 	/* LINTED (c - mdata) fits into a size_t */
1386 	while ((size_t)(c - mdata) < msize) {
1387 		/*LINTED [mdata is malloc'd]*/
1388 		fsd = (ufs_fsd_t *)c;
1389 		assert((fsd->fsd_size % 4) == 0);
1390 		/* LINTED: lint thinks pointers are signed */
1391 		c += FSD_RECSZ(fsd, fsd->fsd_size);
1392 		if ((fsd->fsd_type == FSD_FREE) ||
1393 		    ((unsigned)(fsd->fsd_size) <= sizeof (ufs_fsd_t)) ||
1394 		    (c > (mdata + msize)))
1395 			break;
1396 		for (fsdtype = fsdtypes; fsdtype->type; fsdtype++)
1397 			if (fsdtype->type == fsd->fsd_type)
1398 				(*fsdtype->function)(name, fsd->fsd_data,
1399 				    (unsigned)(fsd->fsd_size) -
1400 				    sizeof (fsd->fsd_type) -
1401 				    sizeof (fsd->fsd_size));
1402 		/* ^^^ be sure to change if fsd ever changes ^^^ */
1403 	}
1404 
1405 	/* reset the state of all the functions */
1406 	for (fsdtype = fsdtypes; fsdtype->type; fsdtype++)
1407 		(*fsdtype->function)(NULL, NULL, 0);
1408 }
1409 
1410 static void
1411 xtrlnkfile(char *buf, size_t size)
1412 {
1413 	/* LINTED: signed/unsigned mix ok */
1414 	pathlen += size;
1415 	if (pathlen > MAXPATHLEN) {
1416 		(void) fprintf(stderr,
1417 		    gettext("symbolic link name: %s->%s%s; too long %d\n"),
1418 		    curfile.name, lnkbuf, buf, pathlen);
1419 		done(1);
1420 	}
1421 	buf[size] = '\0';
1422 	(void) strcat(lnkbuf, buf);
1423 	/* add an extra NULL to make this a legal complex string */
1424 	lnkbuf[pathlen+1] = '\0';
1425 }
1426 
1427 /*ARGSUSED*/
1428 static void
1429 xtrlnkskip(char *buf, size_t size)
1430 {
1431 	(void) fprintf(stderr,
1432 	    gettext("unallocated block in symbolic link %s\n"),
1433 	    curfile.name);
1434 	done(1);
1435 }
1436 
1437 static void
1438 xtrmap(char *buf, size_t size)
1439 {
1440 	if ((map+size) > endmap) {
1441 		int64_t mapsize, increment;
1442 		int64_t diff;
1443 
1444 		if (spcl.c_type != TS_ADDR) {
1445 			(void) fprintf(stderr,
1446 			    gettext("xtrmap: current record not TS_ADDR\n"));
1447 			done(1);
1448 		}
1449 		if ((spcl.c_count < 0) || (spcl.c_count > TP_NINDIR)) {
1450 			(void) fprintf(stderr,
1451 			    gettext("xtrmap: illegal c_count field (%d)\n"),
1452 			    spcl.c_count);
1453 			done(1);
1454 		}
1455 
1456 		increment = d_howmany(
1457 		    ((spcl.c_count * tp_bsize * NBBY) + 1), NBBY);
1458 		mapsize = endmap - beginmap + increment;
1459 		if (mapsize > UINT_MAX) {
1460 			(void) fprintf(stderr,
1461 			    gettext("xtrmap: maximum bitmap size exceeded"));
1462 			done(1);
1463 		}
1464 
1465 		diff = map - beginmap;
1466 		/* LINTED mapsize checked above */
1467 		beginmap = realloc(beginmap, (size_t)mapsize);
1468 		if (beginmap == NULL) {
1469 			(void) fprintf(stderr,
1470 			    gettext("xtrmap: realloc failed\n"));
1471 			done(1);
1472 		}
1473 		map = beginmap + diff;
1474 		endmap = beginmap + mapsize;
1475 		/* LINTED endmap - map cannot exceed 32 bits */
1476 		bzero(map, (size_t)(endmap - map));
1477 		maxino = NBBY * mapsize + 1;
1478 	}
1479 
1480 	bcopy(buf, map, size);
1481 	/* LINTED character pointers aren't signed */
1482 	map += size;
1483 }
1484 
1485 /*ARGSUSED*/
1486 static void
1487 xtrmapskip(char *buf, size_t size)
1488 {
1489 	(void) fprintf(stderr, gettext("hole in map\n"));
1490 	done(1);
1491 }
1492 
1493 /*ARGSUSED*/
1494 void
1495 null(char *buf, size_t size)
1496 {
1497 }
1498 
1499 /*
1500  * Do the tape i/o, dealing with volume changes
1501  * etc..
1502  */
1503 static void
1504 readtape(char *b)
1505 {
1506 	int i;
1507 	int rd, newvol;
1508 	int cnt;
1509 	struct s_spcl *sp;
1510 	int32_t	expected_magic;
1511 
1512 	if (tbf == NULL) {
1513 		(void) fprintf(stderr, gettext(
1514 		    "Internal consistency failure in readtape: tbf is NULL\n"));
1515 		done(1);
1516 	}
1517 	expected_magic = ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC);
1518 
1519 top:
1520 	if (bct < numtrec) {
1521 		/*
1522 		 * check for old-dump floppy EOM -- it may appear in
1523 		 * the middle of a buffer.  The Dflag used to be used for
1524 		 * this, but since it doesn't hurt to always do this we
1525 		 * got rid of the Dflag.
1526 		 */
1527 		/*LINTED [tbf = malloc()]*/
1528 		sp = &((union u_spcl *)&tbf[bct*tp_bsize])->s_spcl;
1529 		if (sp->c_magic == expected_magic && sp->c_type == TS_EOM &&
1530 		    (time_t)(sp->c_date) == dumpdate &&
1531 		    (time_t)(sp->c_ddate) == dumptime) {
1532 			for (i = 0; i < ntrec; i++)
1533 				/*LINTED [tbf = malloc()]*/
1534 				((struct s_spcl *)
1535 				    &tbf[i*tp_bsize])->c_magic = 0;
1536 			bct = 0;
1537 			rd = 0;
1538 			i = 0;
1539 			goto nextvol;
1540 		}
1541 		bcopy(&tbf[(bct++*tp_bsize)], b, (size_t)tp_bsize);
1542 		blksread++;
1543 		tapea++;
1544 		return;
1545 	}
1546 	/*LINTED [assertion always true]*/
1547 	assert(sizeof (union u_spcl) == TP_BSIZE_MAX);
1548 	for (i = 0; i < ntrec; i++)
1549 		/*LINTED [tbf = malloc()]*/
1550 		((struct s_spcl *)&tbf[i*sizeof (struct s_spcl)])->c_magic = 0;
1551 	if (numtrec == 0) {
1552 		/* LINTED unsigned/signed assignment ok */
1553 		numtrec = ntrec;
1554 	}
1555 	/* LINTED unsigned/signed assignment ok */
1556 	cnt = ntrec*tp_bsize;
1557 	rd = 0;
1558 getmore:
1559 	if (host)
1560 		i = rmtread(&tbf[rd], cnt);
1561 	else
1562 		i = read(mt, &tbf[rd], cnt);
1563 	/*
1564 	 * Check for mid-tape short read error.
1565 	 * If found, return rest of buffer.
1566 	 */
1567 	if (numtrec < ntrec && i != 0) {
1568 		/* LINTED unsigned/signed assignment ok */
1569 		numtrec = ntrec;
1570 		goto top;
1571 	}
1572 	/*
1573 	 * Handle partial block read.
1574 	 */
1575 	if (i > 0 && i != ntrec*tp_bsize) {
1576 		if (pipein) {
1577 			rd += i;
1578 			cnt -= i;
1579 			if (cnt > 0)
1580 				goto getmore;
1581 			i = rd;
1582 		} else {
1583 			if (i % tp_bsize != 0)
1584 				panic(gettext(
1585 				    "partial block read: %d should be %d\n"),
1586 				    i, ntrec * tp_bsize);
1587 			numtrec = i / tp_bsize;
1588 			if (numtrec == 0)
1589 				/*
1590 				 * it's possible to read only 512 bytes
1591 				 * from a QIC device...
1592 				 */
1593 				i = 0;
1594 		}
1595 	}
1596 	/*
1597 	 * Handle read error.
1598 	 */
1599 	if (i < 0) {
1600 		switch (curfile.action) {
1601 		default:
1602 			(void) fprintf(stderr, gettext(
1603 			    "Read error while trying to set up volume\n"));
1604 			break;
1605 		case UNKNOWN:
1606 			(void) fprintf(stderr, gettext(
1607 			    "Read error while trying to resynchronize\n"));
1608 			break;
1609 		case USING:
1610 			(void) fprintf(stderr, gettext(
1611 			    "Read error while restoring %s\n"),
1612 			    curfile.name);
1613 			break;
1614 		case SKIP:
1615 			(void) fprintf(stderr, gettext(
1616 			    "Read error while skipping over inode %d\n"),
1617 			    curfile.ino);
1618 			break;
1619 		}
1620 		if (!yflag && !reply(gettext("continue")))
1621 			done(1);
1622 		/* LINTED: unsigned->signed conversion ok */
1623 		i = (int)(ntrec*tp_bsize);
1624 		bzero(tbf, (size_t)i);
1625 		if ((host != 0 && rmtseek(i, 1) < 0) ||
1626 		    (host == 0 && (lseek64(mt, (offset_t)i, 1) ==
1627 		    (off64_t)-1))) {
1628 			perror(gettext("continuation failed"));
1629 			done(1);
1630 		}
1631 	}
1632 	/*
1633 	 * Handle end of tape.  The Dflag used to be used, but since it doesn't
1634 	 * hurt to always check we got rid if it.
1635 	 */
1636 
1637 	/*
1638 	 * if the first record in the buffer just read is EOM,
1639 	 * change volumes.
1640 	 */
1641 	/*LINTED [tbf = malloc()]*/
1642 	sp = &((union u_spcl *)tbf)->s_spcl;
1643 	if (i != 0 && sp->c_magic == expected_magic && sp->c_type == TS_EOM &&
1644 	    (time_t)(sp->c_date) == dumpdate &&
1645 	    (time_t)(sp->c_ddate) == dumptime) {
1646 		i = 0;
1647 	}
1648 nextvol:
1649 	if (i == 0) {
1650 		if (!pipein) {
1651 			newvol = volno + 1;
1652 			volno = 0;
1653 			numtrec = 0;
1654 			getvol(newvol);
1655 			readtape(b); /* XXX tail recursion, not goto top? */
1656 			return;
1657 		}
1658 		/* XXX if panic returns, should we round rd up? */
1659 		/* XXX if we do, then we should zero the intervening space */
1660 		if (rd % tp_bsize != 0)
1661 			panic(gettext("partial block read: %d should be %d\n"),
1662 			    rd, ntrec * tp_bsize);
1663 		bcopy((char *)&endoftapemark, &tbf[rd], (size_t)tp_bsize);
1664 	}
1665 	bct = 0;
1666 	bcopy(&tbf[(bct++*tp_bsize)], b, (size_t)tp_bsize);
1667 	blksread++;
1668 	recsread++;
1669 	tapea++;
1670 	rec_position++;
1671 }
1672 
1673 void
1674 #ifdef __STDC__
1675 findtapeblksize(int arfile)
1676 #else
1677 findtapeblksize(int arfile)
1678 #endif
1679 {
1680 	int	i;
1681 
1682 	if (tbf == NULL) {
1683 		(void) fprintf(stderr, gettext(
1684 		    "Internal consistency failure in findtapeblksize: "
1685 		    "tbf is NULL\n"));
1686 		assert(tbf != NULL);
1687 		done(1);
1688 	}
1689 
1690 	for (i = 0; i < ntrec; i++)
1691 		/*LINTED [tbf = malloc()]*/
1692 		((struct s_spcl *)&tbf[i * tp_bsize])->c_magic = 0;
1693 	bct = 0;
1694 	if (host && arfile == TAPE_FILE)
1695 		tape_rec_size = rmtread(tbf, ntrec * tp_bsize);
1696 	else
1697 		tape_rec_size = read(mt, tbf, ntrec * tp_bsize);
1698 	recsread++;
1699 	rec_position++;
1700 	if (tape_rec_size == (ssize_t)-1) {
1701 		int saverr = errno;
1702 		char *errmsg = gettext("Media read error");
1703 		errno = saverr;
1704 		perror(errmsg);
1705 		done(1);
1706 	}
1707 	if (tape_rec_size % tp_bsize != 0) {
1708 		(void) fprintf(stderr, gettext(
1709 	    "Record size (%d) is not a multiple of dump block size (%d)\n"),
1710 		    tape_rec_size, tp_bsize);
1711 		done(1);
1712 	}
1713 	ntrec = (int)tape_rec_size / tp_bsize;
1714 	/* LINTED unsigned/signed assignment ok */
1715 	numtrec = ntrec;
1716 	vprintf(stdout, gettext("Media block size is %d\n"), ntrec*2);
1717 }
1718 
1719 void
1720 #ifdef __STDC__
1721 flsht(void)
1722 #else
1723 flsht()
1724 #endif
1725 {
1726 	/* LINTED unsigned/signed assignment ok */
1727 	bct = ntrec+1;
1728 }
1729 
1730 void
1731 #ifdef __STDC__
1732 closemt(int mode)
1733 #else
1734 closemt(int mode)
1735 #endif
1736 {
1737 	/*
1738 	 * If mode == FORCE_OFFLINE then we're not done but
1739 	 * we need to change tape. So, rewind and unload current
1740 	 * tape before loading the new one.
1741 	 */
1742 
1743 	static struct mtop mtop = { MTOFFL, 0 };
1744 
1745 	if (mt < 0)
1746 		return;
1747 	if (offline || mode == FORCE_OFFLINE)
1748 		(void) fprintf(stderr, gettext("Rewinding tape\n"));
1749 	if (host) {
1750 		if (offline || mode == FORCE_OFFLINE)
1751 			(void) rmtioctl(MTOFFL, 1);
1752 		rmtclose();
1753 	} else if (pipein) {
1754 		char buffy[MAXBSIZE];
1755 
1756 		while (read(mt, buffy, sizeof (buffy)) > 0) {
1757 			continue;
1758 			/*LINTED [assertion always true]*/
1759 		}
1760 		(void) close(mt);
1761 	} else {
1762 		/*
1763 		 * Only way to tell if this is a floppy is to issue an ioctl
1764 		 * but why waste one - if the eject fails, tough!
1765 		 */
1766 		if (offline || mode == FORCE_OFFLINE)
1767 			(void) ioctl(mt, MTIOCTOP, &mtop);
1768 		(void) ioctl(mt, FDEJECT, 0);
1769 		(void) close(mt);
1770 	}
1771 	mt = -1;
1772 }
1773 
1774 static int
1775 checkvol(struct s_spcl *b, int t)
1776 {
1777 
1778 	if (b->c_volume != t)
1779 		return (FAIL);
1780 	return (GOOD);
1781 }
1782 
1783 int
1784 readhdr(struct s_spcl *b)
1785 {
1786 
1787 	if (gethead(b) == FAIL) {
1788 		dprintf(stdout, gettext("readhdr fails at %ld blocks\n"),
1789 		    blksread);
1790 		return (FAIL);
1791 	}
1792 	return (GOOD);
1793 }
1794 
1795 /*
1796  * read the tape into buf, then return whether or
1797  * or not it is a header block.
1798  */
1799 int
1800 gethead(struct s_spcl *buf)
1801 {
1802 	int i;
1803 	union u_ospcl {
1804 		char dummy[TP_BSIZE_MIN];
1805 		struct	s_ospcl {
1806 			int32_t	c_type;
1807 			int32_t	c_date;
1808 			int32_t	c_ddate;
1809 			int32_t	c_volume;
1810 			int32_t	c_tapea;
1811 			ushort_t c_inumber;
1812 			int32_t	c_magic;
1813 			int32_t	c_checksum;
1814 			struct odinode {
1815 				unsigned short odi_mode;
1816 				ushort_t odi_nlink;
1817 				ushort_t odi_uid;
1818 				ushort_t odi_gid;
1819 				int32_t	odi_size;
1820 				int32_t	odi_rdev;
1821 				char	odi_addr[36];
1822 				int32_t	odi_atime;
1823 				int32_t	odi_mtime;
1824 				int32_t	odi_ctime;
1825 			} c_dinode;
1826 			int32_t	c_count;
1827 			char	c_baddr[256];
1828 		} s_ospcl;
1829 	} u_ospcl;
1830 
1831 	if (cvtflag) {
1832 		readtape((char *)(&u_ospcl.s_ospcl));
1833 		bzero((char *)buf, (size_t)TP_BSIZE_MIN);
1834 		buf->c_type = u_ospcl.s_ospcl.c_type;
1835 		buf->c_date = u_ospcl.s_ospcl.c_date;
1836 		buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1837 		buf->c_volume = u_ospcl.s_ospcl.c_volume;
1838 		buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1839 		buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1840 		buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1841 		buf->c_magic = u_ospcl.s_ospcl.c_magic;
1842 		buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1843 		/* LINTED: unsigned/signed combination ok */
1844 		buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1845 		buf->c_dinode.di_size =
1846 		    (unsigned)(u_ospcl.s_ospcl.c_dinode.odi_size);
1847 		buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1848 		buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1849 		buf->c_dinode.di_suid = UID_LONG;
1850 		buf->c_dinode.di_sgid = GID_LONG;
1851 		buf->c_dinode.di_ordev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1852 		buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
1853 		buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1854 		buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1855 		buf->c_count = u_ospcl.s_ospcl.c_count;
1856 		bcopy(u_ospcl.s_ospcl.c_baddr, buf->c_addr,
1857 		    sizeof (u_ospcl.s_ospcl.c_baddr));
1858 
1859 		/*CONSTANTCONDITION*/
1860 		assert(sizeof (u_ospcl.s_ospcl) < sizeof (union u_spcl));
1861 
1862 		/* we byte-swap the new spclrec, but checksum the old	*/
1863 		/* (see comments in normspcl())				*/
1864 		if (normspcl(byteorder, buf,
1865 		    (int *)(&u_ospcl.s_ospcl), sizeof (u_ospcl.s_ospcl),
1866 		    OFS_MAGIC))
1867 			return (FAIL);
1868 		buf->c_magic =
1869 		    ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC);
1870 	} else {
1871 		readtape((char *)buf);
1872 		if (normspcl(byteorder, buf, (int *)buf, tp_bsize,
1873 		    ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC)))
1874 			return (FAIL);
1875 	}
1876 
1877 	switch (buf->c_type) {
1878 
1879 	case TS_CLRI:
1880 	case TS_BITS:
1881 		/*
1882 		 * Have to patch up missing information in bit map headers
1883 		 */
1884 		buf->c_inumber = 0;
1885 		buf->c_dinode.di_size = (offset_t)buf->c_count * tp_bsize;
1886 		for (i = 0; i < buf->c_count && i < TP_NINDIR; i++)
1887 			buf->c_addr[i] = 1;
1888 		break;
1889 
1890 	case TS_TAPE:
1891 	case TS_END:
1892 		if (dumpinfo.c_date == 0) {
1893 			dumpinfo.c_date = spcl.c_date;
1894 			dumpinfo.c_ddate = spcl.c_ddate;
1895 		}
1896 		if (!hostinfo && spcl.c_host[0] != '\0') {
1897 			bcopy(spcl.c_label, dumpinfo.c_label,
1898 			    sizeof (spcl.c_label));
1899 			bcopy(spcl.c_filesys, dumpinfo.c_filesys,
1900 			    sizeof (spcl.c_filesys));
1901 			bcopy(spcl.c_dev, dumpinfo.c_dev,
1902 			    sizeof (spcl.c_dev));
1903 			bcopy(spcl.c_host, dumpinfo.c_host,
1904 			    sizeof (spcl.c_host));
1905 			dumpinfo.c_level = spcl.c_level;
1906 			hostinfo++;
1907 			if (c_label != NULL &&
1908 			    strncmp(c_label, spcl.c_label,
1909 			    sizeof (spcl.c_label))
1910 			    != 0) {
1911 				(void) fprintf(stderr, gettext(
1912 		    "Incorrect tape label.  Expected `%s', got `%.*s'\n"),
1913 				    c_label,
1914 				    sizeof (spcl.c_label), spcl.c_label);
1915 				done(1);
1916 			}
1917 		}
1918 		if (!inodeinfo && (spcl.c_flags & DR_INODEINFO)) {
1919 			dumpinfo.c_volume = spcl.c_volume;
1920 			bcopy(spcl.c_inos, dumpinfo.c_inos,
1921 			    sizeof (spcl.c_inos));
1922 			inodeinfo++;
1923 		}
1924 		buf->c_inumber = 0;
1925 		break;
1926 
1927 	case TS_INODE:
1928 	case TS_ADDR:
1929 		break;
1930 
1931 	default:
1932 		panic(gettext("%s: unknown inode type %d\n"),
1933 		    "gethead", buf->c_type);
1934 		return (FAIL);
1935 	}
1936 	if (dflag)
1937 		accthdr(buf);
1938 	return (GOOD);
1939 }
1940 
1941 /*
1942  * Check that a header is where it belongs and predict the next header
1943  */
1944 static void
1945 accthdr(struct s_spcl *header)
1946 {
1947 	static ino_t previno = (ino_t)(unsigned)-1;
1948 	static int prevtype;
1949 	static long predict;
1950 	int blks, i;
1951 
1952 	if (header->c_type == TS_TAPE) {
1953 		if (header->c_firstrec)
1954 			(void) fprintf(stderr,
1955 			    gettext("Volume header begins with record %d"),
1956 			    header->c_firstrec);
1957 		else
1958 			(void) fprintf(stderr, gettext("Volume header"));
1959 		(void) fprintf(stderr, "\n");
1960 		previno = (ino_t)(unsigned)-1;
1961 		return;
1962 	}
1963 	if (previno == (ino_t)(unsigned)-1)
1964 		goto newcalc;
1965 	switch (prevtype) {
1966 	case TS_BITS:
1967 		(void) fprintf(stderr, gettext("Dump mask header"));
1968 		break;
1969 	case TS_CLRI:
1970 		(void) fprintf(stderr, gettext("Remove mask header"));
1971 		break;
1972 	case TS_INODE:
1973 		(void) fprintf(stderr,
1974 		    gettext("File header, ino %d at record %d"),
1975 		    previno, rec_position);
1976 		break;
1977 	case TS_ADDR:
1978 		(void) fprintf(stderr,
1979 		    gettext("File continuation header, ino %d"),
1980 		    previno);
1981 		break;
1982 	case TS_END:
1983 		(void) fprintf(stderr, gettext("End of media header"));
1984 		break;
1985 	}
1986 	if (predict != blksread - 1)
1987 		(void) fprintf(stderr,
1988 		    gettext("; predicted %ld blocks, got %ld blocks"),
1989 		    predict, blksread - 1);
1990 	(void) fprintf(stderr, "\n");
1991 newcalc:
1992 	blks = 0;
1993 	if (header->c_type != TS_END)
1994 		for (i = 0; i < header->c_count; i++)
1995 			if ((i >= TP_NINDIR) || (header->c_addr[i] != 0))
1996 				blks++;
1997 	predict = blks;
1998 	blksread = 0;
1999 	prevtype = header->c_type;
2000 	previno = header->c_inumber;
2001 }
2002 
2003 /*
2004  * Try to determine which volume a file resides on.
2005  */
2006 int
2007 volnumber(ino_t inum)
2008 {
2009 	int i;
2010 
2011 	if (inodeinfo == 0)
2012 		return (0);
2013 	for (i = 1; i <= dumpinfo.c_volume; i++)
2014 		if (inum < (ino_t)(unsigned)(dumpinfo.c_inos[i]))
2015 			break;
2016 	return (i - 1);
2017 }
2018 
2019 /*
2020  * Find an inode header.
2021  * Note that *header must be stable storage, as curfile will end up with
2022  * pointers into it.
2023  */
2024 void
2025 findinode(struct s_spcl *header)
2026 {
2027 	long skipcnt = 0;
2028 	int i;
2029 	char buf[TP_BSIZE_MAX];
2030 
2031 	curfile.name = gettext("<name unknown>");
2032 	curfile.action = UNKNOWN;
2033 	curfile.dip = (struct dinode *)NULL;
2034 	curfile.ino = 0;
2035 	curfile.ts = 0;
2036 	if (ishead(header) == FAIL) {
2037 		skipcnt++;
2038 		while (gethead(header) == FAIL ||
2039 		    (time_t)(header->c_date) != dumpdate)
2040 			skipcnt++;
2041 	}
2042 	for (;;) {
2043 		if (checktype(header, TS_ADDR) == GOOD) {
2044 			/*
2045 			 * Skip up to the beginning of the next record
2046 			 */
2047 			for (i = 0; i < header->c_count; i++)
2048 				if ((i >= TP_NINDIR) || (header->c_addr[i]))
2049 					readtape(buf);
2050 			(void) gethead(header);
2051 			continue;
2052 		}
2053 		if (checktype(header, TS_INODE) == GOOD) {
2054 			curfile.dip = &header->c_dinode;
2055 			if (curfile.dip->di_suid != UID_LONG)
2056 				curfile.dip->di_uid = curfile.dip->di_suid;
2057 			if (curfile.dip->di_sgid != GID_LONG)
2058 				curfile.dip->di_gid = curfile.dip->di_sgid;
2059 			curfile.ino = header->c_inumber;
2060 			curfile.ts = TS_INODE;
2061 			break;
2062 		}
2063 		if (checktype(header, TS_END) == GOOD) {
2064 			curfile.ino = maxino;
2065 			curfile.ts = TS_END;
2066 			break;
2067 		}
2068 		if (checktype(header, TS_CLRI) == GOOD) {
2069 			curfile.name = gettext("<file removal list>");
2070 			curfile.ts = TS_CLRI;
2071 			break;
2072 		}
2073 		if (checktype(header, TS_BITS) == GOOD) {
2074 			curfile.name = gettext("<file dump list>");
2075 			curfile.ts = TS_BITS;
2076 			break;
2077 		}
2078 		while (gethead(header) == FAIL)
2079 			skipcnt++;
2080 	}
2081 	if (skipcnt > 0)
2082 		(void) fprintf(stderr,
2083 		    gettext("resync restore, skipped %d blocks\n"),
2084 		    skipcnt);
2085 }
2086 
2087 /*
2088  * return whether or not the buffer contains a header block
2089  */
2090 static int
2091 ishead(struct s_spcl *buf)
2092 {
2093 	if (buf->c_magic !=
2094 	    ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC))
2095 		return (FAIL);
2096 	return (GOOD);
2097 }
2098 
2099 static int
2100 checktype(struct s_spcl *b, int t)
2101 {
2102 	if (b->c_type != t)
2103 		return (FAIL);
2104 	return (GOOD);
2105 }
2106 
2107 /*
2108  * If autoloading is enabled, attempt to do it.  If we succeed,
2109  * return non-zero.
2110  */
2111 static int
2112 #ifdef __STDC__
2113 autoload_tape(void)
2114 #else
2115 autoload_tape()
2116 #endif
2117 {
2118 	int result = 0;		/* assume failure */
2119 	int tries;
2120 	int fd;
2121 
2122 	if (autoload) {
2123 		/*
2124 		 * Wait for the tape to autoload.  Note that the delay
2125 		 * period doesn't take into account however long it takes
2126 		 * for the open to fail (measured at 21 seconds for an
2127 		 * Exabyte 8200 under 2.7 on an Ultra 2).
2128 		 */
2129 
2130 		/* rewind tape and offline drive before loading new tape */
2131 		closemt(FORCE_OFFLINE);
2132 		(void) fprintf(stderr,
2133 		    gettext("Attempting to autoload next volume\n"));
2134 		for (tries = 0; tries < autoload_tries; tries++) {
2135 			if (host) {
2136 				if (rmtopen(magtape, O_RDONLY) >= 0) {
2137 					rmtclose();
2138 					result = 1;
2139 					break;
2140 				}
2141 			} else {
2142 				if ((fd = open(magtape, O_RDONLY|O_LARGEFILE,
2143 				    0600)) >= 0) {
2144 					(void) close(fd);
2145 					result = 1;
2146 					break;
2147 				}
2148 			}
2149 			(void) sleep(autoload_period);
2150 		}
2151 		if (result == 0) {
2152 			/* Assume caller will deal with manual change-over */
2153 			(void) fprintf(stderr,
2154 			    gettext("Autoload timed out\n"));
2155 		} else {
2156 			if ((host != NULL &&
2157 			    (mt = rmtopen(magtape, O_RDONLY)) == -1) ||
2158 			    (host == NULL &&
2159 			    (mt = open(magtape, O_RDONLY|O_LARGEFILE)) == -1)) {
2160 				(void) fprintf(stderr, gettext(
2161 				    "Autoload could not re-open tape\n"));
2162 				result = 0;
2163 			} else {
2164 				(void) fprintf(stderr, gettext(
2165 				    "Tape loaded\n"));
2166 			}
2167 		}
2168 	}
2169 
2170 	return (result);
2171 }
2172