17c478bd9Sstevel@tonic-gate /* 2504a199eSswilcox * Copyright 2006 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> 34355d6bb5Sswilcox #include <malloc.h> 35355d6bb5Sswilcox #include <limits.h> 36355d6bb5Sswilcox #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> 47355d6bb5Sswilcox #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" 57355d6bb5Sswilcox #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) + \ 67355d6bb5Sswilcox /* 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 72355d6bb5Sswilcox #define altsblock (*asblk.b_un.b_fs) 73355d6bb5Sswilcox #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 74355d6bb5Sswilcox 75355d6bb5Sswilcox /* 76355d6bb5Sswilcox * Methods of determining where alternate superblocks should 77355d6bb5Sswilcox * be. MAX_SB_STYLES must be the last one, and the others need 78355d6bb5Sswilcox * to be positive. 79355d6bb5Sswilcox */ 80355d6bb5Sswilcox typedef enum { 81355d6bb5Sswilcox MKFS_STYLE = 1, NEWFS_STYLE, MAX_SB_STYLES 82355d6bb5Sswilcox } calcsb_t; 83355d6bb5Sswilcox 84355d6bb5Sswilcox static caddr_t calcsb_names[] = { 85355d6bb5Sswilcox "<UNKNOWN>", "MKFS", "NEWFS", "<OUT OF RANGE>" 86355d6bb5Sswilcox }; 87355d6bb5Sswilcox 88355d6bb5Sswilcox struct shadowclientinfo *shadowclientinfo = NULL; 89355d6bb5Sswilcox struct shadowclientinfo *attrclientinfo = NULL; 90355d6bb5Sswilcox int maxshadowclients = 1024; /* allocation size, not limit */ 91355d6bb5Sswilcox 92355d6bb5Sswilcox static void badsb(int, caddr_t); 93355d6bb5Sswilcox static int calcsb(calcsb_t, caddr_t, int, struct fs *); 94355d6bb5Sswilcox static int checksb(int); 95355d6bb5Sswilcox static void flush_fs(void); 96355d6bb5Sswilcox static void sblock_init(void); 97355d6bb5Sswilcox static void uncreate_maps(void); 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate static int 100355d6bb5Sswilcox read_super_block(int listerr) 1017c478bd9Sstevel@tonic-gate { 1027c478bd9Sstevel@tonic-gate int fd; 103355d6bb5Sswilcox caddr_t err; 1047c478bd9Sstevel@tonic-gate 105355d6bb5Sswilcox if (mount_point != NULL) { 1067c478bd9Sstevel@tonic-gate fd = open(mount_point, O_RDONLY); 1077c478bd9Sstevel@tonic-gate if (fd == -1) { 108355d6bb5Sswilcox errexit("fsck: open mount point error: %s", 109355d6bb5Sswilcox strerror(errno)); 110355d6bb5Sswilcox /* NOTREACHED */ 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate /* get the latest super block */ 1137c478bd9Sstevel@tonic-gate if (ioctl(fd, _FIOGETSUPERBLOCK, &sblock)) { 114355d6bb5Sswilcox errexit("fsck: ioctl _FIOGETSUPERBLOCK error: %s", 115355d6bb5Sswilcox strerror(errno)); 116355d6bb5Sswilcox /* NOTREACHED */ 1177c478bd9Sstevel@tonic-gate } 118355d6bb5Sswilcox (void) close(fd); 1197c478bd9Sstevel@tonic-gate } else { 120355d6bb5Sswilcox (void) fsck_bread(fsreadfd, (caddr_t)&sblock, 1217c478bd9Sstevel@tonic-gate bflag != 0 ? (diskaddr_t)bflag : (diskaddr_t)SBLOCK, 122355d6bb5Sswilcox SBSIZE); 1237c478bd9Sstevel@tonic-gate } 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate /* 126355d6bb5Sswilcox * Don't let trash from the disk trip us up later 127355d6bb5Sswilcox * in ungetsummaryinfo(). 128355d6bb5Sswilcox */ 129355d6bb5Sswilcox sblock.fs_u.fs_csp = NULL; 130355d6bb5Sswilcox 131355d6bb5Sswilcox /* 132355d6bb5Sswilcox * Rudimentary consistency checks. Can't really call 133355d6bb5Sswilcox * checksb() here, because there may be outstanding 134355d6bb5Sswilcox * deltas that still need to be applied. 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate if ((sblock.fs_magic != FS_MAGIC) && 1377c478bd9Sstevel@tonic-gate (sblock.fs_magic != MTB_UFS_MAGIC)) { 138355d6bb5Sswilcox err = "MAGIC NUMBER WRONG"; 139355d6bb5Sswilcox goto fail; 1407c478bd9Sstevel@tonic-gate } 1416451fdbcSvsakar if (sblock.fs_magic == FS_MAGIC && 1426451fdbcSvsakar (sblock.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 && 1436451fdbcSvsakar sblock.fs_version != UFS_VERSION_MIN)) { 1446451fdbcSvsakar err = "UNRECOGNIZED VERSION"; 1456451fdbcSvsakar goto fail; 1466451fdbcSvsakar } 1477c478bd9Sstevel@tonic-gate if (sblock.fs_magic == MTB_UFS_MAGIC && 1487c478bd9Sstevel@tonic-gate (sblock.fs_version > MTB_UFS_VERSION_1 || 1497c478bd9Sstevel@tonic-gate sblock.fs_version < MTB_UFS_VERSION_MIN)) { 150355d6bb5Sswilcox err = "UNRECOGNIZED VERSION"; 151355d6bb5Sswilcox goto fail; 1527c478bd9Sstevel@tonic-gate } 1537c478bd9Sstevel@tonic-gate if (sblock.fs_ncg < 1) { 154355d6bb5Sswilcox err = "NCG OUT OF RANGE"; 155355d6bb5Sswilcox goto fail; 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate if (sblock.fs_cpg < 1) { 158355d6bb5Sswilcox err = "CPG OUT OF RANGE"; 159355d6bb5Sswilcox goto fail; 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl || 1627c478bd9Sstevel@tonic-gate (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) { 163355d6bb5Sswilcox err = "NCYL IS INCONSISTENT WITH NCG*CPG"; 164355d6bb5Sswilcox goto fail; 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate if (sblock.fs_sbsize < 0 || sblock.fs_sbsize > SBSIZE) { 167355d6bb5Sswilcox err = "SIZE OUT OF RANGE"; 168355d6bb5Sswilcox goto fail; 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate return (1); 172355d6bb5Sswilcox 173355d6bb5Sswilcox fail: 174355d6bb5Sswilcox badsb(listerr, err); 175355d6bb5Sswilcox return (0); 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate 178355d6bb5Sswilcox static void 1797c478bd9Sstevel@tonic-gate flush_fs() 1807c478bd9Sstevel@tonic-gate { 1817c478bd9Sstevel@tonic-gate int fd; 1827c478bd9Sstevel@tonic-gate 183355d6bb5Sswilcox if (mount_point != NULL) { 1847c478bd9Sstevel@tonic-gate fd = open(mount_point, O_RDONLY); 1857c478bd9Sstevel@tonic-gate if (fd == -1) { 186355d6bb5Sswilcox errexit("fsck: open mount point error: %s", 187355d6bb5Sswilcox strerror(errno)); 188355d6bb5Sswilcox /* NOTREACHED */ 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate if (ioctl(fd, _FIOFFS, NULL)) { /* flush file system */ 191355d6bb5Sswilcox errexit("fsck: ioctl _FIOFFS error: %s", 192355d6bb5Sswilcox strerror(errno)); 193355d6bb5Sswilcox /* NOTREACHED */ 1947c478bd9Sstevel@tonic-gate } 195355d6bb5Sswilcox (void) close(fd); 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * Roll the embedded log, if any, and set up the global variables 201355d6bb5Sswilcox * islog and islogok. 2027c478bd9Sstevel@tonic-gate */ 2037c478bd9Sstevel@tonic-gate static int 204355d6bb5Sswilcox logsetup(caddr_t devstr) 2057c478bd9Sstevel@tonic-gate { 2067c478bd9Sstevel@tonic-gate void *buf; 2077c478bd9Sstevel@tonic-gate extent_block_t *ebp; 2087c478bd9Sstevel@tonic-gate ml_unit_t *ul; 2097c478bd9Sstevel@tonic-gate ml_odunit_t *ud; 2107c478bd9Sstevel@tonic-gate void *ud_buf; 2117c478bd9Sstevel@tonic-gate int badlog; 2127c478bd9Sstevel@tonic-gate 213355d6bb5Sswilcox islog = islogok = 0; 214355d6bb5Sswilcox if (bflag != 0) 2157c478bd9Sstevel@tonic-gate return (1); /* can't roll log while alternate sb specified */ 2167c478bd9Sstevel@tonic-gate 217355d6bb5Sswilcox /* 218355d6bb5Sswilcox * Roll the log, if any. A bad sb implies we'll be using 219355d6bb5Sswilcox * an alternate sb as far as logging goes, so just fail back 220355d6bb5Sswilcox * to the caller if we can't read the default sb. Suppress 221355d6bb5Sswilcox * complaints, because the caller will be reading the same 222355d6bb5Sswilcox * superblock again and running full verification on it, so 223355d6bb5Sswilcox * whatever is bad will be reported then. 224355d6bb5Sswilcox */ 2257c478bd9Sstevel@tonic-gate sblock.fs_logbno = 0; 2267c478bd9Sstevel@tonic-gate badlog = 0; 227355d6bb5Sswilcox if (!read_super_block(0)) 228355d6bb5Sswilcox return (1); 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate /* 2317c478bd9Sstevel@tonic-gate * Roll the log in 3 cases: 2327c478bd9Sstevel@tonic-gate * 1. If it's unmounted (mount_point == NULL) and it's not marked 2337c478bd9Sstevel@tonic-gate * as fully rolled (sblock.fs_rolled != FS_ALL_ROLLED) 2347c478bd9Sstevel@tonic-gate * 2. If it's mounted and anything other than a sanity 2357c478bd9Sstevel@tonic-gate * check fsck (mflag) is being done, as we have the current 2367c478bd9Sstevel@tonic-gate * super block. Note, only a sanity check is done for 2377c478bd9Sstevel@tonic-gate * root/usr at boot. If a roll were done then the expensive 2387c478bd9Sstevel@tonic-gate * ufs_flush() gets called, leading to a slower boot. 2397c478bd9Sstevel@tonic-gate * 3. If anything other then a sanity check (mflag) is being done 2407c478bd9Sstevel@tonic-gate * to a mounted filesystem while it is in read-only state 2417c478bd9Sstevel@tonic-gate * (e.g. root during early boot stages) we have to detect this 2427c478bd9Sstevel@tonic-gate * and have to roll the log as well. NB. the read-only mount 2437c478bd9Sstevel@tonic-gate * will flip fs_clean from FSLOG to FSSTABLE and marks the 2447c478bd9Sstevel@tonic-gate * log as FS_NEED_ROLL. 2457c478bd9Sstevel@tonic-gate */ 2467c478bd9Sstevel@tonic-gate if (sblock.fs_logbno && 2477c478bd9Sstevel@tonic-gate (((mount_point == NULL) && (sblock.fs_rolled != FS_ALL_ROLLED)) || 248355d6bb5Sswilcox ((mount_point != NULL) && !mflag))) { 2497c478bd9Sstevel@tonic-gate int roll_log_err = 0; 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate if (sblock.fs_ronly && (sblock.fs_clean == FSSTABLE) && 2527c478bd9Sstevel@tonic-gate (sblock.fs_state + sblock.fs_time == FSOKAY)) { 2537c478bd9Sstevel@tonic-gate /* 2547c478bd9Sstevel@tonic-gate * roll the log without a mount 2557c478bd9Sstevel@tonic-gate */ 2567c478bd9Sstevel@tonic-gate flush_fs(); 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate if (sblock.fs_clean == FSLOG && 2597c478bd9Sstevel@tonic-gate (sblock.fs_state + sblock.fs_time == FSOKAY)) { 2607c478bd9Sstevel@tonic-gate if (rl_roll_log(devstr) != RL_SUCCESS) 2617c478bd9Sstevel@tonic-gate roll_log_err = 1; 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate if (roll_log_err) { 2647c478bd9Sstevel@tonic-gate (void) printf("Can't roll the log for %s.\n", devstr); 2657c478bd9Sstevel@tonic-gate /* 2667c478bd9Sstevel@tonic-gate * There are two cases where we want to set 2677c478bd9Sstevel@tonic-gate * an error code and return: 2687c478bd9Sstevel@tonic-gate * - We're preening 2697c478bd9Sstevel@tonic-gate * - We're not on a live root and the user 2707c478bd9Sstevel@tonic-gate * chose *not* to ignore the log 2717c478bd9Sstevel@tonic-gate * Otherwise, we want to mark the log as bad 2727c478bd9Sstevel@tonic-gate * and continue to check the filesystem. This 2737c478bd9Sstevel@tonic-gate * has the side effect of destroying the log. 2747c478bd9Sstevel@tonic-gate */ 2757c478bd9Sstevel@tonic-gate if (preen || (!hotroot && 2767c478bd9Sstevel@tonic-gate reply( 2777c478bd9Sstevel@tonic-gate "DISCARDING THE LOG MAY DISCARD PENDING TRANSACTIONS.\n" 2787c478bd9Sstevel@tonic-gate "DISCARD THE LOG AND CONTINUE") == 0)) { 279355d6bb5Sswilcox exitstat = EXERRFATAL; 2807c478bd9Sstevel@tonic-gate return (0); 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate ++badlog; 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate /* Logging UFS may be enabled */ 2877c478bd9Sstevel@tonic-gate if (sblock.fs_logbno) { 2887c478bd9Sstevel@tonic-gate ++islog; 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate /* log is not okay; check the fs */ 2917c478bd9Sstevel@tonic-gate if (FSOKAY != (sblock.fs_state + sblock.fs_time)) 2927c478bd9Sstevel@tonic-gate return (1); 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate /* 2957c478bd9Sstevel@tonic-gate * If logging or (stable and mounted) then continue 2967c478bd9Sstevel@tonic-gate */ 297355d6bb5Sswilcox if (!((sblock.fs_clean == FSLOG) || 298355d6bb5Sswilcox (sblock.fs_clean == FSSTABLE) && (mount_point != NULL))) 2997c478bd9Sstevel@tonic-gate return (1); 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate /* get the log allocation block */ 302355d6bb5Sswilcox buf = malloc(dev_bsize); 303355d6bb5Sswilcox if (buf == NULL) { 3047c478bd9Sstevel@tonic-gate return (1); 3057c478bd9Sstevel@tonic-gate } 306355d6bb5Sswilcox ud_buf = malloc(dev_bsize); 307355d6bb5Sswilcox if (ud_buf == NULL) { 3087c478bd9Sstevel@tonic-gate free(buf); 3097c478bd9Sstevel@tonic-gate return (1); 3107c478bd9Sstevel@tonic-gate } 311355d6bb5Sswilcox (void) fsck_bread(fsreadfd, buf, 3127c478bd9Sstevel@tonic-gate logbtodb(&sblock, sblock.fs_logbno), 313355d6bb5Sswilcox dev_bsize); 3147c478bd9Sstevel@tonic-gate ebp = (extent_block_t *)buf; 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate /* log allocation block is not okay; check the fs */ 3177c478bd9Sstevel@tonic-gate if (ebp->type != LUFS_EXTENTS) { 3187c478bd9Sstevel@tonic-gate free(buf); 3197c478bd9Sstevel@tonic-gate free(ud_buf); 3207c478bd9Sstevel@tonic-gate return (1); 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate /* get the log state block(s) */ 324355d6bb5Sswilcox if (fsck_bread(fsreadfd, ud_buf, 3257c478bd9Sstevel@tonic-gate (logbtodb(&sblock, ebp->extents[0].pbno)), 326355d6bb5Sswilcox dev_bsize)) { 327355d6bb5Sswilcox (void) fsck_bread(fsreadfd, ud_buf, 3287c478bd9Sstevel@tonic-gate (logbtodb(&sblock, ebp->extents[0].pbno)) + 1, 329355d6bb5Sswilcox dev_bsize); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate ud = (ml_odunit_t *)ud_buf; 3327c478bd9Sstevel@tonic-gate ul = (ml_unit_t *)malloc(sizeof (*ul)); 3337c478bd9Sstevel@tonic-gate if (ul == NULL) { 3347c478bd9Sstevel@tonic-gate free(buf); 3357c478bd9Sstevel@tonic-gate free(ud_buf); 3367c478bd9Sstevel@tonic-gate return (1); 3377c478bd9Sstevel@tonic-gate } 3387c478bd9Sstevel@tonic-gate ul->un_ondisk = *ud; 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate /* log state is okay; don't need to check the fs */ 3417c478bd9Sstevel@tonic-gate if ((ul->un_chksum == ul->un_head_ident + ul->un_tail_ident) && 3427c478bd9Sstevel@tonic-gate (ul->un_version == LUFS_VERSION_LATEST) && 343355d6bb5Sswilcox (ul->un_badlog == 0) && (!badlog)) { 3447c478bd9Sstevel@tonic-gate ++islogok; 345355d6bb5Sswilcox } 3467c478bd9Sstevel@tonic-gate free(ud_buf); 3477c478bd9Sstevel@tonic-gate free(buf); 3487c478bd9Sstevel@tonic-gate free(ul); 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate return (1); 3527c478bd9Sstevel@tonic-gate } 3537c478bd9Sstevel@tonic-gate 354355d6bb5Sswilcox /* 355355d6bb5Sswilcox * - given a pathname, determine the pathname to actually check 356355d6bb5Sswilcox * - if a directory 357355d6bb5Sswilcox * - if it is in mnttab, set devstr to the special (block) name 358355d6bb5Sswilcox * - if it is in vfstab, set devstr to the special (block) name 359355d6bb5Sswilcox * - if it has not been found, bail 360355d6bb5Sswilcox * - a file is used as-is, clear rflag 361355d6bb5Sswilcox * - a device is converted to block version (so can search mnttab) 362355d6bb5Sswilcox */ 363355d6bb5Sswilcox static void 364355d6bb5Sswilcox derive_devstr(const caddr_t dev, caddr_t devstr, size_t str_size) 3657c478bd9Sstevel@tonic-gate { 366355d6bb5Sswilcox mode_t mode; 367355d6bb5Sswilcox struct stat statb; 3687c478bd9Sstevel@tonic-gate 369355d6bb5Sswilcox if (stat(dev, &statb) < 0) { 370355d6bb5Sswilcox exitstat = EXNOSTAT; 371355d6bb5Sswilcox errexit("fsck: could not stat %s: %s", dev, strerror(errno)); 3727c478bd9Sstevel@tonic-gate } 373355d6bb5Sswilcox 374355d6bb5Sswilcox mode = statb.st_mode & S_IFMT; 375355d6bb5Sswilcox switch (mode) { 376355d6bb5Sswilcox case S_IFDIR: 3777c478bd9Sstevel@tonic-gate /* 378355d6bb5Sswilcox * The check_*() routines update devstr with the name. 3797c478bd9Sstevel@tonic-gate */ 380355d6bb5Sswilcox devstr[0] = '\0'; 381355d6bb5Sswilcox if (!(check_mnttab(dev, devstr, str_size) || 382355d6bb5Sswilcox check_vfstab(dev, devstr, str_size))) { 383355d6bb5Sswilcox exitstat = EXBADPARM; 384355d6bb5Sswilcox errexit( 385355d6bb5Sswilcox "fsck: could not find mountpoint %s in mnttab nor vfstab", 386355d6bb5Sswilcox dev); 3877c478bd9Sstevel@tonic-gate } 388355d6bb5Sswilcox break; 389355d6bb5Sswilcox case S_IFREG: 3907c478bd9Sstevel@tonic-gate rflag = 0; 391*5b4dc236Smishra (void) strlcpy(devstr, dev, str_size); 392355d6bb5Sswilcox break; 393355d6bb5Sswilcox case S_IFCHR: 394355d6bb5Sswilcox case S_IFBLK: 395355d6bb5Sswilcox (void) strlcpy(devstr, unrawname(dev), str_size); 396355d6bb5Sswilcox break; 397355d6bb5Sswilcox default: 398355d6bb5Sswilcox exitstat = EXBADPARM; 399355d6bb5Sswilcox errexit("fsck: %s must be a mountpoint, device, or file", dev); 400355d6bb5Sswilcox /* NOTREACHED */ 401355d6bb5Sswilcox } 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate /* 405355d6bb5Sswilcox * Reports the index of the magic filesystem that mntp names. 406355d6bb5Sswilcox * If it does not correspond any of them, returns zero (hence 407355d6bb5Sswilcox * the backwards loop). 4087c478bd9Sstevel@tonic-gate */ 409355d6bb5Sswilcox static int 410355d6bb5Sswilcox which_corefs(const caddr_t mntp) 411355d6bb5Sswilcox { 412355d6bb5Sswilcox int corefs; 413355d6bb5Sswilcox 414355d6bb5Sswilcox for (corefs = MAGIC_LIMIT - 1; corefs > 0; corefs--) 415355d6bb5Sswilcox if (strcmp(mntp, magic_fs[corefs]) == 0) 416355d6bb5Sswilcox break; 417355d6bb5Sswilcox 418355d6bb5Sswilcox return (corefs); 4197c478bd9Sstevel@tonic-gate } 420355d6bb5Sswilcox 4217c478bd9Sstevel@tonic-gate /* 422355d6bb5Sswilcox * - set mount_point to NULL 423355d6bb5Sswilcox * - if name is mounted (search mnttab) 424355d6bb5Sswilcox * - if it is a device, clear rflag 425355d6bb5Sswilcox * - if mounted on /, /usr, or /var, set corefs 426355d6bb5Sswilcox * - if corefs and read-only, set hotroot and continue 427355d6bb5Sswilcox * - if errorlocked, continue 428355d6bb5Sswilcox * - if preening, bail 429355d6bb5Sswilcox * - ask user whether to continue, bail if not 430355d6bb5Sswilcox * - if it is a device and not mounted and rflag, convert 431355d6bb5Sswilcox * name to raw version 4327c478bd9Sstevel@tonic-gate */ 433355d6bb5Sswilcox static int 434355d6bb5Sswilcox check_mount_state(caddr_t devstr, size_t str_size) 435355d6bb5Sswilcox { 436355d6bb5Sswilcox int corefs = 0; 437355d6bb5Sswilcox int is_dev = 0; 438355d6bb5Sswilcox struct stat statb; 439355d6bb5Sswilcox 440355d6bb5Sswilcox if (stat(devstr, &statb) < 0) { 441355d6bb5Sswilcox exitstat = EXNOSTAT; 442355d6bb5Sswilcox errexit("fsck: could not stat %s: %s", devstr, strerror(errno)); 4437c478bd9Sstevel@tonic-gate } 444355d6bb5Sswilcox if (S_ISCHR(statb.st_mode) || S_ISBLK(statb.st_mode)) 445355d6bb5Sswilcox is_dev = 1; 446355d6bb5Sswilcox 447355d6bb5Sswilcox /* 448355d6bb5Sswilcox * mounted() will update mount_point when returning true. 449355d6bb5Sswilcox */ 450355d6bb5Sswilcox mount_point = NULL; 451355d6bb5Sswilcox if ((mountedfs = mounted(devstr, devstr, str_size)) != M_NOMNT) { 452355d6bb5Sswilcox if (is_dev) 453355d6bb5Sswilcox rflag = 0; 454355d6bb5Sswilcox corefs = which_corefs(mount_point); 455355d6bb5Sswilcox if (corefs && (mountedfs == M_RO)) { 4567c478bd9Sstevel@tonic-gate hotroot++; 457355d6bb5Sswilcox } else if (errorlocked) { 458355d6bb5Sswilcox goto carry_on; 459355d6bb5Sswilcox } else if (preen) { 460355d6bb5Sswilcox exitstat = EXMOUNTED; 461355d6bb5Sswilcox pfatal("%s IS CURRENTLY MOUNTED%s.", 462355d6bb5Sswilcox devstr, mountedfs == M_RW ? " READ/WRITE" : ""); 463355d6bb5Sswilcox } else { 464*5b4dc236Smishra if (!nflag && !mflag) { 465355d6bb5Sswilcox pwarn("%s IS CURRENTLY MOUNTED READ/%s.", 466504a199eSswilcox devstr, mountedfs == M_RW ? "WRITE" : 467504a199eSswilcox "ONLY"); 468355d6bb5Sswilcox if (reply("CONTINUE") == 0) { 469355d6bb5Sswilcox exitstat = EXMOUNTED; 470355d6bb5Sswilcox errexit("Program terminated"); 4717c478bd9Sstevel@tonic-gate } 472504a199eSswilcox } 473355d6bb5Sswilcox } 474355d6bb5Sswilcox } else if (is_dev && rflag) { 475355d6bb5Sswilcox (void) strlcpy(devstr, rawname(devstr), str_size); 476355d6bb5Sswilcox } 477355d6bb5Sswilcox 478355d6bb5Sswilcox carry_on: 479355d6bb5Sswilcox return (corefs); 480355d6bb5Sswilcox } 481355d6bb5Sswilcox 482355d6bb5Sswilcox static int 483355d6bb5Sswilcox open_and_intro(caddr_t devstr, int corefs) 484355d6bb5Sswilcox { 485355d6bb5Sswilcox int retval = 0; 486355d6bb5Sswilcox 4877c478bd9Sstevel@tonic-gate if ((fsreadfd = open64(devstr, O_RDONLY)) < 0) { 488355d6bb5Sswilcox (void) printf("Can't open %s: %s\n", devstr, strerror(errno)); 489355d6bb5Sswilcox exitstat = EXNOSTAT; 490355d6bb5Sswilcox retval = -1; 491355d6bb5Sswilcox goto finish; 4927c478bd9Sstevel@tonic-gate } 493355d6bb5Sswilcox if (!preen || debug != 0) 494355d6bb5Sswilcox (void) printf("** %s", devstr); 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate if (errorlocked) { 497355d6bb5Sswilcox if (debug && elock_combuf != NULL) 498355d6bb5Sswilcox (void) printf(" error-lock comment: \"%s\" ", 499355d6bb5Sswilcox elock_combuf); 5007c478bd9Sstevel@tonic-gate fflag = 1; 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate pid = getpid(); 503355d6bb5Sswilcox if (nflag || roflag || (fswritefd = open64(devstr, O_WRONLY)) < 0) { 5047c478bd9Sstevel@tonic-gate fswritefd = -1; 5057c478bd9Sstevel@tonic-gate if (preen && !debug) 5067c478bd9Sstevel@tonic-gate pfatal("(NO WRITE ACCESS)\n"); 507355d6bb5Sswilcox (void) printf(" (NO WRITE)"); 5087c478bd9Sstevel@tonic-gate } 509355d6bb5Sswilcox if (!preen) 510355d6bb5Sswilcox (void) printf("\n"); 5117c478bd9Sstevel@tonic-gate else if (debug) 512355d6bb5Sswilcox (void) printf(" pid %d\n", pid); 513355d6bb5Sswilcox if (debug && (hotroot || (mountedfs != M_NOMNT))) { 514355d6bb5Sswilcox (void) printf("** %s", devstr); 5157c478bd9Sstevel@tonic-gate if (hotroot) 516355d6bb5Sswilcox (void) printf(" is %s fs", magic_fs[corefs]); 517355d6bb5Sswilcox if (mountedfs != M_NOMNT) 518355d6bb5Sswilcox (void) printf(" and is mounted read-%s", 519355d6bb5Sswilcox (mountedfs == M_RO) ? "only" : "write"); 5207c478bd9Sstevel@tonic-gate if (errorlocked) 521355d6bb5Sswilcox (void) printf(" and is error-locked"); 5227c478bd9Sstevel@tonic-gate 523355d6bb5Sswilcox (void) printf(".\n"); 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate 526355d6bb5Sswilcox finish: 527355d6bb5Sswilcox return (retval); 528355d6bb5Sswilcox } 529355d6bb5Sswilcox 530355d6bb5Sswilcox static int 531355d6bb5Sswilcox find_superblock(caddr_t devstr) 532355d6bb5Sswilcox { 533355d6bb5Sswilcox int cg = 0; 534355d6bb5Sswilcox int retval = 0; 535355d6bb5Sswilcox int first; 536355d6bb5Sswilcox int found; 537355d6bb5Sswilcox calcsb_t style; 538355d6bb5Sswilcox struct fs proto; 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* 541355d6bb5Sswilcox * Check the superblock, looking for alternates if necessary. 542355d6bb5Sswilcox * In more-recent times, some UFS instances get created with 543355d6bb5Sswilcox * only the first ten and last ten superblock backups. Since 544355d6bb5Sswilcox * if we can't get the necessary information from any of those, 545355d6bb5Sswilcox * the odds are also against us for the ones in between, we'll 546355d6bb5Sswilcox * just look at those twenty to save time. 5477c478bd9Sstevel@tonic-gate */ 548355d6bb5Sswilcox if (!read_super_block(1) || !checksb(1)) { 549355d6bb5Sswilcox if (bflag || preen) { 550355d6bb5Sswilcox retval = -1; 551355d6bb5Sswilcox goto finish; 552355d6bb5Sswilcox } 553355d6bb5Sswilcox for (style = MKFS_STYLE; style < MAX_SB_STYLES; style++) { 554355d6bb5Sswilcox if (reply("LOOK FOR ALTERNATE SUPERBLOCKS WITH %s", 555355d6bb5Sswilcox calcsb_names[style]) == 0) 556355d6bb5Sswilcox continue; 557355d6bb5Sswilcox first = 1; 558355d6bb5Sswilcox found = 0; 559355d6bb5Sswilcox if (!calcsb(style, devstr, fsreadfd, &proto)) { 560355d6bb5Sswilcox cg = proto.fs_ncg; 561355d6bb5Sswilcox continue; 562355d6bb5Sswilcox } 563355d6bb5Sswilcox if (debug) { 564355d6bb5Sswilcox (void) printf( 565355d6bb5Sswilcox "debug: calcsb(%s) gave fpg %d, cgoffset %d, ", 566355d6bb5Sswilcox calcsb_names[style], 567355d6bb5Sswilcox proto.fs_fpg, proto.fs_cgoffset); 568355d6bb5Sswilcox (void) printf("cgmask 0x%x, sblk %d, ncg %d\n", 569355d6bb5Sswilcox proto.fs_cgmask, proto.fs_sblkno, 570355d6bb5Sswilcox proto.fs_ncg); 571355d6bb5Sswilcox } 572355d6bb5Sswilcox for (cg = 0; cg < proto.fs_ncg; cg++) { 573355d6bb5Sswilcox bflag = fsbtodb(&proto, cgsblock(&proto, cg)); 574355d6bb5Sswilcox if (debug) 575355d6bb5Sswilcox (void) printf( 576355d6bb5Sswilcox "debug: trying block %lld\n", 577355d6bb5Sswilcox (longlong_t)bflag); 578355d6bb5Sswilcox if (read_super_block(0) && checksb(0)) { 579355d6bb5Sswilcox (void) printf( 580355d6bb5Sswilcox "FOUND ALTERNATE SUPERBLOCK %d WITH %s\n", 581355d6bb5Sswilcox bflag, calcsb_names[style]); 582355d6bb5Sswilcox if (reply( 583355d6bb5Sswilcox "USE ALTERNATE SUPERBLOCK") == 1) { 584355d6bb5Sswilcox found = 1; 585355d6bb5Sswilcox break; 586355d6bb5Sswilcox } 587355d6bb5Sswilcox } 588355d6bb5Sswilcox if (first && (cg >= 9)) { 589355d6bb5Sswilcox first = 0; 590355d6bb5Sswilcox if (proto.fs_ncg <= 9) 591355d6bb5Sswilcox cg = proto.fs_ncg; 592355d6bb5Sswilcox else if (proto.fs_ncg <= 19) 593355d6bb5Sswilcox cg = 9; 594355d6bb5Sswilcox else 595355d6bb5Sswilcox cg = proto.fs_ncg - 10; 596355d6bb5Sswilcox } 597355d6bb5Sswilcox } 5987c478bd9Sstevel@tonic-gate 599355d6bb5Sswilcox if (found) 600355d6bb5Sswilcox break; 601355d6bb5Sswilcox } 602355d6bb5Sswilcox 6037c478bd9Sstevel@tonic-gate /* 604355d6bb5Sswilcox * Didn't find one? Try to fake it. 6057c478bd9Sstevel@tonic-gate */ 606355d6bb5Sswilcox if (style >= MAX_SB_STYLES) { 607355d6bb5Sswilcox pwarn("SEARCH FOR ALTERNATE SUPERBLOCKS FAILED.\n"); 608355d6bb5Sswilcox for (style = MKFS_STYLE; style < MAX_SB_STYLES; 609355d6bb5Sswilcox style++) { 610355d6bb5Sswilcox if (reply("USE GENERIC SUPERBLOCK FROM %s", 611355d6bb5Sswilcox calcsb_names[style]) == 1 && 612355d6bb5Sswilcox calcsb(style, devstr, fsreadfd, &sblock)) { 613355d6bb5Sswilcox break; 614355d6bb5Sswilcox } 615355d6bb5Sswilcox /* 616355d6bb5Sswilcox * We got something from mkfs/newfs, so use it. 617355d6bb5Sswilcox */ 618355d6bb5Sswilcox if (style < MAX_SB_STYLES) 619355d6bb5Sswilcox proto.fs_ncg = sblock.fs_ncg; 620355d6bb5Sswilcox bflag = 0; 621355d6bb5Sswilcox } 622355d6bb5Sswilcox } 623355d6bb5Sswilcox 624355d6bb5Sswilcox /* 625355d6bb5Sswilcox * Still no luck? Tell the user they're on their own. 626355d6bb5Sswilcox */ 627355d6bb5Sswilcox if (style >= MAX_SB_STYLES) { 628355d6bb5Sswilcox pwarn("SEARCH FOR ALTERNATE SUPERBLOCKS FAILED. " 629355d6bb5Sswilcox "YOU MUST USE THE -o b OPTION\n" 630355d6bb5Sswilcox "TO FSCK TO SPECIFY THE LOCATION OF A VALID " 631355d6bb5Sswilcox "ALTERNATE SUPERBLOCK TO\n" 632355d6bb5Sswilcox "SUPPLY NEEDED INFORMATION; SEE fsck(1M).\n"); 633355d6bb5Sswilcox bflag = 0; 634355d6bb5Sswilcox retval = -1; 635355d6bb5Sswilcox goto finish; 636355d6bb5Sswilcox } 637355d6bb5Sswilcox 638355d6bb5Sswilcox /* 639355d6bb5Sswilcox * Need to make sure a human really wants us to use 640355d6bb5Sswilcox * this. -y mode could've gotten us this far, so 641355d6bb5Sswilcox * we need to ask something that has to be answered 642355d6bb5Sswilcox * in the negative. 643355d6bb5Sswilcox * 644355d6bb5Sswilcox * Note that we can't get here when preening. 645355d6bb5Sswilcox */ 646355d6bb5Sswilcox if (!found) { 647355d6bb5Sswilcox pwarn("CALCULATED GENERIC SUPERBLOCK WITH %s\n", 648355d6bb5Sswilcox calcsb_names[style]); 649355d6bb5Sswilcox } else { 650355d6bb5Sswilcox pwarn("FOUND ALTERNATE SUPERBLOCK AT %d USING %s\n", 651355d6bb5Sswilcox bflag, calcsb_names[style]); 652355d6bb5Sswilcox } 653355d6bb5Sswilcox pwarn("If filesystem was created with manually-specified "); 654355d6bb5Sswilcox pwarn("geometry, using\nauto-discovered superblock may "); 655355d6bb5Sswilcox pwarn("result in irrecoverable damage to\nfilesystem and "); 656355d6bb5Sswilcox pwarn("user data.\n"); 657355d6bb5Sswilcox if (reply("CANCEL FILESYSTEM CHECK") == 1) { 658355d6bb5Sswilcox if (cg >= 0) { 659355d6bb5Sswilcox pwarn("Please verify that the indicated block " 660355d6bb5Sswilcox "contains a proper\nsuperblock for the " 661355d6bb5Sswilcox "filesystem (see fsdb(1M)).\n"); 662355d6bb5Sswilcox if (yflag) 663355d6bb5Sswilcox pwarn("\nFSCK was running in YES " 664355d6bb5Sswilcox "mode. If you wish to run in " 665355d6bb5Sswilcox "that mode using\nthe alternate " 666355d6bb5Sswilcox "superblock, run " 667355d6bb5Sswilcox "`fsck -y -o b=%d %s'.\n", 668355d6bb5Sswilcox bflag, devstr); 669355d6bb5Sswilcox } 670355d6bb5Sswilcox retval = -1; 671355d6bb5Sswilcox goto finish; 672355d6bb5Sswilcox } 673355d6bb5Sswilcox 674355d6bb5Sswilcox /* 675355d6bb5Sswilcox * Pretend we found it as an alternate, so everything 676355d6bb5Sswilcox * gets updated when we clean up at the end. 677355d6bb5Sswilcox */ 678355d6bb5Sswilcox if (!found) { 679355d6bb5Sswilcox havesb = 1; 680355d6bb5Sswilcox sblk.b_bno = fsbtodb(&sblock, cgsblock(&sblock, 0)); 681355d6bb5Sswilcox bwrite(fswritefd, (caddr_t)&sblock, SBLOCK, SBSIZE); 682355d6bb5Sswilcox write_altsb(fswritefd); 683355d6bb5Sswilcox } 684355d6bb5Sswilcox } 685355d6bb5Sswilcox 686355d6bb5Sswilcox finish: 687355d6bb5Sswilcox return (retval); 688355d6bb5Sswilcox } 689355d6bb5Sswilcox 6907c478bd9Sstevel@tonic-gate /* 6917c478bd9Sstevel@tonic-gate * Check and potentially fix certain fields in the super block. 6927c478bd9Sstevel@tonic-gate */ 693355d6bb5Sswilcox static void 694355d6bb5Sswilcox fixup_superblock(void) 695355d6bb5Sswilcox { 696355d6bb5Sswilcox /* 697355d6bb5Sswilcox * Kernel looks for FS_OPTTIME, and assumes that if that's not 698355d6bb5Sswilcox * what's there, it must be FS_OPTSPACE, so not fixing does not 699355d6bb5Sswilcox * require setting iscorrupt. 700355d6bb5Sswilcox */ 7017c478bd9Sstevel@tonic-gate if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { 7027c478bd9Sstevel@tonic-gate pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); 7037c478bd9Sstevel@tonic-gate if (reply("SET TO DEFAULT") == 1) { 7047c478bd9Sstevel@tonic-gate sblock.fs_optim = FS_OPTTIME; 7057c478bd9Sstevel@tonic-gate sbdirty(); 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { 7097c478bd9Sstevel@tonic-gate pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 7107c478bd9Sstevel@tonic-gate sblock.fs_minfree); 7117c478bd9Sstevel@tonic-gate if (reply("SET TO DEFAULT") == 1) { 7127c478bd9Sstevel@tonic-gate sblock.fs_minfree = 10; 7137c478bd9Sstevel@tonic-gate sbdirty(); 714355d6bb5Sswilcox } else if (sblock.fs_minfree < 0) { 7157c478bd9Sstevel@tonic-gate /* 716355d6bb5Sswilcox * Kernel uses minfree without verification, 717355d6bb5Sswilcox * and a negative value would do bad things. 7187c478bd9Sstevel@tonic-gate */ 719355d6bb5Sswilcox iscorrupt = 1; 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate } 722355d6bb5Sswilcox } 723355d6bb5Sswilcox 724355d6bb5Sswilcox static int 725355d6bb5Sswilcox initial_error_state_adjust(void) 726355d6bb5Sswilcox { 727355d6bb5Sswilcox int retval = 0; 728355d6bb5Sswilcox 7297c478bd9Sstevel@tonic-gate /* do this right away to prevent any other fscks on this fs */ 7307c478bd9Sstevel@tonic-gate switch (sblock.fs_clean) { 7317c478bd9Sstevel@tonic-gate case FSBAD: 7327c478bd9Sstevel@tonic-gate break; 7337c478bd9Sstevel@tonic-gate case FSFIX: 7347c478bd9Sstevel@tonic-gate if (preen) 7357c478bd9Sstevel@tonic-gate errexit("ERROR-LOCKED; MARKED \"FSFIX\"\n"); 736355d6bb5Sswilcox if (reply("marked FSFIX, CONTINUE") == 0) { 737355d6bb5Sswilcox retval = -1; 738355d6bb5Sswilcox goto finish; 739355d6bb5Sswilcox } 7407c478bd9Sstevel@tonic-gate break; 7417c478bd9Sstevel@tonic-gate case FSCLEAN: 7427c478bd9Sstevel@tonic-gate if (preen) 7437c478bd9Sstevel@tonic-gate errexit("ERROR-LOCKED; MARKED \"FSCLEAN\"\n"); 744355d6bb5Sswilcox if (reply("marked FSCLEAN, CONTINUE") == 0) { 745355d6bb5Sswilcox retval = -1; 746355d6bb5Sswilcox goto finish; 747355d6bb5Sswilcox } 7487c478bd9Sstevel@tonic-gate break; 7497c478bd9Sstevel@tonic-gate default: 7507c478bd9Sstevel@tonic-gate if (preen) { 7517c478bd9Sstevel@tonic-gate if (debug) 7527c478bd9Sstevel@tonic-gate pwarn("ERRORLOCKED; NOT MARKED \"FSBAD\"\n"); 7537c478bd9Sstevel@tonic-gate else 7547c478bd9Sstevel@tonic-gate errexit("ERRORLOCKED; NOT MARKED \"FSBAD\"\n"); 7557c478bd9Sstevel@tonic-gate } else { 756355d6bb5Sswilcox (void) printf("error-locked but not marked \"FSBAD\";"); 757355d6bb5Sswilcox if (reply(" CONTINUE") == 0) { 758355d6bb5Sswilcox retval = -1; 759355d6bb5Sswilcox goto finish; 760355d6bb5Sswilcox } 7617c478bd9Sstevel@tonic-gate } 7627c478bd9Sstevel@tonic-gate break; 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate if (!do_errorlock(LOCKFS_ELOCK)) { 766355d6bb5Sswilcox if (preen) { 767355d6bb5Sswilcox retval = -1; 768355d6bb5Sswilcox goto finish; 769355d6bb5Sswilcox } 770355d6bb5Sswilcox if (reply("error-lock reset failed; CONTINUE") == 0) { 771355d6bb5Sswilcox retval = -1; 772355d6bb5Sswilcox goto finish; 773355d6bb5Sswilcox } 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate sblock.fs_state = FSOKAY - (long)sblock.fs_time; 7777c478bd9Sstevel@tonic-gate sblock.fs_clean = FSFIX; 7787c478bd9Sstevel@tonic-gate sbdirty(); 7797c478bd9Sstevel@tonic-gate write_altsb(fswritefd); 780355d6bb5Sswilcox 781355d6bb5Sswilcox finish: 782355d6bb5Sswilcox return (retval); 7837c478bd9Sstevel@tonic-gate } 784355d6bb5Sswilcox 785355d6bb5Sswilcox static void 786355d6bb5Sswilcox getsummaryinfo(void) 787355d6bb5Sswilcox { 788355d6bb5Sswilcox size_t size; 789355d6bb5Sswilcox int failed; 790355d6bb5Sswilcox int asked; 791355d6bb5Sswilcox int i, j; 792355d6bb5Sswilcox caddr_t sip; 793355d6bb5Sswilcox 7947c478bd9Sstevel@tonic-gate /* 7957c478bd9Sstevel@tonic-gate * read in the summary info. 7967c478bd9Sstevel@tonic-gate */ 797355d6bb5Sswilcox sblock.fs_u.fs_csp = calloc(1, sblock.fs_cssize); 798355d6bb5Sswilcox if (sblock.fs_u.fs_csp == NULL) 799355d6bb5Sswilcox errexit( 800355d6bb5Sswilcox "cannot allocate %u bytes for cylinder group summary info\n", 801355d6bb5Sswilcox (unsigned)sblock.fs_cssize); 802355d6bb5Sswilcox sip = (caddr_t)sblock.fs_u.fs_csp; 803355d6bb5Sswilcox asked = 0; 8047c478bd9Sstevel@tonic-gate for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 8057c478bd9Sstevel@tonic-gate size = sblock.fs_cssize - i < sblock.fs_bsize ? 8067c478bd9Sstevel@tonic-gate sblock.fs_cssize - i : sblock.fs_bsize; 807355d6bb5Sswilcox failed = fsck_bread(fsreadfd, sip, 8087c478bd9Sstevel@tonic-gate fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 809355d6bb5Sswilcox size); 810355d6bb5Sswilcox if (failed && !asked) { 811355d6bb5Sswilcox pfatal("BAD SUMMARY INFORMATION"); 812355d6bb5Sswilcox if (reply("CONTINUE") == 0) { 813355d6bb5Sswilcox ckfini(); 814355d6bb5Sswilcox exit(EXFNDERRS); 815355d6bb5Sswilcox } 816355d6bb5Sswilcox asked = 1; 817355d6bb5Sswilcox } 8187c478bd9Sstevel@tonic-gate sip += size; 8197c478bd9Sstevel@tonic-gate } 8207c478bd9Sstevel@tonic-gate } 821355d6bb5Sswilcox 8227c478bd9Sstevel@tonic-gate /* 823355d6bb5Sswilcox * Reverses the effects of getsummaryinfo(). 8247c478bd9Sstevel@tonic-gate */ 825355d6bb5Sswilcox static void 826355d6bb5Sswilcox ungetsummaryinfo(void) 827355d6bb5Sswilcox { 828355d6bb5Sswilcox if ((sblk.b_un.b_fs != NULL) && 829355d6bb5Sswilcox (sblk.b_un.b_fs->fs_u.fs_csp != NULL)) { 830355d6bb5Sswilcox free(sblk.b_un.b_fs->fs_u.fs_csp); 831355d6bb5Sswilcox sblk.b_un.b_fs->fs_u.fs_csp = NULL; 832355d6bb5Sswilcox } 833355d6bb5Sswilcox } 834355d6bb5Sswilcox 835355d6bb5Sswilcox /* 836355d6bb5Sswilcox * Allocate and initialize the global tables. 837355d6bb5Sswilcox * It is the responsibility of the caller to clean up and allocations 838355d6bb5Sswilcox * if an error is returned. 839355d6bb5Sswilcox */ 840355d6bb5Sswilcox static int 841355d6bb5Sswilcox create_and_init_maps(void) 842355d6bb5Sswilcox { 843355d6bb5Sswilcox int64_t bmapsize; 844355d6bb5Sswilcox int retval = 0; 845355d6bb5Sswilcox 846355d6bb5Sswilcox maxfsblock = sblock.fs_size; 847355d6bb5Sswilcox maxino = sblock.fs_ncg * sblock.fs_ipg; 848355d6bb5Sswilcox 8497c478bd9Sstevel@tonic-gate bmapsize = roundup(howmany((uint64_t)maxfsblock, NBBY), 8507c478bd9Sstevel@tonic-gate sizeof (short)); 8517c478bd9Sstevel@tonic-gate blockmap = calloc((size_t)bmapsize, sizeof (char)); 8527c478bd9Sstevel@tonic-gate if (blockmap == NULL) { 853355d6bb5Sswilcox (void) printf("cannot alloc %lld bytes for blockmap\n", 854355d6bb5Sswilcox (longlong_t)bmapsize); 855355d6bb5Sswilcox retval = -1; 856355d6bb5Sswilcox goto finish; 8577c478bd9Sstevel@tonic-gate } 858355d6bb5Sswilcox statemap = calloc((size_t)(maxino + 1), sizeof (*statemap)); 8597c478bd9Sstevel@tonic-gate if (statemap == NULL) { 860355d6bb5Sswilcox (void) printf("cannot alloc %lld bytes for statemap\n", 861355d6bb5Sswilcox (longlong_t)(maxino + 1) * sizeof (*statemap)); 862355d6bb5Sswilcox retval = -1; 863355d6bb5Sswilcox goto finish; 8647c478bd9Sstevel@tonic-gate } 865355d6bb5Sswilcox lncntp = (short *)calloc((size_t)(maxino + 1), sizeof (short)); 8667c478bd9Sstevel@tonic-gate if (lncntp == NULL) { 867355d6bb5Sswilcox (void) printf("cannot alloc %lld bytes for lncntp\n", 868355d6bb5Sswilcox (longlong_t)(maxino + 1) * sizeof (short)); 869355d6bb5Sswilcox retval = -1; 870355d6bb5Sswilcox goto finish; 8717c478bd9Sstevel@tonic-gate } 872355d6bb5Sswilcox 873355d6bb5Sswilcox /* 874355d6bb5Sswilcox * If we had to fake up a superblock, it won't show that there 875355d6bb5Sswilcox * are any directories at all. This causes problems when we 876355d6bb5Sswilcox * use numdirs to calculate hash keys, so use something at least 877355d6bb5Sswilcox * vaguely plausible. 878355d6bb5Sswilcox */ 8797c478bd9Sstevel@tonic-gate numdirs = sblock.fs_cstotal.cs_ndir; 880355d6bb5Sswilcox if (numdirs == 0) 881355d6bb5Sswilcox numdirs = sblock.fs_ipg * sblock.fs_ncg / 2; 8827c478bd9Sstevel@tonic-gate listmax = numdirs + 10; 8837c478bd9Sstevel@tonic-gate inpsort = (struct inoinfo **)calloc((unsigned)listmax, 8847c478bd9Sstevel@tonic-gate sizeof (struct inoinfo *)); 8857c478bd9Sstevel@tonic-gate inphead = (struct inoinfo **)calloc((unsigned)numdirs, 8867c478bd9Sstevel@tonic-gate sizeof (struct inoinfo *)); 8877c478bd9Sstevel@tonic-gate if (inpsort == NULL || inphead == NULL) { 888355d6bb5Sswilcox (void) printf("cannot alloc %lld bytes for inphead\n", 889355d6bb5Sswilcox (longlong_t)numdirs * sizeof (struct inoinfo *)); 890355d6bb5Sswilcox retval = -1; 891355d6bb5Sswilcox goto finish; 8927c478bd9Sstevel@tonic-gate } 893355d6bb5Sswilcox if (debug) { 894d1a180b0Smaheshvs if (listmax > ULONG_MAX) 895355d6bb5Sswilcox errexit("create_and_init_maps: listmax overflowed\n"); 896d1a180b0Smaheshvs if (numdirs > ULONG_MAX) 897355d6bb5Sswilcox errexit("create_and_init_maps: numdirs overflowed\n"); 898355d6bb5Sswilcox } 899355d6bb5Sswilcox 9007c478bd9Sstevel@tonic-gate numacls = numdirs; 9017c478bd9Sstevel@tonic-gate aclmax = numdirs + 10; 902355d6bb5Sswilcox aclpsort = (struct inoinfo **)calloc((unsigned)aclmax, 903355d6bb5Sswilcox sizeof (struct inoinfo *)); 904355d6bb5Sswilcox aclphead = (struct inoinfo **)calloc((unsigned)numacls, 905355d6bb5Sswilcox sizeof (struct inoinfo *)); 9067c478bd9Sstevel@tonic-gate if (aclpsort == NULL || aclphead == NULL) { 907355d6bb5Sswilcox (void) printf("cannot alloc %lld bytes for aclphead\n", 908355d6bb5Sswilcox (longlong_t)numacls * sizeof (struct inoinfo *)); 909355d6bb5Sswilcox retval = -1; 910355d6bb5Sswilcox goto finish; 911355d6bb5Sswilcox } 912355d6bb5Sswilcox if (debug) { 913d1a180b0Smaheshvs if (aclmax > ULONG_MAX) 914355d6bb5Sswilcox errexit("create_and_init_maps: aclmax overflowed\n"); 915d1a180b0Smaheshvs if (numacls > ULONG_MAX) 916355d6bb5Sswilcox errexit("create_and_init_maps: numacls overflowed\n"); 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate aclplast = 0L; 9197c478bd9Sstevel@tonic-gate inplast = 0L; 920355d6bb5Sswilcox 921355d6bb5Sswilcox finish: 922355d6bb5Sswilcox return (retval); 923355d6bb5Sswilcox } 924355d6bb5Sswilcox 925355d6bb5Sswilcox caddr_t 926355d6bb5Sswilcox setup(caddr_t dev) 927355d6bb5Sswilcox { 928355d6bb5Sswilcox int corefs; 929355d6bb5Sswilcox static char devstr[MAXPATHLEN + 1]; 930355d6bb5Sswilcox 931355d6bb5Sswilcox havesb = 0; 932355d6bb5Sswilcox devname = devstr; 933355d6bb5Sswilcox 934355d6bb5Sswilcox derive_devstr(dev, devstr, sizeof (devstr)); 935355d6bb5Sswilcox errorlocked = is_errorlocked(devstr); 936355d6bb5Sswilcox corefs = check_mount_state(devstr, sizeof (devstr)); 937355d6bb5Sswilcox 938355d6bb5Sswilcox sblock_init(); 939355d6bb5Sswilcox 940355d6bb5Sswilcox if (open_and_intro(devstr, corefs) == -1) 941355d6bb5Sswilcox goto cleanup; 942355d6bb5Sswilcox 943*5b4dc236Smishra if (mflag && mounted(devstr, devstr, 944*5b4dc236Smishra sizeof (devstr)) == M_RW) 945*5b4dc236Smishra return (devstr); 946*5b4dc236Smishra 947355d6bb5Sswilcox /* 948355d6bb5Sswilcox * Check log state 949355d6bb5Sswilcox */ 950355d6bb5Sswilcox if (!logsetup(devstr)) 951355d6bb5Sswilcox goto cleanup; 952355d6bb5Sswilcox 953355d6bb5Sswilcox /* 954355d6bb5Sswilcox * Flush fs if we're going to do anything other than a sanity check. 955355d6bb5Sswilcox * Note, if logging then the fs was already flushed in logsetup(). 956355d6bb5Sswilcox */ 957355d6bb5Sswilcox if (!islog && !mflag) 958355d6bb5Sswilcox flush_fs(); 959355d6bb5Sswilcox 960355d6bb5Sswilcox if (find_superblock(devstr) == -1) 961355d6bb5Sswilcox goto cleanup; 962355d6bb5Sswilcox 963355d6bb5Sswilcox fixup_superblock(); 964355d6bb5Sswilcox 965355d6bb5Sswilcox if (errorlocked && 966355d6bb5Sswilcox (initial_error_state_adjust() == -1)) 967355d6bb5Sswilcox goto cleanup; 968355d6bb5Sswilcox 969355d6bb5Sswilcox /* 970355d6bb5Sswilcox * asblk could be dirty because we found a mismatch between 971355d6bb5Sswilcox * the primary superblock and one of its backups in checksb(). 972355d6bb5Sswilcox */ 973355d6bb5Sswilcox if (asblk.b_dirty && !bflag) { 974355d6bb5Sswilcox (void) memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize); 975355d6bb5Sswilcox flush(fswritefd, &asblk); 976355d6bb5Sswilcox } 977355d6bb5Sswilcox 978355d6bb5Sswilcox getsummaryinfo(); 979355d6bb5Sswilcox 980355d6bb5Sswilcox /* 981355d6bb5Sswilcox * if not error-locked, using the standard superblock, 982355d6bb5Sswilcox * not bad log, not forced, preening, and is clean; 983355d6bb5Sswilcox * stop checking 984355d6bb5Sswilcox */ 985355d6bb5Sswilcox if (!errorlocked && (bflag == 0) && 986355d6bb5Sswilcox ((!islog || islogok) && 987355d6bb5Sswilcox (fflag == 0) && preen && 988355d6bb5Sswilcox (FSOKAY == (sblock.fs_state + sblock.fs_time)) && 989355d6bb5Sswilcox ((sblock.fs_clean == FSLOG && islog) || 990355d6bb5Sswilcox ((sblock.fs_clean == FSCLEAN) || (sblock.fs_clean == FSSTABLE))))) { 991355d6bb5Sswilcox iscorrupt = 0; 992355d6bb5Sswilcox printclean(); 993355d6bb5Sswilcox goto cleanup; 994355d6bb5Sswilcox } 995355d6bb5Sswilcox 996355d6bb5Sswilcox if (create_and_init_maps() == -1) 997355d6bb5Sswilcox goto nomaps; 998355d6bb5Sswilcox 9997c478bd9Sstevel@tonic-gate bufinit(); 10007c478bd9Sstevel@tonic-gate return (devstr); 10017c478bd9Sstevel@tonic-gate 1002355d6bb5Sswilcox nomaps: 10037c478bd9Sstevel@tonic-gate ckfini(); 1004355d6bb5Sswilcox exitstat = EXERRFATAL; 1005355d6bb5Sswilcox /* FALLTHROUGH */ 1006355d6bb5Sswilcox 1007355d6bb5Sswilcox cleanup: 1008355d6bb5Sswilcox unbufinit(); 1009355d6bb5Sswilcox uncreate_maps(); 1010355d6bb5Sswilcox ungetsummaryinfo(); 1011355d6bb5Sswilcox 1012355d6bb5Sswilcox /* 1013355d6bb5Sswilcox * Can't get rid of the superblock buffer, because our 1014355d6bb5Sswilcox * caller references it to generate the summary statistics. 1015355d6bb5Sswilcox */ 1016355d6bb5Sswilcox 1017355d6bb5Sswilcox return (NULL); 1018355d6bb5Sswilcox } 1019355d6bb5Sswilcox 1020355d6bb5Sswilcox /* 1021355d6bb5Sswilcox * Undoes the allocations in create_and_init_maps() 1022355d6bb5Sswilcox */ 1023355d6bb5Sswilcox static void 1024355d6bb5Sswilcox uncreate_maps(void) 1025355d6bb5Sswilcox { 1026355d6bb5Sswilcox /* 1027355d6bb5Sswilcox * No ordering dependency amongst these, so they are here in 1028355d6bb5Sswilcox * the same order they were calculated. 1029355d6bb5Sswilcox */ 1030355d6bb5Sswilcox if (blockmap != NULL) 1031355d6bb5Sswilcox free(blockmap); 1032355d6bb5Sswilcox if (statemap != NULL) 1033355d6bb5Sswilcox free(statemap); 1034355d6bb5Sswilcox if (lncntp != NULL) 1035355d6bb5Sswilcox free(lncntp); 1036355d6bb5Sswilcox if (inpsort != NULL) 1037355d6bb5Sswilcox free(inpsort); 1038355d6bb5Sswilcox if (inphead != NULL) 1039355d6bb5Sswilcox free(inphead); 1040355d6bb5Sswilcox if (aclpsort != NULL) 1041355d6bb5Sswilcox free(aclpsort); 1042355d6bb5Sswilcox if (aclphead != NULL) 1043355d6bb5Sswilcox free(aclphead); 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate /* 10477c478bd9Sstevel@tonic-gate * mkfs limits the size of the inode map to be no more than a third of 10487c478bd9Sstevel@tonic-gate * the cylinder group space. We'll use that value for sanity checking 10497c478bd9Sstevel@tonic-gate * the superblock's inode per group value. 10507c478bd9Sstevel@tonic-gate */ 10517c478bd9Sstevel@tonic-gate #define MAXIpG (roundup(sblock.fs_bsize * NBBY / 3, sblock.fs_inopb)) 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate /* 10547c478bd9Sstevel@tonic-gate * Check the super block and its summary info. 10557c478bd9Sstevel@tonic-gate */ 10567c478bd9Sstevel@tonic-gate static int 10577c478bd9Sstevel@tonic-gate checksb(int listerr) 10587c478bd9Sstevel@tonic-gate { 1059355d6bb5Sswilcox caddr_t err; 1060355d6bb5Sswilcox 10617c478bd9Sstevel@tonic-gate /* 10627c478bd9Sstevel@tonic-gate * When the fs check is successfully completed, the alternate super 10637c478bd9Sstevel@tonic-gate * block at sblk.b_bno will be overwritten by ckfini() with the 10647c478bd9Sstevel@tonic-gate * repaired super block. 10657c478bd9Sstevel@tonic-gate */ 1066355d6bb5Sswilcox sblk.b_bno = bflag ? bflag : (SBOFF / dev_bsize); 10677c478bd9Sstevel@tonic-gate sblk.b_size = SBSIZE; 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate /* 1070355d6bb5Sswilcox * Sanity-check some of the values we are going to use later 1071355d6bb5Sswilcox * in allocation requests. 10727c478bd9Sstevel@tonic-gate */ 10737c478bd9Sstevel@tonic-gate if (sblock.fs_cstotal.cs_ndir < 1 || 10747c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_ndir > sblock.fs_ncg * sblock.fs_ipg) { 1075355d6bb5Sswilcox if (verbose) 1076355d6bb5Sswilcox (void) printf( 1077355d6bb5Sswilcox "Found %d directories, should be between 1 and %d inclusive.\n", 1078355d6bb5Sswilcox sblock.fs_cstotal.cs_ndir, 1079355d6bb5Sswilcox sblock.fs_ncg * sblock.fs_ipg); 1080355d6bb5Sswilcox err = "NUMBER OF DIRECTORIES OUT OF RANGE"; 1081355d6bb5Sswilcox goto failedsb; 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate if (sblock.fs_nrpos <= 0 || sblock.fs_postbloff < 0 || 10857c478bd9Sstevel@tonic-gate sblock.fs_cpc < 0 || 10867c478bd9Sstevel@tonic-gate (sblock.fs_postbloff + 10877c478bd9Sstevel@tonic-gate (sblock.fs_nrpos * sblock.fs_cpc * sizeof (short))) > 10887c478bd9Sstevel@tonic-gate sblock.fs_sbsize) { 1089355d6bb5Sswilcox err = "ROTATIONAL POSITION TABLE SIZE OUT OF RANGE"; 1090355d6bb5Sswilcox goto failedsb; 10917c478bd9Sstevel@tonic-gate } 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate if (sblock.fs_cssize != 10947c478bd9Sstevel@tonic-gate fragroundup(&sblock, sblock.fs_ncg * sizeof (struct csum))) { 1095355d6bb5Sswilcox err = "SIZE OF CYLINDER GROUP SUMMARY AREA WRONG"; 1096355d6bb5Sswilcox goto failedsb; 10977c478bd9Sstevel@tonic-gate } 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate if (sblock.fs_inopb != (sblock.fs_bsize / sizeof (struct dinode))) { 1100355d6bb5Sswilcox err = "INOPB NONSENSICAL RELATIVE TO BSIZE"; 1101355d6bb5Sswilcox goto failedsb; 1102355d6bb5Sswilcox } 1103355d6bb5Sswilcox 1104355d6bb5Sswilcox if (sblock.fs_bsize > MAXBSIZE) { 1105355d6bb5Sswilcox err = "BLOCK SIZE LARGER THAN MAXIMUM SUPPORTED"; 1106355d6bb5Sswilcox goto failedsb; 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate if (sblock.fs_bsize != (sblock.fs_frag * sblock.fs_fsize)) { 1110355d6bb5Sswilcox err = "FRAGS PER BLOCK OR FRAG SIZE WRONG"; 1111355d6bb5Sswilcox goto failedsb; 11127c478bd9Sstevel@tonic-gate } 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate if (sblock.fs_dsize >= sblock.fs_size) { 1115355d6bb5Sswilcox err = "NUMBER OF DATA BLOCKS OUT OF RANGE"; 1116355d6bb5Sswilcox goto failedsb; 11177c478bd9Sstevel@tonic-gate } 11187c478bd9Sstevel@tonic-gate 1119355d6bb5Sswilcox #if 0 1120355d6bb5Sswilcox if (sblock.fs_size > 1121355d6bb5Sswilcox (sblock.fs_nsect * sblock.fs_ntrak * sblock.fs_ncyl)) { 1122355d6bb5Sswilcox err = "FILESYSTEM SIZE LARGER THAN DEVICE"; 1123355d6bb5Sswilcox goto failedsb; 1124355d6bb5Sswilcox } 1125355d6bb5Sswilcox #endif 1126355d6bb5Sswilcox 11277c478bd9Sstevel@tonic-gate /* 11287c478bd9Sstevel@tonic-gate * Check that the number of inodes per group isn't less than or 11297c478bd9Sstevel@tonic-gate * equal to zero. Also makes sure it isn't more than the 11307c478bd9Sstevel@tonic-gate * maximum number mkfs enforces. 11317c478bd9Sstevel@tonic-gate */ 11327c478bd9Sstevel@tonic-gate if (sblock.fs_ipg <= 0 || sblock.fs_ipg > MAXIpG) { 1133355d6bb5Sswilcox err = "INODES PER GROUP OUT OF RANGE"; 1134355d6bb5Sswilcox goto failedsb; 1135355d6bb5Sswilcox } 1136355d6bb5Sswilcox 1137355d6bb5Sswilcox if (sblock.fs_cgsize > sblock.fs_bsize) { 1138355d6bb5Sswilcox err = "CG HEADER LARGER THAN ONE BLOCK"; 1139355d6bb5Sswilcox goto failedsb; 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate /* 11437c478bd9Sstevel@tonic-gate * Set all possible fields that could differ, then do check 11447c478bd9Sstevel@tonic-gate * of whole super block against an alternate super block. 11457c478bd9Sstevel@tonic-gate * When an alternate super-block is specified this check is skipped. 11467c478bd9Sstevel@tonic-gate */ 1147355d6bb5Sswilcox (void) getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), 1148355d6bb5Sswilcox (size_t)sblock.fs_sbsize); 1149355d6bb5Sswilcox if (asblk.b_errs != 0) { 1150355d6bb5Sswilcox brelse(&asblk); 11517c478bd9Sstevel@tonic-gate return (0); 1152355d6bb5Sswilcox } 1153355d6bb5Sswilcox if (bflag != 0) { 11547c478bd9Sstevel@tonic-gate /* 1155355d6bb5Sswilcox * Invalidate clean flag and state information. 1156355d6bb5Sswilcox * Note that we couldn't return until after the 1157355d6bb5Sswilcox * above getblk(), because we're going to want to 1158355d6bb5Sswilcox * update asblk when everything's done. 11597c478bd9Sstevel@tonic-gate */ 11607c478bd9Sstevel@tonic-gate sblock.fs_clean = FSACTIVE; 11617c478bd9Sstevel@tonic-gate sblock.fs_state = (long)sblock.fs_time; 11627c478bd9Sstevel@tonic-gate sblock.fs_reclaim = 0; 11637c478bd9Sstevel@tonic-gate sbdirty(); 11647c478bd9Sstevel@tonic-gate havesb = 1; 11657c478bd9Sstevel@tonic-gate return (1); 11667c478bd9Sstevel@tonic-gate } 11677c478bd9Sstevel@tonic-gate altsblock.fs_link = sblock.fs_link; 11687c478bd9Sstevel@tonic-gate altsblock.fs_rolled = sblock.fs_rolled; 11697c478bd9Sstevel@tonic-gate altsblock.fs_time = sblock.fs_time; 11707c478bd9Sstevel@tonic-gate altsblock.fs_state = sblock.fs_state; 11717c478bd9Sstevel@tonic-gate altsblock.fs_cstotal = sblock.fs_cstotal; 11727c478bd9Sstevel@tonic-gate altsblock.fs_cgrotor = sblock.fs_cgrotor; 11737c478bd9Sstevel@tonic-gate altsblock.fs_fmod = sblock.fs_fmod; 11747c478bd9Sstevel@tonic-gate altsblock.fs_clean = sblock.fs_clean; 11757c478bd9Sstevel@tonic-gate altsblock.fs_ronly = sblock.fs_ronly; 11767c478bd9Sstevel@tonic-gate altsblock.fs_flags = sblock.fs_flags; 11777c478bd9Sstevel@tonic-gate altsblock.fs_maxcontig = sblock.fs_maxcontig; 11787c478bd9Sstevel@tonic-gate altsblock.fs_minfree = sblock.fs_minfree; 11797c478bd9Sstevel@tonic-gate altsblock.fs_optim = sblock.fs_optim; 11807c478bd9Sstevel@tonic-gate altsblock.fs_rotdelay = sblock.fs_rotdelay; 11817c478bd9Sstevel@tonic-gate altsblock.fs_maxbpg = sblock.fs_maxbpg; 11827c478bd9Sstevel@tonic-gate altsblock.fs_logbno = sblock.fs_logbno; 11837c478bd9Sstevel@tonic-gate altsblock.fs_reclaim = sblock.fs_reclaim; 11847c478bd9Sstevel@tonic-gate altsblock.fs_si = sblock.fs_si; 1185355d6bb5Sswilcox (void) memmove((void *)altsblock.fs_fsmnt, (void *)sblock.fs_fsmnt, 11867c478bd9Sstevel@tonic-gate sizeof (sblock.fs_fsmnt)); 11877c478bd9Sstevel@tonic-gate /* 11887c478bd9Sstevel@tonic-gate * The following should not have to be copied. 11897c478bd9Sstevel@tonic-gate */ 1190355d6bb5Sswilcox (void) memmove((void *)altsblock.fs_u.fs_csp_pad, 1191355d6bb5Sswilcox (void *)sblock.fs_u.fs_csp_pad, sizeof (sblock.fs_u.fs_csp_pad)); 11927c478bd9Sstevel@tonic-gate altsblock.fs_fsbtodb = sblock.fs_fsbtodb; 11937c478bd9Sstevel@tonic-gate altsblock.fs_npsect = sblock.fs_npsect; 11947c478bd9Sstevel@tonic-gate altsblock.fs_nrpos = sblock.fs_nrpos; 1195355d6bb5Sswilcox if (memcmp((void *)&sblock, (void *)&altsblock, 1196355d6bb5Sswilcox (size_t)sblock.fs_sbsize) != 0) { 1197355d6bb5Sswilcox err = "BAD VALUES IN SUPER BLOCK"; 1198355d6bb5Sswilcox goto failedsb; 11997c478bd9Sstevel@tonic-gate } 12007c478bd9Sstevel@tonic-gate havesb = 1; 12017c478bd9Sstevel@tonic-gate return (1); 1202355d6bb5Sswilcox 1203355d6bb5Sswilcox failedsb: 1204355d6bb5Sswilcox badsb(listerr, err); 1205355d6bb5Sswilcox return (0); 12067c478bd9Sstevel@tonic-gate } 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate static void 1209355d6bb5Sswilcox badsb(int listerr, caddr_t s) 12107c478bd9Sstevel@tonic-gate { 12117c478bd9Sstevel@tonic-gate if (!listerr) 12127c478bd9Sstevel@tonic-gate return; 12137c478bd9Sstevel@tonic-gate if (preen) 1214355d6bb5Sswilcox (void) printf("%s: ", devname); 1215355d6bb5Sswilcox (void) printf("BAD SUPERBLOCK AT BLOCK %d: %s\n", 1216355d6bb5Sswilcox bflag != 0 ? bflag : SBLOCK, s); 1217355d6bb5Sswilcox if (preen) { 1218355d6bb5Sswilcox pwarn( 1219355d6bb5Sswilcox "USE AN ALTERNATE SUPERBLOCK TO SUPPLY NEEDED INFORMATION;\n"); 1220355d6bb5Sswilcox pwarn("e.g. fsck [-F ufs] -o b=# [special ...] \n"); 1221355d6bb5Sswilcox exitstat = EXERRFATAL; 1222355d6bb5Sswilcox pfatal( 1223355d6bb5Sswilcox "where # is the alternate super block. SEE fsck_ufs(1M). \n"); 1224355d6bb5Sswilcox } 1225355d6bb5Sswilcox /* we're expected to return if not preening */ 12267c478bd9Sstevel@tonic-gate } 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate /* 12297c478bd9Sstevel@tonic-gate * Write out the super block into each of the alternate super blocks. 12307c478bd9Sstevel@tonic-gate */ 12317c478bd9Sstevel@tonic-gate void 12327c478bd9Sstevel@tonic-gate write_altsb(int fd) 12337c478bd9Sstevel@tonic-gate { 12347c478bd9Sstevel@tonic-gate int cylno; 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate for (cylno = 0; cylno < sblock.fs_ncg; cylno++) 1237355d6bb5Sswilcox bwrite(fd, (caddr_t)&sblock, fsbtodb(&sblock, 12387c478bd9Sstevel@tonic-gate cgsblock(&sblock, cylno)), sblock.fs_sbsize); 12397c478bd9Sstevel@tonic-gate } 1240355d6bb5Sswilcox 1241355d6bb5Sswilcox static void 1242355d6bb5Sswilcox sblock_init(void) 1243355d6bb5Sswilcox { 1244355d6bb5Sswilcox fsmodified = 0; 1245355d6bb5Sswilcox if (errorlocked) 1246355d6bb5Sswilcox isdirty = 1; 1247355d6bb5Sswilcox lfdir = 0; 1248355d6bb5Sswilcox initbarea(&sblk); 1249355d6bb5Sswilcox initbarea(&asblk); 1250355d6bb5Sswilcox 1251355d6bb5Sswilcox /* 1252355d6bb5Sswilcox * May have buffer left over from previous filesystem check. 1253355d6bb5Sswilcox */ 1254355d6bb5Sswilcox if (sblk.b_un.b_buf == NULL) 1255355d6bb5Sswilcox sblk.b_un.b_buf = calloc(1, SBSIZE); 1256355d6bb5Sswilcox if (asblk.b_un.b_buf == NULL) 1257355d6bb5Sswilcox asblk.b_un.b_buf = calloc(1, SBSIZE); 1258355d6bb5Sswilcox if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) 1259355d6bb5Sswilcox errexit("cannot allocate space for superblock\n"); 1260355d6bb5Sswilcox /* 1261355d6bb5Sswilcox * Could get the actual sector size from the device here, 1262355d6bb5Sswilcox * but considering how much would need to change in the rest 1263355d6bb5Sswilcox * of the system before it'd be a problem for us, it's not 1264355d6bb5Sswilcox * worth worrying about right now. 1265355d6bb5Sswilcox */ 1266355d6bb5Sswilcox dev_bsize = secsize = DEV_BSIZE; 1267355d6bb5Sswilcox } 1268355d6bb5Sswilcox 1269355d6bb5Sswilcox /* 1270355d6bb5Sswilcox * Calculate a prototype superblock based on information in the disk label. 1271355d6bb5Sswilcox * When done the cgsblock macro can be calculated and the fs_ncg field 1272355d6bb5Sswilcox * can be used. Do NOT attempt to use other macros without verifying that 1273355d6bb5Sswilcox * their needed information is available! 1274355d6bb5Sswilcox * 1275355d6bb5Sswilcox * In BSD, the disk label includes all sorts of useful information, 1276355d6bb5Sswilcox * like cpg. Solaris doesn't have that, and deriving it (as well as 1277355d6bb5Sswilcox * some other parameters) is difficult. Rather than duplicate the 1278355d6bb5Sswilcox * code, just ask mkfs what it would've come up with by default. 1279355d6bb5Sswilcox * Ideally, we'd just link in the code, but given the source base 1280355d6bb5Sswilcox * involved, it's more practical to just get a binary dump. 1281355d6bb5Sswilcox * 1282355d6bb5Sswilcox * The one minor drawback to the above approach is that newfs and mkfs 1283355d6bb5Sswilcox * will produce vastly different layouts for the same partition if 1284355d6bb5Sswilcox * they're allowed to default everything. So, if the superblock that 1285355d6bb5Sswilcox * mkfs gives us doesn't work for guessing where the alternates are, 1286355d6bb5Sswilcox * we need to try newfs. 1287355d6bb5Sswilcox */ 1288355d6bb5Sswilcox static int 1289355d6bb5Sswilcox calcsb(calcsb_t style, caddr_t dev, int devfd, struct fs *fs) 1290355d6bb5Sswilcox { 1291355d6bb5Sswilcox #define FROM_CHILD 0 1292355d6bb5Sswilcox #define TO_FSCK 1 1293355d6bb5Sswilcox #define CMD_IDX 0 1294355d6bb5Sswilcox #define DEV_IDX 3 1295355d6bb5Sswilcox #define SIZE_IDX 4 1296355d6bb5Sswilcox 1297355d6bb5Sswilcox int child_pipe[2]; 1298355d6bb5Sswilcox caddr_t mkfsline[] = { 1299355d6bb5Sswilcox "", /* CMD_IDX */ 1300355d6bb5Sswilcox "-o", 1301355d6bb5Sswilcox "calcbinsb,N", 1302355d6bb5Sswilcox NULL, /* DEV_IDX */ 1303355d6bb5Sswilcox NULL, /* SIZE_IDX */ 1304355d6bb5Sswilcox NULL 1305355d6bb5Sswilcox }; 1306355d6bb5Sswilcox caddr_t newfsline[] = { 1307355d6bb5Sswilcox "", /* CMD_IDX */ 1308355d6bb5Sswilcox "-B", 1309355d6bb5Sswilcox "-N", 1310355d6bb5Sswilcox NULL, /* DEV_IDX */ 1311355d6bb5Sswilcox NULL 1312355d6bb5Sswilcox }; 1313355d6bb5Sswilcox int pending, transferred; 1314355d6bb5Sswilcox caddr_t *cmdline; 1315355d6bb5Sswilcox caddr_t target; 1316355d6bb5Sswilcox caddr_t sizestr = NULL; 1317355d6bb5Sswilcox caddr_t path_old, path_new, mkfs_dir, mkfs_path, newfs_path; 1318355d6bb5Sswilcox caddr_t slash; 1319355d6bb5Sswilcox diskaddr_t size; 1320355d6bb5Sswilcox int devnull; 1321355d6bb5Sswilcox 1322355d6bb5Sswilcox switch (style) { 1323355d6bb5Sswilcox case MKFS_STYLE: 1324355d6bb5Sswilcox if (debug) 1325355d6bb5Sswilcox (void) printf("calcsb() going with style MKFS\n"); 1326355d6bb5Sswilcox cmdline = mkfsline; 1327355d6bb5Sswilcox break; 1328355d6bb5Sswilcox case NEWFS_STYLE: 1329355d6bb5Sswilcox if (debug) 1330355d6bb5Sswilcox (void) printf("calcsb() going with style NEWFS\n"); 1331355d6bb5Sswilcox cmdline = newfsline; 1332355d6bb5Sswilcox break; 1333355d6bb5Sswilcox default: 1334355d6bb5Sswilcox if (debug) 1335355d6bb5Sswilcox (void) printf("calcsb() doesn't undestand style %d\n", 1336355d6bb5Sswilcox style); 1337355d6bb5Sswilcox return (0); 1338355d6bb5Sswilcox } 1339355d6bb5Sswilcox 1340355d6bb5Sswilcox cmdline[DEV_IDX] = dev; 1341355d6bb5Sswilcox 1342355d6bb5Sswilcox /* 1343355d6bb5Sswilcox * Normally, only use the stock versions of the utilities. 1344355d6bb5Sswilcox * However, if we're debugging, the odds are that we're 1345355d6bb5Sswilcox * using experimental versions of them as well, so allow 1346355d6bb5Sswilcox * some flexibility. 1347355d6bb5Sswilcox */ 1348355d6bb5Sswilcox mkfs_path = getenv("MKFS_PATH"); 1349355d6bb5Sswilcox if (!debug || (mkfs_path == NULL)) 1350355d6bb5Sswilcox mkfs_path = MKFS_PATH; 1351355d6bb5Sswilcox 1352355d6bb5Sswilcox newfs_path = getenv("NEWFS_PATH"); 1353355d6bb5Sswilcox if (!debug || (newfs_path == NULL)) 1354355d6bb5Sswilcox newfs_path = NEWFS_PATH; 1355355d6bb5Sswilcox 1356355d6bb5Sswilcox if (style == MKFS_STYLE) { 1357355d6bb5Sswilcox cmdline[CMD_IDX] = mkfs_path; 1358355d6bb5Sswilcox 1359355d6bb5Sswilcox size = getdisksize(dev, devfd); 1360355d6bb5Sswilcox if (size == 0) 1361355d6bb5Sswilcox return (0); 1362355d6bb5Sswilcox 1363355d6bb5Sswilcox (void) fsck_asprintf(&sizestr, "%lld", (longlong_t)size); 1364355d6bb5Sswilcox cmdline[SIZE_IDX] = sizestr; 1365355d6bb5Sswilcox } else if (style == NEWFS_STYLE) { 1366355d6bb5Sswilcox /* 1367355d6bb5Sswilcox * Make sure that newfs will find the right version of mkfs. 1368355d6bb5Sswilcox */ 1369355d6bb5Sswilcox cmdline[CMD_IDX] = newfs_path; 1370355d6bb5Sswilcox path_old = getenv("PATH"); 1371355d6bb5Sswilcox /* mkfs_path is always initialized, despite lint's concerns */ 1372355d6bb5Sswilcox mkfs_dir = strdup(mkfs_path); 1373355d6bb5Sswilcox if (mkfs_dir == NULL) 1374355d6bb5Sswilcox return (0); 1375355d6bb5Sswilcox /* 1376355d6bb5Sswilcox * If no location data for mkfs, don't need to do 1377355d6bb5Sswilcox * anything about PATH. 1378355d6bb5Sswilcox */ 1379355d6bb5Sswilcox slash = strrchr(mkfs_dir, '/'); 1380355d6bb5Sswilcox if (slash != NULL) { 1381355d6bb5Sswilcox /* 1382355d6bb5Sswilcox * Just want the dir, so discard the executable name. 1383355d6bb5Sswilcox */ 1384355d6bb5Sswilcox *slash = '\0'; 1385355d6bb5Sswilcox 1386355d6bb5Sswilcox /* 1387355d6bb5Sswilcox * newfs uses system() to find mkfs, so make sure 1388355d6bb5Sswilcox * that the one we want to use is first on the 1389355d6bb5Sswilcox * list. Don't free path_new upon success, as it 1390355d6bb5Sswilcox * has become part of the environment. 1391355d6bb5Sswilcox */ 1392355d6bb5Sswilcox (void) fsck_asprintf(&path_new, "PATH=%s:%s", 1393355d6bb5Sswilcox mkfs_dir, path_old); 1394355d6bb5Sswilcox if (putenv(path_new) != 0) { 1395355d6bb5Sswilcox free(mkfs_dir); 1396355d6bb5Sswilcox free(path_new); 1397355d6bb5Sswilcox return (0); 1398355d6bb5Sswilcox } 1399355d6bb5Sswilcox } 1400355d6bb5Sswilcox free(mkfs_dir); 1401355d6bb5Sswilcox } else { 1402355d6bb5Sswilcox /* 1403355d6bb5Sswilcox * Bad search style, quietly return failure. 1404355d6bb5Sswilcox */ 1405355d6bb5Sswilcox if (debug) { 1406355d6bb5Sswilcox (void) printf("calcsb: got bad style number %d\n", 1407355d6bb5Sswilcox (int)style); 1408355d6bb5Sswilcox } 1409355d6bb5Sswilcox return (0); 1410355d6bb5Sswilcox } 1411355d6bb5Sswilcox 1412355d6bb5Sswilcox if (pipe(child_pipe) < 0) { 1413355d6bb5Sswilcox pfatal("calcsb: could not create pipe: %s\n", strerror(errno)); 1414355d6bb5Sswilcox if (sizestr != NULL) 1415355d6bb5Sswilcox free(sizestr); 1416355d6bb5Sswilcox return (0); 1417355d6bb5Sswilcox } 1418355d6bb5Sswilcox 1419355d6bb5Sswilcox switch (fork()) { 1420355d6bb5Sswilcox case -1: 1421355d6bb5Sswilcox pfatal("calcsb: fork failed: %s\n", strerror(errno)); 1422355d6bb5Sswilcox if (sizestr != NULL) 1423355d6bb5Sswilcox free(sizestr); 1424355d6bb5Sswilcox return (0); 1425355d6bb5Sswilcox case 0: 1426355d6bb5Sswilcox if (dup2(child_pipe[TO_FSCK], fileno(stdout)) < 0) { 1427355d6bb5Sswilcox (void) printf( 1428355d6bb5Sswilcox "calcsb: could not rename file descriptor: %s\n", 1429355d6bb5Sswilcox strerror(errno)); 1430355d6bb5Sswilcox exit(EXBADPARM); 1431355d6bb5Sswilcox } 1432355d6bb5Sswilcox devnull = open("/dev/null", O_WRONLY); 1433355d6bb5Sswilcox if (devnull == -1) { 1434355d6bb5Sswilcox (void) printf("calcsb: could not open /dev/null: %s\n", 1435355d6bb5Sswilcox strerror(errno)); 1436355d6bb5Sswilcox exit(EXBADPARM); 1437355d6bb5Sswilcox } 1438355d6bb5Sswilcox if (dup2(devnull, fileno(stderr)) < 0) { 1439355d6bb5Sswilcox (void) printf( 1440355d6bb5Sswilcox "calcsb: could not rename file descriptor: %s\n", 1441355d6bb5Sswilcox strerror(errno)); 1442355d6bb5Sswilcox exit(EXBADPARM); 1443355d6bb5Sswilcox } 1444355d6bb5Sswilcox (void) close(child_pipe[FROM_CHILD]); 1445355d6bb5Sswilcox (void) execv(cmdline[CMD_IDX], cmdline); 1446355d6bb5Sswilcox (void) printf("calcsb: could not exec %s: %s\n", 1447355d6bb5Sswilcox cmdline[CMD_IDX], strerror(errno)); 1448355d6bb5Sswilcox exit(EXBADPARM); 1449355d6bb5Sswilcox /* NOTREACHED */ 1450355d6bb5Sswilcox default: 1451355d6bb5Sswilcox break; 1452355d6bb5Sswilcox } 1453355d6bb5Sswilcox 1454355d6bb5Sswilcox (void) close(child_pipe[TO_FSCK]); 1455355d6bb5Sswilcox if (sizestr != NULL) 1456355d6bb5Sswilcox free(sizestr); 1457355d6bb5Sswilcox 1458355d6bb5Sswilcox pending = sizeof (struct fs); 1459355d6bb5Sswilcox target = (caddr_t)fs; 1460355d6bb5Sswilcox do { 1461355d6bb5Sswilcox transferred = read(child_pipe[FROM_CHILD], target, pending); 1462355d6bb5Sswilcox pending -= transferred; 1463355d6bb5Sswilcox target += transferred; 1464355d6bb5Sswilcox } while ((pending > 0) && (transferred > 0)); 1465355d6bb5Sswilcox 1466355d6bb5Sswilcox if (pending > 0) { 1467355d6bb5Sswilcox if (transferred < 0) 1468355d6bb5Sswilcox pfatal( 1469355d6bb5Sswilcox "calcsb: binary read of superblock from %s failed: %s\n", 1470355d6bb5Sswilcox (style == MKFS_STYLE) ? "mkfs" : "newfs", 1471355d6bb5Sswilcox (transferred < 0) ? strerror(errno) : ""); 1472355d6bb5Sswilcox else 1473355d6bb5Sswilcox pfatal( 1474355d6bb5Sswilcox "calcsb: short read of superblock from %s\n", 1475355d6bb5Sswilcox (style == MKFS_STYLE) ? "mkfs" : "newfs"); 1476355d6bb5Sswilcox return (0); 1477355d6bb5Sswilcox } 1478355d6bb5Sswilcox 1479355d6bb5Sswilcox (void) close(child_pipe[FROM_CHILD]); 1480355d6bb5Sswilcox (void) wait(NULL); 1481355d6bb5Sswilcox 1482355d6bb5Sswilcox if ((fs->fs_magic != FS_MAGIC) && 1483355d6bb5Sswilcox (fs->fs_magic != MTB_UFS_MAGIC)) 1484355d6bb5Sswilcox return (0); 1485355d6bb5Sswilcox 1486355d6bb5Sswilcox return (1); 1487355d6bb5Sswilcox } 1488