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