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