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