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