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