1 /* 2 * Copyright 2006 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 (void) strlcpy(devstr, dev, str_size); 392 break; 393 case S_IFCHR: 394 case S_IFBLK: 395 (void) strlcpy(devstr, unrawname(dev), str_size); 396 break; 397 default: 398 exitstat = EXBADPARM; 399 errexit("fsck: %s must be a mountpoint, device, or file", dev); 400 /* NOTREACHED */ 401 } 402 } 403 404 /* 405 * Reports the index of the magic filesystem that mntp names. 406 * If it does not correspond any of them, returns zero (hence 407 * the backwards loop). 408 */ 409 static int 410 which_corefs(const caddr_t mntp) 411 { 412 int corefs; 413 414 for (corefs = MAGIC_LIMIT - 1; corefs > 0; corefs--) 415 if (strcmp(mntp, magic_fs[corefs]) == 0) 416 break; 417 418 return (corefs); 419 } 420 421 /* 422 * - set mount_point to NULL 423 * - if name is mounted (search mnttab) 424 * - if it is a device, clear rflag 425 * - if mounted on /, /usr, or /var, set corefs 426 * - if corefs and read-only, set hotroot and continue 427 * - if errorlocked, continue 428 * - if preening, bail 429 * - ask user whether to continue, bail if not 430 * - if it is a device and not mounted and rflag, convert 431 * name to raw version 432 */ 433 static int 434 check_mount_state(caddr_t devstr, size_t str_size) 435 { 436 int corefs = 0; 437 int is_dev = 0; 438 struct stat statb; 439 440 if (stat(devstr, &statb) < 0) { 441 exitstat = EXNOSTAT; 442 errexit("fsck: could not stat %s: %s", devstr, strerror(errno)); 443 } 444 if (S_ISCHR(statb.st_mode) || S_ISBLK(statb.st_mode)) 445 is_dev = 1; 446 447 /* 448 * mounted() will update mount_point when returning true. 449 */ 450 mount_point = NULL; 451 if ((mountedfs = mounted(devstr, devstr, str_size)) != M_NOMNT) { 452 if (is_dev) 453 rflag = 0; 454 corefs = which_corefs(mount_point); 455 if (corefs && (mountedfs == M_RO)) { 456 hotroot++; 457 } else if (errorlocked) { 458 goto carry_on; 459 } else if (preen) { 460 exitstat = EXMOUNTED; 461 pfatal("%s IS CURRENTLY MOUNTED%s.", 462 devstr, mountedfs == M_RW ? " READ/WRITE" : ""); 463 } else { 464 if (!nflag && !mflag) { 465 pwarn("%s IS CURRENTLY MOUNTED READ/%s.", 466 devstr, mountedfs == M_RW ? "WRITE" : 467 "ONLY"); 468 if (reply("CONTINUE") == 0) { 469 exitstat = EXMOUNTED; 470 errexit("Program terminated"); 471 } 472 } 473 } 474 } else if (is_dev && rflag) { 475 (void) strlcpy(devstr, rawname(devstr), str_size); 476 } 477 478 carry_on: 479 return (corefs); 480 } 481 482 static int 483 open_and_intro(caddr_t devstr, int corefs) 484 { 485 int retval = 0; 486 487 if ((fsreadfd = open64(devstr, O_RDONLY)) < 0) { 488 (void) printf("Can't open %s: %s\n", devstr, strerror(errno)); 489 exitstat = EXNOSTAT; 490 retval = -1; 491 goto finish; 492 } 493 if (!preen || debug != 0) 494 (void) printf("** %s", devstr); 495 496 if (errorlocked) { 497 if (debug && elock_combuf != NULL) 498 (void) printf(" error-lock comment: \"%s\" ", 499 elock_combuf); 500 fflag = 1; 501 } 502 pid = getpid(); 503 if (nflag || roflag || (fswritefd = open64(devstr, O_WRONLY)) < 0) { 504 fswritefd = -1; 505 if (preen && !debug) 506 pfatal("(NO WRITE ACCESS)\n"); 507 (void) printf(" (NO WRITE)"); 508 } 509 if (!preen) 510 (void) printf("\n"); 511 else if (debug) 512 (void) printf(" pid %d\n", pid); 513 if (debug && (hotroot || (mountedfs != M_NOMNT))) { 514 (void) printf("** %s", devstr); 515 if (hotroot) 516 (void) printf(" is %s fs", magic_fs[corefs]); 517 if (mountedfs != M_NOMNT) 518 (void) printf(" and is mounted read-%s", 519 (mountedfs == M_RO) ? "only" : "write"); 520 if (errorlocked) 521 (void) printf(" and is error-locked"); 522 523 (void) printf(".\n"); 524 } 525 526 finish: 527 return (retval); 528 } 529 530 static int 531 find_superblock(caddr_t devstr) 532 { 533 int cg = 0; 534 int retval = 0; 535 int first; 536 int found; 537 calcsb_t style; 538 struct fs proto; 539 540 /* 541 * Check the superblock, looking for alternates if necessary. 542 * In more-recent times, some UFS instances get created with 543 * only the first ten and last ten superblock backups. Since 544 * if we can't get the necessary information from any of those, 545 * the odds are also against us for the ones in between, we'll 546 * just look at those twenty to save time. 547 */ 548 if (!read_super_block(1) || !checksb(1)) { 549 if (bflag || preen) { 550 retval = -1; 551 goto finish; 552 } 553 for (style = MKFS_STYLE; style < MAX_SB_STYLES; style++) { 554 if (reply("LOOK FOR ALTERNATE SUPERBLOCKS WITH %s", 555 calcsb_names[style]) == 0) 556 continue; 557 first = 1; 558 found = 0; 559 if (!calcsb(style, devstr, fsreadfd, &proto)) { 560 cg = proto.fs_ncg; 561 continue; 562 } 563 if (debug) { 564 (void) printf( 565 "debug: calcsb(%s) gave fpg %d, cgoffset %d, ", 566 calcsb_names[style], 567 proto.fs_fpg, proto.fs_cgoffset); 568 (void) printf("cgmask 0x%x, sblk %d, ncg %d\n", 569 proto.fs_cgmask, proto.fs_sblkno, 570 proto.fs_ncg); 571 } 572 for (cg = 0; cg < proto.fs_ncg; cg++) { 573 bflag = fsbtodb(&proto, cgsblock(&proto, cg)); 574 if (debug) 575 (void) printf( 576 "debug: trying block %lld\n", 577 (longlong_t)bflag); 578 if (read_super_block(0) && checksb(0)) { 579 (void) printf( 580 "FOUND ALTERNATE SUPERBLOCK %d WITH %s\n", 581 bflag, calcsb_names[style]); 582 if (reply( 583 "USE ALTERNATE SUPERBLOCK") == 1) { 584 found = 1; 585 break; 586 } 587 } 588 if (first && (cg >= 9)) { 589 first = 0; 590 if (proto.fs_ncg <= 9) 591 cg = proto.fs_ncg; 592 else if (proto.fs_ncg <= 19) 593 cg = 9; 594 else 595 cg = proto.fs_ncg - 10; 596 } 597 } 598 599 if (found) 600 break; 601 } 602 603 /* 604 * Didn't find one? Try to fake it. 605 */ 606 if (style >= MAX_SB_STYLES) { 607 pwarn("SEARCH FOR ALTERNATE SUPERBLOCKS FAILED.\n"); 608 for (style = MKFS_STYLE; style < MAX_SB_STYLES; 609 style++) { 610 if (reply("USE GENERIC SUPERBLOCK FROM %s", 611 calcsb_names[style]) == 1 && 612 calcsb(style, devstr, fsreadfd, &sblock)) { 613 break; 614 } 615 /* 616 * We got something from mkfs/newfs, so use it. 617 */ 618 if (style < MAX_SB_STYLES) 619 proto.fs_ncg = sblock.fs_ncg; 620 bflag = 0; 621 } 622 } 623 624 /* 625 * Still no luck? Tell the user they're on their own. 626 */ 627 if (style >= MAX_SB_STYLES) { 628 pwarn("SEARCH FOR ALTERNATE SUPERBLOCKS FAILED. " 629 "YOU MUST USE THE -o b OPTION\n" 630 "TO FSCK TO SPECIFY THE LOCATION OF A VALID " 631 "ALTERNATE SUPERBLOCK TO\n" 632 "SUPPLY NEEDED INFORMATION; SEE fsck(1M).\n"); 633 bflag = 0; 634 retval = -1; 635 goto finish; 636 } 637 638 /* 639 * Need to make sure a human really wants us to use 640 * this. -y mode could've gotten us this far, so 641 * we need to ask something that has to be answered 642 * in the negative. 643 * 644 * Note that we can't get here when preening. 645 */ 646 if (!found) { 647 pwarn("CALCULATED GENERIC SUPERBLOCK WITH %s\n", 648 calcsb_names[style]); 649 } else { 650 pwarn("FOUND ALTERNATE SUPERBLOCK AT %d USING %s\n", 651 bflag, calcsb_names[style]); 652 } 653 pwarn("If filesystem was created with manually-specified "); 654 pwarn("geometry, using\nauto-discovered superblock may "); 655 pwarn("result in irrecoverable damage to\nfilesystem and "); 656 pwarn("user data.\n"); 657 if (reply("CANCEL FILESYSTEM CHECK") == 1) { 658 if (cg >= 0) { 659 pwarn("Please verify that the indicated block " 660 "contains a proper\nsuperblock for the " 661 "filesystem (see fsdb(1M)).\n"); 662 if (yflag) 663 pwarn("\nFSCK was running in YES " 664 "mode. If you wish to run in " 665 "that mode using\nthe alternate " 666 "superblock, run " 667 "`fsck -y -o b=%d %s'.\n", 668 bflag, devstr); 669 } 670 retval = -1; 671 goto finish; 672 } 673 674 /* 675 * Pretend we found it as an alternate, so everything 676 * gets updated when we clean up at the end. 677 */ 678 if (!found) { 679 havesb = 1; 680 sblk.b_bno = fsbtodb(&sblock, cgsblock(&sblock, 0)); 681 bwrite(fswritefd, (caddr_t)&sblock, SBLOCK, SBSIZE); 682 write_altsb(fswritefd); 683 } 684 } 685 686 finish: 687 return (retval); 688 } 689 690 /* 691 * Check and potentially fix certain fields in the super block. 692 */ 693 static void 694 fixup_superblock(void) 695 { 696 /* 697 * Kernel looks for FS_OPTTIME, and assumes that if that's not 698 * what's there, it must be FS_OPTSPACE, so not fixing does not 699 * require setting iscorrupt. 700 */ 701 if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { 702 pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); 703 if (reply("SET TO DEFAULT") == 1) { 704 sblock.fs_optim = FS_OPTTIME; 705 sbdirty(); 706 } 707 } 708 if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { 709 pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 710 sblock.fs_minfree); 711 if (reply("SET TO DEFAULT") == 1) { 712 sblock.fs_minfree = 10; 713 sbdirty(); 714 } else if (sblock.fs_minfree < 0) { 715 /* 716 * Kernel uses minfree without verification, 717 * and a negative value would do bad things. 718 */ 719 iscorrupt = 1; 720 } 721 } 722 } 723 724 static int 725 initial_error_state_adjust(void) 726 { 727 int retval = 0; 728 729 /* do this right away to prevent any other fscks on this fs */ 730 switch (sblock.fs_clean) { 731 case FSBAD: 732 break; 733 case FSFIX: 734 if (preen) 735 errexit("ERROR-LOCKED; MARKED \"FSFIX\"\n"); 736 if (reply("marked FSFIX, CONTINUE") == 0) { 737 retval = -1; 738 goto finish; 739 } 740 break; 741 case FSCLEAN: 742 if (preen) 743 errexit("ERROR-LOCKED; MARKED \"FSCLEAN\"\n"); 744 if (reply("marked FSCLEAN, CONTINUE") == 0) { 745 retval = -1; 746 goto finish; 747 } 748 break; 749 default: 750 if (preen) { 751 if (debug) 752 pwarn("ERRORLOCKED; NOT MARKED \"FSBAD\"\n"); 753 else 754 errexit("ERRORLOCKED; NOT MARKED \"FSBAD\"\n"); 755 } else { 756 (void) printf("error-locked but not marked \"FSBAD\";"); 757 if (reply(" CONTINUE") == 0) { 758 retval = -1; 759 goto finish; 760 } 761 } 762 break; 763 } 764 765 if (!do_errorlock(LOCKFS_ELOCK)) { 766 if (preen) { 767 retval = -1; 768 goto finish; 769 } 770 if (reply("error-lock reset failed; CONTINUE") == 0) { 771 retval = -1; 772 goto finish; 773 } 774 } 775 776 sblock.fs_state = FSOKAY - (long)sblock.fs_time; 777 sblock.fs_clean = FSFIX; 778 sbdirty(); 779 write_altsb(fswritefd); 780 781 finish: 782 return (retval); 783 } 784 785 static void 786 getsummaryinfo(void) 787 { 788 size_t size; 789 int failed; 790 int asked; 791 int i, j; 792 caddr_t sip; 793 794 /* 795 * read in the summary info. 796 */ 797 sblock.fs_u.fs_csp = calloc(1, sblock.fs_cssize); 798 if (sblock.fs_u.fs_csp == NULL) 799 errexit( 800 "cannot allocate %u bytes for cylinder group summary info\n", 801 (unsigned)sblock.fs_cssize); 802 sip = (caddr_t)sblock.fs_u.fs_csp; 803 asked = 0; 804 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 805 size = sblock.fs_cssize - i < sblock.fs_bsize ? 806 sblock.fs_cssize - i : sblock.fs_bsize; 807 failed = fsck_bread(fsreadfd, sip, 808 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 809 size); 810 if (failed && !asked) { 811 pfatal("BAD SUMMARY INFORMATION"); 812 if (reply("CONTINUE") == 0) { 813 ckfini(); 814 exit(EXFNDERRS); 815 } 816 asked = 1; 817 } 818 sip += size; 819 } 820 } 821 822 /* 823 * Reverses the effects of getsummaryinfo(). 824 */ 825 static void 826 ungetsummaryinfo(void) 827 { 828 if ((sblk.b_un.b_fs != NULL) && 829 (sblk.b_un.b_fs->fs_u.fs_csp != NULL)) { 830 free(sblk.b_un.b_fs->fs_u.fs_csp); 831 sblk.b_un.b_fs->fs_u.fs_csp = NULL; 832 } 833 } 834 835 /* 836 * Allocate and initialize the global tables. 837 * It is the responsibility of the caller to clean up and allocations 838 * if an error is returned. 839 */ 840 static int 841 create_and_init_maps(void) 842 { 843 int64_t bmapsize; 844 int retval = 0; 845 846 maxfsblock = sblock.fs_size; 847 maxino = sblock.fs_ncg * sblock.fs_ipg; 848 849 bmapsize = roundup(howmany((uint64_t)maxfsblock, NBBY), 850 sizeof (short)); 851 blockmap = calloc((size_t)bmapsize, sizeof (char)); 852 if (blockmap == NULL) { 853 (void) printf("cannot alloc %lld bytes for blockmap\n", 854 (longlong_t)bmapsize); 855 retval = -1; 856 goto finish; 857 } 858 statemap = calloc((size_t)(maxino + 1), sizeof (*statemap)); 859 if (statemap == NULL) { 860 (void) printf("cannot alloc %lld bytes for statemap\n", 861 (longlong_t)(maxino + 1) * sizeof (*statemap)); 862 retval = -1; 863 goto finish; 864 } 865 lncntp = (short *)calloc((size_t)(maxino + 1), sizeof (short)); 866 if (lncntp == NULL) { 867 (void) printf("cannot alloc %lld bytes for lncntp\n", 868 (longlong_t)(maxino + 1) * sizeof (short)); 869 retval = -1; 870 goto finish; 871 } 872 873 /* 874 * If we had to fake up a superblock, it won't show that there 875 * are any directories at all. This causes problems when we 876 * use numdirs to calculate hash keys, so use something at least 877 * vaguely plausible. 878 */ 879 numdirs = sblock.fs_cstotal.cs_ndir; 880 if (numdirs == 0) 881 numdirs = sblock.fs_ipg * sblock.fs_ncg / 2; 882 listmax = numdirs + 10; 883 inpsort = (struct inoinfo **)calloc((unsigned)listmax, 884 sizeof (struct inoinfo *)); 885 inphead = (struct inoinfo **)calloc((unsigned)numdirs, 886 sizeof (struct inoinfo *)); 887 if (inpsort == NULL || inphead == NULL) { 888 (void) printf("cannot alloc %lld bytes for inphead\n", 889 (longlong_t)numdirs * sizeof (struct inoinfo *)); 890 retval = -1; 891 goto finish; 892 } 893 if (debug) { 894 if (listmax > ULONG_MAX) 895 errexit("create_and_init_maps: listmax overflowed\n"); 896 if (numdirs > ULONG_MAX) 897 errexit("create_and_init_maps: numdirs overflowed\n"); 898 } 899 900 numacls = numdirs; 901 aclmax = numdirs + 10; 902 aclpsort = (struct inoinfo **)calloc((unsigned)aclmax, 903 sizeof (struct inoinfo *)); 904 aclphead = (struct inoinfo **)calloc((unsigned)numacls, 905 sizeof (struct inoinfo *)); 906 if (aclpsort == NULL || aclphead == NULL) { 907 (void) printf("cannot alloc %lld bytes for aclphead\n", 908 (longlong_t)numacls * sizeof (struct inoinfo *)); 909 retval = -1; 910 goto finish; 911 } 912 if (debug) { 913 if (aclmax > ULONG_MAX) 914 errexit("create_and_init_maps: aclmax overflowed\n"); 915 if (numacls > ULONG_MAX) 916 errexit("create_and_init_maps: numacls overflowed\n"); 917 } 918 aclplast = 0L; 919 inplast = 0L; 920 921 finish: 922 return (retval); 923 } 924 925 caddr_t 926 setup(caddr_t dev) 927 { 928 int corefs; 929 static char devstr[MAXPATHLEN + 1]; 930 931 havesb = 0; 932 devname = devstr; 933 934 derive_devstr(dev, devstr, sizeof (devstr)); 935 errorlocked = is_errorlocked(devstr); 936 corefs = check_mount_state(devstr, sizeof (devstr)); 937 938 sblock_init(); 939 940 if (open_and_intro(devstr, corefs) == -1) 941 goto cleanup; 942 943 if (mflag && mounted(devstr, devstr, 944 sizeof (devstr)) == M_RW) 945 return (devstr); 946 947 /* 948 * Check log state 949 */ 950 if (!logsetup(devstr)) 951 goto cleanup; 952 953 /* 954 * Flush fs if we're going to do anything other than a sanity check. 955 * Note, if logging then the fs was already flushed in logsetup(). 956 */ 957 if (!islog && !mflag) 958 flush_fs(); 959 960 if (find_superblock(devstr) == -1) 961 goto cleanup; 962 963 fixup_superblock(); 964 965 if (errorlocked && 966 (initial_error_state_adjust() == -1)) 967 goto cleanup; 968 969 /* 970 * asblk could be dirty because we found a mismatch between 971 * the primary superblock and one of its backups in checksb(). 972 */ 973 if (asblk.b_dirty && !bflag) { 974 (void) memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize); 975 flush(fswritefd, &asblk); 976 } 977 978 getsummaryinfo(); 979 980 /* 981 * if not error-locked, using the standard superblock, 982 * not bad log, not forced, preening, and is clean; 983 * stop checking 984 */ 985 if (!errorlocked && (bflag == 0) && 986 ((!islog || islogok) && 987 (fflag == 0) && preen && 988 (FSOKAY == (sblock.fs_state + sblock.fs_time)) && 989 ((sblock.fs_clean == FSLOG && islog) || 990 ((sblock.fs_clean == FSCLEAN) || (sblock.fs_clean == FSSTABLE))))) { 991 iscorrupt = 0; 992 printclean(); 993 goto cleanup; 994 } 995 996 if (create_and_init_maps() == -1) 997 goto nomaps; 998 999 bufinit(); 1000 return (devstr); 1001 1002 nomaps: 1003 ckfini(); 1004 exitstat = EXERRFATAL; 1005 /* FALLTHROUGH */ 1006 1007 cleanup: 1008 unbufinit(); 1009 uncreate_maps(); 1010 ungetsummaryinfo(); 1011 1012 /* 1013 * Can't get rid of the superblock buffer, because our 1014 * caller references it to generate the summary statistics. 1015 */ 1016 1017 return (NULL); 1018 } 1019 1020 /* 1021 * Undoes the allocations in create_and_init_maps() 1022 */ 1023 static void 1024 uncreate_maps(void) 1025 { 1026 /* 1027 * No ordering dependency amongst these, so they are here in 1028 * the same order they were calculated. 1029 */ 1030 if (blockmap != NULL) 1031 free(blockmap); 1032 if (statemap != NULL) 1033 free(statemap); 1034 if (lncntp != NULL) 1035 free(lncntp); 1036 if (inpsort != NULL) 1037 free(inpsort); 1038 if (inphead != NULL) 1039 free(inphead); 1040 if (aclpsort != NULL) 1041 free(aclpsort); 1042 if (aclphead != NULL) 1043 free(aclphead); 1044 } 1045 1046 /* 1047 * mkfs limits the size of the inode map to be no more than a third of 1048 * the cylinder group space. We'll use that value for sanity checking 1049 * the superblock's inode per group value. 1050 */ 1051 #define MAXIpG (roundup(sblock.fs_bsize * NBBY / 3, sblock.fs_inopb)) 1052 1053 /* 1054 * Check the super block and its summary info. 1055 */ 1056 static int 1057 checksb(int listerr) 1058 { 1059 caddr_t err; 1060 1061 /* 1062 * When the fs check is successfully completed, the alternate super 1063 * block at sblk.b_bno will be overwritten by ckfini() with the 1064 * repaired super block. 1065 */ 1066 sblk.b_bno = bflag ? bflag : (SBOFF / dev_bsize); 1067 sblk.b_size = SBSIZE; 1068 1069 /* 1070 * Sanity-check some of the values we are going to use later 1071 * in allocation requests. 1072 */ 1073 if (sblock.fs_cstotal.cs_ndir < 1 || 1074 sblock.fs_cstotal.cs_ndir > sblock.fs_ncg * sblock.fs_ipg) { 1075 if (verbose) 1076 (void) printf( 1077 "Found %d directories, should be between 1 and %d inclusive.\n", 1078 sblock.fs_cstotal.cs_ndir, 1079 sblock.fs_ncg * sblock.fs_ipg); 1080 err = "NUMBER OF DIRECTORIES OUT OF RANGE"; 1081 goto failedsb; 1082 } 1083 1084 if (sblock.fs_nrpos <= 0 || sblock.fs_postbloff < 0 || 1085 sblock.fs_cpc < 0 || 1086 (sblock.fs_postbloff + 1087 (sblock.fs_nrpos * sblock.fs_cpc * sizeof (short))) > 1088 sblock.fs_sbsize) { 1089 err = "ROTATIONAL POSITION TABLE SIZE OUT OF RANGE"; 1090 goto failedsb; 1091 } 1092 1093 if (sblock.fs_cssize != 1094 fragroundup(&sblock, sblock.fs_ncg * sizeof (struct csum))) { 1095 err = "SIZE OF CYLINDER GROUP SUMMARY AREA WRONG"; 1096 goto failedsb; 1097 } 1098 1099 if (sblock.fs_inopb != (sblock.fs_bsize / sizeof (struct dinode))) { 1100 err = "INOPB NONSENSICAL RELATIVE TO BSIZE"; 1101 goto failedsb; 1102 } 1103 1104 if (sblock.fs_bsize > MAXBSIZE) { 1105 err = "BLOCK SIZE LARGER THAN MAXIMUM SUPPORTED"; 1106 goto failedsb; 1107 } 1108 1109 if (sblock.fs_bsize != (sblock.fs_frag * sblock.fs_fsize)) { 1110 err = "FRAGS PER BLOCK OR FRAG SIZE WRONG"; 1111 goto failedsb; 1112 } 1113 1114 if (sblock.fs_dsize >= sblock.fs_size) { 1115 err = "NUMBER OF DATA BLOCKS OUT OF RANGE"; 1116 goto failedsb; 1117 } 1118 1119 #if 0 1120 if (sblock.fs_size > 1121 (sblock.fs_nsect * sblock.fs_ntrak * sblock.fs_ncyl)) { 1122 err = "FILESYSTEM SIZE LARGER THAN DEVICE"; 1123 goto failedsb; 1124 } 1125 #endif 1126 1127 /* 1128 * Check that the number of inodes per group isn't less than or 1129 * equal to zero. Also makes sure it isn't more than the 1130 * maximum number mkfs enforces. 1131 */ 1132 if (sblock.fs_ipg <= 0 || sblock.fs_ipg > MAXIpG) { 1133 err = "INODES PER GROUP OUT OF RANGE"; 1134 goto failedsb; 1135 } 1136 1137 if (sblock.fs_cgsize > sblock.fs_bsize) { 1138 err = "CG HEADER LARGER THAN ONE BLOCK"; 1139 goto failedsb; 1140 } 1141 1142 /* 1143 * Set all possible fields that could differ, then do check 1144 * of whole super block against an alternate super block. 1145 * When an alternate super-block is specified this check is skipped. 1146 */ 1147 (void) getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), 1148 (size_t)sblock.fs_sbsize); 1149 if (asblk.b_errs != 0) { 1150 brelse(&asblk); 1151 return (0); 1152 } 1153 if (bflag != 0) { 1154 /* 1155 * Invalidate clean flag and state information. 1156 * Note that we couldn't return until after the 1157 * above getblk(), because we're going to want to 1158 * update asblk when everything's done. 1159 */ 1160 sblock.fs_clean = FSACTIVE; 1161 sblock.fs_state = (long)sblock.fs_time; 1162 sblock.fs_reclaim = 0; 1163 sbdirty(); 1164 havesb = 1; 1165 return (1); 1166 } 1167 altsblock.fs_link = sblock.fs_link; 1168 altsblock.fs_rolled = sblock.fs_rolled; 1169 altsblock.fs_time = sblock.fs_time; 1170 altsblock.fs_state = sblock.fs_state; 1171 altsblock.fs_cstotal = sblock.fs_cstotal; 1172 altsblock.fs_cgrotor = sblock.fs_cgrotor; 1173 altsblock.fs_fmod = sblock.fs_fmod; 1174 altsblock.fs_clean = sblock.fs_clean; 1175 altsblock.fs_ronly = sblock.fs_ronly; 1176 altsblock.fs_flags = sblock.fs_flags; 1177 altsblock.fs_maxcontig = sblock.fs_maxcontig; 1178 altsblock.fs_minfree = sblock.fs_minfree; 1179 altsblock.fs_optim = sblock.fs_optim; 1180 altsblock.fs_rotdelay = sblock.fs_rotdelay; 1181 altsblock.fs_maxbpg = sblock.fs_maxbpg; 1182 altsblock.fs_logbno = sblock.fs_logbno; 1183 altsblock.fs_reclaim = sblock.fs_reclaim; 1184 altsblock.fs_si = sblock.fs_si; 1185 (void) memmove((void *)altsblock.fs_fsmnt, (void *)sblock.fs_fsmnt, 1186 sizeof (sblock.fs_fsmnt)); 1187 /* 1188 * The following should not have to be copied. 1189 */ 1190 (void) memmove((void *)altsblock.fs_u.fs_csp_pad, 1191 (void *)sblock.fs_u.fs_csp_pad, sizeof (sblock.fs_u.fs_csp_pad)); 1192 altsblock.fs_fsbtodb = sblock.fs_fsbtodb; 1193 altsblock.fs_npsect = sblock.fs_npsect; 1194 altsblock.fs_nrpos = sblock.fs_nrpos; 1195 if (memcmp((void *)&sblock, (void *)&altsblock, 1196 (size_t)sblock.fs_sbsize) != 0) { 1197 err = "BAD VALUES IN SUPER BLOCK"; 1198 goto failedsb; 1199 } 1200 havesb = 1; 1201 return (1); 1202 1203 failedsb: 1204 badsb(listerr, err); 1205 return (0); 1206 } 1207 1208 static void 1209 badsb(int listerr, caddr_t s) 1210 { 1211 if (!listerr) 1212 return; 1213 if (preen) 1214 (void) printf("%s: ", devname); 1215 (void) printf("BAD SUPERBLOCK AT BLOCK %d: %s\n", 1216 bflag != 0 ? bflag : SBLOCK, s); 1217 if (preen) { 1218 pwarn( 1219 "USE AN ALTERNATE SUPERBLOCK TO SUPPLY NEEDED INFORMATION;\n"); 1220 pwarn("e.g. fsck [-F ufs] -o b=# [special ...] \n"); 1221 exitstat = EXERRFATAL; 1222 pfatal( 1223 "where # is the alternate super block. SEE fsck_ufs(1M). \n"); 1224 } 1225 /* we're expected to return if not preening */ 1226 } 1227 1228 /* 1229 * Write out the super block into each of the alternate super blocks. 1230 */ 1231 void 1232 write_altsb(int fd) 1233 { 1234 int cylno; 1235 1236 for (cylno = 0; cylno < sblock.fs_ncg; cylno++) 1237 bwrite(fd, (caddr_t)&sblock, fsbtodb(&sblock, 1238 cgsblock(&sblock, cylno)), sblock.fs_sbsize); 1239 } 1240 1241 static void 1242 sblock_init(void) 1243 { 1244 fsmodified = 0; 1245 if (errorlocked) 1246 isdirty = 1; 1247 lfdir = 0; 1248 initbarea(&sblk); 1249 initbarea(&asblk); 1250 1251 /* 1252 * May have buffer left over from previous filesystem check. 1253 */ 1254 if (sblk.b_un.b_buf == NULL) 1255 sblk.b_un.b_buf = calloc(1, SBSIZE); 1256 if (asblk.b_un.b_buf == NULL) 1257 asblk.b_un.b_buf = calloc(1, SBSIZE); 1258 if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) 1259 errexit("cannot allocate space for superblock\n"); 1260 /* 1261 * Could get the actual sector size from the device here, 1262 * but considering how much would need to change in the rest 1263 * of the system before it'd be a problem for us, it's not 1264 * worth worrying about right now. 1265 */ 1266 dev_bsize = secsize = DEV_BSIZE; 1267 } 1268 1269 /* 1270 * Calculate a prototype superblock based on information in the disk label. 1271 * When done the cgsblock macro can be calculated and the fs_ncg field 1272 * can be used. Do NOT attempt to use other macros without verifying that 1273 * their needed information is available! 1274 * 1275 * In BSD, the disk label includes all sorts of useful information, 1276 * like cpg. Solaris doesn't have that, and deriving it (as well as 1277 * some other parameters) is difficult. Rather than duplicate the 1278 * code, just ask mkfs what it would've come up with by default. 1279 * Ideally, we'd just link in the code, but given the source base 1280 * involved, it's more practical to just get a binary dump. 1281 * 1282 * The one minor drawback to the above approach is that newfs and mkfs 1283 * will produce vastly different layouts for the same partition if 1284 * they're allowed to default everything. So, if the superblock that 1285 * mkfs gives us doesn't work for guessing where the alternates are, 1286 * we need to try newfs. 1287 */ 1288 static int 1289 calcsb(calcsb_t style, caddr_t dev, int devfd, struct fs *fs) 1290 { 1291 #define FROM_CHILD 0 1292 #define TO_FSCK 1 1293 #define CMD_IDX 0 1294 #define DEV_IDX 3 1295 #define SIZE_IDX 4 1296 1297 int child_pipe[2]; 1298 caddr_t mkfsline[] = { 1299 "", /* CMD_IDX */ 1300 "-o", 1301 "calcbinsb,N", 1302 NULL, /* DEV_IDX */ 1303 NULL, /* SIZE_IDX */ 1304 NULL 1305 }; 1306 caddr_t newfsline[] = { 1307 "", /* CMD_IDX */ 1308 "-B", 1309 "-N", 1310 NULL, /* DEV_IDX */ 1311 NULL 1312 }; 1313 int pending, transferred; 1314 caddr_t *cmdline; 1315 caddr_t target; 1316 caddr_t sizestr = NULL; 1317 caddr_t path_old, path_new, mkfs_dir, mkfs_path, newfs_path; 1318 caddr_t slash; 1319 diskaddr_t size; 1320 int devnull; 1321 1322 switch (style) { 1323 case MKFS_STYLE: 1324 if (debug) 1325 (void) printf("calcsb() going with style MKFS\n"); 1326 cmdline = mkfsline; 1327 break; 1328 case NEWFS_STYLE: 1329 if (debug) 1330 (void) printf("calcsb() going with style NEWFS\n"); 1331 cmdline = newfsline; 1332 break; 1333 default: 1334 if (debug) 1335 (void) printf("calcsb() doesn't undestand style %d\n", 1336 style); 1337 return (0); 1338 } 1339 1340 cmdline[DEV_IDX] = dev; 1341 1342 /* 1343 * Normally, only use the stock versions of the utilities. 1344 * However, if we're debugging, the odds are that we're 1345 * using experimental versions of them as well, so allow 1346 * some flexibility. 1347 */ 1348 mkfs_path = getenv("MKFS_PATH"); 1349 if (!debug || (mkfs_path == NULL)) 1350 mkfs_path = MKFS_PATH; 1351 1352 newfs_path = getenv("NEWFS_PATH"); 1353 if (!debug || (newfs_path == NULL)) 1354 newfs_path = NEWFS_PATH; 1355 1356 if (style == MKFS_STYLE) { 1357 cmdline[CMD_IDX] = mkfs_path; 1358 1359 size = getdisksize(dev, devfd); 1360 if (size == 0) 1361 return (0); 1362 1363 (void) fsck_asprintf(&sizestr, "%lld", (longlong_t)size); 1364 cmdline[SIZE_IDX] = sizestr; 1365 } else if (style == NEWFS_STYLE) { 1366 /* 1367 * Make sure that newfs will find the right version of mkfs. 1368 */ 1369 cmdline[CMD_IDX] = newfs_path; 1370 path_old = getenv("PATH"); 1371 /* mkfs_path is always initialized, despite lint's concerns */ 1372 mkfs_dir = strdup(mkfs_path); 1373 if (mkfs_dir == NULL) 1374 return (0); 1375 /* 1376 * If no location data for mkfs, don't need to do 1377 * anything about PATH. 1378 */ 1379 slash = strrchr(mkfs_dir, '/'); 1380 if (slash != NULL) { 1381 /* 1382 * Just want the dir, so discard the executable name. 1383 */ 1384 *slash = '\0'; 1385 1386 /* 1387 * newfs uses system() to find mkfs, so make sure 1388 * that the one we want to use is first on the 1389 * list. Don't free path_new upon success, as it 1390 * has become part of the environment. 1391 */ 1392 (void) fsck_asprintf(&path_new, "PATH=%s:%s", 1393 mkfs_dir, path_old); 1394 if (putenv(path_new) != 0) { 1395 free(mkfs_dir); 1396 free(path_new); 1397 return (0); 1398 } 1399 } 1400 free(mkfs_dir); 1401 } else { 1402 /* 1403 * Bad search style, quietly return failure. 1404 */ 1405 if (debug) { 1406 (void) printf("calcsb: got bad style number %d\n", 1407 (int)style); 1408 } 1409 return (0); 1410 } 1411 1412 if (pipe(child_pipe) < 0) { 1413 pfatal("calcsb: could not create pipe: %s\n", strerror(errno)); 1414 if (sizestr != NULL) 1415 free(sizestr); 1416 return (0); 1417 } 1418 1419 switch (fork()) { 1420 case -1: 1421 pfatal("calcsb: fork failed: %s\n", strerror(errno)); 1422 if (sizestr != NULL) 1423 free(sizestr); 1424 return (0); 1425 case 0: 1426 if (dup2(child_pipe[TO_FSCK], fileno(stdout)) < 0) { 1427 (void) printf( 1428 "calcsb: could not rename file descriptor: %s\n", 1429 strerror(errno)); 1430 exit(EXBADPARM); 1431 } 1432 devnull = open("/dev/null", O_WRONLY); 1433 if (devnull == -1) { 1434 (void) printf("calcsb: could not open /dev/null: %s\n", 1435 strerror(errno)); 1436 exit(EXBADPARM); 1437 } 1438 if (dup2(devnull, fileno(stderr)) < 0) { 1439 (void) printf( 1440 "calcsb: could not rename file descriptor: %s\n", 1441 strerror(errno)); 1442 exit(EXBADPARM); 1443 } 1444 (void) close(child_pipe[FROM_CHILD]); 1445 (void) execv(cmdline[CMD_IDX], cmdline); 1446 (void) printf("calcsb: could not exec %s: %s\n", 1447 cmdline[CMD_IDX], strerror(errno)); 1448 exit(EXBADPARM); 1449 /* NOTREACHED */ 1450 default: 1451 break; 1452 } 1453 1454 (void) close(child_pipe[TO_FSCK]); 1455 if (sizestr != NULL) 1456 free(sizestr); 1457 1458 pending = sizeof (struct fs); 1459 target = (caddr_t)fs; 1460 do { 1461 transferred = read(child_pipe[FROM_CHILD], target, pending); 1462 pending -= transferred; 1463 target += transferred; 1464 } while ((pending > 0) && (transferred > 0)); 1465 1466 if (pending > 0) { 1467 if (transferred < 0) 1468 pfatal( 1469 "calcsb: binary read of superblock from %s failed: %s\n", 1470 (style == MKFS_STYLE) ? "mkfs" : "newfs", 1471 (transferred < 0) ? strerror(errno) : ""); 1472 else 1473 pfatal( 1474 "calcsb: short read of superblock from %s\n", 1475 (style == MKFS_STYLE) ? "mkfs" : "newfs"); 1476 return (0); 1477 } 1478 1479 (void) close(child_pipe[FROM_CHILD]); 1480 (void) wait(NULL); 1481 1482 if ((fs->fs_magic != FS_MAGIC) && 1483 (fs->fs_magic != MTB_UFS_MAGIC)) 1484 return (0); 1485 1486 return (1); 1487 } 1488