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