xref: /freebsd/sbin/restore/tape.c (revision 2b743a9e9ddc6736208dc8ca1ce06ce64ad20a19)
1 /*
2  * Copyright (c) 1983, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)tape.c	8.9 (Berkeley) 5/1/95";
38 #endif
39 #endif /* not lint */
40 
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43 
44 #include <sys/param.h>
45 #include <sys/file.h>
46 #include <sys/mtio.h>
47 #include <sys/stat.h>
48 #include <sys/time.h>
49 #include <sys/extattr.h>
50 #include <sys/acl.h>
51 
52 #include <ufs/ufs/dinode.h>
53 #include <protocols/dumprestore.h>
54 
55 #include <errno.h>
56 #include <limits.h>
57 #include <paths.h>
58 #include <setjmp.h>
59 #include <stdint.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <time.h>
64 #include <timeconv.h>
65 #include <unistd.h>
66 
67 #include "restore.h"
68 #include "extern.h"
69 
70 static long	fssize = MAXBSIZE;
71 static int	mt = -1;
72 static int	pipein = 0;
73 static int	pipecmdin = 0;
74 static FILE	*popenfp = NULL;
75 static char	*magtape;
76 static int	blkcnt;
77 static int	numtrec;
78 static char	*tapebuf;
79 static union	u_spcl endoftapemark;
80 static long	byteslide = 0;
81 static long	blksread;		/* blocks read since last header */
82 static int64_t	tapeaddr = 0;		/* current TP_BSIZE tape record */
83 static long	tapesread;
84 static jmp_buf	restart;
85 static int	gettingfile = 0;	/* restart has a valid frame */
86 static char	*host = NULL;
87 static int	readmapflag;
88 
89 static int	ofile;
90 static char	*map;
91 static char	lnkbuf[MAXPATHLEN + 1];
92 static int	pathlen;
93 
94 int		Bcvt;		/* Swap Bytes */
95 int		oldinofmt;	/* FreeBSD 1 inode format needs cvt */
96 
97 #define	FLUSHTAPEBUF()	blkcnt = ntrec + 1
98 
99 char *namespace_names[] = EXTATTR_NAMESPACE_NAMES;
100 
101 static void	 accthdr(struct s_spcl *);
102 static int	 checksum(int *);
103 static void	 findinode(struct s_spcl *);
104 static void	 findtapeblksize(void);
105 static char	*setupextattr(int);
106 static void	 xtrattr(char *, long);
107 static void	 set_extattr_link(char *, void *, int);
108 static void	 set_extattr_fd(int, char *, void *, int);
109 static int	 gethead(struct s_spcl *);
110 static void	 readtape(char *);
111 static void	 setdumpnum(void);
112 static u_long	 swabl(u_long);
113 static u_char	*swablong(u_char *, int);
114 static u_char	*swabshort(u_char *, int);
115 static void	 terminateinput(void);
116 static void	 xtrfile(char *, long);
117 static void	 xtrlnkfile(char *, long);
118 static void	 xtrlnkskip(char *, long);
119 static void	 xtrmap(char *, long);
120 static void	 xtrmapskip(char *, long);
121 static void	 xtrskip(char *, long);
122 
123 /*
124  * Set up an input source
125  */
126 void
127 setinput(char *source, int ispipecommand)
128 {
129 	FLUSHTAPEBUF();
130 	if (bflag)
131 		newtapebuf(ntrec);
132 	else
133 		newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
134 	terminal = stdin;
135 
136 	if (ispipecommand)
137 		pipecmdin++;
138 	else
139 #ifdef RRESTORE
140 	if (strchr(source, ':')) {
141 		host = source;
142 		source = strchr(host, ':');
143 		*source++ = '\0';
144 		if (rmthost(host) == 0)
145 			done(1);
146 	} else
147 #endif
148 	if (strcmp(source, "-") == 0) {
149 		/*
150 		 * Since input is coming from a pipe we must establish
151 		 * our own connection to the terminal.
152 		 */
153 		terminal = fopen(_PATH_TTY, "r");
154 		if (terminal == NULL) {
155 			(void)fprintf(stderr, "cannot open %s: %s\n",
156 			    _PATH_TTY, strerror(errno));
157 			terminal = fopen(_PATH_DEVNULL, "r");
158 			if (terminal == NULL) {
159 				(void)fprintf(stderr, "cannot open %s: %s\n",
160 				    _PATH_DEVNULL, strerror(errno));
161 				done(1);
162 			}
163 		}
164 		pipein++;
165 	}
166 	setuid(getuid());	/* no longer need or want root privileges */
167 	magtape = strdup(source);
168 	if (magtape == NULL) {
169 		fprintf(stderr, "Cannot allocate space for magtape buffer\n");
170 		done(1);
171 	}
172 }
173 
174 void
175 newtapebuf(long size)
176 {
177 	static int tapebufsize = -1;
178 
179 	ntrec = size;
180 	if (size <= tapebufsize)
181 		return;
182 	if (tapebuf != NULL)
183 		free(tapebuf - TP_BSIZE);
184 	tapebuf = malloc((size+1) * TP_BSIZE);
185 	if (tapebuf == NULL) {
186 		fprintf(stderr, "Cannot allocate space for tape buffer\n");
187 		done(1);
188 	}
189 	tapebuf += TP_BSIZE;
190 	tapebufsize = size;
191 }
192 
193 /*
194  * Verify that the tape drive can be accessed and
195  * that it actually is a dump tape.
196  */
197 void
198 setup(void)
199 {
200 	int i, j, *ip;
201 	struct stat stbuf;
202 
203 	vprintf(stdout, "Verify tape and initialize maps\n");
204 	if (pipecmdin) {
205 		if (setenv("RESTORE_VOLUME", "1", 1) == -1) {
206 			fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n",
207 			    strerror(errno));
208 			done(1);
209 		}
210 		popenfp = popen(magtape, "r");
211 		mt = popenfp ? fileno(popenfp) : -1;
212 	} else
213 #ifdef RRESTORE
214 	if (host)
215 		mt = rmtopen(magtape, 0);
216 	else
217 #endif
218 	if (pipein)
219 		mt = 0;
220 	else
221 		mt = open(magtape, O_RDONLY, 0);
222 	if (mt < 0) {
223 		fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
224 		done(1);
225 	}
226 	volno = 1;
227 	setdumpnum();
228 	FLUSHTAPEBUF();
229 	if (!pipein && !bflag)
230 		findtapeblksize();
231 	if (gethead(&spcl) == FAIL) {
232 		fprintf(stderr, "Tape is not a dump tape\n");
233 		done(1);
234 	}
235 	if (pipein) {
236 		endoftapemark.s_spcl.c_magic = FS_UFS2_MAGIC;
237 		endoftapemark.s_spcl.c_type = TS_END;
238 		ip = (int *)&endoftapemark;
239 		j = sizeof(union u_spcl) / sizeof(int);
240 		i = 0;
241 		do
242 			i += *ip++;
243 		while (--j);
244 		endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
245 	}
246 	if (vflag || command == 't')
247 		printdumpinfo();
248 	dumptime = _time64_to_time(spcl.c_ddate);
249 	dumpdate = _time64_to_time(spcl.c_date);
250 	if (stat(".", &stbuf) < 0) {
251 		fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
252 		done(1);
253 	}
254 	if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE )
255 		fssize = TP_BSIZE;
256 	if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE)
257 		fssize = stbuf.st_blksize;
258 	if (((fssize - 1) & fssize) != 0) {
259 		fprintf(stderr, "bad block size %ld\n", fssize);
260 		done(1);
261 	}
262 	if (spcl.c_volume != 1) {
263 		fprintf(stderr, "Tape is not volume 1 of the dump\n");
264 		done(1);
265 	}
266 	if (gethead(&spcl) == FAIL) {
267 		dprintf(stdout, "header read failed at %ld blocks\n", blksread);
268 		panic("no header after volume mark!\n");
269 	}
270 	findinode(&spcl);
271 	if (spcl.c_type != TS_CLRI) {
272 		fprintf(stderr, "Cannot find file removal list\n");
273 		done(1);
274 	}
275 	maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
276 	dprintf(stdout, "maxino = %d\n", maxino);
277 	map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
278 	if (map == NULL)
279 		panic("no memory for active inode map\n");
280 	usedinomap = map;
281 	curfile.action = USING;
282 	getfile(xtrmap, xtrmapskip, xtrmapskip);
283 	if (spcl.c_type != TS_BITS) {
284 		fprintf(stderr, "Cannot find file dump list\n");
285 		done(1);
286 	}
287 	map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
288 	if (map == (char *)NULL)
289 		panic("no memory for file dump list\n");
290 	dumpmap = map;
291 	curfile.action = USING;
292 	getfile(xtrmap, xtrmapskip, xtrmapskip);
293 	/*
294 	 * If there may be whiteout entries on the tape, pretend that the
295 	 * whiteout inode exists, so that the whiteout entries can be
296 	 * extracted.
297 	 */
298 	SETINO(WINO, dumpmap);
299 	/* 'r' restores don't call getvol() for tape 1, so mark it as read. */
300 	if (command == 'r')
301 		tapesread = 1;
302 }
303 
304 /*
305  * Prompt user to load a new dump volume.
306  * "Nextvol" is the next suggested volume to use.
307  * This suggested volume is enforced when doing full
308  * or incremental restores, but can be overridden by
309  * the user when only extracting a subset of the files.
310  */
311 void
312 getvol(long nextvol)
313 {
314 	int64_t prevtapea;
315 	long i, newvol, savecnt;
316 	union u_spcl tmpspcl;
317 #	define tmpbuf tmpspcl.s_spcl
318 	char buf[TP_BSIZE];
319 
320 	if (nextvol == 1) {
321 		tapesread = 0;
322 		gettingfile = 0;
323 	}
324 	prevtapea = tapeaddr;
325 	savecnt = blksread;
326 	if (pipein) {
327 		if (nextvol != 1) {
328 			panic("Changing volumes on pipe input?\n");
329 			/* Avoid looping if we couldn't ask the user. */
330 			if (yflag || ferror(terminal) || feof(terminal))
331 				done(1);
332 		}
333 		if (volno == 1)
334 			return;
335 		if (pipecmdin) {
336 			closemt();
337 			goto getpipecmdhdr;
338 		}
339 		goto gethdr;
340 	}
341 again:
342 	if (pipein)
343 		done(1); /* pipes do not get a second chance */
344 	if (command == 'R' || command == 'r' || curfile.action != SKIP)
345 		newvol = nextvol;
346 	else
347 		newvol = 0;
348 	while (newvol <= 0) {
349 		if (tapesread == 0) {
350 			fprintf(stderr, "%s%s%s%s%s%s%s",
351 			    "You have not read any tapes yet.\n",
352 			    "If you are extracting just a few files,",
353 			    " start with the last volume\n",
354 			    "and work towards the first; restore",
355 			    " can quickly skip tapes that\n",
356 			    "have no further files to extract.",
357 			    " Otherwise, begin with volume 1.\n");
358 		} else {
359 			fprintf(stderr, "You have read volumes");
360 			strcpy(buf, ": ");
361 			for (i = 0; i < 32; i++)
362 				if (tapesread & (1 << i)) {
363 					fprintf(stderr, "%s%ld", buf, i + 1);
364 					strcpy(buf, ", ");
365 				}
366 			fprintf(stderr, "\n");
367 		}
368 		do	{
369 			fprintf(stderr, "Specify next volume #: ");
370 			(void) fflush(stderr);
371 			if (fgets(buf, BUFSIZ, terminal) == NULL)
372 				done(1);
373 		} while (buf[0] == '\n');
374 		newvol = atoi(buf);
375 		if (newvol <= 0) {
376 			fprintf(stderr,
377 			    "Volume numbers are positive numerics\n");
378 		}
379 	}
380 	if (newvol == volno) {
381 		tapesread |= 1 << (volno - 1);
382 		return;
383 	}
384 	closemt();
385 	fprintf(stderr, "Mount tape volume %ld\n", newvol);
386 	fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
387 	fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
388 	(void) fflush(stderr);
389 	if (fgets(buf, BUFSIZ, terminal) == NULL)
390 		done(1);
391 	if (!strcmp(buf, "none\n")) {
392 		terminateinput();
393 		return;
394 	}
395 	if (buf[0] != '\n') {
396 		(void) strcpy(magtape, buf);
397 		magtape[strlen(magtape) - 1] = '\0';
398 	}
399 	if (pipecmdin) {
400 		char volno[sizeof("2147483647")];
401 
402 getpipecmdhdr:
403 		(void)sprintf(volno, "%d", newvol);
404 		if (setenv("RESTORE_VOLUME", volno, 1) == -1) {
405 			fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n",
406 			    strerror(errno));
407 			done(1);
408 		}
409 		popenfp = popen(magtape, "r");
410 		mt = popenfp ? fileno(popenfp) : -1;
411 	} else
412 #ifdef RRESTORE
413 	if (host)
414 		mt = rmtopen(magtape, 0);
415 	else
416 #endif
417 		mt = open(magtape, O_RDONLY, 0);
418 
419 	if (mt == -1) {
420 		fprintf(stderr, "Cannot open %s\n", magtape);
421 		volno = -1;
422 		goto again;
423 	}
424 gethdr:
425 	volno = newvol;
426 	setdumpnum();
427 	FLUSHTAPEBUF();
428 	if (gethead(&tmpbuf) == FAIL) {
429 		dprintf(stdout, "header read failed at %ld blocks\n", blksread);
430 		fprintf(stderr, "tape is not dump tape\n");
431 		volno = 0;
432 		goto again;
433 	}
434 	if (tmpbuf.c_volume != volno) {
435 		fprintf(stderr, "Wrong volume (%ld)\n", tmpbuf.c_volume);
436 		volno = 0;
437 		goto again;
438 	}
439 	if (_time64_to_time(tmpbuf.c_date) != dumpdate ||
440 	    _time64_to_time(tmpbuf.c_ddate) != dumptime) {
441 		time_t t = _time64_to_time(tmpbuf.c_date);
442 		fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t));
443 		fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
444 		volno = 0;
445 		goto again;
446 	}
447 	tapesread |= 1 << (volno - 1);
448 	blksread = savecnt;
449  	/*
450  	 * If continuing from the previous volume, skip over any
451  	 * blocks read already at the end of the previous volume.
452  	 *
453  	 * If coming to this volume at random, skip to the beginning
454  	 * of the next record.
455  	 */
456 	dprintf(stdout, "last rec %qd, tape starts with %qd\n", prevtapea,
457 	    tmpbuf.c_tapea);
458  	if (tmpbuf.c_type == TS_TAPE) {
459  		if (curfile.action != USING) {
460 			/*
461 			 * XXX Dump incorrectly sets c_count to 1 in the
462 			 * volume header of the first tape, so ignore
463 			 * c_count when volno == 1.
464 			 */
465 			if (volno != 1)
466 				for (i = tmpbuf.c_count; i > 0; i--)
467 					readtape(buf);
468  		} else if (tmpbuf.c_tapea <= prevtapea) {
469 			/*
470 			 * Normally the value of c_tapea in the volume
471 			 * header is the record number of the header itself.
472 			 * However in the volume header following an EOT-
473 			 * terminated tape, it is the record number of the
474 			 * first continuation data block (dump bug?).
475 			 *
476 			 * The next record we want is `prevtapea + 1'.
477 			 */
478  			i = prevtapea + 1 - tmpbuf.c_tapea;
479 			dprintf(stderr, "Skipping %ld duplicate record%s.\n",
480 				i, i > 1 ? "s" : "");
481  			while (--i >= 0)
482  				readtape(buf);
483  		}
484  	}
485 	if (curfile.action == USING) {
486 		if (volno == 1)
487 			panic("active file into volume 1\n");
488 		return;
489 	}
490 	(void) gethead(&spcl);
491 	findinode(&spcl);
492 	if (gettingfile) {
493 		gettingfile = 0;
494 		longjmp(restart, 1);
495 	}
496 }
497 
498 /*
499  * Handle unexpected EOF.
500  */
501 static void
502 terminateinput(void)
503 {
504 
505 	if (gettingfile && curfile.action == USING) {
506 		printf("Warning: %s %s\n",
507 		    "End-of-input encountered while extracting", curfile.name);
508 	}
509 	curfile.name = "<name unknown>";
510 	curfile.action = UNKNOWN;
511 	curfile.mode = 0;
512 	curfile.ino = maxino;
513 	if (gettingfile) {
514 		gettingfile = 0;
515 		longjmp(restart, 1);
516 	}
517 }
518 
519 /*
520  * handle multiple dumps per tape by skipping forward to the
521  * appropriate one.
522  */
523 static void
524 setdumpnum(void)
525 {
526 	struct mtop tcom;
527 
528 	if (dumpnum == 1 || volno != 1)
529 		return;
530 	if (pipein) {
531 		fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
532 		done(1);
533 	}
534 	tcom.mt_op = MTFSF;
535 	tcom.mt_count = dumpnum - 1;
536 #ifdef RRESTORE
537 	if (host)
538 		rmtioctl(MTFSF, dumpnum - 1);
539 	else
540 #endif
541 		if (!pipecmdin && ioctl(mt, MTIOCTOP, (char *)&tcom) < 0)
542 			fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
543 }
544 
545 void
546 printdumpinfo(void)
547 {
548 	time_t t;
549 	t = _time64_to_time(spcl.c_date);
550 	fprintf(stdout, "Dump   date: %s", ctime(&t));
551 	t = _time64_to_time(spcl.c_ddate);
552 	fprintf(stdout, "Dumped from: %s",
553 	    (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&t));
554 	if (spcl.c_host[0] == '\0')
555 		return;
556 	fprintf(stderr, "Level %ld dump of %s on %s:%s\n",
557 		spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
558 	fprintf(stderr, "Label: %s\n", spcl.c_label);
559 }
560 
561 int
562 extractfile(char *name)
563 {
564 	int flags;
565 	uid_t uid;
566 	gid_t gid;
567 	mode_t mode;
568 	int extsize;
569 	struct timeval mtimep[2], ctimep[2];
570 	struct entry *ep;
571 	char *buf;
572 
573 	curfile.name = name;
574 	curfile.action = USING;
575 	mtimep[0].tv_sec = curfile.atime_sec;
576 	mtimep[0].tv_usec = curfile.atime_nsec / 1000;
577 	mtimep[1].tv_sec = curfile.mtime_sec;
578 	mtimep[1].tv_usec = curfile.mtime_nsec / 1000;
579 	ctimep[0].tv_sec = curfile.atime_sec;
580 	ctimep[0].tv_usec = curfile.atime_nsec / 1000;
581 	ctimep[1].tv_sec = curfile.birthtime_sec;
582 	ctimep[1].tv_usec = curfile.birthtime_nsec / 1000;
583 	extsize = curfile.extsize;
584 	uid = curfile.uid;
585 	gid = curfile.gid;
586 	mode = curfile.mode;
587 	flags = curfile.file_flags;
588 	switch (mode & IFMT) {
589 
590 	default:
591 		fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
592 		skipfile();
593 		return (FAIL);
594 
595 	case IFSOCK:
596 		vprintf(stdout, "skipped socket %s\n", name);
597 		skipfile();
598 		return (GOOD);
599 
600 	case IFDIR:
601 		if (mflag) {
602 			ep = lookupname(name);
603 			if (ep == NULL || ep->e_flags & EXTRACT)
604 				panic("unextracted directory %s\n", name);
605 			skipfile();
606 			return (GOOD);
607 		}
608 		vprintf(stdout, "extract file %s\n", name);
609 		return (genliteraldir(name, curfile.ino));
610 
611 	case IFLNK:
612 		lnkbuf[0] = '\0';
613 		pathlen = 0;
614 		buf = setupextattr(extsize);
615 		getfile(xtrlnkfile, xtrattr, xtrlnkskip);
616 		if (pathlen == 0) {
617 			vprintf(stdout,
618 			    "%s: zero length symbolic link (ignored)\n", name);
619 			return (GOOD);
620 		}
621 		if (linkit(lnkbuf, name, SYMLINK) == GOOD) {
622 			if (extsize > 0)
623 				set_extattr_link(name, buf, extsize);
624 			(void) lchown(name, uid, gid);
625 			(void) lchmod(name, mode);
626 			(void) lutimes(name, ctimep);
627 			(void) lutimes(name, mtimep);
628 			(void) lchflags(name, flags);
629 			return (GOOD);
630 		}
631 		return (FAIL);
632 
633 	case IFIFO:
634 		vprintf(stdout, "extract fifo %s\n", name);
635 		if (Nflag) {
636 			skipfile();
637 			return (GOOD);
638 		}
639 		if (uflag)
640 			(void) unlink(name);
641 		if (mkfifo(name, 0600) < 0) {
642 			fprintf(stderr, "%s: cannot create fifo: %s\n",
643 			    name, strerror(errno));
644 			skipfile();
645 			return (FAIL);
646 		}
647 		if (extsize == 0) {
648 			skipfile();
649 		} else {
650 			buf = setupextattr(extsize);
651 			getfile(xtrnull, xtrattr, xtrnull);
652 			set_extattr_file(name, buf, extsize);
653 		}
654 		(void) chown(name, uid, gid);
655 		(void) chmod(name, mode);
656 		(void) utimes(name, ctimep);
657 		(void) utimes(name, mtimep);
658 		(void) chflags(name, flags);
659 		return (GOOD);
660 
661 	case IFCHR:
662 	case IFBLK:
663 		vprintf(stdout, "extract special file %s\n", name);
664 		if (Nflag) {
665 			skipfile();
666 			return (GOOD);
667 		}
668 		if (uflag)
669 			(void) unlink(name);
670 		if (mknod(name, (mode & (IFCHR | IFBLK)) | 0600,
671 		    (int)curfile.rdev) < 0) {
672 			fprintf(stderr, "%s: cannot create special file: %s\n",
673 			    name, strerror(errno));
674 			skipfile();
675 			return (FAIL);
676 		}
677 		if (extsize == 0) {
678 			skipfile();
679 		} else {
680 			buf = setupextattr(extsize);
681 			getfile(xtrnull, xtrattr, xtrnull);
682 			set_extattr_file(name, buf, extsize);
683 		}
684 		(void) chown(name, uid, gid);
685 		(void) chmod(name, mode);
686 		(void) utimes(name, ctimep);
687 		(void) utimes(name, mtimep);
688 		(void) chflags(name, flags);
689 		return (GOOD);
690 
691 	case IFREG:
692 		vprintf(stdout, "extract file %s\n", name);
693 		if (Nflag) {
694 			skipfile();
695 			return (GOOD);
696 		}
697 		if (uflag)
698 			(void) unlink(name);
699 		if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
700 		    0600)) < 0) {
701 			fprintf(stderr, "%s: cannot create file: %s\n",
702 			    name, strerror(errno));
703 			skipfile();
704 			return (FAIL);
705 		}
706 		buf = setupextattr(extsize);
707 		getfile(xtrfile, xtrattr, xtrskip);
708 		if (extsize > 0)
709 			set_extattr_fd(ofile, name, buf, extsize);
710 		(void) fchown(ofile, uid, gid);
711 		(void) fchmod(ofile, mode);
712 		(void) futimes(ofile, ctimep);
713 		(void) futimes(ofile, mtimep);
714 		(void) fchflags(ofile, flags);
715 		(void) close(ofile);
716 		return (GOOD);
717 	}
718 	/* NOTREACHED */
719 }
720 
721 /*
722  * Set attributes for a file.
723  */
724 void
725 set_extattr_file(char *name, void *buf, int size)
726 {
727 	struct extattr *eap, *eaend;
728 
729 	vprintf(stdout, "Set attributes for %s:", name);
730 	eaend = buf + size;
731 	for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) {
732 		/*
733 		 * Make sure this entry is complete.
734 		 */
735 		if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) {
736 			dprintf(stdout, "\n\t%scorrupted",
737 				eap == buf ? "" : "remainder ");
738 			break;
739 		}
740 		if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY)
741 			continue;
742 		vprintf(stdout, "\n\t%s, (%d bytes), %*s",
743 			namespace_names[eap->ea_namespace], eap->ea_length,
744 			eap->ea_namelength, eap->ea_name);
745 		/*
746 		 * First we try the general attribute setting interface.
747 		 * However, some attributes can only be set by root or
748 		 * by using special interfaces (for example, ACLs).
749 		 */
750 		if (extattr_set_file(name, eap->ea_namespace, eap->ea_name,
751 		    EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) {
752 			dprintf(stdout, " (set using extattr_set_file)");
753 			continue;
754 		}
755 		/*
756 		 * If the general interface refuses to set the attribute,
757 		 * then we try all the specialized interfaces that we
758 		 * know about.
759 		 */
760 		if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
761 		    !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) {
762 			if (acl_set_file(name, ACL_TYPE_ACCESS,
763 			    EXTATTR_CONTENT(eap)) != -1) {
764 				dprintf(stdout, " (set using acl_set_file)");
765 				continue;
766 			}
767 		}
768 		if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
769 		    !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) {
770 			if (acl_set_file(name, ACL_TYPE_DEFAULT,
771 			    EXTATTR_CONTENT(eap)) != -1) {
772 				dprintf(stdout, " (set using acl_set_file)");
773 				continue;
774 			}
775 		}
776 		vprintf(stdout, " (unable to set)");
777 	}
778 	vprintf(stdout, "\n");
779 }
780 
781 /*
782  * Set attributes for a symbolic link.
783  */
784 static void
785 set_extattr_link(char *name, void *buf, int size)
786 {
787 	struct extattr *eap, *eaend;
788 
789 	vprintf(stdout, "Set attributes for %s:", name);
790 	eaend = buf + size;
791 	for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) {
792 		/*
793 		 * Make sure this entry is complete.
794 		 */
795 		if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) {
796 			dprintf(stdout, "\n\t%scorrupted",
797 				eap == buf ? "" : "remainder ");
798 			break;
799 		}
800 		if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY)
801 			continue;
802 		vprintf(stdout, "\n\t%s, (%d bytes), %*s",
803 			namespace_names[eap->ea_namespace], eap->ea_length,
804 			eap->ea_namelength, eap->ea_name);
805 		/*
806 		 * First we try the general attribute setting interface.
807 		 * However, some attributes can only be set by root or
808 		 * by using special interfaces (for example, ACLs).
809 		 */
810 		if (extattr_set_link(name, eap->ea_namespace, eap->ea_name,
811 		    EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) {
812 			dprintf(stdout, " (set using extattr_set_link)");
813 			continue;
814 		}
815 		/*
816 		 * If the general interface refuses to set the attribute,
817 		 * then we try all the specialized interfaces that we
818 		 * know about.
819 		 */
820 		if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
821 		    !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) {
822 			if (acl_set_link_np(name, ACL_TYPE_ACCESS,
823 			    EXTATTR_CONTENT(eap)) != -1) {
824 				dprintf(stdout, " (set using acl_set_link_np)");
825 				continue;
826 			}
827 		}
828 		if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
829 		    !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) {
830 			if (acl_set_link_np(name, ACL_TYPE_DEFAULT,
831 			    EXTATTR_CONTENT(eap)) != -1) {
832 				dprintf(stdout, " (set using acl_set_link_np)");
833 				continue;
834 			}
835 		}
836 		vprintf(stdout, " (unable to set)");
837 	}
838 	vprintf(stdout, "\n");
839 }
840 
841 /*
842  * Set attributes on a file descriptor.
843  */
844 static void
845 set_extattr_fd(int fd, char *name, void *buf, int size)
846 {
847 	struct extattr *eap, *eaend;
848 
849 	vprintf(stdout, "Set attributes for %s:", name);
850 	eaend = buf + size;
851 	for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) {
852 		/*
853 		 * Make sure this entry is complete.
854 		 */
855 		if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) {
856 			dprintf(stdout, "\n\t%scorrupted",
857 				eap == buf ? "" : "remainder ");
858 			break;
859 		}
860 		if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY)
861 			continue;
862 		vprintf(stdout, "\n\t%s, (%d bytes), %*s",
863 			namespace_names[eap->ea_namespace], eap->ea_length,
864 			eap->ea_namelength, eap->ea_name);
865 		/*
866 		 * First we try the general attribute setting interface.
867 		 * However, some attributes can only be set by root or
868 		 * by using special interfaces (for example, ACLs).
869 		 */
870 		if (extattr_set_fd(fd, eap->ea_namespace, eap->ea_name,
871 		    EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) {
872 			dprintf(stdout, " (set using extattr_set_fd)");
873 			continue;
874 		}
875 		/*
876 		 * If the general interface refuses to set the attribute,
877 		 * then we try all the specialized interfaces that we
878 		 * know about.
879 		 */
880 		if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
881 		    !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) {
882 			if (acl_set_fd(fd, EXTATTR_CONTENT(eap)) != -1) {
883 				dprintf(stdout, " (set using acl_set_fd)");
884 				continue;
885 			}
886 		}
887 		if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM &&
888 		    !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) {
889 			if (acl_set_file(name, ACL_TYPE_DEFAULT,
890 			    EXTATTR_CONTENT(eap)) != -1) {
891 				dprintf(stdout, " (set using acl_set_file)");
892 				continue;
893 			}
894 		}
895 		vprintf(stdout, " (unable to set)");
896 	}
897 	vprintf(stdout, "\n");
898 }
899 
900 /*
901  * skip over bit maps on the tape
902  */
903 void
904 skipmaps(void)
905 {
906 
907 	while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
908 		skipfile();
909 }
910 
911 /*
912  * skip over a file on the tape
913  */
914 void
915 skipfile(void)
916 {
917 
918 	curfile.action = SKIP;
919 	getfile(xtrnull, xtrnull, xtrnull);
920 }
921 
922 /*
923  * Extract a file from the tape.
924  * When an allocated block is found it is passed to the fill function;
925  * when an unallocated block (hole) is found, a zeroed buffer is passed
926  * to the skip function.
927  */
928 void
929 getfile(void (*datafill)(char *, long), void (*attrfill)(char *, long),
930 	void (*skip)(char *, long))
931 {
932 	int i;
933 	off_t size;
934 	int curblk, attrsize;
935 	void (*fillit)(char *, long);
936 	static char clearedbuf[MAXBSIZE];
937 	char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
938 	char junk[TP_BSIZE];
939 
940 	curblk = 0;
941 	size = spcl.c_size;
942 	attrsize = spcl.c_extsize;
943 	if (spcl.c_type == TS_END)
944 		panic("ran off end of tape\n");
945 	if (spcl.c_magic != FS_UFS2_MAGIC)
946 		panic("not at beginning of a file\n");
947 	if (!gettingfile && setjmp(restart) != 0)
948 		return;
949 	gettingfile++;
950 	fillit = datafill;
951 	if (size == 0 && attrsize > 0) {
952 		fillit = attrfill;
953 		size = attrsize;
954 		attrsize = 0;
955 	}
956 loop:
957 	for (i = 0; i < spcl.c_count; i++) {
958 		if (!readmapflag && i > TP_NINDIR) {
959 			if (Dflag) {
960 				fprintf(stderr, "spcl.c_count = %jd\n",
961 				    (intmax_t)spcl.c_count);
962 				break;
963 			} else
964 				panic("spcl.c_count = %jd\n",
965 				    (intmax_t)spcl.c_count);
966 		}
967 		if (readmapflag || spcl.c_addr[i]) {
968 			readtape(&buf[curblk++][0]);
969 			if (curblk == fssize / TP_BSIZE) {
970 				(*fillit)((char *)buf, (long)(size > TP_BSIZE ?
971 				     fssize : (curblk - 1) * TP_BSIZE + size));
972 				curblk = 0;
973 			}
974 		} else {
975 			if (curblk > 0) {
976 				(*fillit)((char *)buf, (long)(size > TP_BSIZE ?
977 				     curblk * TP_BSIZE :
978 				     (curblk - 1) * TP_BSIZE + size));
979 				curblk = 0;
980 			}
981 			(*skip)(clearedbuf, (long)(size > TP_BSIZE ?
982 				TP_BSIZE : size));
983 		}
984 		if ((size -= TP_BSIZE) <= 0) {
985 			if (size > -TP_BSIZE && curblk > 0) {
986 				(*fillit)((char *)buf,
987 					(long)((curblk * TP_BSIZE) + size));
988 				curblk = 0;
989 			}
990 			if (attrsize > 0) {
991 				fillit = attrfill;
992 				size = attrsize;
993 				attrsize = 0;
994 				continue;
995 			}
996 			if (spcl.c_count - i > 1)
997 				dprintf(stdout, "skipping %d junk block(s)\n",
998 					spcl.c_count - i - 1);
999 			for (i++; i < spcl.c_count; i++) {
1000 				if (!readmapflag && i > TP_NINDIR) {
1001 					if (Dflag) {
1002 						fprintf(stderr,
1003 						    "spcl.c_count = %jd\n",
1004 						    (intmax_t)spcl.c_count);
1005 						break;
1006 					} else
1007 						panic("spcl.c_count = %jd\n",
1008 						    (intmax_t)spcl.c_count);
1009 				}
1010 				if (readmapflag || spcl.c_addr[i])
1011 					readtape(junk);
1012 			}
1013 			break;
1014 		}
1015 	}
1016 	if (gethead(&spcl) == GOOD && size > 0) {
1017 		if (spcl.c_type == TS_ADDR)
1018 			goto loop;
1019 		dprintf(stdout,
1020 			"Missing address (header) block for %s at %ld blocks\n",
1021 			curfile.name, blksread);
1022 	}
1023 	if (curblk > 0)
1024 		panic("getfile: lost data\n");
1025 	findinode(&spcl);
1026 	gettingfile = 0;
1027 }
1028 
1029 /*
1030  * These variables are shared between the next two functions.
1031  */
1032 static int extbufsize = 0;
1033 static char *extbuf;
1034 static int extloc;
1035 
1036 /*
1037  * Allocate a buffer into which to extract extended attributes.
1038  */
1039 static char *
1040 setupextattr(int extsize)
1041 {
1042 
1043 	extloc = 0;
1044 	if (extsize <= extbufsize)
1045 		return (extbuf);
1046 	if (extbufsize > 0)
1047 		free(extbuf);
1048 	if ((extbuf = malloc(extsize)) != NULL) {
1049 		extbufsize = extsize;
1050 		return (extbuf);
1051 	}
1052 	extbufsize = 0;
1053 	extbuf = NULL;
1054 	fprintf(stderr, "Cannot extract %d bytes %s for inode %d, name %s\n",
1055 	    extsize, "of extended attributes", curfile.ino, curfile.name);
1056 	return (NULL);
1057 }
1058 
1059 /*
1060  * Extract the next block of extended attributes.
1061  */
1062 static void
1063 xtrattr(char *buf, long size)
1064 {
1065 
1066 	if (extloc + size > extbufsize)
1067 		panic("overrun attribute buffer\n");
1068 	memmove(&extbuf[extloc], buf, size);
1069 	extloc += size;
1070 }
1071 
1072 /*
1073  * Write out the next block of a file.
1074  */
1075 static void
1076 xtrfile(char *buf, long	size)
1077 {
1078 
1079 	if (Nflag)
1080 		return;
1081 	if (write(ofile, buf, (int) size) == -1) {
1082 		fprintf(stderr,
1083 		    "write error extracting inode %d, name %s\nwrite: %s\n",
1084 			curfile.ino, curfile.name, strerror(errno));
1085 	}
1086 }
1087 
1088 /*
1089  * Skip over a hole in a file.
1090  */
1091 /* ARGSUSED */
1092 static void
1093 xtrskip(char *buf, long size)
1094 {
1095 
1096 	if (lseek(ofile, size, SEEK_CUR) == -1) {
1097 		fprintf(stderr,
1098 		    "seek error extracting inode %d, name %s\nlseek: %s\n",
1099 			curfile.ino, curfile.name, strerror(errno));
1100 		done(1);
1101 	}
1102 }
1103 
1104 /*
1105  * Collect the next block of a symbolic link.
1106  */
1107 static void
1108 xtrlnkfile(char *buf, long size)
1109 {
1110 
1111 	pathlen += size;
1112 	if (pathlen > MAXPATHLEN) {
1113 		fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
1114 		    curfile.name, lnkbuf, buf, pathlen);
1115 		done(1);
1116 	}
1117 	(void) strcat(lnkbuf, buf);
1118 }
1119 
1120 /*
1121  * Skip over a hole in a symbolic link (should never happen).
1122  */
1123 /* ARGSUSED */
1124 static void
1125 xtrlnkskip(char *buf, long size)
1126 {
1127 
1128 	fprintf(stderr, "unallocated block in symbolic link %s\n",
1129 		curfile.name);
1130 	done(1);
1131 }
1132 
1133 /*
1134  * Collect the next block of a bit map.
1135  */
1136 static void
1137 xtrmap(char *buf, long size)
1138 {
1139 
1140 	memmove(map, buf, size);
1141 	map += size;
1142 }
1143 
1144 /*
1145  * Skip over a hole in a bit map (should never happen).
1146  */
1147 /* ARGSUSED */
1148 static void
1149 xtrmapskip(char *buf, long size)
1150 {
1151 
1152 	panic("hole in map\n");
1153 	map += size;
1154 }
1155 
1156 /*
1157  * Noop, when an extraction function is not needed.
1158  */
1159 /* ARGSUSED */
1160 void
1161 xtrnull(char *buf, long size)
1162 {
1163 
1164 	return;
1165 }
1166 
1167 /*
1168  * Read TP_BSIZE blocks from the input.
1169  * Handle read errors, and end of media.
1170  */
1171 static void
1172 readtape(char *buf)
1173 {
1174 	long rd, newvol, i, oldnumtrec;
1175 	int cnt, seek_failed;
1176 
1177 	if (blkcnt + (byteslide > 0) < numtrec) {
1178 		memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE) + byteslide], (long)TP_BSIZE);
1179 		blksread++;
1180 		tapeaddr++;
1181 		return;
1182 	}
1183 	if (numtrec > 0)
1184 		memmove(&tapebuf[-TP_BSIZE],
1185 		    &tapebuf[(numtrec-1) * TP_BSIZE], (long)TP_BSIZE);
1186 	oldnumtrec = numtrec;
1187 	for (i = 0; i < ntrec; i++)
1188 		((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1189 	if (numtrec == 0)
1190 		numtrec = ntrec;
1191 	cnt = ntrec * TP_BSIZE;
1192 	rd = 0;
1193 getmore:
1194 #ifdef RRESTORE
1195 	if (host)
1196 		i = rmtread(&tapebuf[rd], cnt);
1197 	else
1198 #endif
1199 		i = read(mt, &tapebuf[rd], cnt);
1200 	/*
1201 	 * Check for mid-tape short read error.
1202 	 * If found, skip rest of buffer and start with the next.
1203 	 */
1204 	if (!pipein && numtrec < ntrec && i > 0) {
1205 		dprintf(stdout, "mid-media short read error.\n");
1206 		numtrec = ntrec;
1207 	}
1208 	/*
1209 	 * Handle partial block read.
1210 	 */
1211 	if (pipein && i == 0 && rd > 0)
1212 		i = rd;
1213 	else if (i > 0 && i != ntrec * TP_BSIZE) {
1214 		if (pipein) {
1215 			rd += i;
1216 			cnt -= i;
1217 			if (cnt > 0)
1218 				goto getmore;
1219 			i = rd;
1220 		} else {
1221 			/*
1222 			 * Short read. Process the blocks read.
1223 			 */
1224 			if (i % TP_BSIZE != 0)
1225 				vprintf(stdout,
1226 				    "partial block read: %ld should be %ld\n",
1227 				    i, ntrec * TP_BSIZE);
1228 			numtrec = i / TP_BSIZE;
1229 		}
1230 	}
1231 	/*
1232 	 * Handle read error.
1233 	 */
1234 	if (i < 0) {
1235 		fprintf(stderr, "Tape read error while ");
1236 		switch (curfile.action) {
1237 		default:
1238 			fprintf(stderr, "trying to set up tape\n");
1239 			break;
1240 		case UNKNOWN:
1241 			fprintf(stderr, "trying to resynchronize\n");
1242 			break;
1243 		case USING:
1244 			fprintf(stderr, "restoring %s\n", curfile.name);
1245 			break;
1246 		case SKIP:
1247 			fprintf(stderr, "skipping over inode %d\n",
1248 				curfile.ino);
1249 			break;
1250 		}
1251 		if (!yflag && !reply("continue"))
1252 			done(1);
1253 		i = ntrec * TP_BSIZE;
1254 		memset(tapebuf, 0, i);
1255 #ifdef RRESTORE
1256 		if (host)
1257 			seek_failed = (rmtseek(i, 1) < 0);
1258 		else
1259 #endif
1260 			seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
1261 
1262 		if (seek_failed) {
1263 			fprintf(stderr,
1264 			    "continuation failed: %s\n", strerror(errno));
1265 			done(1);
1266 		}
1267 	}
1268 	/*
1269 	 * Handle end of tape.
1270 	 */
1271 	if (i == 0) {
1272 		vprintf(stdout, "End-of-tape encountered\n");
1273 		if (!pipein) {
1274 			newvol = volno + 1;
1275 			volno = 0;
1276 			numtrec = 0;
1277 			getvol(newvol);
1278 			readtape(buf);
1279 			return;
1280 		}
1281 		if (rd % TP_BSIZE != 0)
1282 			panic("partial block read: %d should be %d\n",
1283 				rd, ntrec * TP_BSIZE);
1284 		terminateinput();
1285 		memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
1286 	}
1287 	if (oldnumtrec == 0)
1288 		blkcnt = 0;
1289 	else
1290 		blkcnt -= oldnumtrec;
1291 	memmove(buf,
1292 	    &tapebuf[(blkcnt++ * TP_BSIZE) + byteslide], (long)TP_BSIZE);
1293 	blksread++;
1294 	tapeaddr++;
1295 }
1296 
1297 static void
1298 findtapeblksize(void)
1299 {
1300 	long i;
1301 
1302 	for (i = 0; i < ntrec; i++)
1303 		((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
1304 	blkcnt = 0;
1305 #ifdef RRESTORE
1306 	if (host)
1307 		i = rmtread(tapebuf, ntrec * TP_BSIZE);
1308 	else
1309 #endif
1310 		i = read(mt, tapebuf, ntrec * TP_BSIZE);
1311 
1312 	if (i <= 0) {
1313 		fprintf(stderr, "tape read error: %s\n", strerror(errno));
1314 		done(1);
1315 	}
1316 	if (i % TP_BSIZE != 0) {
1317 		fprintf(stderr, "Tape block size (%ld) %s (%d)\n",
1318 			i, "is not a multiple of dump block size", TP_BSIZE);
1319 		done(1);
1320 	}
1321 	ntrec = i / TP_BSIZE;
1322 	numtrec = ntrec;
1323 	vprintf(stdout, "Tape block size is %ld\n", ntrec);
1324 }
1325 
1326 void
1327 closemt(void)
1328 {
1329 
1330 	if (mt < 0)
1331 		return;
1332 	if (pipecmdin) {
1333 		pclose(popenfp);
1334 		popenfp = NULL;
1335 	} else
1336 #ifdef RRESTORE
1337 	if (host)
1338 		rmtclose();
1339 	else
1340 #endif
1341 		(void) close(mt);
1342 }
1343 
1344 /*
1345  * Read the next block from the tape.
1346  * If it is not any valid header, return an error.
1347  */
1348 static int
1349 gethead(struct s_spcl *buf)
1350 {
1351 	long i;
1352 
1353 	readtape((char *)buf);
1354 	if (buf->c_magic != FS_UFS2_MAGIC && buf->c_magic != NFS_MAGIC) {
1355 		if (buf->c_magic == OFS_MAGIC) {
1356 			fprintf(stderr,
1357 			    "Format of dump tape is too old. Must use\n");
1358 			fprintf(stderr,
1359 			    "a version of restore from before 2002.\n");
1360 			return (FAIL);
1361 		}
1362 		if (swabl(buf->c_magic) != FS_UFS2_MAGIC &&
1363 		    buf->c_magic != NFS_MAGIC) {
1364 			if (buf->c_magic == OFS_MAGIC) {
1365 				fprintf(stderr,
1366 				  "Format of dump tape is too old. Must use\n");
1367 				fprintf(stderr,
1368 				  "a version of restore from before 2002.\n");
1369 			}
1370 			return (FAIL);
1371 		}
1372 		if (!Bcvt) {
1373 			vprintf(stdout, "Note: Doing Byte swapping\n");
1374 			Bcvt = 1;
1375 		}
1376 	}
1377 	if (checksum((int *)buf) == FAIL)
1378 		return (FAIL);
1379 	if (_time64_to_time(buf->c_date) != dumpdate)
1380 		fprintf(stderr, "Header with wrong dumpdate.\n");
1381 	if (Bcvt) {
1382 		swabst((u_char *)"8l4s1q8l2q17l", (u_char *)buf);
1383 		swabst((u_char *)"l",(u_char *) &buf->c_level);
1384 		swabst((u_char *)"2l4q",(u_char *) &buf->c_flags);
1385 	}
1386 	readmapflag = 0;
1387 
1388 	switch (buf->c_type) {
1389 
1390 	case TS_CLRI:
1391 	case TS_BITS:
1392 		/*
1393 		 * Have to patch up missing information in bit map headers
1394 		 */
1395 		buf->c_inumber = 0;
1396 		buf->c_size = buf->c_count * TP_BSIZE;
1397 		if (buf->c_count > TP_NINDIR)
1398 			readmapflag = 1;
1399 		else
1400 			for (i = 0; i < buf->c_count; i++)
1401 				buf->c_addr[i]++;
1402 		break;
1403 
1404 	case TS_TAPE:
1405 		if (buf->c_magic == NFS_MAGIC) {
1406 			if ((buf->c_flags & NFS_DR_NEWINODEFMT) == 0)
1407 				oldinofmt = 1;
1408 			buf->c_date = _time32_to_time(buf->c_old_date);
1409 			buf->c_ddate = _time32_to_time(buf->c_old_ddate);
1410 			buf->c_tapea = buf->c_old_tapea;
1411 			buf->c_firstrec = buf->c_old_firstrec;
1412 		}
1413 	case TS_END:
1414 		buf->c_inumber = 0;
1415 		break;
1416 
1417 	case TS_INODE:
1418 		/*
1419 		 * For old dump tapes, have to copy up old fields to
1420 		 * new locations.
1421 		 */
1422 		if (buf->c_magic == NFS_MAGIC) {
1423 			buf->c_tapea = buf->c_old_tapea;
1424 			buf->c_firstrec = buf->c_old_firstrec;
1425 			buf->c_date = _time32_to_time(buf->c_old_date);
1426 			buf->c_ddate = _time32_to_time(buf->c_old_ddate);
1427 			buf->c_atime = _time32_to_time(buf->c_old_atime);
1428 			buf->c_mtime = _time32_to_time(buf->c_old_mtime);
1429 		}
1430 		break;
1431 
1432 	case TS_ADDR:
1433 		break;
1434 
1435 	default:
1436 		panic("gethead: unknown inode type %d\n", buf->c_type);
1437 		break;
1438 	}
1439 	/*
1440 	 * If we're restoring a filesystem with the old (FreeBSD 1)
1441 	 * format inodes, copy the uid/gid to the new location
1442 	 */
1443 	if (oldinofmt) {
1444 		buf->c_uid = buf->c_spare1[1];
1445 		buf->c_gid = buf->c_spare1[2];
1446 	}
1447 	buf->c_magic = FS_UFS2_MAGIC;
1448 	tapeaddr = buf->c_tapea;
1449 	if (dflag)
1450 		accthdr(buf);
1451 	return(GOOD);
1452 }
1453 
1454 /*
1455  * Check that a header is where it belongs and predict the next header
1456  */
1457 static void
1458 accthdr(struct s_spcl *header)
1459 {
1460 	static ino_t previno = 0x7fffffff;
1461 	static int prevtype;
1462 	static long predict;
1463 	long blks, i;
1464 
1465 	if (header->c_type == TS_TAPE) {
1466 		fprintf(stderr, "Volume header ");
1467  		if (header->c_firstrec)
1468  			fprintf(stderr, "begins with record %qd",
1469  				header->c_firstrec);
1470  		fprintf(stderr, "\n");
1471 		previno = 0x7fffffff;
1472 		return;
1473 	}
1474 	if (previno == 0x7fffffff)
1475 		goto newcalc;
1476 	switch (prevtype) {
1477 	case TS_BITS:
1478 		fprintf(stderr, "Dumped inodes map header");
1479 		break;
1480 	case TS_CLRI:
1481 		fprintf(stderr, "Used inodes map header");
1482 		break;
1483 	case TS_INODE:
1484 		fprintf(stderr, "File header, ino %d", previno);
1485 		break;
1486 	case TS_ADDR:
1487 		fprintf(stderr, "File continuation header, ino %d", previno);
1488 		break;
1489 	case TS_END:
1490 		fprintf(stderr, "End of tape header");
1491 		break;
1492 	}
1493 	if (predict != blksread - 1)
1494 		fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
1495 			predict, blksread - 1);
1496 	fprintf(stderr, "\n");
1497 newcalc:
1498 	blks = 0;
1499 	if (header->c_type != TS_END)
1500 		for (i = 0; i < header->c_count; i++)
1501 			if (readmapflag || header->c_addr[i] != 0)
1502 				blks++;
1503 	predict = blks;
1504 	blksread = 0;
1505 	prevtype = header->c_type;
1506 	previno = header->c_inumber;
1507 }
1508 
1509 /*
1510  * Find an inode header.
1511  * Complain if had to skip.
1512  */
1513 static void
1514 findinode(struct s_spcl *header)
1515 {
1516 	static long skipcnt = 0;
1517 	long i;
1518 	char buf[TP_BSIZE];
1519 	int htype;
1520 
1521 	curfile.name = "<name unknown>";
1522 	curfile.action = UNKNOWN;
1523 	curfile.mode = 0;
1524 	curfile.ino = 0;
1525 	do {
1526 		htype = header->c_type;
1527 		switch (htype) {
1528 
1529 		case TS_ADDR:
1530 			/*
1531 			 * Skip up to the beginning of the next record
1532 			 */
1533 			for (i = 0; i < header->c_count; i++)
1534 				if (header->c_addr[i])
1535 					readtape(buf);
1536 			while (gethead(header) == FAIL ||
1537 			    _time64_to_time(header->c_date) != dumpdate) {
1538 				skipcnt++;
1539 				if (Dflag) {
1540 					byteslide++;
1541 					if (byteslide < TP_BSIZE) {
1542 						blkcnt--;
1543 						blksread--;
1544 					} else
1545 						byteslide = 0;
1546 				}
1547 			}
1548 			break;
1549 
1550 		case TS_INODE:
1551 			curfile.mode = header->c_mode;
1552 			curfile.uid = header->c_uid;
1553 			curfile.gid = header->c_gid;
1554 			curfile.file_flags = header->c_file_flags;
1555 			curfile.rdev = header->c_rdev;
1556 			curfile.atime_sec = header->c_atime;
1557 			curfile.atime_nsec = header->c_atimensec;
1558 			curfile.mtime_sec = header->c_mtime;
1559 			curfile.mtime_nsec = header->c_mtimensec;
1560 			curfile.birthtime_sec = header->c_birthtime;
1561 			curfile.birthtime_nsec = header->c_birthtimensec;
1562 			curfile.extsize = header->c_extsize;
1563 			curfile.size = header->c_size;
1564 			curfile.ino = header->c_inumber;
1565 			break;
1566 
1567 		case TS_END:
1568 			/* If we missed some tapes, get another volume. */
1569 			if (tapesread & (tapesread + 1)) {
1570 				getvol(0);
1571 				continue;
1572 			}
1573 			curfile.ino = maxino;
1574 			break;
1575 
1576 		case TS_CLRI:
1577 			curfile.name = "<file removal list>";
1578 			break;
1579 
1580 		case TS_BITS:
1581 			curfile.name = "<file dump list>";
1582 			break;
1583 
1584 		case TS_TAPE:
1585 			if (Dflag)
1586 				fprintf(stderr, "unexpected tape header\n");
1587 			else
1588 				panic("unexpected tape header\n");
1589 
1590 		default:
1591 			if (Dflag)
1592 				fprintf(stderr, "unknown tape header type %d\n",
1593 				    spcl.c_type);
1594 			else
1595 				panic("unknown tape header type %d\n",
1596 				    spcl.c_type);
1597 			while (gethead(header) == FAIL ||
1598 			    _time64_to_time(header->c_date) != dumpdate) {
1599 				skipcnt++;
1600 				if (Dflag) {
1601 					byteslide++;
1602 					if (byteslide < TP_BSIZE) {
1603 						blkcnt--;
1604 						blksread--;
1605 					} else
1606 						byteslide = 0;
1607 				}
1608 			}
1609 
1610 		}
1611 	} while (htype == TS_ADDR);
1612 	if (skipcnt > 0)
1613 		fprintf(stderr, "resync restore, skipped %ld %s\n",
1614 		    skipcnt, Dflag ? "bytes" : "blocks");
1615 	skipcnt = 0;
1616 }
1617 
1618 static int
1619 checksum(int *buf)
1620 {
1621 	int i, j;
1622 
1623 	j = sizeof(union u_spcl) / sizeof(int);
1624 	i = 0;
1625 	if (!Bcvt) {
1626 		do
1627 			i += *buf++;
1628 		while (--j);
1629 	} else {
1630 		/* What happens if we want to read restore tapes
1631 			for a 16bit int machine??? */
1632 		do
1633 			i += swabl(*buf++);
1634 		while (--j);
1635 	}
1636 
1637 	if (i != CHECKSUM) {
1638 		fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1639 			curfile.ino, curfile.name);
1640 		return(FAIL);
1641 	}
1642 	return(GOOD);
1643 }
1644 
1645 #ifdef RRESTORE
1646 #include <stdarg.h>
1647 
1648 void
1649 msg(const char *fmt, ...)
1650 {
1651 	va_list ap;
1652 	va_start(ap, fmt);
1653 	(void)vfprintf(stderr, fmt, ap);
1654 	va_end(ap);
1655 }
1656 #endif /* RRESTORE */
1657 
1658 static u_char *
1659 swabshort(u_char *sp, int n)
1660 {
1661 	char c;
1662 
1663 	while (--n >= 0) {
1664 		c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1665 		sp += 2;
1666 	}
1667 	return (sp);
1668 }
1669 
1670 static u_char *
1671 swablong(u_char *sp, int n)
1672 {
1673 	char c;
1674 
1675 	while (--n >= 0) {
1676 		c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1677 		c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1678 		sp += 4;
1679 	}
1680 	return (sp);
1681 }
1682 
1683 static u_char *
1684 swabquad(u_char *sp, int n)
1685 {
1686 	char c;
1687 
1688 	while (--n >= 0) {
1689 		c = sp[0]; sp[0] = sp[7]; sp[7] = c;
1690 		c = sp[1]; sp[1] = sp[6]; sp[6] = c;
1691 		c = sp[2]; sp[2] = sp[5]; sp[5] = c;
1692 		c = sp[3]; sp[3] = sp[4]; sp[4] = c;
1693 		sp += 8;
1694 	}
1695 	return (sp);
1696 }
1697 
1698 void
1699 swabst(u_char *cp, u_char *sp)
1700 {
1701 	int n = 0;
1702 
1703 	while (*cp) {
1704 		switch (*cp) {
1705 		case '0': case '1': case '2': case '3': case '4':
1706 		case '5': case '6': case '7': case '8': case '9':
1707 			n = (n * 10) + (*cp++ - '0');
1708 			continue;
1709 
1710 		case 's': case 'w': case 'h':
1711 			if (n == 0)
1712 				n = 1;
1713 			sp = swabshort(sp, n);
1714 			break;
1715 
1716 		case 'l':
1717 			if (n == 0)
1718 				n = 1;
1719 			sp = swablong(sp, n);
1720 			break;
1721 
1722 		case 'q':
1723 			if (n == 0)
1724 				n = 1;
1725 			sp = swabquad(sp, n);
1726 			break;
1727 
1728 		case 'b':
1729 			if (n == 0)
1730 				n = 1;
1731 			sp += n;
1732 			break;
1733 
1734 		default:
1735 			fprintf(stderr, "Unknown conversion character: %c\n",
1736 			    *cp);
1737 			done(0);
1738 			break;
1739 		}
1740 		cp++;
1741 		n = 0;
1742 	}
1743 }
1744 
1745 static u_long
1746 swabl(u_long x)
1747 {
1748 	swabst((u_char *)"l", (u_char *)&x);
1749 	return (x);
1750 }
1751