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