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