tape.c revision 37906
1132718Skan/*
2132718Skan * Copyright (c) 1983, 1993
3132718Skan *	The Regents of the University of California.  All rights reserved.
4132718Skan * (c) UNIX System Laboratories, Inc.
5169689Skan * All or some portions of this file are derived from material licensed
6132718Skan * to the University of California by American Telephone and Telegraph
7132718Skan * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8132718Skan * the permission of UNIX System Laboratories, Inc.
9132718Skan *
10132718Skan * Redistribution and use in source and binary forms, with or without
11132718Skan * modification, are permitted provided that the following conditions
12132718Skan * are met:
13132718Skan * 1. Redistributions of source code must retain the above copyright
14132718Skan *    notice, this list of conditions and the following disclaimer.
15132718Skan * 2. Redistributions in binary form must reproduce the above copyright
16132718Skan *    notice, this list of conditions and the following disclaimer in the
17132718Skan *    documentation and/or other materials provided with the distribution.
18132718Skan * 3. All advertising materials mentioning features or use of this software
19132718Skan *    must display the following acknowledgement:
20132718Skan *	This product includes software developed by the University of
21169689Skan *	California, Berkeley and its contributors.
22169689Skan * 4. Neither the name of the University nor the names of its contributors
23132718Skan *    may be used to endorse or promote products derived from this software
24132718Skan *    without specific prior written permission.
25132718Skan *
26132718Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27132718Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28132718Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29132718Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30132718Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32132718Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33132718Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34132718Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35132718Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36132718Skan * SUCH DAMAGE.
37169689Skan */
38132718Skan
39132718Skan#ifndef lint
40132718Skan#if 0
41132718Skanstatic char sccsid[] = "@(#)tape.c	8.9 (Berkeley) 5/1/95";
42132718Skan#endif
43169689Skanstatic const char rcsid[] =
44132718Skan	"$Id$";
45132718Skan#endif /* not lint */
46132718Skan
47132718Skan#include <sys/param.h>
48261188Spfg#include <sys/file.h>
49261188Spfg#include <sys/mtio.h>
50261188Spfg#include <sys/stat.h>
51261188Spfg
52261188Spfg#include <ufs/ufs/dinode.h>
53261188Spfg#include <protocols/dumprestore.h>
54261188Spfg
55132718Skan#include <errno.h>
56169689Skan#include <setjmp.h>
57132718Skan#include <stdio.h>
58169689Skan#include <stdlib.h>
59169689Skan#include <string.h>
60132718Skan#include <unistd.h>
61132718Skan
62132718Skan#include "restore.h"
63169689Skan#include "extern.h"
64132718Skan#include "pathnames.h"
65132718Skan
66261188Spfgstatic long	fssize = MAXBSIZE;
67261188Spfgstatic int	mt = -1;
68261188Spfgstatic int	pipein = 0;
69261188Spfgstatic char	*magtape;
70261188Spfgstatic int	blkcnt;
71261188Spfgstatic int	numtrec;
72261188Spfgstatic char	*tapebuf;
73261188Spfgstatic union	u_spcl endoftapemark;
74261188Spfgstatic long	blksread;		/* blocks read since last header */
75261188Spfgstatic long	tpblksread = 0;		/* TP_BSIZE blocks read */
76261188Spfgstatic long	tapesread;
77261188Spfgstatic jmp_buf	restart;
78261188Spfgstatic int	gettingfile = 0;	/* restart has a valid frame */
79261188Spfgstatic char	*host = NULL;
80261188Spfg
81261188Spfgstatic int	ofile;
82261188Spfgstatic char	*map;
83261188Spfgstatic char	lnkbuf[MAXPATHLEN + 1];
84261188Spfgstatic int	pathlen;
85261188Spfg
86261188Spfgint		oldinofmt;	/* old inode format conversion required */
87261188Spfgint		Bcvt;		/* Swap Bytes (for CCI or sun) */
88132718Skanstatic int	Qcvt;		/* Swap quads (for sun) */
89132718Skan
90169689Skan#define	FLUSHTAPEBUF()	blkcnt = ntrec + 1
91169689Skan
92169689Skanstatic void	 accthdr __P((struct s_spcl *));
93132718Skanstatic int	 checksum __P((int *));
94132718Skanstatic void	 findinode __P((struct s_spcl *));
95261188Spfgstatic void	 findtapeblksize __P((void));
96261188Spfgstatic int	 gethead __P((struct s_spcl *));
97261188Spfgstatic void	 readtape __P((char *));
98261188Spfgstatic void	 setdumpnum __P((void));
99261188Spfgstatic u_long	 swabl __P((u_long));
100261188Spfgstatic u_char	*swablong __P((u_char *, int));
101261188Spfgstatic u_char	*swabshort __P((u_char *, int));
102261188Spfgstatic void	 terminateinput __P((void));
103169689Skanstatic void	 xtrfile __P((char *, long));
104169689Skanstatic void	 xtrlnkfile __P((char *, long));
105261188Spfgstatic void	 xtrlnkskip __P((char *, long));
106261188Spfgstatic void	 xtrmap __P((char *, long));
107261188Spfgstatic void	 xtrmapskip __P((char *, long));
108261188Spfgstatic void	 xtrskip __P((char *, long));
109169689Skan
110169689Skan/*
111169689Skan * Set up an input source
112169689Skan */
113261188Spfgvoid
114261188Spfgsetinput(source)
115261188Spfg	char *source;
116261188Spfg{
117261188Spfg	FLUSHTAPEBUF();
118261188Spfg	if (bflag)
119261188Spfg		newtapebuf(ntrec);
120261188Spfg	else
121261188Spfg		newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
122261188Spfg	terminal = stdin;
123169689Skan
124169689Skan#ifdef RRESTORE
125169689Skan	if (strchr(source, ':')) {
126169689Skan		host = source;
127169689Skan		source = strchr(host, ':');
128169689Skan		*source++ = '\0';
129169689Skan		if (rmthost(host) == 0)
130169689Skan			done(1);
131169689Skan	} else
132169689Skan#endif
133169689Skan	if (strcmp(source, "-") == 0) {
134132718Skan		/*
135169689Skan		 * Since input is coming from a pipe we must establish
136169689Skan		 * our own connection to the terminal.
137169689Skan		 */
138169689Skan		terminal = fopen(_PATH_TTY, "r");
139169689Skan		if (terminal == NULL) {
140169689Skan			(void)fprintf(stderr, "cannot open %s: %s\n",
141132718Skan			    _PATH_TTY, strerror(errno));
142132718Skan			terminal = fopen(_PATH_DEVNULL, "r");
143132718Skan			if (terminal == NULL) {
144132718Skan				(void)fprintf(stderr, "cannot open %s: %s\n",
145132718Skan				    _PATH_DEVNULL, strerror(errno));
146169689Skan				done(1);
147169689Skan			}
148169689Skan		}
149169689Skan		pipein++;
150169689Skan	}
151169689Skan	setuid(getuid());	/* no longer need or want root privileges */
152169689Skan	magtape = strdup(source);
153169689Skan	if (magtape == NULL) {
154169689Skan		fprintf(stderr, "Cannot allocate space for magtape buffer\n");
155169689Skan		done(1);
156169689Skan	}
157261188Spfg}
158261188Spfg
159169689Skanvoid
160169689Skannewtapebuf(size)
161169689Skan	long size;
162169689Skan{
163169689Skan	static tapebufsize = -1;
164261188Spfg
165261188Spfg	ntrec = size;
166169689Skan	if (size <= tapebufsize)
167169689Skan		return;
168261188Spfg	if (tapebuf != NULL)
169169689Skan		free(tapebuf);
170169689Skan	tapebuf = malloc(size * TP_BSIZE);
171169689Skan	if (tapebuf == NULL) {
172169689Skan		fprintf(stderr, "Cannot allocate space for tape buffer\n");
173261188Spfg		done(1);
174261188Spfg	}
175261188Spfg	tapebufsize = size;
176261188Spfg}
177169689Skan
178169689Skan/*
179169689Skan * Verify that the tape drive can be accessed and
180169689Skan * that it actually is a dump tape.
181169689Skan */
182169689Skanvoid
183169689Skansetup()
184169689Skan{
185169689Skan	int i, j, *ip;
186169689Skan	struct stat stbuf;
187169689Skan
188169689Skan	vprintf(stdout, "Verify tape and initialize maps\n");
189169689Skan#ifdef RRESTORE
190169689Skan	if (host)
191169689Skan		mt = rmtopen(magtape, 0);
192169689Skan	else
193169689Skan#endif
194169689Skan	if (pipein)
195169689Skan		mt = 0;
196169689Skan	else
197169689Skan		mt = open(magtape, O_RDONLY, 0);
198169689Skan	if (mt < 0) {
199169689Skan		fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
200169689Skan		done(1);
201169689Skan	}
202169689Skan	volno = 1;
203169689Skan	setdumpnum();
204169689Skan	FLUSHTAPEBUF();
205169689Skan	if (!pipein && !bflag)
206169689Skan		findtapeblksize();
207169689Skan	if (gethead(&spcl) == FAIL) {
208169689Skan		blkcnt--; /* push back this block */
209169689Skan		blksread--;
210169689Skan		tpblksread--;
211169689Skan		cvtflag++;
212169689Skan		if (gethead(&spcl) == FAIL) {
213169689Skan			fprintf(stderr, "Tape is not a dump tape\n");
214169689Skan			done(1);
215169689Skan		}
216169689Skan		fprintf(stderr, "Converting to new file system format.\n");
217169689Skan	}
218169689Skan	if (pipein) {
219169689Skan		endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
220169689Skan		endoftapemark.s_spcl.c_type = TS_END;
221169689Skan		ip = (int *)&endoftapemark;
222169689Skan		j = sizeof(union u_spcl) / sizeof(int);
223169689Skan		i = 0;
224169689Skan		do
225169689Skan			i += *ip++;
226169689Skan		while (--j);
227169689Skan		endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
228169689Skan	}
229169689Skan	if (vflag || command == 't')
230169689Skan		printdumpinfo();
231169689Skan	dumptime = spcl.c_ddate;
232169689Skan	dumpdate = spcl.c_date;
233169689Skan	if (stat(".", &stbuf) < 0) {
234169689Skan		fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
235169689Skan		done(1);
236169689Skan	}
237169689Skan	if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE )
238169689Skan		fssize = TP_BSIZE;
239169689Skan	if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE)
240261188Spfg		fssize = stbuf.st_blksize;
241261188Spfg	if (((fssize - 1) & fssize) != 0) {
242261188Spfg		fprintf(stderr, "bad block size %ld\n", fssize);
243261188Spfg		done(1);
244169689Skan	}
245169689Skan	if (spcl.c_volume != 1) {
246169689Skan		fprintf(stderr, "Tape is not volume 1 of the dump\n");
247169689Skan		done(1);
248261188Spfg	}
249261188Spfg	if (gethead(&spcl) == FAIL) {
250261188Spfg		dprintf(stdout, "header read failed at %ld blocks\n", blksread);
251261188Spfg		panic("no header after volume mark!\n");
252169689Skan	}
253169689Skan	findinode(&spcl);
254169689Skan	if (spcl.c_type != TS_CLRI) {
255169689Skan		fprintf(stderr, "Cannot find file removal list\n");
256169689Skan		done(1);
257169689Skan	}
258169689Skan	maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
259169689Skan	dprintf(stdout, "maxino = %d\n", maxino);
260169689Skan	map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
261169689Skan	if (map == NULL)
262169689Skan		panic("no memory for active inode map\n");
263261188Spfg	usedinomap = map;
264261188Spfg	curfile.action = USING;
265261188Spfg	getfile(xtrmap, xtrmapskip);
266261188Spfg	if (spcl.c_type != TS_BITS) {
267169689Skan		fprintf(stderr, "Cannot find file dump list\n");
268169689Skan		done(1);
269169689Skan	}
270169689Skan	map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
271169689Skan	if (map == (char *)NULL)
272169689Skan		panic("no memory for file dump list\n");
273169689Skan	dumpmap = map;
274169689Skan	curfile.action = USING;
275169689Skan	getfile(xtrmap, xtrmapskip);
276169689Skan	/*
277169689Skan	 * If there may be whiteout entries on the tape, pretend that the
278169689Skan	 * whiteout inode exists, so that the whiteout entries can be
279169689Skan	 * extracted.
280169689Skan	 */
281169689Skan	if (oldinofmt == 0)
282169689Skan		SETINO(WINO, dumpmap);
283169689Skan}
284169689Skan
285169689Skan/*
286169689Skan * Prompt user to load a new dump volume.
287169689Skan * "Nextvol" is the next suggested volume to use.
288169689Skan * This suggested volume is enforced when doing full
289169689Skan * or incremental restores, but can be overridden by
290169689Skan * the user when only extracting a subset of the files.
291169689Skan */
292169689Skanvoid
293169689Skangetvol(nextvol)
294169689Skan	long nextvol;
295169689Skan{
296169689Skan	long newvol, savecnt, wantnext, i;
297169689Skan	union u_spcl tmpspcl;
298169689Skan#	define tmpbuf tmpspcl.s_spcl
299169689Skan	char buf[TP_BSIZE];
300169689Skan
301169689Skan	if (nextvol == 1) {
302169689Skan		tapesread = 0;
303169689Skan		gettingfile = 0;
304169689Skan	}
305169689Skan	if (pipein) {
306169689Skan		if (nextvol != 1)
307169689Skan			panic("Changing volumes on pipe input?\n");
308169689Skan		if (volno == 1)
309169689Skan			return;
310169689Skan		goto gethdr;
311169689Skan	}
312169689Skan	savecnt = blksread;
313169689Skanagain:
314169689Skan	if (pipein)
315169689Skan		done(1); /* pipes do not get a second chance */
316261188Spfg	if (command == 'R' || command == 'r' || curfile.action != SKIP) {
317169689Skan		newvol = nextvol;
318261188Spfg		wantnext = 1;
319261188Spfg	} else {
320261188Spfg		newvol = 0;
321261188Spfg		wantnext = 0;
322261188Spfg	}
323261188Spfg	while (newvol <= 0) {
324261188Spfg		if (tapesread == 0) {
325261188Spfg			fprintf(stderr, "%s%s%s%s%s",
326261188Spfg			    "You have not read any tapes yet.\n",
327261188Spfg			    "Unless you know which volume your",
328261188Spfg			    " file(s) are on you should start\n",
329169689Skan			    "with the last volume and work",
330169689Skan			    " towards the first.\n");
331169689Skan		} else {
332169689Skan			fprintf(stderr, "You have read volumes");
333169689Skan			strcpy(buf, ": ");
334169689Skan			for (i = 1; i < 32; i++)
335169689Skan				if (tapesread & (1 << i)) {
336169689Skan					fprintf(stderr, "%s%ld", buf, i);
337169689Skan					strcpy(buf, ", ");
338169689Skan				}
339169689Skan			fprintf(stderr, "\n");
340169689Skan		}
341169689Skan		do	{
342169689Skan			fprintf(stderr, "Specify next volume #: ");
343169689Skan			(void) fflush(stderr);
344169689Skan			(void) fgets(buf, BUFSIZ, terminal);
345169689Skan		} while (!feof(terminal) && buf[0] == '\n');
346169689Skan		if (feof(terminal))
347169689Skan			done(1);
348169689Skan		newvol = atoi(buf);
349169689Skan		if (newvol <= 0) {
350169689Skan			fprintf(stderr,
351169689Skan			    "Volume numbers are positive numerics\n");
352169689Skan		}
353261188Spfg	}
354261188Spfg	if (newvol == volno) {
355261188Spfg		tapesread |= 1 << volno;
356261188Spfg		return;
357261188Spfg	}
358261188Spfg	closemt();
359169689Skan	fprintf(stderr, "Mount tape volume %ld\n", newvol);
360261188Spfg	fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
361261188Spfg	fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
362261188Spfg	(void) fflush(stderr);
363261188Spfg	(void) fgets(buf, BUFSIZ, terminal);
364261188Spfg	if (feof(terminal))
365261188Spfg		done(1);
366261188Spfg	if (!strcmp(buf, "none\n")) {
367261188Spfg		terminateinput();
368261188Spfg		return;
369261188Spfg	}
370261188Spfg	if (buf[0] != '\n') {
371261188Spfg		(void) strcpy(magtape, buf);
372261188Spfg		magtape[strlen(magtape) - 1] = '\0';
373261188Spfg	}
374261188Spfg#ifdef RRESTORE
375261188Spfg	if (host)
376261188Spfg		mt = rmtopen(magtape, 0);
377261188Spfg	else
378261188Spfg#endif
379261188Spfg		mt = open(magtape, O_RDONLY, 0);
380261188Spfg
381261188Spfg	if (mt == -1) {
382261188Spfg		fprintf(stderr, "Cannot open %s\n", magtape);
383261188Spfg		volno = -1;
384261188Spfg		goto again;
385261188Spfg	}
386261188Spfggethdr:
387261188Spfg	volno = newvol;
388261188Spfg	setdumpnum();
389261188Spfg	FLUSHTAPEBUF();
390261188Spfg	if (gethead(&tmpbuf) == FAIL) {
391261188Spfg		dprintf(stdout, "header read failed at %ld blocks\n", blksread);
392261188Spfg		fprintf(stderr, "tape is not dump tape\n");
393261188Spfg		volno = 0;
394261188Spfg		goto again;
395261188Spfg	}
396261188Spfg	if (tmpbuf.c_volume != volno) {
397169689Skan		fprintf(stderr, "Wrong volume (%ld)\n", tmpbuf.c_volume);
398169689Skan		volno = 0;
399169689Skan		goto again;
400169689Skan	}
401169689Skan	if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
402169689Skan		fprintf(stderr, "Wrong dump date\n\tgot: %s",
403169689Skan			ctime(&tmpbuf.c_date));
404169689Skan		fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
405169689Skan		volno = 0;
406169689Skan		goto again;
407169689Skan	}
408169689Skan	tapesread |= 1 << volno;
409169689Skan	blksread = savecnt;
410169689Skan 	/*
411169689Skan 	 * If continuing from the previous volume, skip over any
412169689Skan 	 * blocks read already at the end of the previous volume.
413169689Skan 	 *
414169689Skan 	 * If coming to this volume at random, skip to the beginning
415169689Skan 	 * of the next record.
416169689Skan 	 */
417169689Skan	dprintf(stdout, "read %ld recs, tape starts with %ld\n",
418169689Skan		tpblksread, tmpbuf.c_firstrec);
419169689Skan 	if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
420169689Skan 		if (!wantnext) {
421169689Skan 			tpblksread = tmpbuf.c_firstrec;
422169689Skan 			for (i = tmpbuf.c_count; i > 0; i--)
423169689Skan 				readtape(buf);
424169689Skan 		} else if (tmpbuf.c_firstrec > 0 &&
425169689Skan			   tmpbuf.c_firstrec < tpblksread - 1) {
426169689Skan			/*
427169689Skan			 * -1 since we've read the volume header
428169689Skan			 */
429169689Skan 			i = tpblksread - tmpbuf.c_firstrec - 1;
430169689Skan			dprintf(stderr, "Skipping %ld duplicate record%s.\n",
431169689Skan				i, i > 1 ? "s" : "");
432169689Skan 			while (--i >= 0)
433169689Skan 				readtape(buf);
434169689Skan 		}
435169689Skan 	}
436169689Skan	if (curfile.action == USING) {
437169689Skan		if (volno == 1)
438169689Skan			panic("active file into volume 1\n");
439169689Skan		return;
440169689Skan	}
441169689Skan	/*
442169689Skan	 * Skip up to the beginning of the next record
443169689Skan	 */
444169689Skan	if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
445169689Skan		for (i = tmpbuf.c_count; i > 0; i--)
446169689Skan			readtape(buf);
447169689Skan	(void) gethead(&spcl);
448169689Skan	findinode(&spcl);
449261188Spfg	if (gettingfile) {
450261188Spfg		gettingfile = 0;
451261188Spfg		longjmp(restart, 1);
452261188Spfg	}
453261188Spfg}
454261188Spfg
455261188Spfg/*
456261188Spfg * Handle unexpected EOF.
457261188Spfg */
458261188Spfgstatic void
459261188Spfgterminateinput()
460261188Spfg{
461261188Spfg
462261188Spfg	if (gettingfile && curfile.action == USING) {
463261188Spfg		printf("Warning: %s %s\n",
464261188Spfg		    "End-of-input encountered while extracting", curfile.name);
465261188Spfg	}
466261188Spfg	curfile.name = "<name unknown>";
467261188Spfg	curfile.action = UNKNOWN;
468261188Spfg	curfile.dip = NULL;
469261188Spfg	curfile.ino = maxino;
470261188Spfg	if (gettingfile) {
471261188Spfg		gettingfile = 0;
472261188Spfg		longjmp(restart, 1);
473261188Spfg	}
474261188Spfg}
475261188Spfg
476261188Spfg/*
477261188Spfg * handle multiple dumps per tape by skipping forward to the
478261188Spfg * appropriate one.
479261188Spfg */
480261188Spfgstatic void
481261188Spfgsetdumpnum()
482261188Spfg{
483261188Spfg	struct mtop tcom;
484261188Spfg
485261188Spfg	if (dumpnum == 1 || volno != 1)
486261188Spfg		return;
487261188Spfg	if (pipein) {
488261188Spfg		fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
489261188Spfg		done(1);
490261188Spfg	}
491261188Spfg	tcom.mt_op = MTFSF;
492261188Spfg	tcom.mt_count = dumpnum - 1;
493261188Spfg#ifdef RRESTORE
494261188Spfg	if (host)
495261188Spfg		rmtioctl(MTFSF, dumpnum - 1);
496261188Spfg	else
497261188Spfg#endif
498261188Spfg		if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
499261188Spfg			fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
500261188Spfg}
501261188Spfg
502261188Spfgvoid
503261188Spfgprintdumpinfo()
504261188Spfg{
505261188Spfg	fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
506261188Spfg	fprintf(stdout, "Dumped from: %s",
507261188Spfg	    (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
508261188Spfg	if (spcl.c_host[0] == '\0')
509261188Spfg		return;
510261188Spfg	fprintf(stderr, "Level %ld dump of %s on %s:%s\n",
511261188Spfg		spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
512261188Spfg	fprintf(stderr, "Label: %s\n", spcl.c_label);
513261188Spfg}
514261188Spfg
515261188Spfgint
516261188Spfgextractfile(name)
517261188Spfg	char *name;
518261188Spfg{
519261188Spfg	int flags;
520261188Spfg	mode_t mode;
521261188Spfg	struct timeval timep[2];
522261188Spfg	struct entry *ep;
523261188Spfg
524261188Spfg	curfile.name = name;
525261188Spfg	curfile.action = USING;
526261188Spfg	timep[0].tv_sec = curfile.dip->di_atime;
527261188Spfg	timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
528261188Spfg	timep[1].tv_sec = curfile.dip->di_mtime;
529261188Spfg	timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
530261188Spfg	mode = curfile.dip->di_mode;
531261188Spfg	flags = curfile.dip->di_flags;
532261188Spfg	switch (mode & IFMT) {
533261188Spfg
534261188Spfg	default:
535261188Spfg		fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
536261188Spfg		skipfile();
537261188Spfg		return (FAIL);
538261188Spfg
539261188Spfg	case IFSOCK:
540261188Spfg		vprintf(stdout, "skipped socket %s\n", name);
541261188Spfg		skipfile();
542261188Spfg		return (GOOD);
543261188Spfg
544261188Spfg	case IFDIR:
545261188Spfg		if (mflag) {
546261188Spfg			ep = lookupname(name);
547261188Spfg			if (ep == NULL || ep->e_flags & EXTRACT)
548261188Spfg				panic("unextracted directory %s\n", name);
549261188Spfg			skipfile();
550261188Spfg			return (GOOD);
551261188Spfg		}
552261188Spfg		vprintf(stdout, "extract file %s\n", name);
553261188Spfg		return (genliteraldir(name, curfile.ino));
554261188Spfg
555261188Spfg	case IFLNK:
556261188Spfg		lnkbuf[0] = '\0';
557261188Spfg		pathlen = 0;
558261188Spfg		getfile(xtrlnkfile, xtrlnkskip);
559261188Spfg		if (pathlen == 0) {
560261188Spfg			vprintf(stdout,
561261188Spfg			    "%s: zero length symbolic link (ignored)\n", name);
562261188Spfg			return (GOOD);
563261188Spfg		}
564261188Spfg		return (linkit(lnkbuf, name, SYMLINK));
565261188Spfg
566261188Spfg	case IFIFO:
567261188Spfg		vprintf(stdout, "extract fifo %s\n", name);
568261188Spfg		if (Nflag) {
569261188Spfg			skipfile();
570261188Spfg			return (GOOD);
571261188Spfg		}
572261188Spfg		if (uflag && !Nflag)
573261188Spfg			(void)unlink(name);
574261188Spfg		if (mkfifo(name, mode) < 0) {
575261188Spfg			fprintf(stderr, "%s: cannot create fifo: %s\n",
576261188Spfg			    name, strerror(errno));
577261188Spfg			skipfile();
578261188Spfg			return (FAIL);
579261188Spfg		}
580261188Spfg		(void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
581261188Spfg		(void) chmod(name, mode);
582261188Spfg		(void) chflags(name, flags);
583261188Spfg		skipfile();
584261188Spfg		utimes(name, timep);
585261188Spfg		return (GOOD);
586261188Spfg
587261188Spfg	case IFCHR:
588261188Spfg	case IFBLK:
589		vprintf(stdout, "extract special file %s\n", name);
590		if (Nflag) {
591			skipfile();
592			return (GOOD);
593		}
594		if (uflag)
595			(void)unlink(name);
596		if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
597			fprintf(stderr, "%s: cannot create special file: %s\n",
598			    name, strerror(errno));
599			skipfile();
600			return (FAIL);
601		}
602		(void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
603		(void) chmod(name, mode);
604		(void) chflags(name, flags);
605		skipfile();
606		utimes(name, timep);
607		return (GOOD);
608
609	case IFREG:
610		vprintf(stdout, "extract file %s\n", name);
611		if (Nflag) {
612			skipfile();
613			return (GOOD);
614		}
615		if (uflag)
616			(void)unlink(name);
617		if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
618		    0666)) < 0) {
619			fprintf(stderr, "%s: cannot create file: %s\n",
620			    name, strerror(errno));
621			skipfile();
622			return (FAIL);
623		}
624		(void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
625		(void) fchmod(ofile, mode);
626		(void) fchflags(ofile, flags);
627		getfile(xtrfile, xtrskip);
628		(void) close(ofile);
629		utimes(name, timep);
630		return (GOOD);
631	}
632	/* NOTREACHED */
633}
634
635/*
636 * skip over bit maps on the tape
637 */
638void
639skipmaps()
640{
641
642	while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
643		skipfile();
644}
645
646/*
647 * skip over a file on the tape
648 */
649void
650skipfile()
651{
652
653	curfile.action = SKIP;
654	getfile(xtrnull, xtrnull);
655}
656
657/*
658 * Extract a file from the tape.
659 * When an allocated block is found it is passed to the fill function;
660 * when an unallocated block (hole) is found, a zeroed buffer is passed
661 * to the skip function.
662 */
663void
664getfile(fill, skip)
665	void	(*fill) __P((char *, long));
666	void	(*skip) __P((char *, long));
667{
668	register int i;
669	int curblk = 0;
670	quad_t size = spcl.c_dinode.di_size;
671	static char clearedbuf[MAXBSIZE];
672	char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
673	char junk[TP_BSIZE];
674
675	if (spcl.c_type == TS_END)
676		panic("ran off end of tape\n");
677	if (spcl.c_magic != NFS_MAGIC)
678		panic("not at beginning of a file\n");
679	if (!gettingfile && setjmp(restart) != 0)
680		return;
681	gettingfile++;
682loop:
683	for (i = 0; i < spcl.c_count; i++) {
684		if (spcl.c_addr[i]) {
685			readtape(&buf[curblk++][0]);
686			if (curblk == fssize / TP_BSIZE) {
687				(*fill)((char *)buf, (long)(size > TP_BSIZE ?
688				     fssize : (curblk - 1) * TP_BSIZE + size));
689				curblk = 0;
690			}
691		} else {
692			if (curblk > 0) {
693				(*fill)((char *)buf, (long)(size > TP_BSIZE ?
694				     curblk * TP_BSIZE :
695				     (curblk - 1) * TP_BSIZE + size));
696				curblk = 0;
697			}
698			(*skip)(clearedbuf, (long)(size > TP_BSIZE ?
699				TP_BSIZE : size));
700		}
701		if ((size -= TP_BSIZE) <= 0) {
702			for (i++; i < spcl.c_count; i++)
703				if (spcl.c_addr[i])
704					readtape(junk);
705			break;
706		}
707	}
708	if (gethead(&spcl) == GOOD && size > 0) {
709		if (spcl.c_type == TS_ADDR)
710			goto loop;
711		dprintf(stdout,
712			"Missing address (header) block for %s at %ld blocks\n",
713			curfile.name, blksread);
714	}
715	if (curblk > 0)
716		(*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
717	findinode(&spcl);
718	gettingfile = 0;
719}
720
721/*
722 * Write out the next block of a file.
723 */
724static void
725xtrfile(buf, size)
726	char	*buf;
727	long	size;
728{
729
730	if (Nflag)
731		return;
732	if (write(ofile, buf, (int) size) == -1) {
733		fprintf(stderr,
734		    "write error extracting inode %d, name %s\nwrite: %s\n",
735			curfile.ino, curfile.name, strerror(errno));
736		done(1);
737	}
738}
739
740/*
741 * Skip over a hole in a file.
742 */
743/* ARGSUSED */
744static void
745xtrskip(buf, size)
746	char *buf;
747	long size;
748{
749
750	if (lseek(ofile, size, SEEK_CUR) == -1) {
751		fprintf(stderr,
752		    "seek error extracting inode %d, name %s\nlseek: %s\n",
753			curfile.ino, curfile.name, strerror(errno));
754		done(1);
755	}
756}
757
758/*
759 * Collect the next block of a symbolic link.
760 */
761static void
762xtrlnkfile(buf, size)
763	char	*buf;
764	long	size;
765{
766
767	pathlen += size;
768	if (pathlen > MAXPATHLEN) {
769		fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
770		    curfile.name, lnkbuf, buf, pathlen);
771		done(1);
772	}
773	(void) strcat(lnkbuf, buf);
774}
775
776/*
777 * Skip over a hole in a symbolic link (should never happen).
778 */
779/* ARGSUSED */
780static void
781xtrlnkskip(buf, size)
782	char *buf;
783	long size;
784{
785
786	fprintf(stderr, "unallocated block in symbolic link %s\n",
787		curfile.name);
788	done(1);
789}
790
791/*
792 * Collect the next block of a bit map.
793 */
794static void
795xtrmap(buf, size)
796	char	*buf;
797	long	size;
798{
799
800	memmove(map, buf, size);
801	map += size;
802}
803
804/*
805 * Skip over a hole in a bit map (should never happen).
806 */
807/* ARGSUSED */
808static void
809xtrmapskip(buf, size)
810	char *buf;
811	long size;
812{
813
814	panic("hole in map\n");
815	map += size;
816}
817
818/*
819 * Noop, when an extraction function is not needed.
820 */
821/* ARGSUSED */
822void
823xtrnull(buf, size)
824	char *buf;
825	long size;
826{
827
828	return;
829}
830
831/*
832 * Read TP_BSIZE blocks from the input.
833 * Handle read errors, and end of media.
834 */
835static void
836readtape(buf)
837	char *buf;
838{
839	long rd, newvol, i;
840	int cnt, seek_failed;
841
842	if (blkcnt < numtrec) {
843		memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
844		blksread++;
845		tpblksread++;
846		return;
847	}
848	for (i = 0; i < ntrec; i++)
849		((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
850	if (numtrec == 0)
851		numtrec = ntrec;
852	cnt = ntrec * TP_BSIZE;
853	rd = 0;
854getmore:
855#ifdef RRESTORE
856	if (host)
857		i = rmtread(&tapebuf[rd], cnt);
858	else
859#endif
860		i = read(mt, &tapebuf[rd], cnt);
861	/*
862	 * Check for mid-tape short read error.
863	 * If found, skip rest of buffer and start with the next.
864	 */
865	if (!pipein && numtrec < ntrec && i > 0) {
866		dprintf(stdout, "mid-media short read error.\n");
867		numtrec = ntrec;
868	}
869	/*
870	 * Handle partial block read.
871	 */
872	if (pipein && i == 0 && rd > 0)
873		i = rd;
874	else if (i > 0 && i != ntrec * TP_BSIZE) {
875		if (pipein) {
876			rd += i;
877			cnt -= i;
878			if (cnt > 0)
879				goto getmore;
880			i = rd;
881		} else {
882			/*
883			 * Short read. Process the blocks read.
884			 */
885			if (i % TP_BSIZE != 0)
886				vprintf(stdout,
887				    "partial block read: %ld should be %ld\n",
888				    i, ntrec * TP_BSIZE);
889			numtrec = i / TP_BSIZE;
890		}
891	}
892	/*
893	 * Handle read error.
894	 */
895	if (i < 0) {
896		fprintf(stderr, "Tape read error while ");
897		switch (curfile.action) {
898		default:
899			fprintf(stderr, "trying to set up tape\n");
900			break;
901		case UNKNOWN:
902			fprintf(stderr, "trying to resynchronize\n");
903			break;
904		case USING:
905			fprintf(stderr, "restoring %s\n", curfile.name);
906			break;
907		case SKIP:
908			fprintf(stderr, "skipping over inode %d\n",
909				curfile.ino);
910			break;
911		}
912		if (!yflag && !reply("continue"))
913			done(1);
914		i = ntrec * TP_BSIZE;
915		memset(tapebuf, 0, i);
916#ifdef RRESTORE
917		if (host)
918			seek_failed = (rmtseek(i, 1) < 0);
919		else
920#endif
921			seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
922
923		if (seek_failed) {
924			fprintf(stderr,
925			    "continuation failed: %s\n", strerror(errno));
926			done(1);
927		}
928	}
929	/*
930	 * Handle end of tape.
931	 */
932	if (i == 0) {
933		vprintf(stdout, "End-of-tape encountered\n");
934		if (!pipein) {
935			newvol = volno + 1;
936			volno = 0;
937			numtrec = 0;
938			getvol(newvol);
939			readtape(buf);
940			return;
941		}
942		if (rd % TP_BSIZE != 0)
943			panic("partial block read: %d should be %d\n",
944				rd, ntrec * TP_BSIZE);
945		terminateinput();
946		memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
947	}
948	blkcnt = 0;
949	memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
950	blksread++;
951	tpblksread++;
952}
953
954static void
955findtapeblksize()
956{
957	register long i;
958
959	for (i = 0; i < ntrec; i++)
960		((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
961	blkcnt = 0;
962#ifdef RRESTORE
963	if (host)
964		i = rmtread(tapebuf, ntrec * TP_BSIZE);
965	else
966#endif
967		i = read(mt, tapebuf, ntrec * TP_BSIZE);
968
969	if (i <= 0) {
970		fprintf(stderr, "tape read error: %s\n", strerror(errno));
971		done(1);
972	}
973	if (i % TP_BSIZE != 0) {
974		fprintf(stderr, "Tape block size (%ld) %s (%d)\n",
975			i, "is not a multiple of dump block size", TP_BSIZE);
976		done(1);
977	}
978	ntrec = i / TP_BSIZE;
979	numtrec = ntrec;
980	vprintf(stdout, "Tape block size is %ld\n", ntrec);
981}
982
983void
984closemt()
985{
986
987	if (mt < 0)
988		return;
989#ifdef RRESTORE
990	if (host)
991		rmtclose();
992	else
993#endif
994		(void) close(mt);
995}
996
997/*
998 * Read the next block from the tape.
999 * Check to see if it is one of several vintage headers.
1000 * If it is an old style header, convert it to a new style header.
1001 * If it is not any valid header, return an error.
1002 */
1003static int
1004gethead(buf)
1005	struct s_spcl *buf;
1006{
1007	long i;
1008	union {
1009		quad_t	qval;
1010		long	val[2];
1011	} qcvt;
1012	union u_ospcl {
1013		char dummy[TP_BSIZE];
1014		struct	s_ospcl {
1015			long	c_type;
1016			long	c_date;
1017			long	c_ddate;
1018			long	c_volume;
1019			long	c_tapea;
1020			u_short	c_inumber;
1021			long	c_magic;
1022			long	c_checksum;
1023			struct odinode {
1024				unsigned short odi_mode;
1025				u_short	odi_nlink;
1026				u_short	odi_uid;
1027				u_short	odi_gid;
1028				long	odi_size;
1029				long	odi_rdev;
1030				char	odi_addr[36];
1031				long	odi_atime;
1032				long	odi_mtime;
1033				long	odi_ctime;
1034			} c_dinode;
1035			long	c_count;
1036			char	c_addr[256];
1037		} s_ospcl;
1038	} u_ospcl;
1039
1040	if (!cvtflag) {
1041		readtape((char *)buf);
1042		if (buf->c_magic != NFS_MAGIC) {
1043			if (swabl(buf->c_magic) != NFS_MAGIC)
1044				return (FAIL);
1045			if (!Bcvt) {
1046				vprintf(stdout, "Note: Doing Byte swapping\n");
1047				Bcvt = 1;
1048			}
1049		}
1050		if (checksum((int *)buf) == FAIL)
1051			return (FAIL);
1052		if (Bcvt) {
1053			swabst((u_char *)"8l4s31l", (u_char *)buf);
1054			swabst((u_char *)"l",(u_char *) &buf->c_level);
1055			swabst((u_char *)"2l",(u_char *) &buf->c_flags);
1056		}
1057		goto good;
1058	}
1059	readtape((char *)(&u_ospcl.s_ospcl));
1060	memset(buf, 0, (long)TP_BSIZE);
1061	buf->c_type = u_ospcl.s_ospcl.c_type;
1062	buf->c_date = u_ospcl.s_ospcl.c_date;
1063	buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1064	buf->c_volume = u_ospcl.s_ospcl.c_volume;
1065	buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1066	buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1067	buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1068	buf->c_magic = u_ospcl.s_ospcl.c_magic;
1069	buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1070	buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1071	buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1072	buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1073	buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
1074	buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1075	buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
1076	buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1077	buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1078	buf->c_count = u_ospcl.s_ospcl.c_count;
1079	memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256);
1080	if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
1081	    checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
1082		return(FAIL);
1083	buf->c_magic = NFS_MAGIC;
1084
1085good:
1086	if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
1087	    (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
1088		qcvt.qval = buf->c_dinode.di_size;
1089		if (qcvt.val[0] || qcvt.val[1]) {
1090			printf("Note: Doing Quad swapping\n");
1091			Qcvt = 1;
1092		}
1093	}
1094	if (Qcvt) {
1095		qcvt.qval = buf->c_dinode.di_size;
1096		i = qcvt.val[1];
1097		qcvt.val[1] = qcvt.val[0];
1098		qcvt.val[0] = i;
1099		buf->c_dinode.di_size = qcvt.qval;
1100	}
1101
1102	switch (buf->c_type) {
1103
1104	case TS_CLRI:
1105	case TS_BITS:
1106		/*
1107		 * Have to patch up missing information in bit map headers
1108		 */
1109		buf->c_inumber = 0;
1110		buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
1111		for (i = 0; i < buf->c_count; i++)
1112			buf->c_addr[i]++;
1113		break;
1114
1115	case TS_TAPE:
1116		if ((buf->c_flags & DR_NEWINODEFMT) == 0)
1117			oldinofmt = 1;
1118		/* fall through */
1119	case TS_END:
1120		buf->c_inumber = 0;
1121		break;
1122
1123	case TS_INODE:
1124	case TS_ADDR:
1125		break;
1126
1127	default:
1128		panic("gethead: unknown inode type %d\n", buf->c_type);
1129		break;
1130	}
1131	/*
1132	 * If we are restoring a filesystem with old format inodes,
1133	 * copy the uid/gid to the new location.
1134	 */
1135	if (oldinofmt) {
1136		buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
1137		buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
1138	}
1139	if (dflag)
1140		accthdr(buf);
1141	return(GOOD);
1142}
1143
1144/*
1145 * Check that a header is where it belongs and predict the next header
1146 */
1147static void
1148accthdr(header)
1149	struct s_spcl *header;
1150{
1151	static ino_t previno = 0x7fffffff;
1152	static int prevtype;
1153	static long predict;
1154	long blks, i;
1155
1156	if (header->c_type == TS_TAPE) {
1157		fprintf(stderr, "Volume header (%s inode format) ",
1158		    oldinofmt ? "old" : "new");
1159 		if (header->c_firstrec)
1160 			fprintf(stderr, "begins with record %ld",
1161 				header->c_firstrec);
1162 		fprintf(stderr, "\n");
1163		previno = 0x7fffffff;
1164		return;
1165	}
1166	if (previno == 0x7fffffff)
1167		goto newcalc;
1168	switch (prevtype) {
1169	case TS_BITS:
1170		fprintf(stderr, "Dumped inodes map header");
1171		break;
1172	case TS_CLRI:
1173		fprintf(stderr, "Used inodes map header");
1174		break;
1175	case TS_INODE:
1176		fprintf(stderr, "File header, ino %d", previno);
1177		break;
1178	case TS_ADDR:
1179		fprintf(stderr, "File continuation header, ino %d", previno);
1180		break;
1181	case TS_END:
1182		fprintf(stderr, "End of tape header");
1183		break;
1184	}
1185	if (predict != blksread - 1)
1186		fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
1187			predict, blksread - 1);
1188	fprintf(stderr, "\n");
1189newcalc:
1190	blks = 0;
1191	if (header->c_type != TS_END)
1192		for (i = 0; i < header->c_count; i++)
1193			if (header->c_addr[i] != 0)
1194				blks++;
1195	predict = blks;
1196	blksread = 0;
1197	prevtype = header->c_type;
1198	previno = header->c_inumber;
1199}
1200
1201/*
1202 * Find an inode header.
1203 * Complain if had to skip, and complain is set.
1204 */
1205static void
1206findinode(header)
1207	struct s_spcl *header;
1208{
1209	static long skipcnt = 0;
1210	long i;
1211	char buf[TP_BSIZE];
1212
1213	curfile.name = "<name unknown>";
1214	curfile.action = UNKNOWN;
1215	curfile.dip = NULL;
1216	curfile.ino = 0;
1217	do {
1218		if (header->c_magic != NFS_MAGIC) {
1219			skipcnt++;
1220			while (gethead(header) == FAIL ||
1221			    header->c_date != dumpdate)
1222				skipcnt++;
1223		}
1224		switch (header->c_type) {
1225
1226		case TS_ADDR:
1227			/*
1228			 * Skip up to the beginning of the next record
1229			 */
1230			for (i = 0; i < header->c_count; i++)
1231				if (header->c_addr[i])
1232					readtape(buf);
1233			while (gethead(header) == FAIL ||
1234			    header->c_date != dumpdate)
1235				skipcnt++;
1236			break;
1237
1238		case TS_INODE:
1239			curfile.dip = &header->c_dinode;
1240			curfile.ino = header->c_inumber;
1241			break;
1242
1243		case TS_END:
1244			curfile.ino = maxino;
1245			break;
1246
1247		case TS_CLRI:
1248			curfile.name = "<file removal list>";
1249			break;
1250
1251		case TS_BITS:
1252			curfile.name = "<file dump list>";
1253			break;
1254
1255		case TS_TAPE:
1256			panic("unexpected tape header\n");
1257			/* NOTREACHED */
1258
1259		default:
1260			panic("unknown tape header type %d\n", spcl.c_type);
1261			/* NOTREACHED */
1262
1263		}
1264	} while (header->c_type == TS_ADDR);
1265	if (skipcnt > 0)
1266		fprintf(stderr, "resync restore, skipped %ld blocks\n",
1267		    skipcnt);
1268	skipcnt = 0;
1269}
1270
1271static int
1272checksum(buf)
1273	register int *buf;
1274{
1275	register int i, j;
1276
1277	j = sizeof(union u_spcl) / sizeof(int);
1278	i = 0;
1279	if(!Bcvt) {
1280		do
1281			i += *buf++;
1282		while (--j);
1283	} else {
1284		/* What happens if we want to read restore tapes
1285			for a 16bit int machine??? */
1286		do
1287			i += swabl(*buf++);
1288		while (--j);
1289	}
1290
1291	if (i != CHECKSUM) {
1292		fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1293			curfile.ino, curfile.name);
1294		return(FAIL);
1295	}
1296	return(GOOD);
1297}
1298
1299#ifdef RRESTORE
1300#if __STDC__
1301#include <stdarg.h>
1302#else
1303#include <varargs.h>
1304#endif
1305
1306void
1307#if __STDC__
1308msg(const char *fmt, ...)
1309#else
1310msg(fmt, va_alist)
1311	char *fmt;
1312	va_dcl
1313#endif
1314{
1315	va_list ap;
1316#if __STDC__
1317	va_start(ap, fmt);
1318#else
1319	va_start(ap);
1320#endif
1321	(void)vfprintf(stderr, fmt, ap);
1322	va_end(ap);
1323}
1324#endif /* RRESTORE */
1325
1326static u_char *
1327swabshort(sp, n)
1328	register u_char *sp;
1329	register int n;
1330{
1331	char c;
1332
1333	while (--n >= 0) {
1334		c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1335		sp += 2;
1336	}
1337	return (sp);
1338}
1339
1340static u_char *
1341swablong(sp, n)
1342	register u_char *sp;
1343	register int n;
1344{
1345	char c;
1346
1347	while (--n >= 0) {
1348		c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1349		c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1350		sp += 4;
1351	}
1352	return (sp);
1353}
1354
1355void
1356swabst(cp, sp)
1357	register u_char *cp, *sp;
1358{
1359	int n = 0;
1360
1361	while (*cp) {
1362		switch (*cp) {
1363		case '0': case '1': case '2': case '3': case '4':
1364		case '5': case '6': case '7': case '8': case '9':
1365			n = (n * 10) + (*cp++ - '0');
1366			continue;
1367
1368		case 's': case 'w': case 'h':
1369			if (n == 0)
1370				n = 1;
1371			sp = swabshort(sp, n);
1372			break;
1373
1374		case 'l':
1375			if (n == 0)
1376				n = 1;
1377			sp = swablong(sp, n);
1378			break;
1379
1380		default: /* Any other character, like 'b' counts as byte. */
1381			if (n == 0)
1382				n = 1;
1383			sp += n;
1384			break;
1385		}
1386		cp++;
1387		n = 0;
1388	}
1389}
1390
1391static u_long
1392swabl(x)
1393	u_long x;
1394{
1395	swabst((u_char *)"l", (u_char *)&x);
1396	return (x);
1397}
1398