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