1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * %sccs.include.redist.c% 11 */ 12 13 #ifndef lint 14 static char sccsid[] = "@(#)tape.c 8.8 (Berkeley) 04/28/95"; 15 #endif /* not lint */ 16 17 #include <sys/param.h> 18 #include <sys/file.h> 19 #include <sys/ioctl.h> 20 #include <sys/mtio.h> 21 #include <sys/stat.h> 22 23 #include <ufs/ufs/dinode.h> 24 #include <protocols/dumprestore.h> 25 26 #include <errno.h> 27 #include <setjmp.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <unistd.h> 32 33 #include "restore.h" 34 #include "extern.h" 35 #include "pathnames.h" 36 37 static long fssize = MAXBSIZE; 38 static int mt = -1; 39 static int pipein = 0; 40 static char magtape[BUFSIZ]; 41 static int blkcnt; 42 static int numtrec; 43 static char *tapebuf; 44 static union u_spcl endoftapemark; 45 static long blksread; /* blocks read since last header */ 46 static long tpblksread = 0; /* TP_BSIZE blocks read */ 47 static long tapesread; 48 static jmp_buf restart; 49 static int gettingfile = 0; /* restart has a valid frame */ 50 static char *host = NULL; 51 52 static int ofile; 53 static char *map; 54 static char lnkbuf[MAXPATHLEN + 1]; 55 static int pathlen; 56 57 int oldinofmt; /* old inode format conversion required */ 58 int Bcvt; /* Swap Bytes (for CCI or sun) */ 59 static int Qcvt; /* Swap quads (for sun) */ 60 61 #define FLUSHTAPEBUF() blkcnt = ntrec + 1 62 63 static void accthdr __P((struct s_spcl *)); 64 static int checksum __P((int *)); 65 static void findinode __P((struct s_spcl *)); 66 static void findtapeblksize __P((void)); 67 static int gethead __P((struct s_spcl *)); 68 static void readtape __P((char *)); 69 static void setdumpnum __P((void)); 70 static u_long swabl __P((u_long)); 71 static u_char *swablong __P((u_char *, int)); 72 static u_char *swabshort __P((u_char *, int)); 73 static void terminateinput __P((void)); 74 static void xtrfile __P((char *, long)); 75 static void xtrlnkfile __P((char *, long)); 76 static void xtrlnkskip __P((char *, long)); 77 static void xtrmap __P((char *, long)); 78 static void xtrmapskip __P((char *, long)); 79 static void xtrskip __P((char *, long)); 80 81 /* 82 * Set up an input source 83 */ 84 void 85 setinput(source) 86 char *source; 87 { 88 FLUSHTAPEBUF(); 89 if (bflag) 90 newtapebuf(ntrec); 91 else 92 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC); 93 terminal = stdin; 94 95 #ifdef RRESTORE 96 if (strchr(source, ':')) { 97 host = source; 98 source = strchr(host, ':'); 99 *source++ = '\0'; 100 if (rmthost(host) == 0) 101 done(1); 102 } else 103 #endif 104 if (strcmp(source, "-") == 0) { 105 /* 106 * Since input is coming from a pipe we must establish 107 * our own connection to the terminal. 108 */ 109 terminal = fopen(_PATH_TTY, "r"); 110 if (terminal == NULL) { 111 (void)fprintf(stderr, "cannot open %s: %s\n", 112 _PATH_TTY, strerror(errno)); 113 terminal = fopen(_PATH_DEVNULL, "r"); 114 if (terminal == NULL) { 115 (void)fprintf(stderr, "cannot open %s: %s\n", 116 _PATH_DEVNULL, strerror(errno)); 117 done(1); 118 } 119 } 120 pipein++; 121 } 122 setuid(getuid()); /* no longer need or want root privileges */ 123 (void) strcpy(magtape, source); 124 } 125 126 void 127 newtapebuf(size) 128 long size; 129 { 130 static tapebufsize = -1; 131 132 ntrec = size; 133 if (size <= tapebufsize) 134 return; 135 if (tapebuf != NULL) 136 free(tapebuf); 137 tapebuf = malloc(size * TP_BSIZE); 138 if (tapebuf == NULL) { 139 fprintf(stderr, "Cannot allocate space for tape buffer\n"); 140 done(1); 141 } 142 tapebufsize = size; 143 } 144 145 /* 146 * Verify that the tape drive can be accessed and 147 * that it actually is a dump tape. 148 */ 149 void 150 setup() 151 { 152 int i, j, *ip; 153 struct stat stbuf; 154 155 vprintf(stdout, "Verify tape and initialize maps\n"); 156 #ifdef RRESTORE 157 if (host) 158 mt = rmtopen(magtape, 0); 159 else 160 #endif 161 if (pipein) 162 mt = 0; 163 else 164 mt = open(magtape, O_RDONLY, 0); 165 if (mt < 0) { 166 fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); 167 done(1); 168 } 169 volno = 1; 170 setdumpnum(); 171 FLUSHTAPEBUF(); 172 if (!pipein && !bflag) 173 findtapeblksize(); 174 if (gethead(&spcl) == FAIL) { 175 blkcnt--; /* push back this block */ 176 blksread--; 177 tpblksread--; 178 cvtflag++; 179 if (gethead(&spcl) == FAIL) { 180 fprintf(stderr, "Tape is not a dump tape\n"); 181 done(1); 182 } 183 fprintf(stderr, "Converting to new file system format.\n"); 184 } 185 if (pipein) { 186 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC; 187 endoftapemark.s_spcl.c_type = TS_END; 188 ip = (int *)&endoftapemark; 189 j = sizeof(union u_spcl) / sizeof(int); 190 i = 0; 191 do 192 i += *ip++; 193 while (--j); 194 endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 195 } 196 if (vflag || command == 't') 197 printdumpinfo(); 198 dumptime = spcl.c_ddate; 199 dumpdate = spcl.c_date; 200 if (stat(".", &stbuf) < 0) { 201 fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); 202 done(1); 203 } 204 if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE) 205 fssize = stbuf.st_blksize; 206 if (((fssize - 1) & fssize) != 0) { 207 fprintf(stderr, "bad block size %d\n", fssize); 208 done(1); 209 } 210 if (spcl.c_volume != 1) { 211 fprintf(stderr, "Tape is not volume 1 of the dump\n"); 212 done(1); 213 } 214 if (gethead(&spcl) == FAIL) { 215 dprintf(stdout, "header read failed at %d blocks\n", blksread); 216 panic("no header after volume mark!\n"); 217 } 218 findinode(&spcl); 219 if (spcl.c_type != TS_CLRI) { 220 fprintf(stderr, "Cannot find file removal list\n"); 221 done(1); 222 } 223 maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; 224 dprintf(stdout, "maxino = %d\n", maxino); 225 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 226 if (map == NULL) 227 panic("no memory for active inode map\n"); 228 usedinomap = map; 229 curfile.action = USING; 230 getfile(xtrmap, xtrmapskip); 231 if (spcl.c_type != TS_BITS) { 232 fprintf(stderr, "Cannot find file dump list\n"); 233 done(1); 234 } 235 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 236 if (map == (char *)NULL) 237 panic("no memory for file dump list\n"); 238 dumpmap = map; 239 curfile.action = USING; 240 getfile(xtrmap, xtrmapskip); 241 /* 242 * If there may be whiteout entries on the tape, pretend that the 243 * whiteout inode exists, so that the whiteout entries can be 244 * extracted. 245 */ 246 if (oldinofmt == 0) 247 SETINO(WINO, dumpmap); 248 } 249 250 /* 251 * Prompt user to load a new dump volume. 252 * "Nextvol" is the next suggested volume to use. 253 * This suggested volume is enforced when doing full 254 * or incremental restores, but can be overrridden by 255 * the user when only extracting a subset of the files. 256 */ 257 void 258 getvol(nextvol) 259 long nextvol; 260 { 261 long newvol, savecnt, wantnext, i; 262 union u_spcl tmpspcl; 263 # define tmpbuf tmpspcl.s_spcl 264 char buf[TP_BSIZE]; 265 266 if (nextvol == 1) { 267 tapesread = 0; 268 gettingfile = 0; 269 } 270 if (pipein) { 271 if (nextvol != 1) 272 panic("Changing volumes on pipe input?\n"); 273 if (volno == 1) 274 return; 275 goto gethdr; 276 } 277 savecnt = blksread; 278 again: 279 if (pipein) 280 done(1); /* pipes do not get a second chance */ 281 if (command == 'R' || command == 'r' || curfile.action != SKIP) { 282 newvol = nextvol; 283 wantnext = 1; 284 } else { 285 newvol = 0; 286 wantnext = 0; 287 } 288 while (newvol <= 0) { 289 if (tapesread == 0) { 290 fprintf(stderr, "%s%s%s%s%s", 291 "You have not read any tapes yet.\n", 292 "Unless you know which volume your", 293 " file(s) are on you should start\n", 294 "with the last volume and work", 295 " towards towards the first.\n"); 296 } else { 297 fprintf(stderr, "You have read volumes"); 298 strcpy(buf, ": "); 299 for (i = 1; i < 32; i++) 300 if (tapesread & (1 << i)) { 301 fprintf(stderr, "%s%d", buf, i); 302 strcpy(buf, ", "); 303 } 304 fprintf(stderr, "\n"); 305 } 306 do { 307 fprintf(stderr, "Specify next volume #: "); 308 (void) fflush(stderr); 309 (void) fgets(buf, BUFSIZ, terminal); 310 } while (!feof(terminal) && buf[0] == '\n'); 311 if (feof(terminal)) 312 done(1); 313 newvol = atoi(buf); 314 if (newvol <= 0) { 315 fprintf(stderr, 316 "Volume numbers are positive numerics\n"); 317 } 318 } 319 if (newvol == volno) { 320 tapesread |= 1 << volno; 321 return; 322 } 323 closemt(); 324 fprintf(stderr, "Mount tape volume %d\n", newvol); 325 fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); 326 fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); 327 (void) fflush(stderr); 328 (void) fgets(buf, BUFSIZ, terminal); 329 if (feof(terminal)) 330 done(1); 331 if (!strcmp(buf, "none\n")) { 332 terminateinput(); 333 return; 334 } 335 if (buf[0] != '\n') { 336 (void) strcpy(magtape, buf); 337 magtape[strlen(magtape) - 1] = '\0'; 338 } 339 #ifdef RRESTORE 340 if (host) 341 mt = rmtopen(magtape, 0); 342 else 343 #endif 344 mt = open(magtape, O_RDONLY, 0); 345 346 if (mt == -1) { 347 fprintf(stderr, "Cannot open %s\n", magtape); 348 volno = -1; 349 goto again; 350 } 351 gethdr: 352 volno = newvol; 353 setdumpnum(); 354 FLUSHTAPEBUF(); 355 if (gethead(&tmpbuf) == FAIL) { 356 dprintf(stdout, "header read failed at %d blocks\n", blksread); 357 fprintf(stderr, "tape is not dump tape\n"); 358 volno = 0; 359 goto again; 360 } 361 if (tmpbuf.c_volume != volno) { 362 fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume); 363 volno = 0; 364 goto again; 365 } 366 if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) { 367 fprintf(stderr, "Wrong dump date\n\tgot: %s", 368 ctime(&tmpbuf.c_date)); 369 fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); 370 volno = 0; 371 goto again; 372 } 373 tapesread |= 1 << volno; 374 blksread = savecnt; 375 /* 376 * If continuing from the previous volume, skip over any 377 * blocks read already at the end of the previous volume. 378 * 379 * If coming to this volume at random, skip to the beginning 380 * of the next record. 381 */ 382 dprintf(stdout, "read %ld recs, tape starts with %ld\n", 383 tpblksread, tmpbuf.c_firstrec); 384 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) { 385 if (!wantnext) { 386 tpblksread = tmpbuf.c_firstrec; 387 for (i = tmpbuf.c_count; i > 0; i--) 388 readtape(buf); 389 } else if (tmpbuf.c_firstrec > 0 && 390 tmpbuf.c_firstrec < tpblksread - 1) { 391 /* 392 * -1 since we've read the volume header 393 */ 394 i = tpblksread - tmpbuf.c_firstrec - 1; 395 dprintf(stderr, "Skipping %d duplicate record%s.\n", 396 i, i > 1 ? "s" : ""); 397 while (--i >= 0) 398 readtape(buf); 399 } 400 } 401 if (curfile.action == USING) { 402 if (volno == 1) 403 panic("active file into volume 1\n"); 404 return; 405 } 406 /* 407 * Skip up to the beginning of the next record 408 */ 409 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) 410 for (i = tmpbuf.c_count; i > 0; i--) 411 readtape(buf); 412 (void) gethead(&spcl); 413 findinode(&spcl); 414 if (gettingfile) { 415 gettingfile = 0; 416 longjmp(restart, 1); 417 } 418 } 419 420 /* 421 * Handle unexpected EOF. 422 */ 423 static void 424 terminateinput() 425 { 426 427 if (gettingfile && curfile.action == USING) { 428 printf("Warning: %s %s\n", 429 "End-of-input encountered while extracting", curfile.name); 430 } 431 curfile.name = "<name unknown>"; 432 curfile.action = UNKNOWN; 433 curfile.dip = NULL; 434 curfile.ino = maxino; 435 if (gettingfile) { 436 gettingfile = 0; 437 longjmp(restart, 1); 438 } 439 } 440 441 /* 442 * handle multiple dumps per tape by skipping forward to the 443 * appropriate one. 444 */ 445 static void 446 setdumpnum() 447 { 448 struct mtop tcom; 449 450 if (dumpnum == 1 || volno != 1) 451 return; 452 if (pipein) { 453 fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); 454 done(1); 455 } 456 tcom.mt_op = MTFSF; 457 tcom.mt_count = dumpnum - 1; 458 #ifdef RRESTORE 459 if (host) 460 rmtioctl(MTFSF, dumpnum - 1); 461 else 462 #endif 463 if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0) 464 fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno)); 465 } 466 467 void 468 printdumpinfo() 469 { 470 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date)); 471 fprintf(stdout, "Dumped from: %s", 472 (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate)); 473 if (spcl.c_host[0] == '\0') 474 return; 475 fprintf(stderr, "Level %d dump of %s on %s:%s\n", 476 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); 477 fprintf(stderr, "Label: %s\n", spcl.c_label); 478 } 479 480 int 481 extractfile(name) 482 char *name; 483 { 484 int flags; 485 mode_t mode; 486 struct timeval timep[2]; 487 struct entry *ep; 488 489 curfile.name = name; 490 curfile.action = USING; 491 timep[0].tv_sec = curfile.dip->di_atime.ts_sec; 492 timep[0].tv_usec = curfile.dip->di_atime.ts_nsec / 1000; 493 timep[1].tv_sec = curfile.dip->di_mtime.ts_sec; 494 timep[1].tv_usec = curfile.dip->di_mtime.ts_nsec / 1000; 495 mode = curfile.dip->di_mode; 496 flags = curfile.dip->di_flags; 497 switch (mode & IFMT) { 498 499 default: 500 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); 501 skipfile(); 502 return (FAIL); 503 504 case IFSOCK: 505 vprintf(stdout, "skipped socket %s\n", name); 506 skipfile(); 507 return (GOOD); 508 509 case IFDIR: 510 if (mflag) { 511 ep = lookupname(name); 512 if (ep == NULL || ep->e_flags & EXTRACT) 513 panic("unextracted directory %s\n", name); 514 skipfile(); 515 return (GOOD); 516 } 517 vprintf(stdout, "extract file %s\n", name); 518 return (genliteraldir(name, curfile.ino)); 519 520 case IFLNK: 521 lnkbuf[0] = '\0'; 522 pathlen = 0; 523 getfile(xtrlnkfile, xtrlnkskip); 524 if (pathlen == 0) { 525 vprintf(stdout, 526 "%s: zero length symbolic link (ignored)\n", name); 527 return (GOOD); 528 } 529 return (linkit(lnkbuf, name, SYMLINK)); 530 531 case IFCHR: 532 case IFBLK: 533 vprintf(stdout, "extract special file %s\n", name); 534 if (Nflag) { 535 skipfile(); 536 return (GOOD); 537 } 538 if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) { 539 fprintf(stderr, "%s: cannot create special file: %s\n", 540 name, strerror(errno)); 541 skipfile(); 542 return (FAIL); 543 } 544 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); 545 (void) chmod(name, mode); 546 (void) chflags(name, flags); 547 skipfile(); 548 utimes(name, timep); 549 return (GOOD); 550 551 case IFIFO: 552 vprintf(stdout, "extract fifo %s\n", name); 553 if (Nflag) { 554 skipfile(); 555 return (GOOD); 556 } 557 if (mkfifo(name, mode) < 0) { 558 fprintf(stderr, "%s: cannot create fifo: %s\n", 559 name, strerror(errno)); 560 skipfile(); 561 return (FAIL); 562 } 563 (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); 564 (void) chmod(name, mode); 565 (void) chflags(name, flags); 566 skipfile(); 567 utimes(name, timep); 568 return (GOOD); 569 570 case IFREG: 571 vprintf(stdout, "extract file %s\n", name); 572 if (Nflag) { 573 skipfile(); 574 return (GOOD); 575 } 576 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 577 0666)) < 0) { 578 fprintf(stderr, "%s: cannot create file: %s\n", 579 name, strerror(errno)); 580 skipfile(); 581 return (FAIL); 582 } 583 (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid); 584 (void) fchmod(ofile, mode); 585 (void) fchflags(ofile, flags); 586 getfile(xtrfile, xtrskip); 587 (void) close(ofile); 588 utimes(name, timep); 589 return (GOOD); 590 } 591 /* NOTREACHED */ 592 } 593 594 /* 595 * skip over bit maps on the tape 596 */ 597 void 598 skipmaps() 599 { 600 601 while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) 602 skipfile(); 603 } 604 605 /* 606 * skip over a file on the tape 607 */ 608 void 609 skipfile() 610 { 611 612 curfile.action = SKIP; 613 getfile(xtrnull, xtrnull); 614 } 615 616 /* 617 * Extract a file from the tape. 618 * When an allocated block is found it is passed to the fill function; 619 * when an unallocated block (hole) is found, a zeroed buffer is passed 620 * to the skip function. 621 */ 622 void 623 getfile(fill, skip) 624 void (*fill) __P((char *, long)); 625 void (*skip) __P((char *, long)); 626 { 627 register int i; 628 int curblk = 0; 629 quad_t size = spcl.c_dinode.di_size; 630 static char clearedbuf[MAXBSIZE]; 631 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 632 char junk[TP_BSIZE]; 633 634 if (spcl.c_type == TS_END) 635 panic("ran off end of tape\n"); 636 if (spcl.c_magic != NFS_MAGIC) 637 panic("not at beginning of a file\n"); 638 if (!gettingfile && setjmp(restart) != 0) 639 return; 640 gettingfile++; 641 loop: 642 for (i = 0; i < spcl.c_count; i++) { 643 if (spcl.c_addr[i]) { 644 readtape(&buf[curblk++][0]); 645 if (curblk == fssize / TP_BSIZE) { 646 (*fill)((char *)buf, (long)(size > TP_BSIZE ? 647 fssize : (curblk - 1) * TP_BSIZE + size)); 648 curblk = 0; 649 } 650 } else { 651 if (curblk > 0) { 652 (*fill)((char *)buf, (long)(size > TP_BSIZE ? 653 curblk * TP_BSIZE : 654 (curblk - 1) * TP_BSIZE + size)); 655 curblk = 0; 656 } 657 (*skip)(clearedbuf, (long)(size > TP_BSIZE ? 658 TP_BSIZE : size)); 659 } 660 if ((size -= TP_BSIZE) <= 0) { 661 for (i++; i < spcl.c_count; i++) 662 if (spcl.c_addr[i]) 663 readtape(junk); 664 break; 665 } 666 } 667 if (gethead(&spcl) == GOOD && size > 0) { 668 if (spcl.c_type == TS_ADDR) 669 goto loop; 670 dprintf(stdout, 671 "Missing address (header) block for %s at %d blocks\n", 672 curfile.name, blksread); 673 } 674 if (curblk > 0) 675 (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size)); 676 findinode(&spcl); 677 gettingfile = 0; 678 } 679 680 /* 681 * Write out the next block of a file. 682 */ 683 static void 684 xtrfile(buf, size) 685 char *buf; 686 long size; 687 { 688 689 if (Nflag) 690 return; 691 if (write(ofile, buf, (int) size) == -1) { 692 fprintf(stderr, 693 "write error extracting inode %d, name %s\nwrite: %s\n", 694 curfile.ino, curfile.name, strerror(errno)); 695 done(1); 696 } 697 } 698 699 /* 700 * Skip over a hole in a file. 701 */ 702 /* ARGSUSED */ 703 static void 704 xtrskip(buf, size) 705 char *buf; 706 long size; 707 { 708 709 if (lseek(ofile, size, SEEK_CUR) == -1) { 710 fprintf(stderr, 711 "seek error extracting inode %d, name %s\nlseek: %s\n", 712 curfile.ino, curfile.name, strerror(errno)); 713 done(1); 714 } 715 } 716 717 /* 718 * Collect the next block of a symbolic link. 719 */ 720 static void 721 xtrlnkfile(buf, size) 722 char *buf; 723 long size; 724 { 725 726 pathlen += size; 727 if (pathlen > MAXPATHLEN) { 728 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", 729 curfile.name, lnkbuf, buf, pathlen); 730 done(1); 731 } 732 (void) strcat(lnkbuf, buf); 733 } 734 735 /* 736 * Skip over a hole in a symbolic link (should never happen). 737 */ 738 /* ARGSUSED */ 739 static void 740 xtrlnkskip(buf, size) 741 char *buf; 742 long size; 743 { 744 745 fprintf(stderr, "unallocated block in symbolic link %s\n", 746 curfile.name); 747 done(1); 748 } 749 750 /* 751 * Collect the next block of a bit map. 752 */ 753 static void 754 xtrmap(buf, size) 755 char *buf; 756 long size; 757 { 758 759 memmove(map, buf, size); 760 map += size; 761 } 762 763 /* 764 * Skip over a hole in a bit map (should never happen). 765 */ 766 /* ARGSUSED */ 767 static void 768 xtrmapskip(buf, size) 769 char *buf; 770 long size; 771 { 772 773 panic("hole in map\n"); 774 map += size; 775 } 776 777 /* 778 * Noop, when an extraction function is not needed. 779 */ 780 /* ARGSUSED */ 781 void 782 xtrnull(buf, size) 783 char *buf; 784 long size; 785 { 786 787 return; 788 } 789 790 /* 791 * Read TP_BSIZE blocks from the input. 792 * Handle read errors, and end of media. 793 */ 794 static void 795 readtape(buf) 796 char *buf; 797 { 798 long rd, newvol, i; 799 int cnt, seek_failed; 800 801 if (blkcnt < numtrec) { 802 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 803 blksread++; 804 tpblksread++; 805 return; 806 } 807 for (i = 0; i < ntrec; i++) 808 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 809 if (numtrec == 0) 810 numtrec = ntrec; 811 cnt = ntrec * TP_BSIZE; 812 rd = 0; 813 getmore: 814 #ifdef RRESTORE 815 if (host) 816 i = rmtread(&tapebuf[rd], cnt); 817 else 818 #endif 819 i = read(mt, &tapebuf[rd], cnt); 820 /* 821 * Check for mid-tape short read error. 822 * If found, skip rest of buffer and start with the next. 823 */ 824 if (!pipein && numtrec < ntrec && i > 0) { 825 dprintf(stdout, "mid-media short read error.\n"); 826 numtrec = ntrec; 827 } 828 /* 829 * Handle partial block read. 830 */ 831 if (pipein && i == 0 && rd > 0) 832 i = rd; 833 else if (i > 0 && i != ntrec * TP_BSIZE) { 834 if (pipein) { 835 rd += i; 836 cnt -= i; 837 if (cnt > 0) 838 goto getmore; 839 i = rd; 840 } else { 841 /* 842 * Short read. Process the blocks read. 843 */ 844 if (i % TP_BSIZE != 0) 845 vprintf(stdout, 846 "partial block read: %d should be %d\n", 847 i, ntrec * TP_BSIZE); 848 numtrec = i / TP_BSIZE; 849 } 850 } 851 /* 852 * Handle read error. 853 */ 854 if (i < 0) { 855 fprintf(stderr, "Tape read error while "); 856 switch (curfile.action) { 857 default: 858 fprintf(stderr, "trying to set up tape\n"); 859 break; 860 case UNKNOWN: 861 fprintf(stderr, "trying to resynchronize\n"); 862 break; 863 case USING: 864 fprintf(stderr, "restoring %s\n", curfile.name); 865 break; 866 case SKIP: 867 fprintf(stderr, "skipping over inode %d\n", 868 curfile.ino); 869 break; 870 } 871 if (!yflag && !reply("continue")) 872 done(1); 873 i = ntrec * TP_BSIZE; 874 memset(tapebuf, 0, i); 875 #ifdef RRESTORE 876 if (host) 877 seek_failed = (rmtseek(i, 1) < 0); 878 else 879 #endif 880 seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1); 881 882 if (seek_failed) { 883 fprintf(stderr, 884 "continuation failed: %s\n", strerror(errno)); 885 done(1); 886 } 887 } 888 /* 889 * Handle end of tape. 890 */ 891 if (i == 0) { 892 vprintf(stdout, "End-of-tape encountered\n"); 893 if (!pipein) { 894 newvol = volno + 1; 895 volno = 0; 896 numtrec = 0; 897 getvol(newvol); 898 readtape(buf); 899 return; 900 } 901 if (rd % TP_BSIZE != 0) 902 panic("partial block read: %d should be %d\n", 903 rd, ntrec * TP_BSIZE); 904 terminateinput(); 905 memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); 906 } 907 blkcnt = 0; 908 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); 909 blksread++; 910 tpblksread++; 911 } 912 913 static void 914 findtapeblksize() 915 { 916 register long i; 917 918 for (i = 0; i < ntrec; i++) 919 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 920 blkcnt = 0; 921 #ifdef RRESTORE 922 if (host) 923 i = rmtread(tapebuf, ntrec * TP_BSIZE); 924 else 925 #endif 926 i = read(mt, tapebuf, ntrec * TP_BSIZE); 927 928 if (i <= 0) { 929 fprintf(stderr, "tape read error: %s\n", strerror(errno)); 930 done(1); 931 } 932 if (i % TP_BSIZE != 0) { 933 fprintf(stderr, "Tape block size (%d) %s (%d)\n", 934 i, "is not a multiple of dump block size", TP_BSIZE); 935 done(1); 936 } 937 ntrec = i / TP_BSIZE; 938 numtrec = ntrec; 939 vprintf(stdout, "Tape block size is %d\n", ntrec); 940 } 941 942 void 943 closemt() 944 { 945 946 if (mt < 0) 947 return; 948 #ifdef RRESTORE 949 if (host) 950 rmtclose(); 951 else 952 #endif 953 (void) close(mt); 954 } 955 956 /* 957 * Read the next block from the tape. 958 * Check to see if it is one of several vintage headers. 959 * If it is an old style header, convert it to a new style header. 960 * If it is not any valid header, return an error. 961 */ 962 static int 963 gethead(buf) 964 struct s_spcl *buf; 965 { 966 long i; 967 union { 968 quad_t qval; 969 long val[2]; 970 } qcvt; 971 union u_ospcl { 972 char dummy[TP_BSIZE]; 973 struct s_ospcl { 974 long c_type; 975 long c_date; 976 long c_ddate; 977 long c_volume; 978 long c_tapea; 979 u_short c_inumber; 980 long c_magic; 981 long c_checksum; 982 struct odinode { 983 unsigned short odi_mode; 984 u_short odi_nlink; 985 u_short odi_uid; 986 u_short odi_gid; 987 long odi_size; 988 long odi_rdev; 989 char odi_addr[36]; 990 long odi_atime; 991 long odi_mtime; 992 long odi_ctime; 993 } c_dinode; 994 long c_count; 995 char c_addr[256]; 996 } s_ospcl; 997 } u_ospcl; 998 999 if (!cvtflag) { 1000 readtape((char *)buf); 1001 if (buf->c_magic != NFS_MAGIC) { 1002 if (swabl(buf->c_magic) != NFS_MAGIC) 1003 return (FAIL); 1004 if (!Bcvt) { 1005 vprintf(stdout, "Note: Doing Byte swapping\n"); 1006 Bcvt = 1; 1007 } 1008 } 1009 if (checksum((int *)buf) == FAIL) 1010 return (FAIL); 1011 if (Bcvt) 1012 swabst((u_char *)"8l4s31l", (u_char *)buf); 1013 goto good; 1014 } 1015 readtape((char *)(&u_ospcl.s_ospcl)); 1016 memset(buf, 0, (long)TP_BSIZE); 1017 buf->c_type = u_ospcl.s_ospcl.c_type; 1018 buf->c_date = u_ospcl.s_ospcl.c_date; 1019 buf->c_ddate = u_ospcl.s_ospcl.c_ddate; 1020 buf->c_volume = u_ospcl.s_ospcl.c_volume; 1021 buf->c_tapea = u_ospcl.s_ospcl.c_tapea; 1022 buf->c_inumber = u_ospcl.s_ospcl.c_inumber; 1023 buf->c_checksum = u_ospcl.s_ospcl.c_checksum; 1024 buf->c_magic = u_ospcl.s_ospcl.c_magic; 1025 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode; 1026 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink; 1027 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid; 1028 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid; 1029 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size; 1030 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev; 1031 buf->c_dinode.di_atime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_atime; 1032 buf->c_dinode.di_mtime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime; 1033 buf->c_dinode.di_ctime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime; 1034 buf->c_count = u_ospcl.s_ospcl.c_count; 1035 memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256); 1036 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC || 1037 checksum((int *)(&u_ospcl.s_ospcl)) == FAIL) 1038 return(FAIL); 1039 buf->c_magic = NFS_MAGIC; 1040 1041 good: 1042 if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) && 1043 (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) { 1044 qcvt.qval = buf->c_dinode.di_size; 1045 if (qcvt.val[0] || qcvt.val[1]) { 1046 printf("Note: Doing Quad swapping\n"); 1047 Qcvt = 1; 1048 } 1049 } 1050 if (Qcvt) { 1051 qcvt.qval = buf->c_dinode.di_size; 1052 i = qcvt.val[1]; 1053 qcvt.val[1] = qcvt.val[0]; 1054 qcvt.val[0] = i; 1055 buf->c_dinode.di_size = qcvt.qval; 1056 } 1057 1058 switch (buf->c_type) { 1059 1060 case TS_CLRI: 1061 case TS_BITS: 1062 /* 1063 * Have to patch up missing information in bit map headers 1064 */ 1065 buf->c_inumber = 0; 1066 buf->c_dinode.di_size = buf->c_count * TP_BSIZE; 1067 for (i = 0; i < buf->c_count; i++) 1068 buf->c_addr[i]++; 1069 break; 1070 1071 case TS_TAPE: 1072 if ((buf->c_flags & DR_NEWINODEFMT) == 0) 1073 oldinofmt = 1; 1074 /* fall through */ 1075 case TS_END: 1076 buf->c_inumber = 0; 1077 break; 1078 1079 case TS_INODE: 1080 case TS_ADDR: 1081 break; 1082 1083 default: 1084 panic("gethead: unknown inode type %d\n", buf->c_type); 1085 break; 1086 } 1087 /* 1088 * If we are restoring a filesystem with old format inodes, 1089 * copy the uid/gid to the new location. 1090 */ 1091 if (oldinofmt) { 1092 buf->c_dinode.di_uid = buf->c_dinode.di_ouid; 1093 buf->c_dinode.di_gid = buf->c_dinode.di_ogid; 1094 } 1095 if (dflag) 1096 accthdr(buf); 1097 return(GOOD); 1098 } 1099 1100 /* 1101 * Check that a header is where it belongs and predict the next header 1102 */ 1103 static void 1104 accthdr(header) 1105 struct s_spcl *header; 1106 { 1107 static ino_t previno = 0x7fffffff; 1108 static int prevtype; 1109 static long predict; 1110 long blks, i; 1111 1112 if (header->c_type == TS_TAPE) { 1113 fprintf(stderr, "Volume header (%s inode format) ", 1114 oldinofmt ? "old" : "new"); 1115 if (header->c_firstrec) 1116 fprintf(stderr, "begins with record %d", 1117 header->c_firstrec); 1118 fprintf(stderr, "\n"); 1119 previno = 0x7fffffff; 1120 return; 1121 } 1122 if (previno == 0x7fffffff) 1123 goto newcalc; 1124 switch (prevtype) { 1125 case TS_BITS: 1126 fprintf(stderr, "Dumped inodes map header"); 1127 break; 1128 case TS_CLRI: 1129 fprintf(stderr, "Used inodes map header"); 1130 break; 1131 case TS_INODE: 1132 fprintf(stderr, "File header, ino %d", previno); 1133 break; 1134 case TS_ADDR: 1135 fprintf(stderr, "File continuation header, ino %d", previno); 1136 break; 1137 case TS_END: 1138 fprintf(stderr, "End of tape header"); 1139 break; 1140 } 1141 if (predict != blksread - 1) 1142 fprintf(stderr, "; predicted %d blocks, got %d blocks", 1143 predict, blksread - 1); 1144 fprintf(stderr, "\n"); 1145 newcalc: 1146 blks = 0; 1147 if (header->c_type != TS_END) 1148 for (i = 0; i < header->c_count; i++) 1149 if (header->c_addr[i] != 0) 1150 blks++; 1151 predict = blks; 1152 blksread = 0; 1153 prevtype = header->c_type; 1154 previno = header->c_inumber; 1155 } 1156 1157 /* 1158 * Find an inode header. 1159 * Complain if had to skip, and complain is set. 1160 */ 1161 static void 1162 findinode(header) 1163 struct s_spcl *header; 1164 { 1165 static long skipcnt = 0; 1166 long i; 1167 char buf[TP_BSIZE]; 1168 1169 curfile.name = "<name unknown>"; 1170 curfile.action = UNKNOWN; 1171 curfile.dip = NULL; 1172 curfile.ino = 0; 1173 do { 1174 if (header->c_magic != NFS_MAGIC) { 1175 skipcnt++; 1176 while (gethead(header) == FAIL || 1177 header->c_date != dumpdate) 1178 skipcnt++; 1179 } 1180 switch (header->c_type) { 1181 1182 case TS_ADDR: 1183 /* 1184 * Skip up to the beginning of the next record 1185 */ 1186 for (i = 0; i < header->c_count; i++) 1187 if (header->c_addr[i]) 1188 readtape(buf); 1189 while (gethead(header) == FAIL || 1190 header->c_date != dumpdate) 1191 skipcnt++; 1192 break; 1193 1194 case TS_INODE: 1195 curfile.dip = &header->c_dinode; 1196 curfile.ino = header->c_inumber; 1197 break; 1198 1199 case TS_END: 1200 curfile.ino = maxino; 1201 break; 1202 1203 case TS_CLRI: 1204 curfile.name = "<file removal list>"; 1205 break; 1206 1207 case TS_BITS: 1208 curfile.name = "<file dump list>"; 1209 break; 1210 1211 case TS_TAPE: 1212 panic("unexpected tape header\n"); 1213 /* NOTREACHED */ 1214 1215 default: 1216 panic("unknown tape header type %d\n", spcl.c_type); 1217 /* NOTREACHED */ 1218 1219 } 1220 } while (header->c_type == TS_ADDR); 1221 if (skipcnt > 0) 1222 fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt); 1223 skipcnt = 0; 1224 } 1225 1226 static int 1227 checksum(buf) 1228 register int *buf; 1229 { 1230 register int i, j; 1231 1232 j = sizeof(union u_spcl) / sizeof(int); 1233 i = 0; 1234 if(!Bcvt) { 1235 do 1236 i += *buf++; 1237 while (--j); 1238 } else { 1239 /* What happens if we want to read restore tapes 1240 for a 16bit int machine??? */ 1241 do 1242 i += swabl(*buf++); 1243 while (--j); 1244 } 1245 1246 if (i != CHECKSUM) { 1247 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i, 1248 curfile.ino, curfile.name); 1249 return(FAIL); 1250 } 1251 return(GOOD); 1252 } 1253 1254 #ifdef RRESTORE 1255 #if __STDC__ 1256 #include <stdarg.h> 1257 #else 1258 #include <varargs.h> 1259 #endif 1260 1261 void 1262 #if __STDC__ 1263 msg(const char *fmt, ...) 1264 #else 1265 msg(fmt, va_alist) 1266 char *fmt; 1267 va_dcl 1268 #endif 1269 { 1270 va_list ap; 1271 #if __STDC__ 1272 va_start(ap, fmt); 1273 #else 1274 va_start(ap); 1275 #endif 1276 (void)vfprintf(stderr, fmt, ap); 1277 va_end(ap); 1278 } 1279 #endif /* RRESTORE */ 1280 1281 static u_char * 1282 swabshort(sp, n) 1283 register u_char *sp; 1284 register int n; 1285 { 1286 char c; 1287 1288 while (--n >= 0) { 1289 c = sp[0]; sp[0] = sp[1]; sp[1] = c; 1290 sp += 2; 1291 } 1292 return (sp); 1293 } 1294 1295 static u_char * 1296 swablong(sp, n) 1297 register u_char *sp; 1298 register int n; 1299 { 1300 char c; 1301 1302 while (--n >= 0) { 1303 c = sp[0]; sp[0] = sp[3]; sp[3] = c; 1304 c = sp[2]; sp[2] = sp[1]; sp[1] = c; 1305 sp += 4; 1306 } 1307 return (sp); 1308 } 1309 1310 void 1311 swabst(cp, sp) 1312 register u_char *cp, *sp; 1313 { 1314 int n = 0; 1315 1316 while (*cp) { 1317 switch (*cp) { 1318 case '0': case '1': case '2': case '3': case '4': 1319 case '5': case '6': case '7': case '8': case '9': 1320 n = (n * 10) + (*cp++ - '0'); 1321 continue; 1322 1323 case 's': case 'w': case 'h': 1324 if (n == 0) 1325 n = 1; 1326 sp = swabshort(sp, n); 1327 break; 1328 1329 case 'l': 1330 if (n == 0) 1331 n = 1; 1332 sp = swablong(sp, n); 1333 break; 1334 1335 default: /* Any other character, like 'b' counts as byte. */ 1336 if (n == 0) 1337 n = 1; 1338 sp += n; 1339 break; 1340 } 1341 cp++; 1342 n = 0; 1343 } 1344 } 1345 1346 static u_long 1347 swabl(x) 1348 u_long x; 1349 { 1350 swabst((u_char *)"l", (u_char *)&x); 1351 return (x); 1352 } 1353