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