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