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