tape.c revision 96113
159191Skris/*
259191Skris * Copyright (c) 1983, 1993
359191Skris *	The Regents of the University of California.  All rights reserved.
459191Skris * (c) UNIX System Laboratories, Inc.
559191Skris * All or some portions of this file are derived from material licensed
659191Skris * to the University of California by American Telephone and Telegraph
759191Skris * Co. or Unix System Laboratories, Inc. and are reproduced herein with
859191Skris * the permission of UNIX System Laboratories, Inc.
959191Skris *
1059191Skris * Redistribution and use in source and binary forms, with or without
1159191Skris * modification, are permitted provided that the following conditions
1259191Skris * are met:
1359191Skris * 1. Redistributions of source code must retain the above copyright
1459191Skris *    notice, this list of conditions and the following disclaimer.
1559191Skris * 2. Redistributions in binary form must reproduce the above copyright
1659191Skris *    notice, this list of conditions and the following disclaimer in the
1759191Skris *    documentation and/or other materials provided with the distribution.
1859191Skris * 3. All advertising materials mentioning features or use of this software
1959191Skris *    must display the following acknowledgement:
2059191Skris *	This product includes software developed by the University of
2159191Skris *	California, Berkeley and its contributors.
2259191Skris * 4. Neither the name of the University nor the names of its contributors
2359191Skris *    may be used to endorse or promote products derived from this software
2459191Skris *    without specific prior written permission.
2559191Skris *
2659191Skris * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2759191Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2859191Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2959191Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3059191Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3159191Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3259191Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3359191Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3459191Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3559191Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3659191Skris * SUCH DAMAGE.
3759191Skris */
3859191Skris
3959191Skris#ifndef lint
4059191Skris#if 0
4159191Skrisstatic char sccsid[] = "@(#)tape.c	8.9 (Berkeley) 5/1/95";
4259191Skris#endif
4359191Skrisstatic const char rcsid[] =
4459191Skris  "$FreeBSD: head/sbin/restore/tape.c 96113 2002-05-06 15:15:51Z iedowse $";
4559191Skris#endif /* not lint */
4659191Skris
4759191Skris#include <sys/param.h>
4859191Skris#include <sys/file.h>
4959191Skris#include <sys/mtio.h>
5059191Skris#include <sys/stat.h>
5159191Skris#include <sys/time.h>
5259191Skris
5359191Skris#include <ufs/ufs/dinode.h>
5459191Skris#include <protocols/dumprestore.h>
5559191Skris
5659191Skris#include <errno.h>
5759191Skris#include <paths.h>
5859191Skris#include <setjmp.h>
5959191Skris#include <stdio.h>
6059191Skris#include <stdlib.h>
6159191Skris#include <string.h>
6259191Skris#include <time.h>
6359191Skris#include <unistd.h>
6459191Skris
6559191Skris#include "restore.h"
6659191Skris#include "extern.h"
67100936Snectar
68109998Smarkmstatic long	fssize = MAXBSIZE;
6959191Skrisstatic int	mt = -1;
70142425Snectarstatic int	pipein = 0;
71142425Snectarstatic char	*magtape;
7259191Skrisstatic int	blkcnt;
7359191Skrisstatic int	numtrec;
74205128Ssimonstatic char	*tapebuf;
75205128Ssimonstatic union	u_spcl endoftapemark;
7659191Skrisstatic long	blksread;		/* blocks read since last header */
7759191Skrisstatic long	tapeaddr = 0;		/* current TP_BSIZE tape record */
7859191Skrisstatic long	tapesread;
7959191Skrisstatic jmp_buf	restart;
8059191Skrisstatic int	gettingfile = 0;	/* restart has a valid frame */
8159191Skrisstatic char	*host = NULL;
8259191Skris
8359191Skrisstatic int	ofile;
8459191Skrisstatic char	*map;
8559191Skrisstatic char	lnkbuf[MAXPATHLEN + 1];
8659191Skrisstatic int	pathlen;
8759191Skris
8859191Skrisint		oldinofmt;	/* old inode format conversion required */
8959191Skrisint		Bcvt;		/* Swap Bytes (for CCI or sun) */
9059191Skrisstatic int	Qcvt;		/* Swap quads (for sun) */
9159191Skris
9259191Skris#define	FLUSHTAPEBUF()	blkcnt = ntrec + 1
9359191Skris
9459191Skrisstatic void	 accthdr(struct s_spcl *);
9559191Skrisstatic int	 checksum(int *);
9659191Skrisstatic void	 findinode(struct s_spcl *);
9759191Skrisstatic void	 findtapeblksize(void);
98109998Smarkmstatic int	 gethead(struct s_spcl *);
9959191Skrisstatic void	 readtape(char *);
10059191Skrisstatic void	 setdumpnum(void);
101238405Sjkimstatic u_long	 swabl(u_long);
102238405Sjkimstatic u_char	*swablong(u_char *, int);
10359191Skrisstatic u_char	*swabshort(u_char *, int);
104238405Sjkimstatic void	 terminateinput(void);
10559191Skrisstatic void	 xtrfile(char *, long);
106109998Smarkmstatic void	 xtrlnkfile(char *, long);
10759191Skrisstatic void	 xtrlnkskip(char *, long);
10859191Skrisstatic void	 xtrmap(char *, long);
10959191Skrisstatic void	 xtrmapskip(char *, long);
11059191Skrisstatic void	 xtrskip(char *, long);
11159191Skris
11259191Skrisstatic int readmapflag;
11359191Skris
11459191Skris/*
115194206Ssimon * Set up an input source
116194206Ssimon */
117194206Ssimonvoid
118194206Ssimonsetinput(char *source)
119194206Ssimon{
120194206Ssimon	FLUSHTAPEBUF();
121194206Ssimon	if (bflag)
122194206Ssimon		newtapebuf(ntrec);
123194206Ssimon	else
124109998Smarkm		newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
12559191Skris	terminal = stdin;
12659191Skris
12759191Skris#ifdef RRESTORE
12859191Skris	if (strchr(source, ':')) {
12959191Skris		host = source;
13059191Skris		source = strchr(host, ':');
13159191Skris		*source++ = '\0';
13259191Skris		if (rmthost(host) == 0)
13359191Skris			done(1);
13459191Skris	} else
135109998Smarkm#endif
13659191Skris	if (strcmp(source, "-") == 0) {
13759191Skris		/*
13859191Skris		 * Since input is coming from a pipe we must establish
13959191Skris		 * our own connection to the terminal.
14059191Skris		 */
14159191Skris		terminal = fopen(_PATH_TTY, "r");
14259191Skris		if (terminal == NULL) {
14359191Skris			(void)fprintf(stderr, "cannot open %s: %s\n",
14459191Skris			    _PATH_TTY, strerror(errno));
145109998Smarkm			terminal = fopen(_PATH_DEVNULL, "r");
14659191Skris			if (terminal == NULL) {
14759191Skris				(void)fprintf(stderr, "cannot open %s: %s\n",
14859191Skris				    _PATH_DEVNULL, strerror(errno));
14959191Skris				done(1);
15059191Skris			}
15159191Skris		}
15259191Skris		pipein++;
15359191Skris	}
15459191Skris	setuid(getuid());	/* no longer need or want root privileges */
15559191Skris	magtape = strdup(source);
156109998Smarkm	if (magtape == NULL) {
15759191Skris		fprintf(stderr, "Cannot allocate space for magtape buffer\n");
15859191Skris		done(1);
15959191Skris	}
16059191Skris}
16159191Skris
16259191Skrisvoid
16359191Skrisnewtapebuf(long size)
164109998Smarkm{
165109998Smarkm	static int tapebufsize = -1;
166109998Smarkm
167109998Smarkm	ntrec = size;
168109998Smarkm	if (size <= tapebufsize)
169142425Snectar		return;
170142425Snectar	if (tapebuf != NULL)
171109998Smarkm		free(tapebuf);
172109998Smarkm	tapebuf = malloc(size * TP_BSIZE);
173238405Sjkim	if (tapebuf == NULL) {
174238405Sjkim		fprintf(stderr, "Cannot allocate space for tape buffer\n");
175109998Smarkm		done(1);
176109998Smarkm	}
177109998Smarkm	tapebufsize = size;
178109998Smarkm}
179109998Smarkm
180142425Snectar/*
181142425Snectar * Verify that the tape drive can be accessed and
182109998Smarkm * that it actually is a dump tape.
183109998Smarkm */
184238405Sjkimvoid
185109998Smarkmsetup(void)
186109998Smarkm{
187109998Smarkm	int i, j, *ip;
188109998Smarkm	struct stat stbuf;
189109998Smarkm
190142425Snectar	vprintf(stdout, "Verify tape and initialize maps\n");
191142425Snectar#ifdef RRESTORE
192109998Smarkm	if (host)
193109998Smarkm		mt = rmtopen(magtape, 0);
194238405Sjkim	else
195238405Sjkim#endif
196109998Smarkm	if (pipein)
197109998Smarkm		mt = 0;
198238405Sjkim	else
199238405Sjkim		mt = open(magtape, O_RDONLY, 0);
200238405Sjkim	if (mt < 0) {
201109998Smarkm		fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
202238405Sjkim		done(1);
203162911Ssimon	}
204162911Ssimon	volno = 1;
205162911Ssimon	setdumpnum();
206162911Ssimon	FLUSHTAPEBUF();
207162911Ssimon	if (!pipein && !bflag)
208162911Ssimon		findtapeblksize();
209162911Ssimon	if (gethead(&spcl) == FAIL) {
210162911Ssimon		blkcnt--; /* push back this block */
211162911Ssimon		blksread--;
212162911Ssimon		cvtflag++;
213162911Ssimon		if (gethead(&spcl) == FAIL) {
214162911Ssimon			fprintf(stderr, "Tape is not a dump tape\n");
215162911Ssimon			done(1);
216162911Ssimon		}
217162911Ssimon		fprintf(stderr, "Converting to new file system format.\n");
218162911Ssimon	}
219162911Ssimon	if (pipein) {
220162911Ssimon		endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
221162911Ssimon		endoftapemark.s_spcl.c_type = TS_END;
222162911Ssimon		ip = (int *)&endoftapemark;
223162911Ssimon		j = sizeof(union u_spcl) / sizeof(int);
224162911Ssimon		i = 0;
225162911Ssimon		do
226162911Ssimon			i += *ip++;
227162911Ssimon		while (--j);
228162911Ssimon		endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
229162911Ssimon	}
23059191Skris	if (vflag || command == 't')
231		printdumpinfo();
232	dumptime = _time32_to_time(spcl.c_ddate);
233	dumpdate = _time32_to_time(spcl.c_date);
234	if (stat(".", &stbuf) < 0) {
235		fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
236		done(1);
237	}
238	if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE )
239		fssize = TP_BSIZE;
240	if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE)
241		fssize = stbuf.st_blksize;
242	if (((fssize - 1) & fssize) != 0) {
243		fprintf(stderr, "bad block size %ld\n", fssize);
244		done(1);
245	}
246	if (spcl.c_volume != 1) {
247		fprintf(stderr, "Tape is not volume 1 of the dump\n");
248		done(1);
249	}
250	if (gethead(&spcl) == FAIL) {
251		dprintf(stdout, "header read failed at %ld blocks\n", blksread);
252		panic("no header after volume mark!\n");
253	}
254	findinode(&spcl);
255	if (spcl.c_type != TS_CLRI) {
256		fprintf(stderr, "Cannot find file removal list\n");
257		done(1);
258	}
259	maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
260	dprintf(stdout, "maxino = %d\n", maxino);
261	map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
262	if (map == NULL)
263		panic("no memory for active inode map\n");
264	usedinomap = map;
265	curfile.action = USING;
266	getfile(xtrmap, xtrmapskip);
267	if (spcl.c_type != TS_BITS) {
268		fprintf(stderr, "Cannot find file dump list\n");
269		done(1);
270	}
271	map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
272	if (map == (char *)NULL)
273		panic("no memory for file dump list\n");
274	dumpmap = map;
275	curfile.action = USING;
276	getfile(xtrmap, xtrmapskip);
277	/*
278	 * If there may be whiteout entries on the tape, pretend that the
279	 * whiteout inode exists, so that the whiteout entries can be
280	 * extracted.
281	 */
282	if (oldinofmt == 0)
283		SETINO(WINO, dumpmap);
284	/* 'r' restores don't call getvol() for tape 1, so mark it as read. */
285	if (command == 'r')
286		tapesread = 1;
287}
288
289/*
290 * Prompt user to load a new dump volume.
291 * "Nextvol" is the next suggested volume to use.
292 * This suggested volume is enforced when doing full
293 * or incremental restores, but can be overridden by
294 * the user when only extracting a subset of the files.
295 */
296void
297getvol(long nextvol)
298{
299	long newvol, prevtapea, savecnt, i;
300	union u_spcl tmpspcl;
301#	define tmpbuf tmpspcl.s_spcl
302	char buf[TP_BSIZE];
303
304	if (nextvol == 1) {
305		tapesread = 0;
306		gettingfile = 0;
307	}
308	prevtapea = tapeaddr;
309	savecnt = blksread;
310	if (pipein) {
311		if (nextvol != 1) {
312			panic("Changing volumes on pipe input?\n");
313			/* Avoid looping if we couldn't ask the user. */
314			if (yflag || ferror(terminal) || feof(terminal))
315				done(1);
316		}
317		if (volno == 1)
318			return;
319		goto gethdr;
320	}
321again:
322	if (pipein)
323		done(1); /* pipes do not get a second chance */
324	if (command == 'R' || command == 'r' || curfile.action != SKIP)
325		newvol = nextvol;
326	else
327		newvol = 0;
328	while (newvol <= 0) {
329		if (tapesread == 0) {
330			fprintf(stderr, "%s%s%s%s%s%s%s",
331			    "You have not read any tapes yet.\n",
332			    "If you are extracting just a few files,",
333			    " start with the last volume\n",
334			    "and work towards the first; restore",
335			    " can quickly skip tapes that\n",
336			    "have no further files to extract.",
337			    " Otherwise, begin with volume 1.\n");
338		} else {
339			fprintf(stderr, "You have read volumes");
340			strcpy(buf, ": ");
341			for (i = 0; i < 32; i++)
342				if (tapesread & (1 << i)) {
343					fprintf(stderr, "%s%ld", buf, i + 1);
344					strcpy(buf, ", ");
345				}
346			fprintf(stderr, "\n");
347		}
348		do	{
349			fprintf(stderr, "Specify next volume #: ");
350			(void) fflush(stderr);
351			if (fgets(buf, BUFSIZ, terminal) == NULL)
352				done(1);
353		} while (buf[0] == '\n');
354		newvol = atoi(buf);
355		if (newvol <= 0) {
356			fprintf(stderr,
357			    "Volume numbers are positive numerics\n");
358		}
359	}
360	if (newvol == volno) {
361		tapesread |= 1 << (volno - 1);
362		return;
363	}
364	closemt();
365	fprintf(stderr, "Mount tape volume %ld\n", newvol);
366	fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
367	fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
368	(void) fflush(stderr);
369	if (fgets(buf, BUFSIZ, terminal) == NULL)
370		done(1);
371	if (!strcmp(buf, "none\n")) {
372		terminateinput();
373		return;
374	}
375	if (buf[0] != '\n') {
376		(void) strcpy(magtape, buf);
377		magtape[strlen(magtape) - 1] = '\0';
378	}
379#ifdef RRESTORE
380	if (host)
381		mt = rmtopen(magtape, 0);
382	else
383#endif
384		mt = open(magtape, O_RDONLY, 0);
385
386	if (mt == -1) {
387		fprintf(stderr, "Cannot open %s\n", magtape);
388		volno = -1;
389		goto again;
390	}
391gethdr:
392	volno = newvol;
393	setdumpnum();
394	FLUSHTAPEBUF();
395	if (gethead(&tmpbuf) == FAIL) {
396		dprintf(stdout, "header read failed at %ld blocks\n", blksread);
397		fprintf(stderr, "tape is not dump tape\n");
398		volno = 0;
399		goto again;
400	}
401	if (tmpbuf.c_volume != volno) {
402		fprintf(stderr, "Wrong volume (%ld)\n", tmpbuf.c_volume);
403		volno = 0;
404		goto again;
405	}
406	if (_time32_to_time(tmpbuf.c_date) != dumpdate ||
407	    _time32_to_time(tmpbuf.c_ddate) != dumptime) {
408		time_t t = _time32_to_time(tmpbuf.c_date);
409		fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t));
410		fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
411		volno = 0;
412		goto again;
413	}
414	tapesread |= 1 << (volno - 1);
415	blksread = savecnt;
416 	/*
417 	 * If continuing from the previous volume, skip over any
418 	 * blocks read already at the end of the previous volume.
419 	 *
420 	 * If coming to this volume at random, skip to the beginning
421 	 * of the next record.
422 	 */
423	dprintf(stdout, "last rec %ld, tape starts with %ld\n", prevtapea,
424	    tmpbuf.c_tapea);
425 	if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
426 		if (curfile.action != USING) {
427			/*
428			 * XXX Dump incorrectly sets c_count to 1 in the
429			 * volume header of the first tape, so ignore
430			 * c_count when volno == 1.
431			 */
432			if (volno != 1)
433				for (i = tmpbuf.c_count; i > 0; i--)
434					readtape(buf);
435 		} else if (tmpbuf.c_tapea <= prevtapea) {
436			/*
437			 * Normally the value of c_tapea in the volume
438			 * header is the record number of the header itself.
439			 * However in the volume header following an EOT-
440			 * terminated tape, it is the record number of the
441			 * first continuation data block (dump bug?).
442			 *
443			 * The next record we want is `prevtapea + 1'.
444			 */
445 			i = prevtapea + 1 - tmpbuf.c_tapea;
446			dprintf(stderr, "Skipping %ld duplicate record%s.\n",
447				i, i > 1 ? "s" : "");
448 			while (--i >= 0)
449 				readtape(buf);
450 		}
451 	}
452	if (curfile.action == USING) {
453		if (volno == 1)
454			panic("active file into volume 1\n");
455		return;
456	}
457	(void) gethead(&spcl);
458	findinode(&spcl);
459	if (gettingfile) {
460		gettingfile = 0;
461		longjmp(restart, 1);
462	}
463}
464
465/*
466 * Handle unexpected EOF.
467 */
468static void
469terminateinput(void)
470{
471
472	if (gettingfile && curfile.action == USING) {
473		printf("Warning: %s %s\n",
474		    "End-of-input encountered while extracting", curfile.name);
475	}
476	curfile.name = "<name unknown>";
477	curfile.action = UNKNOWN;
478	curfile.dip = NULL;
479	curfile.ino = maxino;
480	if (gettingfile) {
481		gettingfile = 0;
482		longjmp(restart, 1);
483	}
484}
485
486/*
487 * handle multiple dumps per tape by skipping forward to the
488 * appropriate one.
489 */
490static void
491setdumpnum(void)
492{
493	struct mtop tcom;
494
495	if (dumpnum == 1 || volno != 1)
496		return;
497	if (pipein) {
498		fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
499		done(1);
500	}
501	tcom.mt_op = MTFSF;
502	tcom.mt_count = dumpnum - 1;
503#ifdef RRESTORE
504	if (host)
505		rmtioctl(MTFSF, dumpnum - 1);
506	else
507#endif
508		if (ioctl(mt, MTIOCTOP, (char *)&tcom) < 0)
509			fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
510}
511
512void
513printdumpinfo(void)
514{
515	time_t t;
516	t = _time32_to_time(spcl.c_date);
517	fprintf(stdout, "Dump   date: %s", ctime(&t));
518	t = _time32_to_time(spcl.c_ddate);
519	fprintf(stdout, "Dumped from: %s",
520	    (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&t));
521	if (spcl.c_host[0] == '\0')
522		return;
523	fprintf(stderr, "Level %ld dump of %s on %s:%s\n",
524		spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
525	fprintf(stderr, "Label: %s\n", spcl.c_label);
526}
527
528int
529extractfile(char *name)
530{
531	int flags;
532	uid_t uid;
533	gid_t gid;
534	mode_t mode;
535	struct timeval timep[2];
536	struct entry *ep;
537
538	curfile.name = name;
539	curfile.action = USING;
540	timep[0].tv_sec = curfile.dip->di_atime;
541	timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
542	timep[1].tv_sec = curfile.dip->di_mtime;
543	timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
544	uid = curfile.dip->di_uid;
545	gid = curfile.dip->di_gid;
546	mode = curfile.dip->di_mode;
547	flags = curfile.dip->di_flags;
548	switch (mode & IFMT) {
549
550	default:
551		fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
552		skipfile();
553		return (FAIL);
554
555	case IFSOCK:
556		vprintf(stdout, "skipped socket %s\n", name);
557		skipfile();
558		return (GOOD);
559
560	case IFDIR:
561		if (mflag) {
562			ep = lookupname(name);
563			if (ep == NULL || ep->e_flags & EXTRACT)
564				panic("unextracted directory %s\n", name);
565			skipfile();
566			return (GOOD);
567		}
568		vprintf(stdout, "extract file %s\n", name);
569		return (genliteraldir(name, curfile.ino));
570
571	case IFLNK:
572		lnkbuf[0] = '\0';
573		pathlen = 0;
574		getfile(xtrlnkfile, xtrlnkskip);
575		if (pathlen == 0) {
576			vprintf(stdout,
577			    "%s: zero length symbolic link (ignored)\n", name);
578			return (GOOD);
579		}
580		if (linkit(lnkbuf, name, SYMLINK) == GOOD) {
581			(void) lchown(name, uid, gid);
582			(void) lchmod(name, mode);
583			(void) lutimes(name, timep);
584			return (GOOD);
585		}
586		return (FAIL);
587
588	case IFIFO:
589		vprintf(stdout, "extract fifo %s\n", name);
590		if (Nflag) {
591			skipfile();
592			return (GOOD);
593		}
594		if (uflag && !Nflag)
595			(void)unlink(name);
596		if (mkfifo(name, mode) < 0) {
597			fprintf(stderr, "%s: cannot create fifo: %s\n",
598			    name, strerror(errno));
599			skipfile();
600			return (FAIL);
601		}
602		(void) chown(name, uid, gid);
603		(void) chmod(name, mode);
604		(void) utimes(name, timep);
605		(void) chflags(name, flags);
606		skipfile();
607		return (GOOD);
608
609	case IFCHR:
610	case IFBLK:
611		vprintf(stdout, "extract special file %s\n", name);
612		if (Nflag) {
613			skipfile();
614			return (GOOD);
615		}
616		if (uflag)
617			(void)unlink(name);
618		if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
619			fprintf(stderr, "%s: cannot create special file: %s\n",
620			    name, strerror(errno));
621			skipfile();
622			return (FAIL);
623		}
624		(void) chown(name, uid, gid);
625		(void) chmod(name, mode);
626		(void) utimes(name, timep);
627		(void) chflags(name, flags);
628		skipfile();
629		return (GOOD);
630
631	case IFREG:
632		vprintf(stdout, "extract file %s\n", name);
633		if (Nflag) {
634			skipfile();
635			return (GOOD);
636		}
637		if (uflag)
638			(void)unlink(name);
639		if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
640		    0666)) < 0) {
641			fprintf(stderr, "%s: cannot create file: %s\n",
642			    name, strerror(errno));
643			skipfile();
644			return (FAIL);
645		}
646		(void) fchown(ofile, uid, gid);
647		(void) fchmod(ofile, mode);
648		getfile(xtrfile, xtrskip);
649		(void) close(ofile);
650		utimes(name, timep);
651		(void) chflags(name, flags);
652		return (GOOD);
653	}
654	/* NOTREACHED */
655}
656
657/*
658 * skip over bit maps on the tape
659 */
660void
661skipmaps(void)
662{
663
664	while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
665		skipfile();
666}
667
668/*
669 * skip over a file on the tape
670 */
671void
672skipfile(void)
673{
674
675	curfile.action = SKIP;
676	getfile(xtrnull, xtrnull);
677}
678
679/*
680 * Extract a file from the tape.
681 * When an allocated block is found it is passed to the fill function;
682 * when an unallocated block (hole) is found, a zeroed buffer is passed
683 * to the skip function.
684 */
685void
686getfile(void (*fill)(char *, long), void (*skip)(char *, long))
687{
688	int i;
689	int curblk = 0;
690	quad_t size = spcl.c_dinode.di_size;
691	static char clearedbuf[MAXBSIZE];
692	char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
693	char junk[TP_BSIZE];
694
695	if (spcl.c_type == TS_END)
696		panic("ran off end of tape\n");
697	if (spcl.c_magic != NFS_MAGIC)
698		panic("not at beginning of a file\n");
699	if (!gettingfile && setjmp(restart) != 0)
700		return;
701	gettingfile++;
702loop:
703	for (i = 0; i < spcl.c_count; i++) {
704		if (readmapflag || spcl.c_addr[i]) {
705			readtape(&buf[curblk++][0]);
706			if (curblk == fssize / TP_BSIZE) {
707				(*fill)((char *)buf, (long)(size > TP_BSIZE ?
708				     fssize : (curblk - 1) * TP_BSIZE + size));
709				curblk = 0;
710			}
711		} else {
712			if (curblk > 0) {
713				(*fill)((char *)buf, (long)(size > TP_BSIZE ?
714				     curblk * TP_BSIZE :
715				     (curblk - 1) * TP_BSIZE + size));
716				curblk = 0;
717			}
718			(*skip)(clearedbuf, (long)(size > TP_BSIZE ?
719				TP_BSIZE : size));
720		}
721		if ((size -= TP_BSIZE) <= 0) {
722			for (i++; i < spcl.c_count; i++)
723				if (readmapflag || spcl.c_addr[i])
724					readtape(junk);
725			break;
726		}
727	}
728	if (gethead(&spcl) == GOOD && size > 0) {
729		if (spcl.c_type == TS_ADDR)
730			goto loop;
731		dprintf(stdout,
732			"Missing address (header) block for %s at %ld blocks\n",
733			curfile.name, blksread);
734	}
735	if (curblk > 0)
736		(*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
737	findinode(&spcl);
738	gettingfile = 0;
739}
740
741/*
742 * Write out the next block of a file.
743 */
744static void
745xtrfile(char *buf, long	size)
746{
747
748	if (Nflag)
749		return;
750	if (write(ofile, buf, (int) size) == -1) {
751		fprintf(stderr,
752		    "write error extracting inode %d, name %s\nwrite: %s\n",
753			curfile.ino, curfile.name, strerror(errno));
754	}
755}
756
757/*
758 * Skip over a hole in a file.
759 */
760/* ARGSUSED */
761static void
762xtrskip(char *buf, long size)
763{
764
765	if (lseek(ofile, size, SEEK_CUR) == -1) {
766		fprintf(stderr,
767		    "seek error extracting inode %d, name %s\nlseek: %s\n",
768			curfile.ino, curfile.name, strerror(errno));
769		done(1);
770	}
771}
772
773/*
774 * Collect the next block of a symbolic link.
775 */
776static void
777xtrlnkfile(char *buf, long size)
778{
779
780	pathlen += size;
781	if (pathlen > MAXPATHLEN) {
782		fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
783		    curfile.name, lnkbuf, buf, pathlen);
784		done(1);
785	}
786	(void) strcat(lnkbuf, buf);
787}
788
789/*
790 * Skip over a hole in a symbolic link (should never happen).
791 */
792/* ARGSUSED */
793static void
794xtrlnkskip(char *buf, long size)
795{
796
797	fprintf(stderr, "unallocated block in symbolic link %s\n",
798		curfile.name);
799	done(1);
800}
801
802/*
803 * Collect the next block of a bit map.
804 */
805static void
806xtrmap(char *buf, long size)
807{
808
809	memmove(map, buf, size);
810	map += size;
811}
812
813/*
814 * Skip over a hole in a bit map (should never happen).
815 */
816/* ARGSUSED */
817static void
818xtrmapskip(char *buf, long size)
819{
820
821	panic("hole in map\n");
822	map += size;
823}
824
825/*
826 * Noop, when an extraction function is not needed.
827 */
828/* ARGSUSED */
829void
830xtrnull(char *buf, long size)
831{
832
833	return;
834}
835
836/*
837 * Read TP_BSIZE blocks from the input.
838 * Handle read errors, and end of media.
839 */
840static void
841readtape(char *buf)
842{
843	long rd, newvol, i;
844	int cnt, seek_failed;
845
846	if (blkcnt < numtrec) {
847		memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
848		blksread++;
849		tapeaddr++;
850		return;
851	}
852	for (i = 0; i < ntrec; i++)
853		((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
854	if (numtrec == 0)
855		numtrec = ntrec;
856	cnt = ntrec * TP_BSIZE;
857	rd = 0;
858getmore:
859#ifdef RRESTORE
860	if (host)
861		i = rmtread(&tapebuf[rd], cnt);
862	else
863#endif
864		i = read(mt, &tapebuf[rd], cnt);
865	/*
866	 * Check for mid-tape short read error.
867	 * If found, skip rest of buffer and start with the next.
868	 */
869	if (!pipein && numtrec < ntrec && i > 0) {
870		dprintf(stdout, "mid-media short read error.\n");
871		numtrec = ntrec;
872	}
873	/*
874	 * Handle partial block read.
875	 */
876	if (pipein && i == 0 && rd > 0)
877		i = rd;
878	else if (i > 0 && i != ntrec * TP_BSIZE) {
879		if (pipein) {
880			rd += i;
881			cnt -= i;
882			if (cnt > 0)
883				goto getmore;
884			i = rd;
885		} else {
886			/*
887			 * Short read. Process the blocks read.
888			 */
889			if (i % TP_BSIZE != 0)
890				vprintf(stdout,
891				    "partial block read: %ld should be %ld\n",
892				    i, ntrec * TP_BSIZE);
893			numtrec = i / TP_BSIZE;
894		}
895	}
896	/*
897	 * Handle read error.
898	 */
899	if (i < 0) {
900		fprintf(stderr, "Tape read error while ");
901		switch (curfile.action) {
902		default:
903			fprintf(stderr, "trying to set up tape\n");
904			break;
905		case UNKNOWN:
906			fprintf(stderr, "trying to resynchronize\n");
907			break;
908		case USING:
909			fprintf(stderr, "restoring %s\n", curfile.name);
910			break;
911		case SKIP:
912			fprintf(stderr, "skipping over inode %d\n",
913				curfile.ino);
914			break;
915		}
916		if (!yflag && !reply("continue"))
917			done(1);
918		i = ntrec * TP_BSIZE;
919		memset(tapebuf, 0, i);
920#ifdef RRESTORE
921		if (host)
922			seek_failed = (rmtseek(i, 1) < 0);
923		else
924#endif
925			seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
926
927		if (seek_failed) {
928			fprintf(stderr,
929			    "continuation failed: %s\n", strerror(errno));
930			done(1);
931		}
932	}
933	/*
934	 * Handle end of tape.
935	 */
936	if (i == 0) {
937		vprintf(stdout, "End-of-tape encountered\n");
938		if (!pipein) {
939			newvol = volno + 1;
940			volno = 0;
941			numtrec = 0;
942			getvol(newvol);
943			readtape(buf);
944			return;
945		}
946		if (rd % TP_BSIZE != 0)
947			panic("partial block read: %d should be %d\n",
948				rd, ntrec * TP_BSIZE);
949		terminateinput();
950		memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
951	}
952	blkcnt = 0;
953	memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
954	blksread++;
955	tapeaddr++;
956}
957
958static void
959findtapeblksize(void)
960{
961	long i;
962
963	for (i = 0; i < ntrec; i++)
964		((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
965	blkcnt = 0;
966#ifdef RRESTORE
967	if (host)
968		i = rmtread(tapebuf, ntrec * TP_BSIZE);
969	else
970#endif
971		i = read(mt, tapebuf, ntrec * TP_BSIZE);
972
973	if (i <= 0) {
974		fprintf(stderr, "tape read error: %s\n", strerror(errno));
975		done(1);
976	}
977	if (i % TP_BSIZE != 0) {
978		fprintf(stderr, "Tape block size (%ld) %s (%d)\n",
979			i, "is not a multiple of dump block size", TP_BSIZE);
980		done(1);
981	}
982	ntrec = i / TP_BSIZE;
983	numtrec = ntrec;
984	vprintf(stdout, "Tape block size is %ld\n", ntrec);
985}
986
987void
988closemt(void)
989{
990
991	if (mt < 0)
992		return;
993#ifdef RRESTORE
994	if (host)
995		rmtclose();
996	else
997#endif
998		(void) close(mt);
999}
1000
1001/*
1002 * Read the next block from the tape.
1003 * Check to see if it is one of several vintage headers.
1004 * If it is an old style header, convert it to a new style header.
1005 * If it is not any valid header, return an error.
1006 */
1007static int
1008gethead(struct s_spcl *buf)
1009{
1010	long i;
1011	union {
1012		quad_t	qval;
1013		int32_t	val[2];
1014	} qcvt;
1015	union u_ospcl {
1016		char dummy[TP_BSIZE];
1017		struct	s_ospcl {
1018			int32_t	c_type;
1019			int32_t	c_date;
1020			int32_t	c_ddate;
1021			int32_t	c_volume;
1022			int32_t	c_tapea;
1023			u_short	c_inumber;
1024			int32_t	c_magic;
1025			int32_t	c_checksum;
1026			struct odinode {
1027				unsigned short odi_mode;
1028				u_short	odi_nlink;
1029				u_short	odi_uid;
1030				u_short	odi_gid;
1031				int32_t	odi_size;
1032				int32_t	odi_rdev;
1033				char	odi_addr[36];
1034				int32_t	odi_atime;
1035				int32_t	odi_mtime;
1036				int32_t	odi_ctime;
1037			} c_dinode;
1038			int32_t	c_count;
1039			char	c_addr[256];
1040		} s_ospcl;
1041	} u_ospcl;
1042
1043	if (!cvtflag) {
1044		readtape((char *)buf);
1045		if (buf->c_magic != NFS_MAGIC) {
1046			if (swabl(buf->c_magic) != NFS_MAGIC)
1047				return (FAIL);
1048			if (!Bcvt) {
1049				vprintf(stdout, "Note: Doing Byte swapping\n");
1050				Bcvt = 1;
1051			}
1052		}
1053		if (checksum((int *)buf) == FAIL)
1054			return (FAIL);
1055		if (Bcvt) {
1056			swabst((u_char *)"8l4s31l", (u_char *)buf);
1057			swabst((u_char *)"l",(u_char *) &buf->c_level);
1058			swabst((u_char *)"2l",(u_char *) &buf->c_flags);
1059		}
1060		goto good;
1061	}
1062	readtape((char *)(&u_ospcl.s_ospcl));
1063	memset(buf, 0, (long)TP_BSIZE);
1064	buf->c_type = u_ospcl.s_ospcl.c_type;
1065	buf->c_date = u_ospcl.s_ospcl.c_date;
1066	buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1067	buf->c_volume = u_ospcl.s_ospcl.c_volume;
1068	buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1069	buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1070	buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1071	buf->c_magic = u_ospcl.s_ospcl.c_magic;
1072	buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1073	buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1074	buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1075	buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1076	buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
1077	buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1078	buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
1079	buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1080	buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1081	buf->c_count = u_ospcl.s_ospcl.c_count;
1082	memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256);
1083	if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
1084	    checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
1085		return(FAIL);
1086	buf->c_magic = NFS_MAGIC;
1087
1088good:
1089	if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
1090	    (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
1091		qcvt.qval = buf->c_dinode.di_size;
1092		if (qcvt.val[0] || qcvt.val[1]) {
1093			printf("Note: Doing Quad swapping\n");
1094			Qcvt = 1;
1095		}
1096	}
1097	if (Qcvt) {
1098		qcvt.qval = buf->c_dinode.di_size;
1099		i = qcvt.val[1];
1100		qcvt.val[1] = qcvt.val[0];
1101		qcvt.val[0] = i;
1102		buf->c_dinode.di_size = qcvt.qval;
1103	}
1104	readmapflag = 0;
1105
1106	switch (buf->c_type) {
1107
1108	case TS_CLRI:
1109	case TS_BITS:
1110		/*
1111		 * Have to patch up missing information in bit map headers
1112		 */
1113		buf->c_inumber = 0;
1114		buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
1115		if (buf->c_count > TP_NINDIR)
1116			readmapflag = 1;
1117		else
1118			for (i = 0; i < buf->c_count; i++)
1119				buf->c_addr[i]++;
1120		break;
1121
1122	case TS_TAPE:
1123		if ((buf->c_flags & DR_NEWINODEFMT) == 0)
1124			oldinofmt = 1;
1125		/* fall through */
1126	case TS_END:
1127		buf->c_inumber = 0;
1128		break;
1129
1130	case TS_INODE:
1131	case TS_ADDR:
1132		break;
1133
1134	default:
1135		panic("gethead: unknown inode type %d\n", buf->c_type);
1136		break;
1137	}
1138	/*
1139	 * If we are restoring a filesystem with old format inodes,
1140	 * copy the uid/gid to the new location.
1141	 */
1142	if (oldinofmt) {
1143		buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
1144		buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
1145	}
1146	tapeaddr = buf->c_tapea;
1147	if (dflag)
1148		accthdr(buf);
1149	return(GOOD);
1150}
1151
1152/*
1153 * Check that a header is where it belongs and predict the next header
1154 */
1155static void
1156accthdr(struct s_spcl *header)
1157{
1158	static ino_t previno = 0x7fffffff;
1159	static int prevtype;
1160	static long predict;
1161	long blks, i;
1162
1163	if (header->c_type == TS_TAPE) {
1164		fprintf(stderr, "Volume header (%s inode format) ",
1165		    oldinofmt ? "old" : "new");
1166 		if (header->c_firstrec)
1167 			fprintf(stderr, "begins with record %ld",
1168 				header->c_firstrec);
1169 		fprintf(stderr, "\n");
1170		previno = 0x7fffffff;
1171		return;
1172	}
1173	if (previno == 0x7fffffff)
1174		goto newcalc;
1175	switch (prevtype) {
1176	case TS_BITS:
1177		fprintf(stderr, "Dumped inodes map header");
1178		break;
1179	case TS_CLRI:
1180		fprintf(stderr, "Used inodes map header");
1181		break;
1182	case TS_INODE:
1183		fprintf(stderr, "File header, ino %d", previno);
1184		break;
1185	case TS_ADDR:
1186		fprintf(stderr, "File continuation header, ino %d", previno);
1187		break;
1188	case TS_END:
1189		fprintf(stderr, "End of tape header");
1190		break;
1191	}
1192	if (predict != blksread - 1)
1193		fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
1194			predict, blksread - 1);
1195	fprintf(stderr, "\n");
1196newcalc:
1197	blks = 0;
1198	if (header->c_type != TS_END)
1199		for (i = 0; i < header->c_count; i++)
1200			if (readmapflag || header->c_addr[i] != 0)
1201				blks++;
1202	predict = blks;
1203	blksread = 0;
1204	prevtype = header->c_type;
1205	previno = header->c_inumber;
1206}
1207
1208/*
1209 * Find an inode header.
1210 * Complain if had to skip.
1211 */
1212static void
1213findinode(struct s_spcl *header)
1214{
1215	static long skipcnt = 0;
1216	long i;
1217	char buf[TP_BSIZE];
1218	int htype;
1219
1220	curfile.name = "<name unknown>";
1221	curfile.action = UNKNOWN;
1222	curfile.dip = NULL;
1223	curfile.ino = 0;
1224	do {
1225		if (header->c_magic != NFS_MAGIC) {
1226			skipcnt++;
1227			while (gethead(header) == FAIL ||
1228			    _time32_to_time(header->c_date) != dumpdate)
1229				skipcnt++;
1230		}
1231		htype = header->c_type;
1232		switch (htype) {
1233
1234		case TS_ADDR:
1235			/*
1236			 * Skip up to the beginning of the next record
1237			 */
1238			for (i = 0; i < header->c_count; i++)
1239				if (header->c_addr[i])
1240					readtape(buf);
1241			while (gethead(header) == FAIL ||
1242			    _time32_to_time(header->c_date) != dumpdate)
1243				skipcnt++;
1244			break;
1245
1246		case TS_INODE:
1247			curfile.dip = &header->c_dinode;
1248			curfile.ino = header->c_inumber;
1249			break;
1250
1251		case TS_END:
1252			/* If we missed some tapes, get another volume. */
1253			if (tapesread & (tapesread + 1)) {
1254				getvol(0);
1255				continue;
1256			}
1257			curfile.ino = maxino;
1258			break;
1259
1260		case TS_CLRI:
1261			curfile.name = "<file removal list>";
1262			break;
1263
1264		case TS_BITS:
1265			curfile.name = "<file dump list>";
1266			break;
1267
1268		case TS_TAPE:
1269			panic("unexpected tape header\n");
1270			/* NOTREACHED */
1271
1272		default:
1273			panic("unknown tape header type %d\n", spcl.c_type);
1274			/* NOTREACHED */
1275
1276		}
1277	} while (htype == TS_ADDR);
1278	if (skipcnt > 0)
1279		fprintf(stderr, "resync restore, skipped %ld blocks\n",
1280		    skipcnt);
1281	skipcnt = 0;
1282}
1283
1284static int
1285checksum(int *buf)
1286{
1287	int i, j;
1288
1289	j = sizeof(union u_spcl) / sizeof(int);
1290	i = 0;
1291	if(!Bcvt) {
1292		do
1293			i += *buf++;
1294		while (--j);
1295	} else {
1296		/* What happens if we want to read restore tapes
1297			for a 16bit int machine??? */
1298		do
1299			i += swabl(*buf++);
1300		while (--j);
1301	}
1302
1303	if (i != CHECKSUM) {
1304		fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1305			curfile.ino, curfile.name);
1306		return(FAIL);
1307	}
1308	return(GOOD);
1309}
1310
1311#ifdef RRESTORE
1312#include <stdarg.h>
1313
1314void
1315msg(const char *fmt, ...)
1316{
1317	va_list ap;
1318	va_start(ap, fmt);
1319	(void)vfprintf(stderr, fmt, ap);
1320	va_end(ap);
1321}
1322#endif /* RRESTORE */
1323
1324static u_char *
1325swabshort(u_char *sp, int n)
1326{
1327	char c;
1328
1329	while (--n >= 0) {
1330		c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1331		sp += 2;
1332	}
1333	return (sp);
1334}
1335
1336static u_char *
1337swablong(u_char *sp, int n)
1338{
1339	char c;
1340
1341	while (--n >= 0) {
1342		c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1343		c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1344		sp += 4;
1345	}
1346	return (sp);
1347}
1348
1349void
1350swabst(u_char *cp, u_char *sp)
1351{
1352	int n = 0;
1353
1354	while (*cp) {
1355		switch (*cp) {
1356		case '0': case '1': case '2': case '3': case '4':
1357		case '5': case '6': case '7': case '8': case '9':
1358			n = (n * 10) + (*cp++ - '0');
1359			continue;
1360
1361		case 's': case 'w': case 'h':
1362			if (n == 0)
1363				n = 1;
1364			sp = swabshort(sp, n);
1365			break;
1366
1367		case 'l':
1368			if (n == 0)
1369				n = 1;
1370			sp = swablong(sp, n);
1371			break;
1372
1373		default: /* Any other character, like 'b' counts as byte. */
1374			if (n == 0)
1375				n = 1;
1376			sp += n;
1377			break;
1378		}
1379		cp++;
1380		n = 0;
1381	}
1382}
1383
1384static u_long
1385swabl(u_long x)
1386{
1387	swabst((u_char *)"l", (u_char *)&x);
1388	return (x);
1389}
1390