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