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