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