1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 static char sccsid[] = "@(#)tape.c 5.14 (Berkeley) 05/13/88"; 9 #endif not lint 10 11 #include "restore.h" 12 #include <protocols/dumprestore.h> 13 #include <sys/ioctl.h> 14 #include <sys/mtio.h> 15 #include <sys/file.h> 16 #include <setjmp.h> 17 #include <sys/stat.h> 18 19 static long fssize = MAXBSIZE; 20 static int mt = -1; 21 static int pipein = 0; 22 static char magtape[BUFSIZ]; 23 static int bct; 24 static char *tbf; 25 static union u_spcl endoftapemark; 26 static long blksread; 27 static long tapesread; 28 static jmp_buf restart; 29 static int gettingfile = 0; /* restart has a valid frame */ 30 31 static int ofile; 32 static char *map; 33 static char lnkbuf[MAXPATHLEN + 1]; 34 static int pathlen; 35 36 int Bcvt; /* Swap Bytes (for CCI or sun) */ 37 static int Qcvt; /* Swap quads (for sun) */ 38 /* 39 * Set up an input source 40 */ 41 setinput(source) 42 char *source; 43 { 44 #ifdef RRESTORE 45 char *host, *tape; 46 #endif RRESTORE 47 48 flsht(); 49 if (bflag) 50 newtapebuf(ntrec); 51 else 52 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC); 53 terminal = stdin; 54 #ifdef RRESTORE 55 host = source; 56 tape = index(host, ':'); 57 if (tape == 0) { 58 nohost: 59 msg("need keyletter ``f'' and device ``host:tape''\n"); 60 done(1); 61 } 62 *tape++ = '\0'; 63 (void) strcpy(magtape, tape); 64 if (rmthost(host) == 0) 65 done(1); 66 setuid(getuid()); /* no longer need or want root privileges */ 67 #else 68 if (strcmp(source, "-") == 0) { 69 /* 70 * Since input is coming from a pipe we must establish 71 * our own connection to the terminal. 72 */ 73 terminal = fopen("/dev/tty", "r"); 74 if (terminal == NULL) { 75 perror("Cannot open(\"/dev/tty\")"); 76 terminal = fopen("/dev/null", "r"); 77 if (terminal == NULL) { 78 perror("Cannot open(\"/dev/null\")"); 79 done(1); 80 } 81 } 82 pipein++; 83 } 84 (void) strcpy(magtape, source); 85 #endif RRESTORE 86 } 87 88 newtapebuf(size) 89 long size; 90 { 91 static tbfsize = -1; 92 93 ntrec = size; 94 if (size <= tbfsize) 95 return; 96 if (tbf != NULL) 97 free(tbf); 98 tbf = (char *)malloc(size * TP_BSIZE); 99 if (tbf == NULL) { 100 fprintf(stderr, "Cannot allocate space for tape buffer\n"); 101 done(1); 102 } 103 tbfsize = size; 104 } 105 106 /* 107 * Verify that the tape drive can be accessed and 108 * that it actually is a dump tape. 109 */ 110 setup() 111 { 112 int i, j, *ip; 113 struct stat stbuf; 114 extern int xtrmap(), xtrmapskip(); 115 116 vprintf(stdout, "Verify tape and initialize maps\n"); 117 #ifdef RRESTORE 118 if ((mt = rmtopen(magtape, 0)) < 0) 119 #else 120 if (pipein) 121 mt = 0; 122 else if ((mt = open(magtape, 0)) < 0) 123 #endif 124 { 125 perror(magtape); 126 done(1); 127 } 128 volno = 1; 129 setdumpnum(); 130 flsht(); 131 if (!pipein && !bflag) 132 findtapeblksize(); 133 if (gethead(&spcl) == FAIL) { 134 bct--; /* push back this block */ 135 cvtflag++; 136 if (gethead(&spcl) == FAIL) { 137 fprintf(stderr, "Tape is not a dump tape\n"); 138 done(1); 139 } 140 fprintf(stderr, "Converting to new file system format.\n"); 141 } 142 if (pipein) { 143 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC; 144 endoftapemark.s_spcl.c_type = TS_END; 145 ip = (int *)&endoftapemark; 146 j = sizeof(union u_spcl) / sizeof(int); 147 i = 0; 148 do 149 i += *ip++; 150 while (--j); 151 endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 152 } 153 if (vflag || command == 't') 154 printdumpinfo(); 155 dumptime = spcl.c_ddate; 156 dumpdate = spcl.c_date; 157 if (stat(".", &stbuf) < 0) { 158 perror("cannot stat ."); 159 done(1); 160 } 161 if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE) 162 fssize = stbuf.st_blksize; 163 if (((fssize - 1) & fssize) != 0) { 164 fprintf(stderr, "bad block size %d\n", fssize); 165 done(1); 166 } 167 if (checkvol(&spcl, (long)1) == FAIL) { 168 fprintf(stderr, "Tape is not volume 1 of the dump\n"); 169 done(1); 170 } 171 if (readhdr(&spcl) == FAIL) 172 panic("no header after volume mark!\n"); 173 findinode(&spcl); 174 if (checktype(&spcl, TS_CLRI) == FAIL) { 175 fprintf(stderr, "Cannot find file removal list\n"); 176 done(1); 177 } 178 maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; 179 dprintf(stdout, "maxino = %d\n", maxino); 180 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 181 if (map == (char *)NIL) 182 panic("no memory for file removal list\n"); 183 clrimap = map; 184 curfile.action = USING; 185 getfile(xtrmap, xtrmapskip); 186 if (checktype(&spcl, TS_BITS) == FAIL) { 187 fprintf(stderr, "Cannot find file dump list\n"); 188 done(1); 189 } 190 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 191 if (map == (char *)NULL) 192 panic("no memory for file dump list\n"); 193 dumpmap = map; 194 curfile.action = USING; 195 getfile(xtrmap, xtrmapskip); 196 } 197 198 /* 199 * Prompt user to load a new dump volume. 200 * "Nextvol" is the next suggested volume to use. 201 * This suggested volume is enforced when doing full 202 * or incremental restores, but can be overrridden by 203 * the user when only extracting a subset of the files. 204 */ 205 getvol(nextvol) 206 long nextvol; 207 { 208 long newvol; 209 long savecnt, i; 210 union u_spcl tmpspcl; 211 # define tmpbuf tmpspcl.s_spcl 212 char buf[TP_BSIZE]; 213 extern char *ctime(); 214 215 if (nextvol == 1) { 216 tapesread = 0; 217 gettingfile = 0; 218 } 219 if (pipein) { 220 if (nextvol != 1) 221 panic("Changing volumes on pipe input?\n"); 222 if (volno == 1) 223 return; 224 goto gethdr; 225 } 226 savecnt = blksread; 227 again: 228 if (pipein) 229 done(1); /* pipes do not get a second chance */ 230 if (command == 'R' || command == 'r' || curfile.action != SKIP) 231 newvol = nextvol; 232 else 233 newvol = 0; 234 while (newvol <= 0) { 235 if (tapesread == 0) { 236 fprintf(stderr, "%s%s%s%s%s", 237 "You have not read any tapes yet.\n", 238 "Unless you know which volume your", 239 " file(s) are on you should start\n", 240 "with the last volume and work", 241 " towards towards the first.\n"); 242 } else { 243 fprintf(stderr, "You have read volumes"); 244 strcpy(tbf, ": "); 245 for (i = 1; i < 32; i++) 246 if (tapesread & (1 << i)) { 247 fprintf(stderr, "%s%d", tbf, i); 248 strcpy(tbf, ", "); 249 } 250 fprintf(stderr, "\n"); 251 } 252 do { 253 fprintf(stderr, "Specify next volume #: "); 254 (void) fflush(stderr); 255 (void) fgets(tbf, BUFSIZ, terminal); 256 } while (!feof(terminal) && tbf[0] == '\n'); 257 if (feof(terminal)) 258 done(1); 259 newvol = atoi(tbf); 260 if (newvol <= 0) { 261 fprintf(stderr, 262 "Volume numbers are positive numerics\n"); 263 } 264 } 265 if (newvol == volno) { 266 tapesread |= 1 << volno; 267 return; 268 } 269 closemt(); 270 fprintf(stderr, "Mount tape volume %d\n", newvol); 271 fprintf(stderr, "then enter tape name (default: %s) ", magtape); 272 (void) fflush(stderr); 273 (void) fgets(tbf, BUFSIZ, terminal); 274 if (feof(terminal)) 275 done(1); 276 if (tbf[0] != '\n') { 277 (void) strcpy(magtape, tbf); 278 magtape[strlen(magtape) - 1] = '\0'; 279 } 280 #ifdef RRESTORE 281 if ((mt = rmtopen(magtape, 0)) == -1) 282 #else 283 if ((mt = open(magtape, 0)) == -1) 284 #endif 285 { 286 fprintf(stderr, "Cannot open %s\n", magtape); 287 volno = -1; 288 goto again; 289 } 290 gethdr: 291 volno = newvol; 292 setdumpnum(); 293 flsht(); 294 if (readhdr(&tmpbuf) == FAIL) { 295 fprintf(stderr, "tape is not dump tape\n"); 296 volno = 0; 297 goto again; 298 } 299 if (checkvol(&tmpbuf, volno) == FAIL) { 300 fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume); 301 volno = 0; 302 goto again; 303 } 304 if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) { 305 fprintf(stderr, "Wrong dump date\n\tgot: %s", 306 ctime(&tmpbuf.c_date)); 307 fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); 308 volno = 0; 309 goto again; 310 } 311 tapesread |= 1 << volno; 312 blksread = savecnt; 313 if (curfile.action == USING) { 314 if (volno == 1) 315 panic("active file into volume 1\n"); 316 return; 317 } 318 /* 319 * Skip up to the beginning of the next record 320 */ 321 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) 322 for (i = tmpbuf.c_count; i > 0; i--) 323 readtape(buf); 324 (void) gethead(&spcl); 325 findinode(&spcl); 326 if (gettingfile) { 327 gettingfile = 0; 328 longjmp(restart, 1); 329 } 330 } 331 332 /* 333 * handle multiple dumps per tape by skipping forward to the 334 * appropriate one. 335 */ 336 setdumpnum() 337 { 338 struct mtop tcom; 339 340 if (dumpnum == 1 || volno != 1) 341 return; 342 if (pipein) { 343 fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); 344 done(1); 345 } 346 tcom.mt_op = MTFSF; 347 tcom.mt_count = dumpnum - 1; 348 #ifdef RRESTORE 349 rmtioctl(MTFSF, dumpnum - 1); 350 #else 351 if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0) 352 perror("ioctl MTFSF"); 353 #endif 354 } 355 356 printdumpinfo() 357 { 358 extern char *ctime(); 359 360 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date)); 361 fprintf(stdout, "Dumped from: %s", 362 (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate)); 363 if (spcl.c_host[0] == '\0') 364 return; 365 fprintf(stderr, "Level %d dump of %s on %s:%s\n", 366 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); 367 fprintf(stderr, "Label: %s\n", spcl.c_label); 368 } 369 370 extractfile(name) 371 char *name; 372 { 373 int mode; 374 time_t timep[2]; 375 struct entry *ep; 376 extern int xtrlnkfile(), xtrlnkskip(); 377 extern int xtrfile(), xtrskip(); 378 379 curfile.name = name; 380 curfile.action = USING; 381 timep[0] = curfile.dip->di_atime; 382 timep[1] = curfile.dip->di_mtime; 383 mode = curfile.dip->di_mode; 384 switch (mode & IFMT) { 385 386 default: 387 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); 388 skipfile(); 389 return (FAIL); 390 391 case IFSOCK: 392 vprintf(stdout, "skipped socket %s\n", name); 393 skipfile(); 394 return (GOOD); 395 396 case IFDIR: 397 if (mflag) { 398 ep = lookupname(name); 399 if (ep == NIL || ep->e_flags & EXTRACT) 400 panic("unextracted directory %s\n", name); 401 skipfile(); 402 return (GOOD); 403 } 404 vprintf(stdout, "extract file %s\n", name); 405 return (genliteraldir(name, curfile.ino)); 406 407 case IFLNK: 408 lnkbuf[0] = '\0'; 409 pathlen = 0; 410 getfile(xtrlnkfile, xtrlnkskip); 411 if (pathlen == 0) { 412 vprintf(stdout, 413 "%s: zero length symbolic link (ignored)\n", name); 414 return (GOOD); 415 } 416 return (linkit(lnkbuf, name, SYMLINK)); 417 418 case IFCHR: 419 case IFBLK: 420 vprintf(stdout, "extract special file %s\n", name); 421 if (Nflag) { 422 skipfile(); 423 return (GOOD); 424 } 425 if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) { 426 fprintf(stderr, "%s: ", name); 427 (void) fflush(stderr); 428 perror("cannot create special file"); 429 skipfile(); 430 return (FAIL); 431 } 432 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); 433 (void) chmod(name, mode); 434 skipfile(); 435 utime(name, timep); 436 return (GOOD); 437 438 case IFREG: 439 vprintf(stdout, "extract file %s\n", name); 440 if (Nflag) { 441 skipfile(); 442 return (GOOD); 443 } 444 if ((ofile = creat(name, 0666)) < 0) { 445 fprintf(stderr, "%s: ", name); 446 (void) fflush(stderr); 447 perror("cannot create file"); 448 skipfile(); 449 return (FAIL); 450 } 451 (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid); 452 (void) fchmod(ofile, mode); 453 getfile(xtrfile, xtrskip); 454 (void) close(ofile); 455 utime(name, timep); 456 return (GOOD); 457 } 458 /* NOTREACHED */ 459 } 460 461 /* 462 * skip over bit maps on the tape 463 */ 464 skipmaps() 465 { 466 467 while (checktype(&spcl, TS_CLRI) == GOOD || 468 checktype(&spcl, TS_BITS) == GOOD) 469 skipfile(); 470 } 471 472 /* 473 * skip over a file on the tape 474 */ 475 skipfile() 476 { 477 extern int null(); 478 479 curfile.action = SKIP; 480 getfile(null, null); 481 } 482 483 /* 484 * Do the file extraction, calling the supplied functions 485 * with the blocks 486 */ 487 getfile(f1, f2) 488 int (*f2)(), (*f1)(); 489 { 490 register int i; 491 int curblk = 0; 492 off_t size = spcl.c_dinode.di_size; 493 static char clearedbuf[MAXBSIZE]; 494 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 495 char junk[TP_BSIZE]; 496 497 if (checktype(&spcl, TS_END) == GOOD) 498 panic("ran off end of tape\n"); 499 if (ishead(&spcl) == FAIL) 500 panic("not at beginning of a file\n"); 501 if (!gettingfile && setjmp(restart) != 0) 502 return; 503 gettingfile++; 504 loop: 505 for (i = 0; i < spcl.c_count; i++) { 506 if (spcl.c_addr[i]) { 507 readtape(&buf[curblk++][0]); 508 if (curblk == fssize / TP_BSIZE) { 509 (*f1)(buf, size > TP_BSIZE ? 510 (long) (fssize) : 511 (curblk - 1) * TP_BSIZE + size); 512 curblk = 0; 513 } 514 } else { 515 if (curblk > 0) { 516 (*f1)(buf, size > TP_BSIZE ? 517 (long) (curblk * TP_BSIZE) : 518 (curblk - 1) * TP_BSIZE + size); 519 curblk = 0; 520 } 521 (*f2)(clearedbuf, size > TP_BSIZE ? 522 (long) TP_BSIZE : size); 523 } 524 if ((size -= TP_BSIZE) <= 0) { 525 for (i++; i < spcl.c_count; i++) 526 if (spcl.c_addr[i]) 527 readtape(junk); 528 break; 529 } 530 } 531 if (readhdr(&spcl) == GOOD && size > 0) { 532 if (checktype(&spcl, TS_ADDR) == GOOD) 533 goto loop; 534 dprintf(stdout, "Missing address (header) block for %s\n", 535 curfile.name); 536 } 537 if (curblk > 0) 538 (*f1)(buf, (curblk * TP_BSIZE) + size); 539 findinode(&spcl); 540 gettingfile = 0; 541 } 542 543 /* 544 * The next routines are called during file extraction to 545 * put the data into the right form and place. 546 */ 547 xtrfile(buf, size) 548 char *buf; 549 long size; 550 { 551 552 if (Nflag) 553 return; 554 if (write(ofile, buf, (int) size) == -1) { 555 fprintf(stderr, "write error extracting inode %d, name %s\n", 556 curfile.ino, curfile.name); 557 perror("write"); 558 done(1); 559 } 560 } 561 562 xtrskip(buf, size) 563 char *buf; 564 long size; 565 { 566 567 #ifdef lint 568 buf = buf; 569 #endif 570 if (lseek(ofile, size, 1) == (long)-1) { 571 fprintf(stderr, "seek error extracting inode %d, name %s\n", 572 curfile.ino, curfile.name); 573 perror("lseek"); 574 done(1); 575 } 576 } 577 578 xtrlnkfile(buf, size) 579 char *buf; 580 long size; 581 { 582 583 pathlen += size; 584 if (pathlen > MAXPATHLEN) { 585 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", 586 curfile.name, lnkbuf, buf, pathlen); 587 done(1); 588 } 589 (void) strcat(lnkbuf, buf); 590 } 591 592 xtrlnkskip(buf, size) 593 char *buf; 594 long size; 595 { 596 597 #ifdef lint 598 buf = buf, size = size; 599 #endif 600 fprintf(stderr, "unallocated block in symbolic link %s\n", 601 curfile.name); 602 done(1); 603 } 604 605 xtrmap(buf, size) 606 char *buf; 607 long size; 608 { 609 610 bcopy(buf, map, size); 611 map += size; 612 } 613 614 xtrmapskip(buf, size) 615 char *buf; 616 long size; 617 { 618 619 #ifdef lint 620 buf = buf; 621 #endif 622 panic("hole in map\n"); 623 map += size; 624 } 625 626 null() {;} 627 628 /* 629 * Do the tape i/o, dealing with volume changes 630 * etc.. 631 */ 632 readtape(b) 633 char *b; 634 { 635 register long i; 636 long rd, newvol; 637 int cnt; 638 639 if (bct < ntrec) { 640 bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE); 641 blksread++; 642 return; 643 } 644 for (i = 0; i < ntrec; i++) 645 ((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0; 646 bct = 0; 647 cnt = ntrec*TP_BSIZE; 648 rd = 0; 649 getmore: 650 #ifdef RRESTORE 651 i = rmtread(&tbf[rd], cnt); 652 #else 653 i = read(mt, &tbf[rd], cnt); 654 #endif 655 if (i > 0 && i != ntrec*TP_BSIZE) { 656 if (pipein) { 657 rd += i; 658 cnt -= i; 659 if (cnt > 0) 660 goto getmore; 661 i = rd; 662 } else { 663 if (i % TP_BSIZE != 0) 664 panic("partial block read: %d should be %d\n", 665 i, ntrec * TP_BSIZE); 666 bcopy((char *)&endoftapemark, &tbf[i], 667 (long)TP_BSIZE); 668 } 669 } 670 if (i < 0) { 671 fprintf(stderr, "Tape read error while "); 672 switch (curfile.action) { 673 default: 674 fprintf(stderr, "trying to set up tape\n"); 675 break; 676 case UNKNOWN: 677 fprintf(stderr, "trying to resynchronize\n"); 678 break; 679 case USING: 680 fprintf(stderr, "restoring %s\n", curfile.name); 681 break; 682 case SKIP: 683 fprintf(stderr, "skipping over inode %d\n", 684 curfile.ino); 685 break; 686 } 687 if (!yflag && !reply("continue")) 688 done(1); 689 i = ntrec*TP_BSIZE; 690 bzero(tbf, i); 691 #ifdef RRESTORE 692 if (rmtseek(i, 1) < 0) 693 #else 694 if (lseek(mt, i, 1) == (long)-1) 695 #endif 696 { 697 perror("continuation failed"); 698 done(1); 699 } 700 } 701 if (i == 0) { 702 if (!pipein) { 703 newvol = volno + 1; 704 volno = 0; 705 getvol(newvol); 706 readtape(b); 707 return; 708 } 709 if (rd % TP_BSIZE != 0) 710 panic("partial block read: %d should be %d\n", 711 rd, ntrec * TP_BSIZE); 712 bcopy((char *)&endoftapemark, &tbf[rd], (long)TP_BSIZE); 713 } 714 bcopy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE); 715 blksread++; 716 } 717 718 findtapeblksize() 719 { 720 register long i; 721 722 for (i = 0; i < ntrec; i++) 723 ((struct s_spcl *)&tbf[i * TP_BSIZE])->c_magic = 0; 724 bct = 0; 725 #ifdef RRESTORE 726 i = rmtread(tbf, ntrec * TP_BSIZE); 727 #else 728 i = read(mt, tbf, ntrec * TP_BSIZE); 729 #endif 730 if (i <= 0) { 731 perror("Tape read error"); 732 done(1); 733 } 734 if (i % TP_BSIZE != 0) { 735 fprintf(stderr, "Tape block size (%d) %s (%d)\n", 736 i, "is not a multiple of dump block size", TP_BSIZE); 737 done(1); 738 } 739 ntrec = i / TP_BSIZE; 740 vprintf(stdout, "Tape block size is %d\n", ntrec); 741 } 742 743 flsht() 744 { 745 746 bct = ntrec+1; 747 } 748 749 closemt() 750 { 751 if (mt < 0) 752 return; 753 #ifdef RRESTORE 754 rmtclose(); 755 #else 756 (void) close(mt); 757 #endif 758 } 759 760 checkvol(b, t) 761 struct s_spcl *b; 762 long t; 763 { 764 765 if (b->c_volume != t) 766 return(FAIL); 767 return(GOOD); 768 } 769 770 readhdr(b) 771 struct s_spcl *b; 772 { 773 774 if (gethead(b) == FAIL) { 775 dprintf(stdout, "readhdr fails at %d blocks\n", blksread); 776 return(FAIL); 777 } 778 return(GOOD); 779 } 780 781 /* 782 * read the tape into buf, then return whether or 783 * or not it is a header block. 784 */ 785 gethead(buf) 786 struct s_spcl *buf; 787 { 788 long i, *j; 789 union u_ospcl { 790 char dummy[TP_BSIZE]; 791 struct s_ospcl { 792 long c_type; 793 long c_date; 794 long c_ddate; 795 long c_volume; 796 long c_tapea; 797 u_short c_inumber; 798 long c_magic; 799 long c_checksum; 800 struct odinode { 801 unsigned short odi_mode; 802 u_short odi_nlink; 803 u_short odi_uid; 804 u_short odi_gid; 805 long odi_size; 806 long odi_rdev; 807 char odi_addr[36]; 808 long odi_atime; 809 long odi_mtime; 810 long odi_ctime; 811 } c_dinode; 812 long c_count; 813 char c_addr[256]; 814 } s_ospcl; 815 } u_ospcl; 816 817 if (!cvtflag) { 818 readtape((char *)buf); 819 if (buf->c_magic != NFS_MAGIC) { 820 if (swabl(buf->c_magic) != NFS_MAGIC) 821 return (FAIL); 822 if (!Bcvt) { 823 vprintf(stdout, "Note: Doing Byte swapping\n"); 824 Bcvt = 1; 825 } 826 } 827 if (checksum((int *)buf) == FAIL) 828 return (FAIL); 829 if (Bcvt) 830 swabst("8l4s31l", (char *)buf); 831 goto good; 832 } 833 readtape((char *)(&u_ospcl.s_ospcl)); 834 bzero((char *)buf, (long)TP_BSIZE); 835 buf->c_type = u_ospcl.s_ospcl.c_type; 836 buf->c_date = u_ospcl.s_ospcl.c_date; 837 buf->c_ddate = u_ospcl.s_ospcl.c_ddate; 838 buf->c_volume = u_ospcl.s_ospcl.c_volume; 839 buf->c_tapea = u_ospcl.s_ospcl.c_tapea; 840 buf->c_inumber = u_ospcl.s_ospcl.c_inumber; 841 buf->c_checksum = u_ospcl.s_ospcl.c_checksum; 842 buf->c_magic = u_ospcl.s_ospcl.c_magic; 843 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode; 844 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink; 845 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid; 846 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid; 847 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size; 848 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev; 849 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime; 850 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime; 851 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime; 852 buf->c_count = u_ospcl.s_ospcl.c_count; 853 bcopy(u_ospcl.s_ospcl.c_addr, buf->c_addr, (long)256); 854 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC || 855 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL) 856 return(FAIL); 857 buf->c_magic = NFS_MAGIC; 858 859 good: 860 j = buf->c_dinode.di_ic.ic_size.val; 861 i = j[1]; 862 if (buf->c_dinode.di_size == 0 && 863 (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt==0) { 864 if (*j || i) { 865 printf("Note: Doing Quad swapping\n"); 866 Qcvt = 1; 867 } 868 } 869 if (Qcvt) { 870 j[1] = *j; *j = i; 871 } 872 switch (buf->c_type) { 873 874 case TS_CLRI: 875 case TS_BITS: 876 /* 877 * Have to patch up missing information in bit map headers 878 */ 879 buf->c_inumber = 0; 880 buf->c_dinode.di_size = buf->c_count * TP_BSIZE; 881 for (i = 0; i < buf->c_count; i++) 882 buf->c_addr[i]++; 883 break; 884 885 case TS_TAPE: 886 case TS_END: 887 buf->c_inumber = 0; 888 break; 889 890 case TS_INODE: 891 case TS_ADDR: 892 break; 893 894 default: 895 panic("gethead: unknown inode type %d\n", buf->c_type); 896 break; 897 } 898 if (dflag) 899 accthdr(buf); 900 return(GOOD); 901 } 902 903 /* 904 * Check that a header is where it belongs and predict the next header 905 */ 906 accthdr(header) 907 struct s_spcl *header; 908 { 909 static ino_t previno = 0x7fffffff; 910 static int prevtype; 911 static long predict; 912 long blks, i; 913 914 if (header->c_type == TS_TAPE) { 915 fprintf(stderr, "Volume header\n"); 916 previno = 0x7fffffff; 917 return; 918 } 919 if (previno == 0x7fffffff) 920 goto newcalc; 921 switch (prevtype) { 922 case TS_BITS: 923 fprintf(stderr, "Dump mask header"); 924 break; 925 case TS_CLRI: 926 fprintf(stderr, "Remove mask header"); 927 break; 928 case TS_INODE: 929 fprintf(stderr, "File header, ino %d", previno); 930 break; 931 case TS_ADDR: 932 fprintf(stderr, "File continuation header, ino %d", previno); 933 break; 934 case TS_END: 935 fprintf(stderr, "End of tape header"); 936 break; 937 } 938 if (predict != blksread - 1) 939 fprintf(stderr, "; predicted %d blocks, got %d blocks", 940 predict, blksread - 1); 941 fprintf(stderr, "\n"); 942 newcalc: 943 blks = 0; 944 if (header->c_type != TS_END) 945 for (i = 0; i < header->c_count; i++) 946 if (header->c_addr[i] != 0) 947 blks++; 948 predict = blks; 949 blksread = 0; 950 prevtype = header->c_type; 951 previno = header->c_inumber; 952 } 953 954 /* 955 * Find an inode header. 956 * Complain if had to skip, and complain is set. 957 */ 958 findinode(header) 959 struct s_spcl *header; 960 { 961 static long skipcnt = 0; 962 long i; 963 char buf[TP_BSIZE]; 964 965 curfile.name = "<name unknown>"; 966 curfile.action = UNKNOWN; 967 curfile.dip = (struct dinode *)NIL; 968 curfile.ino = 0; 969 if (ishead(header) == FAIL) { 970 skipcnt++; 971 while (gethead(header) == FAIL || header->c_date != dumpdate) 972 skipcnt++; 973 } 974 for (;;) { 975 if (checktype(header, TS_ADDR) == GOOD) { 976 /* 977 * Skip up to the beginning of the next record 978 */ 979 for (i = 0; i < header->c_count; i++) 980 if (header->c_addr[i]) 981 readtape(buf); 982 (void) gethead(header); 983 continue; 984 } 985 if (checktype(header, TS_INODE) == GOOD) { 986 curfile.dip = &header->c_dinode; 987 curfile.ino = header->c_inumber; 988 break; 989 } 990 if (checktype(header, TS_END) == GOOD) { 991 curfile.ino = maxino; 992 break; 993 } 994 if (checktype(header, TS_CLRI) == GOOD) { 995 curfile.name = "<file removal list>"; 996 break; 997 } 998 if (checktype(header, TS_BITS) == GOOD) { 999 curfile.name = "<file dump list>"; 1000 break; 1001 } 1002 while (gethead(header) == FAIL) 1003 skipcnt++; 1004 } 1005 if (skipcnt > 0) 1006 fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt); 1007 skipcnt = 0; 1008 } 1009 1010 /* 1011 * return whether or not the buffer contains a header block 1012 */ 1013 ishead(buf) 1014 struct s_spcl *buf; 1015 { 1016 1017 if (buf->c_magic != NFS_MAGIC) 1018 return(FAIL); 1019 return(GOOD); 1020 } 1021 1022 checktype(b, t) 1023 struct s_spcl *b; 1024 int t; 1025 { 1026 1027 if (b->c_type != t) 1028 return(FAIL); 1029 return(GOOD); 1030 } 1031 1032 checksum(b) 1033 register int *b; 1034 { 1035 register int i, j; 1036 1037 j = sizeof(union u_spcl) / sizeof(int); 1038 i = 0; 1039 if(!Bcvt) { 1040 do 1041 i += *b++; 1042 while (--j); 1043 } else { 1044 /* What happens if we want to read restore tapes 1045 for a 16bit int machine??? */ 1046 do 1047 i += swabl(*b++); 1048 while (--j); 1049 } 1050 1051 if (i != CHECKSUM) { 1052 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i, 1053 curfile.ino, curfile.name); 1054 return(FAIL); 1055 } 1056 return(GOOD); 1057 } 1058 1059 #ifdef RRESTORE 1060 /* VARARGS1 */ 1061 msg(cp, a1, a2, a3) 1062 char *cp; 1063 { 1064 1065 fprintf(stderr, cp, a1, a2, a3); 1066 } 1067 #endif RRESTORE 1068 1069 swabst(cp, sp) 1070 register char *cp, *sp; 1071 { 1072 int n = 0; 1073 char c; 1074 while(*cp) { 1075 switch (*cp) { 1076 case '0': case '1': case '2': case '3': case '4': 1077 case '5': case '6': case '7': case '8': case '9': 1078 n = (n * 10) + (*cp++ - '0'); 1079 continue; 1080 1081 case 's': case 'w': case 'h': 1082 c = sp[0]; sp[0] = sp[1]; sp[1] = c; 1083 sp++; 1084 break; 1085 1086 case 'l': 1087 c = sp[0]; sp[0] = sp[3]; sp[3] = c; 1088 c = sp[2]; sp[2] = sp[1]; sp[1] = c; 1089 sp += 3; 1090 } 1091 sp++; /* Any other character, like 'b' counts as byte. */ 1092 if (n <= 1) { 1093 n = 0; cp++; 1094 } else 1095 n--; 1096 } 1097 } 1098 swabl(x) { unsigned long l = x; swabst("l", (char *)&l); return l; } 1099