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