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