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