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