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