xref: /freebsd/sbin/fsck_ffs/setup.c (revision 780a5c1ec16f889d55914a09fbcde7ff7b2cfcca)
18fae3551SRodney W. Grimes /*
28fae3551SRodney W. Grimes  * Copyright (c) 1980, 1986, 1993
38fae3551SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
48fae3551SRodney W. Grimes  *
58fae3551SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
68fae3551SRodney W. Grimes  * modification, are permitted provided that the following conditions
78fae3551SRodney W. Grimes  * are met:
88fae3551SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
98fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
108fae3551SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
118fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
128fae3551SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
138fae3551SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
148fae3551SRodney W. Grimes  *    must display the following acknowledgement:
158fae3551SRodney W. Grimes  *	This product includes software developed by the University of
168fae3551SRodney W. Grimes  *	California, Berkeley and its contributors.
178fae3551SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
188fae3551SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
198fae3551SRodney W. Grimes  *    without specific prior written permission.
208fae3551SRodney W. Grimes  *
218fae3551SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
228fae3551SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
238fae3551SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
248fae3551SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
258fae3551SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
268fae3551SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
278fae3551SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
288fae3551SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
298fae3551SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
308fae3551SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
318fae3551SRodney W. Grimes  * SUCH DAMAGE.
328fae3551SRodney W. Grimes  */
338fae3551SRodney W. Grimes 
348fae3551SRodney W. Grimes #ifndef lint
35780a5c1eSPeter Wemm static const char sccsid[] = "@(#)setup.c	8.10 (Berkeley) 5/9/95";
368fae3551SRodney W. Grimes #endif /* not lint */
378fae3551SRodney W. Grimes 
388fae3551SRodney W. Grimes #define DKTYPENAMES
398fae3551SRodney W. Grimes #include <sys/param.h>
408fae3551SRodney W. Grimes #include <sys/time.h>
418fae3551SRodney W. Grimes #include <sys/stat.h>
428fae3551SRodney W. Grimes #include <sys/ioctl.h>
438fae3551SRodney W. Grimes #include <sys/disklabel.h>
448fae3551SRodney W. Grimes #include <sys/file.h>
45780a5c1eSPeter Wemm 
46780a5c1eSPeter Wemm #include <ufs/ufs/dinode.h>
47780a5c1eSPeter Wemm #include <ufs/ffs/fs.h>
48780a5c1eSPeter Wemm 
49780a5c1eSPeter Wemm #include <ctype.h>
50780a5c1eSPeter Wemm #include <err.h>
518fae3551SRodney W. Grimes #include <errno.h>
5231f4ab50SBruce Evans #include <stdio.h>
538fae3551SRodney W. Grimes #include <stdlib.h>
548fae3551SRodney W. Grimes #include <string.h>
55780a5c1eSPeter Wemm 
568fae3551SRodney W. Grimes #include "fsck.h"
578fae3551SRodney W. Grimes 
588fae3551SRodney W. Grimes struct bufarea asblk;
598fae3551SRodney W. Grimes #define altsblock (*asblk.b_un.b_fs)
608fae3551SRodney W. Grimes #define POWEROF2(num)	(((num) & ((num) - 1)) == 0)
618fae3551SRodney W. Grimes 
6231f4ab50SBruce Evans static void badsb __P((int listerr, char *s));
6331f4ab50SBruce Evans static int calcsb __P((char *dev, int devfd, struct fs *fs));
6431f4ab50SBruce Evans static struct disklabel *getdisklabel __P((char *s, int fd));
65780a5c1eSPeter Wemm static int readsb __P((int listerr));
668fae3551SRodney W. Grimes 
67780a5c1eSPeter Wemm /*
68780a5c1eSPeter Wemm  * Read in a superblock finding an alternate if necessary.
69780a5c1eSPeter Wemm  * Return 1 if successful, 0 if unsuccessful, -1 if filesystem
70780a5c1eSPeter Wemm  * is already clean (preen mode only).
71780a5c1eSPeter Wemm  */
7231f4ab50SBruce Evans int
738fae3551SRodney W. Grimes setup(dev)
748fae3551SRodney W. Grimes 	char *dev;
758fae3551SRodney W. Grimes {
768fae3551SRodney W. Grimes 	long cg, size, asked, i, j;
77780a5c1eSPeter Wemm 	long skipclean, bmapsize;
788fae3551SRodney W. Grimes 	struct disklabel *lp;
798fae3551SRodney W. Grimes 	off_t sizepb;
808fae3551SRodney W. Grimes 	struct stat statb;
818fae3551SRodney W. Grimes 	struct fs proto;
828fae3551SRodney W. Grimes 
838fae3551SRodney W. Grimes 	havesb = 0;
848fae3551SRodney W. Grimes 	fswritefd = -1;
85780a5c1eSPeter Wemm 	skipclean = preen;
868fae3551SRodney W. Grimes 	if (stat(dev, &statb) < 0) {
878fae3551SRodney W. Grimes 		printf("Can't stat %s: %s\n", dev, strerror(errno));
888fae3551SRodney W. Grimes 		return (0);
898fae3551SRodney W. Grimes 	}
908fae3551SRodney W. Grimes 	if ((statb.st_mode & S_IFMT) != S_IFCHR) {
918fae3551SRodney W. Grimes 		pfatal("%s is not a character device", dev);
928fae3551SRodney W. Grimes 		if (reply("CONTINUE") == 0)
938fae3551SRodney W. Grimes 			return (0);
948fae3551SRodney W. Grimes 	}
958fae3551SRodney W. Grimes 	if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
968fae3551SRodney W. Grimes 		printf("Can't open %s: %s\n", dev, strerror(errno));
978fae3551SRodney W. Grimes 		return (0);
988fae3551SRodney W. Grimes 	}
998fae3551SRodney W. Grimes 	if (preen == 0)
1008fae3551SRodney W. Grimes 		printf("** %s", dev);
1018fae3551SRodney W. Grimes 	if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) {
1028fae3551SRodney W. Grimes 		fswritefd = -1;
1038fae3551SRodney W. Grimes 		if (preen)
1048fae3551SRodney W. Grimes 			pfatal("NO WRITE ACCESS");
1058fae3551SRodney W. Grimes 		printf(" (NO WRITE)");
1068fae3551SRodney W. Grimes 	}
1078fae3551SRodney W. Grimes 	if (preen == 0)
1088fae3551SRodney W. Grimes 		printf("\n");
1098fae3551SRodney W. Grimes 	fsmodified = 0;
1108fae3551SRodney W. Grimes 	lfdir = 0;
1118fae3551SRodney W. Grimes 	initbarea(&sblk);
1128fae3551SRodney W. Grimes 	initbarea(&asblk);
1138fae3551SRodney W. Grimes 	sblk.b_un.b_buf = malloc(SBSIZE);
1148fae3551SRodney W. Grimes 	asblk.b_un.b_buf = malloc(SBSIZE);
1158fae3551SRodney W. Grimes 	if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
116780a5c1eSPeter Wemm 		errx(EEXIT, "cannot allocate space for superblock");
11731f4ab50SBruce Evans 	lp = getdisklabel((char *)NULL, fsreadfd);
11831f4ab50SBruce Evans 	if (lp)
1198fae3551SRodney W. Grimes 		dev_bsize = secsize = lp->d_secsize;
1208fae3551SRodney W. Grimes 	else
1218fae3551SRodney W. Grimes 		dev_bsize = secsize = DEV_BSIZE;
1228fae3551SRodney W. Grimes 	/*
1238fae3551SRodney W. Grimes 	 * Read in the superblock, looking for alternates if necessary
1248fae3551SRodney W. Grimes 	 */
1258fae3551SRodney W. Grimes 	if (readsb(1) == 0) {
126780a5c1eSPeter Wemm 		skipclean = 0;
1278fae3551SRodney W. Grimes 		if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
1288fae3551SRodney W. Grimes 			return(0);
1298fae3551SRodney W. Grimes 		if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
1308fae3551SRodney W. Grimes 			return (0);
1318fae3551SRodney W. Grimes 		for (cg = 0; cg < proto.fs_ncg; cg++) {
1328fae3551SRodney W. Grimes 			bflag = fsbtodb(&proto, cgsblock(&proto, cg));
1338fae3551SRodney W. Grimes 			if (readsb(0) != 0)
1348fae3551SRodney W. Grimes 				break;
1358fae3551SRodney W. Grimes 		}
1368fae3551SRodney W. Grimes 		if (cg >= proto.fs_ncg) {
1378fae3551SRodney W. Grimes 			printf("%s %s\n%s %s\n%s %s\n",
1388fae3551SRodney W. Grimes 				"SEARCH FOR ALTERNATE SUPER-BLOCK",
1398fae3551SRodney W. Grimes 				"FAILED. YOU MUST USE THE",
1408fae3551SRodney W. Grimes 				"-b OPTION TO FSCK TO SPECIFY THE",
1418fae3551SRodney W. Grimes 				"LOCATION OF AN ALTERNATE",
1428fae3551SRodney W. Grimes 				"SUPER-BLOCK TO SUPPLY NEEDED",
1438fae3551SRodney W. Grimes 				"INFORMATION; SEE fsck(8).");
1441e30185aSBruce Evans 			bflag = 0;
1458fae3551SRodney W. Grimes 			return(0);
1468fae3551SRodney W. Grimes 		}
1478fae3551SRodney W. Grimes 		pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
1481e30185aSBruce Evans 		bflag = 0;
1498fae3551SRodney W. Grimes 	}
150780a5c1eSPeter Wemm 	if (skipclean && sblock.fs_clean) {
151780a5c1eSPeter Wemm 		pwarn("FILESYSTEM CLEAN; SKIPPING CHECKS\n");
152780a5c1eSPeter Wemm 		return (-1);
153780a5c1eSPeter Wemm 	}
1548fae3551SRodney W. Grimes 	maxfsblock = sblock.fs_size;
1558fae3551SRodney W. Grimes 	maxino = sblock.fs_ncg * sblock.fs_ipg;
1568fae3551SRodney W. Grimes 	/*
1578fae3551SRodney W. Grimes 	 * Check and potentially fix certain fields in the super block.
1588fae3551SRodney W. Grimes 	 */
1598fae3551SRodney W. Grimes 	if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) {
1608fae3551SRodney W. Grimes 		pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
1618fae3551SRodney W. Grimes 		if (reply("SET TO DEFAULT") == 1) {
1628fae3551SRodney W. Grimes 			sblock.fs_optim = FS_OPTTIME;
1638fae3551SRodney W. Grimes 			sbdirty();
1648fae3551SRodney W. Grimes 		}
1658fae3551SRodney W. Grimes 	}
1668fae3551SRodney W. Grimes 	if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) {
1678fae3551SRodney W. Grimes 		pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
1688fae3551SRodney W. Grimes 			sblock.fs_minfree);
1698fae3551SRodney W. Grimes 		if (reply("SET TO DEFAULT") == 1) {
1708fae3551SRodney W. Grimes 			sblock.fs_minfree = 10;
1718fae3551SRodney W. Grimes 			sbdirty();
1728fae3551SRodney W. Grimes 		}
1738fae3551SRodney W. Grimes 	}
1748fae3551SRodney W. Grimes 	if (sblock.fs_interleave < 1 ||
1758fae3551SRodney W. Grimes 	    sblock.fs_interleave > sblock.fs_nsect) {
1768fae3551SRodney W. Grimes 		pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK",
1778fae3551SRodney W. Grimes 			sblock.fs_interleave);
1788fae3551SRodney W. Grimes 		sblock.fs_interleave = 1;
1798fae3551SRodney W. Grimes 		if (preen)
1808fae3551SRodney W. Grimes 			printf(" (FIXED)\n");
1818fae3551SRodney W. Grimes 		if (preen || reply("SET TO DEFAULT") == 1) {
1828fae3551SRodney W. Grimes 			sbdirty();
1838fae3551SRodney W. Grimes 			dirty(&asblk);
1848fae3551SRodney W. Grimes 		}
1858fae3551SRodney W. Grimes 	}
1868fae3551SRodney W. Grimes 	if (sblock.fs_npsect < sblock.fs_nsect ||
1878fae3551SRodney W. Grimes 	    sblock.fs_npsect > sblock.fs_nsect*2) {
1888fae3551SRodney W. Grimes 		pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK",
1898fae3551SRodney W. Grimes 			sblock.fs_npsect);
1908fae3551SRodney W. Grimes 		sblock.fs_npsect = sblock.fs_nsect;
1918fae3551SRodney W. Grimes 		if (preen)
1928fae3551SRodney W. Grimes 			printf(" (FIXED)\n");
1938fae3551SRodney W. Grimes 		if (preen || reply("SET TO DEFAULT") == 1) {
1948fae3551SRodney W. Grimes 			sbdirty();
1958fae3551SRodney W. Grimes 			dirty(&asblk);
1968fae3551SRodney W. Grimes 		}
1978fae3551SRodney W. Grimes 	}
1988fae3551SRodney W. Grimes 	if (sblock.fs_inodefmt >= FS_44INODEFMT) {
1998fae3551SRodney W. Grimes 		newinofmt = 1;
2008fae3551SRodney W. Grimes 	} else {
2018fae3551SRodney W. Grimes 		sblock.fs_qbmask = ~sblock.fs_bmask;
2028fae3551SRodney W. Grimes 		sblock.fs_qfmask = ~sblock.fs_fmask;
2038fae3551SRodney W. Grimes 		newinofmt = 0;
2048fae3551SRodney W. Grimes 	}
2058fae3551SRodney W. Grimes 	/*
2068fae3551SRodney W. Grimes 	 * Convert to new inode format.
2078fae3551SRodney W. Grimes 	 */
2088fae3551SRodney W. Grimes 	if (cvtlevel >= 2 && sblock.fs_inodefmt < FS_44INODEFMT) {
2098fae3551SRodney W. Grimes 		if (preen)
2108fae3551SRodney W. Grimes 			pwarn("CONVERTING TO NEW INODE FORMAT\n");
2118fae3551SRodney W. Grimes 		else if (!reply("CONVERT TO NEW INODE FORMAT"))
2128fae3551SRodney W. Grimes 			return(0);
2138fae3551SRodney W. Grimes 		doinglevel2++;
2148fae3551SRodney W. Grimes 		sblock.fs_inodefmt = FS_44INODEFMT;
2158fae3551SRodney W. Grimes 		sizepb = sblock.fs_bsize;
2168fae3551SRodney W. Grimes 		sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1;
2178fae3551SRodney W. Grimes 		for (i = 0; i < NIADDR; i++) {
2188fae3551SRodney W. Grimes 			sizepb *= NINDIR(&sblock);
2198fae3551SRodney W. Grimes 			sblock.fs_maxfilesize += sizepb;
2208fae3551SRodney W. Grimes 		}
2218fae3551SRodney W. Grimes 		sblock.fs_maxsymlinklen = MAXSYMLINKLEN;
2228fae3551SRodney W. Grimes 		sblock.fs_qbmask = ~sblock.fs_bmask;
2238fae3551SRodney W. Grimes 		sblock.fs_qfmask = ~sblock.fs_fmask;
2248fae3551SRodney W. Grimes 		sbdirty();
2258fae3551SRodney W. Grimes 		dirty(&asblk);
2268fae3551SRodney W. Grimes 	}
2278fae3551SRodney W. Grimes 	/*
2288fae3551SRodney W. Grimes 	 * Convert to new cylinder group format.
2298fae3551SRodney W. Grimes 	 */
2308fae3551SRodney W. Grimes 	if (cvtlevel >= 1 && sblock.fs_postblformat == FS_42POSTBLFMT) {
2318fae3551SRodney W. Grimes 		if (preen)
2328fae3551SRodney W. Grimes 			pwarn("CONVERTING TO NEW CYLINDER GROUP FORMAT\n");
2338fae3551SRodney W. Grimes 		else if (!reply("CONVERT TO NEW CYLINDER GROUP FORMAT"))
2348fae3551SRodney W. Grimes 			return(0);
2358fae3551SRodney W. Grimes 		doinglevel1++;
2368fae3551SRodney W. Grimes 		sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT;
2378fae3551SRodney W. Grimes 		sblock.fs_nrpos = 8;
2388fae3551SRodney W. Grimes 		sblock.fs_postbloff =
2398fae3551SRodney W. Grimes 		    (char *)(&sblock.fs_opostbl[0][0]) -
240780a5c1eSPeter Wemm 		    (char *)(&sblock.fs_firstfield);
2418fae3551SRodney W. Grimes 		sblock.fs_rotbloff = &sblock.fs_space[0] -
242780a5c1eSPeter Wemm 		    (u_char *)(&sblock.fs_firstfield);
2438fae3551SRodney W. Grimes 		sblock.fs_cgsize =
2448fae3551SRodney W. Grimes 			fragroundup(&sblock, CGSIZE(&sblock));
2458fae3551SRodney W. Grimes 		sbdirty();
2468fae3551SRodney W. Grimes 		dirty(&asblk);
2478fae3551SRodney W. Grimes 	}
248780a5c1eSPeter Wemm 	if (asblk.b_dirty && !bflag) {
249780a5c1eSPeter Wemm 		memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize);
2508fae3551SRodney W. Grimes 		flush(fswritefd, &asblk);
2518fae3551SRodney W. Grimes 	}
2528fae3551SRodney W. Grimes 	/*
2538fae3551SRodney W. Grimes 	 * read in the summary info.
2548fae3551SRodney W. Grimes 	 */
2558fae3551SRodney W. Grimes 	asked = 0;
2568fae3551SRodney W. Grimes 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
2578fae3551SRodney W. Grimes 		size = sblock.fs_cssize - i < sblock.fs_bsize ?
2588fae3551SRodney W. Grimes 		    sblock.fs_cssize - i : sblock.fs_bsize;
2598fae3551SRodney W. Grimes 		sblock.fs_csp[j] = (struct csum *)calloc(1, (unsigned)size);
2608fae3551SRodney W. Grimes 		if (bread(fsreadfd, (char *)sblock.fs_csp[j],
2618fae3551SRodney W. Grimes 		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
2628fae3551SRodney W. Grimes 		    size) != 0 && !asked) {
2638fae3551SRodney W. Grimes 			pfatal("BAD SUMMARY INFORMATION");
2648fae3551SRodney W. Grimes 			if (reply("CONTINUE") == 0)
265780a5c1eSPeter Wemm 				exit(EEXIT);
2668fae3551SRodney W. Grimes 			asked++;
2678fae3551SRodney W. Grimes 		}
2688fae3551SRodney W. Grimes 	}
2698fae3551SRodney W. Grimes 	/*
2708fae3551SRodney W. Grimes 	 * allocate and initialize the necessary maps
2718fae3551SRodney W. Grimes 	 */
2728fae3551SRodney W. Grimes 	bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(short));
2738fae3551SRodney W. Grimes 	blockmap = calloc((unsigned)bmapsize, sizeof (char));
2748fae3551SRodney W. Grimes 	if (blockmap == NULL) {
2758fae3551SRodney W. Grimes 		printf("cannot alloc %u bytes for blockmap\n",
2768fae3551SRodney W. Grimes 		    (unsigned)bmapsize);
2778fae3551SRodney W. Grimes 		goto badsb;
2788fae3551SRodney W. Grimes 	}
2798fae3551SRodney W. Grimes 	statemap = calloc((unsigned)(maxino + 1), sizeof(char));
2808fae3551SRodney W. Grimes 	if (statemap == NULL) {
2818fae3551SRodney W. Grimes 		printf("cannot alloc %u bytes for statemap\n",
2828fae3551SRodney W. Grimes 		    (unsigned)(maxino + 1));
2838fae3551SRodney W. Grimes 		goto badsb;
2848fae3551SRodney W. Grimes 	}
2858fae3551SRodney W. Grimes 	typemap = calloc((unsigned)(maxino + 1), sizeof(char));
2868fae3551SRodney W. Grimes 	if (typemap == NULL) {
2878fae3551SRodney W. Grimes 		printf("cannot alloc %u bytes for typemap\n",
2888fae3551SRodney W. Grimes 		    (unsigned)(maxino + 1));
2898fae3551SRodney W. Grimes 		goto badsb;
2908fae3551SRodney W. Grimes 	}
2918fae3551SRodney W. Grimes 	lncntp = (short *)calloc((unsigned)(maxino + 1), sizeof(short));
2928fae3551SRodney W. Grimes 	if (lncntp == NULL) {
2938fae3551SRodney W. Grimes 		printf("cannot alloc %u bytes for lncntp\n",
2948fae3551SRodney W. Grimes 		    (unsigned)(maxino + 1) * sizeof(short));
2958fae3551SRodney W. Grimes 		goto badsb;
2968fae3551SRodney W. Grimes 	}
2978fae3551SRodney W. Grimes 	numdirs = sblock.fs_cstotal.cs_ndir;
2988fae3551SRodney W. Grimes 	inplast = 0;
2998fae3551SRodney W. Grimes 	listmax = numdirs + 10;
3008fae3551SRodney W. Grimes 	inpsort = (struct inoinfo **)calloc((unsigned)listmax,
3018fae3551SRodney W. Grimes 	    sizeof(struct inoinfo *));
3028fae3551SRodney W. Grimes 	inphead = (struct inoinfo **)calloc((unsigned)numdirs,
3038fae3551SRodney W. Grimes 	    sizeof(struct inoinfo *));
3048fae3551SRodney W. Grimes 	if (inpsort == NULL || inphead == NULL) {
3058fae3551SRodney W. Grimes 		printf("cannot alloc %u bytes for inphead\n",
3068fae3551SRodney W. Grimes 		    (unsigned)numdirs * sizeof(struct inoinfo *));
3078fae3551SRodney W. Grimes 		goto badsb;
3088fae3551SRodney W. Grimes 	}
3098fae3551SRodney W. Grimes 	bufinit();
3108fae3551SRodney W. Grimes 	return (1);
3118fae3551SRodney W. Grimes 
3128fae3551SRodney W. Grimes badsb:
313780a5c1eSPeter Wemm 	ckfini(0);
3148fae3551SRodney W. Grimes 	return (0);
3158fae3551SRodney W. Grimes }
3168fae3551SRodney W. Grimes 
3178fae3551SRodney W. Grimes /*
3188fae3551SRodney W. Grimes  * Read in the super block and its summary info.
3198fae3551SRodney W. Grimes  */
32031f4ab50SBruce Evans static int
3218fae3551SRodney W. Grimes readsb(listerr)
3228fae3551SRodney W. Grimes 	int listerr;
3238fae3551SRodney W. Grimes {
324780a5c1eSPeter Wemm 	ufs_daddr_t super = bflag ? bflag : SBOFF / dev_bsize;
3258fae3551SRodney W. Grimes 
3268fae3551SRodney W. Grimes 	if (bread(fsreadfd, (char *)&sblock, super, (long)SBSIZE) != 0)
3278fae3551SRodney W. Grimes 		return (0);
3288fae3551SRodney W. Grimes 	sblk.b_bno = super;
3298fae3551SRodney W. Grimes 	sblk.b_size = SBSIZE;
3308fae3551SRodney W. Grimes 	/*
3318fae3551SRodney W. Grimes 	 * run a few consistency checks of the super block
3328fae3551SRodney W. Grimes 	 */
3338fae3551SRodney W. Grimes 	if (sblock.fs_magic != FS_MAGIC)
3348fae3551SRodney W. Grimes 		{ badsb(listerr, "MAGIC NUMBER WRONG"); return (0); }
3358fae3551SRodney W. Grimes 	if (sblock.fs_ncg < 1)
3368fae3551SRodney W. Grimes 		{ badsb(listerr, "NCG OUT OF RANGE"); return (0); }
3378fae3551SRodney W. Grimes 	if (sblock.fs_cpg < 1)
3388fae3551SRodney W. Grimes 		{ badsb(listerr, "CPG OUT OF RANGE"); return (0); }
3398fae3551SRodney W. Grimes 	if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
3408fae3551SRodney W. Grimes 	    (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
3418fae3551SRodney W. Grimes 		{ badsb(listerr, "NCYL LESS THAN NCG*CPG"); return (0); }
3428fae3551SRodney W. Grimes 	if (sblock.fs_sbsize > SBSIZE)
3438fae3551SRodney W. Grimes 		{ badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); }
3448fae3551SRodney W. Grimes 	/*
3458fae3551SRodney W. Grimes 	 * Compute block size that the filesystem is based on,
3468fae3551SRodney W. Grimes 	 * according to fsbtodb, and adjust superblock block number
3478fae3551SRodney W. Grimes 	 * so we can tell if this is an alternate later.
3488fae3551SRodney W. Grimes 	 */
3498fae3551SRodney W. Grimes 	super *= dev_bsize;
3508fae3551SRodney W. Grimes 	dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
3518fae3551SRodney W. Grimes 	sblk.b_bno = super / dev_bsize;
3528fae3551SRodney W. Grimes 	if (bflag) {
3538fae3551SRodney W. Grimes 		havesb = 1;
3548fae3551SRodney W. Grimes 		return (1);
3558fae3551SRodney W. Grimes 	}
3568fae3551SRodney W. Grimes 	/*
3578fae3551SRodney W. Grimes 	 * Set all possible fields that could differ, then do check
3588fae3551SRodney W. Grimes 	 * of whole super block against an alternate super block.
3598fae3551SRodney W. Grimes 	 * When an alternate super-block is specified this check is skipped.
3608fae3551SRodney W. Grimes 	 */
3618fae3551SRodney W. Grimes 	getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize);
3628fae3551SRodney W. Grimes 	if (asblk.b_errs)
3638fae3551SRodney W. Grimes 		return (0);
364780a5c1eSPeter Wemm 	altsblock.fs_firstfield = sblock.fs_firstfield;
365780a5c1eSPeter Wemm 	altsblock.fs_unused_1 = sblock.fs_unused_1;
3668fae3551SRodney W. Grimes 	altsblock.fs_time = sblock.fs_time;
3678fae3551SRodney W. Grimes 	altsblock.fs_cstotal = sblock.fs_cstotal;
3688fae3551SRodney W. Grimes 	altsblock.fs_cgrotor = sblock.fs_cgrotor;
3698fae3551SRodney W. Grimes 	altsblock.fs_fmod = sblock.fs_fmod;
3708fae3551SRodney W. Grimes 	altsblock.fs_clean = sblock.fs_clean;
3718fae3551SRodney W. Grimes 	altsblock.fs_ronly = sblock.fs_ronly;
3728fae3551SRodney W. Grimes 	altsblock.fs_flags = sblock.fs_flags;
3738fae3551SRodney W. Grimes 	altsblock.fs_maxcontig = sblock.fs_maxcontig;
3748fae3551SRodney W. Grimes 	altsblock.fs_minfree = sblock.fs_minfree;
3758fae3551SRodney W. Grimes 	altsblock.fs_optim = sblock.fs_optim;
3768fae3551SRodney W. Grimes 	altsblock.fs_rotdelay = sblock.fs_rotdelay;
3778fae3551SRodney W. Grimes 	altsblock.fs_maxbpg = sblock.fs_maxbpg;
378780a5c1eSPeter Wemm 	memmove(altsblock.fs_csp, sblock.fs_csp, sizeof sblock.fs_csp);
379780a5c1eSPeter Wemm 	altsblock.fs_maxcluster = sblock.fs_maxcluster;
380780a5c1eSPeter Wemm 	memmove(altsblock.fs_fsmnt, sblock.fs_fsmnt, sizeof sblock.fs_fsmnt);
381780a5c1eSPeter Wemm 	memmove(altsblock.fs_sparecon,
382780a5c1eSPeter Wemm 		sblock.fs_sparecon, sizeof sblock.fs_sparecon);
3838fae3551SRodney W. Grimes 	/*
3848fae3551SRodney W. Grimes 	 * The following should not have to be copied.
3858fae3551SRodney W. Grimes 	 */
3868fae3551SRodney W. Grimes 	altsblock.fs_fsbtodb = sblock.fs_fsbtodb;
3878fae3551SRodney W. Grimes 	altsblock.fs_interleave = sblock.fs_interleave;
3888fae3551SRodney W. Grimes 	altsblock.fs_npsect = sblock.fs_npsect;
3898fae3551SRodney W. Grimes 	altsblock.fs_nrpos = sblock.fs_nrpos;
390780a5c1eSPeter Wemm 	altsblock.fs_state = sblock.fs_state;
3918fae3551SRodney W. Grimes 	altsblock.fs_qbmask = sblock.fs_qbmask;
3928fae3551SRodney W. Grimes 	altsblock.fs_qfmask = sblock.fs_qfmask;
3938fae3551SRodney W. Grimes 	altsblock.fs_state = sblock.fs_state;
3948fae3551SRodney W. Grimes 	altsblock.fs_maxfilesize = sblock.fs_maxfilesize;
395780a5c1eSPeter Wemm 	if (memcmp(&sblock, &altsblock, (int)sblock.fs_sbsize)) {
396780a5c1eSPeter Wemm 		if (debug) {
397780a5c1eSPeter Wemm 			long *nlp, *olp, *endlp;
398780a5c1eSPeter Wemm 
399780a5c1eSPeter Wemm 			printf("superblock mismatches\n");
400780a5c1eSPeter Wemm 			nlp = (long *)&altsblock;
401780a5c1eSPeter Wemm 			olp = (long *)&sblock;
402780a5c1eSPeter Wemm 			endlp = olp + (sblock.fs_sbsize / sizeof *olp);
403780a5c1eSPeter Wemm 			for ( ; olp < endlp; olp++, nlp++) {
404780a5c1eSPeter Wemm 				if (*olp == *nlp)
405780a5c1eSPeter Wemm 					continue;
406780a5c1eSPeter Wemm 				printf("offset %d, original %d, alternate %d\n",
407780a5c1eSPeter Wemm 				    olp - (long *)&sblock, *olp, *nlp);
408780a5c1eSPeter Wemm 			}
409780a5c1eSPeter Wemm 		}
4108fae3551SRodney W. Grimes 		badsb(listerr,
4118fae3551SRodney W. Grimes 		"VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
4128fae3551SRodney W. Grimes 		return (0);
4138fae3551SRodney W. Grimes 	}
4148fae3551SRodney W. Grimes 	havesb = 1;
4158fae3551SRodney W. Grimes 	return (1);
4168fae3551SRodney W. Grimes }
4178fae3551SRodney W. Grimes 
41831f4ab50SBruce Evans static void
4198fae3551SRodney W. Grimes badsb(listerr, s)
4208fae3551SRodney W. Grimes 	int listerr;
4218fae3551SRodney W. Grimes 	char *s;
4228fae3551SRodney W. Grimes {
4238fae3551SRodney W. Grimes 
4248fae3551SRodney W. Grimes 	if (!listerr)
4258fae3551SRodney W. Grimes 		return;
4268fae3551SRodney W. Grimes 	if (preen)
4278fae3551SRodney W. Grimes 		printf("%s: ", cdevname);
4288fae3551SRodney W. Grimes 	pfatal("BAD SUPER BLOCK: %s\n", s);
4298fae3551SRodney W. Grimes }
4308fae3551SRodney W. Grimes 
4318fae3551SRodney W. Grimes /*
4328fae3551SRodney W. Grimes  * Calculate a prototype superblock based on information in the disk label.
4338fae3551SRodney W. Grimes  * When done the cgsblock macro can be calculated and the fs_ncg field
4348fae3551SRodney W. Grimes  * can be used. Do NOT attempt to use other macros without verifying that
4358fae3551SRodney W. Grimes  * their needed information is available!
4368fae3551SRodney W. Grimes  */
437780a5c1eSPeter Wemm static int
4388fae3551SRodney W. Grimes calcsb(dev, devfd, fs)
4398fae3551SRodney W. Grimes 	char *dev;
4408fae3551SRodney W. Grimes 	int devfd;
4418fae3551SRodney W. Grimes 	register struct fs *fs;
4428fae3551SRodney W. Grimes {
4438fae3551SRodney W. Grimes 	register struct disklabel *lp;
4448fae3551SRodney W. Grimes 	register struct partition *pp;
4458fae3551SRodney W. Grimes 	register char *cp;
4468fae3551SRodney W. Grimes 	int i;
4478fae3551SRodney W. Grimes 
448780a5c1eSPeter Wemm 	cp = strchr(dev, '\0') - 1;
44931f4ab50SBruce Evans 	if (cp == (char *)-1 || ((*cp < 'a' || *cp > 'h') && !isdigit(*cp))) {
4508fae3551SRodney W. Grimes 		pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
4518fae3551SRodney W. Grimes 		return (0);
4528fae3551SRodney W. Grimes 	}
4538fae3551SRodney W. Grimes 	lp = getdisklabel(dev, devfd);
4548fae3551SRodney W. Grimes 	if (isdigit(*cp))
4558fae3551SRodney W. Grimes 		pp = &lp->d_partitions[0];
4568fae3551SRodney W. Grimes 	else
4578fae3551SRodney W. Grimes 		pp = &lp->d_partitions[*cp - 'a'];
4588fae3551SRodney W. Grimes 	if (pp->p_fstype != FS_BSDFFS) {
4598fae3551SRodney W. Grimes 		pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n",
4608fae3551SRodney W. Grimes 			dev, pp->p_fstype < FSMAXTYPES ?
4618fae3551SRodney W. Grimes 			fstypenames[pp->p_fstype] : "unknown");
4628fae3551SRodney W. Grimes 		return (0);
4638fae3551SRodney W. Grimes 	}
464780a5c1eSPeter Wemm 	memset(fs, 0, sizeof(struct fs));
4658fae3551SRodney W. Grimes 	fs->fs_fsize = pp->p_fsize;
4668fae3551SRodney W. Grimes 	fs->fs_frag = pp->p_frag;
4678fae3551SRodney W. Grimes 	fs->fs_cpg = pp->p_cpg;
4688fae3551SRodney W. Grimes 	fs->fs_size = pp->p_size;
4698fae3551SRodney W. Grimes 	fs->fs_ntrak = lp->d_ntracks;
4708fae3551SRodney W. Grimes 	fs->fs_nsect = lp->d_nsectors;
4718fae3551SRodney W. Grimes 	fs->fs_spc = lp->d_secpercyl;
4728fae3551SRodney W. Grimes 	fs->fs_nspf = fs->fs_fsize / lp->d_secsize;
4738fae3551SRodney W. Grimes 	fs->fs_sblkno = roundup(
4748fae3551SRodney W. Grimes 		howmany(lp->d_bbsize + lp->d_sbsize, fs->fs_fsize),
4758fae3551SRodney W. Grimes 		fs->fs_frag);
4768fae3551SRodney W. Grimes 	fs->fs_cgmask = 0xffffffff;
4778fae3551SRodney W. Grimes 	for (i = fs->fs_ntrak; i > 1; i >>= 1)
4788fae3551SRodney W. Grimes 		fs->fs_cgmask <<= 1;
4798fae3551SRodney W. Grimes 	if (!POWEROF2(fs->fs_ntrak))
4808fae3551SRodney W. Grimes 		fs->fs_cgmask <<= 1;
4818fae3551SRodney W. Grimes 	fs->fs_cgoffset = roundup(
4828fae3551SRodney W. Grimes 		howmany(fs->fs_nsect, NSPF(fs)), fs->fs_frag);
4838fae3551SRodney W. Grimes 	fs->fs_fpg = (fs->fs_cpg * fs->fs_spc) / NSPF(fs);
4848fae3551SRodney W. Grimes 	fs->fs_ncg = howmany(fs->fs_size / fs->fs_spc, fs->fs_cpg);
4858fae3551SRodney W. Grimes 	for (fs->fs_fsbtodb = 0, i = NSPF(fs); i > 1; i >>= 1)
4868fae3551SRodney W. Grimes 		fs->fs_fsbtodb++;
4878fae3551SRodney W. Grimes 	dev_bsize = lp->d_secsize;
4888fae3551SRodney W. Grimes 	return (1);
4898fae3551SRodney W. Grimes }
4908fae3551SRodney W. Grimes 
491780a5c1eSPeter Wemm static struct disklabel *
4928fae3551SRodney W. Grimes getdisklabel(s, fd)
4938fae3551SRodney W. Grimes 	char *s;
4948fae3551SRodney W. Grimes 	int	fd;
4958fae3551SRodney W. Grimes {
4968fae3551SRodney W. Grimes 	static struct disklabel lab;
4978fae3551SRodney W. Grimes 
4988fae3551SRodney W. Grimes 	if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
4998fae3551SRodney W. Grimes 		if (s == NULL)
5008fae3551SRodney W. Grimes 			return ((struct disklabel *)NULL);
5018fae3551SRodney W. Grimes 		pwarn("ioctl (GCINFO): %s\n", strerror(errno));
502780a5c1eSPeter Wemm 		errx(EEXIT, "%s: can't read disk label", s);
5038fae3551SRodney W. Grimes 	}
5048fae3551SRodney W. Grimes 	return (&lab);
5058fae3551SRodney W. Grimes }
506