1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 8 /* All Rights Reserved */ 9 10 /* 11 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 12 * Use is subject to license terms. 13 */ 14 15 #pragma ident "%Z%%M% %I% %E% SMI" 16 17 #include <setjmp.h> 18 #include "restore.h" 19 #include <byteorder.h> 20 #include <rmt.h> 21 #include <sys/mtio.h> 22 #include <utime.h> 23 #include <sys/errno.h> 24 #include <sys/fdio.h> 25 #include <sys/sysmacros.h> /* for expdev */ 26 #include <assert.h> 27 #include <limits.h> 28 #include <priv_utils.h> 29 30 #define MAXINO 65535 /* KLUDGE */ 31 32 #define MAXTAPES 128 33 34 static size_t fssize = MAXBSIZE; /* preferred size of writes to filesystem */ 35 int mt = -1; 36 static int continuemap = 0; 37 char magtape[BUFSIZ]; 38 int pipein = 0; 39 char *host; /* used in dumprmt.c */ 40 daddr32_t rec_position; 41 static char *archivefile; /* used in metamucil.c */ 42 static int bct; /* block # index into tape record buffer */ 43 static int numtrec; /* # of logical blocks in current tape record */ 44 static char *tbf = NULL; 45 static size_t tbfsize = 0; 46 static int recsread; 47 static union u_spcl endoftapemark; 48 static struct s_spcl dumpinfo; 49 static long blksread; /* # of logical blocks actually read/touched */ 50 static long tapea; /* current logical block # on tape */ 51 static uchar_t tapesread[MAXTAPES]; 52 static jmp_buf restart; 53 static int gettingfile = 0; /* restart has a valid frame */ 54 static int ofile; 55 static char *map, *beginmap; 56 static char *endmap; 57 static char lnkbuf[MAXPATHLEN + 2]; 58 static int pathlen; 59 static int inodeinfo; /* Have starting volume information */ 60 static int hostinfo; /* Have dump host information */ 61 62 #ifdef __STDC__ 63 static int autoload_tape(void); 64 static void setdumpnum(void); 65 static void metacheck(struct s_spcl *); 66 static void xtrmeta(char *, size_t); 67 static void metaskip(char *, size_t); 68 static void xtrfile(char *, size_t); 69 static void xtrskip(char *, size_t); 70 static void xtrlnkfile(char *, size_t); 71 static void xtrlnkskip(char *, size_t); 72 static void xtrmap(char *, size_t); 73 static void xtrmapskip(char *, size_t); 74 static void readtape(char *); 75 static int checkvol(struct s_spcl *, int); 76 static void accthdr(struct s_spcl *); 77 static int ishead(struct s_spcl *); 78 static int checktype(struct s_spcl *, int); 79 static void metaset(char *name); 80 #else 81 static int autoload_tape(); 82 static void setdumpnum(); 83 static void metacheck(); 84 static void xtrmeta(); 85 static void metaskip(); 86 static void xtrfile(); 87 static void xtrskip(); 88 static void xtrlnkfile(); 89 static void xtrlnkskip(); 90 static void xtrmap(); 91 static void xtrmapskip(); 92 static void readtape(); 93 static int checkvol(); 94 static void accthdr(); 95 static int ishead(); 96 static checktype(); 97 static void metaset(); 98 #endif 99 100 /* 101 * Set up an input source 102 */ 103 void 104 setinput(char *source, char *archive) 105 { 106 107 flsht(); 108 archivefile = archive; 109 if (bflag == 0) { 110 ntrec = ((CARTRIDGETREC > HIGHDENSITYTREC) ? 111 (NTREC > CARTRIDGETREC ? NTREC : CARTRIDGETREC) : 112 (NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC)); 113 saved_ntrec = (ntrec * (tp_bsize/DEV_BSIZE)); 114 } 115 newtapebuf(ntrec); 116 terminal = stdin; 117 118 if (source == NULL) { 119 /* A can't-happen */ 120 (void) fprintf(stderr, 121 gettext("Internal consistency check failed.\n")); 122 done(1); 123 } 124 125 if (strchr(source, ':')) { 126 char *tape; 127 128 host = source; 129 tape = strchr(host, ':'); 130 *tape++ = '\0'; 131 if (strlen(tape) > (sizeof (magtape) - 1)) { 132 (void) fprintf(stderr, gettext("Tape name too long\n")); 133 done(1); 134 } 135 (void) strcpy(magtape, tape); 136 if (rmthost(host, ntrec) == 0) 137 done(1); 138 } else { 139 if (strlen(source) > (sizeof (magtape) - 1)) { 140 (void) fprintf(stderr, gettext("Tape name too long\n")); 141 done(1); 142 } 143 /* Not remote, no need for privileges */ 144 __priv_relinquish(); 145 host = NULL; 146 if (strcmp(source, "-") == 0) { 147 /* 148 * Since input is coming from a pipe we must establish 149 * our own connection to the terminal. 150 */ 151 terminal = fopen("/dev/tty", "r"); 152 if (terminal == NULL) { 153 int saverr = errno; 154 char *msg = 155 gettext("Cannot open(\"/dev/tty\")"); 156 errno = saverr; 157 perror(msg); 158 terminal = fopen("/dev/null", "r"); 159 if (terminal == NULL) { 160 saverr = errno; 161 msg = gettext( 162 "Cannot open(\"/dev/null\")"); 163 errno = saverr; 164 perror(msg); 165 done(1); 166 } 167 } 168 pipein++; 169 if (archive) { 170 (void) fprintf(stderr, gettext( 171 "Cannot specify an archive file when reading from a pipe\n")); 172 done(1); 173 } 174 } 175 (void) strcpy(magtape, source); 176 } 177 } 178 179 void 180 newtapebuf(size_t size) 181 { 182 size_t nsize; 183 184 nsize = size * tp_bsize; 185 ntrec = size; 186 if (nsize <= tbfsize) 187 return; 188 if (tbf != NULL) 189 free(tbf); 190 tbf = (char *)malloc(nsize); 191 if (tbf == NULL) { 192 (void) fprintf(stderr, 193 gettext("Cannot allocate space for buffer\n")); 194 done(1); 195 } 196 tbfsize = nsize; 197 } 198 199 /* 200 * Verify that the tape drive can be accessed and 201 * that it actually is a dump tape. 202 */ 203 void 204 #ifdef __STDC__ 205 setup(void) 206 #else 207 setup() 208 #endif 209 { 210 int i, j; 211 int32_t *ip; 212 struct stat stbuf; 213 size_t mapsize; 214 char *syment = RESTORESYMTABLE; 215 216 vprintf(stdout, gettext("Verify volume and initialize maps\n")); 217 if (archivefile) { 218 mt = open(archivefile, O_RDONLY|O_LARGEFILE); 219 if (mt < 0) { 220 perror(archivefile); 221 done(1); 222 } 223 volno = 0; 224 } else if (host) { 225 if ((mt = rmtopen(magtape, O_RDONLY)) < 0) { 226 perror(magtape); 227 done(1); 228 } 229 volno = 1; 230 } else { 231 if (pipein) 232 mt = 0; 233 else if ((mt = open(magtape, O_RDONLY|O_LARGEFILE)) < 0) { 234 perror(magtape); 235 done(1); 236 } 237 volno = 1; 238 } 239 setdumpnum(); 240 flsht(); 241 if (!pipein && !bflag) 242 if (archivefile) 243 findtapeblksize(ARCHIVE_FILE); 244 else 245 findtapeblksize(TAPE_FILE); 246 if (bflag == 1) { 247 tape_rec_size = saved_ntrec * DEV_BSIZE; 248 } 249 250 /* 251 * Get the first header. If c_magic is NOT NFS_MAGIC or if 252 * the checksum is in error, it will fail. The magic could then 253 * be either OFS_MAGIC or MTB_MAGIC. If OFS_MAGIC, assume we 254 * have an old dump, and try to convert it. If it is MTB_MAGIC, we 255 * procees this after. 256 */ 257 if ((gethead(&spcl) == FAIL) && (spcl.c_magic != MTB_MAGIC)) { 258 bct--; /* push back this block */ 259 blksread--; 260 tapea--; 261 cvtflag++; 262 if (gethead(&spcl) == FAIL) { 263 (void) fprintf(stderr, 264 gettext("Volume is not in dump format\n")); 265 done(1); 266 } 267 (void) fprintf(stderr, 268 gettext("Converting to new file system format.\n")); 269 } 270 /* 271 * The above gethead will have failed if the magic is 272 * MTB_MAGIC. If that is true, we need to adjust tp_bsize. 273 * We have assumed to this time that tp_bsize was 1024, if 274 * this is a newer dump, get the real tp_bsize from the header, 275 * and recalculate ntrec, numtrec. 276 */ 277 if (spcl.c_magic == MTB_MAGIC) { 278 tp_bsize = spcl.c_tpbsize; 279 if ((tp_bsize % TP_BSIZE_MIN != 0) || 280 (tp_bsize > TP_BSIZE_MAX)) { 281 (void) fprintf(stderr, 282 gettext("Volume is not in dump format\n")); 283 done(1); 284 } 285 ntrec = (tape_rec_size/tp_bsize); 286 numtrec = ntrec; 287 newtapebuf(ntrec); 288 bct--; /* push back this block */ 289 blksread--; 290 tapea--; 291 /* we have to re-do this in case checksum is wrong */ 292 if (gethead(&spcl) == FAIL) { 293 (void) fprintf(stderr, 294 gettext("Volume is not in dump format\n")); 295 done(1); 296 } 297 } 298 if (vflag) 299 byteorder_banner(byteorder, stdout); 300 if (pipein) { 301 endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : 302 ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC); 303 endoftapemark.s_spcl.c_type = TS_END; 304 305 /* 306 * include this since the `resync' loop in findinode 307 * expects to find a header with the c_date field 308 * filled in. 309 */ 310 endoftapemark.s_spcl.c_date = spcl.c_date; 311 312 ip = (int32_t *)&endoftapemark; 313 /*LINTED [assertion always true]*/ 314 assert((sizeof (endoftapemark) % sizeof (int32_t)) == 0); 315 j = sizeof (endoftapemark) / sizeof (int32_t); 316 i = 0; 317 do 318 i += *ip++; 319 while (--j); 320 endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 321 } 322 if (vflag && command != 't') 323 printdumpinfo(); 324 dumptime = spcl.c_ddate; 325 dumpdate = spcl.c_date; 326 if (stat(".", &stbuf) < 0) { 327 perror(gettext("cannot stat .")); 328 done(1); 329 } 330 if (stbuf.st_blksize >= tp_bsize && stbuf.st_blksize <= MAXBSIZE) { 331 /* LINTED: value fits in a size_t */ 332 fssize = stbuf.st_blksize; 333 } 334 if (((fssize - 1) & fssize) != 0) { 335 (void) fprintf(stderr, 336 gettext("bad filesystem block size %d\n"), fssize); 337 done(1); 338 } 339 if (checkvol(&spcl, 1) == FAIL) { 340 (void) fprintf(stderr, 341 gettext("This is not volume 1 of the dump\n")); 342 done(1); 343 } 344 if (readhdr(&spcl) == FAIL) 345 panic(gettext("no header after volume mark!\n")); 346 347 findinode(&spcl); /* sets curfile, resyncs the tape if need be */ 348 if (checktype(&spcl, TS_CLRI) == FAIL) { 349 (void) fprintf(stderr, 350 gettext("Cannot find file removal list\n")); 351 done(1); 352 } 353 maxino = (unsigned)((spcl.c_count * tp_bsize * NBBY) + 1); 354 dprintf(stdout, "maxino = %lu\n", maxino); 355 /* 356 * Allocate space for at least MAXINO inodes to allow us 357 * to restore partial dump tapes written before dump was 358 * fixed to write out the entire inode map. 359 */ 360 if (maxino > ULONG_MAX) { 361 (void) fprintf(stderr, 362 gettext("file system too large\n")); 363 done(1); 364 } 365 /* LINTED maxino size-checked above */ 366 mapsize = (size_t)d_howmany(maxino > MAXINO ? maxino : MAXINO, NBBY); 367 beginmap = map = calloc((size_t)1, mapsize); 368 if (map == (char *)NIL) { 369 (void) fprintf(stderr, 370 gettext("no memory for file removal list\n")); 371 done(1); 372 } 373 endmap = map + mapsize; 374 clrimap = map; 375 curfile.action = USING; 376 continuemap = 1; 377 getfile(xtrmap, xtrmapskip); 378 if (MAXINO > maxino) 379 maxino = MAXINO; 380 if (checktype(&spcl, TS_BITS) == FAIL) { 381 /* if we have TS_CLRI then no TS_BITS then a TS_END */ 382 /* then we have an empty dump file */ 383 if (gethead(&spcl) == GOOD && checktype(&spcl, TS_END) == GOOD) 384 { 385 if ((command == 'r') || (command == 'R')) { 386 initsymtable(syment); 387 dumpsymtable(syment, volno); 388 } 389 done(0); 390 } 391 /* otherwise we have an error */ 392 (void) fprintf(stderr, gettext("Cannot find file dump list\n")); 393 done(1); 394 } 395 /* LINTED maxino size-checked above */ 396 mapsize = (size_t)d_howmany(maxino, NBBY); 397 beginmap = map = calloc((size_t)1, mapsize); 398 if (map == (char *)NULL) { 399 (void) fprintf(stderr, 400 gettext("no memory for file dump list\n")); 401 done(1); 402 } 403 endmap = map + mapsize; 404 dumpmap = map; 405 curfile.action = USING; 406 continuemap = 1; 407 getfile(xtrmap, xtrmapskip); 408 continuemap = 0; 409 } 410 411 /* 412 * Initialize fssize variable for 'R' command to work. 413 */ 414 void 415 #ifdef __STDC__ 416 setupR(void) 417 #else 418 setupR() 419 #endif 420 { 421 struct stat stbuf; 422 423 if (stat(".", &stbuf) < 0) { 424 perror(gettext("cannot stat .")); 425 done(1); 426 } 427 if (stbuf.st_blksize >= tp_bsize && stbuf.st_blksize <= MAXBSIZE) { 428 /* LINTED: value fits in a size_t */ 429 fssize = stbuf.st_blksize; 430 } 431 if (((fssize - 1) & fssize) != 0) { 432 (void) fprintf(stderr, 433 gettext("bad filesystem block size %d\n"), fssize); 434 done(1); 435 } 436 } 437 438 /* 439 * Prompt user to load a new dump volume. 440 * "Nextvol" is the next suggested volume to use. 441 * This suggested volume is enforced when doing full 442 * or incremental restores, but can be overrridden by 443 * the user when only extracting a subset of the files. 444 * 445 * first_time is used with archive files and can have 1 of 3 states: 446 * FT_STATE_1 Tape has not been read yet 447 * FT_STATE_2 Tape has been read but not positioned past directory 448 * information 449 * FT_STATE_3 Tape has been read and is reading file information 450 */ 451 #define FT_STATE_1 1 452 #define FT_STATE_2 2 453 #define FT_STATE_3 3 454 455 void 456 getvol(int nextvol) 457 { 458 int newvol; 459 long savecnt, savetapea, wantnext; 460 long i; 461 union u_spcl tmpspcl; 462 #define tmpbuf tmpspcl.s_spcl 463 char buf[TP_BSIZE_MAX]; 464 static int first_time = FT_STATE_1; 465 466 if (tbf == NULL) { 467 (void) fprintf(stderr, gettext( 468 "Internal consistency failure in getvol: tbf is NULL\n")); 469 done(1); 470 } 471 472 if (nextvol == 1) { 473 for (i = 0; i < MAXTAPES; i++) 474 tapesread[i] = 0; 475 gettingfile = 0; 476 } 477 if (pipein) { 478 if (nextvol != 1) 479 panic(gettext("changing volumes on pipe input\n")); 480 if (volno == 1) 481 return; 482 goto gethdr; 483 } 484 savecnt = blksread; /* ignore volume verification tape i/o */ 485 savetapea = tapea; 486 again: 487 if (pipein) 488 done(1); /* pipes do not get a second chance */ 489 if (command == 'R' || command == 'r' || curfile.action != SKIP) { 490 wantnext = 1; 491 newvol = nextvol; 492 } else { 493 wantnext = 0; 494 newvol = 0; 495 } 496 497 if (autoload) { 498 if ((volno == 1) && (nextvol == 1)) { 499 tapesread[volno-1]++; 500 return; 501 } 502 if (autoload_tape()) { 503 goto gethdr; 504 } 505 } 506 507 while (newvol <= 0) { 508 int n = 0; 509 510 for (i = 0; i < MAXTAPES; i++) 511 if (tapesread[i]) 512 n++; 513 if (n == 0) { 514 (void) fprintf(stderr, "%s", gettext( 515 "You have not read any volumes yet.\n\ 516 Unless you know which volume your file(s) are on you should start\n\ 517 with the last volume and work towards the first.\n")); 518 } else { 519 (void) fprintf(stderr, 520 gettext("You have read volumes")); 521 (void) strcpy(tbf, ": "); 522 for (i = 0; i < MAXTAPES; i++) 523 if (tapesread[i]) { 524 (void) fprintf(stderr, "%s%ld", 525 tbf, i+1); 526 (void) strcpy(tbf, ", "); 527 } 528 (void) fprintf(stderr, "\n"); 529 } 530 do { 531 (void) fprintf(stderr, 532 gettext("Specify next volume #: ")); 533 (void) fflush(stderr); 534 /* LINTED tbfsize is limited to a few MB */ 535 (void) fgets(tbf, (int)tbfsize, terminal); 536 } while (!feof(terminal) && tbf[0] == '\n'); 537 if (feof(terminal)) 538 done(1); 539 newvol = atoi(tbf); 540 if (newvol <= 0) { 541 (void) fprintf(stderr, gettext( 542 "Volume numbers are positive numerics\n")); 543 } 544 if (newvol > MAXTAPES) { 545 (void) fprintf(stderr, gettext( 546 "This program can only deal with %d volumes\n"), 547 MAXTAPES); 548 newvol = 0; 549 } 550 } 551 if (newvol == volno) { 552 tapesread[volno-1]++; 553 return; 554 } 555 closemt(ALLOW_OFFLINE); 556 /* 557 * XXX: if we are switching devices, we should probably try 558 * the device once without prompting to enable unattended 559 * operation. 560 */ 561 if (host) 562 (void) fprintf(stderr, gettext( 563 "Mount volume %d\nthen enter volume name on host %s (default: %s) "), 564 newvol, host, magtape); 565 else 566 (void) fprintf(stderr, gettext( 567 "Mount volume %d\nthen enter volume name (default: %s) "), 568 newvol, magtape); 569 (void) fflush(stderr); 570 /* LINTED tbfsize is limited to a few MB */ 571 (void) fgets(tbf, (int)tbfsize, terminal); 572 if (feof(terminal)) 573 done(1); 574 /* 575 * XXX We don't allow rotating among tape hosts, just drives. 576 */ 577 if (tbf[0] != '\n') { 578 (void) strncpy(magtape, tbf, sizeof (magtape)); 579 magtape[sizeof (magtape) - 1] = '\0'; 580 /* LINTED unsigned -> signed conversion ok */ 581 i = (int)strlen(magtape); 582 if (magtape[i - 1] == '\n') 583 magtape[i - 1] = '\0'; 584 } 585 if ((host != NULL && (mt = rmtopen(magtape, O_RDONLY)) == -1) || 586 (host == NULL && 587 (mt = open(magtape, O_RDONLY|O_LARGEFILE)) == -1)) { 588 int error = errno; 589 (void) fprintf(stderr, gettext("Cannot open %s: %s\n"), 590 magtape, strerror(error)); 591 volno = -1; 592 goto again; 593 } 594 gethdr: 595 volno = newvol; 596 setdumpnum(); 597 flsht(); 598 if (!pipein && !bflag && archivefile && (first_time == FT_STATE_1)) { 599 first_time = FT_STATE_2; 600 findtapeblksize(TAPE_FILE); 601 } 602 if (readhdr(&tmpbuf) == FAIL) { 603 (void) fprintf(stderr, 604 gettext("volume is not in dump format\n")); 605 volno = 0; 606 goto again; 607 } 608 if (checkvol(&tmpbuf, volno) == FAIL) { 609 (void) fprintf(stderr, gettext("Wrong volume (%d)\n"), 610 tmpbuf.c_volume); 611 volno = 0; 612 goto again; 613 } 614 615 if (((time_t)(tmpbuf.c_date) != dumpdate) || 616 ((time_t)(tmpbuf.c_ddate) != dumptime)) { 617 char *tmp_ct; 618 time_t lc_date = (time_t)tmpbuf.c_date; 619 620 /* 621 * This is used to save the return value from lctime(), 622 * since that's volatile across lctime() invocations. 623 */ 624 tmp_ct = strdup(lctime(&lc_date)); 625 if (tmp_ct == (char *)0) { 626 (void) fprintf(stderr, gettext( 627 "Cannot allocate space for time string\n")); 628 done(1); 629 } 630 631 (void) fprintf(stderr, 632 gettext("Wrong dump date\n\tgot: %s\twanted: %s"), 633 tmp_ct, lctime(&dumpdate)); 634 volno = 0; 635 free(tmp_ct); 636 goto again; 637 } 638 tapesread[volno-1]++; 639 blksread = savecnt; 640 tapea = savetapea; 641 /* 642 * If continuing from the previous volume, skip over any 643 * blocks read already at the end of the previous volume. 644 * 645 * If coming to this volume at random, skip to the beginning 646 * of the next record. 647 */ 648 if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) { 649 if (!wantnext) { 650 if (archivefile && first_time == FT_STATE_2) { 651 first_time = FT_STATE_3; 652 } 653 recsread = tmpbuf.c_firstrec; 654 tapea = tmpbuf.c_tapea; 655 dprintf(stdout, 656 "restore skipping %d records\n", 657 tmpbuf.c_count); 658 for (i = tmpbuf.c_count; i > 0; i--) 659 readtape(buf); 660 } else if (tmpbuf.c_firstrec != 0) { 661 savecnt = blksread; 662 savetapea = tapea; 663 664 if (archivefile && first_time == FT_STATE_2) { 665 /* 666 * subtract 2, 1 for archive file's TS_END 667 * and 1 for tape's TS_TAPE 668 */ 669 first_time = FT_STATE_3; 670 i = tapea - tmpbuf.c_tapea - 2; 671 } else { 672 i = tapea - tmpbuf.c_tapea; 673 } 674 if (i > 0) 675 dprintf(stdout, gettext( 676 "restore skipping %d duplicate records\n"), 677 i); 678 else if (i < 0) 679 dprintf(stdout, gettext( 680 "restore duplicate record botch (%d)\n"), 681 i); 682 while (--i >= 0) 683 readtape(buf); 684 blksread = savecnt; 685 tapea = savetapea + 1; /* <= (void) gethead() below */ 686 } 687 } 688 if (curfile.action == USING) { 689 if (volno == 1) 690 panic(gettext("active file into volume 1\n")); 691 return; 692 } 693 (void) gethead(&spcl); 694 findinode(&spcl); /* do we always restart files in full? */ 695 if (gettingfile) { /* i.e. will we lose metadata? */ 696 gettingfile = 0; 697 longjmp(restart, 1); /* will this set f1 & f2? */ 698 } 699 } 700 701 /* 702 * handle multiple dumps per tape by skipping forward to the 703 * appropriate one. Note we don't use absolute positioning, 704 * as that may take a very long time. 705 */ 706 static void 707 #ifdef __STDC__ 708 setdumpnum(void) 709 #else 710 setdumpnum() 711 #endif 712 { 713 struct mtop tcom; 714 int retval; 715 716 if (dumpnum == 1 || volno != 1) 717 return; 718 if (pipein) { 719 (void) fprintf(stderr, 720 gettext("Cannot have multiple dumps on pipe input\n")); 721 done(1); 722 } 723 tcom.mt_op = MTFSF; 724 tcom.mt_count = dumpnum - 1; 725 if (host) 726 retval = rmtioctl(MTFSF, dumpnum - 1); 727 else 728 retval = ioctl(mt, (int)MTIOCTOP, (char *)&tcom); 729 if (retval < 0) 730 perror("ioctl MTFSF"); 731 } 732 733 void 734 #ifdef __STDC__ 735 printdumpinfo(void) 736 #else 737 printdumpinfo() 738 #endif 739 { 740 int i; 741 time_t date; 742 static char *epoch = NULL; 743 744 if (epoch == NULL) { 745 epoch = strdup(gettext("the epoch\n")); 746 if (epoch == NULL) { 747 (void) fprintf(stderr, gettext("Out of memory\n")); 748 return; 749 } 750 } 751 752 date = (time_t)dumpinfo.c_date; 753 (void) fprintf(stdout, 754 gettext("Dump date: %s"), lctime(&date)); 755 756 date = (time_t)dumpinfo.c_ddate; 757 (void) fprintf(stdout, gettext("Dumped from: %s"), 758 (dumpinfo.c_ddate == 0) ? epoch : lctime(&date)); 759 if (hostinfo) { 760 (void) fprintf(stdout, 761 gettext("Level %d dump of %s on %.*s:%s\n"), 762 dumpinfo.c_level, dumpinfo.c_filesys, 763 sizeof (dumpinfo.c_host), dumpinfo.c_host, dumpinfo.c_dev); 764 (void) fprintf(stdout, 765 gettext("Label: %.*s\n"), 766 sizeof (dumpinfo.c_label), dumpinfo.c_label); 767 } 768 if (inodeinfo) { 769 (void) fprintf(stdout, 770 gettext("Starting inode numbers by volume:\n")); 771 for (i = 1; i <= dumpinfo.c_volume; i++) 772 (void) fprintf(stdout, gettext("\tVolume %d: %6d\n"), 773 i, dumpinfo.c_inos[i]); 774 } 775 } 776 777 int 778 extractfile(char *name) 779 { 780 static int complained_chown = 0; 781 static int complained_lchown = 0; 782 static int complained_chmod = 0; 783 static int complained_utime = 0; 784 static int complained_mknod = 0; 785 mode_t mode; 786 time_t timep[2]; 787 struct entry *ep; 788 uid_t uid; 789 gid_t gid; 790 char *errmsg; 791 int result, saverr; 792 dev_t full_dev; 793 int dfd; 794 char *rname; 795 796 curfile.name = name; 797 curfile.action = USING; 798 timep[0] = (time_t)curfile.dip->di_atime; 799 timep[1] = (time_t)curfile.dip->di_mtime; 800 mode = curfile.dip->di_mode; 801 802 uid = curfile.dip->di_suid == UID_LONG ? 803 curfile.dip->di_uid : (uid_t)curfile.dip->di_suid; 804 gid = curfile.dip->di_sgid == GID_LONG ? 805 curfile.dip->di_gid : (gid_t)curfile.dip->di_sgid; 806 807 resolve(name, &dfd, &rname); 808 if (dfd != AT_FDCWD) { 809 if (fchdir(dfd) < 0) { 810 saverr = errno; 811 (void) fprintf(stderr, gettext( 812 "%s: unable to set attribute context: %s\n"), 813 rname, strerror(saverr)); 814 skipfile(); 815 (void) close(dfd); 816 return (FAIL); 817 } 818 } 819 820 switch (mode & IFMT) { 821 822 default: 823 (void) fprintf(stderr, gettext("%s: unknown file mode 0%lo\n"), 824 rname, (ulong_t)(mode&IFMT)); 825 skipfile(); 826 result = FAIL; 827 break; 828 829 case IFSOCK: 830 vprintf(stdout, gettext("skipped socket %s\n"), rname); 831 skipfile(); 832 result = GOOD; 833 break; 834 835 case IFDIR: 836 if (mflag) { 837 ep = lookupname(name); 838 if (ep == NIL || ep->e_flags & EXTRACT) { 839 panic(gettext( 840 "directory %s was not restored\n"), 841 rname); 842 skipfile(); 843 result = FAIL; 844 break; 845 } 846 skipfile(); 847 result = GOOD; 848 break; 849 } 850 vprintf(stdout, gettext("extract file %s\n"), rname); 851 result = genliteraldir(rname, curfile.ino); 852 break; 853 854 case IFLNK: 855 lnkbuf[0] = '\0'; 856 pathlen = 0; 857 getfile(xtrlnkfile, xtrlnkskip); 858 if (pathlen == 0) { 859 vprintf(stdout, gettext( 860 "%s: zero length symbolic link (ignored)\n"), 861 rname); 862 result = GOOD; 863 break; 864 } 865 if ((result = lf_linkit(lnkbuf, rname, SYMLINK)) != GOOD) 866 break; 867 868 /* 1254700: set uid/gid (previously missing) */ 869 if (lchown(rname, uid, gid) < 0 && !complained_lchown) { 870 /* Just a warning */ 871 saverr = errno; 872 errmsg = gettext( 873 "Unable to restore ownership of symlink %s: %s\n"); 874 (void) fprintf(stderr, errmsg, 875 rname, strerror(saverr)); 876 (void) fprintf(stderr, gettext( 877 "Additional such failures will be ignored.\n")); 878 complained_lchown = 1; 879 } 880 metaset(rname); 881 result = GOOD; 882 break; 883 884 case IFCHR: 885 case IFBLK: 886 case IFIFO: 887 vprintf(stdout, gettext("extract special file %s\n"), rname); 888 /* put device rdev into dev_t expanded format */ 889 /* XXX does this always do the right thing? */ 890 /* XXX does dump do the right thing? */ 891 if (((curfile.dip->di_ordev & 0xFFFF0000) == 0) || 892 ((curfile.dip->di_ordev & 0xFFFF0000) == 0xFFFF0000)) { 893 full_dev = expdev((unsigned)(curfile.dip->di_ordev)); 894 } else { 895 /* LINTED sign extension ok */ 896 full_dev = (unsigned)(curfile.dip->di_ordev); 897 } 898 899 if (mknod(rname, mode, full_dev) < 0) { 900 struct stat64 s[1]; 901 902 saverr = errno; 903 if ((stat64(rname, s)) || 904 ((s->st_mode & S_IFMT) != (mode & S_IFMT)) || 905 (s->st_rdev != full_dev)) { 906 if (saverr != EPERM || !complained_mknod) { 907 (void) fprintf(stderr, "%s: ", rname); 908 (void) fflush(stderr); 909 errno = saverr; 910 perror(gettext( 911 "cannot create special file")); 912 if (saverr == EPERM) { 913 (void) fprintf(stderr, gettext( 914 "Additional such failures will be ignored.\n")); 915 complained_mknod = 1; 916 } 917 } 918 skipfile(); 919 result = FAIL; 920 break; 921 } 922 } 923 if (chown(rname, uid, gid) < 0 && !complained_chown) { 924 /* Just a warning */ 925 saverr = errno; 926 errmsg = gettext( 927 "Unable to restore ownership of %s: %s\n"); 928 (void) fprintf(stderr, errmsg, 929 rname, strerror(saverr)); 930 (void) fprintf(stderr, gettext( 931 "Additional such failures will be ignored.\n")); 932 complained_chown = 1; 933 } 934 if (chmod(rname, mode) < 0 && !complained_chmod) { 935 saverr = errno; 936 errmsg = gettext( 937 "Unable to restore permissions on %s: %s\n"); 938 (void) fprintf(stderr, errmsg, 939 rname, strerror(saverr)); 940 (void) fprintf(stderr, gettext( 941 "Additional such failures will be ignored.\n")); 942 complained_chmod = 1; 943 } 944 skipfile(); 945 metaset(rname); /* skipfile() got the metadata, if any */ 946 if (utime(rname, (struct utimbuf *)timep) < 0 && 947 !complained_utime) { 948 saverr = errno; 949 errmsg = gettext( 950 "Unable to restore times on %s: %s\n"); 951 (void) fprintf(stderr, errmsg, 952 rname, strerror(saverr)); 953 (void) fprintf(stderr, gettext( 954 "Additional such failures will be ignored.\n")); 955 complained_utime = 1; 956 } 957 result = GOOD; 958 break; 959 960 case IFREG: 961 vprintf(stdout, gettext("extract file %s\n"), rname); 962 ofile = creat64(rname, 0666); 963 964 if (ofile < 0) { 965 saverr = errno; 966 errmsg = gettext("cannot create file"); 967 (void) fprintf(stderr, "%s: ", rname); 968 (void) fflush(stderr); 969 errno = saverr; 970 perror(errmsg); 971 skipfile(); 972 result = FAIL; 973 break; 974 } 975 if (fchown(ofile, uid, gid) < 0 && !complained_chown) { 976 /* Just a warning */ 977 saverr = errno; 978 errmsg = gettext( 979 "Unable to restore ownership of %s: %s\n"); 980 (void) fprintf(stderr, errmsg, 981 rname, strerror(saverr)); 982 (void) fprintf(stderr, gettext( 983 "Additional such failures will be ignored.\n")); 984 complained_chown = 1; 985 } 986 if (fchmod(ofile, mode) < 0 && !complained_chmod) { 987 saverr = errno; 988 errmsg = gettext( 989 "Unable to restore permissions on %s: %s\n"); 990 (void) fprintf(stderr, errmsg, 991 rname, strerror(saverr)); 992 (void) fprintf(stderr, gettext( 993 "Additional such failures will be ignored.\n")); 994 complained_chmod = 1; 995 } 996 getfile(xtrfile, xtrskip); 997 metaset(rname); /* we don't have metadata until after */ 998 /* getfile() - maybe fchmod(0) then */ 999 /* fchmod(real) after this? */ 1000 1001 /* 1002 * Some errors don't get reported until we close(2), so 1003 * check for them. 1004 * XXX unlink the file if an error is reported? 1005 */ 1006 if (close(ofile) < 0) { 1007 saverr = errno; 1008 errmsg = gettext("error closing file"); 1009 (void) fprintf(stderr, "%s: ", rname); 1010 (void) fflush(stderr); 1011 errno = saverr; 1012 perror(errmsg); 1013 result = FAIL; 1014 break; 1015 } 1016 if (utime(rname, (struct utimbuf *)timep) < 0 && 1017 !complained_utime) { 1018 saverr = errno; 1019 errmsg = gettext( 1020 "Unable to restore times on %s: %s\n"); 1021 (void) fprintf(stderr, errmsg, 1022 rname, strerror(saverr)); 1023 (void) fprintf(stderr, gettext( 1024 "Additional such failures will be ignored.\n")); 1025 complained_utime = 1; 1026 } 1027 1028 result = GOOD; 1029 break; 1030 } 1031 if (dfd != AT_FDCWD) { 1032 fchdir(savepwd); 1033 (void) close(dfd); 1034 } 1035 return (result); 1036 } 1037 1038 /* 1039 * skip over bit maps on the tape 1040 */ 1041 void 1042 #ifdef __STDC__ 1043 skipmaps(void) 1044 #else 1045 skipmaps() 1046 #endif 1047 { 1048 continuemap = 1; 1049 while (checktype(&spcl, TS_CLRI) == GOOD || 1050 checktype(&spcl, TS_BITS) == GOOD) 1051 skipfile(); 1052 continuemap = 0; 1053 } 1054 1055 /* 1056 * skip over a file on the tape 1057 */ 1058 void 1059 #ifdef __STDC__ 1060 skipfile(void) 1061 #else 1062 skipfile() 1063 #endif 1064 { 1065 curfile.action = SKIP; 1066 getfile(null, null); 1067 } 1068 /* 1069 * Do the file extraction, calling the supplied functions 1070 * with the blocks 1071 */ 1072 void 1073 getfile(void (*f1)(), void (*f2)()) 1074 { 1075 int i; 1076 size_t curblk = 0; 1077 offset_t size = (offset_t)spcl.c_dinode.di_size; 1078 static char clearedbuf[MAXBSIZE]; 1079 char buf[TP_BSIZE_MAX]; 1080 char *bufptr; 1081 char junk[TP_BSIZE_MAX]; 1082 1083 assert(MAXBSIZE >= tp_bsize); 1084 1085 metaset(NULL); /* flush old metadata */ 1086 if (checktype(&spcl, TS_END) == GOOD) { 1087 panic(gettext("ran off end of volume\n")); 1088 return; 1089 } 1090 if (ishead(&spcl) == FAIL) { 1091 panic(gettext("not at beginning of a file\n")); 1092 return; 1093 } 1094 metacheck(&spcl); /* check for metadata in header */ 1095 if (!gettingfile && setjmp(restart) != 0) { 1096 gettingfile = 0; /* paranoia; longjmp'er should do */ 1097 return; 1098 } 1099 gettingfile++; 1100 loop: 1101 if ((spcl.c_dinode.di_mode & IFMT) == IFSHAD) { 1102 f1 = xtrmeta; 1103 f2 = metaskip; 1104 } 1105 for (i = 0, bufptr = buf; i < spcl.c_count; i++) { 1106 if ((i >= TP_NINDIR) || (spcl.c_addr[i])) { 1107 readtape(bufptr); 1108 bufptr += tp_bsize; 1109 curblk++; 1110 if (curblk == (fssize / tp_bsize)) { 1111 (*f1)(buf, size > tp_bsize ? 1112 (size_t)(fssize) : 1113 /* LINTED size <= tp_bsize */ 1114 (curblk - 1) * tp_bsize + (size_t)size); 1115 curblk = 0; 1116 bufptr = buf; 1117 } 1118 } else { 1119 if (curblk > 0) { 1120 (*f1)(buf, size > tp_bsize ? 1121 (size_t)(curblk * tp_bsize) : 1122 /* LINTED size <= tp_bsize */ 1123 (curblk - 1) * tp_bsize + (size_t)size); 1124 curblk = 0; 1125 bufptr = buf; 1126 } 1127 (*f2)(clearedbuf, size > tp_bsize ? 1128 /* LINTED size <= tp_bsize */ 1129 (long)tp_bsize : (size_t)size); 1130 } 1131 if ((size -= tp_bsize) <= 0) { 1132 for (i++; i < spcl.c_count; i++) 1133 if ((i >= TP_NINDIR) || (spcl.c_addr[i])) 1134 readtape(junk); 1135 break; 1136 } 1137 } 1138 if (curblk > 0) { 1139 /* 1140 * Ok to cast size to size_t here. The above for loop reads 1141 * data into the buffer then writes it to the output file. The 1142 * call to f1 here is to write out the data that's in the 1143 * buffer that has not yet been written to the file. 1144 * This will be less than N-KB of data, since the 1145 * above loop writes to the file in filesystem- 1146 * blocksize chunks. 1147 */ 1148 /* LINTED: size fits into a size_t at this point */ 1149 (*f1)(buf, (curblk * tp_bsize) + (size_t)size); 1150 1151 curblk = 0; 1152 bufptr = buf; 1153 } 1154 if ((readhdr(&spcl) == GOOD) && (checktype(&spcl, TS_ADDR) == GOOD)) { 1155 if (continuemap) 1156 size = (offset_t)spcl.c_count * tp_bsize; 1157 /* big bitmap */ 1158 else if ((size <= 0) && 1159 ((spcl.c_dinode.di_mode & IFMT) == IFSHAD)) { 1160 /* LINTED unsigned to signed conversion ok */ 1161 size = spcl.c_dinode.di_size; 1162 } 1163 if (size > 0) 1164 goto loop; 1165 } 1166 if (size > 0) 1167 dprintf(stdout, 1168 gettext("Missing address (header) block for %s\n"), 1169 curfile.name); 1170 findinode(&spcl); 1171 gettingfile = 0; 1172 } 1173 1174 /* 1175 * The next routines are called during file extraction to 1176 * put the data into the right form and place. 1177 */ 1178 static void 1179 xtrfile(char *buf, size_t size) 1180 { 1181 if (write(ofile, buf, (size_t)size) == -1) { 1182 int saverr = errno; 1183 (void) fprintf(stderr, 1184 gettext("write error extracting inode %d, name %s\n"), 1185 curfile.ino, curfile.name); 1186 errno = saverr; 1187 perror("write"); 1188 done(1); 1189 } 1190 } 1191 1192 /* 1193 * Even though size is a size_t, it's seeking to a relative 1194 * offset. Thus, the seek could go beyond 2 GB, so lseek64 is needed. 1195 */ 1196 1197 /*ARGSUSED*/ 1198 static void 1199 xtrskip(char *buf, size_t size) 1200 { 1201 if (lseek64(ofile, (offset_t)size, 1) == -1) { 1202 int saverr = errno; 1203 (void) fprintf(stderr, 1204 gettext("seek error extracting inode %d, name %s\n"), 1205 curfile.ino, curfile.name); 1206 errno = saverr; 1207 perror("lseek64"); 1208 done(1); 1209 } 1210 } 1211 1212 /* these are local to the next five functions */ 1213 static char *metadata = NULL; 1214 static size_t metasize = 0; 1215 1216 static void 1217 metacheck(struct s_spcl *head) 1218 { 1219 if (! (head->c_flags & DR_HASMETA)) 1220 return; 1221 if ((metadata = malloc(metasize = (size_t)sizeof (head->c_shadow))) 1222 == NULL) { 1223 (void) fprintf(stderr, 1224 gettext("Cannot malloc for metadata\n")); 1225 done(1); 1226 } 1227 bcopy(&(head->c_shadow), metadata, metasize); 1228 } 1229 1230 static void 1231 xtrmeta(char *buf, size_t size) 1232 { 1233 if ((metadata == NULL) && ((spcl.c_dinode.di_mode & IFMT) != IFSHAD)) 1234 return; 1235 if ((metadata = realloc(metadata, metasize + size)) == NULL) { 1236 (void) fprintf(stderr, 1237 gettext("Cannot malloc for metadata\n")); 1238 done(1); 1239 } 1240 bcopy(buf, metadata + metasize, size); 1241 metasize += size; 1242 } 1243 1244 /* ARGSUSED */ 1245 static void 1246 metaskip(char *buf, size_t size) 1247 { 1248 if (metadata == NULL) 1249 return; 1250 if ((metadata = realloc(metadata, metasize + size)) == NULL) { 1251 (void) fprintf(stderr, 1252 gettext("Cannot malloc for metadata\n")); 1253 done(1); 1254 } 1255 bzero(metadata + metasize, size); 1256 metasize += size; 1257 } 1258 1259 static void 1260 metaset(char *name) 1261 { 1262 if (metadata == NULL) 1263 return; 1264 if (name != NULL) 1265 metaproc(name, metadata, metasize); 1266 (void) free(metadata); 1267 metadata = NULL; 1268 metasize = 0; 1269 } 1270 1271 void 1272 metaget(data, size) 1273 char **data; 1274 size_t *size; 1275 { 1276 *data = metadata; 1277 *size = metasize; 1278 } 1279 1280 static void 1281 fsd_acl(name, aclp, size) 1282 char *name, *aclp; 1283 unsigned size; 1284 { 1285 static aclent_t *aclent = NULL; 1286 ufs_acl_t *diskacl; 1287 static int n = 0; 1288 uint_t i; 1289 int saverr, j; 1290 1291 if (aclp == NULL) { 1292 if (aclent != NULL) 1293 free(aclent); 1294 aclent = NULL; 1295 n = 0; 1296 return; 1297 } 1298 1299 /*LINTED [aclp is malloc'd]*/ 1300 diskacl = (ufs_acl_t *)aclp; 1301 /* LINTED: result fits in an int */ 1302 j = size / sizeof (*diskacl); 1303 normacls(byteorder, diskacl, j); 1304 1305 i = n; 1306 n += j; 1307 aclent = realloc(aclent, n * (size_t)sizeof (*aclent)); 1308 if (aclent == NULL) { 1309 (void) fprintf(stderr, gettext("Cannot malloc acl list\n")); 1310 done(1); 1311 } 1312 1313 j = 0; 1314 while (i < n) { 1315 aclent[i].a_type = diskacl[j].acl_tag; 1316 aclent[i].a_id = diskacl[j].acl_who; 1317 aclent[i].a_perm = diskacl[j].acl_perm; 1318 ++i; 1319 ++j; 1320 } 1321 1322 if (acl(name, SETACL, n, aclent) == -1) { 1323 static int once = 0; 1324 1325 /* 1326 * Treat some errors from the acl subsystem specially to 1327 * avoid being too noisy: 1328 * 1329 * ENOSYS - ACLs not supported on this file system 1330 * EPERM - not the owner or not privileged 1331 * 1332 * The following is also supported for backwards compat. 1333 * since acl(2) used to return the wrong errno: 1334 * 1335 * EINVAL - not the owner of the object 1336 */ 1337 if (errno == ENOSYS || errno == EPERM || errno == EINVAL) { 1338 if (once == 0) { 1339 saverr = errno; 1340 ++once; 1341 fprintf(stderr, 1342 gettext("setacl failed: %s\n"), 1343 strerror(saverr)); 1344 } 1345 } else { 1346 saverr = errno; 1347 fprintf(stderr, gettext("setacl on %s failed: %s\n"), 1348 name, strerror(saverr)); 1349 } 1350 } 1351 } 1352 1353 static struct fsdtypes { 1354 int type; 1355 void (*function)(); 1356 } fsdtypes[] = { 1357 {FSD_ACL, fsd_acl}, 1358 {FSD_DFACL, fsd_acl}, 1359 {0, NULL} 1360 }; 1361 1362 void 1363 metaproc(char *name, char *mdata, size_t msize) 1364 { 1365 struct fsdtypes *fsdtype; 1366 ufs_fsd_t *fsd; 1367 char *c; 1368 1369 /* 1370 * for the whole shadow inode, dispatch each piece 1371 * to the appropriate function. 1372 */ 1373 c = mdata; 1374 /* LINTED (c - mdata) fits into a size_t */ 1375 while ((size_t)(c - mdata) < msize) { 1376 /*LINTED [mdata is malloc'd]*/ 1377 fsd = (ufs_fsd_t *)c; 1378 assert((fsd->fsd_size % 4) == 0); 1379 /* LINTED: lint thinks pointers are signed */ 1380 c += FSD_RECSZ(fsd, fsd->fsd_size); 1381 if ((fsd->fsd_type == FSD_FREE) || 1382 ((unsigned)(fsd->fsd_size) <= sizeof (ufs_fsd_t)) || 1383 (c > (mdata + msize))) 1384 break; 1385 for (fsdtype = fsdtypes; fsdtype->type; fsdtype++) 1386 if (fsdtype->type == fsd->fsd_type) 1387 (*fsdtype->function)(name, fsd->fsd_data, 1388 (unsigned)(fsd->fsd_size) - 1389 sizeof (fsd->fsd_type) - 1390 sizeof (fsd->fsd_size)); 1391 /* ^^^ be sure to change if fsd ever changes ^^^ */ 1392 } 1393 1394 /* reset the state of all the functions */ 1395 for (fsdtype = fsdtypes; fsdtype->type; fsdtype++) 1396 (*fsdtype->function)(NULL, NULL, 0); 1397 } 1398 1399 static void 1400 xtrlnkfile(char *buf, size_t size) 1401 { 1402 /* LINTED: signed/unsigned mix ok */ 1403 pathlen += size; 1404 if (pathlen > MAXPATHLEN) { 1405 (void) fprintf(stderr, 1406 gettext("symbolic link name: %s->%s%s; too long %d\n"), 1407 curfile.name, lnkbuf, buf, pathlen); 1408 done(1); 1409 } 1410 buf[size] = '\0'; 1411 (void) strcat(lnkbuf, buf); 1412 /* add an extra NULL to make this a legal complex string */ 1413 lnkbuf[pathlen+1] = '\0'; 1414 } 1415 1416 /*ARGSUSED*/ 1417 static void 1418 xtrlnkskip(char *buf, size_t size) 1419 { 1420 (void) fprintf(stderr, 1421 gettext("unallocated block in symbolic link %s\n"), 1422 curfile.name); 1423 done(1); 1424 } 1425 1426 static void 1427 xtrmap(char *buf, size_t size) 1428 { 1429 if ((map+size) > endmap) { 1430 int64_t mapsize, increment; 1431 int64_t diff; 1432 1433 if (spcl.c_type != TS_ADDR) { 1434 (void) fprintf(stderr, 1435 gettext("xtrmap: current record not TS_ADDR\n")); 1436 done(1); 1437 } 1438 if ((spcl.c_count < 0) || (spcl.c_count > TP_NINDIR)) { 1439 (void) fprintf(stderr, 1440 gettext("xtrmap: illegal c_count field (%d)\n"), 1441 spcl.c_count); 1442 done(1); 1443 } 1444 1445 increment = d_howmany( 1446 ((spcl.c_count * tp_bsize * NBBY) + 1), NBBY); 1447 mapsize = endmap - beginmap + increment; 1448 if (mapsize > UINT_MAX) { 1449 (void) fprintf(stderr, 1450 gettext("xtrmap: maximum bitmap size exceeded")); 1451 done(1); 1452 } 1453 1454 diff = map - beginmap; 1455 /* LINTED mapsize checked above */ 1456 beginmap = realloc(beginmap, (size_t)mapsize); 1457 if (beginmap == NULL) { 1458 (void) fprintf(stderr, 1459 gettext("xtrmap: realloc failed\n")); 1460 done(1); 1461 } 1462 map = beginmap + diff; 1463 endmap = beginmap + mapsize; 1464 /* LINTED endmap - map cannot exceed 32 bits */ 1465 bzero(map, (size_t)(endmap - map)); 1466 maxino = NBBY * mapsize + 1; 1467 } 1468 1469 bcopy(buf, map, size); 1470 /* LINTED character pointers aren't signed */ 1471 map += size; 1472 } 1473 1474 /*ARGSUSED*/ 1475 static void 1476 xtrmapskip(char *buf, size_t size) 1477 { 1478 (void) fprintf(stderr, gettext("hole in map\n")); 1479 done(1); 1480 } 1481 1482 /*ARGSUSED*/ 1483 void 1484 null(char *buf, size_t size) 1485 { 1486 } 1487 1488 /* 1489 * Do the tape i/o, dealing with volume changes 1490 * etc.. 1491 */ 1492 static void 1493 readtape(char *b) 1494 { 1495 int i; 1496 int rd, newvol; 1497 int cnt; 1498 struct s_spcl *sp; 1499 int32_t expected_magic; 1500 1501 if (tbf == NULL) { 1502 (void) fprintf(stderr, gettext( 1503 "Internal consistency failure in readtape: tbf is NULL\n")); 1504 done(1); 1505 } 1506 expected_magic = ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC); 1507 1508 top: 1509 if (bct < numtrec) { 1510 /* 1511 * check for old-dump floppy EOM -- it may appear in 1512 * the middle of a buffer. The Dflag used to be used for 1513 * this, but since it doesn't hurt to always do this we 1514 * got rid of the Dflag. 1515 */ 1516 /*LINTED [tbf = malloc()]*/ 1517 sp = &((union u_spcl *)&tbf[bct*tp_bsize])->s_spcl; 1518 if (sp->c_magic == expected_magic && sp->c_type == TS_EOM && 1519 (time_t)(sp->c_date) == dumpdate && 1520 (time_t)(sp->c_ddate) == dumptime) { 1521 for (i = 0; i < ntrec; i++) 1522 /*LINTED [tbf = malloc()]*/ 1523 ((struct s_spcl *) 1524 &tbf[i*tp_bsize])->c_magic = 0; 1525 bct = 0; 1526 rd = 0; 1527 i = 0; 1528 goto nextvol; 1529 } 1530 bcopy(&tbf[(bct++*tp_bsize)], b, (size_t)tp_bsize); 1531 blksread++; 1532 tapea++; 1533 return; 1534 } 1535 /*LINTED [assertion always true]*/ 1536 assert(sizeof (union u_spcl) == TP_BSIZE_MAX); 1537 for (i = 0; i < ntrec; i++) 1538 /*LINTED [tbf = malloc()]*/ 1539 ((struct s_spcl *)&tbf[i*sizeof (struct s_spcl)])->c_magic = 0; 1540 if (numtrec == 0) { 1541 /* LINTED unsigned/signed assignment ok */ 1542 numtrec = ntrec; 1543 } 1544 /* LINTED unsigned/signed assignment ok */ 1545 cnt = ntrec*tp_bsize; 1546 rd = 0; 1547 getmore: 1548 if (host) 1549 i = rmtread(&tbf[rd], cnt); 1550 else 1551 i = read(mt, &tbf[rd], cnt); 1552 /* 1553 * Check for mid-tape short read error. 1554 * If found, return rest of buffer. 1555 */ 1556 if (numtrec < ntrec && i != 0) { 1557 /* LINTED unsigned/signed assignment ok */ 1558 numtrec = ntrec; 1559 goto top; 1560 } 1561 /* 1562 * Handle partial block read. 1563 */ 1564 if (i > 0 && i != ntrec*tp_bsize) { 1565 if (pipein) { 1566 rd += i; 1567 cnt -= i; 1568 if (cnt > 0) 1569 goto getmore; 1570 i = rd; 1571 } else { 1572 if (i % tp_bsize != 0) 1573 panic(gettext( 1574 "partial block read: %d should be %d\n"), 1575 i, ntrec * tp_bsize); 1576 numtrec = i / tp_bsize; 1577 if (numtrec == 0) 1578 /* 1579 * it's possible to read only 512 bytes 1580 * from a QIC device... 1581 */ 1582 i = 0; 1583 } 1584 } 1585 /* 1586 * Handle read error. 1587 */ 1588 if (i < 0) { 1589 switch (curfile.action) { 1590 default: 1591 (void) fprintf(stderr, gettext( 1592 "Read error while trying to set up volume\n")); 1593 break; 1594 case UNKNOWN: 1595 (void) fprintf(stderr, gettext( 1596 "Read error while trying to resynchronize\n")); 1597 break; 1598 case USING: 1599 (void) fprintf(stderr, gettext( 1600 "Read error while restoring %s\n"), 1601 curfile.name); 1602 break; 1603 case SKIP: 1604 (void) fprintf(stderr, gettext( 1605 "Read error while skipping over inode %d\n"), 1606 curfile.ino); 1607 break; 1608 } 1609 if (!yflag && !reply(gettext("continue"))) 1610 done(1); 1611 /* LINTED: unsigned->signed conversion ok */ 1612 i = (int)(ntrec*tp_bsize); 1613 bzero(tbf, (size_t)i); 1614 if ((host != 0 && rmtseek(i, 1) < 0) || 1615 (host == 0 && (lseek64(mt, (offset_t)i, 1) == 1616 (off64_t)-1))) { 1617 perror(gettext("continuation failed")); 1618 done(1); 1619 } 1620 } 1621 /* 1622 * Handle end of tape. The Dflag used to be used, but since it doesn't 1623 * hurt to always check we got rid if it. 1624 */ 1625 1626 /* 1627 * if the first record in the buffer just read is EOM, 1628 * change volumes. 1629 */ 1630 /*LINTED [tbf = malloc()]*/ 1631 sp = &((union u_spcl *)tbf)->s_spcl; 1632 if (i != 0 && sp->c_magic == expected_magic && sp->c_type == TS_EOM && 1633 (time_t)(sp->c_date) == dumpdate && 1634 (time_t)(sp->c_ddate) == dumptime) { 1635 i = 0; 1636 } 1637 nextvol: 1638 if (i == 0) { 1639 if (!pipein) { 1640 newvol = volno + 1; 1641 volno = 0; 1642 numtrec = 0; 1643 getvol(newvol); 1644 readtape(b); /* XXX tail recursion, not goto top? */ 1645 return; 1646 } 1647 /* XXX if panic returns, should we round rd up? */ 1648 /* XXX if we do, then we should zero the intervening space */ 1649 if (rd % tp_bsize != 0) 1650 panic(gettext("partial block read: %d should be %d\n"), 1651 rd, ntrec * tp_bsize); 1652 bcopy((char *)&endoftapemark, &tbf[rd], (size_t)tp_bsize); 1653 } 1654 bct = 0; 1655 bcopy(&tbf[(bct++*tp_bsize)], b, (size_t)tp_bsize); 1656 blksread++; 1657 recsread++; 1658 tapea++; 1659 rec_position++; 1660 } 1661 1662 void 1663 #ifdef __STDC__ 1664 findtapeblksize(int arfile) 1665 #else 1666 findtapeblksize(int arfile) 1667 #endif 1668 { 1669 int i; 1670 1671 if (tbf == NULL) { 1672 (void) fprintf(stderr, gettext( 1673 "Internal consistency failure in findtapeblksize: " 1674 "tbf is NULL\n")); 1675 assert(tbf != NULL); 1676 done(1); 1677 } 1678 1679 for (i = 0; i < ntrec; i++) 1680 /*LINTED [tbf = malloc()]*/ 1681 ((struct s_spcl *)&tbf[i * tp_bsize])->c_magic = 0; 1682 bct = 0; 1683 if (host && arfile == TAPE_FILE) 1684 tape_rec_size = rmtread(tbf, ntrec * tp_bsize); 1685 else 1686 tape_rec_size = read(mt, tbf, ntrec * tp_bsize); 1687 recsread++; 1688 rec_position++; 1689 if (tape_rec_size == (ssize_t)-1) { 1690 int saverr = errno; 1691 char *errmsg = gettext("Media read error"); 1692 errno = saverr; 1693 perror(errmsg); 1694 done(1); 1695 } 1696 if (tape_rec_size % tp_bsize != 0) { 1697 (void) fprintf(stderr, gettext( 1698 "Record size (%d) is not a multiple of dump block size (%d)\n"), 1699 tape_rec_size, tp_bsize); 1700 done(1); 1701 } 1702 ntrec = (int)tape_rec_size / tp_bsize; 1703 /* LINTED unsigned/signed assignment ok */ 1704 numtrec = ntrec; 1705 vprintf(stdout, gettext("Media block size is %d\n"), ntrec*2); 1706 } 1707 1708 void 1709 #ifdef __STDC__ 1710 flsht(void) 1711 #else 1712 flsht() 1713 #endif 1714 { 1715 /* LINTED unsigned/signed assignment ok */ 1716 bct = ntrec+1; 1717 } 1718 1719 void 1720 #ifdef __STDC__ 1721 closemt(int mode) 1722 #else 1723 closemt(int mode) 1724 #endif 1725 { 1726 /* 1727 * If mode == FORCE_OFFLINE then we're not done but 1728 * we need to change tape. So, rewind and unload current 1729 * tape before loading the new one. 1730 */ 1731 1732 static struct mtop mtop = { MTOFFL, 0 }; 1733 1734 if (mt < 0) 1735 return; 1736 if (offline || mode == FORCE_OFFLINE) 1737 (void) fprintf(stderr, gettext("Rewinding tape\n")); 1738 if (host) { 1739 if (offline || mode == FORCE_OFFLINE) 1740 (void) rmtioctl(MTOFFL, 1); 1741 rmtclose(); 1742 } else if (pipein) { 1743 char buffy[MAXBSIZE]; 1744 1745 while (read(mt, buffy, sizeof (buffy)) > 0) { 1746 continue; 1747 /*LINTED [assertion always true]*/ 1748 } 1749 (void) close(mt); 1750 } else { 1751 /* 1752 * Only way to tell if this is a floppy is to issue an ioctl 1753 * but why waste one - if the eject fails, tough! 1754 */ 1755 if (offline || mode == FORCE_OFFLINE) 1756 (void) ioctl(mt, MTIOCTOP, &mtop); 1757 (void) ioctl(mt, FDEJECT, 0); 1758 (void) close(mt); 1759 } 1760 mt = -1; 1761 } 1762 1763 static int 1764 checkvol(struct s_spcl *b, int t) 1765 { 1766 1767 if (b->c_volume != t) 1768 return (FAIL); 1769 return (GOOD); 1770 } 1771 1772 int 1773 readhdr(struct s_spcl *b) 1774 { 1775 1776 if (gethead(b) == FAIL) { 1777 dprintf(stdout, gettext("readhdr fails at %ld blocks\n"), 1778 blksread); 1779 return (FAIL); 1780 } 1781 return (GOOD); 1782 } 1783 1784 /* 1785 * read the tape into buf, then return whether or 1786 * or not it is a header block. 1787 */ 1788 int 1789 gethead(struct s_spcl *buf) 1790 { 1791 int i; 1792 union u_ospcl { 1793 char dummy[TP_BSIZE_MIN]; 1794 struct s_ospcl { 1795 int32_t c_type; 1796 int32_t c_date; 1797 int32_t c_ddate; 1798 int32_t c_volume; 1799 int32_t c_tapea; 1800 ushort_t c_inumber; 1801 int32_t c_magic; 1802 int32_t c_checksum; 1803 struct odinode { 1804 unsigned short odi_mode; 1805 ushort_t odi_nlink; 1806 ushort_t odi_uid; 1807 ushort_t odi_gid; 1808 int32_t odi_size; 1809 int32_t odi_rdev; 1810 char odi_addr[36]; 1811 int32_t odi_atime; 1812 int32_t odi_mtime; 1813 int32_t odi_ctime; 1814 } c_dinode; 1815 int32_t c_count; 1816 char c_baddr[256]; 1817 } s_ospcl; 1818 } u_ospcl; 1819 1820 if (cvtflag) { 1821 readtape((char *)(&u_ospcl.s_ospcl)); 1822 bzero((char *)buf, (size_t)TP_BSIZE_MIN); 1823 buf->c_type = u_ospcl.s_ospcl.c_type; 1824 buf->c_date = u_ospcl.s_ospcl.c_date; 1825 buf->c_ddate = u_ospcl.s_ospcl.c_ddate; 1826 buf->c_volume = u_ospcl.s_ospcl.c_volume; 1827 buf->c_tapea = u_ospcl.s_ospcl.c_tapea; 1828 buf->c_inumber = u_ospcl.s_ospcl.c_inumber; 1829 buf->c_checksum = u_ospcl.s_ospcl.c_checksum; 1830 buf->c_magic = u_ospcl.s_ospcl.c_magic; 1831 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode; 1832 /* LINTED: unsigned/signed combination ok */ 1833 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink; 1834 buf->c_dinode.di_size = 1835 (unsigned)(u_ospcl.s_ospcl.c_dinode.odi_size); 1836 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid; 1837 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid; 1838 buf->c_dinode.di_suid = UID_LONG; 1839 buf->c_dinode.di_sgid = GID_LONG; 1840 buf->c_dinode.di_ordev = u_ospcl.s_ospcl.c_dinode.odi_rdev; 1841 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime; 1842 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime; 1843 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime; 1844 buf->c_count = u_ospcl.s_ospcl.c_count; 1845 bcopy(u_ospcl.s_ospcl.c_baddr, buf->c_addr, 1846 sizeof (u_ospcl.s_ospcl.c_baddr)); 1847 1848 /*CONSTANTCONDITION*/ 1849 assert(sizeof (u_ospcl.s_ospcl) < sizeof (union u_spcl)); 1850 1851 /* we byte-swap the new spclrec, but checksum the old */ 1852 /* (see comments in normspcl()) */ 1853 if (normspcl(byteorder, buf, 1854 (int *)(&u_ospcl.s_ospcl), sizeof (u_ospcl.s_ospcl), 1855 OFS_MAGIC)) 1856 return (FAIL); 1857 buf->c_magic = 1858 ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC); 1859 } else { 1860 readtape((char *)buf); 1861 if (normspcl(byteorder, buf, (int *)buf, tp_bsize, 1862 ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC))) 1863 return (FAIL); 1864 } 1865 1866 switch (buf->c_type) { 1867 1868 case TS_CLRI: 1869 case TS_BITS: 1870 /* 1871 * Have to patch up missing information in bit map headers 1872 */ 1873 buf->c_inumber = 0; 1874 buf->c_dinode.di_size = (offset_t)buf->c_count * tp_bsize; 1875 for (i = 0; i < buf->c_count && i < TP_NINDIR; i++) 1876 buf->c_addr[i] = 1; 1877 break; 1878 1879 case TS_TAPE: 1880 case TS_END: 1881 if (dumpinfo.c_date == 0) { 1882 dumpinfo.c_date = spcl.c_date; 1883 dumpinfo.c_ddate = spcl.c_ddate; 1884 } 1885 if (!hostinfo && spcl.c_host[0] != '\0') { 1886 bcopy(spcl.c_label, dumpinfo.c_label, 1887 sizeof (spcl.c_label)); 1888 bcopy(spcl.c_filesys, dumpinfo.c_filesys, 1889 sizeof (spcl.c_filesys)); 1890 bcopy(spcl.c_dev, dumpinfo.c_dev, 1891 sizeof (spcl.c_dev)); 1892 bcopy(spcl.c_host, dumpinfo.c_host, 1893 sizeof (spcl.c_host)); 1894 dumpinfo.c_level = spcl.c_level; 1895 hostinfo++; 1896 if (c_label != NULL && 1897 strncmp(c_label, spcl.c_label, 1898 sizeof (spcl.c_label)) 1899 != 0) { 1900 (void) fprintf(stderr, gettext( 1901 "Incorrect tape label. Expected `%s', got `%.*s'\n"), 1902 c_label, 1903 sizeof (spcl.c_label), spcl.c_label); 1904 done(1); 1905 } 1906 } 1907 if (!inodeinfo && (spcl.c_flags & DR_INODEINFO)) { 1908 dumpinfo.c_volume = spcl.c_volume; 1909 bcopy(spcl.c_inos, dumpinfo.c_inos, 1910 sizeof (spcl.c_inos)); 1911 inodeinfo++; 1912 } 1913 buf->c_inumber = 0; 1914 break; 1915 1916 case TS_INODE: 1917 case TS_ADDR: 1918 break; 1919 1920 default: 1921 panic(gettext("%s: unknown inode type %d\n"), 1922 "gethead", buf->c_type); 1923 return (FAIL); 1924 } 1925 if (dflag) 1926 accthdr(buf); 1927 return (GOOD); 1928 } 1929 1930 /* 1931 * Check that a header is where it belongs and predict the next header 1932 */ 1933 static void 1934 accthdr(struct s_spcl *header) 1935 { 1936 static ino_t previno = (ino_t)(unsigned)-1; 1937 static int prevtype; 1938 static long predict; 1939 int blks, i; 1940 1941 if (header->c_type == TS_TAPE) { 1942 if (header->c_firstrec) 1943 (void) fprintf(stderr, 1944 gettext("Volume header begins with record %d"), 1945 header->c_firstrec); 1946 else 1947 (void) fprintf(stderr, gettext("Volume header")); 1948 (void) fprintf(stderr, "\n"); 1949 previno = (ino_t)(unsigned)-1; 1950 return; 1951 } 1952 if (previno == (ino_t)(unsigned)-1) 1953 goto newcalc; 1954 switch (prevtype) { 1955 case TS_BITS: 1956 (void) fprintf(stderr, gettext("Dump mask header")); 1957 break; 1958 case TS_CLRI: 1959 (void) fprintf(stderr, gettext("Remove mask header")); 1960 break; 1961 case TS_INODE: 1962 (void) fprintf(stderr, 1963 gettext("File header, ino %d at record %d"), 1964 previno, rec_position); 1965 break; 1966 case TS_ADDR: 1967 (void) fprintf(stderr, 1968 gettext("File continuation header, ino %d"), 1969 previno); 1970 break; 1971 case TS_END: 1972 (void) fprintf(stderr, gettext("End of media header")); 1973 break; 1974 } 1975 if (predict != blksread - 1) 1976 (void) fprintf(stderr, 1977 gettext("; predicted %ld blocks, got %ld blocks"), 1978 predict, blksread - 1); 1979 (void) fprintf(stderr, "\n"); 1980 newcalc: 1981 blks = 0; 1982 if (header->c_type != TS_END) 1983 for (i = 0; i < header->c_count; i++) 1984 if ((i >= TP_NINDIR) || (header->c_addr[i] != 0)) 1985 blks++; 1986 predict = blks; 1987 blksread = 0; 1988 prevtype = header->c_type; 1989 previno = header->c_inumber; 1990 } 1991 1992 /* 1993 * Try to determine which volume a file resides on. 1994 */ 1995 int 1996 volnumber(ino_t inum) 1997 { 1998 int i; 1999 2000 if (inodeinfo == 0) 2001 return (0); 2002 for (i = 1; i <= dumpinfo.c_volume; i++) 2003 if (inum < (ino_t)(unsigned)(dumpinfo.c_inos[i])) 2004 break; 2005 return (i - 1); 2006 } 2007 2008 /* 2009 * Find an inode header. 2010 * Note that *header must be stable storage, as curfile will end up with 2011 * pointers into it. 2012 */ 2013 void 2014 findinode(struct s_spcl *header) 2015 { 2016 long skipcnt = 0; 2017 int i; 2018 char buf[TP_BSIZE_MAX]; 2019 2020 curfile.name = gettext("<name unknown>"); 2021 curfile.action = UNKNOWN; 2022 curfile.dip = (struct dinode *)NULL; 2023 curfile.ino = 0; 2024 curfile.ts = 0; 2025 if (ishead(header) == FAIL) { 2026 skipcnt++; 2027 while (gethead(header) == FAIL || 2028 (time_t)(header->c_date) != dumpdate) 2029 skipcnt++; 2030 } 2031 for (;;) { 2032 if (checktype(header, TS_ADDR) == GOOD) { 2033 /* 2034 * Skip up to the beginning of the next record 2035 */ 2036 for (i = 0; i < header->c_count; i++) 2037 if ((i >= TP_NINDIR) || (header->c_addr[i])) 2038 readtape(buf); 2039 (void) gethead(header); 2040 continue; 2041 } 2042 if (checktype(header, TS_INODE) == GOOD) { 2043 curfile.dip = &header->c_dinode; 2044 if (curfile.dip->di_suid != UID_LONG) 2045 curfile.dip->di_uid = curfile.dip->di_suid; 2046 if (curfile.dip->di_sgid != GID_LONG) 2047 curfile.dip->di_gid = curfile.dip->di_sgid; 2048 curfile.ino = header->c_inumber; 2049 curfile.ts = TS_INODE; 2050 break; 2051 } 2052 if (checktype(header, TS_END) == GOOD) { 2053 curfile.ino = maxino; 2054 curfile.ts = TS_END; 2055 break; 2056 } 2057 if (checktype(header, TS_CLRI) == GOOD) { 2058 curfile.name = gettext("<file removal list>"); 2059 curfile.ts = TS_CLRI; 2060 break; 2061 } 2062 if (checktype(header, TS_BITS) == GOOD) { 2063 curfile.name = gettext("<file dump list>"); 2064 curfile.ts = TS_BITS; 2065 break; 2066 } 2067 while (gethead(header) == FAIL) 2068 skipcnt++; 2069 } 2070 if (skipcnt > 0) 2071 (void) fprintf(stderr, 2072 gettext("resync restore, skipped %d blocks\n"), 2073 skipcnt); 2074 } 2075 2076 /* 2077 * return whether or not the buffer contains a header block 2078 */ 2079 static int 2080 ishead(struct s_spcl *buf) 2081 { 2082 if (buf->c_magic != 2083 ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC)) 2084 return (FAIL); 2085 return (GOOD); 2086 } 2087 2088 static int 2089 checktype(struct s_spcl *b, int t) 2090 { 2091 if (b->c_type != t) 2092 return (FAIL); 2093 return (GOOD); 2094 } 2095 2096 /* 2097 * If autoloading is enabled, attempt to do it. If we succeed, 2098 * return non-zero. 2099 */ 2100 static int 2101 #ifdef __STDC__ 2102 autoload_tape(void) 2103 #else 2104 autoload_tape() 2105 #endif 2106 { 2107 int result = 0; /* assume failure */ 2108 int tries; 2109 int fd; 2110 2111 if (autoload) { 2112 /* 2113 * Wait for the tape to autoload. Note that the delay 2114 * period doesn't take into account however long it takes 2115 * for the open to fail (measured at 21 seconds for an 2116 * Exabyte 8200 under 2.7 on an Ultra 2). 2117 */ 2118 2119 /* rewind tape and offline drive before loading new tape */ 2120 closemt(FORCE_OFFLINE); 2121 (void) fprintf(stderr, 2122 gettext("Attempting to autoload next volume\n")); 2123 for (tries = 0; tries < autoload_tries; tries++) { 2124 if (host) { 2125 if (rmtopen(magtape, O_RDONLY) >= 0) { 2126 rmtclose(); 2127 result = 1; 2128 break; 2129 } 2130 } else { 2131 if ((fd = open(magtape, O_RDONLY|O_LARGEFILE, 2132 0600)) >= 0) { 2133 (void) close(fd); 2134 result = 1; 2135 break; 2136 } 2137 } 2138 (void) sleep(autoload_period); 2139 } 2140 if (result == 0) { 2141 /* Assume caller will deal with manual change-over */ 2142 (void) fprintf(stderr, 2143 gettext("Autoload timed out\n")); 2144 } else { 2145 if ((host != NULL && 2146 (mt = rmtopen(magtape, O_RDONLY)) == -1) || 2147 (host == NULL && 2148 (mt = open(magtape, O_RDONLY|O_LARGEFILE)) == -1)) { 2149 (void) fprintf(stderr, gettext( 2150 "Autoload could not re-open tape\n")); 2151 result = 0; 2152 } else { 2153 (void) fprintf(stderr, gettext( 2154 "Tape loaded\n")); 2155 } 2156 } 2157 } 2158 2159 return (result); 2160 } 2161