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