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