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