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