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