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