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