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