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