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