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