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