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