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