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