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