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