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