tape.c revision 1.39 1 /* $NetBSD: tape.c,v 1.39 2000/01/27 15:25:00 sommerfeld 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.39 2000/01/27 15:25:00 sommerfeld 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 fprintf(stderr, "Wrong dump date\n\tgot: %s",
406 ctime(&tmpbuf.c_date));
407 fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
408 volno = 0;
409 goto again;
410 }
411 tapesread |= 1 << volno;
412 blksread = savecnt;
413 /*
414 * If continuing from the previous volume, skip over any
415 * blocks read already at the end of the previous volume.
416 *
417 * If coming to this volume at random, skip to the beginning
418 * of the next record.
419 */
420 dprintf(stdout, "read %ld recs, tape starts with %ld\n",
421 (long)tpblksread, (long)tmpbuf.c_firstrec);
422 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
423 if (!wantnext) {
424 tpblksread = tmpbuf.c_firstrec;
425 for (i = tmpbuf.c_count; i > 0; i--)
426 readtape(buf);
427 } else if (tmpbuf.c_firstrec > 0 &&
428 tmpbuf.c_firstrec < tpblksread - 1) {
429 /*
430 * -1 since we've read the volume header
431 */
432 i = tpblksread - tmpbuf.c_firstrec - 1;
433 dprintf(stderr, "Skipping %d duplicate record%s.\n",
434 i, i > 1 ? "s" : "");
435 while (--i >= 0)
436 readtape(buf);
437 }
438 }
439 if (curfile.action == USING) {
440 if (volno == 1)
441 panic("active file into volume 1\n");
442 return;
443 }
444 /*
445 * Skip up to the beginning of the next record
446 */
447 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
448 for (i = tmpbuf.c_count; i > 0; i--)
449 readtape(buf);
450 (void) gethead(&spcl);
451 findinode(&spcl);
452 if (gettingfile) {
453 gettingfile = 0;
454 longjmp(restart, 1);
455 }
456 }
457
458 /*
459 * Handle unexpected EOF.
460 */
461 static void
462 terminateinput()
463 {
464
465 if (gettingfile && curfile.action == USING) {
466 printf("Warning: %s %s\n",
467 "End-of-input encountered while extracting", curfile.name);
468 }
469 curfile.name = "<name unknown>";
470 curfile.action = UNKNOWN;
471 curfile.dip = NULL;
472 curfile.ino = maxino;
473 if (gettingfile) {
474 gettingfile = 0;
475 longjmp(restart, 1);
476 }
477 }
478
479 /*
480 * handle multiple dumps per tape by skipping forward to the
481 * appropriate one.
482 */
483 static void
484 setdumpnum()
485 {
486 struct mtop tcom;
487
488 if (dumpnum == 1 || volno != 1)
489 return;
490 if (pipein) {
491 fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
492 exit(1);
493 }
494 tcom.mt_op = MTFSF;
495 tcom.mt_count = dumpnum - 1;
496 #ifdef RRESTORE
497 if (host)
498 rmtioctl(MTFSF, dumpnum - 1);
499 else
500 #endif
501 if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
502 fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
503 }
504
505 void
506 printdumpinfo()
507 {
508 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date));
509 fprintf(stdout, "Dumped from: %s",
510 (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
511 fprintf(stderr, "Level %d dump of %s on %s:%s\n",
512 spcl.c_level, spcl.c_filesys,
513 *spcl.c_host? spcl.c_host: "[unknown]", spcl.c_dev);
514 fprintf(stderr, "Label: %s\n", spcl.c_label);
515 }
516
517 int
518 extractfile(name)
519 char *name;
520 {
521 int flags;
522 uid_t uid;
523 gid_t gid;
524 mode_t mode;
525 struct timeval timep[2];
526 struct entry *ep;
527
528 curfile.name = name;
529 curfile.action = USING;
530 timep[0].tv_sec = curfile.dip->di_atime;
531 timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
532 timep[1].tv_sec = curfile.dip->di_mtime;
533 timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
534 uid = curfile.dip->di_uid;
535 gid = curfile.dip->di_gid;
536 mode = curfile.dip->di_mode;
537 flags = curfile.dip->di_flags;
538 switch (mode & IFMT) {
539
540 default:
541 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
542 skipfile();
543 return (FAIL);
544
545 case IFSOCK:
546 vprintf(stdout, "skipped socket %s\n", name);
547 skipfile();
548 return (GOOD);
549
550 case IFDIR:
551 if (mflag) {
552 ep = lookupname(name);
553 if (ep == NULL || ep->e_flags & EXTRACT)
554 panic("unextracted directory %s\n", name);
555 skipfile();
556 return (GOOD);
557 }
558 vprintf(stdout, "extract file %s\n", name);
559 return (genliteraldir(name, curfile.ino));
560
561 case IFLNK:
562 lnkbuf[0] = '\0';
563 pathlen = 0;
564 getfile(xtrlnkfile, xtrlnkskip);
565 if (pathlen == 0) {
566 vprintf(stdout,
567 "%s: zero length symbolic link (ignored)\n", name);
568 return (GOOD);
569 }
570 if (uflag)
571 (void) unlink(name);
572 if (linkit(lnkbuf, name, SYMLINK) == GOOD) {
573 (void) lutimes(name, timep);
574 (void) lchown(name, uid, gid);
575 (void) lchmod(name, mode);
576 return (GOOD);
577 }
578 return (FAIL);
579
580 case IFCHR:
581 case IFBLK:
582 vprintf(stdout, "extract special file %s\n", name);
583 if (Nflag) {
584 skipfile();
585 return (GOOD);
586 }
587 if (uflag)
588 (void) unlink(name);
589 if (mknod(name, (mode & (IFCHR | IFBLK)) | 0600,
590 (int)curfile.dip->di_rdev) < 0) {
591 fprintf(stderr, "%s: cannot create special file: %s\n",
592 name, strerror(errno));
593 skipfile();
594 return (FAIL);
595 }
596 skipfile();
597 (void) utimes(name, timep);
598 (void) chown(name, uid, gid);
599 (void) chmod(name, mode);
600 (void) chflags(name, flags);
601 return (GOOD);
602
603 case IFIFO:
604 vprintf(stdout, "extract fifo %s\n", name);
605 if (Nflag) {
606 skipfile();
607 return (GOOD);
608 }
609 if (uflag)
610 (void) unlink(name);
611 if (mkfifo(name, 0600) < 0) {
612 fprintf(stderr, "%s: cannot create fifo: %s\n",
613 name, strerror(errno));
614 skipfile();
615 return (FAIL);
616 }
617 skipfile();
618 (void) utimes(name, timep);
619 (void) chown(name, uid, gid);
620 (void) chmod(name, mode);
621 (void) chflags(name, flags);
622 return (GOOD);
623
624 case IFREG:
625 vprintf(stdout, "extract file %s\n", name);
626 if (Nflag) {
627 skipfile();
628 return (GOOD);
629 }
630 if (uflag)
631 (void) unlink(name);
632 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
633 0600)) < 0) {
634 fprintf(stderr, "%s: cannot create file: %s\n",
635 name, strerror(errno));
636 skipfile();
637 return (FAIL);
638 }
639 getfile(xtrfile, xtrskip);
640 (void) futimes(ofile, timep);
641 (void) fchown(ofile, uid, gid);
642 (void) fchmod(ofile, mode);
643 (void) fchflags(ofile, flags);
644 (void) close(ofile);
645 return (GOOD);
646 }
647 /* NOTREACHED */
648 }
649
650 /*
651 * skip over bit maps on the tape
652 */
653 void
654 skipmaps()
655 {
656
657 while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
658 skipfile();
659 }
660
661 /*
662 * skip over a file on the tape
663 */
664 void
665 skipfile()
666 {
667
668 curfile.action = SKIP;
669 getfile(xtrnull, xtrnull);
670 }
671
672 /*
673 * Extract a file from the tape.
674 * When an allocated block is found it is passed to the fill function;
675 * when an unallocated block (hole) is found, a zeroed buffer is passed
676 * to the skip function.
677 */
678 void
679 getfile(fill, skip)
680 void (*fill) __P((char *, long));
681 void (*skip) __P((char *, long));
682 {
683 int i;
684 int curblk = 0;
685 quad_t size = spcl.c_dinode.di_size;
686 static char clearedbuf[MAXBSIZE];
687 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
688 char junk[TP_BSIZE];
689
690 #ifdef __GNUC__ /* XXX: to shut up gcc warnings */
691 (void)&curblk;
692 (void)&size;
693 #endif
694
695 if (spcl.c_type == TS_END)
696 panic("ran off end of tape\n");
697 if (spcl.c_magic != NFS_MAGIC)
698 panic("not at beginning of a file\n");
699 if (!gettingfile && setjmp(restart) != 0)
700 return;
701 gettingfile++;
702 loop:
703 for (i = 0; i < spcl.c_count; i++) {
704 if (spcl.c_addr[i]) {
705 readtape(&buf[curblk++][0]);
706 if (curblk == fssize / TP_BSIZE) {
707 (*fill)((char *)buf, (long)(size > TP_BSIZE ?
708 fssize : (curblk - 1) * TP_BSIZE + size));
709 curblk = 0;
710 }
711 } else {
712 if (curblk > 0) {
713 (*fill)((char *)buf, (long)(size > TP_BSIZE ?
714 curblk * TP_BSIZE :
715 (curblk - 1) * TP_BSIZE + size));
716 curblk = 0;
717 }
718 (*skip)(clearedbuf, (long)(size > TP_BSIZE ?
719 TP_BSIZE : size));
720 }
721 if ((size -= TP_BSIZE) <= 0) {
722 for (i++; i < spcl.c_count; i++)
723 if (spcl.c_addr[i])
724 readtape(junk);
725 break;
726 }
727 }
728 if (gethead(&spcl) == GOOD && size > 0) {
729 if (spcl.c_type == TS_ADDR)
730 goto loop;
731 dprintf(stdout,
732 "Missing address (header) block for %s at %d blocks\n",
733 curfile.name, blksread);
734 }
735 if (curblk > 0)
736 (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
737 findinode(&spcl);
738 gettingfile = 0;
739 }
740
741 /*
742 * Write out the next block of a file.
743 */
744 static void
745 xtrfile(buf, size)
746 char *buf;
747 long size;
748 {
749
750 if (Nflag)
751 return;
752 if (write(ofile, buf, (int) size) == -1) {
753 fprintf(stderr,
754 "write error extracting inode %d, name %s\nwrite: %s\n",
755 curfile.ino, curfile.name, strerror(errno));
756 exit(1);
757 }
758 }
759
760 /*
761 * Skip over a hole in a file.
762 */
763 /* ARGSUSED */
764 static void
765 xtrskip(buf, size)
766 char *buf;
767 long size;
768 {
769
770 if (lseek(ofile, size, SEEK_CUR) == -1) {
771 fprintf(stderr,
772 "seek error extracting inode %d, name %s\nlseek: %s\n",
773 curfile.ino, curfile.name, strerror(errno));
774 exit(1);
775 }
776 }
777
778 /*
779 * Collect the next block of a symbolic link.
780 */
781 static void
782 xtrlnkfile(buf, size)
783 char *buf;
784 long size;
785 {
786
787 pathlen += size;
788 if (pathlen > MAXPATHLEN) {
789 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
790 curfile.name, lnkbuf, buf, pathlen);
791 exit(1);
792 }
793 (void) strcat(lnkbuf, buf);
794 }
795
796 /*
797 * Skip over a hole in a symbolic link (should never happen).
798 */
799 /* ARGSUSED */
800 static void
801 xtrlnkskip(buf, size)
802 char *buf;
803 long size;
804 {
805
806 fprintf(stderr, "unallocated block in symbolic link %s\n",
807 curfile.name);
808 exit(1);
809 }
810
811 /*
812 * Collect the next block of a bit map.
813 */
814 static void
815 xtrmap(buf, size)
816 char *buf;
817 long size;
818 {
819
820 memmove(map, buf, size);
821 map += size;
822 }
823
824 /*
825 * Skip over a hole in a bit map (should never happen).
826 */
827 /* ARGSUSED */
828 static void
829 xtrmapskip(buf, size)
830 char *buf;
831 long size;
832 {
833
834 panic("hole in map\n");
835 map += size;
836 }
837
838 /*
839 * Noop, when an extraction function is not needed.
840 */
841 /* ARGSUSED */
842 void
843 xtrnull(buf, size)
844 char *buf;
845 long size;
846 {
847
848 return;
849 }
850
851 /*
852 * Read TP_BSIZE blocks from the input.
853 * Handle read errors, and end of media.
854 */
855 static void
856 readtape(buf)
857 char *buf;
858 {
859 int rd, newvol, i;
860 int cnt, seek_failed;
861
862 if (blkcnt < numtrec) {
863 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
864 blksread++;
865 tpblksread++;
866 return;
867 }
868 for (i = 0; i < ntrec; i++)
869 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
870 if (numtrec == 0)
871 numtrec = ntrec;
872 cnt = ntrec * TP_BSIZE;
873 rd = 0;
874 getmore:
875 #ifdef RRESTORE
876 if (host)
877 i = rmtread(&tapebuf[rd], cnt);
878 else
879 #endif
880 i = read(mt, &tapebuf[rd], cnt);
881 /*
882 * Check for mid-tape short read error.
883 * If found, skip rest of buffer and start with the next.
884 */
885 if (!pipein && numtrec < ntrec && i > 0) {
886 dprintf(stdout, "mid-media short read error.\n");
887 numtrec = ntrec;
888 }
889 /*
890 * Handle partial block read.
891 */
892 if (pipein && i == 0 && rd > 0)
893 i = rd;
894 else if (i > 0 && i != ntrec * TP_BSIZE) {
895 if (pipein) {
896 rd += i;
897 cnt -= i;
898 if (cnt > 0)
899 goto getmore;
900 i = rd;
901 } else {
902 /*
903 * Short read. Process the blocks read.
904 */
905 if (i % TP_BSIZE != 0)
906 vprintf(stdout,
907 "partial block read: %d should be %d\n",
908 i, ntrec * TP_BSIZE);
909 numtrec = i / TP_BSIZE;
910 }
911 }
912 /*
913 * Handle read error.
914 */
915 if (i < 0) {
916 fprintf(stderr, "Tape read error while ");
917 switch (curfile.action) {
918 default:
919 fprintf(stderr, "trying to set up tape\n");
920 break;
921 case UNKNOWN:
922 fprintf(stderr, "trying to resynchronize\n");
923 break;
924 case USING:
925 fprintf(stderr, "restoring %s\n", curfile.name);
926 break;
927 case SKIP:
928 fprintf(stderr, "skipping over inode %d\n",
929 curfile.ino);
930 break;
931 }
932 if (!yflag && !reply("continue"))
933 exit(1);
934 i = ntrec * TP_BSIZE;
935 memset(tapebuf, 0, i);
936 #ifdef RRESTORE
937 if (host)
938 seek_failed = (rmtseek(i, 1) < 0);
939 else
940 #endif
941 seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
942
943 if (seek_failed) {
944 fprintf(stderr,
945 "continuation failed: %s\n", strerror(errno));
946 exit(1);
947 }
948 }
949 /*
950 * Handle end of tape.
951 */
952 if (i == 0) {
953 vprintf(stdout, "End-of-tape encountered\n");
954 if (!pipein) {
955 newvol = volno + 1;
956 volno = 0;
957 numtrec = 0;
958 getvol(newvol);
959 readtape(buf);
960 return;
961 }
962 if (rd % TP_BSIZE != 0)
963 panic("partial block read: %d should be %d\n",
964 rd, ntrec * TP_BSIZE);
965 terminateinput();
966 memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
967 }
968 blkcnt = 0;
969 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
970 blksread++;
971 tpblksread++;
972 }
973
974 static void
975 findtapeblksize()
976 {
977 long i;
978
979 for (i = 0; i < ntrec; i++)
980 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
981 blkcnt = 0;
982 #ifdef RRESTORE
983 if (host)
984 i = rmtread(tapebuf, ntrec * TP_BSIZE);
985 else
986 #endif
987 i = read(mt, tapebuf, ntrec * TP_BSIZE);
988
989 if (i <= 0) {
990 fprintf(stderr, "tape read error: %s\n", strerror(errno));
991 exit(1);
992 }
993 if (i % TP_BSIZE != 0) {
994 fprintf(stderr, "Tape block size (%ld) %s (%ld)\n",
995 (long)i, "is not a multiple of dump block size",
996 (long)TP_BSIZE);
997 exit(1);
998 }
999 ntrec = i / TP_BSIZE;
1000 numtrec = ntrec;
1001 vprintf(stdout, "Tape block size is %d\n", ntrec);
1002 }
1003
1004 void
1005 closemt()
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 */
1024 static int
1025 gethead(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_int16_t c_inumber;
1042 int32_t c_magic;
1043 int32_t c_checksum;
1044 struct odinode {
1045 unsigned short odi_mode;
1046 u_int16_t odi_nlink;
1047 u_int16_t odi_uid;
1048 u_int16_t 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 *)"8l4s31l528b1l192b2l", (u_char *)buf);
1075 goto good;
1076 }
1077 readtape((char *)(&u_ospcl.s_ospcl));
1078 memset(buf, 0, (long)TP_BSIZE);
1079 buf->c_type = u_ospcl.s_ospcl.c_type;
1080 buf->c_date = u_ospcl.s_ospcl.c_date;
1081 buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1082 buf->c_volume = u_ospcl.s_ospcl.c_volume;
1083 buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1084 buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1085 buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1086 buf->c_magic = u_ospcl.s_ospcl.c_magic;
1087 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1088 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1089 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1090 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1091 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
1092 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1093 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
1094 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1095 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1096 buf->c_count = u_ospcl.s_ospcl.c_count;
1097 memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256);
1098 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
1099 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
1100 return(FAIL);
1101 buf->c_magic = NFS_MAGIC;
1102
1103 good:
1104 if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
1105 (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
1106 qcvt.qval = buf->c_dinode.di_size;
1107 if (qcvt.val[0] || qcvt.val[1]) {
1108 printf("Note: Doing Quad swapping\n");
1109 Qcvt = 1;
1110 }
1111 }
1112 if (Qcvt) {
1113 qcvt.qval = buf->c_dinode.di_size;
1114 i = qcvt.val[1];
1115 qcvt.val[1] = qcvt.val[0];
1116 qcvt.val[0] = i;
1117 buf->c_dinode.di_size = qcvt.qval;
1118 }
1119
1120 switch (buf->c_type) {
1121
1122 case TS_CLRI:
1123 case TS_BITS:
1124 /*
1125 * Have to patch up missing information in bit map headers
1126 */
1127 buf->c_inumber = 0;
1128 buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
1129 for (i = 0; i < buf->c_count; i++)
1130 buf->c_addr[i]++;
1131 break;
1132
1133 case TS_TAPE:
1134 if ((buf->c_flags & DR_NEWINODEFMT) == 0)
1135 oldinofmt = 1;
1136 /* fall through */
1137 case TS_END:
1138 buf->c_inumber = 0;
1139 break;
1140
1141 case TS_INODE:
1142 case TS_ADDR:
1143 break;
1144
1145 default:
1146 panic("gethead: unknown inode type %d\n", buf->c_type);
1147 break;
1148 }
1149 /*
1150 * If we are restoring a filesystem with old format inodes,
1151 * copy the uid/gid to the new location.
1152 */
1153 if (oldinofmt) {
1154 buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
1155 buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
1156 }
1157 if (dflag)
1158 accthdr(buf);
1159 return(GOOD);
1160 }
1161
1162 /*
1163 * Check that a header is where it belongs and predict the next header
1164 */
1165 static void
1166 accthdr(header)
1167 struct s_spcl *header;
1168 {
1169 static ino_t previno = 0x7fffffff;
1170 static int prevtype;
1171 static long predict;
1172 long blks, i;
1173
1174 if (header->c_type == TS_TAPE) {
1175 fprintf(stderr, "Volume header (%s inode format) ",
1176 oldinofmt ? "old" : "new");
1177 if (header->c_firstrec)
1178 fprintf(stderr, "begins with record %d",
1179 header->c_firstrec);
1180 fprintf(stderr, "\n");
1181 previno = 0x7fffffff;
1182 return;
1183 }
1184 if (previno == 0x7fffffff)
1185 goto newcalc;
1186 switch (prevtype) {
1187 case TS_BITS:
1188 fprintf(stderr, "Dumped inodes map header");
1189 break;
1190 case TS_CLRI:
1191 fprintf(stderr, "Used inodes map header");
1192 break;
1193 case TS_INODE:
1194 fprintf(stderr, "File header, ino %d", previno);
1195 break;
1196 case TS_ADDR:
1197 fprintf(stderr, "File continuation header, ino %d", previno);
1198 break;
1199 case TS_END:
1200 fprintf(stderr, "End of tape header");
1201 break;
1202 }
1203 if (predict != blksread - 1)
1204 fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
1205 (long)predict, (long)(blksread - 1));
1206 fprintf(stderr, "\n");
1207 newcalc:
1208 blks = 0;
1209 if (header->c_type != TS_END)
1210 for (i = 0; i < header->c_count; i++)
1211 if (header->c_addr[i] != 0)
1212 blks++;
1213 predict = blks;
1214 blksread = 0;
1215 prevtype = header->c_type;
1216 previno = header->c_inumber;
1217 }
1218
1219 /*
1220 * Find an inode header.
1221 * Complain if had to skip, and complain is set.
1222 */
1223 static void
1224 findinode(header)
1225 struct s_spcl *header;
1226 {
1227 static long skipcnt = 0;
1228 long i;
1229 char buf[TP_BSIZE];
1230
1231 curfile.name = "<name unknown>";
1232 curfile.action = UNKNOWN;
1233 curfile.dip = NULL;
1234 curfile.ino = 0;
1235 do {
1236 if (header->c_magic != NFS_MAGIC) {
1237 skipcnt++;
1238 while (gethead(header) == FAIL ||
1239 header->c_date != dumpdate)
1240 skipcnt++;
1241 }
1242 switch (header->c_type) {
1243
1244 case TS_ADDR:
1245 /*
1246 * Skip up to the beginning of the next record
1247 */
1248 for (i = 0; i < header->c_count; i++)
1249 if (header->c_addr[i])
1250 readtape(buf);
1251 while (gethead(header) == FAIL ||
1252 header->c_date != dumpdate)
1253 skipcnt++;
1254 break;
1255
1256 case TS_INODE:
1257 curfile.dip = &header->c_dinode;
1258 curfile.ino = header->c_inumber;
1259 break;
1260
1261 case TS_END:
1262 curfile.ino = maxino;
1263 break;
1264
1265 case TS_CLRI:
1266 curfile.name = "<file removal list>";
1267 break;
1268
1269 case TS_BITS:
1270 curfile.name = "<file dump list>";
1271 break;
1272
1273 case TS_TAPE:
1274 panic("unexpected tape header\n");
1275 /* NOTREACHED */
1276
1277 default:
1278 panic("unknown tape header type %d\n", spcl.c_type);
1279 /* NOTREACHED */
1280
1281 }
1282 } while (header->c_type == TS_ADDR);
1283 if (skipcnt > 0)
1284 fprintf(stderr, "resync restore, skipped %ld blocks\n",
1285 (long)skipcnt);
1286 skipcnt = 0;
1287 }
1288
1289 static int
1290 checksum(buf)
1291 int *buf;
1292 {
1293 int i, j;
1294
1295 j = sizeof(union u_spcl) / sizeof(int);
1296 i = 0;
1297 if(!Bcvt) {
1298 do
1299 i += *buf++;
1300 while (--j);
1301 } else {
1302 /* What happens if we want to read restore tapes
1303 for a 16bit int machine??? */
1304 do
1305 i += swabl(*buf++);
1306 while (--j);
1307 }
1308
1309 if (i != CHECKSUM) {
1310 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1311 curfile.ino, curfile.name);
1312 return(FAIL);
1313 }
1314 return(GOOD);
1315 }
1316
1317 #ifdef RRESTORE
1318 #if __STDC__
1319 #include <stdarg.h>
1320 #else
1321 #include <varargs.h>
1322 #endif
1323
1324 void
1325 #if __STDC__
1326 msg(const char *fmt, ...)
1327 #else
1328 msg(fmt, va_alist)
1329 char *fmt;
1330 va_dcl
1331 #endif
1332 {
1333 va_list ap;
1334 #if __STDC__
1335 va_start(ap, fmt);
1336 #else
1337 va_start(ap);
1338 #endif
1339 (void)vfprintf(stderr, fmt, ap);
1340 va_end(ap);
1341 }
1342 #endif /* RRESTORE */
1343
1344 static u_char *
1345 swabshort(sp, n)
1346 u_char *sp;
1347 int n;
1348 {
1349 char c;
1350
1351 while (--n >= 0) {
1352 c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1353 sp += 2;
1354 }
1355 return (sp);
1356 }
1357
1358 static u_char *
1359 swablong(sp, n)
1360 u_char *sp;
1361 int n;
1362 {
1363 char c;
1364
1365 while (--n >= 0) {
1366 c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1367 c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1368 sp += 4;
1369 }
1370 return (sp);
1371 }
1372
1373 void
1374 swabst(cp, sp)
1375 u_char *cp, *sp;
1376 {
1377 int n = 0;
1378
1379 while (*cp) {
1380 switch (*cp) {
1381 case '0': case '1': case '2': case '3': case '4':
1382 case '5': case '6': case '7': case '8': case '9':
1383 n = (n * 10) + (*cp++ - '0');
1384 continue;
1385
1386 case 's': case 'w': case 'h':
1387 if (n == 0)
1388 n = 1;
1389 sp = swabshort(sp, n);
1390 break;
1391
1392 case 'l':
1393 if (n == 0)
1394 n = 1;
1395 sp = swablong(sp, n);
1396 break;
1397
1398 default: /* Any other character, like 'b' counts as byte. */
1399 if (n == 0)
1400 n = 1;
1401 sp += n;
1402 break;
1403 }
1404 cp++;
1405 n = 0;
1406 }
1407 }
1408
1409 static u_long
1410 swabl(x)
1411 u_long x;
1412 {
1413 swabst((u_char *)"l", (u_char *)&x);
1414 return (x);
1415 }
1416