xref: /illumos-gate/usr/src/cmd/fs.d/ufs/fsck/setup.c (revision ac34f4dd)
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 #define	DKTYPENAMES
297c478bd9Sstevel@tonic-gate #include <stdio.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <errno.h>
32355d6bb5Sswilcox #include <malloc.h>
33355d6bb5Sswilcox #include <limits.h>
34355d6bb5Sswilcox #include <wait.h>
357c478bd9Sstevel@tonic-gate #include <sys/param.h>
367c478bd9Sstevel@tonic-gate #include <sys/types.h>
377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
387c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
397c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
407c478bd9Sstevel@tonic-gate #include <sys/filio.h>
417c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>	/* for ENDIAN defines */
427c478bd9Sstevel@tonic-gate #include <sys/int_const.h>
437c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
447c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
45355d6bb5Sswilcox #include <sys/fs/ufs_fs.h>
467c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
477c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_log.h>
487c478bd9Sstevel@tonic-gate #include <sys/stat.h>
497c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
507c478bd9Sstevel@tonic-gate #include <string.h>
517c478bd9Sstevel@tonic-gate #include <unistd.h>
527c478bd9Sstevel@tonic-gate #include <fcntl.h>
537c478bd9Sstevel@tonic-gate #include <sys/vfstab.h>
547c478bd9Sstevel@tonic-gate #include "roll_log.h"
55355d6bb5Sswilcox #include "fsck.h"
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  * The size of a cylinder group is calculated by CGSIZE. The maximum size
597c478bd9Sstevel@tonic-gate  * is limited by the fact that cylinder groups are at most one block.
607c478bd9Sstevel@tonic-gate  * Its size is derived from the size of the maps maintained in the
617c478bd9Sstevel@tonic-gate  * cylinder group and the (struct cg) size.
627c478bd9Sstevel@tonic-gate  */
637c478bd9Sstevel@tonic-gate #define	CGSIZE(fs) \
647c478bd9Sstevel@tonic-gate 	/* base cg */	  (sizeof (struct cg) + \
65355d6bb5Sswilcox 	/* blktot size */ (fs)->fs_cpg * sizeof (int32_t) + \
667c478bd9Sstevel@tonic-gate 	/* blks size */	  (fs)->fs_cpg * (fs)->fs_nrpos * sizeof (short) + \
677c478bd9Sstevel@tonic-gate 	/* inode map */	  howmany((fs)->fs_ipg, NBBY) + \
687c478bd9Sstevel@tonic-gate 	/* block map */	  howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY))
697c478bd9Sstevel@tonic-gate 
70355d6bb5Sswilcox #define	altsblock (*asblk.b_un.b_fs)
71355d6bb5Sswilcox #define	POWEROF2(num)	(((num) & ((num) - 1)) == 0)
72355d6bb5Sswilcox 
73355d6bb5Sswilcox /*
74355d6bb5Sswilcox  * Methods of determining where alternate superblocks should
75355d6bb5Sswilcox  * be.  MAX_SB_STYLES must be the last one, and the others need
76355d6bb5Sswilcox  * to be positive.
77355d6bb5Sswilcox  */
78355d6bb5Sswilcox typedef enum {
79355d6bb5Sswilcox 	MKFS_STYLE = 1, NEWFS_STYLE, MAX_SB_STYLES
80355d6bb5Sswilcox } calcsb_t;
81355d6bb5Sswilcox 
82355d6bb5Sswilcox static caddr_t calcsb_names[] = {
83355d6bb5Sswilcox 	"<UNKNOWN>", "MKFS", "NEWFS", "<OUT OF RANGE>"
84355d6bb5Sswilcox };
85355d6bb5Sswilcox 
86355d6bb5Sswilcox struct shadowclientinfo *shadowclientinfo = NULL;
87355d6bb5Sswilcox struct shadowclientinfo *attrclientinfo = NULL;
88355d6bb5Sswilcox int maxshadowclients = 1024;	/* allocation size, not limit  */
89355d6bb5Sswilcox 
90355d6bb5Sswilcox static void badsb(int, caddr_t);
91355d6bb5Sswilcox static int calcsb(calcsb_t, caddr_t, int, struct fs *);
92355d6bb5Sswilcox static int checksb(int);
93355d6bb5Sswilcox static void flush_fs(void);
94355d6bb5Sswilcox static void sblock_init(void);
95355d6bb5Sswilcox static void uncreate_maps(void);
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate static int
read_super_block(int listerr)98355d6bb5Sswilcox read_super_block(int listerr)
997c478bd9Sstevel@tonic-gate {
1007c478bd9Sstevel@tonic-gate 	int fd;
101355d6bb5Sswilcox 	caddr_t err;
1027c478bd9Sstevel@tonic-gate 
103355d6bb5Sswilcox 	if (mount_point != NULL) {
1047c478bd9Sstevel@tonic-gate 		fd = open(mount_point, O_RDONLY);
1057c478bd9Sstevel@tonic-gate 		if (fd == -1) {
106355d6bb5Sswilcox 			errexit("fsck: open mount point error: %s",
107355d6bb5Sswilcox 			    strerror(errno));
108355d6bb5Sswilcox 			/* NOTREACHED */
1097c478bd9Sstevel@tonic-gate 		}
1107c478bd9Sstevel@tonic-gate 		/* get the latest super block */
1117c478bd9Sstevel@tonic-gate 		if (ioctl(fd, _FIOGETSUPERBLOCK, &sblock)) {
112355d6bb5Sswilcox 			errexit("fsck: ioctl _FIOGETSUPERBLOCK error: %s",
113355d6bb5Sswilcox 			    strerror(errno));
114355d6bb5Sswilcox 			/* NOTREACHED */
1157c478bd9Sstevel@tonic-gate 		}
116355d6bb5Sswilcox 		(void) close(fd);
1177c478bd9Sstevel@tonic-gate 	} else {
118355d6bb5Sswilcox 		(void) fsck_bread(fsreadfd, (caddr_t)&sblock,
1197c478bd9Sstevel@tonic-gate 			bflag != 0 ? (diskaddr_t)bflag : (diskaddr_t)SBLOCK,
120355d6bb5Sswilcox 			SBSIZE);
1217c478bd9Sstevel@tonic-gate 	}
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	/*
124355d6bb5Sswilcox 	 * Don't let trash from the disk trip us up later
125355d6bb5Sswilcox 	 * in ungetsummaryinfo().
126355d6bb5Sswilcox 	 */
127355d6bb5Sswilcox 	sblock.fs_u.fs_csp = NULL;
128355d6bb5Sswilcox 
129355d6bb5Sswilcox 	/*
130355d6bb5Sswilcox 	 * Rudimentary consistency checks.  Can't really call
131355d6bb5Sswilcox 	 * checksb() here, because there may be outstanding
132355d6bb5Sswilcox 	 * deltas that still need to be applied.
1337c478bd9Sstevel@tonic-gate 	 */
1347c478bd9Sstevel@tonic-gate 	if ((sblock.fs_magic != FS_MAGIC) &&
135355d6bb5Sswilcox 	    (sblock.fs_magic != MTB_UFS_MAGIC)) {
136355d6bb5Sswilcox 		err = "MAGIC NUMBER WRONG";
137355d6bb5Sswilcox 		goto fail;
1387c478bd9Sstevel@tonic-gate 	}
1396451fdbcSvsakar 	if (sblock.fs_magic == FS_MAGIC &&
1406451fdbcSvsakar 		(sblock.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
1416451fdbcSvsakar 		sblock.fs_version != UFS_VERSION_MIN)) {
1426451fdbcSvsakar 		err = "UNRECOGNIZED VERSION";
1436451fdbcSvsakar 		goto fail;
1446451fdbcSvsakar 	}
1457c478bd9Sstevel@tonic-gate 	if (sblock.fs_magic == MTB_UFS_MAGIC &&
1467c478bd9Sstevel@tonic-gate 		(sblock.fs_version > MTB_UFS_VERSION_1 ||
1477c478bd9Sstevel@tonic-gate 		sblock.fs_version < MTB_UFS_VERSION_MIN)) {
148355d6bb5Sswilcox 		err = "UNRECOGNIZED VERSION";
149355d6bb5Sswilcox 		goto fail;
1507c478bd9Sstevel@tonic-gate 	}
1517c478bd9Sstevel@tonic-gate 	if (sblock.fs_ncg < 1) {
152355d6bb5Sswilcox 		err = "NCG OUT OF RANGE";
153355d6bb5Sswilcox 		goto fail;
1547c478bd9Sstevel@tonic-gate 	}
1557c478bd9Sstevel@tonic-gate 	if (sblock.fs_cpg < 1) {
156355d6bb5Sswilcox 		err = "CPG OUT OF RANGE";
157355d6bb5Sswilcox 		goto fail;
1587c478bd9Sstevel@tonic-gate 	}
1597c478bd9Sstevel@tonic-gate 	if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
1607c478bd9Sstevel@tonic-gate 		(sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) {
161355d6bb5Sswilcox 		err = "NCYL IS INCONSISTENT WITH NCG*CPG";
162355d6bb5Sswilcox 		goto fail;
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate 	if (sblock.fs_sbsize < 0 || sblock.fs_sbsize > SBSIZE) {
165355d6bb5Sswilcox 		err = "SIZE OUT OF RANGE";
166355d6bb5Sswilcox 		goto fail;
1677c478bd9Sstevel@tonic-gate 	}
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	return (1);
170355d6bb5Sswilcox 
171355d6bb5Sswilcox fail:
172355d6bb5Sswilcox 	badsb(listerr, err);
173355d6bb5Sswilcox 	return (0);
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate 
176355d6bb5Sswilcox static void
flush_fs()1777c478bd9Sstevel@tonic-gate flush_fs()
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate 	int fd;
1807c478bd9Sstevel@tonic-gate 
181355d6bb5Sswilcox 	if (mount_point != NULL) {
1827c478bd9Sstevel@tonic-gate 		fd = open(mount_point, O_RDONLY);
1837c478bd9Sstevel@tonic-gate 		if (fd == -1) {
184355d6bb5Sswilcox 			errexit("fsck: open mount point error: %s",
185355d6bb5Sswilcox 			    strerror(errno));
186355d6bb5Sswilcox 			/* NOTREACHED */
1877c478bd9Sstevel@tonic-gate 		}
1887c478bd9Sstevel@tonic-gate 		if (ioctl(fd, _FIOFFS, NULL)) { /* flush file system */
189355d6bb5Sswilcox 			errexit("fsck: ioctl _FIOFFS error: %s",
190355d6bb5Sswilcox 			    strerror(errno));
191355d6bb5Sswilcox 			/* NOTREACHED */
1927c478bd9Sstevel@tonic-gate 		}
193355d6bb5Sswilcox 		(void) close(fd);
1947c478bd9Sstevel@tonic-gate 	}
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /*
1987c478bd9Sstevel@tonic-gate  * Roll the embedded log, if any, and set up the global variables
199355d6bb5Sswilcox  * islog and islogok.
2007c478bd9Sstevel@tonic-gate  */
2017c478bd9Sstevel@tonic-gate static int
logsetup(caddr_t devstr)202355d6bb5Sswilcox logsetup(caddr_t devstr)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate 	void		*buf;
2057c478bd9Sstevel@tonic-gate 	extent_block_t	*ebp;
2067c478bd9Sstevel@tonic-gate 	ml_unit_t	*ul;
2077c478bd9Sstevel@tonic-gate 	ml_odunit_t	*ud;
2087c478bd9Sstevel@tonic-gate 	void		*ud_buf;
2097c478bd9Sstevel@tonic-gate 	int		badlog;
2107c478bd9Sstevel@tonic-gate 
211355d6bb5Sswilcox 	islog = islogok = 0;
212355d6bb5Sswilcox 	if (bflag != 0)
2137c478bd9Sstevel@tonic-gate 		return (1); /* can't roll log while alternate sb specified */
2147c478bd9Sstevel@tonic-gate 
215355d6bb5Sswilcox 	/*
216355d6bb5Sswilcox 	 * Roll the log, if any.  A bad sb implies we'll be using
217355d6bb5Sswilcox 	 * an alternate sb as far as logging goes, so just fail back
218355d6bb5Sswilcox 	 * to the caller if we can't read the default sb.  Suppress
219355d6bb5Sswilcox 	 * complaints, because the caller will be reading the same
220355d6bb5Sswilcox 	 * superblock again and running full verification on it, so
221355d6bb5Sswilcox 	 * whatever is bad will be reported then.
222355d6bb5Sswilcox 	 */
2237c478bd9Sstevel@tonic-gate 	sblock.fs_logbno = 0;
2247c478bd9Sstevel@tonic-gate 	badlog = 0;
225355d6bb5Sswilcox 	if (!read_super_block(0))
226355d6bb5Sswilcox 		return (1);
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	/*
2297c478bd9Sstevel@tonic-gate 	 * Roll the log in 3 cases:
2307c478bd9Sstevel@tonic-gate 	 * 1. If it's unmounted (mount_point == NULL) and it's not marked
2317c478bd9Sstevel@tonic-gate 	 *    as fully rolled (sblock.fs_rolled != FS_ALL_ROLLED)
2327c478bd9Sstevel@tonic-gate 	 * 2. If it's mounted and anything other than a sanity
2337c478bd9Sstevel@tonic-gate 	 *    check fsck (mflag) is being done, as we have the current
2347c478bd9Sstevel@tonic-gate 	 *    super block. Note, only a sanity check is done for
2357c478bd9Sstevel@tonic-gate 	 *    root/usr at boot. If a roll were done then the expensive
2367c478bd9Sstevel@tonic-gate 	 *    ufs_flush() gets called, leading to a slower boot.
2377c478bd9Sstevel@tonic-gate 	 * 3. If anything other then a sanity check (mflag) is being done
2387c478bd9Sstevel@tonic-gate 	 *    to a mounted filesystem while it is in read-only state
2397c478bd9Sstevel@tonic-gate 	 *    (e.g. root during early boot stages) we have to detect this
2407c478bd9Sstevel@tonic-gate 	 *    and have to roll the log as well. NB. the read-only mount
2417c478bd9Sstevel@tonic-gate 	 *    will flip fs_clean from FSLOG to FSSTABLE and marks the
2427c478bd9Sstevel@tonic-gate 	 *    log as FS_NEED_ROLL.
2437c478bd9Sstevel@tonic-gate 	 */
2447c478bd9Sstevel@tonic-gate 	if (sblock.fs_logbno &&
2457c478bd9Sstevel@tonic-gate 	    (((mount_point == NULL) && (sblock.fs_rolled != FS_ALL_ROLLED)) ||
246355d6bb5Sswilcox 	    ((mount_point != NULL) && !mflag))) {
2477c478bd9Sstevel@tonic-gate 		int roll_log_err = 0;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 		if (sblock.fs_ronly && (sblock.fs_clean == FSSTABLE) &&
2507c478bd9Sstevel@tonic-gate 			(sblock.fs_state + sblock.fs_time == FSOKAY)) {
2517c478bd9Sstevel@tonic-gate 			/*
2527c478bd9Sstevel@tonic-gate 			 * roll the log without a mount
2537c478bd9Sstevel@tonic-gate 			 */
2547c478bd9Sstevel@tonic-gate 			flush_fs();
2557c478bd9Sstevel@tonic-gate 		}
2567c478bd9Sstevel@tonic-gate 		if (sblock.fs_clean == FSLOG &&
2577c478bd9Sstevel@tonic-gate 			(sblock.fs_state + sblock.fs_time == FSOKAY)) {
2587c478bd9Sstevel@tonic-gate 			if (rl_roll_log(devstr) != RL_SUCCESS)
2597c478bd9Sstevel@tonic-gate 				roll_log_err = 1;
2607c478bd9Sstevel@tonic-gate 		}
2617c478bd9Sstevel@tonic-gate 		if (roll_log_err) {
2627c478bd9Sstevel@tonic-gate 			(void) printf("Can't roll the log for %s.\n", devstr);
2637c478bd9Sstevel@tonic-gate 			/*
2647c478bd9Sstevel@tonic-gate 			 * There are two cases where we want to set
2657c478bd9Sstevel@tonic-gate 			 * an error code and return:
2667c478bd9Sstevel@tonic-gate 			 *  - We're preening
2677c478bd9Sstevel@tonic-gate 			 *  - We're not on a live root and the user
2687c478bd9Sstevel@tonic-gate 			 *    chose *not* to ignore the log
2697c478bd9Sstevel@tonic-gate 			 * Otherwise, we want to mark the log as bad
2707c478bd9Sstevel@tonic-gate 			 * and continue to check the filesystem.  This
2717c478bd9Sstevel@tonic-gate 			 * has the side effect of destroying the log.
2727c478bd9Sstevel@tonic-gate 			 */
2737c478bd9Sstevel@tonic-gate 			if (preen || (!hotroot &&
2747c478bd9Sstevel@tonic-gate 			    reply(
2757c478bd9Sstevel@tonic-gate 			"DISCARDING THE LOG MAY DISCARD PENDING TRANSACTIONS.\n"
2767c478bd9Sstevel@tonic-gate 					"DISCARD THE LOG AND CONTINUE") == 0)) {
277355d6bb5Sswilcox 				exitstat = EXERRFATAL;
2787c478bd9Sstevel@tonic-gate 				return (0);
2797c478bd9Sstevel@tonic-gate 			}
2807c478bd9Sstevel@tonic-gate 			++badlog;
2817c478bd9Sstevel@tonic-gate 		}
2827c478bd9Sstevel@tonic-gate 	}
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	/* Logging UFS may be enabled */
2857c478bd9Sstevel@tonic-gate 	if (sblock.fs_logbno) {
2867c478bd9Sstevel@tonic-gate 		++islog;
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 		/* log is not okay; check the fs */
2897c478bd9Sstevel@tonic-gate 		if (FSOKAY != (sblock.fs_state + sblock.fs_time))
2907c478bd9Sstevel@tonic-gate 			return (1);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 		/*
2937c478bd9Sstevel@tonic-gate 		 * If logging or (stable and mounted) then continue
2947c478bd9Sstevel@tonic-gate 		 */
295355d6bb5Sswilcox 		if (!((sblock.fs_clean == FSLOG) ||
296355d6bb5Sswilcox 		    (sblock.fs_clean == FSSTABLE) && (mount_point != NULL)))
2977c478bd9Sstevel@tonic-gate 			return (1);
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 		/* get the log allocation block */
300355d6bb5Sswilcox 		buf = malloc(dev_bsize);
301355d6bb5Sswilcox 		if (buf == NULL) {
3027c478bd9Sstevel@tonic-gate 			return (1);
3037c478bd9Sstevel@tonic-gate 		}
304355d6bb5Sswilcox 		ud_buf = malloc(dev_bsize);
305355d6bb5Sswilcox 		if (ud_buf == NULL) {
3067c478bd9Sstevel@tonic-gate 			free(buf);
3077c478bd9Sstevel@tonic-gate 			return (1);
3087c478bd9Sstevel@tonic-gate 		}
309355d6bb5Sswilcox 		(void) fsck_bread(fsreadfd, buf,
3107c478bd9Sstevel@tonic-gate 		    logbtodb(&sblock, sblock.fs_logbno),
311355d6bb5Sswilcox 		    dev_bsize);
3127c478bd9Sstevel@tonic-gate 		ebp = (extent_block_t *)buf;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 		/* log allocation block is not okay; check the fs */
3157c478bd9Sstevel@tonic-gate 		if (ebp->type != LUFS_EXTENTS) {
3167c478bd9Sstevel@tonic-gate 			free(buf);
3177c478bd9Sstevel@tonic-gate 			free(ud_buf);
3187c478bd9Sstevel@tonic-gate 			return (1);
3197c478bd9Sstevel@tonic-gate 		}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 		/* get the log state block(s) */
322355d6bb5Sswilcox 		if (fsck_bread(fsreadfd, ud_buf,
3237c478bd9Sstevel@tonic-gate 		    (logbtodb(&sblock, ebp->extents[0].pbno)),
324355d6bb5Sswilcox 		    dev_bsize)) {
325355d6bb5Sswilcox 			(void) fsck_bread(fsreadfd, ud_buf,
326355d6bb5Sswilcox 			    (logbtodb(&sblock, ebp->extents[0].pbno)) + 1,
327355d6bb5Sswilcox 			    dev_bsize);
3287c478bd9Sstevel@tonic-gate 		}
3297c478bd9Sstevel@tonic-gate 		ud = (ml_odunit_t *)ud_buf;
3307c478bd9Sstevel@tonic-gate 		ul = (ml_unit_t *)malloc(sizeof (*ul));
3317c478bd9Sstevel@tonic-gate 		if (ul == NULL) {
3327c478bd9Sstevel@tonic-gate 			free(buf);
3337c478bd9Sstevel@tonic-gate 			free(ud_buf);
3347c478bd9Sstevel@tonic-gate 			return (1);
3357c478bd9Sstevel@tonic-gate 		}
3367c478bd9Sstevel@tonic-gate 		ul->un_ondisk = *ud;
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 		/* log state is okay; don't need to check the fs */
3397c478bd9Sstevel@tonic-gate 		if ((ul->un_chksum == ul->un_head_ident + ul->un_tail_ident) &&
3407c478bd9Sstevel@tonic-gate 		    (ul->un_version == LUFS_VERSION_LATEST) &&
341355d6bb5Sswilcox 		    (ul->un_badlog == 0) && (!badlog)) {
3427c478bd9Sstevel@tonic-gate 			++islogok;
343355d6bb5Sswilcox 		}
3447c478bd9Sstevel@tonic-gate 		free(ud_buf);
3457c478bd9Sstevel@tonic-gate 		free(buf);
3467c478bd9Sstevel@tonic-gate 		free(ul);
3477c478bd9Sstevel@tonic-gate 	}
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	return (1);
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate 
352355d6bb5Sswilcox /*
353355d6bb5Sswilcox  * - given a pathname, determine the pathname to actually check
354355d6bb5Sswilcox  * - if a directory
355355d6bb5Sswilcox  *   - if it is in mnttab, set devstr to the special (block) name
356355d6bb5Sswilcox  *   - if it is in vfstab, set devstr to the special (block) name
357355d6bb5Sswilcox  *   - if it has not been found, bail
358355d6bb5Sswilcox  * - a file is used as-is, clear rflag
359355d6bb5Sswilcox  * - a device is converted to block version (so can search mnttab)
360355d6bb5Sswilcox  */
361355d6bb5Sswilcox static void
derive_devstr(const caddr_t dev,caddr_t devstr,size_t str_size)362355d6bb5Sswilcox derive_devstr(const caddr_t dev, caddr_t devstr, size_t str_size)
3637c478bd9Sstevel@tonic-gate {
364355d6bb5Sswilcox 	mode_t mode;
365355d6bb5Sswilcox 	struct stat statb;
3667c478bd9Sstevel@tonic-gate 
367355d6bb5Sswilcox 	if (stat(dev, &statb) < 0) {
368355d6bb5Sswilcox 		exitstat = EXNOSTAT;
369355d6bb5Sswilcox 		errexit("fsck: could not stat %s: %s", dev, strerror(errno));
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 
372355d6bb5Sswilcox 	mode = statb.st_mode & S_IFMT;
373355d6bb5Sswilcox 	switch (mode) {
374355d6bb5Sswilcox 	case S_IFDIR:
3757c478bd9Sstevel@tonic-gate 		/*
376355d6bb5Sswilcox 		 * The check_*() routines update devstr with the name.
3777c478bd9Sstevel@tonic-gate 		 */
378355d6bb5Sswilcox 		devstr[0] = '\0';
379355d6bb5Sswilcox 		if (!(check_mnttab(dev, devstr, str_size) ||
380355d6bb5Sswilcox 		    check_vfstab(dev, devstr, str_size))) {
381355d6bb5Sswilcox 			exitstat = EXBADPARM;
382355d6bb5Sswilcox 			errexit(
383355d6bb5Sswilcox 		    "fsck: could not find mountpoint %s in mnttab nor vfstab",
384355d6bb5Sswilcox 			    dev);
3857c478bd9Sstevel@tonic-gate 		}
386355d6bb5Sswilcox 		break;
387355d6bb5Sswilcox 	case S_IFREG:
3887c478bd9Sstevel@tonic-gate 		rflag = 0;
3895b4dc236Smishra 		(void) strlcpy(devstr, dev, str_size);
390355d6bb5Sswilcox 		break;
391355d6bb5Sswilcox 	case S_IFCHR:
392355d6bb5Sswilcox 	case S_IFBLK:
393355d6bb5Sswilcox 		(void) strlcpy(devstr, unrawname(dev), str_size);
394355d6bb5Sswilcox 		break;
395355d6bb5Sswilcox 	default:
396355d6bb5Sswilcox 		exitstat = EXBADPARM;
397355d6bb5Sswilcox 		errexit("fsck: %s must be a mountpoint, device, or file", dev);
398355d6bb5Sswilcox 		/* NOTREACHED */
3997c478bd9Sstevel@tonic-gate 	}
400355d6bb5Sswilcox }
4017c478bd9Sstevel@tonic-gate 
402355d6bb5Sswilcox /*
403355d6bb5Sswilcox  * Reports the index of the magic filesystem that mntp names.
404355d6bb5Sswilcox  * If it does not correspond any of them, returns zero (hence
405355d6bb5Sswilcox  * the backwards loop).
406355d6bb5Sswilcox  */
407355d6bb5Sswilcox static int
which_corefs(const caddr_t mntp)408355d6bb5Sswilcox which_corefs(const caddr_t mntp)
409355d6bb5Sswilcox {
410355d6bb5Sswilcox 	int corefs;
411355d6bb5Sswilcox 
412355d6bb5Sswilcox 	for (corefs = MAGIC_LIMIT - 1; corefs > 0; corefs--)
413355d6bb5Sswilcox 		if (strcmp(mntp, magic_fs[corefs]) == 0)
414355d6bb5Sswilcox 			break;
415355d6bb5Sswilcox 
416355d6bb5Sswilcox 	return (corefs);
417355d6bb5Sswilcox }
418355d6bb5Sswilcox 
419355d6bb5Sswilcox /*
420355d6bb5Sswilcox  * - set mount_point to NULL
421355d6bb5Sswilcox  * - if name is mounted (search mnttab)
422355d6bb5Sswilcox  *   - if it is a device, clear rflag
423355d6bb5Sswilcox  *   - if mounted on /, /usr, or /var, set corefs
424355d6bb5Sswilcox  *   - if corefs and read-only, set hotroot and continue
425355d6bb5Sswilcox  *   - if errorlocked, continue
426355d6bb5Sswilcox  *   - if preening, bail
427355d6bb5Sswilcox  *   - ask user whether to continue, bail if not
428355d6bb5Sswilcox  * - if it is a device and not mounted and rflag, convert
429355d6bb5Sswilcox  *   name to raw version
430355d6bb5Sswilcox  */
431355d6bb5Sswilcox static int
check_mount_state(caddr_t devstr,size_t str_size)432355d6bb5Sswilcox check_mount_state(caddr_t devstr, size_t str_size)
433355d6bb5Sswilcox {
434355d6bb5Sswilcox 	int corefs = 0;
435355d6bb5Sswilcox 	int is_dev = 0;
436355d6bb5Sswilcox 	struct stat statb;
437355d6bb5Sswilcox 
438355d6bb5Sswilcox 	if (stat(devstr, &statb) < 0) {
439355d6bb5Sswilcox 		exitstat = EXNOSTAT;
440355d6bb5Sswilcox 		errexit("fsck: could not stat %s: %s", devstr, strerror(errno));
4417c478bd9Sstevel@tonic-gate 	}
442355d6bb5Sswilcox 	if (S_ISCHR(statb.st_mode) || S_ISBLK(statb.st_mode))
443355d6bb5Sswilcox 		is_dev = 1;
444355d6bb5Sswilcox 
445355d6bb5Sswilcox 	/*
446355d6bb5Sswilcox 	 * mounted() will update mount_point when returning true.
447355d6bb5Sswilcox 	 */
448355d6bb5Sswilcox 	mount_point = NULL;
449355d6bb5Sswilcox 	if ((mountedfs = mounted(devstr, devstr, str_size)) != M_NOMNT) {
450355d6bb5Sswilcox 		if (is_dev)
451355d6bb5Sswilcox 			rflag = 0;
452355d6bb5Sswilcox 		corefs = which_corefs(mount_point);
453355d6bb5Sswilcox 		if (corefs && (mountedfs == M_RO)) {
454355d6bb5Sswilcox 			hotroot++;
455355d6bb5Sswilcox 		} else if (errorlocked) {
456355d6bb5Sswilcox 			goto carry_on;
457355d6bb5Sswilcox 		} else if (preen) {
458355d6bb5Sswilcox 			exitstat = EXMOUNTED;
459355d6bb5Sswilcox 			pfatal("%s IS CURRENTLY MOUNTED%s.",
460355d6bb5Sswilcox 			    devstr, mountedfs == M_RW ? " READ/WRITE" : "");
461355d6bb5Sswilcox 		} else {
4625b4dc236Smishra 			if (!nflag && !mflag) {
463504a199eSswilcox 				pwarn("%s IS CURRENTLY MOUNTED READ/%s.",
464504a199eSswilcox 				    devstr, mountedfs == M_RW ? "WRITE" :
465504a199eSswilcox 				    "ONLY");
466504a199eSswilcox 				if (reply("CONTINUE") == 0) {
467504a199eSswilcox 					exitstat = EXMOUNTED;
468504a199eSswilcox 					errexit("Program terminated");
469504a199eSswilcox 				}
470355d6bb5Sswilcox 			}
4717c478bd9Sstevel@tonic-gate 		}
472355d6bb5Sswilcox 	} else if (is_dev && rflag) {
473355d6bb5Sswilcox 		(void) strlcpy(devstr, rawname(devstr), str_size);
4747c478bd9Sstevel@tonic-gate 	}
475355d6bb5Sswilcox 
476355d6bb5Sswilcox carry_on:
477355d6bb5Sswilcox 	return (corefs);
478355d6bb5Sswilcox }
479355d6bb5Sswilcox 
480355d6bb5Sswilcox static int
open_and_intro(caddr_t devstr,int corefs)481355d6bb5Sswilcox open_and_intro(caddr_t devstr, int corefs)
482355d6bb5Sswilcox {
483355d6bb5Sswilcox 	int retval = 0;
484355d6bb5Sswilcox 
4857c478bd9Sstevel@tonic-gate 	if ((fsreadfd = open64(devstr, O_RDONLY)) < 0) {
486355d6bb5Sswilcox 		(void) printf("Can't open %s: %s\n", devstr, strerror(errno));
487355d6bb5Sswilcox 		exitstat = EXNOSTAT;
488355d6bb5Sswilcox 		retval = -1;
489355d6bb5Sswilcox 		goto finish;
4907c478bd9Sstevel@tonic-gate 	}
491355d6bb5Sswilcox 	if (!preen || debug != 0)
492355d6bb5Sswilcox 		(void) printf("** %s", devstr);
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	if (errorlocked) {
495355d6bb5Sswilcox 		if (debug && elock_combuf != NULL)
496355d6bb5Sswilcox 			(void) printf(" error-lock comment: \"%s\" ",
497355d6bb5Sswilcox 			    elock_combuf);
4987c478bd9Sstevel@tonic-gate 		fflag = 1;
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 	pid = getpid();
501355d6bb5Sswilcox 	if (nflag || roflag || (fswritefd = open64(devstr, O_WRONLY)) < 0) {
5027c478bd9Sstevel@tonic-gate 		fswritefd = -1;
5037c478bd9Sstevel@tonic-gate 		if (preen && !debug)
5047c478bd9Sstevel@tonic-gate 			pfatal("(NO WRITE ACCESS)\n");
505355d6bb5Sswilcox 		(void) printf(" (NO WRITE)");
5067c478bd9Sstevel@tonic-gate 	}
507355d6bb5Sswilcox 	if (!preen)
508355d6bb5Sswilcox 		(void) printf("\n");
5097c478bd9Sstevel@tonic-gate 	else if (debug)
510355d6bb5Sswilcox 		(void) printf(" pid %d\n", pid);
511355d6bb5Sswilcox 	if (debug && (hotroot || (mountedfs != M_NOMNT))) {
512355d6bb5Sswilcox 		(void) printf("** %s", devstr);
5137c478bd9Sstevel@tonic-gate 		if (hotroot)
514355d6bb5Sswilcox 			(void) printf(" is %s fs", magic_fs[corefs]);
515355d6bb5Sswilcox 		if (mountedfs != M_NOMNT)
516355d6bb5Sswilcox 			(void) printf(" and is mounted read-%s",
517355d6bb5Sswilcox 			    (mountedfs == M_RO) ? "only" : "write");
5187c478bd9Sstevel@tonic-gate 		if (errorlocked)
519355d6bb5Sswilcox 			(void) printf(" and is error-locked");
5207c478bd9Sstevel@tonic-gate 
521355d6bb5Sswilcox 		(void) printf(".\n");
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 
524355d6bb5Sswilcox finish:
525355d6bb5Sswilcox 	return (retval);
526355d6bb5Sswilcox }
5277c478bd9Sstevel@tonic-gate 
528355d6bb5Sswilcox static int
find_superblock(caddr_t devstr)529355d6bb5Sswilcox find_superblock(caddr_t devstr)
530355d6bb5Sswilcox {
531355d6bb5Sswilcox 	int cg = 0;
532355d6bb5Sswilcox 	int retval = 0;
533355d6bb5Sswilcox 	int first;
534355d6bb5Sswilcox 	int found;
535355d6bb5Sswilcox 	calcsb_t style;
536355d6bb5Sswilcox 	struct fs proto;
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	/*
539355d6bb5Sswilcox 	 * Check the superblock, looking for alternates if necessary.
540355d6bb5Sswilcox 	 * In more-recent times, some UFS instances get created with
541355d6bb5Sswilcox 	 * only the first ten and last ten superblock backups.  Since
542355d6bb5Sswilcox 	 * if we can't get the necessary information from any of those,
543355d6bb5Sswilcox 	 * the odds are also against us for the ones in between, we'll
544355d6bb5Sswilcox 	 * just look at those twenty to save time.
5457c478bd9Sstevel@tonic-gate 	 */
546355d6bb5Sswilcox 	if (!read_super_block(1) || !checksb(1)) {
547355d6bb5Sswilcox 		if (bflag || preen) {
548355d6bb5Sswilcox 			retval = -1;
549355d6bb5Sswilcox 			goto finish;
550355d6bb5Sswilcox 		}
551355d6bb5Sswilcox 		for (style = MKFS_STYLE; style < MAX_SB_STYLES; style++) {
552355d6bb5Sswilcox 			if (reply("LOOK FOR ALTERNATE SUPERBLOCKS WITH %s",
553355d6bb5Sswilcox 			    calcsb_names[style]) == 0)
554355d6bb5Sswilcox 				continue;
555355d6bb5Sswilcox 			first = 1;
556355d6bb5Sswilcox 			found = 0;
557355d6bb5Sswilcox 			if (!calcsb(style, devstr, fsreadfd, &proto)) {
558355d6bb5Sswilcox 				cg = proto.fs_ncg;
559355d6bb5Sswilcox 				continue;
560355d6bb5Sswilcox 			}
561355d6bb5Sswilcox 			if (debug) {
562355d6bb5Sswilcox 				(void) printf(
563355d6bb5Sswilcox 			    "debug: calcsb(%s) gave fpg %d, cgoffset %d, ",
564355d6bb5Sswilcox 				    calcsb_names[style],
565355d6bb5Sswilcox 				    proto.fs_fpg, proto.fs_cgoffset);
566355d6bb5Sswilcox 				(void) printf("cgmask 0x%x, sblk %d, ncg %d\n",
567355d6bb5Sswilcox 				    proto.fs_cgmask, proto.fs_sblkno,
568355d6bb5Sswilcox 				    proto.fs_ncg);
569355d6bb5Sswilcox 			}
570