17c478bd9Sstevel@tonic-gate /* 2*355d6bb5Sswilcox * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 77c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 87c478bd9Sstevel@tonic-gate 97c478bd9Sstevel@tonic-gate /* 107c478bd9Sstevel@tonic-gate * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. 117c478bd9Sstevel@tonic-gate * All rights reserved. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 147c478bd9Sstevel@tonic-gate * provided that: (1) source distributions retain this entire copyright 157c478bd9Sstevel@tonic-gate * notice and comment, and (2) distributions including binaries display 167c478bd9Sstevel@tonic-gate * the following acknowledgement: ``This product includes software 177c478bd9Sstevel@tonic-gate * developed by the University of California, Berkeley and its contributors'' 187c478bd9Sstevel@tonic-gate * in the documentation or other materials provided with the distribution 197c478bd9Sstevel@tonic-gate * and in all advertising materials mentioning features or use of this 207c478bd9Sstevel@tonic-gate * software. Neither the name of the University nor the names of its 217c478bd9Sstevel@tonic-gate * contributors may be used to endorse or promote products derived 227c478bd9Sstevel@tonic-gate * from this software without specific prior written permission. 237c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 247c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 257c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #define DKTYPENAMES 317c478bd9Sstevel@tonic-gate #include <stdio.h> 327c478bd9Sstevel@tonic-gate #include <stdlib.h> 337c478bd9Sstevel@tonic-gate #include <errno.h> 34*355d6bb5Sswilcox #include <malloc.h> 35*355d6bb5Sswilcox #include <limits.h> 36*355d6bb5Sswilcox #include <wait.h> 377c478bd9Sstevel@tonic-gate #include <sys/param.h> 387c478bd9Sstevel@tonic-gate #include <sys/types.h> 397c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 407c478bd9Sstevel@tonic-gate #include <sys/mntent.h> 417c478bd9Sstevel@tonic-gate #include <sys/dkio.h> 427c478bd9Sstevel@tonic-gate #include <sys/filio.h> 437c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> /* for ENDIAN defines */ 447c478bd9Sstevel@tonic-gate #include <sys/int_const.h> 457c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h> 467c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 47*355d6bb5Sswilcox #include <sys/fs/ufs_fs.h> 487c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h> 497c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_log.h> 507c478bd9Sstevel@tonic-gate #include <sys/stat.h> 517c478bd9Sstevel@tonic-gate #include <sys/fcntl.h> 527c478bd9Sstevel@tonic-gate #include <string.h> 537c478bd9Sstevel@tonic-gate #include <unistd.h> 547c478bd9Sstevel@tonic-gate #include <fcntl.h> 557c478bd9Sstevel@tonic-gate #include <sys/vfstab.h> 567c478bd9Sstevel@tonic-gate #include "roll_log.h" 57*355d6bb5Sswilcox #include "fsck.h" 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate /* 607c478bd9Sstevel@tonic-gate * The size of a cylinder group is calculated by CGSIZE. The maximum size 617c478bd9Sstevel@tonic-gate * is limited by the fact that cylinder groups are at most one block. 627c478bd9Sstevel@tonic-gate * Its size is derived from the size of the maps maintained in the 637c478bd9Sstevel@tonic-gate * cylinder group and the (struct cg) size. 647c478bd9Sstevel@tonic-gate */ 657c478bd9Sstevel@tonic-gate #define CGSIZE(fs) \ 667c478bd9Sstevel@tonic-gate /* base cg */ (sizeof (struct cg) + \ 67*355d6bb5Sswilcox /* blktot size */ (fs)->fs_cpg * sizeof (int32_t) + \ 687c478bd9Sstevel@tonic-gate /* blks size */ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof (short) + \ 697c478bd9Sstevel@tonic-gate /* inode map */ howmany((fs)->fs_ipg, NBBY) + \ 707c478bd9Sstevel@tonic-gate /* block map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY)) 717c478bd9Sstevel@tonic-gate 72*355d6bb5Sswilcox #define altsblock (*asblk.b_un.b_fs) 73*355d6bb5Sswilcox #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 74*355d6bb5Sswilcox 75*355d6bb5Sswilcox /* 76*355d6bb5Sswilcox * Methods of determining where alternate superblocks should 77*355d6bb5Sswilcox * be. MAX_SB_STYLES must be the last one, and the others need 78*355d6bb5Sswilcox * to be positive. 79*355d6bb5Sswilcox */ 80*355d6bb5Sswilcox typedef enum { 81*355d6bb5Sswilcox MKFS_STYLE = 1, NEWFS_STYLE, MAX_SB_STYLES 82*355d6bb5Sswilcox } calcsb_t; 83*355d6bb5Sswilcox 84*355d6bb5Sswilcox static caddr_t calcsb_names[] = { 85*355d6bb5Sswilcox "<UNKNOWN>", "MKFS", "NEWFS", "<OUT OF RANGE>" 86*355d6bb5Sswilcox }; 87*355d6bb5Sswilcox 88*355d6bb5Sswilcox struct shadowclientinfo *shadowclientinfo = NULL; 89*355d6bb5Sswilcox struct shadowclientinfo *attrclientinfo = NULL; 90*355d6bb5Sswilcox int maxshadowclients = 1024; /* allocation size, not limit */ 91*355d6bb5Sswilcox 92*355d6bb5Sswilcox static void badsb(int, caddr_t); 93*355d6bb5Sswilcox static int calcsb(calcsb_t, caddr_t, int, struct fs *); 94*355d6bb5Sswilcox static int checksb(int); 95*355d6bb5Sswilcox static void flush_fs(void); 96*355d6bb5Sswilcox static void sblock_init(void); 97*355d6bb5Sswilcox static void uncreate_maps(void); 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate static int 100*355d6bb5Sswilcox read_super_block(int listerr) 1017c478bd9Sstevel@tonic-gate { 1027c478bd9Sstevel@tonic-gate int fd; 103*355d6bb5Sswilcox caddr_t err; 1047c478bd9Sstevel@tonic-gate 105*355d6bb5Sswilcox if (mount_point != NULL) { 1067c478bd9Sstevel@tonic-gate fd = open(mount_point, O_RDONLY); 1077c478bd9Sstevel@tonic-gate if (fd == -1) { 108*355d6bb5Sswilcox errexit("fsck: open mount point error: %s", 109*355d6bb5Sswilcox strerror(errno)); 110*355d6bb5Sswilcox /* NOTREACHED */ 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate /* get the latest super block */ 1137c478bd9Sstevel@tonic-gate if (ioctl(fd, _FIOGETSUPERBLOCK, &sblock)) { 114*355d6bb5Sswilcox errexit("fsck: ioctl _FIOGETSUPERBLOCK error: %s", 115*355d6bb5Sswilcox strerror(errno)); 116*355d6bb5Sswilcox /* NOTREACHED */ 1177c478bd9Sstevel@tonic-gate } 118*355d6bb5Sswilcox (void) close(fd); 1197c478bd9Sstevel@tonic-gate } else { 120*355d6bb5Sswilcox (void) fsck_bread(fsreadfd, (caddr_t)&sblock, 1217c478bd9Sstevel@tonic-gate bflag != 0 ? (diskaddr_t)bflag : (diskaddr_t)SBLOCK, 122*355d6bb5Sswilcox SBSIZE); 1237c478bd9Sstevel@tonic-gate } 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate /* 126*355d6bb5Sswilcox * Don't let trash from the disk trip us up later 127*355d6bb5Sswilcox * in ungetsummaryinfo(). 128*355d6bb5Sswilcox */ 129*355d6bb5Sswilcox sblock.fs_u.fs_csp = NULL; 130*355d6bb5Sswilcox 131*355d6bb5Sswilcox /* 132*355d6bb5Sswilcox * Rudimentary consistency checks. Can't really call 133*355d6bb5Sswilcox * checksb() here, because there may be outstanding 134*355d6bb5Sswilcox * deltas that still need to be applied. 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate if ((sblock.fs_magic != FS_MAGIC) && 137*355d6bb5Sswilcox (sblock.fs_magic != MTB_UFS_MAGIC)) { 138*355d6bb5Sswilcox err = "MAGIC NUMBER WRONG"; 139*355d6bb5Sswilcox goto fail; 1407c478bd9Sstevel@tonic-gate } 1417c478bd9Sstevel@tonic-gate if (sblock.fs_magic == MTB_UFS_MAGIC && 1427c478bd9Sstevel@tonic-gate (sblock.fs_version > MTB_UFS_VERSION_1 || 1437c478bd9Sstevel@tonic-gate sblock.fs_version < MTB_UFS_VERSION_MIN)) { 144*355d6bb5Sswilcox err = "UNRECOGNIZED VERSION"; 145*355d6bb5Sswilcox goto fail; 1467c478bd9Sstevel@tonic-gate } 1477c478bd9Sstevel@tonic-gate if (sblock.fs_ncg < 1) { 148*355d6bb5Sswilcox err = "NCG OUT OF RANGE"; 149*355d6bb5Sswilcox goto fail; 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate if (sblock.fs_cpg < 1) { 152*355d6bb5Sswilcox err = "CPG OUT OF RANGE"; 153*355d6bb5Sswilcox goto fail; 1547c478bd9Sstevel@tonic-gate } 1557c478bd9Sstevel@tonic-gate if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl || 1567c478bd9Sstevel@tonic-gate (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) { 157*355d6bb5Sswilcox err = "NCYL IS INCONSISTENT WITH NCG*CPG"; 158*355d6bb5Sswilcox goto fail; 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate if (sblock.fs_sbsize < 0 || sblock.fs_sbsize > SBSIZE) { 161*355d6bb5Sswilcox err = "SIZE OUT OF RANGE"; 162*355d6bb5Sswilcox goto fail; 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate return (1); 166*355d6bb5Sswilcox 167*355d6bb5Sswilcox fail: 168*355d6bb5Sswilcox badsb(listerr, err); 169*355d6bb5Sswilcox return (0); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate 172*355d6bb5Sswilcox static void 1737c478bd9Sstevel@tonic-gate flush_fs() 1747c478bd9Sstevel@tonic-gate { 1757c478bd9Sstevel@tonic-gate int fd; 1767c478bd9Sstevel@tonic-gate 177*355d6bb5Sswilcox if (mount_point != NULL) { 1787c478bd9Sstevel@tonic-gate fd = open(mount_point, O_RDONLY); 1797c478bd9Sstevel@tonic-gate if (fd == -1) { 180*355d6bb5Sswilcox errexit("fsck: open mount point error: %s", 181*355d6bb5Sswilcox strerror(errno)); 182*355d6bb5Sswilcox /* NOTREACHED */ 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate if (ioctl(fd, _FIOFFS, NULL)) { /* flush file system */ 185*355d6bb5Sswilcox errexit("fsck: ioctl _FIOFFS error: %s", 186*355d6bb5Sswilcox strerror(errno)); 187*355d6bb5Sswilcox /* NOTREACHED */ 1887c478bd9Sstevel@tonic-gate } 189*355d6bb5Sswilcox (void) close(fd); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate /* 1947c478bd9Sstevel@tonic-gate * Roll the embedded log, if any, and set up the global variables 195*355d6bb5Sswilcox * islog and islogok. 1967c478bd9Sstevel@tonic-gate */ 1977c478bd9Sstevel@tonic-gate static int 198*355d6bb5Sswilcox logsetup(caddr_t devstr) 1997c478bd9Sstevel@tonic-gate { 2007c478bd9Sstevel@tonic-gate void *buf; 2017c478bd9Sstevel@tonic-gate extent_block_t *ebp; 2027c478bd9Sstevel@tonic-gate ml_unit_t *ul; 2037c478bd9Sstevel@tonic-gate ml_odunit_t *ud; 2047c478bd9Sstevel@tonic-gate void *ud_buf; 2057c478bd9Sstevel@tonic-gate int badlog; 2067c478bd9Sstevel@tonic-gate 207*355d6bb5Sswilcox islog = islogok = 0; 208*355d6bb5Sswilcox if (bflag != 0) 2097c478bd9Sstevel@tonic-gate return (1); /* can't roll log while alternate sb specified */ 2107c478bd9Sstevel@tonic-gate 211*355d6bb5Sswilcox /* 212*355d6bb5Sswilcox * Roll the log, if any. A bad sb implies we'll be using 213*355d6bb5Sswilcox * an alternate sb as far as logging goes, so just fail back 214*355d6bb5Sswilcox * to the caller if we can't read the default sb. Suppress 215*355d6bb5Sswilcox * complaints, because the caller will be reading the same 216*355d6bb5Sswilcox * superblock again and running full verification on it, so 217*355d6bb5Sswilcox * whatever is bad will be reported then. 218*355d6bb5Sswilcox */ 2197c478bd9Sstevel@tonic-gate sblock.fs_logbno = 0; 2207c478bd9Sstevel@tonic-gate badlog = 0; 221*355d6bb5Sswilcox if (!read_super_block(0)) 222*355d6bb5Sswilcox return (1); 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * Roll the log in 3 cases: 2267c478bd9Sstevel@tonic-gate * 1. If it's unmounted (mount_point == NULL) and it's not marked 2277c478bd9Sstevel@tonic-gate * as fully rolled (sblock.fs_rolled != FS_ALL_ROLLED) 2287c478bd9Sstevel@tonic-gate * 2. If it's mounted and anything other than a sanity 2297c478bd9Sstevel@tonic-gate * check fsck (mflag) is being done, as we have the current 2307c478bd9Sstevel@tonic-gate * super block. Note, only a sanity check is done for 2317c478bd9Sstevel@tonic-gate * root/usr at boot. If a roll were done then the expensive 2327c478bd9Sstevel@tonic-gate * ufs_flush() gets called, leading to a slower boot. 2337c478bd9Sstevel@tonic-gate * 3. If anything other then a sanity check (mflag) is being done 2347c478bd9Sstevel@tonic-gate * to a mounted filesystem while it is in read-only state 2357c478bd9Sstevel@tonic-gate * (e.g. root during early boot stages) we have to detect this 2367c478bd9Sstevel@tonic-gate * and have to roll the log as well. NB. the read-only mount 2377c478bd9Sstevel@tonic-gate * will flip fs_clean from FSLOG to FSSTABLE and marks the 2387c478bd9Sstevel@tonic-gate * log as FS_NEED_ROLL. 2397c478bd9Sstevel@tonic-gate */ 2407c478bd9Sstevel@tonic-gate if (sblock.fs_logbno && 2417c478bd9Sstevel@tonic-gate (((mount_point == NULL) && (sblock.fs_rolled != FS_ALL_ROLLED)) || 242*355d6bb5Sswilcox ((mount_point != NULL) && !mflag))) { 2437c478bd9Sstevel@tonic-gate int roll_log_err = 0; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (sblock.fs_ronly && (sblock.fs_clean == FSSTABLE) && 2467c478bd9Sstevel@tonic-gate (sblock.fs_state + sblock.fs_time == FSOKAY)) { 2477c478bd9Sstevel@tonic-gate /* 2487c478bd9Sstevel@tonic-gate * roll the log without a mount 2497c478bd9Sstevel@tonic-gate */ 2507c478bd9Sstevel@tonic-gate flush_fs(); 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate if (sblock.fs_clean == FSLOG && 2537c478bd9Sstevel@tonic-gate (sblock.fs_state + sblock.fs_time == FSOKAY)) { 2547c478bd9Sstevel@tonic-gate if (rl_roll_log(devstr) != RL_SUCCESS) 2557c478bd9Sstevel@tonic-gate roll_log_err = 1; 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate if (roll_log_err) { 2587c478bd9Sstevel@tonic-gate (void) printf("Can't roll the log for %s.\n", devstr); 2597c478bd9Sstevel@tonic-gate /* 2607c478bd9Sstevel@tonic-gate * There are two cases where we want to set 2617c478bd9Sstevel@tonic-gate * an error code and return: 2627c478bd9Sstevel@tonic-gate * - We're preening 2637c478bd9Sstevel@tonic-gate * - We're not on a live root and the user 2647c478bd9Sstevel@tonic-gate * chose *not* to ignore the log 2657c478bd9Sstevel@tonic-gate * Otherwise, we want to mark the log as bad 2667c478bd9Sstevel@tonic-gate * and continue to check the filesystem. This 2677c478bd9Sstevel@tonic-gate * has the side effect of destroying the log. 2687c478bd9Sstevel@tonic-gate */ 2697c478bd9Sstevel@tonic-gate if (preen || (!hotroot && 2707c478bd9Sstevel@tonic-gate reply( 2717c478bd9Sstevel@tonic-gate "DISCARDING THE LOG MAY DISCARD PENDING TRANSACTIONS.\n" 2727c478bd9Sstevel@tonic-gate "DISCARD THE LOG AND CONTINUE") == 0)) { 273*355d6bb5Sswilcox exitstat = EXERRFATAL; 2747c478bd9Sstevel@tonic-gate return (0); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate ++badlog; 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate /* Logging UFS may be enabled */ 2817c478bd9Sstevel@tonic-gate if (sblock.fs_logbno) { 2827c478bd9Sstevel@tonic-gate ++islog; 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* log is not okay; check the fs */ 2857c478bd9Sstevel@tonic-gate if (FSOKAY != (sblock.fs_state + sblock.fs_time)) 2867c478bd9Sstevel@tonic-gate return (1); 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate /* 2897c478bd9Sstevel@tonic-gate * If logging or (stable and mounted) then continue 2907c478bd9Sstevel@tonic-gate */ 291*355d6bb5Sswilcox if (!((sblock.fs_clean == FSLOG) || 292*355d6bb5Sswilcox (sblock.fs_clean == FSSTABLE) && (mount_point != NULL))) 2937c478bd9Sstevel@tonic-gate return (1); 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate /* get the log allocation block */ 296*355d6bb5Sswilcox buf = malloc(dev_bsize); 297*355d6bb5Sswilcox if (buf == NULL) { 2987c478bd9Sstevel@tonic-gate return (1); 2997c478bd9Sstevel@tonic-gate } 300*355d6bb5Sswilcox ud_buf = malloc(dev_bsize); 301*355d6bb5Sswilcox if (ud_buf == NULL) { 3027c478bd9Sstevel@tonic-gate free(buf); 3037c478bd9Sstevel@tonic-gate return (1); 3047c478bd9Sstevel@tonic-gate } 305*355d6bb5Sswilcox (void) fsck_bread(fsreadfd, buf, 3067c478bd9Sstevel@tonic-gate logbtodb(&sblock, sblock.fs_logbno), 307*355d6bb5Sswilcox dev_bsize); 3087c478bd9Sstevel@tonic-gate ebp = (extent_block_t *)buf; 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* log allocation block is not okay; check the fs */ 3117c478bd9Sstevel@tonic-gate if (ebp->type != LUFS_EXTENTS) { 3127c478bd9Sstevel@tonic-gate free(buf); 3137c478bd9Sstevel@tonic-gate free(ud_buf); 3147c478bd9Sstevel@tonic-gate return (1); 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate /* get the log state block(s) */ 318*355d6bb5Sswilcox if (fsck_bread(fsreadfd, ud_buf, 3197c478bd9Sstevel@tonic-gate (logbtodb(&sblock, ebp->extents[0].pbno)), 320*355d6bb5Sswilcox dev_bsize)) { 321*355d6bb5Sswilcox (void) fsck_bread(fsreadfd, ud_buf, 322*355d6bb5Sswilcox (logbtodb(&sblock, ebp->extents[0].pbno)) + 1, 323*355d6bb5Sswilcox dev_bsize); 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate ud = (ml_odunit_t *)ud_buf; 3267c478bd9Sstevel@tonic-gate ul = (ml_unit_t *)malloc(sizeof (*ul)); 3277c478bd9Sstevel@tonic-gate if (ul == NULL) { 3287c478bd9Sstevel@tonic-gate free(buf); 3297c478bd9Sstevel@tonic-gate free(ud_buf); 3307c478bd9Sstevel@tonic-gate return (1); 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate ul->un_ondisk = *ud; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate /* log state is okay; don't need to check the fs */ 3357c478bd9Sstevel@tonic-gate if ((ul->un_chksum == ul->un_head_ident + ul->un_tail_ident) && 3367c478bd9Sstevel@tonic-gate (ul->un_version == LUFS_VERSION_LATEST) && 337*355d6bb5Sswilcox (ul->un_badlog == 0) && (!badlog)) { 3387c478bd9Sstevel@tonic-gate ++islogok; 339*355d6bb5Sswilcox } 3407c478bd9Sstevel@tonic-gate free(ud_buf); 3417c478bd9Sstevel@tonic-gate free(buf); 3427c478bd9Sstevel@tonic-gate free(ul); 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate return (1); 3467c478bd9Sstevel@tonic-gate } 3477c478bd9Sstevel@tonic-gate 348*355d6bb5Sswilcox /* 349*355d6bb5Sswilcox * - given a pathname, determine the pathname to actually check 350*355d6bb5Sswilcox * - if a directory 351*355d6bb5Sswilcox * - if it is in mnttab, set devstr to the special (block) name 352*355d6bb5Sswilcox * - if it is in vfstab, set devstr to the special (block) name 353*355d6bb5Sswilcox * - if it has not been found, bail 354*355d6bb5Sswilcox * - a file is used as-is, clear rflag 355*355d6bb5Sswilcox * - a device is converted to block version (so can search mnttab) 356*355d6bb5Sswilcox */ 357*355d6bb5Sswilcox static void 358*355d6bb5Sswilcox derive_devstr(const caddr_t dev, caddr_t devstr, size_t str_size) 3597c478bd9Sstevel@tonic-gate { 360*355d6bb5Sswilcox mode_t mode; 361*355d6bb5Sswilcox struct stat statb; 3627c478bd9Sstevel@tonic-gate 363*355d6bb5Sswilcox if (stat(dev, &statb) < 0) { 364*355d6bb5Sswilcox exitstat = EXNOSTAT; 365*355d6bb5Sswilcox errexit("fsck: could not stat %s: %s", dev, strerror(errno)); 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate 368*355d6bb5Sswilcox mode = statb.st_mode & S_IFMT; 369*355d6bb5Sswilcox switch (mode) { 370*355d6bb5Sswilcox case S_IFDIR: 3717c478bd9Sstevel@tonic-gate /* 372*355d6bb5Sswilcox * The check_*() routines update devstr with the name. 3737c478bd9Sstevel@tonic-gate */ 374*355d6bb5Sswilcox devstr[0] = '\0'; 375*355d6bb5Sswilcox if (!(check_mnttab(dev, devstr, str_size) || 376*355d6bb5Sswilcox check_vfstab(dev, devstr, str_size))) { 377*355d6bb5Sswilcox exitstat = EXBADPARM; 378*355d6bb5Sswilcox errexit( 379*355d6bb5Sswilcox "fsck: could not find mountpoint %s in mnttab nor vfstab", 380*355d6bb5Sswilcox dev); 3817c478bd9Sstevel@tonic-gate } 382*355d6bb5Sswilcox break; 383*355d6bb5Sswilcox case S_IFREG: 3847c478bd9Sstevel@tonic-gate rflag = 0; 385*355d6bb5Sswilcox break; 386*355d6bb5Sswilcox case S_IFCHR: 387*355d6bb5Sswilcox case S_IFBLK: 388*355d6bb5Sswilcox (void) strlcpy(devstr, unrawname(dev), str_size); 389*355d6bb5Sswilcox break; 390*355d6bb5Sswilcox default: 391*355d6bb5Sswilcox exitstat = EXBADPARM; 392*355d6bb5Sswilcox errexit("fsck: %s must be a mountpoint, device, or file", dev); 393*355d6bb5Sswilcox /* NOTREACHED */ 3947c478bd9Sstevel@tonic-gate } 395*355d6bb5Sswilcox } 3967c478bd9Sstevel@tonic-gate 397*355d6bb5Sswilcox /* 398*355d6bb5Sswilcox * Reports the index of the magic filesystem that mntp names. 399*355d6bb5Sswilcox * If it does not correspond any of them, returns zero (hence 400*355d6bb5Sswilcox * the backwards loop). 401*355d6bb5Sswilcox */ 402*355d6bb5Sswilcox static int 403*355d6bb5Sswilcox which_corefs(const caddr_t mntp) 404*355d6bb5Sswilcox { 405*355d6bb5Sswilcox int corefs; 406*355d6bb5Sswilcox 407*355d6bb5Sswilcox for (corefs = MAGIC_LIMIT - 1; corefs > 0; corefs--) 408*355d6bb5Sswilcox if (strcmp(mntp, magic_fs[corefs]) == 0) 409*355d6bb5Sswilcox break; 410*355d6bb5Sswilcox 411*355d6bb5Sswilcox return (corefs); 412*355d6bb5Sswilcox } 413*355d6bb5Sswilcox 414*355d6bb5Sswilcox /* 415*355d6bb5Sswilcox * - set mount_point to NULL 416*355d6bb5Sswilcox * - if name is mounted (search mnttab) 417*355d6bb5Sswilcox * - if it is a device, clear rflag 418*355d6bb5Sswilcox * - if mounted on /, /usr, or /var, set corefs 419*355d6bb5Sswilcox * - if corefs and read-only, set hotroot and continue 420*355d6bb5Sswilcox * - if errorlocked, continue 421*355d6bb5Sswilcox * - if preening, bail 422*355d6bb5Sswilcox * - ask user whether to continue, bail if not 423*355d6bb5Sswilcox * - if it is a device and not mounted and rflag, convert 424*355d6bb5Sswilcox * name to raw version 425*355d6bb5Sswilcox */ 426*355d6bb5Sswilcox static int 427*355d6bb5Sswilcox check_mount_state(caddr_t devstr, size_t str_size) 428*355d6bb5Sswilcox { 429*355d6bb5Sswilcox int corefs = 0; 430*355d6bb5Sswilcox int is_dev = 0; 431*355d6bb5Sswilcox struct stat statb; 432*355d6bb5Sswilcox 433*355d6bb5Sswilcox if (stat(devstr, &statb) < 0) { 434*355d6bb5Sswilcox exitstat = EXNOSTAT; 435*355d6bb5Sswilcox errexit("fsck: could not stat %s: %s", devstr, strerror(errno)); 4367c478bd9Sstevel@tonic-gate } 437*355d6bb5Sswilcox if (S_ISCHR(statb.st_mode) || S_ISBLK(statb.st_mode)) 438*355d6bb5Sswilcox is_dev = 1; 439*355d6bb5Sswilcox 440*355d6bb5Sswilcox /* 441*355d6bb5Sswilcox * mounted() will update mount_point when returning true. 442*355d6bb5Sswilcox */ 443*355d6bb5Sswilcox mount_point = NULL; 444*355d6bb5Sswilcox if ((mountedfs = mounted(devstr, devstr, str_size)) != M_NOMNT) { 445*355d6bb5Sswilcox if (is_dev) 446*355d6bb5Sswilcox rflag = 0; 447*355d6bb5Sswilcox corefs = which_corefs(mount_point); 448*355d6bb5Sswilcox if (corefs && (mountedfs == M_RO)) { 449*355d6bb5Sswilcox hotroot++; 450*355d6bb5Sswilcox } else if (errorlocked) { 451*355d6bb5Sswilcox goto carry_on; 452*355d6bb5Sswilcox } else if (preen) { 453*355d6bb5Sswilcox exitstat = EXMOUNTED; 454*355d6bb5Sswilcox pfatal("%s IS CURRENTLY MOUNTED%s.", 455*355d6bb5Sswilcox devstr, mountedfs == M_RW ? " READ/WRITE" : ""); 456*355d6bb5Sswilcox } else { 457*355d6bb5Sswilcox pwarn("%s IS CURRENTLY MOUNTED READ/%s.", 458*355d6bb5Sswilcox devstr, mountedfs == M_RW ? "WRITE" : "ONLY"); 459*355d6bb5Sswilcox if (reply("CONTINUE") == 0) { 460*355d6bb5Sswilcox exitstat = EXMOUNTED; 461*355d6bb5Sswilcox errexit("Program terminated"); 462*355d6bb5Sswilcox } 4637c478bd9Sstevel@tonic-gate } 464*355d6bb5Sswilcox } else if (is_dev && rflag) { 465*355d6bb5Sswilcox (void) strlcpy(devstr, rawname(devstr), str_size); 4667c478bd9Sstevel@tonic-gate } 467*355d6bb5Sswilcox 468*355d6bb5Sswilcox carry_on: 469*355d6bb5Sswilcox return (corefs); 470*355d6bb5Sswilcox } 471*355d6bb5Sswilcox 472*355d6bb5Sswilcox static int 473*355d6bb5Sswilcox open_and_intro(caddr_t devstr, int corefs) 474*355d6bb5Sswilcox { 475*355d6bb5Sswilcox int retval = 0; 476*355d6bb5Sswilcox 4777c478bd9Sstevel@tonic-gate if ((fsreadfd = open64(devstr, O_RDONLY)) < 0) { 478*355d6bb5Sswilcox (void) printf("Can't open %s: %s\n", devstr, strerror(errno)); 479*355d6bb5Sswilcox exitstat = EXNOSTAT; 480*355d6bb5Sswilcox retval = -1; 481*355d6bb5Sswilcox goto finish; 4827c478bd9Sstevel@tonic-gate } 483*355d6bb5Sswilcox if (!preen || debug != 0) 484*355d6bb5Sswilcox (void) printf("** %s", devstr); 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate if (errorlocked) { 487*355d6bb5Sswilcox if (debug && elock_combuf != NULL) 488*355d6bb5Sswilcox (void) printf(" error-lock comment: \"%s\" ", 489*355d6bb5Sswilcox elock_combuf); 4907c478bd9Sstevel@tonic-gate fflag = 1; 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate pid = getpid(); 493*355d6bb5Sswilcox if (nflag || roflag || (fswritefd = open64(devstr, O_WRONLY)) < 0) { 4947c478bd9Sstevel@tonic-gate fswritefd = -1; 4957c478bd9Sstevel@tonic-gate if (preen && !debug) 4967c478bd9Sstevel@tonic-gate pfatal("(NO WRITE ACCESS)\n"); 497*355d6bb5Sswilcox (void) printf(" (NO WRITE)"); 4987c478bd9Sstevel@tonic-gate } 499*355d6bb5Sswilcox if (!preen) 500*355d6bb5Sswilcox (void) printf("\n"); 5017c478bd9Sstevel@tonic-gate else if (debug) 502*355d6bb5Sswilcox (void) printf(" pid %d\n", pid); 503*355d6bb5Sswilcox if (debug && (hotroot || (mountedfs != M_NOMNT))) { 504*355d6bb5Sswilcox (void) printf("** %s", devstr); 5057c478bd9Sstevel@tonic-gate if (hotroot) 506*355d6bb5Sswilcox (void) printf(" is %s fs", magic_fs[corefs]); 507*355d6bb5Sswilcox if (mountedfs != M_NOMNT) 508*355d6bb5Sswilcox (void) printf(" and is mounted read-%s", 509*355d6bb5Sswilcox (mountedfs == M_RO) ? "only" : "write"); 5107c478bd9Sstevel@tonic-gate if (errorlocked) 511*355d6bb5Sswilcox (void) printf(" and is error-locked"); 5127c478bd9Sstevel@tonic-gate 513*355d6bb5Sswilcox (void) printf(".\n"); 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate 516*355d6bb5Sswilcox finish: 517*355d6bb5Sswilcox return (retval); 518*355d6bb5Sswilcox } 5197c478bd9Sstevel@tonic-gate 520*355d6bb5Sswilcox static int 521*355d6bb5Sswilcox find_superblock(caddr_t devstr) 522*355d6bb5Sswilcox { 523*355d6bb5Sswilcox int cg = 0; 524*355d6bb5Sswilcox int retval = 0; 525*355d6bb5Sswilcox int first; 526*355d6bb5Sswilcox int found; 527*355d6bb5Sswilcox calcsb_t style; 528*355d6bb5Sswilcox struct fs proto; 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate /* 531*355d6bb5Sswilcox * Check the superblock, looking for alternates if necessary. 532*355d6bb5Sswilcox * In more-recent times, some UFS instances get created with 533*355d6bb5Sswilcox * only the first ten and last ten superblock backups. Since 534*355d6bb5Sswilcox * if we can't get the necessary information from any of those, 535*355d6bb5Sswilcox * the odds are also against us for the ones in between, we'll 536*355d6bb5Sswilcox * just look at those twenty to save time. 5377c478bd9Sstevel@tonic-gate */ 538*355d6bb5Sswilcox if (!read_super_block(1) || !checksb(1)) { 539*355d6bb5Sswilcox if (bflag || preen) { 540*355d6bb5Sswilcox retval = -1; 541*355d6bb5Sswilcox goto finish; 542*355d6bb5Sswilcox } 543*355d6bb5Sswilcox for (style = MKFS_STYLE; style < MAX_SB_STYLES; style++) { 544*355d6bb5Sswilcox if (reply("LOOK FOR ALTERNATE SUPERBLOCKS WITH %s", 545*355d6bb5Sswilcox calcsb_names[style]) == 0) 546*355d6bb5Sswilcox continue; 547*355d6bb5Sswilcox first = 1; 548*355d6bb5Sswilcox found = 0; 549*355d6bb5Sswilcox if (!calcsb(style, devstr, fsreadfd, &proto)) { 550*355d6bb5Sswilcox cg = proto.fs_ncg; 551*355d6bb5Sswilcox continue; 552*355d6bb5Sswilcox } 553*355d6bb5Sswilcox if (debug) { 554*355d6bb5Sswilcox (void) printf( 555*355d6bb5Sswilcox "debug: calcsb(%s) gave fpg %d, cgoffset %d, ", 556*355d6bb5Sswilcox calcsb_names[style], 557*355d6bb5Sswilcox proto.fs_fpg, proto.fs_cgoffset); 558*355d6bb5Sswilcox (void) printf("cgmask 0x%x, sblk %d, ncg %d\n", 559*355d6bb5Sswilcox proto.fs_cgmask, proto.fs_sblkno, 560*355d6bb5Sswilcox proto.fs_ncg); 561*355d6bb5Sswilcox } 562*355d6bb5Sswilcox for (cg = 0; cg < proto.fs_ncg; cg++) { 563*355d6bb5Sswilcox bflag = fsbtodb(&proto, cgsblock(&proto, cg)); 564*355d6bb5Sswilcox if (debug) 565*355d6bb5Sswilcox (void) printf( 566*355d6bb5Sswilcox "debug: trying block %lld\n", 567*355d6bb5Sswilcox (longlong_t)bflag); 568*355d6bb5Sswilcox if (read_super_block(0) && checksb(0)) { 569*355d6bb5Sswilcox (void) printf( 570*355d6bb5Sswilcox "FOUND ALTERNATE SUPERBLOCK %d WITH %s\n", 571*355d6bb5Sswilcox bflag, calcsb_names[style]); 572*355d6bb5Sswilcox if (reply( 573*355d6bb5Sswilcox "USE ALTERNATE SUPERBLOCK") == 1) { 574*355d6bb5Sswilcox found = 1; 575*355d6bb5Sswilcox break; 576*355d6bb5Sswilcox } 577*355d6bb5Sswilcox } 578*355d6bb5Sswilcox if (first && (cg >= 9)) { 579*355d6bb5Sswilcox first = 0; 580*355d6bb5Sswilcox if (proto.fs_ncg <= 9) 581*355d6bb5Sswilcox cg = proto.fs_ncg; 582*355d6bb5Sswilcox else if (proto.fs_ncg <= 19) 583*355d6bb5Sswilcox cg = 9; 584*355d6bb5Sswilcox else 585*355d6bb5Sswilcox cg = proto.fs_ncg - 10; 586*355d6bb5Sswilcox } 587*355d6bb5Sswilcox } 588*355d6bb5Sswilcox 589*355d6bb5Sswilcox if (found) 590*355d6bb5Sswilcox break; 591*355d6bb5Sswilcox } 592*355d6bb5Sswilcox 593*355d6bb5Sswilcox /* 594*355d6bb5Sswilcox * Didn't find one? Try to fake it. 595*355d6bb5Sswilcox */ 596*355d6bb5Sswilcox if (style >= MAX_SB_STYLES) { 597*355d6bb5Sswilcox pwarn("SEARCH FOR ALTERNATE SUPERBLOCKS FAILED.\n"); 598*355d6bb5Sswilcox for (style = MKFS_STYLE; style < MAX_SB_STYLES; 599*355d6bb5Sswilcox style++) { 600*355d6bb5Sswilcox if (reply("USE GENERIC SUPERBLOCK FROM %s", 601*355d6bb5Sswilcox calcsb_names[style]) == 1 && 602*355d6bb5Sswilcox calcsb(style, devstr, fsreadfd, &sblock)) { 603*355d6bb5Sswilcox break; 604*355d6bb5Sswilcox } 605*355d6bb5Sswilcox /* 606*355d6bb5Sswilcox * We got something from mkfs/newfs, so use it. 607*355d6bb5Sswilcox */ 608*355d6bb5Sswilcox if (style < MAX_SB_STYLES) 609*355d6bb5Sswilcox proto.fs_ncg = sblock.fs_ncg; 610*355d6bb5Sswilcox bflag = 0; 611*355d6bb5Sswilcox } 612*355d6bb5Sswilcox } 613*355d6bb5Sswilcox 614*355d6bb5Sswilcox /* 615*355d6bb5Sswilcox * Still no luck? Tell the user they're on their own. 616*355d6bb5Sswilcox */ 617*355d6bb5Sswilcox if (style >= MAX_SB_STYLES) { 618*355d6bb5Sswilcox pwarn("SEARCH FOR ALTERNATE SUPERBLOCKS FAILED. " 619*355d6bb5Sswilcox "YOU MUST USE THE -o b OPTION\n" 620*355d6bb5Sswilcox "TO FSCK TO SPECIFY THE LOCATION OF A VALID " 621*355d6bb5Sswilcox "ALTERNATE SUPERBLOCK TO\n" 622*355d6bb5Sswilcox "SUPPLY NEEDED INFORMATION; SEE fsck(1M).\n"); 623*355d6bb5Sswilcox bflag = 0; 624*355d6bb5Sswilcox retval = -1; 625*355d6bb5Sswilcox goto finish; 626*355d6bb5Sswilcox } 627*355d6bb5Sswilcox 628*355d6bb5Sswilcox /* 629*355d6bb5Sswilcox * Need to make sure a human really wants us to use 630*355d6bb5Sswilcox * this. -y mode could've gotten us this far, so 631*355d6bb5Sswilcox * we need to ask something that has to be answered 632*355d6bb5Sswilcox * in the negative. 633*355d6bb5Sswilcox * 634*355d6bb5Sswilcox * Note that we can't get here when preening. 635*355d6bb5Sswilcox */ 636*355d6bb5Sswilcox if (!found) { 637*355d6bb5Sswilcox pwarn("CALCULATED GENERIC SUPERBLOCK WITH %s\n", 638*355d6bb5Sswilcox calcsb_names[style]); 639*355d6bb5Sswilcox } else { 640*355d6bb5Sswilcox pwarn("FOUND ALTERNATE SUPERBLOCK AT %d USING %s\n", 641*355d6bb5Sswilcox bflag, calcsb_names[style]); 642*355d6bb5Sswilcox } 643*355d6bb5Sswilcox pwarn("If filesystem was created with manually-specified "); 644*355d6bb5Sswilcox pwarn("geometry, using\nauto-discovered superblock may "); 645*355d6bb5Sswilcox pwarn("result in irrecoverable damage to\nfilesystem and "); 646*355d6bb5Sswilcox pwarn("user data.\n"); 647*355d6bb5Sswilcox if (reply("CANCEL FILESYSTEM CHECK") == 1) { 648*355d6bb5Sswilcox if (cg >= 0) { 649*355d6bb5Sswilcox pwarn("Please verify that the indicated block " 650*355d6bb5Sswilcox "contains a proper\nsuperblock for the " 651*355d6bb5Sswilcox "filesystem (see fsdb(1M)).\n"); 652*355d6bb5Sswilcox if (yflag) 653*355d6bb5Sswilcox pwarn("\nFSCK was running in YES " 654*355d6bb5Sswilcox "mode. If you wish to run in " 655*355d6bb5Sswilcox "that mode using\nthe alternate " 656*355d6bb5Sswilcox "superblock, run " 657*355d6bb5Sswilcox "`fsck -y -o b=%d %s'.\n", 658*355d6bb5Sswilcox bflag, devstr); 659*355d6bb5Sswilcox } 660*355d6bb5Sswilcox retval = -1; 661*355d6bb5Sswilcox goto finish; 662*355d6bb5Sswilcox } 663*355d6bb5Sswilcox 664*355d6bb5Sswilcox /* 665*355d6bb5Sswilcox * Pretend we found it as an alternate, so everything 666*355d6bb5Sswilcox * gets updated when we clean up at the end. 667*355d6bb5Sswilcox */ 668*355d6bb5Sswilcox if (!found) { 669*355d6bb5Sswilcox havesb = 1; 670*355d6bb5Sswilcox sblk.b_bno = fsbtodb(&sblock, cgsblock(&sblock, 0)); 671*355d6bb5Sswilcox bwrite(fswritefd, (caddr_t)&sblock, SBLOCK, SBSIZE); 672*355d6bb5Sswilcox write_altsb(fswritefd); 673*355d6bb5Sswilcox } 674*355d6bb5Sswilcox } 675*355d6bb5Sswilcox 676*355d6bb5Sswilcox finish: 677*355d6bb5Sswilcox return (retval); 678*355d6bb5Sswilcox } 679*355d6bb5Sswilcox 680*355d6bb5Sswilcox /* 681*355d6bb5Sswilcox * Check and potentially fix certain fields in the super block. 682*355d6bb5Sswilcox */ 683*355d6bb5Sswilcox static void 684*355d6bb5Sswilcox fixup_superblock(void) 685*355d6bb5Sswilcox { 6867c478bd9Sstevel@tonic-gate /* 687*355d6bb5Sswilcox * Kernel looks for FS_OPTTIME, and assumes that if that's not 688*355d6bb5Sswilcox * what's there, it must be FS_OPTSPACE, so not fixing does not 689*355d6bb5Sswilcox * require setting iscorrupt. 6907c478bd9Sstevel@tonic-gate */ 6917c478bd9Sstevel@tonic-gate if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { 6927c478bd9Sstevel@tonic-gate pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); 6937c478bd9Sstevel@tonic-gate if (reply("SET TO DEFAULT") == 1) { 6947c478bd9Sstevel@tonic-gate sblock.fs_optim = FS_OPTTIME; 6957c478bd9Sstevel@tonic-gate sbdirty(); 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { 6997c478bd9Sstevel@tonic-gate pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 700*355d6bb5Sswilcox sblock.fs_minfree); 7017c478bd9Sstevel@tonic-gate if (reply("SET TO DEFAULT") == 1) { 7027c478bd9Sstevel@tonic-gate sblock.fs_minfree = 10; 7037c478bd9Sstevel@tonic-gate sbdirty(); 704*355d6bb5Sswilcox } else if (sblock.fs_minfree < 0) { 7057c478bd9Sstevel@tonic-gate /* 706*355d6bb5Sswilcox * Kernel uses minfree without verification, 707*355d6bb5Sswilcox * and a negative value would do bad things. 7087c478bd9Sstevel@tonic-gate */ 709*355d6bb5Sswilcox iscorrupt = 1; 7107c478bd9Sstevel@tonic-gate } 7117c478bd9Sstevel@tonic-gate } 712*355d6bb5Sswilcox } 713*355d6bb5Sswilcox 714*355d6bb5Sswilcox static int 715*355d6bb5Sswilcox initial_error_state_adjust(void) 716*355d6bb5Sswilcox { 717*355d6bb5Sswilcox int retval = 0; 718*355d6bb5Sswilcox 719*355d6bb5Sswilcox /* do this right away to prevent any other fscks on this fs */ 720*355d6bb5Sswilcox switch (sblock.fs_clean) { 721*355d6bb5Sswilcox case FSBAD: 722*355d6bb5Sswilcox break; 723*355d6bb5Sswilcox case FSFIX: 724*355d6bb5Sswilcox if (preen) 725*355d6bb5Sswilcox errexit("ERROR-LOCKED; MARKED \"FSFIX\"\n"); 726*355d6bb5Sswilcox if (reply("marked FSFIX, CONTINUE") == 0) { 727*355d6bb5Sswilcox retval = -1; 728*355d6bb5Sswilcox goto finish; 729*355d6bb5Sswilcox } 730*355d6bb5Sswilcox break; 731*355d6bb5Sswilcox case FSCLEAN: 732*355d6bb5Sswilcox if (preen) 733*355d6bb5Sswilcox errexit("ERROR-LOCKED; MARKED \"FSCLEAN\"\n"); 734*355d6bb5Sswilcox if (reply("marked FSCLEAN, CONTINUE") == 0) { 735*355d6bb5Sswilcox retval = -1; 736*355d6bb5Sswilcox goto finish; 737*355d6bb5Sswilcox } 738*355d6bb5Sswilcox break; 739*355d6bb5Sswilcox default: 740*355d6bb5Sswilcox if (preen) { 741*355d6bb5Sswilcox if (debug) 7427c478bd9Sstevel@tonic-gate pwarn("ERRORLOCKED; NOT MARKED \"FSBAD\"\n"); 743*355d6bb5Sswilcox else 7447c478bd9Sstevel@tonic-gate errexit("ERRORLOCKED; NOT MARKED \"FSBAD\"\n"); 745*355d6bb5Sswilcox } else { 746*355d6bb5Sswilcox (void) printf("error-locked but not marked \"FSBAD\";"); 747*355d6bb5Sswilcox if (reply(" CONTINUE") == 0) { 748*355d6bb5Sswilcox retval = -1; 749*355d6bb5Sswilcox goto finish; 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate } 752*355d6bb5Sswilcox break; 753*355d6bb5Sswilcox } 7547c478bd9Sstevel@tonic-gate 755*355d6bb5Sswilcox if (!do_errorlock(LOCKFS_ELOCK)) { 756*355d6bb5Sswilcox if (preen) { 757*355d6bb5Sswilcox retval = -1; 758*355d6bb5Sswilcox goto finish; 759*355d6bb5Sswilcox } 760*355d6bb5Sswilcox if (reply("error-lock reset failed; CONTINUE") == 0) { 761*355d6bb5Sswilcox retval = -1; 762*355d6bb5Sswilcox goto finish; 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate } 765*355d6bb5Sswilcox 766*355d6bb5Sswilcox sblock.fs_state = FSOKAY - (long)sblock.fs_time; 767*355d6bb5Sswilcox sblock.fs_clean = FSFIX; 768*355d6bb5Sswilcox sbdirty(); 769*355d6bb5Sswilcox write_altsb(fswritefd); 770*355d6bb5Sswilcox 771*355d6bb5Sswilcox finish: 772*355d6bb5Sswilcox return (retval); 773*355d6bb5Sswilcox } 774*355d6bb5Sswilcox 775*355d6bb5Sswilcox static void 776*355d6bb5Sswilcox getsummaryinfo(void) 777*355d6bb5Sswilcox { 778*355d6bb5Sswilcox size_t size; 779*355d6bb5Sswilcox int failed; 780*355d6bb5Sswilcox int asked; 781*355d6bb5Sswilcox int i, j; 782*355d6bb5Sswilcox caddr_t sip; 783*355d6bb5Sswilcox 7847c478bd9Sstevel@tonic-gate /* 7857c478bd9Sstevel@tonic-gate * read in the summary info. 7867c478bd9Sstevel@tonic-gate */ 787*355d6bb5Sswilcox sblock.fs_u.fs_csp = calloc(1, sblock.fs_cssize); 788*355d6bb5Sswilcox if (sblock.fs_u.fs_csp == NULL) 789*355d6bb5Sswilcox errexit( 790*355d6bb5Sswilcox "cannot allocate %u bytes for cylinder group summary info\n", 791*355d6bb5Sswilcox (unsigned)sblock.fs_cssize); 792*355d6bb5Sswilcox sip = (caddr_t)sblock.fs_u.fs_csp; 793*355d6bb5Sswilcox asked = 0; 7947c478bd9Sstevel@tonic-gate for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 7957c478bd9Sstevel@tonic-gate size = sblock.fs_cssize - i < sblock.fs_bsize ? 796*355d6bb5Sswilcox sblock.fs_cssize - i : sblock.fs_bsize; 797*355d6bb5Sswilcox failed = fsck_bread(fsreadfd, sip, 7987c478bd9Sstevel@tonic-gate fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 799*355d6bb5Sswilcox size); 800*355d6bb5Sswilcox if (failed && !asked) { 801*355d6bb5Sswilcox pfatal("BAD SUMMARY INFORMATION"); 802*355d6bb5Sswilcox if (reply("CONTINUE") == 0) { 803*355d6bb5Sswilcox ckfini(); 804*355d6bb5Sswilcox exit(EXFNDERRS); 805*355d6bb5Sswilcox } 806*355d6bb5Sswilcox asked = 1; 807*355d6bb5Sswilcox } 8087c478bd9Sstevel@tonic-gate sip += size; 8097c478bd9Sstevel@tonic-gate } 810*355d6bb5Sswilcox } 811*355d6bb5Sswilcox 812*355d6bb5Sswilcox /* 813*355d6bb5Sswilcox * Reverses the effects of getsummaryinfo(). 814*355d6bb5Sswilcox */ 815*355d6bb5Sswilcox static void 816*355d6bb5Sswilcox ungetsummaryinfo(void) 817*355d6bb5Sswilcox { 818*355d6bb5Sswilcox if ((sblk.b_un.b_fs != NULL) && 819*355d6bb5Sswilcox (sblk.b_un.b_fs->fs_u.fs_csp != NULL)) { 820*355d6bb5Sswilcox free(sblk.b_un.b_fs->fs_u.fs_csp); 821*355d6bb5Sswilcox sblk.b_un.b_fs->fs_u.fs_csp = NULL; 8227c478bd9Sstevel@tonic-gate } 823*355d6bb5Sswilcox } 824*355d6bb5Sswilcox 825*355d6bb5Sswilcox /* 826*355d6bb5Sswilcox * Allocate and initialize the global tables. 827*355d6bb5Sswilcox * It is the responsibility of the caller to clean up and allocations 828*355d6bb5Sswilcox * if an error is returned. 829*355d6bb5Sswilcox */ 830*355d6bb5Sswilcox static int 831*355d6bb5Sswilcox create_and_init_maps(void) 832*355d6bb5Sswilcox { 833*355d6bb5Sswilcox int64_t bmapsize; 834*355d6bb5Sswilcox int retval = 0; 835*355d6bb5Sswilcox 836*355d6bb5Sswilcox maxfsblock = sblock.fs_size; 837*355d6bb5Sswilcox maxino = sblock.fs_ncg * sblock.fs_ipg; 838*355d6bb5Sswilcox 8397c478bd9Sstevel@tonic-gate bmapsize = roundup(howmany((uint64_t)maxfsblock, NBBY), 8407c478bd9Sstevel@tonic-gate sizeof (short)); 8417c478bd9Sstevel@tonic-gate blockmap = calloc((size_t)bmapsize, sizeof (char)); 8427c478bd9Sstevel@tonic-gate if (blockmap == NULL) { 843*355d6bb5Sswilcox (void) printf("cannot alloc %lld bytes for blockmap\n", 844*355d6bb5Sswilcox (longlong_t)bmapsize); 845*355d6bb5Sswilcox retval = -1; 846*355d6bb5Sswilcox goto finish; 8477c478bd9Sstevel@tonic-gate } 848*355d6bb5Sswilcox statemap = calloc((size_t)(maxino + 1), sizeof (*statemap)); 8497c478bd9Sstevel@tonic-gate if (statemap == NULL) { 850*355d6bb5Sswilcox (void) printf("cannot alloc %lld bytes for statemap\n", 851*355d6bb5Sswilcox (longlong_t)(maxino + 1) * sizeof (*statemap)); 852*355d6bb5Sswilcox retval = -1; 853*355d6bb5Sswilcox goto finish; 8547c478bd9Sstevel@tonic-gate } 855*355d6bb5Sswilcox lncntp = (short *)calloc((size_t)(maxino + 1), sizeof (short)); 8567c478bd9Sstevel@tonic-gate if (lncntp == NULL) { 857*355d6bb5Sswilcox (void) printf("cannot alloc %lld bytes for lncntp\n", 858*355d6bb5Sswilcox (longlong_t)(maxino + 1) * sizeof (short)); 859*355d6bb5Sswilcox retval = -1; 860*355d6bb5Sswilcox goto finish; 8617c478bd9Sstevel@tonic-gate } 862*355d6bb5Sswilcox 863*355d6bb5Sswilcox /* 864*355d6bb5Sswilcox * If we had to fake up a superblock, it won't show that there 865*355d6bb5Sswilcox * are any directories at all. This causes problems when we 866*355d6bb5Sswilcox * use numdirs to calculate hash keys, so use something at least 867*355d6bb5Sswilcox * vaguely plausible. 868*355d6bb5Sswilcox */ 8697c478bd9Sstevel@tonic-gate numdirs = sblock.fs_cstotal.cs_ndir; 870*355d6bb5Sswilcox if (numdirs == 0) 871*355d6bb5Sswilcox numdirs = sblock.fs_ipg * sblock.fs_ncg / 2; 8727c478bd9Sstevel@tonic-gate listmax = numdirs + 10; 8737c478bd9Sstevel@tonic-gate inpsort = (struct inoinfo **)calloc((unsigned)listmax, 8747c478bd9Sstevel@tonic-gate sizeof (struct inoinfo *)); 8757c478bd9Sstevel@tonic-gate inphead = (struct inoinfo **)calloc((unsigned)numdirs, 8767c478bd9Sstevel@tonic-gate sizeof (struct inoinfo *)); 8777c478bd9Sstevel@tonic-gate if (inpsort == NULL || inphead == NULL) { 878*355d6bb5Sswilcox (void) printf("cannot alloc %lld bytes for inphead\n", 879*355d6bb5Sswilcox (longlong_t)numdirs * sizeof (struct inoinfo *)); 880*355d6bb5Sswilcox retval = -1; 881*355d6bb5Sswilcox goto finish; 882*355d6bb5Sswilcox } 883*355d6bb5Sswilcox if (debug) { 884*355d6bb5Sswilcox if (listmax > USI_MAX) 885*355d6bb5Sswilcox errexit("create_and_init_maps: listmax overflowed\n"); 886*355d6bb5Sswilcox if (numdirs > USI_MAX) 887*355d6bb5Sswilcox errexit("create_and_init_maps: numdirs overflowed\n"); 8887c478bd9Sstevel@tonic-gate } 889*355d6bb5Sswilcox 8907c478bd9Sstevel@tonic-gate numacls = numdirs; 8917c478bd9Sstevel@tonic-gate aclmax = numdirs + 10; 892*355d6bb5Sswilcox aclpsort = (struct inoinfo **)calloc((unsigned)aclmax, 893*355d6bb5Sswilcox sizeof (struct inoinfo *)); 894*355d6bb5Sswilcox aclphead = (struct inoinfo **)calloc((unsigned)numacls, 895*355d6bb5Sswilcox sizeof (struct inoinfo *)); 8967c478bd9Sstevel@tonic-gate if (aclpsort == NULL || aclphead == NULL) { 897*355d6bb5Sswilcox (void) printf("cannot alloc %lld bytes for aclphead\n", 898*355d6bb5Sswilcox (longlong_t)numacls * sizeof (struct inoinfo *)); 899*355d6bb5Sswilcox retval = -1; 900*355d6bb5Sswilcox goto finish; 901*355d6bb5Sswilcox } 902*355d6bb5Sswilcox if (debug) { 903*355d6bb5Sswilcox if (aclmax > USI_MAX) 904*355d6bb5Sswilcox errexit("create_and_init_maps: aclmax overflowed\n"); 905*355d6bb5Sswilcox if (numacls > USI_MAX) 906*355d6bb5Sswilcox errexit("create_and_init_maps: numacls overflowed\n"); 9077c478bd9Sstevel@tonic-gate } 9087c478bd9Sstevel@tonic-gate aclplast = 0L; 9097c478bd9Sstevel@tonic-gate inplast = 0L; 910*355d6bb5Sswilcox 911*355d6bb5Sswilcox finish: 912*355d6bb5Sswilcox return (retval); 913*355d6bb5Sswilcox } 914*355d6bb5Sswilcox 915*355d6bb5Sswilcox caddr_t 916*355d6bb5Sswilcox setup(caddr_t dev) 917*355d6bb5Sswilcox { 918*355d6bb5Sswilcox int corefs; 919*355d6bb5Sswilcox static char devstr[MAXPATHLEN + 1]; 920*355d6bb5Sswilcox 921*355d6bb5Sswilcox havesb = 0; 922*355d6bb5Sswilcox devname = devstr; 923*355d6bb5Sswilcox 924*355d6bb5Sswilcox derive_devstr(dev, devstr, sizeof (devstr)); 925*355d6bb5Sswilcox errorlocked = is_errorlocked(devstr); 926*355d6bb5Sswilcox corefs = check_mount_state(devstr, sizeof (devstr)); 927*355d6bb5Sswilcox 928*355d6bb5Sswilcox sblock_init(); 929*355d6bb5Sswilcox 930*355d6bb5Sswilcox if (open_and_intro(devstr, corefs) == -1) 931*355d6bb5Sswilcox goto cleanup; 932*355d6bb5Sswilcox 933*355d6bb5Sswilcox /* 934*355d6bb5Sswilcox * Check log state 935*355d6bb5Sswilcox */ 936*355d6bb5Sswilcox if (!logsetup(devstr)) 937*355d6bb5Sswilcox goto cleanup; 938*355d6bb5Sswilcox 939*355d6bb5Sswilcox /* 940*355d6bb5Sswilcox * Flush fs if we're going to do anything other than a sanity check. 941*355d6bb5Sswilcox * Note, if logging then the fs was already flushed in logsetup(). 942*355d6bb5Sswilcox */ 943*355d6bb5Sswilcox if (!islog && !mflag) 944*355d6bb5Sswilcox flush_fs(); 945*355d6bb5Sswilcox 946*355d6bb5Sswilcox if (find_superblock(devstr) == -1) 947*355d6bb5Sswilcox goto cleanup; 948*355d6bb5Sswilcox 949*355d6bb5Sswilcox fixup_superblock(); 950*355d6bb5Sswilcox 951*355d6bb5Sswilcox if (errorlocked && 952*355d6bb5Sswilcox (initial_error_state_adjust() == -1)) 953*355d6bb5Sswilcox goto cleanup; 954*355d6bb5Sswilcox 955*355d6bb5Sswilcox /* 956*355d6bb5Sswilcox * asblk could be dirty because we found a mismatch between 957*355d6bb5Sswilcox * the primary superblock and one of its backups in checksb(). 958*355d6bb5Sswilcox */ 959*355d6bb5Sswilcox if (asblk.b_dirty && !bflag) { 960*355d6bb5Sswilcox (void) memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize); 961*355d6bb5Sswilcox flush(fswritefd, &asblk); 962*355d6bb5Sswilcox } 963*355d6bb5Sswilcox 964*355d6bb5Sswilcox getsummaryinfo(); 965*355d6bb5Sswilcox 966*355d6bb5Sswilcox /* 967*355d6bb5Sswilcox * if not error-locked, using the standard superblock, 968*355d6bb5Sswilcox * not bad log, not forced, preening, and is clean; 969*355d6bb5Sswilcox * stop checking 970*355d6bb5Sswilcox */ 971*355d6bb5Sswilcox if (!errorlocked && (bflag == 0) && 972*355d6bb5Sswilcox ((!islog || islogok) && 973*355d6bb5Sswilcox (fflag == 0) && preen && 974*355d6bb5Sswilcox (FSOKAY == (sblock.fs_state + sblock.fs_time)) && 975*355d6bb5Sswilcox ((sblock.fs_clean == FSLOG && islog) || 976*355d6bb5Sswilcox ((sblock.fs_clean == FSCLEAN) || (sblock.fs_clean == FSSTABLE))))) { 977*355d6bb5Sswilcox iscorrupt = 0; 978*355d6bb5Sswilcox printclean(); 979*355d6bb5Sswilcox goto cleanup; 980*355d6bb5Sswilcox } 981*355d6bb5Sswilcox 982*355d6bb5Sswilcox if (create_and_init_maps() == -1) 983*355d6bb5Sswilcox goto nomaps; 984*355d6bb5Sswilcox 9857c478bd9Sstevel@tonic-gate bufinit(); 9867c478bd9Sstevel@tonic-gate return (devstr); 9877c478bd9Sstevel@tonic-gate 988*355d6bb5Sswilcox nomaps: 9897c478bd9Sstevel@tonic-gate ckfini(); 990*355d6bb5Sswilcox exitstat = EXERRFATAL; 991*355d6bb5Sswilcox /* FALLTHROUGH */ 992*355d6bb5Sswilcox 993*355d6bb5Sswilcox cleanup: 994*355d6bb5Sswilcox unbufinit(); 995*355d6bb5Sswilcox uncreate_maps(); 996*355d6bb5Sswilcox ungetsummaryinfo(); 997*355d6bb5Sswilcox 998*355d6bb5Sswilcox /* 999*355d6bb5Sswilcox * Can't get rid of the superblock buffer, because our 1000*355d6bb5Sswilcox * caller references it to generate the summary statistics. 1001*355d6bb5Sswilcox */ 1002*355d6bb5Sswilcox 1003*355d6bb5Sswilcox return (NULL); 1004*355d6bb5Sswilcox } 1005*355d6bb5Sswilcox 1006*355d6bb5Sswilcox /* 1007*355d6bb5Sswilcox * Undoes the allocations in create_and_init_maps() 1008*355d6bb5Sswilcox */ 1009*355d6bb5Sswilcox static void 1010*355d6bb5Sswilcox uncreate_maps(void) 1011*355d6bb5Sswilcox { 1012*355d6bb5Sswilcox /* 1013*355d6bb5Sswilcox * No ordering dependency amongst these, so they are here in 1014*355d6bb5Sswilcox * the same order they were calculated. 1015*355d6bb5Sswilcox */ 1016*355d6bb5Sswilcox if (blockmap != NULL) 1017*355d6bb5Sswilcox free(blockmap); 1018*355d6bb5Sswilcox if (statemap != NULL) 1019*355d6bb5Sswilcox free(statemap); 1020*355d6bb5Sswilcox if (lncntp != NULL) 1021*355d6bb5Sswilcox free(lncntp); 1022*355d6bb5Sswilcox if (inpsort != NULL) 1023*355d6bb5Sswilcox free(inpsort); 1024*355d6bb5Sswilcox if (inphead != NULL) 1025*355d6bb5Sswilcox free(inphead); 1026*355d6bb5Sswilcox if (aclpsort != NULL) 1027*355d6bb5Sswilcox free(aclpsort); 1028*355d6bb5Sswilcox if (aclphead != NULL) 1029*355d6bb5Sswilcox free(aclphead); 10307c478bd9Sstevel@tonic-gate } 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate /* 10337c478bd9Sstevel@tonic-gate * mkfs limits the size of the inode map to be no more than a third of 10347c478bd9Sstevel@tonic-gate * the cylinder group space. We'll use that value for sanity checking 10357c478bd9Sstevel@tonic-gate * the superblock's inode per group value. 10367c478bd9Sstevel@tonic-gate */ 10377c478bd9Sstevel@tonic-gate #define MAXIpG (roundup(sblock.fs_bsize * NBBY / 3, sblock.fs_inopb)) 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate /* 10407c478bd9Sstevel@tonic-gate * Check the super block and its summary info. 10417c478bd9Sstevel@tonic-gate */ 10427c478bd9Sstevel@tonic-gate static int 10437c478bd9Sstevel@tonic-gate checksb(int listerr) 10447c478bd9Sstevel@tonic-gate { 1045*355d6bb5Sswilcox caddr_t err; 1046*355d6bb5Sswilcox 10477c478bd9Sstevel@tonic-gate /* 10487c478bd9Sstevel@tonic-gate * When the fs check is successfully completed, the alternate super 10497c478bd9Sstevel@tonic-gate * block at sblk.b_bno will be overwritten by ckfini() with the 10507c478bd9Sstevel@tonic-gate * repaired super block. 10517c478bd9Sstevel@tonic-gate */ 1052*355d6bb5Sswilcox sblk.b_bno = bflag ? bflag : (SBOFF / dev_bsize); 10537c478bd9Sstevel@tonic-gate sblk.b_size = SBSIZE; 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate /* 1056*355d6bb5Sswilcox * Sanity-check some of the values we are going to use later 1057*355d6bb5Sswilcox * in allocation requests. 10587c478bd9Sstevel@tonic-gate */ 10597c478bd9Sstevel@tonic-gate if (sblock.fs_cstotal.cs_ndir < 1 || 10607c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_ndir > sblock.fs_ncg * sblock.fs_ipg) { 1061*355d6bb5Sswilcox if (verbose) 1062*355d6bb5Sswilcox (void) printf( 1063*355d6bb5Sswilcox "Found %d directories, should be between 1 and %d inclusive.\n", 1064*355d6bb5Sswilcox sblock.fs_cstotal.cs_ndir, 1065*355d6bb5Sswilcox sblock.fs_ncg * sblock.fs_ipg); 1066*355d6bb5Sswilcox err = "NUMBER OF DIRECTORIES OUT OF RANGE"; 1067*355d6bb5Sswilcox goto failedsb; 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate if (sblock.fs_nrpos <= 0 || sblock.fs_postbloff < 0 || 10717c478bd9Sstevel@tonic-gate sblock.fs_cpc < 0 || 10727c478bd9Sstevel@tonic-gate (sblock.fs_postbloff + 1073*355d6bb5Sswilcox (sblock.fs_nrpos * sblock.fs_cpc * sizeof (short))) > 10747c478bd9Sstevel@tonic-gate sblock.fs_sbsize) { 1075*355d6bb5Sswilcox err = "ROTATIONAL POSITION TABLE SIZE OUT OF RANGE"; 1076*355d6bb5Sswilcox goto failedsb; 10777c478bd9Sstevel@tonic-gate } 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate if (sblock.fs_cssize != 1080*355d6bb5Sswilcox fragroundup(&sblock, sblock.fs_ncg * sizeof (struct csum))) { 1081*355d6bb5Sswilcox err = "SIZE OF CYLINDER GROUP SUMMARY AREA WRONG"; 1082*355d6bb5Sswilcox goto failedsb; 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate if (sblock.fs_inopb != (sblock.fs_bsize / sizeof (struct dinode))) { 1086*355d6bb5Sswilcox err = "INOPB NONSENSICAL RELATIVE TO BSIZE"; 1087*355d6bb5Sswilcox goto failedsb; 1088*355d6bb5Sswilcox } 1089*355d6bb5Sswilcox 1090*355d6bb5Sswilcox if (sblock.fs_bsize > MAXBSIZE) { 1091*355d6bb5Sswilcox err = "BLOCK SIZE LARGER THAN MAXIMUM SUPPORTED"; 1092*355d6bb5Sswilcox goto failedsb; 10937c478bd9Sstevel@tonic-gate } 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate if (sblock.fs_bsize != (sblock.fs_frag * sblock.fs_fsize)) { 1096*355d6bb5Sswilcox err = "FRAGS PER BLOCK OR FRAG SIZE WRONG"; 1097*355d6bb5Sswilcox goto failedsb; 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate if (sblock.fs_dsize >= sblock.fs_size) { 1101*355d6bb5Sswilcox err = "NUMBER OF DATA BLOCKS OUT OF RANGE"; 1102*355d6bb5Sswilcox goto failedsb; 11037c478bd9Sstevel@tonic-gate } 11047c478bd9Sstevel@tonic-gate 1105*355d6bb5Sswilcox #if 0 1106*355d6bb5Sswilcox if (sblock.fs_size > 1107*355d6bb5Sswilcox (sblock.fs_nsect * sblock.fs_ntrak * sblock.fs_ncyl)) { 1108*355d6bb5Sswilcox err = "FILESYSTEM SIZE LARGER THAN DEVICE"; 1109*355d6bb5Sswilcox goto failedsb; 1110*355d6bb5Sswilcox } 1111*355d6bb5Sswilcox #endif 1112*355d6bb5Sswilcox 11137c478bd9Sstevel@tonic-gate /* 11147c478bd9Sstevel@tonic-gate * Check that the number of inodes per group isn't less than or 11157c478bd9Sstevel@tonic-gate * equal to zero. Also makes sure it isn't more than the 11167c478bd9Sstevel@tonic-gate * maximum number mkfs enforces. 11177c478bd9Sstevel@tonic-gate */ 11187c478bd9Sstevel@tonic-gate if (sblock.fs_ipg <= 0 || sblock.fs_ipg > MAXIpG) { 1119*355d6bb5Sswilcox err = "INODES PER GROUP OUT OF RANGE"; 1120*355d6bb5Sswilcox goto failedsb; 1121*355d6bb5Sswilcox } 1122*355d6bb5Sswilcox 1123*355d6bb5Sswilcox if (sblock.fs_cgsize > sblock.fs_bsize) { 1124*355d6bb5Sswilcox err = "CG HEADER LARGER THAN ONE BLOCK"; 1125*355d6bb5Sswilcox goto failedsb; 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate /* 11297c478bd9Sstevel@tonic-gate * Set all possible fields that could differ, then do check 11307c478bd9Sstevel@tonic-gate * of whole super block against an alternate super block. 11317c478bd9Sstevel@tonic-gate * When an alternate super-block is specified this check is skipped. 11327c478bd9Sstevel@tonic-gate */ 1133*355d6bb5Sswilcox (void) getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), 1134*355d6bb5Sswilcox (size_t)sblock.fs_sbsize); 1135*355d6bb5Sswilcox if (asblk.b_errs != 0) { 1136*355d6bb5Sswilcox brelse(&asblk); 11377c478bd9Sstevel@tonic-gate return (0); 1138*355d6bb5Sswilcox } 1139*355d6bb5Sswilcox if (bflag != 0) { 11407c478bd9Sstevel@tonic-gate /* 1141*355d6bb5Sswilcox * Invalidate clean flag and state information. 1142*355d6bb5Sswilcox * Note that we couldn't return until after the 1143*355d6bb5Sswilcox * above getblk(), because we're going to want to 1144*355d6bb5Sswilcox * update asblk when everything's done. 11457c478bd9Sstevel@tonic-gate */ 11467c478bd9Sstevel@tonic-gate sblock.fs_clean = FSACTIVE; 11477c478bd9Sstevel@tonic-gate sblock.fs_state = (long)sblock.fs_time; 11487c478bd9Sstevel@tonic-gate sblock.fs_reclaim = 0; 11497c478bd9Sstevel@tonic-gate sbdirty(); 11507c478bd9Sstevel@tonic-gate havesb = 1; 11517c478bd9Sstevel@tonic-gate return (1); 11527c478bd9Sstevel@tonic-gate } 11537c478bd9Sstevel@tonic-gate altsblock.fs_link = sblock.fs_link; 11547c478bd9Sstevel@tonic-gate altsblock.fs_rolled = sblock.fs_rolled; 11557c478bd9Sstevel@tonic-gate altsblock.fs_time = sblock.fs_time; 11567c478bd9Sstevel@tonic-gate altsblock.fs_state = sblock.fs_state; 11577c478bd9Sstevel@tonic-gate altsblock.fs_cstotal = sblock.fs_cstotal; 11587c478bd9Sstevel@tonic-gate altsblock.fs_cgrotor = sblock.fs_cgrotor; 11597c478bd9Sstevel@tonic-gate altsblock.fs_fmod = sblock.fs_fmod; 11607c478bd9Sstevel@tonic-gate altsblock.fs_clean = sblock.fs_clean; 11617c478bd9Sstevel@tonic-gate altsblock.fs_ronly = sblock.fs_ronly; 11627c478bd9Sstevel@tonic-gate altsblock.fs_flags = sblock.fs_flags; 11637c478bd9Sstevel@tonic-gate altsblock.fs_maxcontig = sblock.fs_maxcontig; 11647c478bd9Sstevel@tonic-gate altsblock.fs_minfree = sblock.fs_minfree; 11657c478bd9Sstevel@tonic-gate altsblock.fs_optim = sblock.fs_optim; 11667c478bd9Sstevel@tonic-gate altsblock.fs_rotdelay = sblock.fs_rotdelay; 11677c478bd9Sstevel@tonic-gate altsblock.fs_maxbpg = sblock.fs_maxbpg; 11687c478bd9Sstevel@tonic-gate altsblock.fs_logbno = sblock.fs_logbno; 11697c478bd9Sstevel@tonic-gate altsblock.fs_reclaim = sblock.fs_reclaim; 11707c478bd9Sstevel@tonic-gate altsblock.fs_si = sblock.fs_si; 1171*355d6bb5Sswilcox (void) memmove((void *)altsblock.fs_fsmnt, (void *)sblock.fs_fsmnt, 1172*355d6bb5Sswilcox sizeof (sblock.fs_fsmnt)); 11737c478bd9Sstevel@tonic-gate /* 11747c478bd9Sstevel@tonic-gate * The following should not have to be copied. 11757c478bd9Sstevel@tonic-gate */ 1176*355d6bb5Sswilcox (void) memmove((void *)altsblock.fs_u.fs_csp_pad, 1177*355d6bb5Sswilcox (void *)sblock.fs_u.fs_csp_pad, sizeof (sblock.fs_u.fs_csp_pad)); 11787c478bd9Sstevel@tonic-gate altsblock.fs_fsbtodb = sblock.fs_fsbtodb; 11797c478bd9Sstevel@tonic-gate altsblock.fs_npsect = sblock.fs_npsect; 11807c478bd9Sstevel@tonic-gate altsblock.fs_nrpos = sblock.fs_nrpos; 1181*355d6bb5Sswilcox if (memcmp((void *)&sblock, (void *)&altsblock, 1182*355d6bb5Sswilcox (size_t)sblock.fs_sbsize) != 0) { 1183*355d6bb5Sswilcox err = "BAD VALUES IN SUPER BLOCK"; 1184*355d6bb5Sswilcox goto failedsb; 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate havesb = 1; 11877c478bd9Sstevel@tonic-gate return (1); 1188*355d6bb5Sswilcox 1189*355d6bb5Sswilcox failedsb: 1190*355d6bb5Sswilcox badsb(listerr, err); 1191*355d6bb5Sswilcox return (0); 11927c478bd9Sstevel@tonic-gate } 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate static void 1195*355d6bb5Sswilcox badsb(int listerr, caddr_t s) 11967c478bd9Sstevel@tonic-gate { 11977c478bd9Sstevel@tonic-gate if (!listerr) 11987c478bd9Sstevel@tonic-gate return; 11997c478bd9Sstevel@tonic-gate if (preen) 1200*355d6bb5Sswilcox (void) printf("%s: ", devname); 1201*355d6bb5Sswilcox (void) printf("BAD SUPERBLOCK AT BLOCK %d: %s\n", 1202*355d6bb5Sswilcox bflag != 0 ? bflag : SBLOCK, s); 1203*355d6bb5Sswilcox if (preen) { 1204*355d6bb5Sswilcox pwarn( 1205*355d6bb5Sswilcox "USE AN ALTERNATE SUPERBLOCK TO SUPPLY NEEDED INFORMATION;\n"); 1206*355d6bb5Sswilcox pwarn("e.g. fsck [-F ufs] -o b=# [special ...] \n"); 1207*355d6bb5Sswilcox exitstat = EXERRFATAL; 1208*355d6bb5Sswilcox pfatal( 1209*355d6bb5Sswilcox "where # is the alternate super block. SEE fsck_ufs(1M). \n"); 1210*355d6bb5Sswilcox } 1211*355d6bb5Sswilcox /* we're expected to return if not preening */ 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate /* 12157c478bd9Sstevel@tonic-gate * Write out the super block into each of the alternate super blocks. 12167c478bd9Sstevel@tonic-gate */ 12177c478bd9Sstevel@tonic-gate void 12187c478bd9Sstevel@tonic-gate write_altsb(int fd) 12197c478bd9Sstevel@tonic-gate { 12207c478bd9Sstevel@tonic-gate int cylno; 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate for (cylno = 0; cylno < sblock.fs_ncg; cylno++) 1223*355d6bb5Sswilcox bwrite(fd, (caddr_t)&sblock, fsbtodb(&sblock, 1224*355d6bb5Sswilcox cgsblock(&sblock, cylno)), sblock.fs_sbsize); 1225*355d6bb5Sswilcox } 1226*355d6bb5Sswilcox 1227*355d6bb5Sswilcox static void 1228*355d6bb5Sswilcox sblock_init(void) 1229*355d6bb5Sswilcox { 1230*355d6bb5Sswilcox fsmodified = 0; 1231*355d6bb5Sswilcox if (errorlocked) 1232*355d6bb5Sswilcox isdirty = 1; 1233*355d6bb5Sswilcox lfdir = 0; 1234*355d6bb5Sswilcox initbarea(&sblk); 1235*355d6bb5Sswilcox initbarea(&asblk); 1236*355d6bb5Sswilcox 1237*355d6bb5Sswilcox /* 1238*355d6bb5Sswilcox * May have buffer left over from previous filesystem check. 1239*355d6bb5Sswilcox */ 1240*355d6bb5Sswilcox if (sblk.b_un.b_buf == NULL) 1241*355d6bb5Sswilcox sblk.b_un.b_buf = calloc(1, SBSIZE); 1242*355d6bb5Sswilcox if (asblk.b_un.b_buf == NULL) 1243*355d6bb5Sswilcox asblk.b_un.b_buf = calloc(1, SBSIZE); 1244*355d6bb5Sswilcox if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) 1245*355d6bb5Sswilcox errexit("cannot allocate space for superblock\n"); 1246*355d6bb5Sswilcox /* 1247*355d6bb5Sswilcox * Could get the actual sector size from the device here, 1248*355d6bb5Sswilcox * but considering how much would need to change in the rest 1249*355d6bb5Sswilcox * of the system before it'd be a problem for us, it's not 1250*355d6bb5Sswilcox * worth worrying about right now. 1251*355d6bb5Sswilcox */ 1252*355d6bb5Sswilcox dev_bsize = secsize = DEV_BSIZE; 1253*355d6bb5Sswilcox } 1254*355d6bb5Sswilcox 1255*355d6bb5Sswilcox /* 1256*355d6bb5Sswilcox * Calculate a prototype superblock based on information in the disk label. 1257*355d6bb5Sswilcox * When done the cgsblock macro can be calculated and the fs_ncg field 1258*355d6bb5Sswilcox * can be used. Do NOT attempt to use other macros without verifying that 1259*355d6bb5Sswilcox * their needed information is available! 1260*355d6bb5Sswilcox * 1261*355d6bb5Sswilcox * In BSD, the disk label includes all sorts of useful information, 1262*355d6bb5Sswilcox * like cpg. Solaris doesn't have that, and deriving it (as well as 1263*355d6bb5Sswilcox * some other parameters) is difficult. Rather than duplicate the 1264*355d6bb5Sswilcox * code, just ask mkfs what it would've come up with by default. 1265*355d6bb5Sswilcox * Ideally, we'd just link in the code, but given the source base 1266*355d6bb5Sswilcox * involved, it's more practical to just get a binary dump. 1267*355d6bb5Sswilcox * 1268*355d6bb5Sswilcox * The one minor drawback to the above approach is that newfs and mkfs 1269*355d6bb5Sswilcox * will produce vastly different layouts for the same partition if 1270*355d6bb5Sswilcox * they're allowed to default everything. So, if the superblock that 1271*355d6bb5Sswilcox * mkfs gives us doesn't work for guessing where the alternates are, 1272*355d6bb5Sswilcox * we need to try newfs. 1273*355d6bb5Sswilcox */ 1274*355d6bb5Sswilcox static int 1275*355d6bb5Sswilcox calcsb(calcsb_t style, caddr_t dev, int devfd, struct fs *fs) 1276*355d6bb5Sswilcox { 1277*355d6bb5Sswilcox #define FROM_CHILD 0 1278*355d6bb5Sswilcox #define TO_FSCK 1 1279*355d6bb5Sswilcox #define CMD_IDX 0 1280*355d6bb5Sswilcox #define DEV_IDX 3 1281*355d6bb5Sswilcox #define SIZE_IDX 4 1282*355d6bb5Sswilcox 1283*355d6bb5Sswilcox int child_pipe[2]; 1284*355d6bb5Sswilcox caddr_t mkfsline[] = { 1285*355d6bb5Sswilcox "", /* CMD_IDX */ 1286*355d6bb5Sswilcox "-o", 1287*355d6bb5Sswilcox "calcbinsb,N", 1288*355d6bb5Sswilcox NULL, /* DEV_IDX */ 1289*355d6bb5Sswilcox NULL, /* SIZE_IDX */ 1290*355d6bb5Sswilcox NULL 1291*355d6bb5Sswilcox }; 1292*355d6bb5Sswilcox caddr_t newfsline[] = { 1293*355d6bb5Sswilcox "", /* CMD_IDX */ 1294*355d6bb5Sswilcox "-B", 1295*355d6bb5Sswilcox "-N", 1296*355d6bb5Sswilcox NULL, /* DEV_IDX */ 1297*355d6bb5Sswilcox NULL 1298*355d6bb5Sswilcox }; 1299*355d6bb5Sswilcox int pending, transferred; 1300*355d6bb5Sswilcox caddr_t *cmdline; 1301*355d6bb5Sswilcox caddr_t target; 1302*355d6bb5Sswilcox caddr_t sizestr = NULL; 1303*355d6bb5Sswilcox caddr_t path_old, path_new, mkfs_dir, mkfs_path, newfs_path; 1304*355d6bb5Sswilcox caddr_t slash; 1305*355d6bb5Sswilcox diskaddr_t size; 1306*355d6bb5Sswilcox int devnull; 1307*355d6bb5Sswilcox 1308*355d6bb5Sswilcox switch (style) { 1309*355d6bb5Sswilcox case MKFS_STYLE: 1310*355d6bb5Sswilcox if (debug) 1311*355d6bb5Sswilcox (void) printf("calcsb() going with style MKFS\n"); 1312*355d6bb5Sswilcox cmdline = mkfsline; 1313*355d6bb5Sswilcox break; 1314*355d6bb5Sswilcox case NEWFS_STYLE: 1315*355d6bb5Sswilcox if (debug) 1316*355d6bb5Sswilcox (void) printf("calcsb() going with style NEWFS\n"); 1317*355d6bb5Sswilcox cmdline = newfsline; 1318*355d6bb5Sswilcox break; 1319*355d6bb5Sswilcox default: 1320*355d6bb5Sswilcox if (debug) 1321*355d6bb5Sswilcox (void) printf("calcsb() doesn't undestand style %d\n", 1322*355d6bb5Sswilcox style); 1323*355d6bb5Sswilcox return (0); 1324*355d6bb5Sswilcox } 1325*355d6bb5Sswilcox 1326*355d6bb5Sswilcox cmdline[DEV_IDX] = dev; 1327*355d6bb5Sswilcox 1328*355d6bb5Sswilcox /* 1329*355d6bb5Sswilcox * Normally, only use the stock versions of the utilities. 1330*355d6bb5Sswilcox * However, if we're debugging, the odds are that we're 1331*355d6bb5Sswilcox * using experimental versions of them as well, so allow 1332*355d6bb5Sswilcox * some flexibility. 1333*355d6bb5Sswilcox */ 1334*355d6bb5Sswilcox mkfs_path = getenv("MKFS_PATH"); 1335*355d6bb5Sswilcox if (!debug || (mkfs_path == NULL)) 1336*355d6bb5Sswilcox mkfs_path = MKFS_PATH; 1337*355d6bb5Sswilcox 1338*355d6bb5Sswilcox newfs_path = getenv("NEWFS_PATH"); 1339*355d6bb5Sswilcox if (!debug || (newfs_path == NULL)) 1340*355d6bb5Sswilcox newfs_path = NEWFS_PATH; 1341*355d6bb5Sswilcox 1342*355d6bb5Sswilcox if (style == MKFS_STYLE) { 1343*355d6bb5Sswilcox cmdline[CMD_IDX] = mkfs_path; 1344*355d6bb5Sswilcox 1345*355d6bb5Sswilcox size = getdisksize(dev, devfd); 1346*355d6bb5Sswilcox if (size == 0) 1347*355d6bb5Sswilcox return (0); 1348*355d6bb5Sswilcox 1349*355d6bb5Sswilcox (void) fsck_asprintf(&sizestr, "%lld", (longlong_t)size); 1350*355d6bb5Sswilcox cmdline[SIZE_IDX] = sizestr; 1351*355d6bb5Sswilcox } else if (style == NEWFS_STYLE) { 1352*355d6bb5Sswilcox /* 1353*355d6bb5Sswilcox * Make sure that newfs will find the right version of mkfs. 1354*355d6bb5Sswilcox */ 1355*355d6bb5Sswilcox cmdline[CMD_IDX] = newfs_path; 1356*355d6bb5Sswilcox path_old = getenv("PATH"); 1357*355d6bb5Sswilcox /* mkfs_path is always initialized, despite lint's concerns */ 1358*355d6bb5Sswilcox mkfs_dir = strdup(mkfs_path); 1359*355d6bb5Sswilcox if (mkfs_dir == NULL) 1360*355d6bb5Sswilcox return (0); 1361*355d6bb5Sswilcox /* 1362*355d6bb5Sswilcox * If no location data for mkfs, don't need to do 1363*355d6bb5Sswilcox * anything about PATH. 1364*355d6bb5Sswilcox */ 1365*355d6bb5Sswilcox slash = strrchr(mkfs_dir, '/'); 1366*355d6bb5Sswilcox if (slash != NULL) { 1367*355d6bb5Sswilcox /* 1368*355d6bb5Sswilcox * Just want the dir, so discard the executable name. 1369*355d6bb5Sswilcox */ 1370*355d6bb5Sswilcox *slash = '\0'; 1371*355d6bb5Sswilcox 1372*355d6bb5Sswilcox /* 1373*355d6bb5Sswilcox * newfs uses system() to find mkfs, so make sure 1374*355d6bb5Sswilcox * that the one we want to use is first on the 1375*355d6bb5Sswilcox * list. Don't free path_new upon success, as it 1376*355d6bb5Sswilcox * has become part of the environment. 1377*355d6bb5Sswilcox */ 1378*355d6bb5Sswilcox (void) fsck_asprintf(&path_new, "PATH=%s:%s", 1379*355d6bb5Sswilcox mkfs_dir, path_old); 1380*355d6bb5Sswilcox if (putenv(path_new) != 0) { 1381*355d6bb5Sswilcox free(mkfs_dir); 1382*355d6bb5Sswilcox free(path_new); 1383*355d6bb5Sswilcox return (0); 1384*355d6bb5Sswilcox } 1385*355d6bb5Sswilcox } 1386*355d6bb5Sswilcox free(mkfs_dir); 1387*355d6bb5Sswilcox } else { 1388*355d6bb5Sswilcox /* 1389*355d6bb5Sswilcox * Bad search style, quietly return failure. 1390*355d6bb5Sswilcox */ 1391*355d6bb5Sswilcox if (debug) { 1392*355d6bb5Sswilcox (void) printf("calcsb: got bad style number %d\n", 1393*355d6bb5Sswilcox (int)style); 1394*355d6bb5Sswilcox } 1395*355d6bb5Sswilcox return (0); 1396*355d6bb5Sswilcox } 1397*355d6bb5Sswilcox 1398*355d6bb5Sswilcox if (pipe(child_pipe) < 0) { 1399*355d6bb5Sswilcox pfatal("calcsb: could not create pipe: %s\n", strerror(errno)); 1400*355d6bb5Sswilcox if (sizestr != NULL) 1401*355d6bb5Sswilcox free(sizestr); 1402*355d6bb5Sswilcox return (0); 1403*355d6bb5Sswilcox } 1404*355d6bb5Sswilcox 1405*355d6bb5Sswilcox switch (fork()) { 1406*355d6bb5Sswilcox case -1: 1407*355d6bb5Sswilcox pfatal("calcsb: fork failed: %s\n", strerror(errno)); 1408*355d6bb5Sswilcox if (sizestr != NULL) 1409*355d6bb5Sswilcox free(sizestr); 1410*355d6bb5Sswilcox return (0); 1411*355d6bb5Sswilcox case 0: 1412*355d6bb5Sswilcox if (dup2(child_pipe[TO_FSCK], fileno(stdout)) < 0) { 1413*355d6bb5Sswilcox (void) printf( 1414*355d6bb5Sswilcox "calcsb: could not rename file descriptor: %s\n", 1415*355d6bb5Sswilcox strerror(errno)); 1416*355d6bb5Sswilcox exit(EXBADPARM); 1417*355d6bb5Sswilcox } 1418*355d6bb5Sswilcox devnull = open("/dev/null", O_WRONLY); 1419*355d6bb5Sswilcox if (devnull == -1) { 1420*355d6bb5Sswilcox (void) printf("calcsb: could not open /dev/null: %s\n", 1421*355d6bb5Sswilcox strerror(errno)); 1422*355d6bb5Sswilcox exit(EXBADPARM); 1423*355d6bb5Sswilcox } 1424*355d6bb5Sswilcox if (dup2(devnull, fileno(stderr)) < 0) { 1425*355d6bb5Sswilcox (void) printf( 1426*355d6bb5Sswilcox "calcsb: could not rename file descriptor: %s\n", 1427*355d6bb5Sswilcox strerror(errno)); 1428*355d6bb5Sswilcox exit(EXBADPARM); 1429*355d6bb5Sswilcox } 1430*355d6bb5Sswilcox (void) close(child_pipe[FROM_CHILD]); 1431*355d6bb5Sswilcox (void) execv(cmdline[CMD_IDX], cmdline); 1432*355d6bb5Sswilcox (void) printf("calcsb: could not exec %s: %s\n", 1433*355d6bb5Sswilcox cmdline[CMD_IDX], strerror(errno)); 1434*355d6bb5Sswilcox exit(EXBADPARM); 1435*355d6bb5Sswilcox /* NOTREACHED */ 1436*355d6bb5Sswilcox default: 1437*355d6bb5Sswilcox break; 1438*355d6bb5Sswilcox } 1439*355d6bb5Sswilcox 1440*355d6bb5Sswilcox (void) close(child_pipe[TO_FSCK]); 1441*355d6bb5Sswilcox if (sizestr != NULL) 1442*355d6bb5Sswilcox free(sizestr); 1443*355d6bb5Sswilcox 1444*355d6bb5Sswilcox pending = sizeof (struct fs); 1445*355d6bb5Sswilcox target = (caddr_t)fs; 1446*355d6bb5Sswilcox do { 1447*355d6bb5Sswilcox transferred = read(child_pipe[FROM_CHILD], target, pending); 1448*355d6bb5Sswilcox pending -= transferred; 1449*355d6bb5Sswilcox target += transferred; 1450*355d6bb5Sswilcox } while ((pending > 0) && (transferred > 0)); 1451*355d6bb5Sswilcox 1452*355d6bb5Sswilcox if (pending > 0) { 1453*355d6bb5Sswilcox if (transferred < 0) 1454*355d6bb5Sswilcox pfatal( 1455*355d6bb5Sswilcox "calcsb: binary read of superblock from %s failed: %s\n", 1456*355d6bb5Sswilcox (style == MKFS_STYLE) ? "mkfs" : "newfs", 1457*355d6bb5Sswilcox (transferred < 0) ? strerror(errno) : ""); 1458*355d6bb5Sswilcox else 1459*355d6bb5Sswilcox pfatal( 1460*355d6bb5Sswilcox "calcsb: short read of superblock from %s\n", 1461*355d6bb5Sswilcox (style == MKFS_STYLE) ? "mkfs" : "newfs"); 1462*355d6bb5Sswilcox return (0); 1463*355d6bb5Sswilcox } 1464*355d6bb5Sswilcox 1465*355d6bb5Sswilcox (void) close(child_pipe[FROM_CHILD]); 1466*355d6bb5Sswilcox (void) wait(NULL); 1467*355d6bb5Sswilcox 1468*355d6bb5Sswilcox if ((fs->fs_magic != FS_MAGIC) && 1469*355d6bb5Sswilcox (fs->fs_magic != MTB_UFS_MAGIC)) 1470*355d6bb5Sswilcox return (0); 1471*355d6bb5Sswilcox 1472*355d6bb5Sswilcox return (1); 14737c478bd9Sstevel@tonic-gate } 1474