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