tape.c revision 1.43 1 /* $NetBSD: tape.c,v 1.43 2001/01/24 23:14:04 enami 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.43 2001/01/24 23:14:04 enami 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 (void) lchflags(name, flags);
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_type == TS_BITS || spcl.c_type == TS_CLRI ||
706 spcl.c_addr[i]) {
707 readtape(&buf[curblk++][0]);
708 if (curblk == fssize / TP_BSIZE) {
709 (*fill)((char *)buf, (long)(size > TP_BSIZE ?
710 fssize : (curblk - 1) * TP_BSIZE + size));
711 curblk = 0;
712 }
713 } else {
714 if (curblk > 0) {
715 (*fill)((char *)buf, (long)(size > TP_BSIZE ?
716 curblk * TP_BSIZE :
717 (curblk - 1) * TP_BSIZE + size));
718 curblk = 0;
719 }
720 (*skip)(clearedbuf, (long)(size > TP_BSIZE ?
721 TP_BSIZE : size));
722 }
723 if ((size -= TP_BSIZE) <= 0) {
724 if (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) {
725 /*
726 * In this case, the following expression
727 * should always be false since the size was
728 * initially set to spcl.c_dinode.di_size and
729 * it is initialized to spcl.c_count * TP_BSIZE
730 * in gethead().
731 */
732 if (!(size == 0 && i == spcl.c_count - 1))
733 panic("inconsistent map size\n");
734 } else {
735 for (i++; i < spcl.c_count; i++)
736 if (spcl.c_addr[i])
737 readtape(junk);
738 }
739 break;
740 }
741 }
742 if (gethead(&spcl) == GOOD && size > 0) {
743 if (spcl.c_type == TS_ADDR)
744 goto loop;
745 dprintf(stdout,
746 "Missing address (header) block for %s at %d blocks\n",
747 curfile.name, blksread);
748 }
749 if (curblk > 0)
750 (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
751 findinode(&spcl);
752 gettingfile = 0;
753 }
754
755 /*
756 * Write out the next block of a file.
757 */
758 static void
759 xtrfile(buf, size)
760 char *buf;
761 long size;
762 {
763
764 if (Nflag)
765 return;
766 if (write(ofile, buf, (int) size) == -1) {
767 fprintf(stderr,
768 "write error extracting inode %d, name %s\nwrite: %s\n",
769 curfile.ino, curfile.name, strerror(errno));
770 exit(1);
771 }
772 }
773
774 /*
775 * Skip over a hole in a file.
776 */
777 /* ARGSUSED */
778 static void
779 xtrskip(buf, size)
780 char *buf;
781 long size;
782 {
783
784 if (lseek(ofile, size, SEEK_CUR) == -1) {
785 fprintf(stderr,
786 "seek error extracting inode %d, name %s\nlseek: %s\n",
787 curfile.ino, curfile.name, strerror(errno));
788 exit(1);
789 }
790 }
791
792 /*
793 * Collect the next block of a symbolic link.
794 */
795 static void
796 xtrlnkfile(buf, size)
797 char *buf;
798 long size;
799 {
800
801 pathlen += size;
802 if (pathlen > MAXPATHLEN) {
803 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
804 curfile.name, lnkbuf, buf, pathlen);
805 exit(1);
806 }
807 (void) strcat(lnkbuf, buf);
808 }
809
810 /*
811 * Skip over a hole in a symbolic link (should never happen).
812 */
813 /* ARGSUSED */
814 static void
815 xtrlnkskip(buf, size)
816 char *buf;
817 long size;
818 {
819
820 fprintf(stderr, "unallocated block in symbolic link %s\n",
821 curfile.name);
822 exit(1);
823 }
824
825 /*
826 * Collect the next block of a bit map.
827 */
828 static void
829 xtrmap(buf, size)
830 char *buf;
831 long size;
832 {
833
834 memmove(map, buf, size);
835 map += size;
836 }
837
838 /*
839 * Skip over a hole in a bit map (should never happen).
840 */
841 /* ARGSUSED */
842 static void
843 xtrmapskip(buf, size)
844 char *buf;
845 long size;
846 {
847
848 panic("hole in map\n");
849 map += size;
850 }
851
852 /*
853 * Noop, when an extraction function is not needed.
854 */
855 /* ARGSUSED */
856 void
857 xtrnull(buf, size)
858 char *buf;
859 long size;
860 {
861
862 return;
863 }
864
865 /*
866 * Read TP_BSIZE blocks from the input.
867 * Handle read errors, and end of media.
868 */
869 static void
870 readtape(buf)
871 char *buf;
872 {
873 int rd, newvol, i;
874 int cnt, seek_failed;
875
876 if (blkcnt < numtrec) {
877 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
878 blksread++;
879 tpblksread++;
880 return;
881 }
882 for (i = 0; i < ntrec; i++)
883 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
884 if (numtrec == 0)
885 numtrec = ntrec;
886 cnt = ntrec * TP_BSIZE;
887 rd = 0;
888 getmore:
889 #ifdef RRESTORE
890 if (host)
891 i = rmtread(&tapebuf[rd], cnt);
892 else
893 #endif
894 i = read(mt, &tapebuf[rd], cnt);
895 /*
896 * Check for mid-tape short read error.
897 * If found, skip rest of buffer and start with the next.
898 */
899 if (!pipein && numtrec < ntrec && i > 0) {
900 dprintf(stdout, "mid-media short read error.\n");
901 numtrec = ntrec;
902 }
903 /*
904 * Handle partial block read.
905 */
906 if (pipein && i == 0 && rd > 0)
907 i = rd;
908 else if (i > 0 && i != ntrec * TP_BSIZE) {
909 if (pipein) {
910 rd += i;
911 cnt -= i;
912 if (cnt > 0)
913 goto getmore;
914 i = rd;
915 } else {
916 /*
917 * Short read. Process the blocks read.
918 */
919 if (i % TP_BSIZE != 0)
920 vprintf(stdout,
921 "partial block read: %d should be %d\n",
922 i, ntrec * TP_BSIZE);
923 numtrec = i / TP_BSIZE;
924 }
925 }
926 /*
927 * Handle read error.
928 */
929 if (i < 0) {
930 fprintf(stderr, "Tape read error while ");
931 switch (curfile.action) {
932 default:
933 fprintf(stderr, "trying to set up tape\n");
934 break;
935 case UNKNOWN:
936 fprintf(stderr, "trying to resynchronize\n");
937 break;
938 case USING:
939 fprintf(stderr, "restoring %s\n", curfile.name);
940 break;
941 case SKIP:
942 fprintf(stderr, "skipping over inode %d\n",
943 curfile.ino);
944 break;
945 }
946 if (!yflag && !reply("continue"))
947 exit(1);
948 i = ntrec * TP_BSIZE;
949 memset(tapebuf, 0, i);
950 #ifdef RRESTORE
951 if (host)
952 seek_failed = (rmtseek(i, 1) < 0);
953 else
954 #endif
955 seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
956
957 if (seek_failed) {
958 fprintf(stderr,
959 "continuation failed: %s\n", strerror(errno));
960 exit(1);
961 }
962 }
963 /*
964 * Handle end of tape.
965 */
966 if (i == 0) {
967 vprintf(stdout, "End-of-tape encountered\n");
968 if (!pipein) {
969 newvol = volno + 1;
970 volno = 0;
971 numtrec = 0;
972 getvol(newvol);
973 readtape(buf);
974 return;
975 }
976 if (rd % TP_BSIZE != 0)
977 panic("partial block read: %d should be %d\n",
978 rd, ntrec * TP_BSIZE);
979 terminateinput();
980 memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
981 }
982 blkcnt = 0;
983 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
984 blksread++;
985 tpblksread++;
986 }
987
988 static void
989 findtapeblksize()
990 {
991 long i;
992
993 for (i = 0; i < ntrec; i++)
994 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
995 blkcnt = 0;
996 #ifdef RRESTORE
997 if (host)
998 i = rmtread(tapebuf, ntrec * TP_BSIZE);
999 else
1000 #endif
1001 i = read(mt, tapebuf, ntrec * TP_BSIZE);
1002
1003 if (i <= 0) {
1004 fprintf(stderr, "tape read error: %s\n", strerror(errno));
1005 exit(1);
1006 }
1007 if (i % TP_BSIZE != 0) {
1008 fprintf(stderr, "Tape block size (%ld) %s (%ld)\n",
1009 (long)i, "is not a multiple of dump block size",
1010 (long)TP_BSIZE);
1011 exit(1);
1012 }
1013 ntrec = i / TP_BSIZE;
1014 numtrec = ntrec;
1015 vprintf(stdout, "Tape block size is %d\n", ntrec);
1016 }
1017
1018 void
1019 closemt()
1020 {
1021
1022 if (mt < 0)
1023 return;
1024 #ifdef RRESTORE
1025 if (host)
1026 rmtclose();
1027 else
1028 #endif
1029 (void) close(mt);
1030 }
1031
1032 /*
1033 * Read the next block from the tape.
1034 * Check to see if it is one of several vintage headers.
1035 * If it is an old style header, convert it to a new style header.
1036 * If it is not any valid header, return an error.
1037 */
1038 static int
1039 gethead(buf)
1040 struct s_spcl *buf;
1041 {
1042 long i;
1043 union {
1044 quad_t qval;
1045 int32_t val[2];
1046 } qcvt;
1047 union u_ospcl {
1048 char dummy[TP_BSIZE];
1049 struct s_ospcl {
1050 int32_t c_type;
1051 int32_t c_date;
1052 int32_t c_ddate;
1053 int32_t c_volume;
1054 int32_t c_tapea;
1055 u_int16_t c_inumber;
1056 int32_t c_magic;
1057 int32_t c_checksum;
1058 struct odinode {
1059 unsigned short odi_mode;
1060 u_int16_t odi_nlink;
1061 u_int16_t odi_uid;
1062 u_int16_t odi_gid;
1063 int32_t odi_size;
1064 int32_t odi_rdev;
1065 char odi_addr[36];
1066 int32_t odi_atime;
1067 int32_t odi_mtime;
1068 int32_t odi_ctime;
1069 } c_dinode;
1070 int32_t c_count;
1071 char c_addr[256];
1072 } s_ospcl;
1073 } u_ospcl;
1074
1075 if (!cvtflag) {
1076 readtape((char *)buf);
1077 if (buf->c_magic != NFS_MAGIC) {
1078 if (swabl(buf->c_magic) != NFS_MAGIC)
1079 return (FAIL);
1080 if (!Bcvt) {
1081 vprintf(stdout, "Note: Doing Byte swapping\n");
1082 Bcvt = 1;
1083 }
1084 }
1085 if (checksum((int *)buf) == FAIL)
1086 return (FAIL);
1087 if (Bcvt)
1088 swabst((u_char *)"8l4s31l528b1l192b2l", (u_char *)buf);
1089 goto good;
1090 }
1091 readtape((char *)(&u_ospcl.s_ospcl));
1092 memset(buf, 0, (long)TP_BSIZE);
1093 buf->c_type = u_ospcl.s_ospcl.c_type;
1094 buf->c_date = u_ospcl.s_ospcl.c_date;
1095 buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1096 buf->c_volume = u_ospcl.s_ospcl.c_volume;
1097 buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1098 buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
1099 buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
1100 buf->c_magic = u_ospcl.s_ospcl.c_magic;
1101 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1102 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1103 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1104 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1105 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
1106 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1107 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
1108 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1109 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1110 buf->c_count = u_ospcl.s_ospcl.c_count;
1111 memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256);
1112 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
1113 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
1114 return(FAIL);
1115 buf->c_magic = NFS_MAGIC;
1116
1117 good:
1118 if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
1119 (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
1120 qcvt.qval = buf->c_dinode.di_size;
1121 if (qcvt.val[0] || qcvt.val[1]) {
1122 printf("Note: Doing Quad swapping\n");
1123 Qcvt = 1;
1124 }
1125 }
1126 if (Qcvt) {
1127 qcvt.qval = buf->c_dinode.di_size;
1128 i = qcvt.val[1];
1129 qcvt.val[1] = qcvt.val[0];
1130 qcvt.val[0] = i;
1131 buf->c_dinode.di_size = qcvt.qval;
1132 }
1133
1134 switch (buf->c_type) {
1135
1136 case TS_CLRI:
1137 case TS_BITS:
1138 /*
1139 * Have to patch up missing information in bit map headers
1140 */
1141 buf->c_inumber = 0;
1142 buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
1143 break;
1144
1145 case TS_TAPE:
1146 if ((buf->c_flags & DR_NEWINODEFMT) == 0)
1147 oldinofmt = 1;
1148 /* fall through */
1149 case TS_END:
1150 buf->c_inumber = 0;
1151 break;
1152
1153 case TS_INODE:
1154 case TS_ADDR:
1155 break;
1156
1157 default:
1158 panic("gethead: unknown inode type %d\n", buf->c_type);
1159 break;
1160 }
1161 /*
1162 * If we are restoring a filesystem with old format inodes,
1163 * copy the uid/gid to the new location.
1164 */
1165 if (oldinofmt) {
1166 buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
1167 buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
1168 }
1169 if (dflag)
1170 accthdr(buf);
1171 return(GOOD);
1172 }
1173
1174 /*
1175 * Check that a header is where it belongs and predict the next header
1176 */
1177 static void
1178 accthdr(header)
1179 struct s_spcl *header;
1180 {
1181 static ino_t previno = 0x7fffffff;
1182 static int prevtype;
1183 static long predict;
1184 long blks, i;
1185
1186 if (header->c_type == TS_TAPE) {
1187 fprintf(stderr, "Volume header (%s inode format) ",
1188 oldinofmt ? "old" : "new");
1189 if (header->c_firstrec)
1190 fprintf(stderr, "begins with record %d",
1191 header->c_firstrec);
1192 fprintf(stderr, "\n");
1193 previno = 0x7fffffff;
1194 return;
1195 }
1196 if (previno == 0x7fffffff)
1197 goto newcalc;
1198 switch (prevtype) {
1199 case TS_BITS:
1200 fprintf(stderr, "Dumped inodes map header");
1201 break;
1202 case TS_CLRI:
1203 fprintf(stderr, "Used inodes map header");
1204 break;
1205 case TS_INODE:
1206 fprintf(stderr, "File header, ino %d", previno);
1207 break;
1208 case TS_ADDR:
1209 fprintf(stderr, "File continuation header, ino %d", previno);
1210 break;
1211 case TS_END:
1212 fprintf(stderr, "End of tape header");
1213 break;
1214 }
1215 if (predict != blksread - 1)
1216 fprintf(stderr, "; predicted %ld blocks, got %ld blocks",
1217 (long)predict, (long)(blksread - 1));
1218 fprintf(stderr, "\n");
1219 newcalc:
1220 blks = 0;
1221 switch (header->c_type) {
1222 case TS_END:
1223 break;
1224 case TS_CLRI:
1225 case TS_BITS:
1226 blks = header->c_count;
1227 break;
1228 default:
1229 for (i = 0; i < header->c_count; i++)
1230 if (header->c_addr[i] != 0)
1231 blks++;
1232 break;
1233 }
1234 predict = blks;
1235 blksread = 0;
1236 prevtype = header->c_type;
1237 previno = header->c_inumber;
1238 }
1239
1240 /*
1241 * Find an inode header.
1242 * Complain if had to skip, and complain is set.
1243 */
1244 static void
1245 findinode(header)
1246 struct s_spcl *header;
1247 {
1248 static long skipcnt = 0;
1249 long i;
1250 char buf[TP_BSIZE];
1251
1252 curfile.name = "<name unknown>";
1253 curfile.action = UNKNOWN;
1254 curfile.dip = NULL;
1255 curfile.ino = 0;
1256 do {
1257 if (header->c_magic != NFS_MAGIC) {
1258 skipcnt++;
1259 while (gethead(header) == FAIL ||
1260 header->c_date != dumpdate)
1261 skipcnt++;
1262 }
1263 switch (header->c_type) {
1264
1265 case TS_ADDR:
1266 /*
1267 * Skip up to the beginning of the next record
1268 */
1269 for (i = 0; i < header->c_count; i++)
1270 if (header->c_addr[i])
1271 readtape(buf);
1272 while (gethead(header) == FAIL ||
1273 header->c_date != dumpdate)
1274 skipcnt++;
1275 break;
1276
1277 case TS_INODE:
1278 curfile.dip = &header->c_dinode;
1279 curfile.ino = header->c_inumber;
1280 break;
1281
1282 case TS_END:
1283 curfile.ino = maxino;
1284 break;
1285
1286 case TS_CLRI:
1287 curfile.name = "<file removal list>";
1288 break;
1289
1290 case TS_BITS:
1291 curfile.name = "<file dump list>";
1292 break;
1293
1294 case TS_TAPE:
1295 panic("unexpected tape header\n");
1296 break;
1297
1298 default:
1299 panic("unknown tape header type %d\n", spcl.c_type);
1300 break;
1301
1302 }
1303 } while (header->c_type == TS_ADDR);
1304 if (skipcnt > 0)
1305 fprintf(stderr, "resync restore, skipped %ld blocks\n",
1306 (long)skipcnt);
1307 skipcnt = 0;
1308 }
1309
1310 static int
1311 checksum(buf)
1312 int *buf;
1313 {
1314 int i, j;
1315
1316 j = sizeof(union u_spcl) / sizeof(int);
1317 i = 0;
1318 if(!Bcvt) {
1319 do
1320 i += *buf++;
1321 while (--j);
1322 } else {
1323 /* What happens if we want to read restore tapes
1324 for a 16bit int machine??? */
1325 do
1326 i += swabl(*buf++);
1327 while (--j);
1328 }
1329
1330 if (i != CHECKSUM) {
1331 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
1332 curfile.ino, curfile.name);
1333 return(FAIL);
1334 }
1335 return(GOOD);
1336 }
1337
1338 #ifdef RRESTORE
1339 #if __STDC__
1340 #include <stdarg.h>
1341 #else
1342 #include <varargs.h>
1343 #endif
1344
1345 void
1346 #if __STDC__
1347 msg(const char *fmt, ...)
1348 #else
1349 msg(fmt, va_alist)
1350 char *fmt;
1351 va_dcl
1352 #endif
1353 {
1354 va_list ap;
1355 #if __STDC__
1356 va_start(ap, fmt);
1357 #else
1358 va_start(ap);
1359 #endif
1360 (void)vfprintf(stderr, fmt, ap);
1361 va_end(ap);
1362 }
1363 #endif /* RRESTORE */
1364
1365 static u_char *
1366 swabshort(sp, n)
1367 u_char *sp;
1368 int n;
1369 {
1370 char c;
1371
1372 while (--n >= 0) {
1373 c = sp[0]; sp[0] = sp[1]; sp[1] = c;
1374 sp += 2;
1375 }
1376 return (sp);
1377 }
1378
1379 static u_char *
1380 swablong(sp, n)
1381 u_char *sp;
1382 int n;
1383 {
1384 char c;
1385
1386 while (--n >= 0) {
1387 c = sp[0]; sp[0] = sp[3]; sp[3] = c;
1388 c = sp[2]; sp[2] = sp[1]; sp[1] = c;
1389 sp += 4;
1390 }
1391 return (sp);
1392 }
1393
1394 void
1395 swabst(cp, sp)
1396 u_char *cp, *sp;
1397 {
1398 int n = 0;
1399
1400 while (*cp) {
1401 switch (*cp) {
1402 case '0': case '1': case '2': case '3': case '4':
1403 case '5': case '6': case '7': case '8': case '9':
1404 n = (n * 10) + (*cp++ - '0');
1405 continue;
1406
1407 case 's': case 'w': case 'h':
1408 if (n == 0)
1409 n = 1;
1410 sp = swabshort(sp, n);
1411 break;
1412
1413 case 'l':
1414 if (n == 0)
1415 n = 1;
1416 sp = swablong(sp, n);
1417 break;
1418
1419 default: /* Any other character, like 'b' counts as byte. */
1420 if (n == 0)
1421 n = 1;
1422 sp += n;
1423 break;
1424 }
1425 cp++;
1426 n = 0;
1427 }
1428 }
1429
1430 static u_long
1431 swabl(x)
1432 u_long x;
1433 {
1434 swabst((u_char *)"l", (u_char *)&x);
1435 return (x);
1436 }
1437