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