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