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