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