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