tape.c revision 6305
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 IFIFO:
549		if (mkfifo(name, mode) < 0) {
550			fprintf(stderr, "%s: cannot create FIFO: %s\n",
551				name, strerror(errno));
552			skipfile();
553			return (FAIL);
554		}
555		(void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
556		(void) chmod(name, mode);
557		skipfile();
558		utimes(name, timep);
559		return (GOOD);
560
561	case IFCHR:
562	case IFBLK:
563		vprintf(stdout, "extract special file %s\n", name);
564		if (Nflag) {
565			skipfile();
566			return (GOOD);
567		}
568		if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
569			fprintf(stderr, "%s: cannot create special file: %s\n",
570			    name, strerror(errno));
571			skipfile();
572			return (FAIL);
573		}
574		(void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
575		(void) chmod(name, mode);
576		skipfile();
577		utimes(name, timep);
578		return (GOOD);
579
580	case IFREG:
581		vprintf(stdout, "extract file %s\n", name);
582		if (Nflag) {
583			skipfile();
584			return (GOOD);
585		}
586		if ((ofile = creat(name, 0666)) < 0) {
587			fprintf(stderr, "%s: cannot create file: %s\n",
588			    name, strerror(errno));
589			skipfile();
590			return (FAIL);
591		}
592		(void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
593		(void) fchmod(ofile, mode);
594		getfile(xtrfile, xtrskip);
595		(void) close(ofile);
596		utimes(name, timep);
597		return (GOOD);
598	}
599	/* NOTREACHED */
600}
601
602/*
603 * skip over bit maps on the tape
604 */
605void
606skipmaps()
607{
608
609	while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
610		skipfile();
611}
612
613/*
614 * skip over a file on the tape
615 */
616void
617skipfile()
618{
619
620	curfile.action = SKIP;
621	getfile(xtrnull, xtrnull);
622}
623
624/*
625 * Extract a file from the tape.
626 * When an allocated block is found it is passed to the fill function;
627 * when an unallocated block (hole) is found, a zeroed buffer is passed
628 * to the skip function.
629 */
630void
631getfile(fill, skip)
632	void	(*fill) __P((char *, long));
633	void	(*skip) __P((char *, long));
634{
635	register int i;
636	int curblk = 0;
637	long size = spcl.c_dinode.di_size;
638	static char clearedbuf[MAXBSIZE];
639	char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
640	char junk[TP_BSIZE];
641
642	if (spcl.c_type == TS_END)
643		panic("ran off end of tape\n");
644	if (spcl.c_magic != NFS_MAGIC)
645		panic("not at beginning of a file\n");
646	if (!gettingfile && setjmp(restart) != 0)
647		return;
648	gettingfile++;
649loop:
650	for (i = 0; i < spcl.c_count; i++) {
651		if (spcl.c_addr[i]) {
652			readtape(&buf[curblk++][0]);
653			if (curblk == fssize / TP_BSIZE) {
654				(*fill)((char *)buf, size > TP_BSIZE ?
655				     (long) (fssize) :
656				     (curblk - 1) * TP_BSIZE + size);
657				curblk = 0;
658			}
659		} else {
660			if (curblk > 0) {
661				(*fill)((char *)buf, size > TP_BSIZE ?
662				     (long) (curblk * TP_BSIZE) :
663				     (curblk - 1) * TP_BSIZE + size);
664				curblk = 0;
665			}
666			(*skip)(clearedbuf, size > TP_BSIZE ?
667				(long) TP_BSIZE : size);
668		}
669		if ((size -= TP_BSIZE) <= 0) {
670			for (i++; i < spcl.c_count; i++)
671				if (spcl.c_addr[i])
672					readtape(junk);
673			break;
674		}
675	}
676	if (gethead(&spcl) == GOOD && size > 0) {
677		if (spcl.c_type == TS_ADDR)
678			goto loop;
679		dprintf(stdout,
680			"Missing address (header) block for %s at %d blocks\n",
681			curfile.name, blksread);
682	}
683	if (curblk > 0)
684		(*fill)((char *)buf, (curblk * TP_BSIZE) + size);
685	findinode(&spcl);
686	gettingfile = 0;
687}
688
689/*
690 * Write out the next block of a file.
691 */
692static void
693xtrfile(buf, size)
694	char	*buf;
695	long	size;
696{
697
698	if (Nflag)
699		return;
700	if (write(ofile, buf, (int) size) == -1) {
701		fprintf(stderr,
702		    "write error extracting inode %d, name %s\nwrite: %s\n",
703			curfile.ino, curfile.name, strerror(errno));
704		done(1);
705	}
706}
707
708/*
709 * Skip over a hole in a file.
710 */
711/* ARGSUSED */
712static void
713xtrskip(buf, size)
714	char *buf;
715	long size;
716{
717
718	if (lseek(ofile, size, SEEK_CUR) == -1) {
719		fprintf(stderr,
720		    "seek error extracting inode %d, name %s\nlseek: %s\n",
721			curfile.ino, curfile.name, strerror(errno));
722		done(1);
723	}
724}
725
726/*
727 * Collect the next block of a symbolic link.
728 */
729static void
730xtrlnkfile(buf, size)
731	char	*buf;
732	long	size;
733{
734
735	pathlen += size;
736	if (pathlen > MAXPATHLEN) {
737		fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
738		    curfile.name, lnkbuf, buf, pathlen);
739		done(1);
740	}
741	(void) strcat(lnkbuf, buf);
742}
743
744/*
745 * Skip over a hole in a symbolic link (should never happen).
746 */
747/* ARGSUSED */
748static void
749xtrlnkskip(buf, size)
750	char *buf;
751	long size;
752{
753
754	fprintf(stderr, "unallocated block in symbolic link %s\n",
755		curfile.name);
756	done(1);
757}
758
759/*
760 * Collect the next block of a bit map.
761 */
762static void
763xtrmap(buf, size)
764	char	*buf;
765	long	size;
766{
767
768	bcopy(buf, map, size);
769	map += size;
770}
771
772/*
773 * Skip over a hole in a bit map (should never happen).
774 */
775/* ARGSUSED */
776static void
777xtrmapskip(buf, size)
778	char *buf;
779	long size;
780{
781
782	panic("hole in map\n");
783	map += size;
784}
785
786/*
787 * Noop, when an extraction function is not needed.
788 */
789/* ARGSUSED */
790void
791xtrnull(buf, size)
792	char *buf;
793	long size;
794{
795
796	return;
797}
798
799/*
800 * Read TP_BSIZE blocks from the input.
801 * Handle read errors, and end of media.
802 */
803static void
804readtape(buf)
805	char *buf;
806{
807	long rd, newvol, i;
808	int cnt, seek_failed;
809
810	if (blkcnt < numtrec) {
811		bcopy(&tapebuf[(blkcnt++ * TP_BSIZE)], buf, (long)TP_BSIZE);
812		blksread++;
813		tpblksread++;
814		return;
815	}
816	for (i = 0; i < ntrec; i++)
817		((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
818	if (numtrec == 0)
819		numtrec = ntrec;
820	cnt = ntrec * TP_BSIZE;
821	rd = 0;
822getmore:
823#ifdef RRESTORE
824	if (host)
825		i = rmtread(&tapebuf[rd], cnt);
826	else
827#endif
828		i = read(mt, &tapebuf[rd], cnt);
829	/*
830	 * Check for mid-tape short read error.
831	 * If found, skip rest of buffer and start with the next.
832	 */
833	if (!pipein && numtrec < ntrec && i > 0) {
834		dprintf(stdout, "mid-media short read error.\n");
835		numtrec = ntrec;
836	}
837	/*
838	 * Handle partial block read.
839	 */
840	if (pipein && i == 0 && rd > 0)
841		i = rd;
842	else if (i > 0 && i != ntrec * TP_BSIZE) {
843		if (pipein) {
844			rd += i;
845			cnt -= i;
846			if (cnt > 0)
847				goto getmore;
848			i = rd;
849		} else {
850			/*
851			 * Short read. Process the blocks read.
852			 */
853			if (i % TP_BSIZE != 0)
854				vprintf(stdout,
855				    "partial block read: %d should be %d\n",
856				    i, ntrec * TP_BSIZE);
857			numtrec = i / TP_BSIZE;
858		}
859	}
860	/*
861	 * Handle read error.
862	 */
863	if (i < 0) {
864		fprintf(stderr, "Tape read error while ");
865		switch (curfile.action) {
866		default:
867			fprintf(stderr, "trying to set up tape\n");
868			break;
869		case UNKNOWN:
870			fprintf(stderr, "trying to resynchronize\n");
871			break;
872		case USING:
873			fprintf(stderr, "restoring %s\n", curfile.name);
874			break;
875		case SKIP:
876			fprintf(stderr, "skipping over inode %d\n",
877				curfile.ino);
878			break;
879		}
880		if (!yflag && !reply("continue"))
881			done(1);
882		i = ntrec * TP_BSIZE;
883		bzero(tapebuf, i);
884#ifdef RRESTORE
885		if (host)
886			seek_failed = (rmtseek(i, 1) < 0);
887		else
888#endif
889			seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
890
891		if (seek_failed) {
892			fprintf(stderr,
893			    "continuation failed: %s\n", strerror(errno));
894			done(1);
895		}
896	}
897	/*
898	 * Handle end of tape.
899	 */
900	if (i == 0) {
901		vprintf(stdout, "End-of-tape encountered\n");
902		if (!pipein) {
903			newvol = volno + 1;
904			volno = 0;
905			numtrec = 0;
906			getvol(newvol);
907			readtape(buf);
908			return;
909		}
910		if (rd % TP_BSIZE != 0)
911			panic("partial block read: %d should be %d\n",
912				rd, ntrec * TP_BSIZE);
913		terminateinput();
914		bcopy((char *)&endoftapemark, &tapebuf[rd], (long)TP_BSIZE);
915	}
916	blkcnt = 0;
917	bcopy(&tapebuf[(blkcnt++ * TP_BSIZE)], buf, (long)TP_BSIZE);
918	blksread++;
919	tpblksread++;
920}
921
922static void
923findtapeblksize()
924{
925	register long i;
926
927	for (i = 0; i < ntrec; i++)
928		((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
929	blkcnt = 0;
930#ifdef RRESTORE
931	if (host)
932		i = rmtread(tapebuf, ntrec * TP_BSIZE);
933	else
934#endif
935		i = read(mt, tapebuf, ntrec * TP_BSIZE);
936
937	if (i <= 0) {
938		fprintf(stderr, "tape read error: %s\n", strerror(errno));
939		done(1);
940	}
941	if (i % TP_BSIZE != 0) {
942		fprintf(stderr, "Tape block size (%d) %s (%d)\n",
943			i, "is not a multiple of dump block size", TP_BSIZE);
944		done(1);
945	}
946	ntrec = i / TP_BSIZE;
947	numtrec = ntrec;
948	vprintf(stdout, "Tape block size is %d\n", ntrec);
949}
950
951void
952closemt()
953{
954
955	if (mt < 0)
956		return;
957#ifdef RRESTORE
958	if (host)
959		rmtclose();
960	else
961#endif
962		(void) close(mt);
963}
964
965/*
966 * Read the next block from the tape.
967 * Check to see if it is one of several vintage headers.
968 * If it is an old style header, convert it to a new style header.
969 * If it is not any valid header, return an error.
970 */
971static int
972gethead(buf)
973	struct s_spcl *buf;
974{
975	long i;
976	union {
977		quad_t	qval;
978		long	val[2];
979	} qcvt;
980	union u_ospcl {
981		char dummy[TP_BSIZE];
982		struct	s_ospcl {
983			long	c_type;
984			long	c_date;
985			long	c_ddate;
986			long	c_volume;
987			long	c_tapea;
988			u_short	c_inumber;
989			long	c_magic;
990			long	c_checksum;
991			struct odinode {
992				unsigned short odi_mode;
993				u_short	odi_nlink;
994				u_short	odi_uid;
995				u_short	odi_gid;
996				long	odi_size;
997				long	odi_rdev;
998				char	odi_addr[36];
999				long	odi_atime;
1000				long	odi_mtime;
1001				long	odi_ctime;
1002			} c_dinode;
1003			long	c_count;
1004			char	c_addr[256];
1005		} s_ospcl;
1006	} u_ospcl;
1007
1008	if (!cvtflag) {
1009		readtape((char *)buf);
1010		if (buf->c_magic != NFS_MAGIC) {
1011			if (swabl(buf->c_magic) != NFS_MAGIC)
1012				return (FAIL);
1013			if (!Bcvt) {
1014				vprintf(stdout, "Note: Doing Byte swapping\n");
1015				Bcvt = 1;
1016			}
1017		}
1018		if (checksum((int *)buf) == FAIL)
1019			return (FAIL);
1020		if (Bcvt)
1021			swabst((u_char *)"8l4s31l", (u_char *)buf);
1022		goto good;
1023	}
1024	readtape((char *)(&u_ospcl.s_ospcl));
1025	bzero((char *)buf, (long)TP_BSIZE);
1026	buf->c_type = u_ospcl.s_ospcl.c_type;
1027	buf->c_date = u_ospcl.s_ospcl.c_date;
1028	buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1029	buf->c_volume = u_ospcl.s_ospcl.c_volume;
1030	buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1031	buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1032	buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1033	buf->c_magic = u_ospcl.s_ospcl.c_magic;
1034	buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1035	buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1036	buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1037	buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1038	buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
1039	buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1040	buf->c_dinode.di_atime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_atime;
1041	buf->c_dinode.di_mtime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1042	buf->c_dinode.di_ctime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1043	buf->c_count = u_ospcl.s_ospcl.c_count;
1044	bcopy(u_ospcl.s_ospcl.c_addr, buf->c_addr, (long)256);
1045	if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
1046	    checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
1047		return(FAIL);
1048	buf->c_magic = NFS_MAGIC;
1049
1050good:
1051	if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
1052	    (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
1053		qcvt.qval = buf->c_dinode.di_size;
1054		if (qcvt.val[0] || qcvt.val[1]) {
1055			printf("Note: Doing Quad swapping\n");
1056			Qcvt = 1;
1057		}
1058	}
1059	if (Qcvt) {
1060		qcvt.qval = buf->c_dinode.di_size;
1061		i = qcvt.val[1];
1062		qcvt.val[1] = qcvt.val[0];
1063		qcvt.val[0] = i;
1064		buf->c_dinode.di_size = qcvt.qval;
1065	}
1066
1067	switch (buf->c_type) {
1068
1069	case TS_CLRI:
1070	case TS_BITS:
1071		/*
1072		 * Have to patch up missing information in bit map headers
1073		 */
1074		buf->c_inumber = 0;
1075		buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
1076		for (i = 0; i < buf->c_count; i++)
1077			buf->c_addr[i]++;
1078		break;
1079
1080	case TS_TAPE:
1081		if ((buf->c_flags & DR_NEWINODEFMT) == 0)
1082			oldinofmt = 1;
1083		/* fall through */
1084	case TS_END:
1085		buf->c_inumber = 0;
1086		break;
1087
1088	case TS_INODE:
1089	case TS_ADDR:
1090		break;
1091
1092	default:
1093		panic("gethead: unknown inode type %d\n", buf->c_type);
1094		break;
1095	}
1096	/*
1097	 * If we are restoring a filesystem with old format inodes,
1098	 * copy the uid/gid to the new location.
1099	 */
1100	if (oldinofmt) {
1101		buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
1102		buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
1103	}
1104	if (dflag)
1105		accthdr(buf);
1106	return(GOOD);
1107}
1108
1109/*
1110 * Check that a header is where it belongs and predict the next header
1111 */
1112static void
1113accthdr(header)
1114	struct s_spcl *header;
1115{
1116	static ino_t previno = 0x7fffffff;
1117	static int prevtype;
1118	static long predict;
1119	long blks, i;
1120
1121	if (header->c_type == TS_TAPE) {
1122		fprintf(stderr, "Volume header (%s inode format) ",
1123		    oldinofmt ? "old" : "new");
1124 		if (header->c_firstrec)
1125 			fprintf(stderr, "begins with record %d",
1126 				header->c_firstrec);
1127 		fprintf(stderr, "\n");
1128		previno = 0x7fffffff;
1129		return;
1130	}
1131	if (previno == 0x7fffffff)
1132		goto newcalc;
1133	switch (prevtype) {
1134	case TS_BITS:
1135		fprintf(stderr, "Dump mask header");
1136		break;
1137	case TS_CLRI:
1138		fprintf(stderr, "Remove mask header");
1139		break;
1140	case TS_INODE:
1141		fprintf(stderr, "File header, ino %d", previno);
1142		break;
1143	case TS_ADDR:
1144		fprintf(stderr, "File continuation header, ino %d", previno);
1145		break;
1146	case TS_END:
1147		fprintf(stderr, "End of tape header");
1148		break;
1149	}
1150	if (predict != blksread - 1)
1151		fprintf(stderr, "; predicted %d blocks, got %d blocks",
1152			predict, blksread - 1);
1153	fprintf(stderr, "\n");
1154newcalc:
1155	blks = 0;
1156	if (header->c_type != TS_END)
1157		for (i = 0; i < header->c_count; i++)
1158			if (header->c_addr[i] != 0)
1159				blks++;
1160	predict = blks;
1161	blksread = 0;
1162	prevtype = header->c_type;
1163	previno = header->c_inumber;
1164}
1165
1166/*
1167 * Find an inode header.
1168 * Complain if had to skip, and complain is set.
1169 */
1170static void
1171findinode(header)
1172	struct s_spcl *header;
1173{
1174	static long skipcnt = 0;
1175	long i;
1176	char buf[TP_BSIZE];
1177
1178	curfile.name = "<name unknown>";
1179	curfile.action = UNKNOWN;
1180	curfile.dip = NULL;
1181	curfile.ino = 0;
1182	do {
1183		if (header->c_magic != NFS_MAGIC) {
1184			skipcnt++;
1185			while (gethead(header) == FAIL ||
1186			    header->c_date != dumpdate)
1187				skipcnt++;
1188		}
1189		switch (header->c_type) {
1190
1191		case TS_ADDR:
1192			/*
1193			 * Skip up to the beginning of the next record
1194			 */
1195			for (i = 0; i < header->c_count; i++)
1196				if (header->c_addr[i])
1197					readtape(buf);
1198			while (gethead(header) == FAIL ||
1199			    header->c_date != dumpdate)
1200				skipcnt++;
1201			break;
1202
1203		case TS_INODE:
1204			curfile.dip = &header->c_dinode;
1205			curfile.ino = header->c_inumber;
1206			break;
1207
1208		case TS_END:
1209			curfile.ino = maxino;
1210			break;
1211
1212		case TS_CLRI:
1213			curfile.name = "<file removal list>";
1214			break;
1215
1216		case TS_BITS:
1217			curfile.name = "<file dump list>";
1218			break;
1219
1220		case TS_TAPE:
1221			panic("unexpected tape header\n");
1222			/* NOTREACHED */
1223
1224		default:
1225			panic("unknown tape header type %d\n", spcl.c_type);
1226			/* NOTREACHED */
1227
1228		}
1229	} while (header->c_type == TS_ADDR);
1230	if (skipcnt > 0)
1231		fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
1232	skipcnt = 0;
1233}
1234
1235static int
1236checksum(buf)
1237	register int *buf;
1238{
1239	register int i, j;
1240
1241	j = sizeof(union u_spcl) / sizeof(int);
1242	i = 0;
1243	if(!Bcvt) {
1244		do
1245			i += *buf++;
1246		while (--j);
1247	} else {
1248		/* What happens if we want to read restore tapes
1249			for a 16bit int machine??? */
1250		do
1251			i += swabl(*buf++);
1252		while (--j);
1253	}
1254
1255	if (i != CHECKSUM) {
1256		fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1257			curfile.ino, curfile.name);
1258		return(FAIL);
1259	}
1260	return(GOOD);
1261}
1262
1263#ifdef RRESTORE
1264#if __STDC__
1265#include <stdarg.h>
1266#else
1267#include <varargs.h>
1268#endif
1269
1270void
1271#if __STDC__
1272msg(const char *fmt, ...)
1273#else
1274msg(fmt, va_alist)
1275	char *fmt;
1276	va_dcl
1277#endif
1278{
1279	va_list ap;
1280#if __STDC__
1281	va_start(ap, fmt);
1282#else
1283	va_start(ap);
1284#endif
1285	(void)vfprintf(stderr, fmt, ap);
1286	va_end(ap);
1287}
1288#endif /* RRESTORE */
1289
1290static u_char *
1291swabshort(sp, n)
1292	register u_char *sp;
1293	register int n;
1294{
1295	char c;
1296
1297	while (--n >= 0) {
1298		c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1299		sp += 2;
1300	}
1301	return (sp);
1302}
1303
1304static u_char *
1305swablong(sp, n)
1306	register u_char *sp;
1307	register int n;
1308{
1309	char c;
1310
1311	while (--n >= 0) {
1312		c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1313		c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1314		sp += 4;
1315	}
1316	return (sp);
1317}
1318
1319void
1320swabst(cp, sp)
1321	register u_char *cp, *sp;
1322{
1323	int n = 0;
1324
1325	while (*cp) {
1326		switch (*cp) {
1327		case '0': case '1': case '2': case '3': case '4':
1328		case '5': case '6': case '7': case '8': case '9':
1329			n = (n * 10) + (*cp++ - '0');
1330			continue;
1331
1332		case 's': case 'w': case 'h':
1333			if (n == 0)
1334				n = 1;
1335			sp = swabshort(sp, n);
1336			break;
1337
1338		case 'l':
1339			if (n == 0)
1340				n = 1;
1341			sp = swablong(sp, n);
1342			break;
1343
1344		default: /* Any other character, like 'b' counts as byte. */
1345			if (n == 0)
1346				n = 1;
1347			sp += n;
1348			break;
1349		}
1350		cp++;
1351		n = 0;
1352	}
1353}
1354
1355static u_long
1356swabl(x)
1357	u_long x;
1358{
1359	swabst((u_char *)"l", (u_char *)&x);
1360	return (x);
1361}
1362