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