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