setup.c revision 114589
1173319Sedwin/*
2153761Swollman * Copyright (c) 1980, 1986, 1993
3153761Swollman *	The Regents of the University of California.  All rights reserved.
42742Swollman *
52742Swollman * Redistribution and use in source and binary forms, with or without
62742Swollman * modification, are permitted provided that the following conditions
72742Swollman * are met:
82742Swollman * 1. Redistributions of source code must retain the above copyright
92742Swollman *    notice, this list of conditions and the following disclaimer.
10149514Swollman * 2. Redistributions in binary form must reproduce the above copyright
112742Swollman *    notice, this list of conditions and the following disclaimer in the
1258787Sru *    documentation and/or other materials provided with the distribution.
132742Swollman * 3. All advertising materials mentioning features or use of this software
142742Swollman *    must display the following acknowledgement:
152742Swollman *	This product includes software developed by the University of
162742Swollman *	California, Berkeley and its contributors.
172742Swollman * 4. Neither the name of the University nor the names of its contributors
1858787Sru *    may be used to endorse or promote products derived from this software
1958787Sru *    without specific prior written permission.
2058787Sru *
2158787Sru * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2258787Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2358787Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2458787Sru * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2558787Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2658787Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2758787Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2858787Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29149514Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30149514Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31149514Swollman * SUCH DAMAGE.
32149514Swollman */
33158421Swollman
3414343Swollman#if 0
3514343Swollman#ifndef lint
3614343Swollmanstatic const char sccsid[] = "@(#)setup.c	8.10 (Berkeley) 5/9/95";
3714343Swollman#endif /* not lint */
38158421Swollman#endif
3914343Swollman#include <sys/cdefs.h>
4075267Swollman__FBSDID("$FreeBSD: head/sbin/fsck_ffs/setup.c 114589 2003-05-03 18:41:59Z obrien $");
4117200Swollman
4275267Swollman#include <sys/param.h>
4375267Swollman#include <sys/stat.h>
4417200Swollman#define FSTYPENAMES
4517200Swollman#include <sys/disklabel.h>
4617200Swollman#include <sys/file.h>
4717200Swollman#include <sys/sysctl.h>
4817200Swollman
4917200Swollman#include <ufs/ufs/dinode.h>
5017200Swollman#include <ufs/ffs/fs.h>
5117200Swollman
5217200Swollman#include <ctype.h>
5317200Swollman#include <err.h>
5417200Swollman#include <errno.h>
5517200Swollman#include <limits.h>
5617200Swollman#include <stdint.h>
57149514Swollman#include <string.h>
58149514Swollman
5975267Swollman#include "fsck.h"
6075267Swollman
6175267Swollmanstruct bufarea asblk;
6275267Swollman#define altsblock (*asblk.b_un.b_fs)
6375267Swollman#define POWEROF2(num)	(((num) & ((num) - 1)) == 0)
6475267Swollman
6575267Swollmanstatic void badsb(int listerr, const char *s);
6675267Swollmanstatic int calcsb(char *dev, int devfd, struct fs *fs);
6775267Swollmanstatic struct disklabel *getdisklabel(char *s, int fd);
6875267Swollman
6917200Swollman/*
702742Swollman * Read in a superblock finding an alternate if necessary.
712742Swollman * Return 1 if successful, 0 if unsuccessful, -1 if file system
7219878Swollman * is already clean (preen mode only).
7319878Swollman */
742742Swollmanint
752742Swollmansetup(char *dev)
762742Swollman{
772742Swollman	long cg, asked, i, j;
782742Swollman	long bmapsize;
7967578Swollman	struct stat statb;
8067578Swollman	struct fs proto;
8167578Swollman	size_t size;
8267578Swollman
8367578Swollman	havesb = 0;
8467578Swollman	fswritefd = -1;
8567578Swollman	cursnapshot = 0;
8667578Swollman	if (stat(dev, &statb) < 0) {
8767578Swollman		printf("Can't stat %s: %s\n", dev, strerror(errno));
88149514Swollman		if (bkgrdflag) {
8967578Swollman			unlink(snapname);
9067578Swollman			bkgrdflag = 0;
9186222Swollman		}
9267578Swollman		return (0);
9367578Swollman	}
9467578Swollman	if ((statb.st_mode & S_IFMT) != S_IFCHR &&
9567578Swollman	    (statb.st_mode & S_IFMT) != S_IFBLK) {
9686222Swollman		if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) {
9767578Swollman			unlink(snapname);
98114173Swollman			printf("background fsck lacks a snapshot\n");
99114173Swollman			exit(EEXIT);
100114173Swollman		}
101114173Swollman		if ((statb.st_flags & SF_SNAPSHOT) != 0 && cvtlevel == 0) {
102114173Swollman			cursnapshot = statb.st_ino;
103114173Swollman		} else {
104114173Swollman			if (cvtlevel == 0 ||
105114173Swollman			    (statb.st_flags & SF_SNAPSHOT) == 0) {
106114173Swollman				if (preen && bkgrdflag) {
107114173Swollman					unlink(snapname);
108114173Swollman					bkgrdflag = 0;
109114173Swollman				}
110114173Swollman				pfatal("%s is not a disk device", dev);
111114173Swollman				if (reply("CONTINUE") == 0) {
112114173Swollman					if (bkgrdflag) {
113114173Swollman						unlink(snapname);
114114173Swollman						bkgrdflag = 0;
115149590Swollman					}
116149590Swollman					return (0);
117149590Swollman				}
118149590Swollman			} else {
119149590Swollman				if (bkgrdflag) {
120149590Swollman					unlink(snapname);
1212742Swollman					bkgrdflag = 0;
12275267Swollman				}
1232742Swollman				pfatal("cannot convert a snapshot");
1242742Swollman				exit(EEXIT);
12567578Swollman			}
1262742Swollman		}
127149514Swollman	}
1282742Swollman	if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
1292742Swollman		if (bkgrdflag) {
1302742Swollman			unlink(snapname);
1312742Swollman			bkgrdflag = 0;
132149514Swollman		}
133149514Swollman		printf("Can't open %s: %s\n", dev, strerror(errno));
134149514Swollman		return (0);
1352742Swollman	}
136153761Swollman	if (bkgrdflag) {
137153761Swollman		unlink(snapname);
138153761Swollman		size = MIBSIZE;
139153761Swollman		if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0||
140153761Swollman		    sysctlnametomib("vfs.ffs.adjblkcnt", adjblkcnt, &size) < 0||
141153761Swollman		    sysctlnametomib("vfs.ffs.freefiles", freefiles, &size) < 0||
142153761Swollman		    sysctlnametomib("vfs.ffs.freedirs", freedirs, &size) < 0 ||
143153761Swollman		    sysctlnametomib("vfs.ffs.freeblks", freeblks, &size) < 0) {
144153761Swollman			pfatal("kernel lacks background fsck support\n");
145153761Swollman			exit(EEXIT);
146153761Swollman		}
147153761Swollman		cmd.version = FFS_CMD_VERSION;
148153761Swollman		cmd.handle = fsreadfd;
149153761Swollman		fswritefd = -1;
150153761Swollman	}
151153761Swollman	if (preen == 0)
152153761Swollman		printf("** %s", dev);
153153761Swollman	if (bkgrdflag == 0 &&
154153761Swollman	    (nflag || (fswritefd = open(dev, O_WRONLY)) < 0)) {
155153761Swollman		fswritefd = -1;
15619878Swollman		if (preen)
1572742Swollman			pfatal("NO WRITE ACCESS");
1582742Swollman		printf(" (NO WRITE)");
1592742Swollman	}
1602742Swollman	if (preen == 0)
1612742Swollman		printf("\n");
1622742Swollman	/*
1632742Swollman	 * Read in the superblock, looking for alternates if necessary
1642742Swollman	 */
1652742Swollman	if (readsb(1) == 0) {
1662742Swollman		skipclean = 0;
1672742Swollman		if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
16814343Swollman			return(0);
16914343Swollman		if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
17014343Swollman			return (0);
17114343Swollman		for (cg = 0; cg < proto.fs_ncg; cg++) {
17219878Swollman			bflag = fsbtodb(&proto, cgsblock(&proto, cg));
1732742Swollman			if (readsb(0) != 0)
1742742Swollman				break;
1752742Swollman		}
1762742Swollman		if (cg >= proto.fs_ncg) {
1772742Swollman			printf("%s %s\n%s %s\n%s %s\n",
1782742Swollman				"SEARCH FOR ALTERNATE SUPER-BLOCK",
1792742Swollman				"FAILED. YOU MUST USE THE",
1802742Swollman				"-b OPTION TO FSCK TO SPECIFY THE",
1812742Swollman				"LOCATION OF AN ALTERNATE",
1822742Swollman				"SUPER-BLOCK TO SUPPLY NEEDED",
1832742Swollman				"INFORMATION; SEE fsck(8).");
1842742Swollman			bflag = 0;
1852742Swollman			return(0);
1862742Swollman		}
1872742Swollman		pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
18819878Swollman		bflag = 0;
1892742Swollman	}
1902742Swollman	if (skipclean && preen && sblock.fs_clean) {
1912742Swollman		pwarn("FILESYSTEM CLEAN; SKIPPING CHECKS\n");
1922742Swollman		return (-1);
1932742Swollman	}
19419878Swollman	maxfsblock = sblock.fs_size;
1952742Swollman	maxino = sblock.fs_ncg * sblock.fs_ipg;
1962742Swollman	/*
19719878Swollman	 * Check and potentially fix certain fields in the super block.
1982742Swollman	 */
1992742Swollman	if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) {
2002742Swollman		pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
2012742Swollman		if (reply("SET TO DEFAULT") == 1) {
2022742Swollman			sblock.fs_optim = FS_OPTTIME;
2032742Swollman			sbdirty();
2042742Swollman		}
2052742Swollman	}
2062742Swollman	if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) {
20719878Swollman		pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
2082742Swollman			sblock.fs_minfree);
2092742Swollman		if (reply("SET TO DEFAULT") == 1) {
2102742Swollman			sblock.fs_minfree = 10;
2112742Swollman			sbdirty();
2122742Swollman		}
2132742Swollman	}
2142742Swollman	if (sblock.fs_magic == FS_UFS1_MAGIC &&
2152742Swollman	    sblock.fs_old_inodefmt < FS_44INODEFMT) {
2162742Swollman		pwarn("Format of file system is too old.\n");
21719878Swollman		pwarn("Must update to modern format using a version of fsck\n");
2182742Swollman		pfatal("from before 2002 with the command ``fsck -c 2''\n");
2192742Swollman		exit(EEXIT);
2202742Swollman	}
2212742Swollman	if (asblk.b_dirty && !bflag) {
2222742Swollman		memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize);
2232742Swollman		flush(fswritefd, &asblk);
2242742Swollman	}
2252742Swollman	/*
2262742Swollman	 * read in the summary info.
22714343Swollman	 */
22875267Swollman	asked = 0;
22975267Swollman	sblock.fs_csp = calloc(1, sblock.fs_cssize);
23075267Swollman	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
23175267Swollman		size = sblock.fs_cssize - i < sblock.fs_bsize ?
232158421Swollman		    sblock.fs_cssize - i : sblock.fs_bsize;
233149514Swollman		if (bread(fsreadfd, (char *)sblock.fs_csp + i,
234149514Swollman		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
235149514Swollman		    size) != 0 && !asked) {
236149514Swollman			pfatal("BAD SUMMARY INFORMATION");
237149514Swollman			if (reply("CONTINUE") == 0) {
238149514Swollman				ckfini(0);
239149514Swollman				exit(EEXIT);
240149514Swollman			}
241149514Swollman			asked++;
242149514Swollman		}
243149514Swollman	}
244149514Swollman	/*
245149514Swollman	 * allocate and initialize the necessary maps
246149514Swollman	 */
247149514Swollman	bmapsize = roundup(howmany(maxfsblock, CHAR_BIT), sizeof(short));
248149514Swollman	blockmap = calloc((unsigned)bmapsize, sizeof (char));
249149514Swollman	if (blockmap == NULL) {
250149514Swollman		printf("cannot alloc %u bytes for blockmap\n",
251149514Swollman		    (unsigned)bmapsize);
2522742Swollman		goto badsb;
25386222Swollman	}
25475267Swollman	inostathead = calloc((unsigned)(sblock.fs_ncg),
25567578Swollman	    sizeof(struct inostatlist));
256149590Swollman	if (inostathead == NULL) {
257149590Swollman		printf("cannot alloc %u bytes for inostathead\n",
258114173Swollman		    (unsigned)(sizeof(struct inostatlist) * (sblock.fs_ncg)));
259114173Swollman		goto badsb;
260114173Swollman	}
26167578Swollman	numdirs = MAX(sblock.fs_cstotal.cs_ndir, 128);
262149514Swollman	dirhash = numdirs;
263149514Swollman	inplast = 0;
264149514Swollman	listmax = numdirs + 10;
265149514Swollman	inpsort = (struct inoinfo **)calloc((unsigned)listmax,
266149514Swollman	    sizeof(struct inoinfo *));
267149514Swollman	inphead = (struct inoinfo **)calloc((unsigned)numdirs,
268149514Swollman	    sizeof(struct inoinfo *));
269153670Swollman	if (inpsort == NULL || inphead == NULL) {
270153670Swollman		printf("cannot alloc %ju bytes for inphead\n",
271153670Swollman		    (uintmax_t)numdirs * sizeof(struct inoinfo *));
272153670Swollman		goto badsb;
273153670Swollman	}
274153670Swollman	bufinit();
275153670Swollman	if (sblock.fs_flags & FS_DOSOFTDEP)
276153670Swollman		usedsoftdep = 1;
277158421Swollman	else
278153670Swollman		usedsoftdep = 0;
27914343Swollman	return (1);
28014343Swollman
28114343Swollmanbadsb:
28214343Swollman	ckfini(0);
28314343Swollman	return (0);
28414343Swollman}
28514343Swollman
286149514Swollman/*
28714343Swollman * Possible superblock locations ordered from most to least likely.
28814343Swollman */
28914343Swollmanstatic int sblock_try[] = SBLOCKSEARCH;
29014343Swollman
29114343Swollman/*
2922742Swollman * Read in the super block and its summary info.
29386222Swollman */
29467578Swollmanint
295136638Swollmanreadsb(int listerr)
296136638Swollman{
297136638Swollman	ufs2_daddr_t super;
298114173Swollman	int i;
299114173Swollman
300114173Swollman	if (bflag) {
301114173Swollman		super = bflag;
302114173Swollman		if ((bread(fsreadfd, (char *)&sblock, super, (long)SBLOCKSIZE)))
30367578Swollman			return (0);
304158421Swollman		if (sblock.fs_magic != FS_UFS1_MAGIC &&
305158421Swollman		    sblock.fs_magic != FS_UFS2_MAGIC) {
306158421Swollman			fprintf(stderr, "%d is not a file system superblock\n",
307158421Swollman			    bflag);
308158421Swollman			return (0);
309158421Swollman		}
310169811Swollman	} else {
311169811Swollman		for (i = 0; sblock_try[i] != -1; i++) {
312169811Swollman			super = sblock_try[i] / dev_bsize;
313169811Swollman			if ((bread(fsreadfd, (char *)&sblock, super,
314169811Swollman			    (long)SBLOCKSIZE)))
315158421Swollman				return (0);
31614343Swollman			if ((sblock.fs_magic == FS_UFS1_MAGIC ||
31714343Swollman			     (sblock.fs_magic == FS_UFS2_MAGIC &&
31814343Swollman			      sblock.fs_sblockloc == sblock_try[i])) &&
31914343Swollman			    sblock.fs_ncg >= 1 &&
32014343Swollman			    sblock.fs_bsize >= MINBSIZE &&
32114343Swollman			    sblock.fs_bsize >= sizeof(struct fs))
32214343Swollman				break;
32314343Swollman		}
324149514Swollman		if (sblock_try[i] == -1) {
32514343Swollman			fprintf(stderr, "Cannot find file system superblock\n");
32614343Swollman			return (0);
32714343Swollman		}
32814343Swollman	}
32914343Swollman	/*
33014343Swollman	 * Compute block size that the file system is based on,
33114343Swollman	 * according to fsbtodb, and adjust superblock block number
33286222Swollman	 * so we can tell if this is an alternate later.
333149514Swollman	 */
33486222Swollman	super *= dev_bsize;
33586222Swollman	dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
336158421Swollman	sblk.b_bno = super / dev_bsize;
337158421Swollman	sblk.b_size = SBLOCKSIZE;
338158421Swollman	if (bflag)
339158421Swollman		goto out;
340158421Swollman	/*
341158421Swollman	 * Compare all fields that should not differ in alternate super block.
342158421Swollman	 * When an alternate super-block is specified this check is skipped.
343158421Swollman	 */
344158421Swollman	getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize);
345158421Swollman	if (asblk.b_errs)
3462742Swollman		return (0);
34786222Swollman	if (altsblock.fs_sblkno != sblock.fs_sblkno ||
34867578Swollman	    altsblock.fs_cblkno != sblock.fs_cblkno ||
349136638Swollman	    altsblock.fs_iblkno != sblock.fs_iblkno ||
35086222Swollman	    altsblock.fs_dblkno != sblock.fs_dblkno ||
351171948Sedwin	    altsblock.fs_ncg != sblock.fs_ncg ||
35275267Swollman	    altsblock.fs_bsize != sblock.fs_bsize ||
35375267Swollman	    altsblock.fs_fsize != sblock.fs_fsize ||
35467578Swollman	    altsblock.fs_frag != sblock.fs_frag ||
35514343Swollman	    altsblock.fs_bmask != sblock.fs_bmask ||
35614343Swollman	    altsblock.fs_fmask != sblock.fs_fmask ||
35714343Swollman	    altsblock.fs_bshift != sblock.fs_bshift ||
35814343Swollman	    altsblock.fs_fshift != sblock.fs_fshift ||
35914343Swollman	    altsblock.fs_fragshift != sblock.fs_fragshift ||
36014343Swollman	    altsblock.fs_fsbtodb != sblock.fs_fsbtodb ||
3612742Swollman	    altsblock.fs_sbsize != sblock.fs_sbsize ||
362149514Swollman	    altsblock.fs_nindir != sblock.fs_nindir ||
36315309Swollman	    altsblock.fs_inopb != sblock.fs_inopb ||
36415309Swollman	    altsblock.fs_cssize != sblock.fs_cssize ||
36515309Swollman	    altsblock.fs_ipg != sblock.fs_ipg ||
36615309Swollman	    altsblock.fs_fpg != sblock.fs_fpg ||
36715309Swollman	    altsblock.fs_magic != sblock.fs_magic) {
3682742Swollman		badsb(listerr,
36914343Swollman		"VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
37067578Swollman		return (0);
371136638Swollman	}
372171948Sedwinout:
373171948Sedwin	/*
374136638Swollman	 * If not yet done, update UFS1 superblock with new wider fields.
37567578Swollman	 */
37614343Swollman	if (sblock.fs_magic == FS_UFS1_MAGIC &&
37714343Swollman	    sblock.fs_maxbsize != sblock.fs_bsize) {
37814343Swollman		sblock.fs_maxbsize = sblock.fs_bsize;
37914343Swollman		sblock.fs_time = sblock.fs_old_time;
38014343Swollman		sblock.fs_size = sblock.fs_old_size;
38114343Swollman		sblock.fs_dsize = sblock.fs_old_dsize;
38214343Swollman		sblock.fs_csaddr = sblock.fs_old_csaddr;
383149514Swollman		sblock.fs_cstotal.cs_ndir = sblock.fs_old_cstotal.cs_ndir;
38414343Swollman		sblock.fs_cstotal.cs_nbfree = sblock.fs_old_cstotal.cs_nbfree;
38514343Swollman		sblock.fs_cstotal.cs_nifree = sblock.fs_old_cstotal.cs_nifree;
38614343Swollman		sblock.fs_cstotal.cs_nffree = sblock.fs_old_cstotal.cs_nffree;
3878029Swollman	}
38814343Swollman	havesb = 1;
38914343Swollman	return (1);
39014343Swollman}
39186222Swollman
39214343Swollmanstatic void
39319878Swollmanbadsb(int listerr, const char *s)
39475267Swollman{
39575267Swollman
39675267Swollman	if (!listerr)
39775267Swollman		return;
39814343Swollman	if (preen)
39986222Swollman		printf("%s: ", cdevname);
40086222Swollman	pfatal("BAD SUPER BLOCK: %s\n", s);
40186222Swollman}
40286222Swollman
40386222Swollmanvoid
40486222Swollmansblock_init(void)
40586222Swollman{
40614343Swollman	struct disklabel *lp;
40775267Swollman
40875267Swollman	fswritefd = -1;
40914343Swollman	fsmodified = 0;
41014343Swollman	lfdir = 0;
41114343Swollman	initbarea(&sblk);
41214343Swollman	initbarea(&asblk);
413136638Swollman	sblk.b_un.b_buf = malloc(SBLOCKSIZE);
41414343Swollman	asblk.b_un.b_buf = malloc(SBLOCKSIZE);
41575267Swollman	if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
41675267Swollman		errx(EEXIT, "cannot allocate space for superblock");
41714343Swollman	if ((lp = getdisklabel(NULL, fsreadfd)))
41814343Swollman		dev_bsize = secsize = lp->d_secsize;
41914343Swollman	else
420136638Swollman		dev_bsize = secsize = DEV_BSIZE;
42114343Swollman}
42275267Swollman
42375267Swollman/*
42414343Swollman * Calculate a prototype superblock based on information in the disk label.
425158421Swollman * When done the cgsblock macro can be calculated and the fs_ncg field
426158421Swollman * can be used. Do NOT attempt to use other macros without verifying that
42714343Swollman * their needed information is available!
42814343Swollman */
42914343Swollmanstatic int
430136638Swollmancalcsb(char *dev, int devfd, struct fs *fs)
43114343Swollman{
43275267Swollman	struct disklabel *lp;
43375267Swollman	struct partition *pp;
43414343Swollman	char *cp;
43514343Swollman	int i, nspf;
43614343Swollman
43714343Swollman	cp = strchr(dev, '\0') - 1;
43814343Swollman	if (cp == (char *)-1 || ((*cp < 'a' || *cp > 'h') && !isdigit(*cp))) {
439136638Swollman		pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
44014343Swollman		return (0);
44175267Swollman	}
44275267Swollman	lp = getdisklabel(dev, devfd);
44314343Swollman	if (isdigit(*cp))
44414343Swollman		pp = &lp->d_partitions[0];
44514343Swollman	else
44614343Swollman		pp = &lp->d_partitions[*cp - 'a'];
44714343Swollman	if (pp->p_fstype != FS_BSDFFS) {
448136638Swollman		pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n",
44914343Swollman			dev, pp->p_fstype < FSMAXTYPES ?
450149514Swollman			fstypenames[pp->p_fstype] : "unknown");
451149514Swollman		return (0);
45214343Swollman	}
45314343Swollman	if (pp->p_fsize == 0 || pp->p_frag == 0 ||
45414343Swollman	    pp->p_cpg == 0 || pp->p_size == 0) {
455149514Swollman		pfatal("%s: %s: type %s fsize %d, frag %d, cpg %d, size %d\n",
456149514Swollman		    dev, "INCOMPLETE LABEL", fstypenames[pp->p_fstype],
457149514Swollman		    pp->p_fsize, pp->p_frag, pp->p_cpg, pp->p_size);
458149514Swollman		return (0);
459149514Swollman	}
460149514Swollman	memset(fs, 0, sizeof(struct fs));
461149514Swollman	fs->fs_fsize = pp->p_fsize;
462149514Swollman	fs->fs_frag = pp->p_frag;
463149514Swollman	fs->fs_size = pp->p_size;
464149514Swollman	fs->fs_sblkno = roundup(
465149514Swollman		howmany(lp->d_bbsize + lp->d_sbsize, fs->fs_fsize),
466149514Swollman		fs->fs_frag);
467149514Swollman	nspf = fs->fs_fsize / lp->d_secsize;
468149514Swollman	for (fs->fs_fsbtodb = 0, i = nspf; i > 1; i >>= 1)
469149514Swollman		fs->fs_fsbtodb++;
4702742Swollman	dev_bsize = lp->d_secsize;
47114343Swollman	if (fs->fs_magic == FS_UFS2_MAGIC) {
47214343Swollman		fs->fs_fpg = pp->p_cpg;
47314343Swollman		fs->fs_ncg = howmany(fs->fs_size, fs->fs_fpg);
47414343Swollman	} else /* if (fs->fs_magic == FS_UFS1_MAGIC) */ {
47514343Swollman		fs->fs_old_cpg = pp->p_cpg;
47614343Swollman		fs->fs_old_cgmask = 0xffffffff;
47714343Swollman		for (i = lp->d_ntracks; i > 1; i >>= 1)
47814343Swollman			fs->fs_old_cgmask <<= 1;
47914343Swollman		if (!POWEROF2(lp->d_ntracks))
48014343Swollman			fs->fs_old_cgmask <<= 1;
48114343Swollman		fs->fs_old_cgoffset = roundup(howmany(lp->d_nsectors, nspf),
48214343Swollman		    fs->fs_frag);
48314343Swollman		fs->fs_fpg = (fs->fs_old_cpg * lp->d_secpercyl) / nspf;
48414343Swollman		fs->fs_ncg = howmany(fs->fs_size / lp->d_secpercyl,
48514343Swollman		    fs->fs_old_cpg);
48614343Swollman	}
4872742Swollman	return (1);
48814343Swollman}
48914343Swollman
49014343Swollmanstatic struct disklabel *
491114173Swollmangetdisklabel(char *s, int fd)
492114173Swollman{
493114173Swollman	static struct disklabel lab;
494114173Swollman
495114173Swollman	if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
496114173Swollman		if (s == NULL)
497114173Swollman			return ((struct disklabel *)NULL);
498114173Swollman		pwarn("ioctl (GCINFO): %s\n", strerror(errno));
499114173Swollman		errx(EEXIT, "%s: can't read disk label", s);
500114173Swollman	}
501114173Swollman	return (&lab);
502114173Swollman}
503114173Swollman