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