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