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