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