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