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