xref: /original-bsd/sbin/restore/tape.c (revision 5d3a6356)
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.14 (Berkeley) 05/13/88";
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 int xtrmap(), xtrmapskip();
115 
116 	vprintf(stdout, "Verify tape and initialize maps\n");
117 #ifdef RRESTORE
118 	if ((mt = rmtopen(magtape, 0)) < 0)
119 #else
120 	if (pipein)
121 		mt = 0;
122 	else if ((mt = open(magtape, 0)) < 0)
123 #endif
124 	{
125 		perror(magtape);
126 		done(1);
127 	}
128 	volno = 1;
129 	setdumpnum();
130 	flsht();
131 	if (!pipein && !bflag)
132 		findtapeblksize();
133 	if (gethead(&spcl) == FAIL) {
134 		bct--; /* push back this block */
135 		cvtflag++;
136 		if (gethead(&spcl) == FAIL) {
137 			fprintf(stderr, "Tape is not a dump tape\n");
138 			done(1);
139 		}
140 		fprintf(stderr, "Converting to new file system format.\n");
141 	}
142 	if (pipein) {
143 		endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
144 		endoftapemark.s_spcl.c_type = TS_END;
145 		ip = (int *)&endoftapemark;
146 		j = sizeof(union u_spcl) / sizeof(int);
147 		i = 0;
148 		do
149 			i += *ip++;
150 		while (--j);
151 		endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
152 	}
153 	if (vflag || command == 't')
154 		printdumpinfo();
155 	dumptime = spcl.c_ddate;
156 	dumpdate = spcl.c_date;
157 	if (stat(".", &stbuf) < 0) {
158 		perror("cannot stat .");
159 		done(1);
160 	}
161 	if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
162 		fssize = stbuf.st_blksize;
163 	if (((fssize - 1) & fssize) != 0) {
164 		fprintf(stderr, "bad block size %d\n", fssize);
165 		done(1);
166 	}
167 	if (checkvol(&spcl, (long)1) == FAIL) {
168 		fprintf(stderr, "Tape is not volume 1 of the dump\n");
169 		done(1);
170 	}
171 	if (readhdr(&spcl) == FAIL)
172 		panic("no header after volume mark!\n");
173 	findinode(&spcl);
174 	if (checktype(&spcl, TS_CLRI) == FAIL) {
175 		fprintf(stderr, "Cannot find file removal list\n");
176 		done(1);
177 	}
178 	maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
179 	dprintf(stdout, "maxino = %d\n", maxino);
180 	map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
181 	if (map == (char *)NIL)
182 		panic("no memory for file removal list\n");
183 	clrimap = map;
184 	curfile.action = USING;
185 	getfile(xtrmap, xtrmapskip);
186 	if (checktype(&spcl, TS_BITS) == FAIL) {
187 		fprintf(stderr, "Cannot find file dump list\n");
188 		done(1);
189 	}
190 	map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
191 	if (map == (char *)NULL)
192 		panic("no memory for file dump list\n");
193 	dumpmap = map;
194 	curfile.action = USING;
195 	getfile(xtrmap, xtrmapskip);
196 }
197 
198 /*
199  * Prompt user to load a new dump volume.
200  * "Nextvol" is the next suggested volume to use.
201  * This suggested volume is enforced when doing full
202  * or incremental restores, but can be overrridden by
203  * the user when only extracting a subset of the files.
204  */
205 getvol(nextvol)
206 	long nextvol;
207 {
208 	long newvol;
209 	long savecnt, i;
210 	union u_spcl tmpspcl;
211 #	define tmpbuf tmpspcl.s_spcl
212 	char buf[TP_BSIZE];
213 	extern char *ctime();
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 	extern char *ctime();
359 
360 	fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
361 	fprintf(stdout, "Dumped from: %s",
362 	    (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
363 	if (spcl.c_host[0] == '\0')
364 		return;
365 	fprintf(stderr, "Level %d dump of %s on %s:%s\n",
366 		spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
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 (Nflag) {
422 			skipfile();
423 			return (GOOD);
424 		}
425 		if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
426 			fprintf(stderr, "%s: ", name);
427 			(void) fflush(stderr);
428 			perror("cannot create special file");
429 			skipfile();
430 			return (FAIL);
431 		}
432 		(void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
433 		(void) chmod(name, mode);
434 		skipfile();
435 		utime(name, timep);
436 		return (GOOD);
437 
438 	case IFREG:
439 		vprintf(stdout, "extract file %s\n", name);
440 		if (Nflag) {
441 			skipfile();
442 			return (GOOD);
443 		}
444 		if ((ofile = creat(name, 0666)) < 0) {
445 			fprintf(stderr, "%s: ", name);
446 			(void) fflush(stderr);
447 			perror("cannot create file");
448 			skipfile();
449 			return (FAIL);
450 		}
451 		(void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
452 		(void) fchmod(ofile, mode);
453 		getfile(xtrfile, xtrskip);
454 		(void) close(ofile);
455 		utime(name, timep);
456 		return (GOOD);
457 	}
458 	/* NOTREACHED */
459 }
460 
461 /*
462  * skip over bit maps on the tape
463  */
464 skipmaps()
465 {
466 
467 	while (checktype(&spcl, TS_CLRI) == GOOD ||
468 	       checktype(&spcl, TS_BITS) == GOOD)
469 		skipfile();
470 }
471 
472 /*
473  * skip over a file on the tape
474  */
475 skipfile()
476 {
477 	extern int null();
478 
479 	curfile.action = SKIP;
480 	getfile(null, null);
481 }
482 
483 /*
484  * Do the file extraction, calling the supplied functions
485  * with the blocks
486  */
487 getfile(f1, f2)
488 	int	(*f2)(), (*f1)();
489 {
490 	register int i;
491 	int curblk = 0;
492 	off_t size = spcl.c_dinode.di_size;
493 	static char clearedbuf[MAXBSIZE];
494 	char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
495 	char junk[TP_BSIZE];
496 
497 	if (checktype(&spcl, TS_END) == GOOD)
498 		panic("ran off end of tape\n");
499 	if (ishead(&spcl) == FAIL)
500 		panic("not at beginning of a file\n");
501 	if (!gettingfile && setjmp(restart) != 0)
502 		return;
503 	gettingfile++;
504 loop:
505 	for (i = 0; i < spcl.c_count; i++) {
506 		if (spcl.c_addr[i]) {
507 			readtape(&buf[curblk++][0]);
508 			if (curblk == fssize / TP_BSIZE) {
509 				(*f1)(buf, size > TP_BSIZE ?
510 				     (long) (fssize) :
511 				     (curblk - 1) * TP_BSIZE + size);
512 				curblk = 0;
513 			}
514 		} else {
515 			if (curblk > 0) {
516 				(*f1)(buf, size > TP_BSIZE ?
517 				     (long) (curblk * TP_BSIZE) :
518 				     (curblk - 1) * TP_BSIZE + size);
519 				curblk = 0;
520 			}
521 			(*f2)(clearedbuf, size > TP_BSIZE ?
522 				(long) TP_BSIZE : size);
523 		}
524 		if ((size -= TP_BSIZE) <= 0) {
525 			for (i++; i < spcl.c_count; i++)
526 				if (spcl.c_addr[i])
527 					readtape(junk);
528 			break;
529 		}
530 	}
531 	if (readhdr(&spcl) == GOOD && size > 0) {
532 		if (checktype(&spcl, TS_ADDR) == GOOD)
533 			goto loop;
534 		dprintf(stdout, "Missing address (header) block for %s\n",
535 			curfile.name);
536 	}
537 	if (curblk > 0)
538 		(*f1)(buf, (curblk * TP_BSIZE) + size);
539 	findinode(&spcl);
540 	gettingfile = 0;
541 }
542 
543 /*
544  * The next routines are called during file extraction to
545  * put the data into the right form and place.
546  */
547 xtrfile(buf, size)
548 	char	*buf;
549 	long	size;
550 {
551 
552 	if (Nflag)
553 		return;
554 	if (write(ofile, buf, (int) size) == -1) {
555 		fprintf(stderr, "write error extracting inode %d, name %s\n",
556 			curfile.ino, curfile.name);
557 		perror("write");
558 		done(1);
559 	}
560 }
561 
562 xtrskip(buf, size)
563 	char *buf;
564 	long size;
565 {
566 
567 #ifdef lint
568 	buf = buf;
569 #endif
570 	if (lseek(ofile, size, 1) == (long)-1) {
571 		fprintf(stderr, "seek error extracting inode %d, name %s\n",
572 			curfile.ino, curfile.name);
573 		perror("lseek");
574 		done(1);
575 	}
576 }
577 
578 xtrlnkfile(buf, size)
579 	char	*buf;
580 	long	size;
581 {
582 
583 	pathlen += size;
584 	if (pathlen > MAXPATHLEN) {
585 		fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
586 		    curfile.name, lnkbuf, buf, pathlen);
587 		done(1);
588 	}
589 	(void) strcat(lnkbuf, buf);
590 }
591 
592 xtrlnkskip(buf, size)
593 	char *buf;
594 	long size;
595 {
596 
597 #ifdef lint
598 	buf = buf, size = size;
599 #endif
600 	fprintf(stderr, "unallocated block in symbolic link %s\n",
601 		curfile.name);
602 	done(1);
603 }
604 
605 xtrmap(buf, size)
606 	char	*buf;
607 	long	size;
608 {
609 
610 	bcopy(buf, map, size);
611 	map += size;
612 }
613 
614 xtrmapskip(buf, size)
615 	char *buf;
616 	long size;
617 {
618 
619 #ifdef lint
620 	buf = buf;
621 #endif
622 	panic("hole in map\n");
623 	map += size;
624 }
625 
626 null() {;}
627 
628 /*
629  * Do the tape i/o, dealing with volume changes
630  * etc..
631  */
632 readtape(b)
633 	char *b;
634 {
635 	register long i;
636 	long rd, newvol;
637 	int cnt;
638 
639 	if (bct < ntrec) {
640 		bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
641 		blksread++;
642 		return;
643 	}
644 	for (i = 0; i < ntrec; i++)
645 		((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
646 	bct = 0;
647 	cnt = ntrec*TP_BSIZE;
648 	rd = 0;
649 getmore:
650 #ifdef RRESTORE
651 	i = rmtread(&tbf[rd], cnt);
652 #else
653 	i = read(mt, &tbf[rd], cnt);
654 #endif
655 	if (i > 0 && i != ntrec*TP_BSIZE) {
656 		if (pipein) {
657 			rd += i;
658 			cnt -= i;
659 			if (cnt > 0)
660 				goto getmore;
661 			i = rd;
662 		} else {
663 			if (i % TP_BSIZE != 0)
664 				panic("partial block read: %d should be %d\n",
665 					i, ntrec * TP_BSIZE);
666 			bcopy((char *)&endoftapemark, &tbf[i],
667 				(long)TP_BSIZE);
668 		}
669 	}
670 	if (i < 0) {
671 		fprintf(stderr, "Tape read error while ");
672 		switch (curfile.action) {
673 		default:
674 			fprintf(stderr, "trying to set up tape\n");
675 			break;
676 		case UNKNOWN:
677 			fprintf(stderr, "trying to resynchronize\n");
678 			break;
679 		case USING:
680 			fprintf(stderr, "restoring %s\n", curfile.name);
681 			break;
682 		case SKIP:
683 			fprintf(stderr, "skipping over inode %d\n",
684 				curfile.ino);
685 			break;
686 		}
687 		if (!yflag && !reply("continue"))
688 			done(1);
689 		i = ntrec*TP_BSIZE;
690 		bzero(tbf, i);
691 #ifdef RRESTORE
692 		if (rmtseek(i, 1) < 0)
693 #else
694 		if (lseek(mt, i, 1) == (long)-1)
695 #endif
696 		{
697 			perror("continuation failed");
698 			done(1);
699 		}
700 	}
701 	if (i == 0) {
702 		if (!pipein) {
703 			newvol = volno + 1;
704 			volno = 0;
705 			getvol(newvol);
706 			readtape(b);
707 			return;
708 		}
709 		if (rd % TP_BSIZE != 0)
710 			panic("partial block read: %d should be %d\n",
711 				rd, ntrec * TP_BSIZE);
712 		bcopy((char *)&endoftapemark, &tbf[rd], (long)TP_BSIZE);
713 	}
714 	bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
715 	blksread++;
716 }
717 
718 findtapeblksize()
719 {
720 	register long i;
721 
722 	for (i = 0; i < ntrec; i++)
723 		((struct s_spcl *)&tbf[i * TP_BSIZE])->c_magic = 0;
724 	bct = 0;
725 #ifdef RRESTORE
726 	i = rmtread(tbf, ntrec * TP_BSIZE);
727 #else
728 	i = read(mt, tbf, ntrec * TP_BSIZE);
729 #endif
730 	if (i <= 0) {
731 		perror("Tape read error");
732 		done(1);
733 	}
734 	if (i % TP_BSIZE != 0) {
735 		fprintf(stderr, "Tape block size (%d) %s (%d)\n",
736 			i, "is not a multiple of dump block size", TP_BSIZE);
737 		done(1);
738 	}
739 	ntrec = i / TP_BSIZE;
740 	vprintf(stdout, "Tape block size is %d\n", ntrec);
741 }
742 
743 flsht()
744 {
745 
746 	bct = ntrec+1;
747 }
748 
749 closemt()
750 {
751 	if (mt < 0)
752 		return;
753 #ifdef RRESTORE
754 	rmtclose();
755 #else
756 	(void) close(mt);
757 #endif
758 }
759 
760 checkvol(b, t)
761 	struct s_spcl *b;
762 	long t;
763 {
764 
765 	if (b->c_volume != t)
766 		return(FAIL);
767 	return(GOOD);
768 }
769 
770 readhdr(b)
771 	struct s_spcl *b;
772 {
773 
774 	if (gethead(b) == FAIL) {
775 		dprintf(stdout, "readhdr fails at %d blocks\n", blksread);
776 		return(FAIL);
777 	}
778 	return(GOOD);
779 }
780 
781 /*
782  * read the tape into buf, then return whether or
783  * or not it is a header block.
784  */
785 gethead(buf)
786 	struct s_spcl *buf;
787 {
788 	long i, *j;
789 	union u_ospcl {
790 		char dummy[TP_BSIZE];
791 		struct	s_ospcl {
792 			long	c_type;
793 			long	c_date;
794 			long	c_ddate;
795 			long	c_volume;
796 			long	c_tapea;
797 			u_short	c_inumber;
798 			long	c_magic;
799 			long	c_checksum;
800 			struct odinode {
801 				unsigned short odi_mode;
802 				u_short	odi_nlink;
803 				u_short	odi_uid;
804 				u_short	odi_gid;
805 				long	odi_size;
806 				long	odi_rdev;
807 				char	odi_addr[36];
808 				long	odi_atime;
809 				long	odi_mtime;
810 				long	odi_ctime;
811 			} c_dinode;
812 			long	c_count;
813 			char	c_addr[256];
814 		} s_ospcl;
815 	} u_ospcl;
816 
817 	if (!cvtflag) {
818 		readtape((char *)buf);
819 		if (buf->c_magic != NFS_MAGIC) {
820 			if (swabl(buf->c_magic) != NFS_MAGIC)
821 				return (FAIL);
822 			if (!Bcvt) {
823 				vprintf(stdout, "Note: Doing Byte swapping\n");
824 				Bcvt = 1;
825 			}
826 		}
827 		if (checksum((int *)buf) == FAIL)
828 			return (FAIL);
829 		if (Bcvt)
830 			swabst("8l4s31l", (char *)buf);
831 		goto good;
832 	}
833 	readtape((char *)(&u_ospcl.s_ospcl));
834 	bzero((char *)buf, (long)TP_BSIZE);
835 	buf->c_type = u_ospcl.s_ospcl.c_type;
836 	buf->c_date = u_ospcl.s_ospcl.c_date;
837 	buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
838 	buf->c_volume = u_ospcl.s_ospcl.c_volume;
839 	buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
840 	buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
841 	buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
842 	buf->c_magic = u_ospcl.s_ospcl.c_magic;
843 	buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
844 	buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
845 	buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
846 	buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
847 	buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
848 	buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
849 	buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
850 	buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
851 	buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
852 	buf->c_count = u_ospcl.s_ospcl.c_count;
853 	bcopy(u_ospcl.s_ospcl.c_addr, buf->c_addr, (long)256);
854 	if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
855 	    checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
856 		return(FAIL);
857 	buf->c_magic = NFS_MAGIC;
858 
859 good:
860 	j = buf->c_dinode.di_ic.ic_size.val;
861 	i = j[1];
862 	if (buf->c_dinode.di_size == 0 &&
863 	    (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt==0) {
864 		if (*j || i) {
865 			printf("Note: Doing Quad swapping\n");
866 			Qcvt = 1;
867 		}
868 	}
869 	if (Qcvt) {
870 		j[1] = *j; *j = i;
871 	}
872 	switch (buf->c_type) {
873 
874 	case TS_CLRI:
875 	case TS_BITS:
876 		/*
877 		 * Have to patch up missing information in bit map headers
878 		 */
879 		buf->c_inumber = 0;
880 		buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
881 		for (i = 0; i < buf->c_count; i++)
882 			buf->c_addr[i]++;
883 		break;
884 
885 	case TS_TAPE:
886 	case TS_END:
887 		buf->c_inumber = 0;
888 		break;
889 
890 	case TS_INODE:
891 	case TS_ADDR:
892 		break;
893 
894 	default:
895 		panic("gethead: unknown inode type %d\n", buf->c_type);
896 		break;
897 	}
898 	if (dflag)
899 		accthdr(buf);
900 	return(GOOD);
901 }
902 
903 /*
904  * Check that a header is where it belongs and predict the next header
905  */
906 accthdr(header)
907 	struct s_spcl *header;
908 {
909 	static ino_t previno = 0x7fffffff;
910 	static int prevtype;
911 	static long predict;
912 	long blks, i;
913 
914 	if (header->c_type == TS_TAPE) {
915 		fprintf(stderr, "Volume header\n");
916 		previno = 0x7fffffff;
917 		return;
918 	}
919 	if (previno == 0x7fffffff)
920 		goto newcalc;
921 	switch (prevtype) {
922 	case TS_BITS:
923 		fprintf(stderr, "Dump mask header");
924 		break;
925 	case TS_CLRI:
926 		fprintf(stderr, "Remove mask header");
927 		break;
928 	case TS_INODE:
929 		fprintf(stderr, "File header, ino %d", previno);
930 		break;
931 	case TS_ADDR:
932 		fprintf(stderr, "File continuation header, ino %d", previno);
933 		break;
934 	case TS_END:
935 		fprintf(stderr, "End of tape header");
936 		break;
937 	}
938 	if (predict != blksread - 1)
939 		fprintf(stderr, "; predicted %d blocks, got %d blocks",
940 			predict, blksread - 1);
941 	fprintf(stderr, "\n");
942 newcalc:
943 	blks = 0;
944 	if (header->c_type != TS_END)
945 		for (i = 0; i < header->c_count; i++)
946 			if (header->c_addr[i] != 0)
947 				blks++;
948 	predict = blks;
949 	blksread = 0;
950 	prevtype = header->c_type;
951 	previno = header->c_inumber;
952 }
953 
954 /*
955  * Find an inode header.
956  * Complain if had to skip, and complain is set.
957  */
958 findinode(header)
959 	struct s_spcl *header;
960 {
961 	static long skipcnt = 0;
962 	long i;
963 	char buf[TP_BSIZE];
964 
965 	curfile.name = "<name unknown>";
966 	curfile.action = UNKNOWN;
967 	curfile.dip = (struct dinode *)NIL;
968 	curfile.ino = 0;
969 	if (ishead(header) == FAIL) {
970 		skipcnt++;
971 		while (gethead(header) == FAIL || header->c_date != dumpdate)
972 			skipcnt++;
973 	}
974 	for (;;) {
975 		if (checktype(header, TS_ADDR) == GOOD) {
976 			/*
977 			 * Skip up to the beginning of the next record
978 			 */
979 			for (i = 0; i < header->c_count; i++)
980 				if (header->c_addr[i])
981 					readtape(buf);
982 			(void) gethead(header);
983 			continue;
984 		}
985 		if (checktype(header, TS_INODE) == GOOD) {
986 			curfile.dip = &header->c_dinode;
987 			curfile.ino = header->c_inumber;
988 			break;
989 		}
990 		if (checktype(header, TS_END) == GOOD) {
991 			curfile.ino = maxino;
992 			break;
993 		}
994 		if (checktype(header, TS_CLRI) == GOOD) {
995 			curfile.name = "<file removal list>";
996 			break;
997 		}
998 		if (checktype(header, TS_BITS) == GOOD) {
999 			curfile.name = "<file dump list>";
1000 			break;
1001 		}
1002 		while (gethead(header) == FAIL)
1003 			skipcnt++;
1004 	}
1005 	if (skipcnt > 0)
1006 		fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
1007 	skipcnt = 0;
1008 }
1009 
1010 /*
1011  * return whether or not the buffer contains a header block
1012  */
1013 ishead(buf)
1014 	struct s_spcl *buf;
1015 {
1016 
1017 	if (buf->c_magic != NFS_MAGIC)
1018 		return(FAIL);
1019 	return(GOOD);
1020 }
1021 
1022 checktype(b, t)
1023 	struct s_spcl *b;
1024 	int	t;
1025 {
1026 
1027 	if (b->c_type != t)
1028 		return(FAIL);
1029 	return(GOOD);
1030 }
1031 
1032 checksum(b)
1033 	register int *b;
1034 {
1035 	register int i, j;
1036 
1037 	j = sizeof(union u_spcl) / sizeof(int);
1038 	i = 0;
1039 	if(!Bcvt) {
1040 		do
1041 			i += *b++;
1042 		while (--j);
1043 	} else {
1044 		/* What happens if we want to read restore tapes
1045 			for a 16bit int machine??? */
1046 		do
1047 			i += swabl(*b++);
1048 		while (--j);
1049 	}
1050 
1051 	if (i != CHECKSUM) {
1052 		fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1053 			curfile.ino, curfile.name);
1054 		return(FAIL);
1055 	}
1056 	return(GOOD);
1057 }
1058 
1059 #ifdef RRESTORE
1060 /* VARARGS1 */
1061 msg(cp, a1, a2, a3)
1062 	char *cp;
1063 {
1064 
1065 	fprintf(stderr, cp, a1, a2, a3);
1066 }
1067 #endif RRESTORE
1068 
1069 swabst(cp, sp)
1070 register char *cp, *sp;
1071 {
1072 	int n = 0;
1073 	char c;
1074 	while(*cp) {
1075 		switch (*cp) {
1076 		case '0': case '1': case '2': case '3': case '4':
1077 		case '5': case '6': case '7': case '8': case '9':
1078 			n = (n * 10) + (*cp++ - '0');
1079 			continue;
1080 
1081 		case 's': case 'w': case 'h':
1082 			c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1083 			sp++;
1084 			break;
1085 
1086 		case 'l':
1087 			c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1088 			c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1089 			sp += 3;
1090 		}
1091 		sp++; /* Any other character, like 'b' counts as byte. */
1092 		if (n <= 1) {
1093 			n = 0; cp++;
1094 		} else
1095 			n--;
1096 	}
1097 }
1098 swabl(x) { unsigned long l = x; swabst("l", (char *)&l); return l; }
1099