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