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