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