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 59static long fssize = MAXBSIZE; 60static int mt = -1; 61static int pipein = 0; 62static char magtape[BUFSIZ]; 63static int blkcnt; 64static int numtrec; 65static char *tapebuf; 66static union u_spcl endoftapemark; 67static long blksread; /* blocks read since last header */ 68static long tpblksread = 0; /* TP_BSIZE blocks read */ 69static long tapesread; 70static jmp_buf restart; 71static int gettingfile = 0; /* restart has a valid frame */ 72#ifdef RRESTORE 73static char *host = NULL; 74#endif 75 76static int ofile; 77static char *map; 78static char lnkbuf[PATH_MAX + 1]; 79static size_t pathlen; 80 81struct context curfile; /* describes next file available on the tape */ 82union u_spcl u_spcl; /* mapping of variables in a control block */ 83int oldinofmt; /* old inode format conversion required */ 84int Bcvt; /* Swap Bytes (for CCI or sun) */ 85 86#define FLUSHTAPEBUF() blkcnt = ntrec + 1 87 88union 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 116static void accthdr(struct s_spcl *); 117static int checksum(int *); 118static void findinode(struct s_spcl *); 119static void findtapeblksize(void); 120static int gethead(struct s_spcl *); 121static void readtape(char *); 122static void setdumpnum(void); 123static void swap_header(struct s_spcl *); 124static void swap_old_header(struct s_ospcl *); 125static void terminateinput(void); 126static void xtrlnkfile(char *, size_t); 127static void xtrlnkskip(char *, size_t); 128static void xtrmap(char *, size_t); 129static void xtrmapskip(char *, size_t); 130static void xtrskip(char *, size_t); 131 132/* 133 * Set up an input source 134 */ 135void 136setinput(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 172void 173newtapebuf(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 */ 191void 192setup(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 */ 281void 282getvol(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; 302again: 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 } 373gethdr: 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 */ 455static void 456terminateinput(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 */ 477static void 478setdumpnum(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 497void 498printdumpinfo(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 523int 524extractfile(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 */ 662void 663skipmaps(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 */ 673void 674skipfile(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 */ 690void 691getfile(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++; 708loop: 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 */ 751void 752xtrfile(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 */ 765static void 766xtrskip(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 */ 777static void 778xtrlnkfile(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 */ 791static void 792xtrlnkskip(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 */ 801static void 802xtrmap(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 */ 812static void 813xtrmapskip(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 */ 823void 824xtrnull(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 */ 834static void 835readtape(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; 852getmore: 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 949static void 950findtapeblksize(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 976void 977closemt(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 */ 996static int 997gethead(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; 1051good: 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 */ 1110static void 1111accthdr(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"); 1153newcalc: 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 */ 1180static void 1181findinode(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 1255static int 1256checksum(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 1283void 1284msg(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 1294static void 1295swap_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 1338static void 1339swap_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