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