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