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