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