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 */
7bfbf29e2SToomas Soome /* 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
86bfbf29e2SToomas Soome fsck_ino_t lfdir;
87bfbf29e2SToomas Soome int64_t numacls, aclmax, aclplast;
88bfbf29e2SToomas Soome int64_t numdirs, listmax, inplast;
89bfbf29e2SToomas Soome char havesb;
90bfbf29e2SToomas Soome int fsreadfd;
91bfbf29e2SToomas Soome int isdirty;
92bfbf29e2SToomas Soome int pid;
93bfbf29e2SToomas Soome int secsize;
94bfbf29e2SToomas Soome size_t dev_bsize;
95bfbf29e2SToomas Soome struct bufarea sblk;
96bfbf29e2SToomas Soome static struct bufarea asblk; /* alternate superblock */
97bfbf29e2SToomas Soome struct inoinfo **inphead, **inpsort;
98355d6bb5Sswilcox struct shadowclientinfo *shadowclientinfo = NULL;
99355d6bb5Sswilcox struct shadowclientinfo *attrclientinfo = NULL;
100355d6bb5Sswilcox int maxshadowclients = 1024; /* allocation size, not limit */
101355d6bb5Sswilcox
102355d6bb5Sswilcox static void badsb(int, caddr_t);
103355d6bb5Sswilcox static int calcsb(calcsb_t, caddr_t, int, struct fs *);
104355d6bb5Sswilcox static int checksb(int);
105355d6bb5Sswilcox static void flush_fs(void);
106355d6bb5Sswilcox static void sblock_init(void);
107355d6bb5Sswilcox static void uncreate_maps(void);
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate static int
read_super_block(int listerr)110355d6bb5Sswilcox read_super_block(int listerr)
1117c478bd9Sstevel@tonic-gate {
1127c478bd9Sstevel@tonic-gate int fd;
113355d6bb5Sswilcox caddr_t err;
1147c478bd9Sstevel@tonic-gate
115355d6bb5Sswilcox if (mount_point != NULL) {
1167c478bd9Sstevel@tonic-gate fd = open(mount_point, O_RDONLY);
1177c478bd9Sstevel@tonic-gate if (fd == -1) {
118355d6bb5Sswilcox errexit("fsck: open mount point error: %s",
119355d6bb5Sswilcox strerror(errno));
120355d6bb5Sswilcox /* NOTREACHED */
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate /* get the latest super block */
1237c478bd9Sstevel@tonic-gate if (ioctl(fd, _FIOGETSUPERBLOCK, &sblock)) {
124355d6bb5Sswilcox errexit("fsck: ioctl _FIOGETSUPERBLOCK error: %s",
125355d6bb5Sswilcox strerror(errno));
126355d6bb5Sswilcox /* NOTREACHED */
1277c478bd9Sstevel@tonic-gate }
128355d6bb5Sswilcox (void) close(fd);
1297c478bd9Sstevel@tonic-gate } else {
130355d6bb5Sswilcox (void) fsck_bread(fsreadfd, (caddr_t)&sblock,
1317c478bd9Sstevel@tonic-gate bflag != 0 ? (diskaddr_t)bflag : (diskaddr_t)SBLOCK,
132355d6bb5Sswilcox SBSIZE);
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate /*
136355d6bb5Sswilcox * Don't let trash from the disk trip us up later
137355d6bb5Sswilcox * in ungetsummaryinfo().
138355d6bb5Sswilcox */
139355d6bb5Sswilcox sblock.fs_u.fs_csp = NULL;
140355d6bb5Sswilcox
141355d6bb5Sswilcox /*
142355d6bb5Sswilcox * Rudimentary consistency checks. Can't really call
143355d6bb5Sswilcox * checksb() here, because there may be outstanding
144355d6bb5Sswilcox * deltas that still need to be applied.
1457c478bd9Sstevel@tonic-gate */
1467c478bd9Sstevel@tonic-gate if ((sblock.fs_magic != FS_MAGIC) &&
147355d6bb5Sswilcox (sblock.fs_magic != MTB_UFS_MAGIC)) {
148355d6bb5Sswilcox err = "MAGIC NUMBER WRONG";
149355d6bb5Sswilcox goto fail;
1507c478bd9Sstevel@tonic-gate }
1516451fdbcSvsakar if (sblock.fs_magic == FS_MAGIC &&
1526451fdbcSvsakar (sblock.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
1536451fdbcSvsakar sblock.fs_version != UFS_VERSION_MIN)) {
1546451fdbcSvsakar err = "UNRECOGNIZED VERSION";
1556451fdbcSvsakar goto fail;
1566451fdbcSvsakar }
1577c478bd9Sstevel@tonic-gate if (sblock.fs_magic == MTB_UFS_MAGIC &&
1587c478bd9Sstevel@tonic-gate (sblock.fs_version > MTB_UFS_VERSION_1 ||
1597c478bd9Sstevel@tonic-gate sblock.fs_version < MTB_UFS_VERSION_MIN)) {
160355d6bb5Sswilcox err = "UNRECOGNIZED VERSION";
161355d6bb5Sswilcox goto fail;
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate if (sblock.fs_ncg < 1) {
164355d6bb5Sswilcox err = "NCG OUT OF RANGE";
165355d6bb5Sswilcox goto fail;
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate if (sblock.fs_cpg < 1) {
168355d6bb5Sswilcox err = "CPG OUT OF RANGE";
169355d6bb5Sswilcox goto fail;
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
1727c478bd9Sstevel@tonic-gate (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) {
173355d6bb5Sswilcox err = "NCYL IS INCONSISTENT WITH NCG*CPG";
174355d6bb5Sswilcox goto fail;
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate if (sblock.fs_sbsize < 0 || sblock.fs_sbsize > SBSIZE) {
177355d6bb5Sswilcox err = "SIZE OUT OF RANGE";
178355d6bb5Sswilcox goto fail;
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate return (1);
182355d6bb5Sswilcox
183355d6bb5Sswilcox fail:
184355d6bb5Sswilcox badsb(listerr, err);
185355d6bb5Sswilcox return (0);
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate
188355d6bb5Sswilcox static void
flush_fs()1897c478bd9Sstevel@tonic-gate flush_fs()
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate int fd;
1927c478bd9Sstevel@tonic-gate
193355d6bb5Sswilcox if (mount_point != NULL) {
1947c478bd9Sstevel@tonic-gate fd = open(mount_point, O_RDONLY);
1957c478bd9Sstevel@tonic-gate if (fd == -1) {
196355d6bb5Sswilcox errexit("fsck: open mount point error: %s",
197355d6bb5Sswilcox strerror(errno));
198355d6bb5Sswilcox /* NOTREACHED */
1997c478bd9Sstevel@tonic-gate }
2007c478bd9Sstevel@tonic-gate if (ioctl(fd, _FIOFFS, NULL)) { /* flush file system */
201355d6bb5Sswilcox errexit("fsck: ioctl _FIOFFS error: %s",
202355d6bb5Sswilcox strerror(errno));
203355d6bb5Sswilcox /* NOTREACHED */
2047c478bd9Sstevel@tonic-gate }
205355d6bb5Sswilcox (void) close(fd);
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate /*
2107c478bd9Sstevel@tonic-gate * Roll the embedded log, if any, and set up the global variables
211355d6bb5Sswilcox * islog and islogok.
2127c478bd9Sstevel@tonic-gate */
2137c478bd9Sstevel@tonic-gate static int
logsetup(caddr_t devstr)214355d6bb5Sswilcox logsetup(caddr_t devstr)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate void *buf;
2177c478bd9Sstevel@tonic-gate extent_block_t *ebp;
2187c478bd9Sstevel@tonic-gate ml_unit_t *ul;
2197c478bd9Sstevel@tonic-gate ml_odunit_t *ud;
2207c478bd9Sstevel@tonic-gate void *ud_buf;
2217c478bd9Sstevel@tonic-gate int badlog;
2227c478bd9Sstevel@tonic-gate
223355d6bb5Sswilcox islog = islogok = 0;
224355d6bb5Sswilcox if (bflag != 0)
2257c478bd9Sstevel@tonic-gate return (1); /* can't roll log while alternate sb specified */
2267c478bd9Sstevel@tonic-gate
227355d6bb5Sswilcox /*
228355d6bb5Sswilcox * Roll the log, if any. A bad sb implies we'll be using
229355d6bb5Sswilcox * an alternate sb as far as logging goes, so just fail back
230355d6bb5Sswilcox * to the caller if we can't read the default sb. Suppress
231355d6bb5Sswilcox * complaints, because the caller will be reading the same
232355d6bb5Sswilcox * superblock again and running full verification on it, so
233355d6bb5Sswilcox * whatever is bad will be reported then.
234355d6bb5Sswilcox */
2357c478bd9Sstevel@tonic-gate sblock.fs_logbno = 0;
2367c478bd9Sstevel@tonic-gate badlog = 0;
237355d6bb5Sswilcox if (!read_super_block(0))
238355d6bb5Sswilcox return (1);
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate /*
2417c478bd9Sstevel@tonic-gate * Roll the log in 3 cases:
2427c478bd9Sstevel@tonic-gate * 1. If it's unmounted (mount_point == NULL) and it's not marked
2437c478bd9Sstevel@tonic-gate * as fully rolled (sblock.fs_rolled != FS_ALL_ROLLED)
2447c478bd9Sstevel@tonic-gate * 2. If it's mounted and anything other than a sanity
2457c478bd9Sstevel@tonic-gate * check fsck (mflag) is being done, as we have the current
2467c478bd9Sstevel@tonic-gate * super block. Note, only a sanity check is done for
2477c478bd9Sstevel@tonic-gate * root/usr at boot. If a roll were done then the expensive
2487c478bd9Sstevel@tonic-gate * ufs_flush() gets called, leading to a slower boot.
2497c478bd9Sstevel@tonic-gate * 3. If anything other then a sanity check (mflag) is being done
2507c478bd9Sstevel@tonic-gate * to a mounted filesystem while it is in read-only state
2517c478bd9Sstevel@tonic-gate * (e.g. root during early boot stages) we have to detect this
2527c478bd9Sstevel@tonic-gate * and have to roll the log as well. NB. the read-only mount
2537c478bd9Sstevel@tonic-gate * will flip fs_clean from FSLOG to FSSTABLE and marks the
2547c478bd9Sstevel@tonic-gate * log as FS_NEED_ROLL.
2557c478bd9Sstevel@tonic-gate */
2567c478bd9Sstevel@tonic-gate if (sblock.fs_logbno &&
2577c478bd9Sstevel@tonic-gate (((mount_point == NULL) && (sblock.fs_rolled != FS_ALL_ROLLED)) ||
258355d6bb5Sswilcox ((mount_point != NULL) && !mflag))) {
2597c478bd9Sstevel@tonic-gate int roll_log_err = 0;
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate if (sblock.fs_ronly && (sblock.fs_clean == FSSTABLE) &&
2627c478bd9Sstevel@tonic-gate (sblock.fs_state + sblock.fs_time == FSOKAY)) {
2637c478bd9Sstevel@tonic-gate /*
2647c478bd9Sstevel@tonic-gate * roll the log without a mount
2657c478bd9Sstevel@tonic-gate */
2667c478bd9Sstevel@tonic-gate flush_fs();
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate if (sblock.fs_clean == FSLOG &&
2697c478bd9Sstevel@tonic-gate (sblock.fs_state + sblock.fs_time == FSOKAY)) {
2707c478bd9Sstevel@tonic-gate if (rl_roll_log(devstr) != RL_SUCCESS)
2717c478bd9Sstevel@tonic-gate roll_log_err = 1;
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate if (roll_log_err) {
2747c478bd9Sstevel@tonic-gate (void) printf("Can't roll the log for %s.\n", devstr);
2757c478bd9Sstevel@tonic-gate /*
2767c478bd9Sstevel@tonic-gate * There are two cases where we want to set
2777c478bd9Sstevel@tonic-gate * an error code and return:
2787c478bd9Sstevel@tonic-gate * - We're preening
2797c478bd9Sstevel@tonic-gate * - We're not on a live root and the user
2807c478bd9Sstevel@tonic-gate * chose *not* to ignore the log
2817c478bd9Sstevel@tonic-gate * Otherwise, we want to mark the log as bad
2827c478bd9Sstevel@tonic-gate * and continue to check the filesystem. This
2837c478bd9Sstevel@tonic-gate * has the side effect of destroying the log.
2847c478bd9Sstevel@tonic-gate */
2857c478bd9Sstevel@tonic-gate if (preen || (!hotroot &&
2867c478bd9Sstevel@tonic-gate reply(
2877c478bd9Sstevel@tonic-gate "DISCARDING THE LOG MAY DISCARD PENDING TRANSACTIONS.\n"
2887c478bd9Sstevel@tonic-gate "DISCARD THE LOG AND CONTINUE") == 0)) {
289355d6bb5Sswilcox exitstat = EXERRFATAL;
2907c478bd9Sstevel@tonic-gate return (0);
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate ++badlog;
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate
2967c478bd9Sstevel@tonic-gate /* Logging UFS may be enabled */
2977c478bd9Sstevel@tonic-gate if (sblock.fs_logbno) {
2987c478bd9Sstevel@tonic-gate ++islog;
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate /* log is not okay; check the fs */
3017c478bd9Sstevel@tonic-gate if (FSOKAY != (sblock.fs_state + sblock.fs_time))
3027c478bd9Sstevel@tonic-gate return (1);
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate /*
3057c478bd9Sstevel@tonic-gate * If logging or (stable and mounted) then continue
3067c478bd9Sstevel@tonic-gate */
307355d6bb5Sswilcox if (!((sblock.fs_clean == FSLOG) ||
308355d6bb5Sswilcox (sblock.fs_clean == FSSTABLE) && (mount_point != NULL)))
3097c478bd9Sstevel@tonic-gate return (1);
3107c478bd9Sstevel@tonic-gate
3117c478bd9Sstevel@tonic-gate /* get the log allocation block */
312355d6bb5Sswilcox buf = malloc(dev_bsize);
313355d6bb5Sswilcox if (buf == NULL) {
3147c478bd9Sstevel@tonic-gate return (1);
3157c478bd9Sstevel@tonic-gate }
316355d6bb5Sswilcox ud_buf = malloc(dev_bsize);
317355d6bb5Sswilcox if (ud_buf == NULL) {
3187c478bd9Sstevel@tonic-gate free(buf);
3197c478bd9Sstevel@tonic-gate return (1);
3207c478bd9Sstevel@tonic-gate }
321355d6bb5Sswilcox (void) fsck_bread(fsreadfd, buf,
3227c478bd9Sstevel@tonic-gate logbtodb(&sblock, sblock.fs_logbno),
323355d6bb5Sswilcox dev_bsize);
3247c478bd9Sstevel@tonic-gate ebp = (extent_block_t *)buf;
3257c478bd9Sstevel@tonic-gate
3267c478bd9Sstevel@tonic-gate /* log allocation block is not okay; check the fs */
3277c478bd9Sstevel@tonic-gate if (ebp->type != LUFS_EXTENTS) {
3287c478bd9Sstevel@tonic-gate free(buf);
3297c478bd9Sstevel@tonic-gate free(ud_buf);
3307c478bd9Sstevel@tonic-gate return (1);
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate
3337c478bd9Sstevel@tonic-gate /* get the log state block(s) */
334355d6bb5Sswilcox if (fsck_bread(fsreadfd, ud_buf,
3357c478bd9Sstevel@tonic-gate (logbtodb(&sblock, ebp->extents[0].pbno)),
336355d6bb5Sswilcox dev_bsize)) {
337355d6bb5Sswilcox (void) fsck_bread(fsreadfd, ud_buf,
338355d6bb5Sswilcox (logbtodb(&sblock, ebp->extents[0].pbno)) + 1,
339355d6bb5Sswilcox dev_bsize);
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate ud = (ml_odunit_t *)ud_buf;
3427c478bd9Sstevel@tonic-gate ul = (ml_unit_t *)malloc(sizeof (*ul));
3437c478bd9Sstevel@tonic-gate if (ul == NULL) {
3447c478bd9Sstevel@tonic-gate free(buf);
3457c478bd9Sstevel@tonic-gate free(ud_buf);
3467c478bd9Sstevel@tonic-gate return (1);
3477c478bd9Sstevel@tonic-gate }
3487c478bd9Sstevel@tonic-gate ul->un_ondisk = *ud;
3497c478bd9Sstevel@tonic-gate
3507c478bd9Sstevel@tonic-gate /* log state is okay; don't need to check the fs */
3517c478bd9Sstevel@tonic-gate if ((ul->un_chksum == ul->un_head_ident + ul->un_tail_ident) &&
3527c478bd9Sstevel@tonic-gate (ul->un_version == LUFS_VERSION_LATEST) &&
353355d6bb5Sswilcox (ul->un_badlog == 0) && (!badlog)) {
3547c478bd9Sstevel@tonic-gate ++islogok;
355355d6bb5Sswilcox }
3567c478bd9Sstevel@tonic-gate free(ud_buf);
3577c478bd9Sstevel@tonic-gate free(buf);
3587c478bd9Sstevel@tonic-gate free(ul);
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate
3617c478bd9Sstevel@tonic-gate return (1);
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate
364355d6bb5Sswilcox /*
365355d6bb5Sswilcox * - given a pathname, determine the pathname to actually check
366355d6bb5Sswilcox * - if a directory
367355d6bb5Sswilcox * - if it is in mnttab, set devstr to the special (block) name
368355d6bb5Sswilcox * - if it is in vfstab, set devstr to the special (block) name
369355d6bb5Sswilcox * - if it has not been found, bail
370355d6bb5Sswilcox * - a file is used as-is, clear rflag
371355d6bb5Sswilcox * - a device is converted to block version (so can search mnttab)
372355d6bb5Sswilcox */
373355d6bb5Sswilcox static void
derive_devstr(const caddr_t dev,caddr_t devstr,size_t str_size)374355d6bb5Sswilcox derive_devstr(const caddr_t dev, caddr_t devstr, size_t str_size)
3757c478bd9Sstevel@tonic-gate {
376355d6bb5Sswilcox mode_t mode;
377355d6bb5Sswilcox struct stat statb;
3787c478bd9Sstevel@tonic-gate
379355d6bb5Sswilcox if (stat(dev, &statb) < 0) {
380355d6bb5Sswilcox exitstat = EXNOSTAT;
381355d6bb5Sswilcox errexit("fsck: could not stat %s: %s", dev, strerror(errno));
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate
384355d6bb5Sswilcox mode = statb.st_mode & S_IFMT;
385355d6bb5Sswilcox switch (mode) {
386355d6bb5Sswilcox case S_IFDIR:
3877c478bd9Sstevel@tonic-gate /*
388355d6bb5Sswilcox * The check_*() routines update devstr with the name.
3897c478bd9Sstevel@tonic-gate */
390355d6bb5Sswilcox devstr[0] = '\0';
391355d6bb5Sswilcox if (!(check_mnttab(dev, devstr, str_size) ||
392355d6bb5Sswilcox check_vfstab(dev, devstr, str_size))) {
393355d6bb5Sswilcox exitstat = EXBADPARM;
394355d6bb5Sswilcox errexit(
395355d6bb5Sswilcox "fsck: could not find mountpoint %s in mnttab nor vfstab",
396355d6bb5Sswilcox dev);
3977c478bd9Sstevel@tonic-gate }
398355d6bb5Sswilcox break;
399355d6bb5Sswilcox case S_IFREG:
4007c478bd9Sstevel@tonic-gate rflag = 0;
4015b4dc236Smishra (void) strlcpy(devstr, dev, str_size);
402355d6bb5Sswilcox break;
403355d6bb5Sswilcox case S_IFCHR:
404355d6bb5Sswilcox case S_IFBLK:
405355d6bb5Sswilcox (void) strlcpy(devstr, unrawname(dev), str_size);
406355d6bb5Sswilcox break;
407355d6bb5Sswilcox default:
408355d6bb5Sswilcox exitstat = EXBADPARM;
409355d6bb5Sswilcox errexit("fsck: %s must be a mountpoint, device, or file", dev);
410355d6bb5Sswilcox /* NOTREACHED */
4117c478bd9Sstevel@tonic-gate }
412355d6bb5Sswilcox }
4137c478bd9Sstevel@tonic-gate
414355d6bb5Sswilcox /*
415355d6bb5Sswilcox * Reports the index of the magic filesystem that mntp names.
416355d6bb5Sswilcox * If it does not correspond any of them, returns zero (hence
417355d6bb5Sswilcox * the backwards loop).
418355d6bb5Sswilcox */
419355d6bb5Sswilcox static int
which_corefs(const caddr_t mntp)420355d6bb5Sswilcox which_corefs(const caddr_t mntp)
421355d6bb5Sswilcox {
422355d6bb5Sswilcox int corefs;
423355d6bb5Sswilcox
424355d6bb5Sswilcox for (corefs = MAGIC_LIMIT - 1; corefs > 0; corefs--)
425355d6bb5Sswilcox if (strcmp(mntp, magic_fs[corefs]) == 0)
426355d6bb5Sswilcox break;
427355d6bb5Sswilcox
428355d6bb5Sswilcox return (corefs);
429355d6bb5Sswilcox }
430355d6bb5Sswilcox
431355d6bb5Sswilcox /*
432355d6bb5Sswilcox * - set mount_point to NULL
433355d6bb5Sswilcox * - if name is mounted (search mnttab)
434355d6bb5Sswilcox * - if it is a device, clear rflag
435355d6bb5Sswilcox * - if mounted on /, /usr, or /var, set corefs
436355d6bb5Sswilcox * - if corefs and read-only, set hotroot and continue
437355d6bb5Sswilcox * - if errorlocked, continue
438355d6bb5Sswilcox * - if preening, bail
439355d6bb5Sswilcox * - ask user whether to continue, bail if not
440355d6bb5Sswilcox * - if it is a device and not mounted and rflag, convert
441355d6bb5Sswilcox * name to raw version
442355d6bb5Sswilcox */
443355d6bb5Sswilcox static int
check_mount_state(caddr_t devstr,size_t str_size)444355d6bb5Sswilcox check_mount_state(caddr_t devstr, size_t str_size)
445355d6bb5Sswilcox {
446355d6bb5Sswilcox int corefs = 0;
447355d6bb5Sswilcox int is_dev = 0;
448355d6bb5Sswilcox struct stat statb;
449355d6bb5Sswilcox
450355d6bb5Sswilcox if (stat(devstr, &statb) < 0) {
451355d6bb5Sswilcox exitstat = EXNOSTAT;
452355d6bb5Sswilcox errexit("fsck: could not stat %s: %s", devstr, strerror(errno));
4537c478bd9Sstevel@tonic-gate }
454355d6bb5Sswilcox if (S_ISCHR(statb.st_mode) || S_ISBLK(statb.st_mode))
455355d6bb5Sswilcox is_dev = 1;
456355d6bb5Sswilcox
457355d6bb5Sswilcox /*
458355d6bb5Sswilcox * mounted() will update mount_point when returning true.
459355d6bb5Sswilcox */
460355d6bb5Sswilcox mount_point = NULL;
461355d6bb5Sswilcox if ((mountedfs = mounted(devstr, devstr, str_size)) != M_NOMNT) {
462355d6bb5Sswilcox if (is_dev)
463355d6bb5Sswilcox rflag = 0;
464355d6bb5Sswilcox corefs = which_corefs(mount_point);
465355d6bb5Sswilcox if (corefs && (mountedfs == M_RO)) {
466355d6bb5Sswilcox hotroot++;
467355d6bb5Sswilcox } else if (errorlocked) {
468355d6bb5Sswilcox goto carry_on;
469355d6bb5Sswilcox } else if (preen) {
470355d6bb5Sswilcox exitstat = EXMOUNTED;
471355d6bb5Sswilcox pfatal("%s IS CURRENTLY MOUNTED%s.",
472355d6bb5Sswilcox devstr, mountedfs == M_RW ? " READ/WRITE" : "");
473355d6bb5Sswilcox } else {
4745b4dc236Smishra if (!nflag && !mflag) {
475504a199eSswilcox pwarn("%s IS CURRENTLY MOUNTED READ/%s.",
476504a199eSswilcox devstr, mountedfs == M_RW ? "WRITE" :
477504a199eSswilcox "ONLY");
478504a199eSswilcox if (reply("CONTINUE") == 0) {
479504a199eSswilcox exitstat = EXMOUNTED;
480504a199eSswilcox errexit("Program terminated");
481504a199eSswilcox }
482355d6bb5Sswilcox }
4837c478bd9Sstevel@tonic-gate }
484355d6bb5Sswilcox } else if (is_dev && rflag) {
485355d6bb5Sswilcox (void) strlcpy(devstr, rawname(devstr), str_size);
4867c478bd9Sstevel@tonic-gate }
487355d6bb5Sswilcox
488355d6bb5Sswilcox carry_on:
489355d6bb5Sswilcox return (corefs);
490355d6bb5Sswilcox }
491355d6bb5Sswilcox
492355d6bb5Sswilcox static int
open_and_intro(caddr_t devstr,int corefs)493355d6bb5Sswilcox open_and_intro(caddr_t devstr, int corefs)
494355d6bb5Sswilcox {
495355d6bb5Sswilcox int retval = 0;
496355d6bb5Sswilcox
4977c478bd9Sstevel@tonic-gate if ((fsreadfd = open64(devstr, O_RDONLY)) < 0) {
498355d6bb5Sswilcox (void) printf("Can't open %s: %s\n", devstr, strerror(errno));
499355d6bb5Sswilcox exitstat = EXNOSTAT;
500355d6bb5Sswilcox retval = -1;
501355d6bb5Sswilcox goto finish;
5027c478bd9Sstevel@tonic-gate }
503355d6bb5Sswilcox if (!preen || debug != 0)
504355d6bb5Sswilcox (void) printf("** %s", devstr);
5057c478bd9Sstevel@tonic-gate
5067c478bd9Sstevel@tonic-gate if (errorlocked) {
507355d6bb5Sswilcox if (debug && elock_combuf != NULL)
508355d6bb5Sswilcox (void) printf(" error-lock comment: \"%s\" ",
509355d6bb5Sswilcox elock_combuf);
5107c478bd9Sstevel@tonic-gate fflag = 1;
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate pid = getpid();
513bfbf29e2SToomas Soome if (nflag || (fswritefd = open64(devstr, O_WRONLY)) < 0) {
5147c478bd9Sstevel@tonic-gate fswritefd = -1;
5157c478bd9Sstevel@tonic-gate if (preen && !debug)
5167c478bd9Sstevel@tonic-gate pfatal("(NO WRITE ACCESS)\n");
517355d6bb5Sswilcox (void) printf(" (NO WRITE)");
5187c478bd9Sstevel@tonic-gate }
519355d6bb5Sswilcox if (!preen)
520355d6bb5Sswilcox (void) printf("\n");
5217c478bd9Sstevel@tonic-gate else if (debug)
522355d6bb5Sswilcox (void) printf(" pid %d\n", pid);
523355d6bb5Sswilcox if (debug && (hotroot || (mountedfs != M_NOMNT))) {
524355d6bb5Sswilcox (void) printf("** %s", devstr);
5257c478bd9Sstevel@tonic-gate if (hotroot)
526355d6bb5Sswilcox (void) printf(" is %s fs", magic_fs[corefs]);
527355d6bb5Sswilcox if (mountedfs != M_NOMNT)
528355d6bb5Sswilcox (void) printf(" and is mounted read-%s",
529355d6bb5Sswilcox (mountedfs == M_RO) ? "only" : "write");
5307c478bd9Sstevel@tonic-gate if (errorlocked)
531355d6bb5Sswilcox (void) printf(" and is error-locked");
5327c478bd9Sstevel@tonic-gate
533355d6bb5Sswilcox (void) printf(".\n");
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate
536355d6bb5Sswilcox finish:
537355d6bb5Sswilcox return (retval);
538355d6bb5Sswilcox }
5397c478bd9Sstevel@tonic-gate
540355d6bb5Sswilcox static int
find_superblock(caddr_t devstr)541355d6bb5Sswilcox find_superblock(caddr_t devstr)
542355d6bb5Sswilcox {
543355d6bb5Sswilcox int cg = 0;
544355d6bb5Sswilcox int retval = 0;
545355d6bb5Sswilcox int first;
546355d6bb5Sswilcox int found;
547355d6bb5Sswilcox calcsb_t style;
548355d6bb5Sswilcox struct fs proto;
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate /*
551355d6bb5Sswilcox * Check the superblock, looking for alternates if necessary.
552355d6bb5Sswilcox * In more-recent times, some UFS instances get created with
553355d6bb5Sswilcox * only the first ten and last ten superblock backups. Since
554355d6bb5Sswilcox * if we can't get the necessary information from any of those,
555355d6bb5Sswilcox * the odds are also against us for the ones in between, we'll
556355d6bb5Sswilcox * just look at those twenty to save time.
5577c478bd9Sstevel@tonic-gate */
558355d6bb5Sswilcox if (!read_super_block(1) || !checksb(1)) {
559355d6bb5Sswilcox if (bflag || preen) {
560355d6bb5Sswilcox retval = -1;
561355d6bb5Sswilcox goto finish;
562355d6bb5Sswilcox }
563355d6bb5Sswilcox for (style = MKFS_STYLE; style < MAX_SB_STYLES; style++) {
564355d6bb5Sswilcox if (reply("LOOK FOR ALTERNATE SUPERBLOCKS WITH %s",
565355d6bb5Sswilcox calcsb_names[style]) == 0)
566355d6bb5Sswilcox continue;
567355d6bb5Sswilcox first = 1;
568355d6bb5Sswilcox found = 0;
569355d6bb5Sswilcox if (!calcsb(style, devstr, fsreadfd, &proto)) {
570355d6bb5Sswilcox cg = proto.fs_ncg;
571355d6bb5Sswilcox continue;
572355d6bb5Sswilcox }
573355d6bb5Sswilcox if (debug) {
574355d6bb5Sswilcox (void) printf(
575355d6bb5Sswilcox "debug: calcsb(%s) gave fpg %d, cgoffset %d, ",
576355d6bb5Sswilcox calcsb_names[style],
577355d6bb5Sswilcox proto.fs_fpg, proto.fs_cgoffset);
578355d6bb5Sswilcox (void) printf("cgmask 0x%x, sblk %d, ncg %d\n",
579355d6bb5Sswilcox proto.fs_cgmask, proto.fs_sblkno,
580355d6bb5Sswilcox proto.fs_ncg);
581355d6bb5Sswilcox }
582355d6bb5Sswilcox for (cg = 0; cg < proto.fs_ncg; cg++) {
583355d6bb5Sswilcox bflag = fsbtodb(&proto, cgsblock(&proto, cg));
584355d6bb5Sswilcox if (debug)
585355d6bb5Sswilcox (void) printf(
586355d6bb5Sswilcox "debug: trying block %lld\n",
587355d6bb5Sswilcox (longlong_t)bflag);
588355d6bb5Sswilcox if (read_super_block(0) && checksb(0)) {
589355d6bb5Sswilcox (void) printf(
590355d6bb5Sswilcox "FOUND ALTERNATE SUPERBLOCK %d WITH %s\n",
591355d6bb5Sswilcox bflag, calcsb_names[style]);
592355d6bb5Sswilcox if (reply(
593355d6bb5Sswilcox "USE ALTERNATE SUPERBLOCK") == 1) {
594355d6bb5Sswilcox found = 1;
595355d6bb5Sswilcox break;
596355d6bb5Sswilcox }
597355d6bb5Sswilcox }
598355d6bb5Sswilcox if (first && (cg >= 9)) {
599355d6bb5Sswilcox first = 0;
600355d6bb5Sswilcox if (proto.fs_ncg <= 9)
601355d6bb5Sswilcox cg = proto.fs_ncg;
602355d6bb5Sswilcox else if (proto.fs_ncg <= 19)
603355d6bb5Sswilcox cg = 9;
604355d6bb5Sswilcox else
605355d6bb5Sswilcox cg = proto.fs_ncg - 10;
606355d6bb5Sswilcox }
607355d6bb5Sswilcox }
608355d6bb5Sswilcox
609355d6bb5Sswilcox if (found)
610355d6bb5Sswilcox break;
611355d6bb5Sswilcox }
612355d6bb5Sswilcox
613355d6bb5Sswilcox /*
614355d6bb5Sswilcox * Didn't find one? Try to fake it.
615355d6bb5Sswilcox */
616355d6bb5Sswilcox if (style >= MAX_SB_STYLES) {
617355d6bb5Sswilcox pwarn("SEARCH FOR ALTERNATE SUPERBLOCKS FAILED.\n");
618355d6bb5Sswilcox for (style = MKFS_STYLE; style < MAX_SB_STYLES;
619355d6bb5Sswilcox style++) {
620355d6bb5Sswilcox if (reply("USE GENERIC SUPERBLOCK FROM %s",
621355d6bb5Sswilcox calcsb_names[style]) == 1 &&
622355d6bb5Sswilcox calcsb(style, devstr, fsreadfd, &sblock)) {
623355d6bb5Sswilcox break;
624ac34f4ddSToomas Soome }
625355d6bb5Sswilcox }
626355d6bb5Sswilcox /*
627355d6bb5Sswilcox * We got something from mkfs/newfs, so use it.
628355d6bb5Sswilcox */
629ac34f4ddSToomas Soome if (style < MAX_SB_STYLES) {
630355d6bb5Sswilcox proto.fs_ncg = sblock.fs_ncg;
631355d6bb5Sswilcox bflag = 0;
632355d6bb5Sswilcox }
633355d6bb5Sswilcox }
634355d6bb5Sswilcox
635355d6bb5Sswilcox /*
636355d6bb5Sswilcox * Still no luck? Tell the user they're on their own.
637355d6bb5Sswilcox */
638355d6bb5Sswilcox if (style >= MAX_SB_STYLES) {
639355d6bb5Sswilcox pwarn("SEARCH FOR ALTERNATE SUPERBLOCKS FAILED. "
640355d6bb5Sswilcox "YOU MUST USE THE -o b OPTION\n"
641355d6bb5Sswilcox "TO FSCK TO SPECIFY THE LOCATION OF A VALID "
642355d6bb5Sswilcox "ALTERNATE SUPERBLOCK TO\n"
643*bbf21555SRichard Lowe "SUPPLY NEEDED INFORMATION; SEE fsck(8).\n");
644355d6bb5Sswilcox bflag = 0;
645355d6bb5Sswilcox retval = -1;
646355d6bb5Sswilcox goto finish;
647355d6bb5Sswilcox }
648355d6bb5Sswilcox
649355d6bb5Sswilcox /*
650355d6bb5Sswilcox * Need to make sure a human really wants us to use
651355d6bb5Sswilcox * this. -y mode could've gotten us this far, so
652355d6bb5Sswilcox * we need to ask something that has to be answered
653355d6bb5Sswilcox * in the negative.
654355d6bb5Sswilcox *
655355d6bb5Sswilcox * Note that we can't get here when preening.
656355d6bb5Sswilcox */
657355d6bb5Sswilcox if (!found) {
658355d6bb5Sswilcox pwarn("CALCULATED GENERIC SUPERBLOCK WITH %s\n",
659355d6bb5Sswilcox calcsb_names[style]);
660355d6bb5Sswilcox } else {
661355d6bb5Sswilcox pwarn("FOUND ALTERNATE SUPERBLOCK AT %d USING %s\n",
662355d6bb5Sswilcox bflag, calcsb_names[style]);
663355d6bb5Sswilcox }
664355d6bb5Sswilcox pwarn("If filesystem was created with manually-specified ");
665355d6bb5Sswilcox pwarn("geometry, using\nauto-discovered superblock may ");
666355d6bb5Sswilcox pwarn("result in irrecoverable damage to\nfilesystem and ");
667355d6bb5Sswilcox pwarn("user data.\n");
668355d6bb5Sswilcox if (reply("CANCEL FILESYSTEM CHECK") == 1) {
669355d6bb5Sswilcox if (cg >= 0) {
670355d6bb5Sswilcox pwarn("Please verify that the indicated block "
671355d6bb5Sswilcox "contains a proper\nsuperblock for the "
672*bbf21555SRichard Lowe "filesystem (see fsdb(8)).\n");
673355d6bb5Sswilcox if (yflag)
674355d6bb5Sswilcox pwarn("\nFSCK was running in YES "
675355d6bb5Sswilcox "mode. If you wish to run in "
676355d6bb5Sswilcox "that mode using\nthe alternate "
677355d6bb5Sswilcox "superblock, run "
678355d6bb5Sswilcox "`fsck -y -o b=%d %s'.\n",
679355d6bb5Sswilcox bflag, devstr);
680355d6bb5Sswilcox }
681355d6bb5Sswilcox retval = -1;
682355d6bb5Sswilcox goto finish;
683355d6bb5Sswilcox }
684355d6bb5Sswilcox
685355d6bb5Sswilcox /*
686355d6bb5Sswilcox * Pretend we found it as an alternate, so everything
687355d6bb5Sswilcox * gets updated when we clean up at the end.
688355d6bb5Sswilcox */
689355d6bb5Sswilcox if (!found) {
690355d6bb5Sswilcox havesb = 1;
691355d6bb5Sswilcox sblk.b_bno = fsbtodb(&sblock, cgsblock(&sblock, 0));
692355d6bb5Sswilcox bwrite(fswritefd, (caddr_t)&sblock, SBLOCK, SBSIZE);
693355d6bb5Sswilcox write_altsb(fswritefd);
694355d6bb5Sswilcox }
695355d6bb5Sswilcox }
696355d6bb5Sswilcox
697355d6bb5Sswilcox finish:
698355d6bb5Sswilcox return (retval);
699355d6bb5Sswilcox }
700355d6bb5Sswilcox
701355d6bb5Sswilcox /*
702355d6bb5Sswilcox * Check and potentially fix certain fields in the super block.
703355d6bb5Sswilcox */
704355d6bb5Sswilcox static void
fixup_superblock(void)705355d6bb5Sswilcox fixup_superblock(void)
706355d6bb5Sswilcox {
7077c478bd9Sstevel@tonic-gate /*
708355d6bb5Sswilcox * Kernel looks for FS_OPTTIME, and assumes that if that's not
709355d6bb5Sswilcox * what's there, it must be FS_OPTSPACE, so not fixing does not
710355d6bb5Sswilcox * require setting iscorrupt.
7117c478bd9Sstevel@tonic-gate */
7127c478bd9Sstevel@tonic-gate if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) {
7137c478bd9Sstevel@tonic-gate pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
7147c478bd9Sstevel@tonic-gate if (reply("SET TO DEFAULT") == 1) {
7157c478bd9Sstevel@tonic-gate sblock.fs_optim = FS_OPTTIME;
7167c478bd9Sstevel@tonic-gate sbdirty();
7177c478bd9Sstevel@tonic-gate }
7187c478bd9Sstevel@tonic-gate }
7197c478bd9Sstevel@tonic-gate if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) {
7207c478bd9Sstevel@tonic-gate pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
721355d6bb5Sswilcox sblock.fs_minfree);
7227c478bd9Sstevel@tonic-gate if (reply("SET TO DEFAULT") == 1) {
7237c478bd9Sstevel@tonic-gate sblock.fs_minfree = 10;
7247c478bd9Sstevel@tonic-gate sbdirty();
725355d6bb5Sswilcox } else if (sblock.fs_minfree < 0) {
7267c478bd9Sstevel@tonic-gate /*
727355d6bb5Sswilcox * Kernel uses minfree without verification,
728355d6bb5Sswilcox * and a negative value would do bad things.
7297c478bd9Sstevel@tonic-gate */
730355d6bb5Sswilcox iscorrupt = 1;
7317c478bd9Sstevel@tonic-gate }
7327c478bd9Sstevel@tonic-gate }
733355d6bb5Sswilcox }
734355d6bb5Sswilcox
735355d6bb5Sswilcox static int
initial_error_state_adjust(void)736355d6bb5Sswilcox initial_error_state_adjust(void)
737355d6bb5Sswilcox {
738355d6bb5Sswilcox int retval = 0;
739355d6bb5Sswilcox
740355d6bb5Sswilcox /* do this right away to prevent any other fscks on this fs */
741355d6bb5Sswilcox switch (sblock.fs_clean) {
742355d6bb5Sswilcox case FSBAD:
743355d6bb5Sswilcox break;
744355d6bb5Sswilcox case FSFIX:
745355d6bb5Sswilcox if (preen)
746355d6bb5Sswilcox errexit("ERROR-LOCKED; MARKED \"FSFIX\"\n");
747355d6bb5Sswilcox if (reply("marked FSFIX, CONTINUE") == 0) {
748355d6bb5Sswilcox retval = -1;
749355d6bb5Sswilcox goto finish;
750355d6bb5Sswilcox }
751355d6bb5Sswilcox break;
752355d6bb5Sswilcox case FSCLEAN:
753355d6bb5Sswilcox if (preen)
754355d6bb5Sswilcox errexit("ERROR-LOCKED; MARKED \"FSCLEAN\"\n");
755355d6bb5Sswilcox if (reply("marked FSCLEAN, CONTINUE") == 0) {
756355d6bb5Sswilcox retval = -1;
757355d6bb5Sswilcox goto finish;
758355d6bb5Sswilcox }
759355d6bb5Sswilcox break;
760355d6bb5Sswilcox default:
761355d6bb5Sswilcox if (preen) {
762355d6bb5Sswilcox if (debug)
7637c478bd9Sstevel@tonic-gate pwarn("ERRORLOCKED; NOT MARKED \"FSBAD\"\n");
764355d6bb5Sswilcox else
7657c478bd9Sstevel@tonic-gate errexit("ERRORLOCKED; NOT MARKED \"FSBAD\"\n");
766355d6bb5Sswilcox } else {
767355d6bb5Sswilcox (void) printf("error-locked but not marked \"FSBAD\";");
768355d6bb5Sswilcox if (reply(" CONTINUE") == 0) {
769355d6bb5Sswilcox retval = -1;
770355d6bb5Sswilcox goto finish;
7717c478bd9Sstevel@tonic-gate }
7727c478bd9Sstevel@tonic-gate }
773355d6bb5Sswilcox break;
774355d6bb5Sswilcox }
7757c478bd9Sstevel@tonic-gate
776355d6bb5Sswilcox if (!do_errorlock(LOCKFS_ELOCK)) {
777355d6bb5Sswilcox if (preen) {
778355d6bb5Sswilcox retval = -1;
779355d6bb5Sswilcox goto finish;
780355d6bb5Sswilcox }
781355d6bb5Sswilcox if (reply("error-lock reset failed; CONTINUE") == 0) {
782355d6bb5Sswilcox retval = -1;
783355d6bb5Sswilcox goto finish;
7847c478bd9Sstevel@tonic-gate }
7857c478bd9Sstevel@tonic-gate }
786355d6bb5Sswilcox
787355d6bb5Sswilcox sblock.fs_state = FSOKAY - (long)sblock.fs_time;
788355d6bb5Sswilcox sblock.fs_clean = FSFIX;
789355d6bb5Sswilcox sbdirty();
790355d6bb5Sswilcox write_altsb(fswritefd);
791355d6bb5Sswilcox
792355d6bb5Sswilcox finish:
793355d6bb5Sswilcox return (retval);
794355d6bb5Sswilcox }
795355d6bb5Sswilcox
796355d6bb5Sswilcox static void
getsummaryinfo(void)797355d6bb5Sswilcox getsummaryinfo(void)
798355d6bb5Sswilcox {
799355d6bb5Sswilcox size_t size;
800355d6bb5Sswilcox int failed;
801355d6bb5Sswilcox int asked;
802355d6bb5Sswilcox int i, j;
803355d6bb5Sswilcox caddr_t sip;
804355d6bb5Sswilcox
8057c478bd9Sstevel@tonic-gate /*
8067c478bd9Sstevel@tonic-gate * read in the summary info.
8077c478bd9Sstevel@tonic-gate */
808355d6bb5Sswilcox sblock.fs_u.fs_csp = calloc(1, sblock.fs_cssize);
809355d6bb5Sswilcox if (sblock.fs_u.fs_csp == NULL)
810355d6bb5Sswilcox errexit(
811355d6bb5Sswilcox "cannot allocate %u bytes for cylinder group summary info\n",
812355d6bb5Sswilcox (unsigned)sblock.fs_cssize);
813355d6bb5Sswilcox sip = (caddr_t)sblock.fs_u.fs_csp;
814355d6bb5Sswilcox asked = 0;
8157c478bd9Sstevel@tonic-gate for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
8167c478bd9Sstevel@tonic-gate size = sblock.fs_cssize - i < sblock.fs_bsize ?
817355d6bb5Sswilcox sblock.fs_cssize - i : sblock.fs_bsize;
818355d6bb5Sswilcox failed = fsck_bread(fsreadfd, sip,
8197c478bd9Sstevel@tonic-gate fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
820355d6bb5Sswilcox size);
821355d6bb5Sswilcox if (failed && !asked) {
822355d6bb5Sswilcox pfatal("BAD SUMMARY INFORMATION");
823355d6bb5Sswilcox if (reply("CONTINUE") == 0) {
824355d6bb5Sswilcox ckfini();
825355d6bb5Sswilcox exit(EXFNDERRS);
826355d6bb5Sswilcox }
827355d6bb5Sswilcox asked = 1;
828355d6bb5Sswilcox }
8297c478bd9Sstevel@tonic-gate sip += size;
8307c478bd9Sstevel@tonic-gate }
831355d6bb5Sswilcox }
832355d6bb5Sswilcox
833355d6bb5Sswilcox /*
834355d6bb5Sswilcox * Reverses the effects of getsummaryinfo().
835355d6bb5Sswilcox */
836355d6bb5Sswilcox static void
ungetsummaryinfo(void)837355d6bb5Sswilcox ungetsummaryinfo(void)
838355d6bb5Sswilcox {
839355d6bb5Sswilcox if ((sblk.b_un.b_fs != NULL) &&
840355d6bb5Sswilcox (sblk.b_un.b_fs->fs_u.fs_csp != NULL)) {
841355d6bb5Sswilcox free(sblk.b_un.b_fs->fs_u.fs_csp);
842355d6bb5Sswilcox sblk.b_un.b_fs->fs_u.fs_csp = NULL;
8437c478bd9Sstevel@tonic-gate }
844355d6bb5Sswilcox }
845355d6bb5Sswilcox
846355d6bb5Sswilcox /*
847355d6bb5Sswilcox * Allocate and initialize the global tables.
848355d6bb5Sswilcox * It is the responsibility of the caller to clean up and allocations
849355d6bb5Sswilcox * if an error is returned.
850355d6bb5Sswilcox */
851355d6bb5Sswilcox static int
create_and_init_maps(void)852355d6bb5Sswilcox create_and_init_maps(void)
853355d6bb5Sswilcox {
854355d6bb5Sswilcox int64_t bmapsize;
855355d6bb5Sswilcox int retval = 0;
856355d6bb5Sswilcox
857355d6bb5Sswilcox maxfsblock = sblock.fs_size;
858355d6bb5Sswilcox maxino = sblock.fs_ncg * sblock.fs_ipg;
859355d6bb5Sswilcox
8607c478bd9Sstevel@tonic-gate bmapsize = roundup(howmany((uint64_t)maxfsblock, NBBY),
8617c478bd9Sstevel@tonic-gate sizeof (short));
8627c478bd9Sstevel@tonic-gate blockmap = calloc((size_t)bmapsize, sizeof (char));
8637c478bd9Sstevel@tonic-gate if (blockmap == NULL) {
864355d6bb5Sswilcox (void) printf("cannot alloc %lld bytes for blockmap\n",
865355d6bb5Sswilcox (longlong_t)bmapsize);
866355d6bb5Sswilcox retval = -1;
867355d6bb5Sswilcox goto finish;
8687c478bd9Sstevel@tonic-gate }
869355d6bb5Sswilcox statemap = calloc((size_t)(maxino + 1), sizeof (*statemap));
8707c478bd9Sstevel@tonic-gate if (statemap == NULL) {
871355d6bb5Sswilcox (void) printf("cannot alloc %lld bytes for statemap\n",
872355d6bb5Sswilcox (longlong_t)(maxino + 1) * sizeof (*statemap));
873355d6bb5Sswilcox retval = -1;
874355d6bb5Sswilcox goto finish;
8757c478bd9Sstevel@tonic-gate }
876355d6bb5Sswilcox lncntp = (short *)calloc((size_t)(maxino + 1), sizeof (short));
8777c478bd9Sstevel@tonic-gate if (lncntp == NULL) {
878355d6bb5Sswilcox (void) printf("cannot alloc %lld bytes for lncntp\n",
879355d6bb5Sswilcox (longlong_t)(maxino + 1) * sizeof (short));
880355d6bb5Sswilcox retval = -1;
881355d6bb5Sswilcox goto finish;
8827c478bd9Sstevel@tonic-gate }
883355d6bb5Sswilcox
884355d6bb5Sswilcox /*
885355d6bb5Sswilcox * If we had to fake up a superblock, it won't show that there
886355d6bb5Sswilcox * are any directories at all. This causes problems when we
887355d6bb5Sswilcox * use numdirs to calculate hash keys, so use something at least
888355d6bb5Sswilcox * vaguely plausible.
889355d6bb5Sswilcox */
8907c478bd9Sstevel@tonic-gate numdirs = sblock.fs_cstotal.cs_ndir;
891355d6bb5Sswilcox if (numdirs == 0)
892355d6bb5Sswilcox numdirs = sblock.fs_ipg * sblock.fs_ncg / 2;
8937c478bd9Sstevel@tonic-gate listmax = numdirs + 10;
8947c478bd9Sstevel@tonic-gate inpsort = (struct inoinfo **)calloc((unsigned)listmax,
8957c478bd9Sstevel@tonic-gate sizeof (struct inoinfo *));
8967c478bd9Sstevel@tonic-gate inphead = (struct inoinfo **)calloc((unsigned)numdirs,
8977c478bd9Sstevel@tonic-gate sizeof (struct inoinfo *));
8987c478bd9Sstevel@tonic-gate if (inpsort == NULL || inphead == NULL) {
899355d6bb5Sswilcox (void) printf("cannot alloc %lld bytes for inphead\n",
900355d6bb5Sswilcox (longlong_t)numdirs * sizeof (struct inoinfo *));
901355d6bb5Sswilcox retval = -1;
902355d6bb5Sswilcox goto finish;
903355d6bb5Sswilcox }
904355d6bb5Sswilcox if (debug) {
905d1a180b0Smaheshvs if (listmax > ULONG_MAX)
906355d6bb5Sswilcox errexit("create_and_init_maps: listmax overflowed\n");
907d1a180b0Smaheshvs if (numdirs > ULONG_MAX)
908355d6bb5Sswilcox errexit("create_and_init_maps: numdirs overflowed\n");
9097c478bd9Sstevel@tonic-gate }
910355d6bb5Sswilcox
9117c478bd9Sstevel@tonic-gate numacls = numdirs;
9127c478bd9Sstevel@tonic-gate aclmax = numdirs + 10;
913355d6bb5Sswilcox aclpsort = (struct inoinfo **)calloc((unsigned)aclmax,
914355d6bb5Sswilcox sizeof (struct inoinfo *));
915355d6bb5Sswilcox aclphead = (struct inoinfo **)calloc((unsigned)numacls,
916355d6bb5Sswilcox sizeof (struct inoinfo *));
9177c478bd9Sstevel@tonic-gate if (aclpsort == NULL || aclphead == NULL) {
918355d6bb5Sswilcox (void) printf("cannot alloc %lld bytes for aclphead\n",
919355d6bb5Sswilcox (longlong_t)numacls * sizeof (struct inoinfo *));
920355d6bb5Sswilcox retval = -1;
921355d6bb5Sswilcox goto finish;
922355d6bb5Sswilcox }
923355d6bb5Sswilcox if (debug) {
924d1a180b0Smaheshvs if (aclmax > ULONG_MAX)
925355d6bb5Sswilcox errexit("create_and_init_maps: aclmax overflowed\n");
926d1a180b0Smaheshvs if (numacls > ULONG_MAX)
927355d6bb5Sswilcox errexit("create_and_init_maps: numacls overflowed\n");
9287c478bd9Sstevel@tonic-gate }
9297c478bd9Sstevel@tonic-gate aclplast = 0L;
9307c478bd9Sstevel@tonic-gate inplast = 0L;
931355d6bb5Sswilcox
932355d6bb5Sswilcox finish:
933355d6bb5Sswilcox return (retval);
934355d6bb5Sswilcox }
935355d6bb5Sswilcox
936355d6bb5Sswilcox caddr_t
setup(caddr_t dev)937355d6bb5Sswilcox setup(caddr_t dev)
938355d6bb5Sswilcox {
939355d6bb5Sswilcox int corefs;
940355d6bb5Sswilcox static char devstr[MAXPATHLEN + 1];
941355d6bb5Sswilcox
942355d6bb5Sswilcox havesb = 0;
943355d6bb5Sswilcox devname = devstr;
944355d6bb5Sswilcox
945355d6bb5Sswilcox derive_devstr(dev, devstr, sizeof (devstr));
946355d6bb5Sswilcox errorlocked = is_errorlocked(devstr);
947355d6bb5Sswilcox corefs = check_mount_state(devstr, sizeof (devstr));
948355d6bb5Sswilcox
949355d6bb5Sswilcox sblock_init();
950355d6bb5Sswilcox
951355d6bb5Sswilcox if (open_and_intro(devstr, corefs) == -1)
952355d6bb5Sswilcox goto cleanup;
953355d6bb5Sswilcox
9545b4dc236Smishra if (mflag && mounted(devstr, devstr,
9555b4dc236Smishra sizeof (devstr)) == M_RW)
9565b4dc236Smishra return (devstr);
9575b4dc236Smishra
958355d6bb5Sswilcox /*
959355d6bb5Sswilcox * Check log state
960355d6bb5Sswilcox */
961355d6bb5Sswilcox if (!logsetup(devstr))
962355d6bb5Sswilcox goto cleanup;
963355d6bb5Sswilcox
964355d6bb5Sswilcox /*
965355d6bb5Sswilcox * Flush fs if we're going to do anything other than a sanity check.
966355d6bb5Sswilcox * Note, if logging then the fs was already flushed in logsetup().
967355d6bb5Sswilcox */
968355d6bb5Sswilcox if (!islog && !mflag)
969355d6bb5Sswilcox flush_fs();
970355d6bb5Sswilcox
971355d6bb5Sswilcox if (find_superblock(devstr) == -1)
972355d6bb5Sswilcox goto cleanup;
973355d6bb5Sswilcox
974355d6bb5Sswilcox fixup_superblock();
975355d6bb5Sswilcox
976355d6bb5Sswilcox if (errorlocked &&
977355d6bb5Sswilcox (initial_error_state_adjust() == -1))
978355d6bb5Sswilcox goto cleanup;
979355d6bb5Sswilcox
980355d6bb5Sswilcox /*
981355d6bb5Sswilcox * asblk could be dirty because we found a mismatch between
982355d6bb5Sswilcox * the primary superblock and one of its backups in checksb().
983355d6bb5Sswilcox */
984355d6bb5Sswilcox if (asblk.b_dirty && !bflag) {
985355d6bb5Sswilcox (void) memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize);
986355d6bb5Sswilcox flush(fswritefd, &asblk);
987355d6bb5Sswilcox }
988355d6bb5Sswilcox
989355d6bb5Sswilcox getsummaryinfo();
990355d6bb5Sswilcox
991355d6bb5Sswilcox /*
992355d6bb5Sswilcox * if not error-locked, using the standard superblock,
993355d6bb5Sswilcox * not bad log, not forced, preening, and is clean;
994355d6bb5Sswilcox * stop checking
995355d6bb5Sswilcox */
996355d6bb5Sswilcox if (!errorlocked && (bflag == 0) &&
997355d6bb5Sswilcox ((!islog || islogok) &&
998355d6bb5Sswilcox (fflag == 0) && preen &&
999355d6bb5Sswilcox (FSOKAY == (sblock.fs_state + sblock.fs_time)) &&
1000355d6bb5Sswilcox ((sblock.fs_clean == FSLOG && islog) ||
1001355d6bb5Sswilcox ((sblock.fs_clean == FSCLEAN) || (sblock.fs_clean == FSSTABLE))))) {
1002355d6bb5Sswilcox iscorrupt = 0;
1003355d6bb5Sswilcox printclean();
1004355d6bb5Sswilcox goto cleanup;
1005355d6bb5Sswilcox }
1006355d6bb5Sswilcox
1007355d6bb5Sswilcox if (create_and_init_maps() == -1)
1008355d6bb5Sswilcox goto nomaps;
1009355d6bb5Sswilcox
10107c478bd9Sstevel@tonic-gate bufinit();
10117c478bd9Sstevel@tonic-gate return (devstr);
10127c478bd9Sstevel@tonic-gate
1013355d6bb5Sswilcox nomaps:
10147c478bd9Sstevel@tonic-gate ckfini();
1015355d6bb5Sswilcox exitstat = EXERRFATAL;
1016355d6bb5Sswilcox /* FALLTHROUGH */
1017355d6bb5Sswilcox
1018355d6bb5Sswilcox cleanup:
1019355d6bb5Sswilcox unbufinit();
1020355d6bb5Sswilcox uncreate_maps();
1021355d6bb5Sswilcox ungetsummaryinfo();
1022355d6bb5Sswilcox
1023355d6bb5Sswilcox /*
1024355d6bb5Sswilcox * Can't get rid of the superblock buffer, because our
1025355d6bb5Sswilcox * caller references it to generate the summary statistics.
1026355d6bb5Sswilcox */
1027355d6bb5Sswilcox
1028355d6bb5Sswilcox return (NULL);
1029355d6bb5Sswilcox }
1030355d6bb5Sswilcox
1031355d6bb5Sswilcox /*
1032355d6bb5Sswilcox * Undoes the allocations in create_and_init_maps()
1033355d6bb5Sswilcox */
1034355d6bb5Sswilcox static void
uncreate_maps(void)1035355d6bb5Sswilcox uncreate_maps(void)
1036355d6bb5Sswilcox {
1037355d6bb5Sswilcox /*
1038355d6bb5Sswilcox * No ordering dependency amongst these, so they are here in
1039355d6bb5Sswilcox * the same order they were calculated.
1040355d6bb5Sswilcox */
1041355d6bb5Sswilcox if (blockmap != NULL)
1042355d6bb5Sswilcox free(blockmap);
1043355d6bb5Sswilcox if (statemap != NULL)
1044355d6bb5Sswilcox free(statemap);
1045355d6bb5Sswilcox if (lncntp != NULL)
1046355d6bb5Sswilcox free(lncntp);
1047355d6bb5Sswilcox if (inpsort != NULL)
1048355d6bb5Sswilcox free(inpsort);
1049355d6bb5Sswilcox if (inphead != NULL)
1050355d6bb5Sswilcox free(inphead);
1051355d6bb5Sswilcox if (aclpsort != NULL)
1052355d6bb5Sswilcox free(aclpsort);
1053355d6bb5Sswilcox if (aclphead != NULL)
1054355d6bb5Sswilcox free(aclphead);
10557c478bd9Sstevel@tonic-gate }
10567c478bd9Sstevel@tonic-gate
10577c478bd9Sstevel@tonic-gate /*
10587c478bd9Sstevel@tonic-gate * mkfs limits the size of the inode map to be no more than a third of
10597c478bd9Sstevel@tonic-gate * the cylinder group space. We'll use that value for sanity checking
10607c478bd9Sstevel@tonic-gate * the superblock's inode per group value.
10617c478bd9Sstevel@tonic-gate */
10627c478bd9Sstevel@tonic-gate #define MAXIpG (roundup(sblock.fs_bsize * NBBY / 3, sblock.fs_inopb))
10637c478bd9Sstevel@tonic-gate
10647c478bd9Sstevel@tonic-gate /*
10657c478bd9Sstevel@tonic-gate * Check the super block and its summary info.
10667c478bd9Sstevel@tonic-gate */
10677c478bd9Sstevel@tonic-gate static int
checksb(int listerr)10687c478bd9Sstevel@tonic-gate checksb(int listerr)
10697c478bd9Sstevel@tonic-gate {
1070355d6bb5Sswilcox caddr_t err;
1071355d6bb5Sswilcox
10727c478bd9Sstevel@tonic-gate /*
10737c478bd9Sstevel@tonic-gate * When the fs check is successfully completed, the alternate super
10747c478bd9Sstevel@tonic-gate * block at sblk.b_bno will be overwritten by ckfini() with the
10757c478bd9Sstevel@tonic-gate * repaired super block.
10767c478bd9Sstevel@tonic-gate */
1077355d6bb5Sswilcox sblk.b_bno = bflag ? bflag : (SBOFF / dev_bsize);
10787c478bd9Sstevel@tonic-gate sblk.b_size = SBSIZE;
10797c478bd9Sstevel@tonic-gate
10807c478bd9Sstevel@tonic-gate /*
1081355d6bb5Sswilcox * Sanity-check some of the values we are going to use later
1082355d6bb5Sswilcox * in allocation requests.
10837c478bd9Sstevel@tonic-gate */
10847c478bd9Sstevel@tonic-gate if (sblock.fs_cstotal.cs_ndir < 1 ||
10857c478bd9Sstevel@tonic-gate sblock.fs_cstotal.cs_ndir > sblock.fs_ncg * sblock.fs_ipg) {
1086355d6bb5Sswilcox if (verbose)
1087355d6bb5Sswilcox (void) printf(
1088355d6bb5Sswilcox "Found %d directories, should be between 1 and %d inclusive.\n",
1089355d6bb5Sswilcox sblock.fs_cstotal.cs_ndir,
1090355d6bb5Sswilcox sblock.fs_ncg * sblock.fs_ipg);
1091355d6bb5Sswilcox err = "NUMBER OF DIRECTORIES OUT OF RANGE";
1092355d6bb5Sswilcox goto failedsb;
10937c478bd9Sstevel@tonic-gate }
10947c478bd9Sstevel@tonic-gate
10957c478bd9Sstevel@tonic-gate if (sblock.fs_nrpos <= 0 || sblock.fs_postbloff < 0 ||
10967c478bd9Sstevel@tonic-gate sblock.fs_cpc < 0 ||
10977c478bd9Sstevel@tonic-gate (sblock.fs_postbloff +
1098355d6bb5Sswilcox (sblock.fs_nrpos * sblock.fs_cpc * sizeof (short))) >
10997c478bd9Sstevel@tonic-gate sblock.fs_sbsize) {
1100355d6bb5Sswilcox err = "ROTATIONAL POSITION TABLE SIZE OUT OF RANGE";
1101355d6bb5Sswilcox goto failedsb;
11027c478bd9Sstevel@tonic-gate }
11037c478bd9Sstevel@tonic-gate
11047c478bd9Sstevel@tonic-gate if (sblock.fs_cssize !=
1105355d6bb5Sswilcox fragroundup(&sblock, sblock.fs_ncg * sizeof (struct csum))) {
1106355d6bb5Sswilcox err = "SIZE OF CYLINDER GROUP SUMMARY AREA WRONG";
1107355d6bb5Sswilcox goto failedsb;
11087c478bd9Sstevel@tonic-gate }
11097c478bd9Sstevel@tonic-gate
11107c478bd9Sstevel@tonic-gate if (sblock.fs_inopb != (sblock.fs_bsize / sizeof (struct dinode))) {
1111355d6bb5Sswilcox err = "INOPB NONSENSICAL RELATIVE TO BSIZE";
1112355d6bb5Sswilcox goto failedsb;
1113355d6bb5Sswilcox }
1114355d6bb5Sswilcox
1115355d6bb5Sswilcox if (sblock.fs_bsize > MAXBSIZE) {
1116355d6bb5Sswilcox err = "BLOCK SIZE LARGER THAN MAXIMUM SUPPORTED";
1117355d6bb5Sswilcox goto failedsb;
11187c478bd9Sstevel@tonic-gate }
11197c478bd9Sstevel@tonic-gate
11207c478bd9Sstevel@tonic-gate if (sblock.fs_bsize != (sblock.fs_frag * sblock.fs_fsize)) {
1121355d6bb5Sswilcox err = "FRAGS PER BLOCK OR FRAG SIZE WRONG";
1122355d6bb5Sswilcox goto failedsb;
11237c478bd9Sstevel@tonic-gate }
11247c478bd9Sstevel@tonic-gate
11257c478bd9Sstevel@tonic-gate if (sblock.fs_dsize >= sblock.fs_size) {
1126355d6bb5Sswilcox err = "NUMBER OF DATA BLOCKS OUT OF RANGE";
1127355d6bb5Sswilcox goto failedsb;
11287c478bd9Sstevel@tonic-gate }
11297c478bd9Sstevel@tonic-gate
1130355d6bb5Sswilcox #if 0
1131355d6bb5Sswilcox if (sblock.fs_size >
1132355d6bb5Sswilcox (sblock.fs_nsect * sblock.fs_ntrak * sblock.fs_ncyl)) {
1133355d6bb5Sswilcox err = "FILESYSTEM SIZE LARGER THAN DEVICE";
1134355d6bb5Sswilcox goto failedsb;
1135355d6bb5Sswilcox }
1136355d6bb5Sswilcox #endif
1137355d6bb5Sswilcox
11387c478bd9Sstevel@tonic-gate /*
11397c478bd9Sstevel@tonic-gate * Check that the number of inodes per group isn't less than or
11407c478bd9Sstevel@tonic-gate * equal to zero. Also makes sure it isn't more than the
11417c478bd9Sstevel@tonic-gate * maximum number mkfs enforces.
11427c478bd9Sstevel@tonic-gate */
11437c478bd9Sstevel@tonic-gate if (sblock.fs_ipg <= 0 || sblock.fs_ipg > MAXIpG) {
1144355d6bb5Sswilcox err = "INODES PER GROUP OUT OF RANGE";
1145355d6bb5Sswilcox goto failedsb;
1146355d6bb5Sswilcox }
1147355d6bb5Sswilcox
1148355d6bb5Sswilcox if (sblock.fs_cgsize > sblock.fs_bsize) {
1149355d6bb5Sswilcox err = "CG HEADER LARGER THAN ONE BLOCK";
1150355d6bb5Sswilcox goto failedsb;
11517c478bd9Sstevel@tonic-gate }
11527c478bd9Sstevel@tonic-gate
11537c478bd9Sstevel@tonic-gate /*
11547c478bd9Sstevel@tonic-gate * Set all possible fields that could differ, then do check
11557c478bd9Sstevel@tonic-gate * of whole super block against an alternate super block.
11567c478bd9Sstevel@tonic-gate * When an alternate super-block is specified this check is skipped.
11577c478bd9Sstevel@tonic-gate */
1158355d6bb5Sswilcox (void) getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1),
1159355d6bb5Sswilcox (size_t)sblock.fs_sbsize);
1160355d6bb5Sswilcox if (asblk.b_errs != 0) {
1161355d6bb5Sswilcox brelse(&asblk);
11627c478bd9Sstevel@tonic-gate return (0);
1163355d6bb5Sswilcox }
1164355d6bb5Sswilcox if (bflag != 0) {
11657c478bd9Sstevel@tonic-gate /*
1166355d6bb5Sswilcox * Invalidate clean flag and state information.
1167355d6bb5Sswilcox * Note that we couldn't return until after the
1168355d6bb5Sswilcox * above getblk(), because we're going to want to
1169355d6bb5Sswilcox * update asblk when everything's done.
11707c478bd9Sstevel@tonic-gate */
11717c478bd9Sstevel@tonic-gate sblock.fs_clean = FSACTIVE;
11727c478bd9Sstevel@tonic-gate sblock.fs_state = (long)sblock.fs_time;
11737c478bd9Sstevel@tonic-gate sblock.fs_reclaim = 0;
11747c478bd9Sstevel@tonic-gate sbdirty();
11757c478bd9Sstevel@tonic-gate havesb = 1;
11767c478bd9Sstevel@tonic-gate return (1);
11777c478bd9Sstevel@tonic-gate }
11787c478bd9Sstevel@tonic-gate altsblock.fs_link = sblock.fs_link;
11797c478bd9Sstevel@tonic-gate altsblock.fs_rolled = sblock.fs_rolled;
11807c478bd9Sstevel@tonic-gate altsblock.fs_time = sblock.fs_time;
11817c478bd9Sstevel@tonic-gate altsblock.fs_state = sblock.fs_state;
11827c478bd9Sstevel@tonic-gate altsblock.fs_cstotal = sblock.fs_cstotal;
11837c478bd9Sstevel@tonic-gate altsblock.fs_cgrotor = sblock.fs_cgrotor;
11847c478bd9Sstevel@tonic-gate altsblock.fs_fmod = sblock.fs_fmod;
11857c478bd9Sstevel@tonic-gate altsblock.fs_clean = sblock.fs_clean;
11867c478bd9Sstevel@tonic-gate altsblock.fs_ronly = sblock.fs_ronly;
11877c478bd9Sstevel@tonic-gate altsblock.fs_flags = sblock.fs_flags;
11887c478bd9Sstevel@tonic-gate altsblock.fs_maxcontig = sblock.fs_maxcontig;
11897c478bd9Sstevel@tonic-gate altsblock.fs_minfree = sblock.fs_minfree;
11907c478bd9Sstevel@tonic-gate altsblock.fs_optim = sblock.fs_optim;
11917c478bd9Sstevel@tonic-gate altsblock.fs_rotdelay = sblock.fs_rotdelay;
11927c478bd9Sstevel@tonic-gate altsblock.fs_maxbpg = sblock.fs_maxbpg;
11937c478bd9Sstevel@tonic-gate altsblock.fs_logbno = sblock.fs_logbno;
11947c478bd9Sstevel@tonic-gate altsblock.fs_reclaim = sblock.fs_reclaim;
11957c478bd9Sstevel@tonic-gate altsblock.fs_si = sblock.fs_si;
1196355d6bb5Sswilcox (void) memmove((void *)altsblock.fs_fsmnt, (void *)sblock.fs_fsmnt,
1197355d6bb5Sswilcox sizeof (sblock.fs_fsmnt));
11987c478bd9Sstevel@tonic-gate /*
11997c478bd9Sstevel@tonic-gate * The following should not have to be copied.
12007c478bd9Sstevel@tonic-gate */
1201355d6bb5Sswilcox (void) memmove((void *)altsblock.fs_u.fs_csp_pad,
1202355d6bb5Sswilcox (void *)sblock.fs_u.fs_csp_pad, sizeof (sblock.fs_u.fs_csp_pad));
12037c478bd9Sstevel@tonic-gate altsblock.fs_fsbtodb = sblock.fs_fsbtodb;
12047c478bd9Sstevel@tonic-gate altsblock.fs_npsect = sblock.fs_npsect;
12057c478bd9Sstevel@tonic-gate altsblock.fs_nrpos = sblock.fs_nrpos;
1206355d6bb5Sswilcox if (memcmp((void *)&sblock, (void *)&altsblock,
1207355d6bb5Sswilcox (size_t)sblock.fs_sbsize) != 0) {
1208355d6bb5Sswilcox err = "BAD VALUES IN SUPER BLOCK";
1209355d6bb5Sswilcox goto failedsb;
12107c478bd9Sstevel@tonic-gate }
12117c478bd9Sstevel@tonic-gate havesb = 1;
12127c478bd9Sstevel@tonic-gate return (1);
1213355d6bb5Sswilcox
1214355d6bb5Sswilcox failedsb:
1215355d6bb5Sswilcox badsb(listerr, err);
1216355d6bb5Sswilcox return (0);
12177c478bd9Sstevel@tonic-gate }
12187c478bd9Sstevel@tonic-gate
12197c478bd9Sstevel@tonic-gate static void
badsb(int listerr,caddr_t s)1220355d6bb5Sswilcox badsb(int listerr, caddr_t s)
12217c478bd9Sstevel@tonic-gate {
12227c478bd9Sstevel@tonic-gate if (!listerr)
12237c478bd9Sstevel@tonic-gate return;
12247c478bd9Sstevel@tonic-gate if (preen)
1225355d6bb5Sswilcox (void) printf("%s: ", devname);
1226355d6bb5Sswilcox (void) printf("BAD SUPERBLOCK AT BLOCK %d: %s\n",
1227355d6bb5Sswilcox bflag != 0 ? bflag : SBLOCK, s);
1228355d6bb5Sswilcox if (preen) {
1229355d6bb5Sswilcox pwarn(
1230355d6bb5Sswilcox "USE AN ALTERNATE SUPERBLOCK TO SUPPLY NEEDED INFORMATION;\n");
1231355d6bb5Sswilcox pwarn("e.g. fsck [-F ufs] -o b=# [special ...] \n");
1232355d6bb5Sswilcox exitstat = EXERRFATAL;
1233355d6bb5Sswilcox pfatal(
1234*bbf21555SRichard Lowe "where # is the alternate super block. SEE fsck_ufs(8). \n");
1235355d6bb5Sswilcox }
1236355d6bb5Sswilcox /* we're expected to return if not preening */
12377c478bd9Sstevel@tonic-gate }
12387c478bd9Sstevel@tonic-gate
12397c478bd9Sstevel@tonic-gate /*
12407c478bd9Sstevel@tonic-gate * Write out the super block into each of the alternate super blocks.
12417c478bd9Sstevel@tonic-gate */
12427c478bd9Sstevel@tonic-gate void
write_altsb(int fd)12437c478bd9Sstevel@tonic-gate write_altsb(int fd)
12447c478bd9Sstevel@tonic-gate {
12457c478bd9Sstevel@tonic-gate int cylno;
12467c478bd9Sstevel@tonic-gate
12477c478bd9Sstevel@tonic-gate for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
1248355d6bb5Sswilcox bwrite(fd, (caddr_t)&sblock, fsbtodb(&sblock,
1249355d6bb5Sswilcox cgsblock(&sblock, cylno)), sblock.fs_sbsize);
1250355d6bb5Sswilcox }
1251355d6bb5Sswilcox
1252355d6bb5Sswilcox static void
sblock_init(void)1253355d6bb5Sswilcox sblock_init(void)
1254355d6bb5Sswilcox {
1255355d6bb5Sswilcox fsmodified = 0;
1256355d6bb5Sswilcox if (errorlocked)
1257355d6bb5Sswilcox isdirty = 1;
1258355d6bb5Sswilcox lfdir = 0;
1259355d6bb5Sswilcox initbarea(&sblk);
1260355d6bb5Sswilcox initbarea(&asblk);
1261355d6bb5Sswilcox
1262355d6bb5Sswilcox /*
1263355d6bb5Sswilcox * May have buffer left over from previous filesystem check.
1264355d6bb5Sswilcox */
1265355d6bb5Sswilcox if (sblk.b_un.b_buf == NULL)
1266355d6bb5Sswilcox sblk.b_un.b_buf = calloc(1, SBSIZE);
1267355d6bb5Sswilcox if (asblk.b_un.b_buf == NULL)
1268355d6bb5Sswilcox asblk.b_un.b_buf = calloc(1, SBSIZE);
1269355d6bb5Sswilcox if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
1270355d6bb5Sswilcox errexit("cannot allocate space for superblock\n");
1271355d6bb5Sswilcox /*
1272355d6bb5Sswilcox * Could get the actual sector size from the device here,
1273355d6bb5Sswilcox * but considering how much would need to change in the rest
1274355d6bb5Sswilcox * of the system before it'd be a problem for us, it's not
1275355d6bb5Sswilcox * worth worrying about right now.
1276355d6bb5Sswilcox */
1277355d6bb5Sswilcox dev_bsize = secsize = DEV_BSIZE;
1278355d6bb5Sswilcox }
1279355d6bb5Sswilcox
1280355d6bb5Sswilcox /*
1281355d6bb5Sswilcox * Calculate a prototype superblock based on information in the disk label.
1282355d6bb5Sswilcox * When done the cgsblock macro can be calculated and the fs_ncg field
1283355d6bb5Sswilcox * can be used. Do NOT attempt to use other macros without verifying that
1284355d6bb5Sswilcox * their needed information is available!
1285355d6bb5Sswilcox *
1286355d6bb5Sswilcox * In BSD, the disk label includes all sorts of useful information,
1287355d6bb5Sswilcox * like cpg. Solaris doesn't have that, and deriving it (as well as
1288355d6bb5Sswilcox * some other parameters) is difficult. Rather than duplicate the
1289355d6bb5Sswilcox * code, just ask mkfs what it would've come up with by default.
1290355d6bb5Sswilcox * Ideally, we'd just link in the code, but given the source base
1291355d6bb5Sswilcox * involved, it's more practical to just get a binary dump.
1292355d6bb5Sswilcox *
1293355d6bb5Sswilcox * The one minor drawback to the above approach is that newfs and mkfs
1294355d6bb5Sswilcox * will produce vastly different layouts for the same partition if
1295355d6bb5Sswilcox * they're allowed to default everything. So, if the superblock that
1296355d6bb5Sswilcox * mkfs gives us doesn't work for guessing where the alternates are,
1297355d6bb5Sswilcox * we need to try newfs.
1298355d6bb5Sswilcox */
1299355d6bb5Sswilcox static int
calcsb(calcsb_t style,caddr_t dev,int devfd,struct fs * fs)1300355d6bb5Sswilcox calcsb(calcsb_t style, caddr_t dev, int devfd, struct fs *fs)
1301355d6bb5Sswilcox {
1302355d6bb5Sswilcox #define FROM_CHILD 0
1303355d6bb5Sswilcox #define TO_FSCK 1
1304355d6bb5Sswilcox #define CMD_IDX 0
1305355d6bb5Sswilcox #define DEV_IDX 3
1306355d6bb5Sswilcox #define SIZE_IDX 4
1307355d6bb5Sswilcox
1308355d6bb5Sswilcox int child_pipe[2];
1309355d6bb5Sswilcox caddr_t mkfsline[] = {
1310355d6bb5Sswilcox "", /* CMD_IDX */
1311355d6bb5Sswilcox "-o",
1312355d6bb5Sswilcox "calcbinsb,N",
1313355d6bb5Sswilcox NULL, /* DEV_IDX */
1314355d6bb5Sswilcox NULL, /* SIZE_IDX */
1315355d6bb5Sswilcox NULL
1316355d6bb5Sswilcox };
1317355d6bb5Sswilcox caddr_t newfsline[] = {
1318355d6bb5Sswilcox "", /* CMD_IDX */
1319355d6bb5Sswilcox "-B",
1320355d6bb5Sswilcox "-N",
1321355d6bb5Sswilcox NULL, /* DEV_IDX */
1322355d6bb5Sswilcox NULL
1323355d6bb5Sswilcox };
1324355d6bb5Sswilcox int pending, transferred;
1325355d6bb5Sswilcox caddr_t *cmdline;
1326355d6bb5Sswilcox caddr_t target;
1327355d6bb5Sswilcox caddr_t sizestr = NULL;
1328355d6bb5Sswilcox caddr_t path_old, path_new, mkfs_dir, mkfs_path, newfs_path;
1329355d6bb5Sswilcox caddr_t slash;
1330355d6bb5Sswilcox diskaddr_t size;
1331355d6bb5Sswilcox int devnull;
1332355d6bb5Sswilcox
1333355d6bb5Sswilcox switch (style) {
1334355d6bb5Sswilcox case MKFS_STYLE:
1335355d6bb5Sswilcox if (debug)
1336355d6bb5Sswilcox (void) printf("calcsb() going with style MKFS\n");
1337355d6bb5Sswilcox cmdline = mkfsline;
1338355d6bb5Sswilcox break;
1339355d6bb5Sswilcox case NEWFS_STYLE:
1340355d6bb5Sswilcox if (debug)
1341355d6bb5Sswilcox (void) printf("calcsb() going with style NEWFS\n");
1342355d6bb5Sswilcox cmdline = newfsline;
1343355d6bb5Sswilcox break;
1344355d6bb5Sswilcox default:
1345355d6bb5Sswilcox if (debug)
1346355d6bb5Sswilcox (void) printf("calcsb() doesn't undestand style %d\n",
1347355d6bb5Sswilcox style);
1348355d6bb5Sswilcox return (0);
1349355d6bb5Sswilcox }
1350355d6bb5Sswilcox
1351355d6bb5Sswilcox cmdline[DEV_IDX] = dev;
1352355d6bb5Sswilcox
1353355d6bb5Sswilcox /*
1354355d6bb5Sswilcox * Normally, only use the stock versions of the utilities.
1355355d6bb5Sswilcox * However, if we're debugging, the odds are that we're
1356355d6bb5Sswilcox * using experimental versions of them as well, so allow
1357355d6bb5Sswilcox * some flexibility.
1358355d6bb5Sswilcox */
1359355d6bb5Sswilcox mkfs_path = getenv("MKFS_PATH");
1360355d6bb5Sswilcox if (!debug || (mkfs_path == NULL))
1361355d6bb5Sswilcox mkfs_path = MKFS_PATH;
1362355d6bb5Sswilcox
1363355d6bb5Sswilcox newfs_path = getenv("NEWFS_PATH");
1364355d6bb5Sswilcox if (!debug || (newfs_path == NULL))
1365355d6bb5Sswilcox newfs_path = NEWFS_PATH;
1366355d6bb5Sswilcox
1367355d6bb5Sswilcox if (style == MKFS_STYLE) {
1368355d6bb5Sswilcox cmdline[CMD_IDX] = mkfs_path;
1369355d6bb5Sswilcox
1370355d6bb5Sswilcox size = getdisksize(dev, devfd);
1371355d6bb5Sswilcox if (size == 0)
1372355d6bb5Sswilcox return (0);
1373355d6bb5Sswilcox
1374355d6bb5Sswilcox (void) fsck_asprintf(&sizestr, "%lld", (longlong_t)size);
1375355d6bb5Sswilcox cmdline[SIZE_IDX] = sizestr;
1376355d6bb5Sswilcox } else if (style == NEWFS_STYLE) {
1377355d6bb5Sswilcox /*
1378355d6bb5Sswilcox * Make sure that newfs will find the right version of mkfs.
1379355d6bb5Sswilcox */
1380355d6bb5Sswilcox cmdline[CMD_IDX] = newfs_path;
1381355d6bb5Sswilcox path_old = getenv("PATH");
1382355d6bb5Sswilcox /* mkfs_path is always initialized, despite lint's concerns */
1383355d6bb5Sswilcox mkfs_dir = strdup(mkfs_path);
1384355d6bb5Sswilcox if (mkfs_dir == NULL)
1385355d6bb5Sswilcox return (0);
1386355d6bb5Sswilcox /*
1387355d6bb5Sswilcox * If no location data for mkfs, don't need to do
1388355d6bb5Sswilcox * anything about PATH.
1389355d6bb5Sswilcox */
1390355d6bb5Sswilcox slash = strrchr(mkfs_dir, '/');
1391355d6bb5Sswilcox if (slash != NULL) {
1392355d6bb5Sswilcox /*
1393355d6bb5Sswilcox * Just want the dir, so discard the executable name.
1394355d6bb5Sswilcox */
1395355d6bb5Sswilcox *slash = '\0';
1396355d6bb5Sswilcox
1397355d6bb5Sswilcox /*
1398355d6bb5Sswilcox * newfs uses system() to find mkfs, so make sure
1399355d6bb5Sswilcox * that the one we want to use is first on the
1400355d6bb5Sswilcox * list. Don't free path_new upon success, as it
1401355d6bb5Sswilcox * has become part of the environment.
1402355d6bb5Sswilcox */
1403355d6bb5Sswilcox (void) fsck_asprintf(&path_new, "PATH=%s:%s",
1404355d6bb5Sswilcox mkfs_dir, path_old);
1405355d6bb5Sswilcox if (putenv(path_new) != 0) {
1406355d6bb5Sswilcox free(mkfs_dir);
1407355d6bb5Sswilcox free(path_new);
1408355d6bb5Sswilcox return (0);
1409355d6bb5Sswilcox }
1410355d6bb5Sswilcox }
1411355d6bb5Sswilcox free(mkfs_dir);
1412355d6bb5Sswilcox } else {
1413355d6bb5Sswilcox /*
1414355d6bb5Sswilcox * Bad search style, quietly return failure.
1415355d6bb5Sswilcox */
1416355d6bb5Sswilcox if (debug) {
1417355d6bb5Sswilcox (void) printf("calcsb: got bad style number %d\n",
1418355d6bb5Sswilcox (int)style);
1419355d6bb5Sswilcox }
1420355d6bb5Sswilcox return (0);
1421355d6bb5Sswilcox }
1422355d6bb5Sswilcox
1423355d6bb5Sswilcox if (pipe(child_pipe) < 0) {
1424355d6bb5Sswilcox pfatal("calcsb: could not create pipe: %s\n", strerror(errno));
1425355d6bb5Sswilcox if (sizestr != NULL)
1426355d6bb5Sswilcox free(sizestr);
1427355d6bb5Sswilcox return (0);
1428355d6bb5Sswilcox }
1429355d6bb5Sswilcox
1430355d6bb5Sswilcox switch (fork()) {
1431355d6bb5Sswilcox case -1:
1432355d6bb5Sswilcox pfatal("calcsb: fork failed: %s\n", strerror(errno));
1433355d6bb5Sswilcox if (sizestr != NULL)
1434355d6bb5Sswilcox free(sizestr);
1435355d6bb5Sswilcox return (0);
1436355d6bb5Sswilcox case 0:
1437355d6bb5Sswilcox if (dup2(child_pipe[TO_FSCK], fileno(stdout)) < 0) {
1438355d6bb5Sswilcox (void) printf(
1439355d6bb5Sswilcox "calcsb: could not rename file descriptor: %s\n",
1440355d6bb5Sswilcox strerror(errno));
1441355d6bb5Sswilcox exit(EXBADPARM);
1442355d6bb5Sswilcox }
1443355d6bb5Sswilcox devnull = open("/dev/null", O_WRONLY);
1444355d6bb5Sswilcox if (devnull == -1) {
1445355d6bb5Sswilcox (void) printf("calcsb: could not open /dev/null: %s\n",
1446355d6bb5Sswilcox strerror(errno));
1447355d6bb5Sswilcox exit(EXBADPARM);
1448355d6bb5Sswilcox }
1449355d6bb5Sswilcox if (dup2(devnull, fileno(stderr)) < 0) {
1450355d6bb5Sswilcox (void) printf(
1451355d6bb5Sswilcox "calcsb: could not rename file descriptor: %s\n",
1452355d6bb5Sswilcox strerror(errno));
1453355d6bb5Sswilcox exit(EXBADPARM);
1454355d6bb5Sswilcox }
1455355d6bb5Sswilcox (void) close(child_pipe[FROM_CHILD]);
1456355d6bb5Sswilcox (void) execv(cmdline[CMD_IDX], cmdline);
1457355d6bb5Sswilcox (void) printf("calcsb: could not exec %s: %s\n",
1458355d6bb5Sswilcox cmdline[CMD_IDX], strerror(errno));
1459355d6bb5Sswilcox exit(EXBADPARM);
1460355d6bb5Sswilcox /* NOTREACHED */
1461355d6bb5Sswilcox default:
1462355d6bb5Sswilcox break;
1463355d6bb5Sswilcox }
1464355d6bb5Sswilcox
1465355d6bb5Sswilcox (void) close(child_pipe[TO_FSCK]);
1466355d6bb5Sswilcox if (sizestr != NULL)
1467355d6bb5Sswilcox free(sizestr);
1468355d6bb5Sswilcox
1469355d6bb5Sswilcox pending = sizeof (struct fs);
1470355d6bb5Sswilcox target = (caddr_t)fs;
1471355d6bb5Sswilcox do {
1472355d6bb5Sswilcox transferred = read(child_pipe[FROM_CHILD], target, pending);
1473355d6bb5Sswilcox pending -= transferred;
1474355d6bb5Sswilcox target += transferred;
1475355d6bb5Sswilcox } while ((pending > 0) && (transferred > 0));
1476355d6bb5Sswilcox
1477355d6bb5Sswilcox if (pending > 0) {
1478355d6bb5Sswilcox if (transferred < 0)
1479355d6bb5Sswilcox pfatal(
1480355d6bb5Sswilcox "calcsb: binary read of superblock from %s failed: %s\n",
1481355d6bb5Sswilcox (style == MKFS_STYLE) ? "mkfs" : "newfs",
1482355d6bb5Sswilcox (transferred < 0) ? strerror(errno) : "");
1483355d6bb5Sswilcox else
1484355d6bb5Sswilcox pfatal(
1485355d6bb5Sswilcox "calcsb: short read of superblock from %s\n",
1486355d6bb5Sswilcox (style == MKFS_STYLE) ? "mkfs" : "newfs");
1487355d6bb5Sswilcox return (0);
1488355d6bb5Sswilcox }
1489355d6bb5Sswilcox
1490355d6bb5Sswilcox (void) close(child_pipe[FROM_CHILD]);
1491355d6bb5Sswilcox (void) wait(NULL);
1492355d6bb5Sswilcox
1493355d6bb5Sswilcox if ((fs->fs_magic != FS_MAGIC) &&
1494355d6bb5Sswilcox (fs->fs_magic != MTB_UFS_MAGIC))
1495355d6bb5Sswilcox return (0);
1496355d6bb5Sswilcox
1497355d6bb5Sswilcox return (1);
14987c478bd9Sstevel@tonic-gate }
1499