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