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