GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/restore/tape.c Lines: 0 679 0.0 %
Date: 2017-11-13 Branches: 0 432 0.0 %

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