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