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