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