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