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