1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. 11 * All rights reserved. 12 * 13 * Redistribution and use in source and binary forms are permitted 14 * provided that: (1) source distributions retain this entire copyright 15 * notice and comment, and (2) distributions including binaries display 16 * the following acknowledgement: ``This product includes software 17 * developed by the University of California, Berkeley and its contributors'' 18 * in the documentation or other materials provided with the distribution 19 * and in all advertising materials mentioning features or use of this 20 * software. Neither the name of the University nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #define DKTYPENAMES 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <errno.h> 34 #include <malloc.h> 35 #include <limits.h> 36 #include <wait.h> 37 #include <sys/param.h> 38 #include <sys/types.h> 39 #include <sys/sysmacros.h> 40 #include <sys/mntent.h> 41 #include <sys/dkio.h> 42 #include <sys/filio.h> 43 #include <sys/isa_defs.h> /* for ENDIAN defines */ 44 #include <sys/int_const.h> 45 #include <sys/fs/ufs_fs.h> 46 #include <sys/vnode.h> 47 #include <sys/fs/ufs_fs.h> 48 #include <sys/fs/ufs_inode.h> 49 #include <sys/fs/ufs_log.h> 50 #include <sys/stat.h> 51 #include <sys/fcntl.h> 52 #include <string.h> 53 #include <unistd.h> 54 #include <fcntl.h> 55 #include <sys/vfstab.h> 56 #include "roll_log.h" 57 #include "fsck.h" 58 59 /* 60 * The size of a cylinder group is calculated by CGSIZE. The maximum size 61 * is limited by the fact that cylinder groups are at most one block. 62 * Its size is derived from the size of the maps maintained in the 63 * cylinder group and the (struct cg) size. 64 */ 65 #define CGSIZE(fs) \ 66 /* base cg */ (sizeof (struct cg) + \ 67 /* blktot size */ (fs)->fs_cpg * sizeof (int32_t) + \ 68 /* blks size */ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof (short) + \ 69 /* inode map */ howmany((fs)->fs_ipg, NBBY) + \ 70 /* block map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY)) 71 72 #define altsblock (*asblk.b_un.b_fs) 73 #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 74 75 /* 76 * Methods of determining where alternate superblocks should 77 * be. MAX_SB_STYLES must be the last one, and the others need 78 * to be positive. 79 */ 80 typedef enum { 81 MKFS_STYLE = 1, NEWFS_STYLE, MAX_SB_STYLES 82 } calcsb_t; 83 84 static caddr_t calcsb_names[] = { 85 "<UNKNOWN>", "MKFS", "NEWFS", "<OUT OF RANGE>" 86 }; 87 88 struct shadowclientinfo *shadowclientinfo = NULL; 89 struct shadowclientinfo *attrclientinfo = NULL; 90 int maxshadowclients = 1024; /* allocation size, not limit */ 91 92 static void badsb(int, caddr_t); 93 static int calcsb(calcsb_t, caddr_t, int, struct fs *); 94 static int checksb(int); 95 static void flush_fs(void); 96 static void sblock_init(void); 97 static void uncreate_maps(void); 98 99 static int 100 read_super_block(int listerr) 101 { 102 int fd; 103 caddr_t err; 104 105 if (mount_point != NULL) { 106 fd = open(mount_point, O_RDONLY); 107 if (fd == -1) { 108 errexit("fsck: open mount point error: %s", 109 strerror(errno)); 110 /* NOTREACHED */ 111 } 112 /* get the latest super block */ 113 if (ioctl(fd, _FIOGETSUPERBLOCK, &sblock)) { 114 errexit("fsck: ioctl _FIOGETSUPERBLOCK error: %s", 115 strerror(errno)); 116 /* NOTREACHED */ 117 } 118 (void) close(fd); 119 } else { 120 (void) fsck_bread(fsreadfd, (caddr_t)&sblock, 121 bflag != 0 ? (diskaddr_t)bflag : (diskaddr_t)SBLOCK, 122 SBSIZE); 123 } 124 125 /* 126 * Don't let trash from the disk trip us up later 127 * in ungetsummaryinfo(). 128 */ 129 sblock.fs_u.fs_csp = NULL; 130 131 /* 132 * Rudimentary consistency checks. Can't really call 133 * checksb() here, because there may be outstanding 134 * deltas that still need to be applied. 135 */ 136 if ((sblock.fs_magic != FS_MAGIC) && 137 (sblock.fs_magic != MTB_UFS_MAGIC)) { 138 err = "MAGIC NUMBER WRONG"; 139 goto fail; 140 } 141 if (sblock.fs_magic == FS_MAGIC && 142 (sblock.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 && 143 sblock.fs_version != UFS_VERSION_MIN)) { 144 err = "UNRECOGNIZED VERSION"; 145 goto fail; 146 } 147 if (sblock.fs_magic == MTB_UFS_MAGIC && 148 (sblock.fs_version > MTB_UFS_VERSION_1 || 149 sblock.fs_version < MTB_UFS_VERSION_MIN)) { 150 err = "UNRECOGNIZED VERSION"; 151 goto fail; 152 } 153 if (sblock.fs_ncg < 1) { 154 err = "NCG OUT OF RANGE"; 155 goto fail; 156 } 157 if (sblock.fs_cpg < 1) { 158 err = "CPG OUT OF RANGE"; 159 goto fail; 160 } 161 if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl || 162 (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) { 163 err = "NCYL IS INCONSISTENT WITH NCG*CPG"; 164 goto fail; 165 } 166 if (sblock.fs_sbsize < 0 || sblock.fs_sbsize > SBSIZE) { 167 err = "SIZE OUT OF RANGE"; 168 goto fail; 169 } 170 171 return (1); 172 173 fail: 174 badsb(listerr, err); 175 return (0); 176 } 177 178 static void 179 flush_fs() 180 { 181 int fd; 182 183 if (mount_point != NULL) { 184 fd = open(mount_point, O_RDONLY); 185 if (fd == -1) { 186 errexit("fsck: open mount point error: %s", 187 strerror(errno)); 188 /* NOTREACHED */ 189 } 190 if (ioctl(fd, _FIOFFS, NULL)) { /* flush file system */ 191 errexit("fsck: ioctl _FIOFFS error: %s", 192 strerror(errno)); 193 /* NOTREACHED */ 194 } 195 (void) close(fd); 196 } 197 } 198 199 /* 200 * Roll the embedded log, if any, and set up the global variables 201 * islog and islogok. 202 */ 203 static int 204 logsetup(caddr_t devstr) 205 { 206 void *buf; 207 extent_block_t *ebp; 208 ml_unit_t *ul; 209 ml_odunit_t *ud; 210 void *ud_buf; 211 int badlog; 212 213 islog = islogok = 0; 214 if (bflag != 0) 215 return (1); /* can't roll log while alternate sb specified */ 216 217 /* 218 * Roll the log, if any. A bad sb implies we'll be using 219 * an alternate sb as far as logging goes, so just fail back 220 * to the caller if we can't read the default sb. Suppress 221 * complaints, because the caller will be reading the same 222 * superblock again and running full verification on it, so 223 * whatever is bad will be reported then. 224 */ 225 sblock.fs_logbno = 0; 226 badlog = 0; 227 if (!read_super_block(0)) 228 return (1); 229 230 /* 231 * Roll the log in 3 cases: 232 * 1. If it's unmounted (mount_point == NULL) and it's not marked 233 * as fully rolled (sblock.fs_rolled != FS_ALL_ROLLED) 234 * 2. If it's mounted and anything other than a sanity 235 * check fsck (mflag) is being done, as we have the current 236 * super block. Note, only a sanity check is done for 237 * root/usr at boot. If a roll were done then the expensive 238 * ufs_flush() gets called, leading to a slower boot. 239 * 3. If anything other then a sanity check (mflag) is being done 240 * to a mounted filesystem while it is in read-only state 241 * (e.g. root during early boot stages) we have to detect this 242 * and have to roll the log as well. NB. the read-only mount 243 * will flip fs_clean from FSLOG to FSSTABLE and marks the 244 * log as FS_NEED_ROLL. 245 */ 246 if (sblock.fs_logbno && 247 (((mount_point == NULL) && (sblock.fs_rolled != FS_ALL_ROLLED)) || 248 ((mount_point != NULL) && !mflag))) { 249 int roll_log_err = 0; 250 251 if (sblock.fs_ronly && (sblock.fs_clean == FSSTABLE) && 252 (sblock.fs_state + sblock.fs_time == FSOKAY)) { 253 /* 254 * roll the log without a mount 255 */ 256 flush_fs(); 257 } 258 if (sblock.fs_clean == FSLOG && 259 (sblock.fs_state + sblock.fs_time == FSOKAY)) { 260 if (rl_roll_log(devstr) != RL_SUCCESS) 261 roll_log_err = 1; 262 } 263 if (roll_log_err) { 264 (void) printf("Can't roll the log for %s.\n", devstr); 265 /* 266 * There are two cases where we want to set 267 * an error code and return: 268 * - We're preening 269 * - We're not on a live root and the user 270 * chose *not* to ignore the log 271 * Otherwise, we want to mark the log as bad 272 * and continue to check the filesystem. This 273 * has the side effect of destroying the log. 274 */ 275 if (preen || (!hotroot && 276 reply( 277 "DISCARDING THE LOG MAY DISCARD PENDING TRANSACTIONS.\n" 278 "DISCARD THE LOG AND CONTINUE") == 0)) { 279 exitstat = EXERRFATAL; 280 return (0); 281 } 282 ++badlog; 283 } 284 } 285 286 /* Logging UFS may be enabled */ 287 if (sblock.fs_logbno) { 288 ++islog; 289 290 /* log is not okay; check the fs */ 291 if (FSOKAY != (sblock.fs_state + sblock.fs_time)) 292 return (1); 293 294 /* 295 * If logging or (stable and mounted) then continue 296 */ 297 if (!((sblock.fs_clean == FSLOG) || 298 (sblock.fs_clean == FSSTABLE) && (mount_point != NULL))) 299 return (1); 300 301 /* get the log allocation block */ 302 buf = malloc(dev_bsize); 303 if (buf == NULL) { 304 return (1); 305 } 306 ud_buf = malloc(dev_bsize); 307 if (ud_buf == NULL) { 308 free(buf); 309 return (1); 310 } 311 (void) fsck_bread(fsreadfd, buf, 312 logbtodb(&sblock, sblock.fs_logbno), 313 dev_bsize); 314 ebp = (extent_block_t *)buf; 315 316 /* log allocation block is not okay; check the fs */ 317 if (ebp->type != LUFS_EXTENTS) { 318 free(buf); 319 free(ud_buf); 320 return (1); 321 } 322 323 /* get the log state block(s) */ 324 if (fsck_bread(fsreadfd, ud_buf, 325 (logbtodb(&sblock, ebp->extents[0].pbno)), 326 dev_bsize)) { 327 (void) fsck_bread(fsreadfd, ud_buf, 328 (logbtodb(&sblock, ebp->extents[0].pbno)) + 1, 329 dev_bsize); 330 } 331 ud = (ml_odunit_t *)ud_buf; 332 ul = (ml_unit_t *)malloc(sizeof (*ul)); 333 if (ul == NULL) { 334 free(buf); 335 free(ud_buf); 336 return (1); 337 } 338 ul->un_ondisk = *ud; 339 340 /* log state is okay; don't need to check the fs */ 341 if ((ul->un_chksum == ul->un_head_ident + ul->un_tail_ident) && 342 (ul->un_version == LUFS_VERSION_LATEST) && 343 (ul->un_badlog == 0) && (!badlog)) { 344 ++islogok; 345 } 346 free(ud_buf); 347 free(buf); 348 free(ul); 349 } 350 351 return (1); 352 } 353 354 /* 355 * - given a pathname, determine the pathname to actually check 356 * - if a directory 357 * - if it is in mnttab, set devstr to the special (block) name 358 * - if it is in vfstab, set devstr to the special (block) name 359 * - if it has not been found, bail 360 * - a file is used as-is, clear rflag 361 * - a device is converted to block version (so can search mnttab) 362 */ 363 static void 364 derive_devstr(const caddr_t dev, caddr_t devstr, size_t str_size) 365 { 366 mode_t mode; 367 struct stat statb; 368 369 if (stat(dev, &statb) < 0) { 370 exitstat = EXNOSTAT; 371 errexit("fsck: could not stat %s: %s", dev, strerror(errno)); 372 } 373 374 mode = statb.st_mode & S_IFMT; 375 switch (mode) { 376 case S_IFDIR: 377 /* 378 * The check_*() routines update devstr with the name. 379 */ 380 devstr[0] = '\0'; 381 if (!(check_mnttab(dev, devstr, str_size) || 382 check_vfstab(dev, devstr, str_size))) { 383 exitstat = EXBADPARM; 384 errexit( 385 "fsck: could not find mountpoint %s in mnttab nor vfstab", 386 dev); 387 } 388 break; 389 case S_IFREG: 390 rflag = 0; 391 break; 392 case S_IFCHR: 393 case S_IFBLK: 394 (void) strlcpy(devstr, unrawname(dev), str_size); 395 break; 396 default: 397 exitstat = EXBADPARM; 398 errexit("fsck: %s must be a mountpoint, device, or file", dev); 399 /* NOTREACHED */ 400 } 401 } 402 403 /* 404 * Reports the index of the magic filesystem that mntp names. 405 * If it does not correspond any of them, returns zero (hence 406 * the backwards loop). 407 */ 408 static int 409 which_corefs(const caddr_t mntp) 410 { 411 int corefs; 412 413 for (corefs = MAGIC_LIMIT - 1; corefs > 0; corefs--) 414 if (strcmp(mntp, magic_fs[corefs]) == 0) 415 break; 416 417 return (corefs); 418 } 419 420 /* 421 * - set mount_point to NULL 422 * - if name is mounted (search mnttab) 423 * - if it is a device, clear rflag 424 * - if mounted on /, /usr, or /var, set corefs 425 * - if corefs and read-only, set hotroot and continue 426 * - if errorlocked, continue 427 * - if preening, bail 428 * - ask user whether to continue, bail if not 429 * - if it is a device and not mounted and rflag, convert 430 * name to raw version 431 */ 432 static int 433 check_mount_state(caddr_t devstr, size_t str_size) 434 { 435 int corefs = 0; 436 int is_dev = 0; 437 struct stat statb; 438 439 if (stat(devstr, &statb) < 0) { 440 exitstat = EXNOSTAT; 441 errexit("fsck: could not stat %s: %s", devstr, strerror(errno)); 442 } 443 if (S_ISCHR(statb.st_mode) || S_ISBLK(statb.st_mode)) 444 is_dev = 1; 445 446 /* 447 * mounted() will update mount_point when returning true. 448 */ 449 mount_point = NULL; 450 if ((mountedfs = mounted(devstr, devstr, str_size)) != M_NOMNT) { 451 if (is_dev) 452 rflag = 0; 453 corefs = which_corefs(mount_point); 454 if (corefs && (mountedfs == M_RO)) { 455 hotroot++; 456 } else if (errorlocked) { 457 goto carry_on; 458 } else if (preen) { 459 exitstat = EXMOUNTED; 460 pfatal("%s IS CURRENTLY MOUNTED%s.", 461 devstr, mountedfs == M_RW ? " READ/WRITE" : ""); 462 } else { 463 pwarn("%s IS CURRENTLY MOUNTED READ/%s.", 464 devstr, mountedfs == M_RW ? "WRITE" : "ONLY"); 465 if (reply("CONTINUE") == 0) { 466 exitstat = EXMOUNTED; 467 errexit("Program terminated"); 468 } 469 } 470 } else if (is_dev && rflag) { 471 (void) strlcpy(devstr, rawname(devstr), str_size); 472 } 473 474 carry_on: 475 return (corefs); 476 } 477 478 static int 479 open_and_intro(caddr_t devstr, int corefs) 480 { 481 int retval = 0; 482 483 if ((fsreadfd = open64(devstr, O_RDONLY)) < 0) { 484 (void) printf("Can't open %s: %s\n", devstr, strerror(errno)); 485 exitstat = EXNOSTAT; 486 retval = -1; 487 goto finish; 488 } 489 if (!preen || debug != 0) 490 (void) printf("** %s", devstr); 491 492 if (errorlocked) { 493 if (debug && elock_combuf != NULL) 494 (void) printf(" error-lock comment: \"%s\" ", 495 elock_combuf); 496 fflag = 1; 497 } 498 pid = getpid(); 499 if (nflag || roflag || (fswritefd = open64(devstr, O_WRONLY)) < 0) { 500 fswritefd = -1; 501 if (preen && !debug) 502 pfatal("(NO WRITE ACCESS)\n"); 503 (void) printf(" (NO WRITE)"); 504 } 505 if (!preen) 506 (void) printf("\n"); 507 else if (debug) 508 (void) printf(" pid %d\n", pid); 509 if (debug && (hotroot || (mountedfs != M_NOMNT))) { 510 (void) printf("** %s", devstr); 511 if (hotroot) 512 (void) printf(" is %s fs", magic_fs[corefs]); 513 if (mountedfs != M_NOMNT) 514 (void) printf(" and is mounted read-%s", 515 (mountedfs == M_RO) ? "only" : "write"); 516 if (errorlocked) 517 (void) printf(" and is error-locked"); 518 519 (void) printf(".\n"); 520 } 521 522 finish: 523 return (retval); 524 } 525 526 static int 527 find_superblock(caddr_t devstr) 528 { 529 int cg = 0; 530 int retval = 0; 531 int first; 532 int found; 533 calcsb_t style; 534 struct fs proto; 535 536 /* 537 * Check the superblock, looking for alternates if necessary. 538 * In more-recent times, some UFS instances get created with 539 * only the first ten and last ten superblock backups. Since 540 * if we can't get the necessary information from any of those, 541 * the odds are also against us for the ones in between, we'll 542 * just look at those twenty to save time. 543 */ 544 if (!read_super_block(1) || !checksb(1)) { 545 if (bflag || preen) { 546 retval = -1; 547 goto finish; 548 } 549 for (style = MKFS_STYLE; style < MAX_SB_STYLES; style++) { 550 if (reply("LOOK FOR ALTERNATE SUPERBLOCKS WITH %s", 551 calcsb_names[style]) == 0) 552 continue; 553 first = 1; 554 found = 0; 555 if (!calcsb(style, devstr, fsreadfd, &proto)) { 556 cg = proto.fs_ncg; 557 continue; 558 } 559 if (debug) { 560 (void) printf( 561 "debug: calcsb(%s) gave fpg %d, cgoffset %d, ", 562 calcsb_names[style], 563 proto.fs_fpg, proto.fs_cgoffset); 564 (void) printf("cgmask 0x%x, sblk %d, ncg %d\n", 565 proto.fs_cgmask, proto.fs_sblkno, 566 proto.fs_ncg); 567 } 568 for (cg = 0; cg < proto.fs_ncg; cg++) { 569 bflag = fsbtodb(&proto, cgsblock(&proto, cg)); 570 if (debug) 571 (void) printf( 572 "debug: trying block %lld\n", 573 (longlong_t)bflag); 574 if (read_super_block(0) && checksb(0)) { 575 (void) printf( 576 "FOUND ALTERNATE SUPERBLOCK %d WITH %s\n", 577 bflag, calcsb_names[style]); 578 if (reply( 579 "USE ALTERNATE SUPERBLOCK") == 1) { 580 found = 1; 581 break; 582 } 583 } 584 if (first && (cg >= 9)) { 585 first = 0; 586 if (proto.fs_ncg <= 9) 587 cg = proto.fs_ncg; 588 else if (proto.fs_ncg <= 19) 589 cg = 9; 590 else 591 cg = proto.fs_ncg - 10; 592 } 593 } 594 595 if (found) 596 break; 597 } 598 599 /* 600 * Didn't find one? Try to fake it. 601 */ 602 if (style >= MAX_SB_STYLES) { 603 pwarn("SEARCH FOR ALTERNATE SUPERBLOCKS FAILED.\n"); 604 for (style = MKFS_STYLE; style < MAX_SB_STYLES; 605 style++) { 606 if (reply("USE GENERIC SUPERBLOCK FROM %s", 607 calcsb_names[style]) == 1 && 608 calcsb(style, devstr, fsreadfd, &sblock)) { 609 break; 610 } 611 /* 612 * We got something from mkfs/newfs, so use it. 613 */ 614 if (style < MAX_SB_STYLES) 615 proto.fs_ncg = sblock.fs_ncg; 616 bflag = 0; 617 } 618 } 619 620 /* 621 * Still no luck? Tell the user they're on their own. 622 */ 623 if (style >= MAX_SB_STYLES) { 624 pwarn("SEARCH FOR ALTERNATE SUPERBLOCKS FAILED. " 625 "YOU MUST USE THE -o b OPTION\n" 626 "TO FSCK TO SPECIFY THE LOCATION OF A VALID " 627 "ALTERNATE SUPERBLOCK TO\n" 628 "SUPPLY NEEDED INFORMATION; SEE fsck(1M).\n"); 629 bflag = 0; 630 retval = -1; 631 goto finish; 632 } 633 634 /* 635 * Need to make sure a human really wants us to use 636 * this. -y mode could've gotten us this far, so 637 * we need to ask something that has to be answered 638 * in the negative. 639 * 640 * Note that we can't get here when preening. 641 */ 642 if (!found) { 643 pwarn("CALCULATED GENERIC SUPERBLOCK WITH %s\n", 644 calcsb_names[style]); 645 } else { 646 pwarn("FOUND ALTERNATE SUPERBLOCK AT %d USING %s\n", 647 bflag, calcsb_names[style]); 648 } 649 pwarn("If filesystem was created with manually-specified "); 650 pwarn("geometry, using\nauto-discovered superblock may "); 651 pwarn("result in irrecoverable damage to\nfilesystem and "); 652 pwarn("user data.\n"); 653 if (reply("CANCEL FILESYSTEM CHECK") == 1) { 654 if (cg >= 0) { 655 pwarn("Please verify that the indicated block " 656 "contains a proper\nsuperblock for the " 657 "filesystem (see fsdb(1M)).\n"); 658 if (yflag) 659 pwarn("\nFSCK was running in YES " 660 "mode. If you wish to run in " 661 "that mode using\nthe alternate " 662 "superblock, run " 663 "`fsck -y -o b=%d %s'.\n", 664 bflag, devstr); 665 } 666 retval = -1; 667 goto finish; 668 } 669 670 /* 671 * Pretend we found it as an alternate, so everything 672 * gets updated when we clean up at the end. 673 */ 674 if (!found) { 675 havesb = 1; 676 sblk.b_bno = fsbtodb(&sblock, cgsblock(&sblock, 0)); 677 bwrite(fswritefd, (caddr_t)&sblock, SBLOCK, SBSIZE); 678 write_altsb(fswritefd); 679 } 680 } 681 682 finish: 683 return (retval); 684 } 685 686 /* 687 * Check and potentially fix certain fields in the super block. 688 */ 689 static void 690 fixup_superblock(void) 691 { 692 /* 693 * Kernel looks for FS_OPTTIME, and assumes that if that's not 694 * what's there, it must be FS_OPTSPACE, so not fixing does not 695 * require setting iscorrupt. 696 */ 697 if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { 698 pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); 699 if (reply("SET TO DEFAULT") == 1) { 700 sblock.fs_optim = FS_OPTTIME; 701 sbdirty(); 702 } 703 } 704 if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { 705 pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 706 sblock.fs_minfree); 707 if (reply("SET TO DEFAULT") == 1) { 708 sblock.fs_minfree = 10; 709 sbdirty(); 710 } else if (sblock.fs_minfree < 0) { 711 /* 712 * Kernel uses minfree without verification, 713 * and a negative value would do bad things. 714 */ 715 iscorrupt = 1; 716 } 717 } 718 } 719 720 static int 721 initial_error_state_adjust(void) 722 { 723 int retval = 0; 724 725 /* do this right away to prevent any other fscks on this fs */ 726 switch (sblock.fs_clean) { 727 case FSBAD: 728 break; 729 case FSFIX: 730 if (preen) 731 errexit("ERROR-LOCKED; MARKED \"FSFIX\"\n"); 732 if (reply("marked FSFIX, CONTINUE") == 0) { 733 retval = -1; 734 goto finish; 735 } 736 break; 737 case FSCLEAN: 738 if (preen) 739 errexit("ERROR-LOCKED; MARKED \"FSCLEAN\"\n"); 740 if (reply("marked FSCLEAN, CONTINUE") == 0) { 741 retval = -1; 742 goto finish; 743 } 744 break; 745 default: 746 if (preen) { 747 if (debug) 748 pwarn("ERRORLOCKED; NOT MARKED \"FSBAD\"\n"); 749 else 750 errexit("ERRORLOCKED; NOT MARKED \"FSBAD\"\n"); 751 } else { 752 (void) printf("error-locked but not marked \"FSBAD\";"); 753 if (reply(" CONTINUE") == 0) { 754 retval = -1; 755 goto finish; 756 } 757 } 758 break; 759 } 760 761 if (!do_errorlock(LOCKFS_ELOCK)) { 762 if (preen) { 763 retval = -1; 764 goto finish; 765 } 766 if (reply("error-lock reset failed; CONTINUE") == 0) { 767 retval = -1; 768 goto finish; 769 } 770 } 771 772 sblock.fs_state = FSOKAY - (long)sblock.fs_time; 773 sblock.fs_clean = FSFIX; 774 sbdirty(); 775 write_altsb(fswritefd); 776 777 finish: 778 return (retval); 779 } 780 781 static void 782 getsummaryinfo(void) 783 { 784 size_t size; 785 int failed; 786 int asked; 787 int i, j; 788 caddr_t sip; 789 790 /* 791 * read in the summary info. 792 */ 793 sblock.fs_u.fs_csp = calloc(1, sblock.fs_cssize); 794 if (sblock.fs_u.fs_csp == NULL) 795 errexit( 796 "cannot allocate %u bytes for cylinder group summary info\n", 797 (unsigned)sblock.fs_cssize); 798 sip = (caddr_t)sblock.fs_u.fs_csp; 799 asked = 0; 800 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 801 size = sblock.fs_cssize - i < sblock.fs_bsize ? 802 sblock.fs_cssize - i : sblock.fs_bsize; 803 failed = fsck_bread(fsreadfd, sip, 804 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 805 size); 806 if (failed && !asked) { 807 pfatal("BAD SUMMARY INFORMATION"); 808 if (reply("CONTINUE") == 0) { 809 ckfini(); 810 exit(EXFNDERRS); 811 } 812 asked = 1; 813 } 814 sip += size; 815 } 816 } 817 818 /* 819 * Reverses the effects of getsummaryinfo(). 820 */ 821 static void 822 ungetsummaryinfo(void) 823 { 824 if ((sblk.b_un.b_fs != NULL) && 825 (sblk.b_un.b_fs->fs_u.fs_csp != NULL)) { 826 free(sblk.b_un.b_fs->fs_u.fs_csp); 827 sblk.b_un.b_fs->fs_u.fs_csp = NULL; 828 } 829 } 830 831 /* 832 * Allocate and initialize the global tables. 833 * It is the responsibility of the caller to clean up and allocations 834 * if an error is returned. 835 */ 836 static int 837 create_and_init_maps(void) 838 { 839 int64_t bmapsize; 840 int retval = 0; 841 842 maxfsblock = sblock.fs_size; 843 maxino = sblock.fs_ncg * sblock.fs_ipg; 844 845 bmapsize = roundup(howmany((uint64_t)maxfsblock, NBBY), 846 sizeof (short)); 847 blockmap = calloc((size_t)bmapsize, sizeof (char)); 848 if (blockmap == NULL) { 849 (void) printf("cannot alloc %lld bytes for blockmap\n", 850 (longlong_t)bmapsize); 851 retval = -1; 852 goto finish; 853 } 854 statemap = calloc((size_t)(maxino + 1), sizeof (*statemap)); 855 if (statemap == NULL) { 856 (void) printf("cannot alloc %lld bytes for statemap\n", 857 (longlong_t)(maxino + 1) * sizeof (*statemap)); 858 retval = -1; 859 goto finish; 860 } 861 lncntp = (short *)calloc((size_t)(maxino + 1), sizeof (short)); 862 if (lncntp == NULL) { 863 (void) printf("cannot alloc %lld bytes for lncntp\n", 864 (longlong_t)(maxino + 1) * sizeof (short)); 865 retval = -1; 866 goto finish; 867 } 868 869 /* 870 * If we had to fake up a superblock, it won't show that there 871 * are any directories at all. This causes problems when we 872 * use numdirs to calculate hash keys, so use something at least 873 * vaguely plausible. 874 */ 875 numdirs = sblock.fs_cstotal.cs_ndir; 876 if (numdirs == 0) 877 numdirs = sblock.fs_ipg * sblock.fs_ncg / 2; 878 listmax = numdirs + 10; 879 inpsort = (struct inoinfo **)calloc((unsigned)listmax, 880 sizeof (struct inoinfo *)); 881 inphead = (struct inoinfo **)calloc((unsigned)numdirs, 882 sizeof (struct inoinfo *)); 883 if (inpsort == NULL || inphead == NULL) { 884 (void) printf("cannot alloc %lld bytes for inphead\n", 885 (longlong_t)numdirs * sizeof (struct inoinfo *)); 886 retval = -1; 887 goto finish; 888 } 889 if (debug) { 890 if (listmax > USI_MAX) 891 errexit("create_and_init_maps: listmax overflowed\n"); 892 if (numdirs > USI_MAX) 893 errexit("create_and_init_maps: numdirs overflowed\n"); 894 } 895 896 numacls = numdirs; 897 aclmax = numdirs + 10; 898 aclpsort = (struct inoinfo **)calloc((unsigned)aclmax, 899 sizeof (struct inoinfo *)); 900 aclphead = (struct inoinfo **)calloc((unsigned)numacls, 901 sizeof (struct inoinfo *)); 902 if (aclpsort == NULL || aclphead == NULL) { 903 (void) printf("cannot alloc %lld bytes for aclphead\n", 904 (longlong_t)numacls * sizeof (struct inoinfo *)); 905 retval = -1; 906 goto finish; 907 } 908 if (debug) { 909 if (aclmax > USI_MAX) 910 errexit("create_and_init_maps: aclmax overflowed\n"); 911 if (numacls > USI_MAX) 912 errexit("create_and_init_maps: numacls overflowed\n"); 913 } 914 aclplast = 0L; 915 inplast = 0L; 916 917 finish: 918 return (retval); 919 } 920 921 caddr_t 922 setup(caddr_t dev) 923 { 924 int corefs; 925 static char devstr[MAXPATHLEN + 1]; 926 927 havesb = 0; 928 devname = devstr; 929 930 derive_devstr(dev, devstr, sizeof (devstr)); 931 errorlocked = is_errorlocked(devstr); 932 corefs = check_mount_state(devstr, sizeof (devstr)); 933 934 sblock_init(); 935 936 if (open_and_intro(devstr, corefs) == -1) 937 goto cleanup; 938 939 /* 940 * Check log state 941 */ 942 if (!logsetup(devstr)) 943 goto cleanup; 944 945 /* 946 * Flush fs if we're going to do anything other than a sanity check. 947 * Note, if logging then the fs was already flushed in logsetup(). 948 */ 949 if (!islog && !mflag) 950 flush_fs(); 951 952 if (find_superblock(devstr) == -1) 953 goto cleanup; 954 955 fixup_superblock(); 956 957 if (errorlocked && 958 (initial_error_state_adjust() == -1)) 959 goto cleanup; 960 961 /* 962 * asblk could be dirty because we found a mismatch between 963 * the primary superblock and one of its backups in checksb(). 964 */ 965 if (asblk.b_dirty && !bflag) { 966 (void) memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize); 967 flush(fswritefd, &asblk); 968 } 969 970 getsummaryinfo(); 971 972 /* 973 * if not error-locked, using the standard superblock, 974 * not bad log, not forced, preening, and is clean; 975 * stop checking 976 */ 977 if (!errorlocked && (bflag == 0) && 978 ((!islog || islogok) && 979 (fflag == 0) && preen && 980 (FSOKAY == (sblock.fs_state + sblock.fs_time)) && 981 ((sblock.fs_clean == FSLOG && islog) || 982 ((sblock.fs_clean == FSCLEAN) || (sblock.fs_clean == FSSTABLE))))) { 983 iscorrupt = 0; 984 printclean(); 985 goto cleanup; 986 } 987 988 if (create_and_init_maps() == -1) 989 goto nomaps; 990 991 bufinit(); 992 return (devstr); 993 994 nomaps: 995 ckfini(); 996 exitstat = EXERRFATAL; 997 /* FALLTHROUGH */ 998 999 cleanup: 1000 unbufinit(); 1001 uncreate_maps(); 1002 ungetsummaryinfo(); 1003 1004 /* 1005 * Can't get rid of the superblock buffer, because our 1006 * caller references it to generate the summary statistics. 1007 */ 1008 1009 return (NULL); 1010 } 1011 1012 /* 1013 * Undoes the allocations in create_and_init_maps() 1014 */ 1015 static void 1016 uncreate_maps(void) 1017 { 1018 /* 1019 * No ordering dependency amongst these, so they are here in 1020 * the same order they were calculated. 1021 */ 1022 if (blockmap != NULL) 1023 free(blockmap); 1024 if (statemap != NULL) 1025 free(statemap); 1026 if (lncntp != NULL) 1027 free(lncntp); 1028 if (inpsort != NULL) 1029 free(inpsort); 1030 if (inphead != NULL) 1031 free(inphead); 1032 if (aclpsort != NULL) 1033 free(aclpsort); 1034 if (aclphead != NULL) 1035 free(aclphead); 1036 } 1037 1038 /* 1039 * mkfs limits the size of the inode map to be no more than a third of 1040 * the cylinder group space. We'll use that value for sanity checking 1041 * the superblock's inode per group value. 1042 */ 1043 #define MAXIpG (roundup(sblock.fs_bsize * NBBY / 3, sblock.fs_inopb)) 1044 1045 /* 1046 * Check the super block and its summary info. 1047 */ 1048 static int 1049 checksb(int listerr) 1050 { 1051 caddr_t err; 1052 1053 /* 1054 * When the fs check is successfully completed, the alternate super 1055 * block at sblk.b_bno will be overwritten by ckfini() with the 1056 * repaired super block. 1057 */ 1058 sblk.b_bno = bflag ? bflag : (SBOFF / dev_bsize); 1059 sblk.b_size = SBSIZE; 1060 1061 /* 1062 * Sanity-check some of the values we are going to use later 1063 * in allocation requests. 1064 */ 1065 if (sblock.fs_cstotal.cs_ndir < 1 || 1066 sblock.fs_cstotal.cs_ndir > sblock.fs_ncg * sblock.fs_ipg) { 1067 if (verbose) 1068 (void) printf( 1069 "Found %d directories, should be between 1 and %d inclusive.\n", 1070 sblock.fs_cstotal.cs_ndir, 1071 sblock.fs_ncg * sblock.fs_ipg); 1072 err = "NUMBER OF DIRECTORIES OUT OF RANGE"; 1073 goto failedsb; 1074 } 1075 1076 if (sblock.fs_nrpos <= 0 || sblock.fs_postbloff < 0 || 1077 sblock.fs_cpc < 0 || 1078 (sblock.fs_postbloff + 1079 (sblock.fs_nrpos * sblock.fs_cpc * sizeof (short))) > 1080 sblock.fs_sbsize) { 1081 err = "ROTATIONAL POSITION TABLE SIZE OUT OF RANGE"; 1082 goto failedsb; 1083 } 1084 1085 if (sblock.fs_cssize != 1086 fragroundup(&sblock, sblock.fs_ncg * sizeof (struct csum))) { 1087 err = "SIZE OF CYLINDER GROUP SUMMARY AREA WRONG"; 1088 goto failedsb; 1089 } 1090 1091 if (sblock.fs_inopb != (sblock.fs_bsize / sizeof (struct dinode))) { 1092 err = "INOPB NONSENSICAL RELATIVE TO BSIZE"; 1093 goto failedsb; 1094 } 1095 1096 if (sblock.fs_bsize > MAXBSIZE) { 1097 err = "BLOCK SIZE LARGER THAN MAXIMUM SUPPORTED"; 1098 goto failedsb; 1099 } 1100 1101 if (sblock.fs_bsize != (sblock.fs_frag * sblock.fs_fsize)) { 1102 err = "FRAGS PER BLOCK OR FRAG SIZE WRONG"; 1103 goto failedsb; 1104 } 1105 1106 if (sblock.fs_dsize >= sblock.fs_size) { 1107 err = "NUMBER OF DATA BLOCKS OUT OF RANGE"; 1108 goto failedsb; 1109 } 1110 1111 #if 0 1112 if (sblock.fs_size > 1113 (sblock.fs_nsect * sblock.fs_ntrak * sblock.fs_ncyl)) { 1114 err = "FILESYSTEM SIZE LARGER THAN DEVICE"; 1115 goto failedsb; 1116 } 1117 #endif 1118 1119 /* 1120 * Check that the number of inodes per group isn't less than or 1121 * equal to zero. Also makes sure it isn't more than the 1122 * maximum number mkfs enforces. 1123 */ 1124 if (sblock.fs_ipg <= 0 || sblock.fs_ipg > MAXIpG) { 1125 err = "INODES PER GROUP OUT OF RANGE"; 1126 goto failedsb; 1127 } 1128 1129 if (sblock.fs_cgsize > sblock.fs_bsize) { 1130 err = "CG HEADER LARGER THAN ONE BLOCK"; 1131 goto failedsb; 1132 } 1133 1134 /* 1135 * Set all possible fields that could differ, then do check 1136 * of whole super block against an alternate super block. 1137 * When an alternate super-block is specified this check is skipped. 1138 */ 1139 (void) getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), 1140 (size_t)sblock.fs_sbsize); 1141 if (asblk.b_errs != 0) { 1142 brelse(&asblk); 1143 return (0); 1144 } 1145 if (bflag != 0) { 1146 /* 1147 * Invalidate clean flag and state information. 1148 * Note that we couldn't return until after the 1149 * above getblk(), because we're going to want to 1150 * update asblk when everything's done. 1151 */ 1152 sblock.fs_clean = FSACTIVE; 1153 sblock.fs_state = (long)sblock.fs_time; 1154 sblock.fs_reclaim = 0; 1155 sbdirty(); 1156 havesb = 1; 1157 return (1); 1158 } 1159 altsblock.fs_link = sblock.fs_link; 1160 altsblock.fs_rolled = sblock.fs_rolled; 1161 altsblock.fs_time = sblock.fs_time; 1162 altsblock.fs_state = sblock.fs_state; 1163 altsblock.fs_cstotal = sblock.fs_cstotal; 1164 altsblock.fs_cgrotor = sblock.fs_cgrotor; 1165 altsblock.fs_fmod = sblock.fs_fmod; 1166 altsblock.fs_clean = sblock.fs_clean; 1167 altsblock.fs_ronly = sblock.fs_ronly; 1168 altsblock.fs_flags = sblock.fs_flags; 1169 altsblock.fs_maxcontig = sblock.fs_maxcontig; 1170 altsblock.fs_minfree = sblock.fs_minfree; 1171 altsblock.fs_optim = sblock.fs_optim; 1172 altsblock.fs_rotdelay = sblock.fs_rotdelay; 1173 altsblock.fs_maxbpg = sblock.fs_maxbpg; 1174 altsblock.fs_logbno = sblock.fs_logbno; 1175 altsblock.fs_reclaim = sblock.fs_reclaim; 1176 altsblock.fs_si = sblock.fs_si; 1177 (void) memmove((void *)altsblock.fs_fsmnt, (void *)sblock.fs_fsmnt, 1178 sizeof (sblock.fs_fsmnt)); 1179 /* 1180 * The following should not have to be copied. 1181 */ 1182 (void) memmove((void *)altsblock.fs_u.fs_csp_pad, 1183 (void *)sblock.fs_u.fs_csp_pad, sizeof (sblock.fs_u.fs_csp_pad)); 1184 altsblock.fs_fsbtodb = sblock.fs_fsbtodb; 1185 altsblock.fs_npsect = sblock.fs_npsect; 1186 altsblock.fs_nrpos = sblock.fs_nrpos; 1187 if (memcmp((void *)&sblock, (void *)&altsblock, 1188 (size_t)sblock.fs_sbsize) != 0) { 1189 err = "BAD VALUES IN SUPER BLOCK"; 1190 goto failedsb; 1191 } 1192 havesb = 1; 1193 return (1); 1194 1195 failedsb: 1196 badsb(listerr, err); 1197 return (0); 1198 } 1199 1200 static void 1201 badsb(int listerr, caddr_t s) 1202 { 1203 if (!listerr) 1204 return; 1205 if (preen) 1206 (void) printf("%s: ", devname); 1207 (void) printf("BAD SUPERBLOCK AT BLOCK %d: %s\n", 1208 bflag != 0 ? bflag : SBLOCK, s); 1209 if (preen) { 1210 pwarn( 1211 "USE AN ALTERNATE SUPERBLOCK TO SUPPLY NEEDED INFORMATION;\n"); 1212 pwarn("e.g. fsck [-F ufs] -o b=# [special ...] \n"); 1213 exitstat = EXERRFATAL; 1214 pfatal( 1215 "where # is the alternate super block. SEE fsck_ufs(1M). \n"); 1216 } 1217 /* we're expected to return if not preening */ 1218 } 1219 1220 /* 1221 * Write out the super block into each of the alternate super blocks. 1222 */ 1223 void 1224 write_altsb(int fd) 1225 { 1226 int cylno; 1227 1228 for (cylno = 0; cylno < sblock.fs_ncg; cylno++) 1229 bwrite(fd, (caddr_t)&sblock, fsbtodb(&sblock, 1230 cgsblock(&sblock, cylno)), sblock.fs_sbsize); 1231 } 1232 1233 static void 1234 sblock_init(void) 1235 { 1236 fsmodified = 0; 1237 if (errorlocked) 1238 isdirty = 1; 1239 lfdir = 0; 1240 initbarea(&sblk); 1241 initbarea(&asblk); 1242 1243 /* 1244 * May have buffer left over from previous filesystem check. 1245 */ 1246 if (sblk.b_un.b_buf == NULL) 1247 sblk.b_un.b_buf = calloc(1, SBSIZE); 1248 if (asblk.b_un.b_buf == NULL) 1249 asblk.b_un.b_buf = calloc(1, SBSIZE); 1250 if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) 1251 errexit("cannot allocate space for superblock\n"); 1252 /* 1253 * Could get the actual sector size from the device here, 1254 * but considering how much would need to change in the rest 1255 * of the system before it'd be a problem for us, it's not 1256 * worth worrying about right now. 1257 */ 1258 dev_bsize = secsize = DEV_BSIZE; 1259 } 1260 1261 /* 1262 * Calculate a prototype superblock based on information in the disk label. 1263 * When done the cgsblock macro can be calculated and the fs_ncg field 1264 * can be used. Do NOT attempt to use other macros without verifying that 1265 * their needed information is available! 1266 * 1267 * In BSD, the disk label includes all sorts of useful information, 1268 * like cpg. Solaris doesn't have that, and deriving it (as well as 1269 * some other parameters) is difficult. Rather than duplicate the 1270 * code, just ask mkfs what it would've come up with by default. 1271 * Ideally, we'd just link in the code, but given the source base 1272 * involved, it's more practical to just get a binary dump. 1273 * 1274 * The one minor drawback to the above approach is that newfs and mkfs 1275 * will produce vastly different layouts for the same partition if 1276 * they're allowed to default everything. So, if the superblock that 1277 * mkfs gives us doesn't work for guessing where the alternates are, 1278 * we need to try newfs. 1279 */ 1280 static int 1281 calcsb(calcsb_t style, caddr_t dev, int devfd, struct fs *fs) 1282 { 1283 #define FROM_CHILD 0 1284 #define TO_FSCK 1 1285 #define CMD_IDX 0 1286 #define DEV_IDX 3 1287 #define SIZE_IDX 4 1288 1289 int child_pipe[2]; 1290 caddr_t mkfsline[] = { 1291 "", /* CMD_IDX */ 1292 "-o", 1293 "calcbinsb,N", 1294 NULL, /* DEV_IDX */ 1295 NULL, /* SIZE_IDX */ 1296 NULL 1297 }; 1298 caddr_t newfsline[] = { 1299 "", /* CMD_IDX */ 1300 "-B", 1301 "-N", 1302 NULL, /* DEV_IDX */ 1303 NULL 1304 }; 1305 int pending, transferred; 1306 caddr_t *cmdline; 1307 caddr_t target; 1308 caddr_t sizestr = NULL; 1309 caddr_t path_old, path_new, mkfs_dir, mkfs_path, newfs_path; 1310 caddr_t slash; 1311 diskaddr_t size; 1312 int devnull; 1313 1314 switch (style) { 1315 case MKFS_STYLE: 1316 if (debug) 1317 (void) printf("calcsb() going with style MKFS\n"); 1318 cmdline = mkfsline; 1319 break; 1320 case NEWFS_STYLE: 1321 if (debug) 1322 (void) printf("calcsb() going with style NEWFS\n"); 1323 cmdline = newfsline; 1324 break; 1325 default: 1326 if (debug) 1327 (void) printf("calcsb() doesn't undestand style %d\n", 1328 style); 1329 return (0); 1330 } 1331 1332 cmdline[DEV_IDX] = dev; 1333 1334 /* 1335 * Normally, only use the stock versions of the utilities. 1336 * However, if we're debugging, the odds are that we're 1337 * using experimental versions of them as well, so allow 1338 * some flexibility. 1339 */ 1340 mkfs_path = getenv("MKFS_PATH"); 1341 if (!debug || (mkfs_path == NULL)) 1342 mkfs_path = MKFS_PATH; 1343 1344 newfs_path = getenv("NEWFS_PATH"); 1345 if (!debug || (newfs_path == NULL)) 1346 newfs_path = NEWFS_PATH; 1347 1348 if (style == MKFS_STYLE) { 1349 cmdline[CMD_IDX] = mkfs_path; 1350 1351 size = getdisksize(dev, devfd); 1352 if (size == 0) 1353 return (0); 1354 1355 (void) fsck_asprintf(&sizestr, "%lld", (longlong_t)size); 1356 cmdline[SIZE_IDX] = sizestr; 1357 } else if (style == NEWFS_STYLE) { 1358 /* 1359 * Make sure that newfs will find the right version of mkfs. 1360 */ 1361 cmdline[CMD_IDX] = newfs_path; 1362 path_old = getenv("PATH"); 1363 /* mkfs_path is always initialized, despite lint's concerns */ 1364 mkfs_dir = strdup(mkfs_path); 1365 if (mkfs_dir == NULL) 1366 return (0); 1367 /* 1368 * If no location data for mkfs, don't need to do 1369 * anything about PATH. 1370 */ 1371 slash = strrchr(mkfs_dir, '/'); 1372 if (slash != NULL) { 1373 /* 1374 * Just want the dir, so discard the executable name. 1375 */ 1376 *slash = '\0'; 1377 1378 /* 1379 * newfs uses system() to find mkfs, so make sure 1380 * that the one we want to use is first on the 1381 * list. Don't free path_new upon success, as it 1382 * has become part of the environment. 1383 */ 1384 (void) fsck_asprintf(&path_new, "PATH=%s:%s", 1385 mkfs_dir, path_old); 1386 if (putenv(path_new) != 0) { 1387 free(mkfs_dir); 1388 free(path_new); 1389 return (0); 1390 } 1391 } 1392 free(mkfs_dir); 1393 } else { 1394 /* 1395 * Bad search style, quietly return failure. 1396 */ 1397 if (debug) { 1398 (void) printf("calcsb: got bad style number %d\n", 1399 (int)style); 1400 } 1401 return (0); 1402 } 1403 1404 if (pipe(child_pipe) < 0) { 1405 pfatal("calcsb: could not create pipe: %s\n", strerror(errno)); 1406 if (sizestr != NULL) 1407 free(sizestr); 1408 return (0); 1409 } 1410 1411 switch (fork()) { 1412 case -1: 1413 pfatal("calcsb: fork failed: %s\n", strerror(errno)); 1414 if (sizestr != NULL) 1415 free(sizestr); 1416 return (0); 1417 case 0: 1418 if (dup2(child_pipe[TO_FSCK], fileno(stdout)) < 0) { 1419 (void) printf( 1420 "calcsb: could not rename file descriptor: %s\n", 1421 strerror(errno)); 1422 exit(EXBADPARM); 1423 } 1424 devnull = open("/dev/null", O_WRONLY); 1425 if (devnull == -1) { 1426 (void) printf("calcsb: could not open /dev/null: %s\n", 1427 strerror(errno)); 1428 exit(EXBADPARM); 1429 } 1430 if (dup2(devnull, fileno(stderr)) < 0) { 1431 (void) printf( 1432 "calcsb: could not rename file descriptor: %s\n", 1433 strerror(errno)); 1434 exit(EXBADPARM); 1435 } 1436 (void) close(child_pipe[FROM_CHILD]); 1437 (void) execv(cmdline[CMD_IDX], cmdline); 1438 (void) printf("calcsb: could not exec %s: %s\n", 1439 cmdline[CMD_IDX], strerror(errno)); 1440 exit(EXBADPARM); 1441 /* NOTREACHED */ 1442 default: 1443 break; 1444 } 1445 1446 (void) close(child_pipe[TO_FSCK]); 1447 if (sizestr != NULL) 1448 free(sizestr); 1449 1450 pending = sizeof (struct fs); 1451 target = (caddr_t)fs; 1452 do { 1453 transferred = read(child_pipe[FROM_CHILD], target, pending); 1454 pending -= transferred; 1455 target += transferred; 1456 } while ((pending > 0) && (transferred > 0)); 1457 1458 if (pending > 0) { 1459 if (transferred < 0) 1460 pfatal( 1461 "calcsb: binary read of superblock from %s failed: %s\n", 1462 (style == MKFS_STYLE) ? "mkfs" : "newfs", 1463 (transferred < 0) ? strerror(errno) : ""); 1464 else 1465 pfatal( 1466 "calcsb: short read of superblock from %s\n", 1467 (style == MKFS_STYLE) ? "mkfs" : "newfs"); 1468 return (0); 1469 } 1470 1471 (void) close(child_pipe[FROM_CHILD]); 1472 (void) wait(NULL); 1473 1474 if ((fs->fs_magic != FS_MAGIC) && 1475 (fs->fs_magic != MTB_UFS_MAGIC)) 1476 return (0); 1477 1478 return (1); 1479 } 1480