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