1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #ifndef lint 36 #if 0 37 static char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 5/1/95"; 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/cdefs.h> 42 __FBSDID("$FreeBSD$"); 43 44 #include <sys/param.h> 45 #include <sys/file.h> 46 #include <sys/mtio.h> 47 #include <sys/stat.h> 48 #include <sys/time.h> 49 #include <sys/extattr.h> 50 #include <sys/acl.h> 51 52 #include <ufs/ufs/dinode.h> 53 #include <protocols/dumprestore.h> 54 55 #include <errno.h> 56 #include <limits.h> 57 #include <paths.h> 58 #include <setjmp.h> 59 #include <stdint.h> 60 #include <stdio.h> 61 #include <stdlib.h> 62 #include <string.h> 63 #include <time.h> 64 #include <timeconv.h> 65 #include <unistd.h> 66 67 #include "restore.h" 68 #include "extern.h" 69 70 static long fssize = MAXBSIZE; 71 static int mt = -1; 72 static int pipein = 0; 73 static int pipecmdin = 0; 74 static FILE *popenfp = NULL; 75 static char *magtape; 76 static int blkcnt; 77 static int numtrec; 78 static char *tapebuf; 79 static union u_spcl endoftapemark; 80 static long byteslide = 0; 81 static long blksread; /* blocks read since last header */ 82 static int64_t tapeaddr = 0; /* current TP_BSIZE tape record */ 83 static long tapesread; 84 static jmp_buf restart; 85 static int gettingfile = 0; /* restart has a valid frame */ 86 static char *host = NULL; 87 static int readmapflag; 88 89 static int ofile; 90 static char *map; 91 static char lnkbuf[MAXPATHLEN + 1]; 92 static int pathlen; 93 94 int Bcvt; /* Swap Bytes */ 95 int oldinofmt; /* FreeBSD 1 inode format needs cvt */ 96 97 #define FLUSHTAPEBUF() blkcnt = ntrec + 1 98 99 char *namespace_names[] = EXTATTR_NAMESPACE_NAMES; 100 101 static void accthdr(struct s_spcl *); 102 static int checksum(int *); 103 static void findinode(struct s_spcl *); 104 static void findtapeblksize(void); 105 static char *setupextattr(int); 106 static void xtrattr(char *, long); 107 static void set_extattr_link(char *, void *, int); 108 static void set_extattr_fd(int, char *, void *, int); 109 static int gethead(struct s_spcl *); 110 static void readtape(char *); 111 static void setdumpnum(void); 112 static u_long swabl(u_long); 113 static u_char *swablong(u_char *, int); 114 static u_char *swabshort(u_char *, int); 115 static void terminateinput(void); 116 static void xtrfile(char *, long); 117 static void xtrlnkfile(char *, long); 118 static void xtrlnkskip(char *, long); 119 static void xtrmap(char *, long); 120 static void xtrmapskip(char *, long); 121 static void xtrskip(char *, long); 122 123 /* 124 * Set up an input source 125 */ 126 void 127 setinput(char *source, int ispipecommand) 128 { 129 FLUSHTAPEBUF(); 130 if (bflag) 131 newtapebuf(ntrec); 132 else 133 newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC); 134 terminal = stdin; 135 136 if (ispipecommand) 137 pipecmdin++; 138 else 139 #ifdef RRESTORE 140 if (strchr(source, ':')) { 141 host = source; 142 source = strchr(host, ':'); 143 *source++ = '\0'; 144 if (rmthost(host) == 0) 145 done(1); 146 } else 147 #endif 148 if (strcmp(source, "-") == 0) { 149 /* 150 * Since input is coming from a pipe we must establish 151 * our own connection to the terminal. 152 */ 153 terminal = fopen(_PATH_TTY, "r"); 154 if (terminal == NULL) { 155 (void)fprintf(stderr, "cannot open %s: %s\n", 156 _PATH_TTY, strerror(errno)); 157 terminal = fopen(_PATH_DEVNULL, "r"); 158 if (terminal == NULL) { 159 (void)fprintf(stderr, "cannot open %s: %s\n", 160 _PATH_DEVNULL, strerror(errno)); 161 done(1); 162 } 163 } 164 pipein++; 165 } 166 setuid(getuid()); /* no longer need or want root privileges */ 167 magtape = strdup(source); 168 if (magtape == NULL) { 169 fprintf(stderr, "Cannot allocate space for magtape buffer\n"); 170 done(1); 171 } 172 } 173 174 void 175 newtapebuf(long size) 176 { 177 static int tapebufsize = -1; 178 179 ntrec = size; 180 if (size <= tapebufsize) 181 return; 182 if (tapebuf != NULL) 183 free(tapebuf - TP_BSIZE); 184 tapebuf = malloc((size+1) * TP_BSIZE); 185 if (tapebuf == NULL) { 186 fprintf(stderr, "Cannot allocate space for tape buffer\n"); 187 done(1); 188 } 189 tapebuf += TP_BSIZE; 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 if (pipecmdin) { 205 if (setenv("RESTORE_VOLUME", "1", 1) == -1) { 206 fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n", 207 strerror(errno)); 208 done(1); 209 } 210 popenfp = popen(magtape, "r"); 211 mt = popenfp ? fileno(popenfp) : -1; 212 } else 213 #ifdef RRESTORE 214 if (host) 215 mt = rmtopen(magtape, 0); 216 else 217 #endif 218 if (pipein) 219 mt = 0; 220 else 221 mt = open(magtape, O_RDONLY, 0); 222 if (mt < 0) { 223 fprintf(stderr, "%s: %s\n", magtape, strerror(errno)); 224 done(1); 225 } 226 volno = 1; 227 setdumpnum(); 228 FLUSHTAPEBUF(); 229 if (!pipein && !bflag) 230 findtapeblksize(); 231 if (gethead(&spcl) == FAIL) { 232 fprintf(stderr, "Tape is not a dump tape\n"); 233 done(1); 234 } 235 if (pipein) { 236 endoftapemark.s_spcl.c_magic = FS_UFS2_MAGIC; 237 endoftapemark.s_spcl.c_type = TS_END; 238 ip = (int *)&endoftapemark; 239 j = sizeof(union u_spcl) / sizeof(int); 240 i = 0; 241 do 242 i += *ip++; 243 while (--j); 244 endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 245 } 246 if (vflag || command == 't') 247 printdumpinfo(); 248 dumptime = _time64_to_time(spcl.c_ddate); 249 dumpdate = _time64_to_time(spcl.c_date); 250 if (stat(".", &stbuf) < 0) { 251 fprintf(stderr, "cannot stat .: %s\n", strerror(errno)); 252 done(1); 253 } 254 if (stbuf.st_blksize > 0 && stbuf.st_blksize < TP_BSIZE ) 255 fssize = TP_BSIZE; 256 if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE) 257 fssize = stbuf.st_blksize; 258 if (((fssize - 1) & fssize) != 0) { 259 fprintf(stderr, "bad block size %ld\n", fssize); 260 done(1); 261 } 262 if (spcl.c_volume != 1) { 263 fprintf(stderr, "Tape is not volume 1 of the dump\n"); 264 done(1); 265 } 266 if (gethead(&spcl) == FAIL) { 267 dprintf(stdout, "header read failed at %ld blocks\n", blksread); 268 panic("no header after volume mark!\n"); 269 } 270 findinode(&spcl); 271 if (spcl.c_type != TS_CLRI) { 272 fprintf(stderr, "Cannot find file removal list\n"); 273 done(1); 274 } 275 maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1; 276 dprintf(stdout, "maxino = %d\n", maxino); 277 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 278 if (map == NULL) 279 panic("no memory for active inode map\n"); 280 usedinomap = map; 281 curfile.action = USING; 282 getfile(xtrmap, xtrmapskip, xtrmapskip); 283 if (spcl.c_type != TS_BITS) { 284 fprintf(stderr, "Cannot find file dump list\n"); 285 done(1); 286 } 287 map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); 288 if (map == (char *)NULL) 289 panic("no memory for file dump list\n"); 290 dumpmap = map; 291 curfile.action = USING; 292 getfile(xtrmap, xtrmapskip, xtrmapskip); 293 /* 294 * If there may be whiteout entries on the tape, pretend that the 295 * whiteout inode exists, so that the whiteout entries can be 296 * extracted. 297 */ 298 SETINO(WINO, dumpmap); 299 /* 'r' restores don't call getvol() for tape 1, so mark it as read. */ 300 if (command == 'r') 301 tapesread = 1; 302 } 303 304 /* 305 * Prompt user to load a new dump volume. 306 * "Nextvol" is the next suggested volume to use. 307 * This suggested volume is enforced when doing full 308 * or incremental restores, but can be overridden by 309 * the user when only extracting a subset of the files. 310 */ 311 void 312 getvol(long nextvol) 313 { 314 int64_t prevtapea; 315 long i, newvol, savecnt; 316 union u_spcl tmpspcl; 317 # define tmpbuf tmpspcl.s_spcl 318 char buf[TP_BSIZE]; 319 320 if (nextvol == 1) { 321 tapesread = 0; 322 gettingfile = 0; 323 } 324 prevtapea = tapeaddr; 325 savecnt = blksread; 326 if (pipein) { 327 if (nextvol != 1) { 328 panic("Changing volumes on pipe input?\n"); 329 /* Avoid looping if we couldn't ask the user. */ 330 if (yflag || ferror(terminal) || feof(terminal)) 331 done(1); 332 } 333 if (volno == 1) 334 return; 335 if (pipecmdin) { 336 closemt(); 337 goto getpipecmdhdr; 338 } 339 goto gethdr; 340 } 341 again: 342 if (pipein) 343 done(1); /* pipes do not get a second chance */ 344 if (command == 'R' || command == 'r' || curfile.action != SKIP) 345 newvol = nextvol; 346 else 347 newvol = 0; 348 while (newvol <= 0) { 349 if (tapesread == 0) { 350 fprintf(stderr, "%s%s%s%s%s%s%s", 351 "You have not read any tapes yet.\n", 352 "If you are extracting just a few files,", 353 " start with the last volume\n", 354 "and work towards the first; restore", 355 " can quickly skip tapes that\n", 356 "have no further files to extract.", 357 " Otherwise, begin with volume 1.\n"); 358 } else { 359 fprintf(stderr, "You have read volumes"); 360 strcpy(buf, ": "); 361 for (i = 0; i < 32; i++) 362 if (tapesread & (1 << i)) { 363 fprintf(stderr, "%s%ld", buf, i + 1); 364 strcpy(buf, ", "); 365 } 366 fprintf(stderr, "\n"); 367 } 368 do { 369 fprintf(stderr, "Specify next volume #: "); 370 (void) fflush(stderr); 371 if (fgets(buf, BUFSIZ, terminal) == NULL) 372 done(1); 373 } while (buf[0] == '\n'); 374 newvol = atoi(buf); 375 if (newvol <= 0) { 376 fprintf(stderr, 377 "Volume numbers are positive numerics\n"); 378 } 379 } 380 if (newvol == volno) { 381 tapesread |= 1 << (volno - 1); 382 return; 383 } 384 closemt(); 385 fprintf(stderr, "Mount tape volume %ld\n", newvol); 386 fprintf(stderr, "Enter ``none'' if there are no more tapes\n"); 387 fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape); 388 (void) fflush(stderr); 389 if (fgets(buf, BUFSIZ, terminal) == NULL) 390 done(1); 391 if (!strcmp(buf, "none\n")) { 392 terminateinput(); 393 return; 394 } 395 if (buf[0] != '\n') { 396 (void) strcpy(magtape, buf); 397 magtape[strlen(magtape) - 1] = '\0'; 398 } 399 if (pipecmdin) { 400 char volno[sizeof("2147483647")]; 401 402 getpipecmdhdr: 403 (void)sprintf(volno, "%d", newvol); 404 if (setenv("RESTORE_VOLUME", volno, 1) == -1) { 405 fprintf(stderr, "Cannot set $RESTORE_VOLUME: %s\n", 406 strerror(errno)); 407 done(1); 408 } 409 popenfp = popen(magtape, "r"); 410 mt = popenfp ? fileno(popenfp) : -1; 411 } else 412 #ifdef RRESTORE 413 if (host) 414 mt = rmtopen(magtape, 0); 415 else 416 #endif 417 mt = open(magtape, O_RDONLY, 0); 418 419 if (mt == -1) { 420 fprintf(stderr, "Cannot open %s\n", magtape); 421 volno = -1; 422 goto again; 423 } 424 gethdr: 425 volno = newvol; 426 setdumpnum(); 427 FLUSHTAPEBUF(); 428 if (gethead(&tmpbuf) == FAIL) { 429 dprintf(stdout, "header read failed at %ld blocks\n", blksread); 430 fprintf(stderr, "tape is not dump tape\n"); 431 volno = 0; 432 goto again; 433 } 434 if (tmpbuf.c_volume != volno) { 435 fprintf(stderr, "Wrong volume (%ld)\n", tmpbuf.c_volume); 436 volno = 0; 437 goto again; 438 } 439 if (_time64_to_time(tmpbuf.c_date) != dumpdate || 440 _time64_to_time(tmpbuf.c_ddate) != dumptime) { 441 time_t t = _time64_to_time(tmpbuf.c_date); 442 fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t)); 443 fprintf(stderr, "\twanted: %s", ctime(&dumpdate)); 444 volno = 0; 445 goto again; 446 } 447 tapesread |= 1 << (volno - 1); 448 blksread = savecnt; 449 /* 450 * If continuing from the previous volume, skip over any 451 * blocks read already at the end of the previous volume. 452 * 453 * If coming to this volume at random, skip to the beginning 454 * of the next record. 455 */ 456 dprintf(stdout, "last rec %qd, tape starts with %qd\n", prevtapea, 457 tmpbuf.c_tapea); 458 if (tmpbuf.c_type == TS_TAPE) { 459 if (curfile.action != USING) { 460 /* 461 * XXX Dump incorrectly sets c_count to 1 in the 462 * volume header of the first tape, so ignore 463 * c_count when volno == 1. 464 */ 465 if (volno != 1) 466 for (i = tmpbuf.c_count; i > 0; i--) 467 readtape(buf); 468 } else if (tmpbuf.c_tapea <= prevtapea) { 469 /* 470 * Normally the value of c_tapea in the volume 471 * header is the record number of the header itself. 472 * However in the volume header following an EOT- 473 * terminated tape, it is the record number of the 474 * first continuation data block (dump bug?). 475 * 476 * The next record we want is `prevtapea + 1'. 477 */ 478 i = prevtapea + 1 - tmpbuf.c_tapea; 479 dprintf(stderr, "Skipping %ld duplicate record%s.\n", 480 i, i > 1 ? "s" : ""); 481 while (--i >= 0) 482 readtape(buf); 483 } 484 } 485 if (curfile.action == USING) { 486 if (volno == 1) 487 panic("active file into volume 1\n"); 488 return; 489 } 490 (void) gethead(&spcl); 491 findinode(&spcl); 492 if (gettingfile) { 493 gettingfile = 0; 494 longjmp(restart, 1); 495 } 496 } 497 498 /* 499 * Handle unexpected EOF. 500 */ 501 static void 502 terminateinput(void) 503 { 504 505 if (gettingfile && curfile.action == USING) { 506 printf("Warning: %s %s\n", 507 "End-of-input encountered while extracting", curfile.name); 508 } 509 curfile.name = "<name unknown>"; 510 curfile.action = UNKNOWN; 511 curfile.mode = 0; 512 curfile.ino = maxino; 513 if (gettingfile) { 514 gettingfile = 0; 515 longjmp(restart, 1); 516 } 517 } 518 519 /* 520 * handle multiple dumps per tape by skipping forward to the 521 * appropriate one. 522 */ 523 static void 524 setdumpnum(void) 525 { 526 struct mtop tcom; 527 528 if (dumpnum == 1 || volno != 1) 529 return; 530 if (pipein) { 531 fprintf(stderr, "Cannot have multiple dumps on pipe input\n"); 532 done(1); 533 } 534 tcom.mt_op = MTFSF; 535 tcom.mt_count = dumpnum - 1; 536 #ifdef RRESTORE 537 if (host) 538 rmtioctl(MTFSF, dumpnum - 1); 539 else 540 #endif 541 if (!pipecmdin && ioctl(mt, MTIOCTOP, (char *)&tcom) < 0) 542 fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno)); 543 } 544 545 void 546 printdumpinfo(void) 547 { 548 time_t t; 549 t = _time64_to_time(spcl.c_date); 550 fprintf(stdout, "Dump date: %s", ctime(&t)); 551 t = _time64_to_time(spcl.c_ddate); 552 fprintf(stdout, "Dumped from: %s", 553 (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&t)); 554 if (spcl.c_host[0] == '\0') 555 return; 556 fprintf(stderr, "Level %ld dump of %s on %s:%s\n", 557 spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev); 558 fprintf(stderr, "Label: %s\n", spcl.c_label); 559 } 560 561 int 562 extractfile(char *name) 563 { 564 int flags; 565 uid_t uid; 566 gid_t gid; 567 mode_t mode; 568 int extsize; 569 struct timeval mtimep[2], ctimep[2]; 570 struct entry *ep; 571 char *buf; 572 573 curfile.name = name; 574 curfile.action = USING; 575 mtimep[0].tv_sec = curfile.atime_sec; 576 mtimep[0].tv_usec = curfile.atime_nsec / 1000; 577 mtimep[1].tv_sec = curfile.mtime_sec; 578 mtimep[1].tv_usec = curfile.mtime_nsec / 1000; 579 ctimep[0].tv_sec = curfile.atime_sec; 580 ctimep[0].tv_usec = curfile.atime_nsec / 1000; 581 ctimep[1].tv_sec = curfile.birthtime_sec; 582 ctimep[1].tv_usec = curfile.birthtime_nsec / 1000; 583 extsize = curfile.extsize; 584 uid = curfile.uid; 585 gid = curfile.gid; 586 mode = curfile.mode; 587 flags = curfile.file_flags; 588 switch (mode & IFMT) { 589 590 default: 591 fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode); 592 skipfile(); 593 return (FAIL); 594 595 case IFSOCK: 596 vprintf(stdout, "skipped socket %s\n", name); 597 skipfile(); 598 return (GOOD); 599 600 case IFDIR: 601 if (mflag) { 602 ep = lookupname(name); 603 if (ep == NULL || ep->e_flags & EXTRACT) 604 panic("unextracted directory %s\n", name); 605 skipfile(); 606 return (GOOD); 607 } 608 vprintf(stdout, "extract file %s\n", name); 609 return (genliteraldir(name, curfile.ino)); 610 611 case IFLNK: 612 lnkbuf[0] = '\0'; 613 pathlen = 0; 614 buf = setupextattr(extsize); 615 getfile(xtrlnkfile, xtrattr, xtrlnkskip); 616 if (pathlen == 0) { 617 vprintf(stdout, 618 "%s: zero length symbolic link (ignored)\n", name); 619 return (GOOD); 620 } 621 if (linkit(lnkbuf, name, SYMLINK) == GOOD) { 622 if (extsize > 0) 623 set_extattr_link(name, buf, extsize); 624 (void) lchown(name, uid, gid); 625 (void) lchmod(name, mode); 626 (void) lutimes(name, ctimep); 627 (void) lutimes(name, mtimep); 628 (void) lchflags(name, flags); 629 return (GOOD); 630 } 631 return (FAIL); 632 633 case IFIFO: 634 vprintf(stdout, "extract fifo %s\n", name); 635 if (Nflag) { 636 skipfile(); 637 return (GOOD); 638 } 639 if (uflag) 640 (void) unlink(name); 641 if (mkfifo(name, 0600) < 0) { 642 fprintf(stderr, "%s: cannot create fifo: %s\n", 643 name, strerror(errno)); 644 skipfile(); 645 return (FAIL); 646 } 647 if (extsize == 0) { 648 skipfile(); 649 } else { 650 buf = setupextattr(extsize); 651 getfile(xtrnull, xtrattr, xtrnull); 652 set_extattr_file(name, buf, extsize); 653 } 654 (void) chown(name, uid, gid); 655 (void) chmod(name, mode); 656 (void) utimes(name, ctimep); 657 (void) utimes(name, mtimep); 658 (void) chflags(name, flags); 659 return (GOOD); 660 661 case IFCHR: 662 case IFBLK: 663 vprintf(stdout, "extract special file %s\n", name); 664 if (Nflag) { 665 skipfile(); 666 return (GOOD); 667 } 668 if (uflag) 669 (void) unlink(name); 670 if (mknod(name, (mode & (IFCHR | IFBLK)) | 0600, 671 (int)curfile.rdev) < 0) { 672 fprintf(stderr, "%s: cannot create special file: %s\n", 673 name, strerror(errno)); 674 skipfile(); 675 return (FAIL); 676 } 677 if (extsize == 0) { 678 skipfile(); 679 } else { 680 buf = setupextattr(extsize); 681 getfile(xtrnull, xtrattr, xtrnull); 682 set_extattr_file(name, buf, extsize); 683 } 684 (void) chown(name, uid, gid); 685 (void) chmod(name, mode); 686 (void) utimes(name, ctimep); 687 (void) utimes(name, mtimep); 688 (void) chflags(name, flags); 689 return (GOOD); 690 691 case IFREG: 692 vprintf(stdout, "extract file %s\n", name); 693 if (Nflag) { 694 skipfile(); 695 return (GOOD); 696 } 697 if (uflag) 698 (void) unlink(name); 699 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 700 0600)) < 0) { 701 fprintf(stderr, "%s: cannot create file: %s\n", 702 name, strerror(errno)); 703 skipfile(); 704 return (FAIL); 705 } 706 buf = setupextattr(extsize); 707 getfile(xtrfile, xtrattr, xtrskip); 708 if (extsize > 0) 709 set_extattr_fd(ofile, name, buf, extsize); 710 (void) fchown(ofile, uid, gid); 711 (void) fchmod(ofile, mode); 712 (void) futimes(ofile, ctimep); 713 (void) futimes(ofile, mtimep); 714 (void) fchflags(ofile, flags); 715 (void) close(ofile); 716 return (GOOD); 717 } 718 /* NOTREACHED */ 719 } 720 721 /* 722 * Set attributes for a file. 723 */ 724 void 725 set_extattr_file(char *name, void *buf, int size) 726 { 727 struct extattr *eap, *eaend; 728 729 vprintf(stdout, "Set attributes for %s:", name); 730 eaend = buf + size; 731 for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) { 732 /* 733 * Make sure this entry is complete. 734 */ 735 if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) { 736 dprintf(stdout, "\n\t%scorrupted", 737 eap == buf ? "" : "remainder "); 738 break; 739 } 740 if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY) 741 continue; 742 vprintf(stdout, "\n\t%s, (%d bytes), %*s", 743 namespace_names[eap->ea_namespace], eap->ea_length, 744 eap->ea_namelength, eap->ea_name); 745 /* 746 * First we try the general attribute setting interface. 747 * However, some attributes can only be set by root or 748 * by using special interfaces (for example, ACLs). 749 */ 750 if (extattr_set_file(name, eap->ea_namespace, eap->ea_name, 751 EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) { 752 dprintf(stdout, " (set using extattr_set_file)"); 753 continue; 754 } 755 /* 756 * If the general interface refuses to set the attribute, 757 * then we try all the specialized interfaces that we 758 * know about. 759 */ 760 if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 761 !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) { 762 if (acl_set_file(name, ACL_TYPE_ACCESS, 763 EXTATTR_CONTENT(eap)) != -1) { 764 dprintf(stdout, " (set using acl_set_file)"); 765 continue; 766 } 767 } 768 if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 769 !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) { 770 if (acl_set_file(name, ACL_TYPE_DEFAULT, 771 EXTATTR_CONTENT(eap)) != -1) { 772 dprintf(stdout, " (set using acl_set_file)"); 773 continue; 774 } 775 } 776 vprintf(stdout, " (unable to set)"); 777 } 778 vprintf(stdout, "\n"); 779 } 780 781 /* 782 * Set attributes for a symbolic link. 783 */ 784 static void 785 set_extattr_link(char *name, void *buf, int size) 786 { 787 struct extattr *eap, *eaend; 788 789 vprintf(stdout, "Set attributes for %s:", name); 790 eaend = buf + size; 791 for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) { 792 /* 793 * Make sure this entry is complete. 794 */ 795 if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) { 796 dprintf(stdout, "\n\t%scorrupted", 797 eap == buf ? "" : "remainder "); 798 break; 799 } 800 if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY) 801 continue; 802 vprintf(stdout, "\n\t%s, (%d bytes), %*s", 803 namespace_names[eap->ea_namespace], eap->ea_length, 804 eap->ea_namelength, eap->ea_name); 805 /* 806 * First we try the general attribute setting interface. 807 * However, some attributes can only be set by root or 808 * by using special interfaces (for example, ACLs). 809 */ 810 if (extattr_set_link(name, eap->ea_namespace, eap->ea_name, 811 EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) { 812 dprintf(stdout, " (set using extattr_set_link)"); 813 continue; 814 } 815 /* 816 * If the general interface refuses to set the attribute, 817 * then we try all the specialized interfaces that we 818 * know about. 819 */ 820 if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 821 !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) { 822 if (acl_set_link_np(name, ACL_TYPE_ACCESS, 823 EXTATTR_CONTENT(eap)) != -1) { 824 dprintf(stdout, " (set using acl_set_link_np)"); 825 continue; 826 } 827 } 828 if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 829 !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) { 830 if (acl_set_link_np(name, ACL_TYPE_DEFAULT, 831 EXTATTR_CONTENT(eap)) != -1) { 832 dprintf(stdout, " (set using acl_set_link_np)"); 833 continue; 834 } 835 } 836 vprintf(stdout, " (unable to set)"); 837 } 838 vprintf(stdout, "\n"); 839 } 840 841 /* 842 * Set attributes on a file descriptor. 843 */ 844 static void 845 set_extattr_fd(int fd, char *name, void *buf, int size) 846 { 847 struct extattr *eap, *eaend; 848 849 vprintf(stdout, "Set attributes for %s:", name); 850 eaend = buf + size; 851 for (eap = buf; eap < eaend; eap = EXTATTR_NEXT(eap)) { 852 /* 853 * Make sure this entry is complete. 854 */ 855 if (EXTATTR_NEXT(eap) > eaend || eap->ea_length <= 0) { 856 dprintf(stdout, "\n\t%scorrupted", 857 eap == buf ? "" : "remainder "); 858 break; 859 } 860 if (eap->ea_namespace == EXTATTR_NAMESPACE_EMPTY) 861 continue; 862 vprintf(stdout, "\n\t%s, (%d bytes), %*s", 863 namespace_names[eap->ea_namespace], eap->ea_length, 864 eap->ea_namelength, eap->ea_name); 865 /* 866 * First we try the general attribute setting interface. 867 * However, some attributes can only be set by root or 868 * by using special interfaces (for example, ACLs). 869 */ 870 if (extattr_set_fd(fd, eap->ea_namespace, eap->ea_name, 871 EXTATTR_CONTENT(eap), EXTATTR_CONTENT_SIZE(eap)) != -1) { 872 dprintf(stdout, " (set using extattr_set_fd)"); 873 continue; 874 } 875 /* 876 * If the general interface refuses to set the attribute, 877 * then we try all the specialized interfaces that we 878 * know about. 879 */ 880 if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 881 !strcmp(eap->ea_name, POSIX1E_ACL_ACCESS_EXTATTR_NAME)) { 882 if (acl_set_fd(fd, EXTATTR_CONTENT(eap)) != -1) { 883 dprintf(stdout, " (set using acl_set_fd)"); 884 continue; 885 } 886 } 887 if (eap->ea_namespace == EXTATTR_NAMESPACE_SYSTEM && 888 !strcmp(eap->ea_name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME)) { 889 if (acl_set_file(name, ACL_TYPE_DEFAULT, 890 EXTATTR_CONTENT(eap)) != -1) { 891 dprintf(stdout, " (set using acl_set_file)"); 892 continue; 893 } 894 } 895 vprintf(stdout, " (unable to set)"); 896 } 897 vprintf(stdout, "\n"); 898 } 899 900 /* 901 * skip over bit maps on the tape 902 */ 903 void 904 skipmaps(void) 905 { 906 907 while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI) 908 skipfile(); 909 } 910 911 /* 912 * skip over a file on the tape 913 */ 914 void 915 skipfile(void) 916 { 917 918 curfile.action = SKIP; 919 getfile(xtrnull, xtrnull, xtrnull); 920 } 921 922 /* 923 * Extract a file from the tape. 924 * When an allocated block is found it is passed to the fill function; 925 * when an unallocated block (hole) is found, a zeroed buffer is passed 926 * to the skip function. 927 */ 928 void 929 getfile(void (*datafill)(char *, long), void (*attrfill)(char *, long), 930 void (*skip)(char *, long)) 931 { 932 int i; 933 off_t size; 934 int curblk, attrsize; 935 void (*fillit)(char *, long); 936 static char clearedbuf[MAXBSIZE]; 937 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; 938 char junk[TP_BSIZE]; 939 940 curblk = 0; 941 size = spcl.c_size; 942 attrsize = spcl.c_extsize; 943 if (spcl.c_type == TS_END) 944 panic("ran off end of tape\n"); 945 if (spcl.c_magic != FS_UFS2_MAGIC) 946 panic("not at beginning of a file\n"); 947 if (!gettingfile && setjmp(restart) != 0) 948 return; 949 gettingfile++; 950 fillit = datafill; 951 if (size == 0 && attrsize > 0) { 952 fillit = attrfill; 953 size = attrsize; 954 attrsize = 0; 955 } 956 loop: 957 for (i = 0; i < spcl.c_count; i++) { 958 if (!readmapflag && i > TP_NINDIR) { 959 if (Dflag) { 960 fprintf(stderr, "spcl.c_count = %jd\n", 961 (intmax_t)spcl.c_count); 962 break; 963 } else 964 panic("spcl.c_count = %jd\n", 965 (intmax_t)spcl.c_count); 966 } 967 if (readmapflag || spcl.c_addr[i]) { 968 readtape(&buf[curblk++][0]); 969 if (curblk == fssize / TP_BSIZE) { 970 (*fillit)((char *)buf, (long)(size > TP_BSIZE ? 971 fssize : (curblk - 1) * TP_BSIZE + size)); 972 curblk = 0; 973 } 974 } else { 975 if (curblk > 0) { 976 (*fillit)((char *)buf, (long)(size > TP_BSIZE ? 977 curblk * TP_BSIZE : 978 (curblk - 1) * TP_BSIZE + size)); 979 curblk = 0; 980 } 981 (*skip)(clearedbuf, (long)(size > TP_BSIZE ? 982 TP_BSIZE : size)); 983 } 984 if ((size -= TP_BSIZE) <= 0) { 985 if (size > -TP_BSIZE && curblk > 0) { 986 (*fillit)((char *)buf, 987 (long)((curblk * TP_BSIZE) + size)); 988 curblk = 0; 989 } 990 if (attrsize > 0) { 991 fillit = attrfill; 992 size = attrsize; 993 attrsize = 0; 994 continue; 995 } 996 if (spcl.c_count - i > 1) 997 dprintf(stdout, "skipping %d junk block(s)\n", 998 spcl.c_count - i - 1); 999 for (i++; i < spcl.c_count; i++) { 1000 if (!readmapflag && i > TP_NINDIR) { 1001 if (Dflag) { 1002 fprintf(stderr, 1003 "spcl.c_count = %jd\n", 1004 (intmax_t)spcl.c_count); 1005 break; 1006 } else 1007 panic("spcl.c_count = %jd\n", 1008 (intmax_t)spcl.c_count); 1009 } 1010 if (readmapflag || spcl.c_addr[i]) 1011 readtape(junk); 1012 } 1013 break; 1014 } 1015 } 1016 if (gethead(&spcl) == GOOD && size > 0) { 1017 if (spcl.c_type == TS_ADDR) 1018 goto loop; 1019 dprintf(stdout, 1020 "Missing address (header) block for %s at %ld blocks\n", 1021 curfile.name, blksread); 1022 } 1023 if (curblk > 0) 1024 panic("getfile: lost data\n"); 1025 findinode(&spcl); 1026 gettingfile = 0; 1027 } 1028 1029 /* 1030 * These variables are shared between the next two functions. 1031 */ 1032 static int extbufsize = 0; 1033 static char *extbuf; 1034 static int extloc; 1035 1036 /* 1037 * Allocate a buffer into which to extract extended attributes. 1038 */ 1039 static char * 1040 setupextattr(int extsize) 1041 { 1042 1043 extloc = 0; 1044 if (extsize <= extbufsize) 1045 return (extbuf); 1046 if (extbufsize > 0) 1047 free(extbuf); 1048 if ((extbuf = malloc(extsize)) != NULL) { 1049 extbufsize = extsize; 1050 return (extbuf); 1051 } 1052 extbufsize = 0; 1053 extbuf = NULL; 1054 fprintf(stderr, "Cannot extract %d bytes %s for inode %d, name %s\n", 1055 extsize, "of extended attributes", curfile.ino, curfile.name); 1056 return (NULL); 1057 } 1058 1059 /* 1060 * Extract the next block of extended attributes. 1061 */ 1062 static void 1063 xtrattr(char *buf, long size) 1064 { 1065 1066 if (extloc + size > extbufsize) 1067 panic("overrun attribute buffer\n"); 1068 memmove(&extbuf[extloc], buf, size); 1069 extloc += size; 1070 } 1071 1072 /* 1073 * Write out the next block of a file. 1074 */ 1075 static void 1076 xtrfile(char *buf, long size) 1077 { 1078 1079 if (Nflag) 1080 return; 1081 if (write(ofile, buf, (int) size) == -1) { 1082 fprintf(stderr, 1083 "write error extracting inode %d, name %s\nwrite: %s\n", 1084 curfile.ino, curfile.name, strerror(errno)); 1085 } 1086 } 1087 1088 /* 1089 * Skip over a hole in a file. 1090 */ 1091 /* ARGSUSED */ 1092 static void 1093 xtrskip(char *buf, long size) 1094 { 1095 1096 if (lseek(ofile, size, SEEK_CUR) == -1) { 1097 fprintf(stderr, 1098 "seek error extracting inode %d, name %s\nlseek: %s\n", 1099 curfile.ino, curfile.name, strerror(errno)); 1100 done(1); 1101 } 1102 } 1103 1104 /* 1105 * Collect the next block of a symbolic link. 1106 */ 1107 static void 1108 xtrlnkfile(char *buf, long size) 1109 { 1110 1111 pathlen += size; 1112 if (pathlen > MAXPATHLEN) { 1113 fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n", 1114 curfile.name, lnkbuf, buf, pathlen); 1115 done(1); 1116 } 1117 (void) strcat(lnkbuf, buf); 1118 } 1119 1120 /* 1121 * Skip over a hole in a symbolic link (should never happen). 1122 */ 1123 /* ARGSUSED */ 1124 static void 1125 xtrlnkskip(char *buf, long size) 1126 { 1127 1128 fprintf(stderr, "unallocated block in symbolic link %s\n", 1129 curfile.name); 1130 done(1); 1131 } 1132 1133 /* 1134 * Collect the next block of a bit map. 1135 */ 1136 static void 1137 xtrmap(char *buf, long size) 1138 { 1139 1140 memmove(map, buf, size); 1141 map += size; 1142 } 1143 1144 /* 1145 * Skip over a hole in a bit map (should never happen). 1146 */ 1147 /* ARGSUSED */ 1148 static void 1149 xtrmapskip(char *buf, long size) 1150 { 1151 1152 panic("hole in map\n"); 1153 map += size; 1154 } 1155 1156 /* 1157 * Noop, when an extraction function is not needed. 1158 */ 1159 /* ARGSUSED */ 1160 void 1161 xtrnull(char *buf, long size) 1162 { 1163 1164 return; 1165 } 1166 1167 /* 1168 * Read TP_BSIZE blocks from the input. 1169 * Handle read errors, and end of media. 1170 */ 1171 static void 1172 readtape(char *buf) 1173 { 1174 long rd, newvol, i, oldnumtrec; 1175 int cnt, seek_failed; 1176 1177 if (blkcnt + (byteslide > 0) < numtrec) { 1178 memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE) + byteslide], (long)TP_BSIZE); 1179 blksread++; 1180 tapeaddr++; 1181 return; 1182 } 1183 if (numtrec > 0) 1184 memmove(&tapebuf[-TP_BSIZE], 1185 &tapebuf[(numtrec-1) * TP_BSIZE], (long)TP_BSIZE); 1186 oldnumtrec = numtrec; 1187 for (i = 0; i < ntrec; i++) 1188 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 1189 if (numtrec == 0) 1190 numtrec = ntrec; 1191 cnt = ntrec * TP_BSIZE; 1192 rd = 0; 1193 getmore: 1194 #ifdef RRESTORE 1195 if (host) 1196 i = rmtread(&tapebuf[rd], cnt); 1197 else 1198 #endif 1199 i = read(mt, &tapebuf[rd], cnt); 1200 /* 1201 * Check for mid-tape short read error. 1202 * If found, skip rest of buffer and start with the next. 1203 */ 1204 if (!pipein && numtrec < ntrec && i > 0) { 1205 dprintf(stdout, "mid-media short read error.\n"); 1206 numtrec = ntrec; 1207 } 1208 /* 1209 * Handle partial block read. 1210 */ 1211 if (pipein && i == 0 && rd > 0) 1212 i = rd; 1213 else if (i > 0 && i != ntrec * TP_BSIZE) { 1214 if (pipein) { 1215 rd += i; 1216 cnt -= i; 1217 if (cnt > 0) 1218 goto getmore; 1219 i = rd; 1220 } else { 1221 /* 1222 * Short read. Process the blocks read. 1223 */ 1224 if (i % TP_BSIZE != 0) 1225 vprintf(stdout, 1226 "partial block read: %ld should be %ld\n", 1227 i, ntrec * TP_BSIZE); 1228 numtrec = i / TP_BSIZE; 1229 } 1230 } 1231 /* 1232 * Handle read error. 1233 */ 1234 if (i < 0) { 1235 fprintf(stderr, "Tape read error while "); 1236 switch (curfile.action) { 1237 default: 1238 fprintf(stderr, "trying to set up tape\n"); 1239 break; 1240 case UNKNOWN: 1241 fprintf(stderr, "trying to resynchronize\n"); 1242 break; 1243 case USING: 1244 fprintf(stderr, "restoring %s\n", curfile.name); 1245 break; 1246 case SKIP: 1247 fprintf(stderr, "skipping over inode %d\n", 1248 curfile.ino); 1249 break; 1250 } 1251 if (!yflag && !reply("continue")) 1252 done(1); 1253 i = ntrec * TP_BSIZE; 1254 memset(tapebuf, 0, i); 1255 #ifdef RRESTORE 1256 if (host) 1257 seek_failed = (rmtseek(i, 1) < 0); 1258 else 1259 #endif 1260 seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1); 1261 1262 if (seek_failed) { 1263 fprintf(stderr, 1264 "continuation failed: %s\n", strerror(errno)); 1265 done(1); 1266 } 1267 } 1268 /* 1269 * Handle end of tape. 1270 */ 1271 if (i == 0) { 1272 vprintf(stdout, "End-of-tape encountered\n"); 1273 if (!pipein) { 1274 newvol = volno + 1; 1275 volno = 0; 1276 numtrec = 0; 1277 getvol(newvol); 1278 readtape(buf); 1279 return; 1280 } 1281 if (rd % TP_BSIZE != 0) 1282 panic("partial block read: %d should be %d\n", 1283 rd, ntrec * TP_BSIZE); 1284 terminateinput(); 1285 memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); 1286 } 1287 if (oldnumtrec == 0) 1288 blkcnt = 0; 1289 else 1290 blkcnt -= oldnumtrec; 1291 memmove(buf, 1292 &tapebuf[(blkcnt++ * TP_BSIZE) + byteslide], (long)TP_BSIZE); 1293 blksread++; 1294 tapeaddr++; 1295 } 1296 1297 static void 1298 findtapeblksize(void) 1299 { 1300 long i; 1301 1302 for (i = 0; i < ntrec; i++) 1303 ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0; 1304 blkcnt = 0; 1305 #ifdef RRESTORE 1306 if (host) 1307 i = rmtread(tapebuf, ntrec * TP_BSIZE); 1308 else 1309 #endif 1310 i = read(mt, tapebuf, ntrec * TP_BSIZE); 1311 1312 if (i <= 0) { 1313 fprintf(stderr, "tape read error: %s\n", strerror(errno)); 1314 done(1); 1315 } 1316 if (i % TP_BSIZE != 0) { 1317 fprintf(stderr, "Tape block size (%ld) %s (%d)\n", 1318 i, "is not a multiple of dump block size", TP_BSIZE); 1319 done(1); 1320 } 1321 ntrec = i / TP_BSIZE; 1322 numtrec = ntrec; 1323 vprintf(stdout, "Tape block size is %ld\n", ntrec); 1324 } 1325 1326 void 1327 closemt(void) 1328 { 1329 1330 if (mt < 0) 1331 return; 1332 if (pipecmdin) { 1333 pclose(popenfp); 1334 popenfp = NULL; 1335 } else 1336 #ifdef RRESTORE 1337 if (host) 1338 rmtclose(); 1339 else 1340 #endif 1341 (void) close(mt); 1342 } 1343 1344 /* 1345 * Read the next block from the tape. 1346 * If it is not any valid header, return an error. 1347 */ 1348 static int 1349 gethead(struct s_spcl *buf) 1350 { 1351 long i; 1352 1353 readtape((char *)buf); 1354 if (buf->c_magic != FS_UFS2_MAGIC && buf->c_magic != NFS_MAGIC) { 1355 if (buf->c_magic == OFS_MAGIC) { 1356 fprintf(stderr, 1357 "Format of dump tape is too old. Must use\n"); 1358 fprintf(stderr, 1359 "a version of restore from before 2002.\n"); 1360 return (FAIL); 1361 } 1362 if (swabl(buf->c_magic) != FS_UFS2_MAGIC && 1363 buf->c_magic != NFS_MAGIC) { 1364 if (buf->c_magic == OFS_MAGIC) { 1365 fprintf(stderr, 1366 "Format of dump tape is too old. Must use\n"); 1367 fprintf(stderr, 1368 "a version of restore from before 2002.\n"); 1369 } 1370 return (FAIL); 1371 } 1372 if (!Bcvt) { 1373 vprintf(stdout, "Note: Doing Byte swapping\n"); 1374 Bcvt = 1; 1375 } 1376 } 1377 if (checksum((int *)buf) == FAIL) 1378 return (FAIL); 1379 if (_time64_to_time(buf->c_date) != dumpdate) 1380 fprintf(stderr, "Header with wrong dumpdate.\n"); 1381 if (Bcvt) { 1382 swabst((u_char *)"8l4s1q8l2q17l", (u_char *)buf); 1383 swabst((u_char *)"l",(u_char *) &buf->c_level); 1384 swabst((u_char *)"2l4q",(u_char *) &buf->c_flags); 1385 } 1386 readmapflag = 0; 1387 1388 switch (buf->c_type) { 1389 1390 case TS_CLRI: 1391 case TS_BITS: 1392 /* 1393 * Have to patch up missing information in bit map headers 1394 */ 1395 buf->c_inumber = 0; 1396 buf->c_size = buf->c_count * TP_BSIZE; 1397 if (buf->c_count > TP_NINDIR) 1398 readmapflag = 1; 1399 else 1400 for (i = 0; i < buf->c_count; i++) 1401 buf->c_addr[i]++; 1402 break; 1403 1404 case TS_TAPE: 1405 if (buf->c_magic == NFS_MAGIC) { 1406 if ((buf->c_flags & NFS_DR_NEWINODEFMT) == 0) 1407 oldinofmt = 1; 1408 buf->c_date = _time32_to_time(buf->c_old_date); 1409 buf->c_ddate = _time32_to_time(buf->c_old_ddate); 1410 buf->c_tapea = buf->c_old_tapea; 1411 buf->c_firstrec = buf->c_old_firstrec; 1412 } 1413 case TS_END: 1414 buf->c_inumber = 0; 1415 break; 1416 1417 case TS_INODE: 1418 /* 1419 * For old dump tapes, have to copy up old fields to 1420 * new locations. 1421 */ 1422 if (buf->c_magic == NFS_MAGIC) { 1423 buf->c_tapea = buf->c_old_tapea; 1424 buf->c_firstrec = buf->c_old_firstrec; 1425 buf->c_date = _time32_to_time(buf->c_old_date); 1426 buf->c_ddate = _time32_to_time(buf->c_old_ddate); 1427 buf->c_atime = _time32_to_time(buf->c_old_atime); 1428 buf->c_mtime = _time32_to_time(buf->c_old_mtime); 1429 } 1430 break; 1431 1432 case TS_ADDR: 1433 break; 1434 1435 default: 1436 panic("gethead: unknown inode type %d\n", buf->c_type); 1437 break; 1438 } 1439 /* 1440 * If we're restoring a filesystem with the old (FreeBSD 1) 1441 * format inodes, copy the uid/gid to the new location 1442 */ 1443 if (oldinofmt) { 1444 buf->c_uid = buf->c_spare1[1]; 1445 buf->c_gid = buf->c_spare1[2]; 1446 } 1447 buf->c_magic = FS_UFS2_MAGIC; 1448 tapeaddr = buf->c_tapea; 1449 if (dflag) 1450 accthdr(buf); 1451 return(GOOD); 1452 } 1453 1454 /* 1455 * Check that a header is where it belongs and predict the next header 1456 */ 1457 static void 1458 accthdr(struct s_spcl *header) 1459 { 1460 static ino_t previno = 0x7fffffff; 1461 static int prevtype; 1462 static long predict; 1463 long blks, i; 1464 1465 if (header->c_type == TS_TAPE) { 1466 fprintf(stderr, "Volume header "); 1467 if (header->c_firstrec) 1468 fprintf(stderr, "begins with record %qd", 1469 header->c_firstrec); 1470 fprintf(stderr, "\n"); 1471 previno = 0x7fffffff; 1472 return; 1473 } 1474 if (previno == 0x7fffffff) 1475 goto newcalc; 1476 switch (prevtype) { 1477 case TS_BITS: 1478 fprintf(stderr, "Dumped inodes map header"); 1479 break; 1480 case TS_CLRI: 1481 fprintf(stderr, "Used inodes map header"); 1482 break; 1483 case TS_INODE: 1484 fprintf(stderr, "File header, ino %d", previno); 1485 break; 1486 case TS_ADDR: 1487 fprintf(stderr, "File continuation header, ino %d", previno); 1488 break; 1489 case TS_END: 1490 fprintf(stderr, "End of tape header"); 1491 break; 1492 } 1493 if (predict != blksread - 1) 1494 fprintf(stderr, "; predicted %ld blocks, got %ld blocks", 1495 predict, blksread - 1); 1496 fprintf(stderr, "\n"); 1497 newcalc: 1498 blks = 0; 1499 if (header->c_type != TS_END) 1500 for (i = 0; i < header->c_count; i++) 1501 if (readmapflag || header->c_addr[i] != 0) 1502 blks++; 1503 predict = blks; 1504 blksread = 0; 1505 prevtype = header->c_type; 1506 previno = header->c_inumber; 1507 } 1508 1509 /* 1510 * Find an inode header. 1511 * Complain if had to skip. 1512 */ 1513 static void 1514 findinode(struct s_spcl *header) 1515 { 1516 static long skipcnt = 0; 1517 long i; 1518 char buf[TP_BSIZE]; 1519 int htype; 1520 1521 curfile.name = "<name unknown>"; 1522 curfile.action = UNKNOWN; 1523 curfile.mode = 0; 1524 curfile.ino = 0; 1525 do { 1526 htype = header->c_type; 1527 switch (htype) { 1528 1529 case TS_ADDR: 1530 /* 1531 * Skip up to the beginning of the next record 1532 */ 1533 for (i = 0; i < header->c_count; i++) 1534 if (header->c_addr[i]) 1535 readtape(buf); 1536 while (gethead(header) == FAIL || 1537 _time64_to_time(header->c_date) != dumpdate) { 1538 skipcnt++; 1539 if (Dflag) { 1540 byteslide++; 1541 if (byteslide < TP_BSIZE) { 1542 blkcnt--; 1543 blksread--; 1544 } else 1545 byteslide = 0; 1546 } 1547 } 1548 break; 1549 1550 case TS_INODE: 1551 curfile.mode = header->c_mode; 1552 curfile.uid = header->c_uid; 1553 curfile.gid = header->c_gid; 1554 curfile.file_flags = header->c_file_flags; 1555 curfile.rdev = header->c_rdev; 1556 curfile.atime_sec = header->c_atime; 1557 curfile.atime_nsec = header->c_atimensec; 1558 curfile.mtime_sec = header->c_mtime; 1559 curfile.mtime_nsec = header->c_mtimensec; 1560 curfile.birthtime_sec = header->c_birthtime; 1561 curfile.birthtime_nsec = header->c_birthtimensec; 1562 curfile.extsize = header->c_extsize; 1563 curfile.size = header->c_size; 1564 curfile.ino = header->c_inumber; 1565 break; 1566 1567 case TS_END: 1568 /* If we missed some tapes, get another volume. */ 1569 if (tapesread & (tapesread + 1)) { 1570 getvol(0); 1571 continue; 1572 } 1573 curfile.ino = maxino; 1574 break; 1575 1576 case TS_CLRI: 1577 curfile.name = "<file removal list>"; 1578 break; 1579 1580 case TS_BITS: 1581 curfile.name = "<file dump list>"; 1582 break; 1583 1584 case TS_TAPE: 1585 if (Dflag) 1586 fprintf(stderr, "unexpected tape header\n"); 1587 else 1588 panic("unexpected tape header\n"); 1589 1590 default: 1591 if (Dflag) 1592 fprintf(stderr, "unknown tape header type %d\n", 1593 spcl.c_type); 1594 else 1595 panic("unknown tape header type %d\n", 1596 spcl.c_type); 1597 while (gethead(header) == FAIL || 1598 _time64_to_time(header->c_date) != dumpdate) { 1599 skipcnt++; 1600 if (Dflag) { 1601 byteslide++; 1602 if (byteslide < TP_BSIZE) { 1603 blkcnt--; 1604 blksread--; 1605 } else 1606 byteslide = 0; 1607 } 1608 } 1609 1610 } 1611 } while (htype == TS_ADDR); 1612 if (skipcnt > 0) 1613 fprintf(stderr, "resync restore, skipped %ld %s\n", 1614 skipcnt, Dflag ? "bytes" : "blocks"); 1615 skipcnt = 0; 1616 } 1617 1618 static int 1619 checksum(int *buf) 1620 { 1621 int i, j; 1622 1623 j = sizeof(union u_spcl) / sizeof(int); 1624 i = 0; 1625 if (!Bcvt) { 1626 do 1627 i += *buf++; 1628 while (--j); 1629 } else { 1630 /* What happens if we want to read restore tapes 1631 for a 16bit int machine??? */ 1632 do 1633 i += swabl(*buf++); 1634 while (--j); 1635 } 1636 1637 if (i != CHECKSUM) { 1638 fprintf(stderr, "Checksum error %o, inode %d file %s\n", i, 1639 curfile.ino, curfile.name); 1640 return(FAIL); 1641 } 1642 return(GOOD); 1643 } 1644 1645 #ifdef RRESTORE 1646 #include <stdarg.h> 1647 1648 void 1649 msg(const char *fmt, ...) 1650 { 1651 va_list ap; 1652 va_start(ap, fmt); 1653 (void)vfprintf(stderr, fmt, ap); 1654 va_end(ap); 1655 } 1656 #endif /* RRESTORE */ 1657 1658 static u_char * 1659 swabshort(u_char *sp, int n) 1660 { 1661 char c; 1662 1663 while (--n >= 0) { 1664 c = sp[0]; sp[0] = sp[1]; sp[1] = c; 1665 sp += 2; 1666 } 1667 return (sp); 1668 } 1669 1670 static u_char * 1671 swablong(u_char *sp, int n) 1672 { 1673 char c; 1674 1675 while (--n >= 0) { 1676 c = sp[0]; sp[0] = sp[3]; sp[3] = c; 1677 c = sp[2]; sp[2] = sp[1]; sp[1] = c; 1678 sp += 4; 1679 } 1680 return (sp); 1681 } 1682 1683 static u_char * 1684 swabquad(u_char *sp, int n) 1685 { 1686 char c; 1687 1688 while (--n >= 0) { 1689 c = sp[0]; sp[0] = sp[7]; sp[7] = c; 1690 c = sp[1]; sp[1] = sp[6]; sp[6] = c; 1691 c = sp[2]; sp[2] = sp[5]; sp[5] = c; 1692 c = sp[3]; sp[3] = sp[4]; sp[4] = c; 1693 sp += 8; 1694 } 1695 return (sp); 1696 } 1697 1698 void 1699 swabst(u_char *cp, u_char *sp) 1700 { 1701 int n = 0; 1702 1703 while (*cp) { 1704 switch (*cp) { 1705 case '0': case '1': case '2': case '3': case '4': 1706 case '5': case '6': case '7': case '8': case '9': 1707 n = (n * 10) + (*cp++ - '0'); 1708 continue; 1709 1710 case 's': case 'w': case 'h': 1711 if (n == 0) 1712 n = 1; 1713 sp = swabshort(sp, n); 1714 break; 1715 1716 case 'l': 1717 if (n == 0) 1718 n = 1; 1719 sp = swablong(sp, n); 1720 break; 1721 1722 case 'q': 1723 if (n == 0) 1724 n = 1; 1725 sp = swabquad(sp, n); 1726 break; 1727 1728 case 'b': 1729 if (n == 0) 1730 n = 1; 1731 sp += n; 1732 break; 1733 1734 default: 1735 fprintf(stderr, "Unknown conversion character: %c\n", 1736 *cp); 1737 done(0); 1738 break; 1739 } 1740 cp++; 1741 n = 0; 1742 } 1743 } 1744 1745 static u_long 1746 swabl(u_long x) 1747 { 1748 swabst((u_char *)"l", (u_char *)&x); 1749 return (x); 1750 } 1751