setup.c revision 125036
10SN/A/*
29330SN/A * Copyright (c) 1980, 1986, 1993
30SN/A *	The Regents of the University of California.  All rights reserved.
40SN/A *
50SN/A * Redistribution and use in source and binary forms, with or without
60SN/A * modification, are permitted provided that the following conditions
72362SN/A * are met:
80SN/A * 1. Redistributions of source code must retain the above copyright
92362SN/A *    notice, this list of conditions and the following disclaimer.
100SN/A * 2. Redistributions in binary form must reproduce the above copyright
110SN/A *    notice, this list of conditions and the following disclaimer in the
120SN/A *    documentation and/or other materials provided with the distribution.
130SN/A * 3. All advertising materials mentioning features or use of this software
140SN/A *    must display the following acknowledgement:
150SN/A *	This product includes software developed by the University of
160SN/A *	California, Berkeley and its contributors.
170SN/A * 4. Neither the name of the University nor the names of its contributors
180SN/A *    may be used to endorse or promote products derived from this software
190SN/A *    without specific prior written permission.
200SN/A *
212362SN/A * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
222362SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
232362SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
240SN/A * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
250SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
260SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
270SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
280SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
290SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
300SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
310SN/A * SUCH DAMAGE.
320SN/A */
330SN/A
340SN/A#if 0
350SN/A#ifndef lint
360SN/Astatic const char sccsid[] = "@(#)setup.c	8.10 (Berkeley) 5/9/95";
370SN/A#endif /* not lint */
380SN/A#endif
390SN/A#include <sys/cdefs.h>
400SN/A__FBSDID("$FreeBSD: head/sbin/fsck_ffs/setup.c 125036 2004-01-26 15:05:30Z cperciva $");
410SN/A
420SN/A#include <sys/param.h>
430SN/A#include <sys/stat.h>
440SN/A#define FSTYPENAMES
450SN/A#include <sys/disklabel.h>
460SN/A#include <sys/file.h>
470SN/A#include <sys/sysctl.h>
480SN/A
490SN/A#include <ufs/ufs/dinode.h>
500SN/A#include <ufs/ffs/fs.h>
510SN/A
520SN/A#include <ctype.h>
530SN/A#include <err.h>
540SN/A#include <errno.h>
550SN/A#include <limits.h>
560SN/A#include <stdint.h>
570SN/A#include <string.h>
580SN/A
590SN/A#include "fsck.h"
600SN/A
610SN/Astruct bufarea asblk;
620SN/A#define altsblock (*asblk.b_un.b_fs)
630SN/A#define POWEROF2(num)	(((num) & ((num) - 1)) == 0)
640SN/A
650SN/Astatic void badsb(int listerr, const char *s);
660SN/Astatic int calcsb(char *dev, int devfd, struct fs *fs);
670SN/Astatic struct disklabel *getdisklabel(char *s, int fd);
680SN/A
690SN/A/*
704487SN/A * Read in a superblock finding an alternate if necessary.
710SN/A * Return 1 if successful, 0 if unsuccessful, -1 if file system
724487SN/A * is already clean (preen mode only).
730SN/A */
740SN/Aint
750SN/Asetup(char *dev)
760SN/A{
770SN/A	long cg, asked, i, j;
780SN/A	long bmapsize;
790SN/A	struct stat statb;
800SN/A	struct fs proto;
810SN/A	size_t size;
820SN/A
830SN/A	havesb = 0;
840SN/A	fswritefd = -1;
850SN/A	cursnapshot = 0;
860SN/A	if (stat(dev, &statb) < 0) {
870SN/A		printf("Can't stat %s: %s\n", dev, strerror(errno));
880SN/A		if (bkgrdflag) {
890SN/A			unlink(snapname);
900SN/A			bkgrdflag = 0;
910SN/A		}
920SN/A		return (0);
930SN/A	}
940SN/A	if ((statb.st_mode & S_IFMT) != S_IFCHR &&
950SN/A	    (statb.st_mode & S_IFMT) != S_IFBLK) {
960SN/A		if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) {
970SN/A			unlink(snapname);
980SN/A			printf("background fsck lacks a snapshot\n");
990SN/A			exit(EEXIT);
1000SN/A		}
1010SN/A		if ((statb.st_flags & SF_SNAPSHOT) != 0 && cvtlevel == 0) {
1020SN/A			cursnapshot = statb.st_ino;
1030SN/A		} else {
1040SN/A			if (cvtlevel == 0 ||
1054487SN/A			    (statb.st_flags & SF_SNAPSHOT) == 0) {
1060SN/A				if (preen && bkgrdflag) {
1070SN/A					unlink(snapname);
1080SN/A					bkgrdflag = 0;
1090SN/A				}
1100SN/A				pfatal("%s is not a disk device", dev);
1110SN/A				if (reply("CONTINUE") == 0) {
1120SN/A					if (bkgrdflag) {
1130SN/A						unlink(snapname);
1140SN/A						bkgrdflag = 0;
1150SN/A					}
1160SN/A					return (0);
1170SN/A				}
1180SN/A			} else {
1190SN/A				if (bkgrdflag) {
1200SN/A					unlink(snapname);
1210SN/A					bkgrdflag = 0;
1220SN/A				}
1234487SN/A				pfatal("cannot convert a snapshot");
1240SN/A				exit(EEXIT);
1250SN/A			}
1260SN/A		}
1270SN/A	}
1280SN/A	if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
1290SN/A		if (bkgrdflag) {
1300SN/A			unlink(snapname);
1310SN/A			bkgrdflag = 0;
1320SN/A		}
1330SN/A		printf("Can't open %s: %s\n", dev, strerror(errno));
1340SN/A		return (0);
1350SN/A	}
1360SN/A	if (bkgrdflag) {
1370SN/A		unlink(snapname);
1380SN/A		size = MIBSIZE;
1390SN/A		if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0||
1400SN/A		    sysctlnametomib("vfs.ffs.adjblkcnt", adjblkcnt, &size) < 0||
1410SN/A		    sysctlnametomib("vfs.ffs.freefiles", freefiles, &size) < 0||
1420SN/A		    sysctlnametomib("vfs.ffs.freedirs", freedirs, &size) < 0 ||
1430SN/A		    sysctlnametomib("vfs.ffs.freeblks", freeblks, &size) < 0) {
1440SN/A			pfatal("kernel lacks background fsck support\n");
1450SN/A			exit(EEXIT);
1460SN/A		}
1470SN/A		cmd.version = FFS_CMD_VERSION;
1480SN/A		cmd.handle = fsreadfd;
1490SN/A		fswritefd = -1;
1500SN/A	}
1510SN/A	if (preen == 0)
1520SN/A		printf("** %s", dev);
15311287Sweijun	if (bkgrdflag == 0 &&
15411287Sweijun	    (nflag || (fswritefd = open(dev, O_WRONLY)) < 0)) {
15511287Sweijun		fswritefd = -1;
15611287Sweijun		if (preen)
15711287Sweijun			pfatal("NO WRITE ACCESS");
1580SN/A		printf(" (NO WRITE)");
1590SN/A	}
1600SN/A	if (preen == 0)
1610SN/A		printf("\n");
1620SN/A	/*
16311287Sweijun	 * Read in the superblock, looking for alternates if necessary
16411287Sweijun	 */
16511287Sweijun	if (readsb(1) == 0) {
16611287Sweijun		skipclean = 0;
16711287Sweijun		if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
16811287Sweijun			return(0);
16911287Sweijun		if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
17011287Sweijun			return (0);
17111287Sweijun		for (cg = 0; cg < proto.fs_ncg; cg++) {
17211287Sweijun			bflag = fsbtodb(&proto, cgsblock(&proto, cg));
17311287Sweijun			if (readsb(0) != 0)
17411287Sweijun				break;
17511287Sweijun		}
17611287Sweijun		if (cg >= proto.fs_ncg) {
17711287Sweijun			printf("%s %s\n%s %s\n%s %s\n",
17811287Sweijun				"SEARCH FOR ALTERNATE SUPER-BLOCK",
17911287Sweijun				"FAILED. YOU MUST USE THE",
18011287Sweijun				"-b OPTION TO FSCK TO SPECIFY THE",
18111287Sweijun				"LOCATION OF AN ALTERNATE",
18211287Sweijun				"SUPER-BLOCK TO SUPPLY NEEDED",
18311287Sweijun				"INFORMATION; SEE fsck(8).");
18411287Sweijun			bflag = 0;
18511287Sweijun			return(0);
18611287Sweijun		}
18711287Sweijun		pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
1880SN/A		bflag = 0;
1890SN/A	}
1900SN/A	if (skipclean && preen && sblock.fs_clean) {
1910SN/A		pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n");
1920SN/A		return (-1);
1930SN/A	}
1940SN/A	maxfsblock = sblock.fs_size;
1950SN/A	maxino = sblock.fs_ncg * sblock.fs_ipg;
1960SN/A	/*
1970SN/A	 * Check and potentially fix certain fields in the super block.
1980SN/A	 */
1990SN/A	if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) {
2000SN/A		pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
2010SN/A		if (reply("SET TO DEFAULT") == 1) {
2020SN/A			sblock.fs_optim = FS_OPTTIME;
2030SN/A			sbdirty();
2040SN/A		}
2050SN/A	}
2060SN/A	if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) {
2070SN/A		pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
2080SN/A			sblock.fs_minfree);
2090SN/A		if (reply("SET TO DEFAULT") == 1) {
2100SN/A			sblock.fs_minfree = 10;
2110SN/A			sbdirty();
2120SN/A		}
2130SN/A	}
2140SN/A	if (sblock.fs_magic == FS_UFS1_MAGIC &&
2150SN/A	    sblock.fs_old_inodefmt < FS_44INODEFMT) {
2160SN/A		pwarn("Format of file system is too old.\n");
2170SN/A		pwarn("Must update to modern format using a version of fsck\n");
2180SN/A		pfatal("from before 2002 with the command ``fsck -c 2''\n");
2190SN/A		exit(EEXIT);
2200SN/A	}
2210SN/A	if (asblk.b_dirty && !bflag) {
2220SN/A		memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize);
2230SN/A		flush(fswritefd, &asblk);
2240SN/A	}
2250SN/A	/*
2260SN/A	 * read in the summary info.
2270SN/A	 */
2280SN/A	asked = 0;
2290SN/A	sblock.fs_csp = calloc(1, sblock.fs_cssize);
2300SN/A	if (sblock.fs_csp == NULL) {
2310SN/A		printf("cannot alloc %u bytes for cg summary info\n",
2320SN/A		    (unsigned)sblock.fs_cssize);
2330SN/A		goto badsb;
2340SN/A	}
2350SN/A	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
2360SN/A		size = sblock.fs_cssize - i < sblock.fs_bsize ?
2370SN/A		    sblock.fs_cssize - i : sblock.fs_bsize;
2380SN/A		if (bread(fsreadfd, (char *)sblock.fs_csp + i,
2390SN/A		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
2400SN/A		    size) != 0 && !asked) {
2410SN/A			pfatal("BAD SUMMARY INFORMATION");
2420SN/A			if (reply("CONTINUE") == 0) {
2430SN/A				ckfini(0);
2440SN/A				exit(EEXIT);
2450SN/A			}
2460SN/A			asked++;
2470SN/A		}
24811287Sweijun	}
24911287Sweijun	/*
25011287Sweijun	 * allocate and initialize the necessary maps
25111287Sweijun	 */
25211287Sweijun	bmapsize = roundup(howmany(maxfsblock, CHAR_BIT), sizeof(short));
25311287Sweijun	blockmap = calloc((unsigned)bmapsize, sizeof (char));
25411287Sweijun	if (blockmap == NULL) {
25511287Sweijun		printf("cannot alloc %u bytes for blockmap\n",
2560SN/A		    (unsigned)bmapsize);
2570SN/A		goto badsb;
2580SN/A	}
2590SN/A	inostathead = calloc((unsigned)(sblock.fs_ncg),
2600SN/A	    sizeof(struct inostatlist));
2610SN/A	if (inostathead == NULL) {
2620SN/A		printf("cannot alloc %u bytes for inostathead\n",
2630SN/A		    (unsigned)(sizeof(struct inostatlist) * (sblock.fs_ncg)));
2640SN/A		goto badsb;
2650SN/A	}
2660SN/A	numdirs = MAX(sblock.fs_cstotal.cs_ndir, 128);
2670SN/A	dirhash = numdirs;
2680SN/A	inplast = 0;
2690SN/A	listmax = numdirs + 10;
2700SN/A	inpsort = (struct inoinfo **)calloc((unsigned)listmax,
2710SN/A	    sizeof(struct inoinfo *));
2720SN/A	inphead = (struct inoinfo **)calloc((unsigned)numdirs,
2730SN/A	    sizeof(struct inoinfo *));
2740SN/A	if (inpsort == NULL || inphead == NULL) {
2750SN/A		printf("cannot alloc %ju bytes for inphead\n",
2760SN/A		    (uintmax_t)numdirs * sizeof(struct inoinfo *));
2770SN/A		goto badsb;
2780SN/A	}
2790SN/A	bufinit();
2800SN/A	if (sblock.fs_flags & FS_DOSOFTDEP)
2810SN/A		usedsoftdep = 1;
2820SN/A	else
2830SN/A		usedsoftdep = 0;
2840SN/A	return (1);
2850SN/A
2860SN/Abadsb:
2870SN/A	ckfini(0);
2880SN/A	return (0);
2895620SN/A}
2900SN/A
2915620SN/A/*
2920SN/A * Possible superblock locations ordered from most to least likely.
2930SN/A */
2940SN/Astatic int sblock_try[] = SBLOCKSEARCH;
2950SN/A
2960SN/A#define BAD_MAGIC_MSG \
2970SN/A"The previous newfs operation on this volume did not complete.\n" \
2985620SN/A"You must complete newfs before mounting this volume.\n"
2990SN/A
3000SN/A/*
3010SN/A * Read in the super block and its summary info.
3020SN/A */
3030SN/Aint
3040SN/Areadsb(int listerr)
3050SN/A{
3060SN/A	ufs2_daddr_t super;
3070SN/A	int i;
3080SN/A
3090SN/A	if (bflag) {
3100SN/A		super = bflag;
3110SN/A		if ((bread(fsreadfd, (char *)&sblock, super, (long)SBLOCKSIZE)))
3120SN/A			return (0);
3130SN/A		if (sblock.fs_magic == FS_BAD2_MAGIC) {
3145620SN/A			fprintf(stderr, BAD_MAGIC_MSG);
3150SN/A			exit(11);
3160SN/A		}
3170SN/A		if (sblock.fs_magic != FS_UFS1_MAGIC &&
3180SN/A		    sblock.fs_magic != FS_UFS2_MAGIC) {
3190SN/A			fprintf(stderr, "%d is not a file system superblock\n",
3205620SN/A			    bflag);
3210SN/A			return (0);
3220SN/A		}
3230SN/A	} else {
3240SN/A		for (i = 0; sblock_try[i] != -1; i++) {
3250SN/A			super = sblock_try[i] / dev_bsize;
3260SN/A			if ((bread(fsreadfd, (char *)&sblock, super,
3270SN/A			    (long)SBLOCKSIZE)))
3280SN/A				return (0);
3290SN/A			if (sblock.fs_magic == FS_BAD2_MAGIC) {
3300SN/A				fprintf(stderr, BAD_MAGIC_MSG);
3310SN/A				exit(11);
3320SN/A			}
3330SN/A			if ((sblock.fs_magic == FS_UFS1_MAGIC ||
3340SN/A			     (sblock.fs_magic == FS_UFS2_MAGIC &&
3350SN/A			      sblock.fs_sblockloc == sblock_try[i])) &&
3360SN/A			    sblock.fs_ncg >= 1 &&
3375620SN/A			    sblock.fs_bsize >= MINBSIZE &&
3380SN/A			    sblock.fs_bsize >= sizeof(struct fs))
3390SN/A				break;
3400SN/A		}
3410SN/A		if (sblock_try[i] == -1) {
3420SN/A			fprintf(stderr, "Cannot find file system superblock\n");
3430SN/A			return (0);
3440SN/A		}
3450SN/A	}
3460SN/A	/*
3470SN/A	 * Compute block size that the file system is based on,
3480SN/A	 * according to fsbtodb, and adjust superblock block number
3490SN/A	 * so we can tell if this is an alternate later.
3505996SN/A	 */
3511243SN/A	super *= dev_bsize;
3521243SN/A	dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
3531243SN/A	sblk.b_bno = super / dev_bsize;
3540SN/A	sblk.b_size = SBLOCKSIZE;
3550SN/A	if (bflag)
3560SN/A		goto out;
3571243SN/A	/*
3580SN/A	 * Compare all fields that should not differ in alternate super block.
3590SN/A	 * When an alternate super-block is specified this check is skipped.
3601243SN/A	 */
3615996SN/A	getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize);
3625996SN/A	if (asblk.b_errs)
3631243SN/A		return (0);
3641243SN/A	if (altsblock.fs_sblkno != sblock.fs_sblkno ||
3651243SN/A	    altsblock.fs_cblkno != sblock.fs_cblkno ||
3661243SN/A	    altsblock.fs_iblkno != sblock.fs_iblkno ||
3675996SN/A	    altsblock.fs_dblkno != sblock.fs_dblkno ||
3685996SN/A	    altsblock.fs_ncg != sblock.fs_ncg ||
3695996SN/A	    altsblock.fs_bsize != sblock.fs_bsize ||
3705996SN/A	    altsblock.fs_fsize != sblock.fs_fsize ||
3715996SN/A	    altsblock.fs_frag != sblock.fs_frag ||
3725996SN/A	    altsblock.fs_bmask != sblock.fs_bmask ||
3735996SN/A	    altsblock.fs_fmask != sblock.fs_fmask ||
3741243SN/A	    altsblock.fs_bshift != sblock.fs_bshift ||
3751243SN/A	    altsblock.fs_fshift != sblock.fs_fshift ||
3761243SN/A	    altsblock.fs_fragshift != sblock.fs_fragshift ||
3771243SN/A	    altsblock.fs_fsbtodb != sblock.fs_fsbtodb ||
3781243SN/A	    altsblock.fs_sbsize != sblock.fs_sbsize ||
3791243SN/A	    altsblock.fs_nindir != sblock.fs_nindir ||
3801243SN/A	    altsblock.fs_inopb != sblock.fs_inopb ||
3811243SN/A	    altsblock.fs_cssize != sblock.fs_cssize ||
3821243SN/A	    altsblock.fs_ipg != sblock.fs_ipg ||
3830SN/A	    altsblock.fs_fpg != sblock.fs_fpg ||
3840SN/A	    altsblock.fs_magic != sblock.fs_magic) {
3850SN/A		badsb(listerr,
3860SN/A		"VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
3870SN/A		return (0);
3880SN/A	}
3890SN/Aout:
39010475Sweijun	/*
39110475Sweijun	 * If not yet done, update UFS1 superblock with new wider fields.
39210475Sweijun	 */
39311099Smartin	if (sblock.fs_magic == FS_UFS1_MAGIC &&
3940SN/A	    sblock.fs_maxbsize != sblock.fs_bsize) {
39510475Sweijun		sblock.fs_maxbsize = sblock.fs_bsize;
39610475Sweijun		sblock.fs_time = sblock.fs_old_time;
3970SN/A		sblock.fs_size = sblock.fs_old_size;
3980SN/A		sblock.fs_dsize = sblock.fs_old_dsize;
39910475Sweijun		sblock.fs_csaddr = sblock.fs_old_csaddr;
40013418Schegar		sblock.fs_cstotal.cs_ndir = sblock.fs_old_cstotal.cs_ndir;
40110475Sweijun		sblock.fs_cstotal.cs_nbfree = sblock.fs_old_cstotal.cs_nbfree;
40210475Sweijun		sblock.fs_cstotal.cs_nifree = sblock.fs_old_cstotal.cs_nifree;
4030SN/A		sblock.fs_cstotal.cs_nffree = sblock.fs_old_cstotal.cs_nffree;
40410475Sweijun	}
40510475Sweijun	havesb = 1;
40610475Sweijun	return (1);
40710475Sweijun}
40810475Sweijun
40910475Sweijunstatic void
41010475Sweijunbadsb(int listerr, const char *s)
41110475Sweijun{
41210475Sweijun
41310475Sweijun	if (!listerr)
4140SN/A		return;
4150SN/A	if (preen)
4160SN/A		printf("%s: ", cdevname);
4170SN/A	pfatal("BAD SUPER BLOCK: %s\n", s);
4180SN/A}
4190SN/A
4200SN/Avoid
4210SN/Asblock_init(void)
4220SN/A{
4230SN/A	struct disklabel *lp;
4240SN/A
4250SN/A	fswritefd = -1;
4260SN/A	fsmodified = 0;
4270SN/A	lfdir = 0;
4280SN/A	initbarea(&sblk);
4290SN/A	initbarea(&asblk);
4300SN/A	sblk.b_un.b_buf = malloc(SBLOCKSIZE);
4310SN/A	asblk.b_un.b_buf = malloc(SBLOCKSIZE);
4320SN/A	if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
4330SN/A		errx(EEXIT, "cannot allocate space for superblock");
4340SN/A	if ((lp = getdisklabel(NULL, fsreadfd)))
4350SN/A		dev_bsize = secsize = lp->d_secsize;
4360SN/A	else
4370SN/A		dev_bsize = secsize = DEV_BSIZE;
4380SN/A}
4390SN/A
4400SN/A/*
4410SN/A * Calculate a prototype superblock based on information in the disk label.
4420SN/A * When done the cgsblock macro can be calculated and the fs_ncg field
4430SN/A * can be used. Do NOT attempt to use other macros without verifying that
4440SN/A * their needed information is available!
4450SN/A */
4460SN/Astatic int
4470SN/Acalcsb(char *dev, int devfd, struct fs *fs)
4480SN/A{
4490SN/A	struct disklabel *lp;
4500SN/A	struct partition *pp;
4510SN/A	char *cp;
4520SN/A	int i, nspf;
4530SN/A
4540SN/A	cp = strchr(dev, '\0') - 1;
4550SN/A	if (cp == (char *)-1 || ((*cp < 'a' || *cp > 'h') && !isdigit(*cp))) {
4560SN/A		pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
4570SN/A		return (0);
4580SN/A	}
4590SN/A	lp = getdisklabel(dev, devfd);
4600SN/A	if (isdigit(*cp))
4610SN/A		pp = &lp->d_partitions[0];
4620SN/A	else
4630SN/A		pp = &lp->d_partitions[*cp - 'a'];
4640SN/A	if (pp->p_fstype != FS_BSDFFS) {
4650SN/A		pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n",
4660SN/A			dev, pp->p_fstype < FSMAXTYPES ?
4670SN/A			fstypenames[pp->p_fstype] : "unknown");
4680SN/A		return (0);
4690SN/A	}
4700SN/A	if (pp->p_fsize == 0 || pp->p_frag == 0 ||
4710SN/A	    pp->p_cpg == 0 || pp->p_size == 0) {
4720SN/A		pfatal("%s: %s: type %s fsize %d, frag %d, cpg %d, size %d\n",
4730SN/A		    dev, "INCOMPLETE LABEL", fstypenames[pp->p_fstype],
4740SN/A		    pp->p_fsize, pp->p_frag, pp->p_cpg, pp->p_size);
4750SN/A		return (0);
4763388SN/A	}
4770SN/A	memset(fs, 0, sizeof(struct fs));
4780SN/A	fs->fs_fsize = pp->p_fsize;
4790SN/A	fs->fs_frag = pp->p_frag;
4800SN/A	fs->fs_size = pp->p_size;
4810SN/A	fs->fs_sblkno = roundup(
4820SN/A		howmany(lp->d_bbsize + lp->d_sbsize, fs->fs_fsize),
4830SN/A		fs->fs_frag);
4840SN/A	nspf = fs->fs_fsize / lp->d_secsize;
4850SN/A	for (fs->fs_fsbtodb = 0, i = nspf; i > 1; i >>= 1)
4860SN/A		fs->fs_fsbtodb++;
4870SN/A	dev_bsize = lp->d_secsize;
4880SN/A	if (fs->fs_magic == FS_UFS2_MAGIC) {
4890SN/A		fs->fs_fpg = pp->p_cpg;
4900SN/A		fs->fs_ncg = howmany(fs->fs_size, fs->fs_fpg);
4910SN/A	} else /* if (fs->fs_magic == FS_UFS1_MAGIC) */ {
4920SN/A		fs->fs_old_cpg = pp->p_cpg;
4930SN/A		fs->fs_old_cgmask = 0xffffffff;
4940SN/A		for (i = lp->d_ntracks; i > 1; i >>= 1)
4950SN/A			fs->fs_old_cgmask <<= 1;
4960SN/A		if (!POWEROF2(lp->d_ntracks))
4970SN/A			fs->fs_old_cgmask <<= 1;
4980SN/A		fs->fs_old_cgoffset = roundup(howmany(lp->d_nsectors, nspf),
4998565SN/A		    fs->fs_frag);
5000SN/A		fs->fs_fpg = (fs->fs_old_cpg * lp->d_secpercyl) / nspf;
5010SN/A		fs->fs_ncg = howmany(fs->fs_size / lp->d_secpercyl,
5020SN/A		    fs->fs_old_cpg);
5030SN/A	}
5040SN/A	return (1);
5050SN/A}
5060SN/A
5070SN/Astatic struct disklabel *
5080SN/Agetdisklabel(char *s, int fd)
5090SN/A{
5100SN/A	static struct disklabel lab;
5110SN/A
5120SN/A	if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
5130SN/A		if (s == NULL)
5140SN/A			return ((struct disklabel *)NULL);
5150SN/A		pwarn("ioctl (GCINFO): %s\n", strerror(errno));
5160SN/A		errx(EEXIT, "%s: can't read disk label", s);
5170SN/A	}
5180SN/A	return (&lab);
5190SN/A}
5200SN/A