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