xref: /illumos-gate/usr/src/cmd/fs.d/ufs/fsck/setup.c (revision 355d6bb5)
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