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