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