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