2 * Copyright (c) 1980, 1986, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * @(#)setup.c 8.10 (Berkeley) 5/9/95
34 * $FreeBSD: src/sbin/fsck/setup.c,v 1.17.2.4 2002/06/24 05:10:41 dillon Exp $
35 * $DragonFly: src/sbin/fsck/setup.c,v 1.8 2007/05/20 20:29:01 dillon Exp $
39 #include <sys/param.h>
41 #include <sys/diskslice.h>
44 #include <vfs/ufs/dinode.h>
45 #include <vfs/ufs/fs.h>
55 #define altsblock (*asblk.b_un.b_fs)
56 #define POWEROF2(num) (((num) & ((num) - 1)) == 0)
58 static void badsb(int listerr
, char *s
);
59 static int readsb(int listerr
);
62 * Read in a superblock finding an alternate if necessary.
63 * Return 1 if successful, 0 if unsuccessful, -1 if filesystem
64 * is already clean (preen mode only).
69 long cg
, size
, asked
, i
, j
;
70 long skipclean
, bmapsize
;
77 skipclean
= fflag
? 0 : preen
;
78 if (stat(dev
, &statb
) < 0) {
79 printf("Can't stat %s: %s\n", dev
, strerror(errno
));
82 if ((statb
.st_mode
& S_IFMT
) != S_IFCHR
&&
83 (statb
.st_mode
& S_IFMT
) != S_IFBLK
) {
84 pfatal("%s is not a disk device", dev
);
85 if (reply("CONTINUE") == 0)
88 if ((fsreadfd
= open(dev
, O_RDONLY
)) < 0) {
89 printf("Can't open %s: %s\n", dev
, strerror(errno
));
94 if (nflag
|| (fswritefd
= open(dev
, O_WRONLY
)) < 0) {
97 pfatal("NO WRITE ACCESS");
98 printf(" (NO WRITE)");
106 sblk
.b_un
.b_buf
= malloc(SBSIZE
);
107 asblk
.b_un
.b_buf
= malloc(SBSIZE
);
108 if (sblk
.b_un
.b_buf
== NULL
|| asblk
.b_un
.b_buf
== NULL
)
109 errx(EEXIT
, "cannot allocate space for superblock");
112 * Figure out the device block size and the sector size. The
113 * block size is updated by readsb() later on.
116 struct partinfo pinfo
;
118 if (ioctl(fsreadfd
, DIOCGPART
, &pinfo
) == 0) {
119 dev_bsize
= secsize
= pinfo
.media_blksize
;
121 dev_bsize
= secsize
= DEV_BSIZE
;
126 * Read in the superblock, looking for alternates if necessary
128 if (readsb(1) == 0) {
132 if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
135 if (readsb(0) == 0) {
137 "YOU MUST USE THE -b OPTION TO FSCK TO SPECIFY\n"
138 "THE LOCATION OF AN ALTERNATE SUPER-BLOCK TO\n"
139 "SUPPLY NEEDED INFORMATION; SEE fsck(8).");
143 pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag
);
146 if (skipclean
&& sblock
.fs_clean
) {
147 pwarn("FILESYSTEM CLEAN; SKIPPING CHECKS\n");
150 maxfsblock
= sblock
.fs_size
;
151 maxino
= sblock
.fs_ncg
* sblock
.fs_ipg
;
153 * Check and potentially fix certain fields in the super block.
155 if (sblock
.fs_optim
!= FS_OPTTIME
&& sblock
.fs_optim
!= FS_OPTSPACE
) {
156 pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
157 if (reply("SET TO DEFAULT") == 1) {
158 sblock
.fs_optim
= FS_OPTTIME
;
162 if ((sblock
.fs_minfree
< 0 || sblock
.fs_minfree
> 99)) {
163 pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
165 if (reply("SET TO DEFAULT") == 1) {
166 sblock
.fs_minfree
= 10;
170 if (sblock
.fs_interleave
< 1 ||
171 sblock
.fs_interleave
> sblock
.fs_nsect
) {
172 pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK",
173 sblock
.fs_interleave
);
174 sblock
.fs_interleave
= 1;
176 printf(" (FIXED)\n");
177 if (preen
|| reply("SET TO DEFAULT") == 1) {
182 if (sblock
.fs_npsect
< sblock
.fs_nsect
||
183 sblock
.fs_npsect
> sblock
.fs_nsect
*2) {
184 pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK",
186 sblock
.fs_npsect
= sblock
.fs_nsect
;
188 printf(" (FIXED)\n");
189 if (preen
|| reply("SET TO DEFAULT") == 1) {
194 if (sblock
.fs_inodefmt
>= FS_44INODEFMT
) {
197 sblock
.fs_qbmask
= ~sblock
.fs_bmask
;
198 sblock
.fs_qfmask
= ~sblock
.fs_fmask
;
199 /* This should match the kernel limit in ffs_oldfscompat(). */
200 sblock
.fs_maxfilesize
= (u_int64_t
)1 << 39;
204 * Convert to new inode format.
206 if (cvtlevel
>= 2 && sblock
.fs_inodefmt
< FS_44INODEFMT
) {
208 pwarn("CONVERTING TO NEW INODE FORMAT\n");
209 else if (!reply("CONVERT TO NEW INODE FORMAT"))
212 sblock
.fs_inodefmt
= FS_44INODEFMT
;
213 sizepb
= sblock
.fs_bsize
;
214 sblock
.fs_maxfilesize
= sblock
.fs_bsize
* NDADDR
- 1;
215 for (i
= 0; i
< NIADDR
; i
++) {
216 sizepb
*= NINDIR(&sblock
);
217 sblock
.fs_maxfilesize
+= sizepb
;
219 sblock
.fs_maxsymlinklen
= MAXSYMLINKLEN
;
220 sblock
.fs_qbmask
= ~sblock
.fs_bmask
;
221 sblock
.fs_qfmask
= ~sblock
.fs_fmask
;
226 * Convert to new cylinder group format.
228 if (cvtlevel
>= 1 && sblock
.fs_postblformat
== FS_42POSTBLFMT
) {
230 pwarn("CONVERTING TO NEW CYLINDER GROUP FORMAT\n");
231 else if (!reply("CONVERT TO NEW CYLINDER GROUP FORMAT"))
234 sblock
.fs_postblformat
= FS_DYNAMICPOSTBLFMT
;
236 sblock
.fs_postbloff
=
237 (char *)(&sblock
.fs_opostbl
[0][0]) -
238 (char *)(&sblock
.fs_firstfield
);
239 sblock
.fs_rotbloff
= &sblock
.fs_space
[0] -
240 (u_char
*)(&sblock
.fs_firstfield
);
242 fragroundup(&sblock
, CGSIZE(&sblock
));
246 if (asblk
.b_dirty
&& !bflag
) {
247 memmove(&altsblock
, &sblock
, (size_t)sblock
.fs_sbsize
);
248 flush(fswritefd
, &asblk
);
251 * read in the summary info.
254 sblock
.fs_csp
= calloc(1, sblock
.fs_cssize
);
255 for (i
= 0, j
= 0; i
< sblock
.fs_cssize
; i
+= sblock
.fs_bsize
, j
++) {
256 size
= sblock
.fs_cssize
- i
< sblock
.fs_bsize
?
257 sblock
.fs_cssize
- i
: sblock
.fs_bsize
;
258 if (bread(fsreadfd
, (char *)sblock
.fs_csp
+ i
,
259 fsbtodb(&sblock
, sblock
.fs_csaddr
+ j
* sblock
.fs_frag
),
260 size
) != 0 && !asked
) {
261 pfatal("BAD SUMMARY INFORMATION");
262 if (reply("CONTINUE") == 0) {
270 * allocate and initialize the necessary maps
272 bmapsize
= roundup(howmany(maxfsblock
, NBBY
), sizeof(short));
273 blockmap
= calloc((unsigned)bmapsize
, sizeof (char));
274 if (blockmap
== NULL
) {
275 printf("cannot alloc %u bytes for blockmap\n",
279 inostathead
= calloc((unsigned)(sblock
.fs_ncg
),
280 sizeof(struct inostatlist
));
281 if (inostathead
== NULL
) {
282 printf("cannot alloc %u bytes for inostathead\n",
283 (unsigned)(sizeof(struct inostatlist
) * (sblock
.fs_ncg
)));
286 numdirs
= sblock
.fs_cstotal
.cs_ndir
;
289 * Calculate the directory hash table size. Do not allocate
290 * a ridiculous amount of memory if we have a lot of directories.
292 for (dirhash
= 16; dirhash
< numdirs
; dirhash
<<= 1)
294 if (dirhash
> 1024*1024)
296 dirhashmask
= dirhash
- 1;
299 printf("numdirs is zero, try using an alternate superblock\n");
303 listmax
= numdirs
+ 10;
304 inpsort
= calloc((unsigned)listmax
, sizeof(struct inoinfo
*));
305 inphead
= calloc((unsigned)dirhash
, sizeof(struct inoinfo
*));
306 if (inpsort
== NULL
|| inphead
== NULL
) {
307 printf("cannot allocate base structures for %ld directories\n",
312 if (sblock
.fs_flags
& FS_DOSOFTDEP
)
324 * Read in the super block and its summary info.
329 ufs_daddr_t super
= bflag
? bflag
: SBOFF
/ dev_bsize
;
331 if (bread(fsreadfd
, (char *)&sblock
, super
, (long)SBSIZE
) != 0)
334 sblk
.b_size
= SBSIZE
;
336 * run a few consistency checks of the super block
338 if (sblock
.fs_magic
!= FS_MAGIC
)
339 { badsb(listerr
, "MAGIC NUMBER WRONG"); return (0); }
340 if (sblock
.fs_ncg
< 1)
341 { badsb(listerr
, "NCG OUT OF RANGE"); return (0); }
342 if (sblock
.fs_cpg
< 1)
343 { badsb(listerr
, "CPG OUT OF RANGE"); return (0); }
344 if (sblock
.fs_ncg
* sblock
.fs_cpg
< sblock
.fs_ncyl
||
345 (sblock
.fs_ncg
- 1) * sblock
.fs_cpg
>= sblock
.fs_ncyl
)
346 { badsb(listerr
, "NCYL LESS THAN NCG*CPG"); return (0); }
347 if (sblock
.fs_sbsize
> SBSIZE
)
348 { badsb(listerr
, "SIZE PREPOSTEROUSLY LARGE"); return (0); }
350 * Compute block size that the filesystem is based on,
351 * according to fsbtodb, and adjust superblock block number
352 * so we can tell if this is an alternate later.
355 dev_bsize
= sblock
.fs_fsize
/ fsbtodb(&sblock
, 1);
356 sblk
.b_bno
= super
/ dev_bsize
;
362 * Compare all fields that should not differ in alternate super block.
363 * When an alternate super-block is specified this check is skipped.
365 getblk(&asblk
, cgsblock(&sblock
, sblock
.fs_ncg
- 1), sblock
.fs_sbsize
);
368 if (altsblock
.fs_sblkno
!= sblock
.fs_sblkno
||
369 altsblock
.fs_cblkno
!= sblock
.fs_cblkno
||
370 altsblock
.fs_iblkno
!= sblock
.fs_iblkno
||
371 altsblock
.fs_dblkno
!= sblock
.fs_dblkno
||
372 altsblock
.fs_cgoffset
!= sblock
.fs_cgoffset
||
373 altsblock
.fs_cgmask
!= sblock
.fs_cgmask
||
374 altsblock
.fs_ncg
!= sblock
.fs_ncg
||
375 altsblock
.fs_bsize
!= sblock
.fs_bsize
||
376 altsblock
.fs_fsize
!= sblock
.fs_fsize
||
377 altsblock
.fs_frag
!= sblock
.fs_frag
||
378 altsblock
.fs_bmask
!= sblock
.fs_bmask
||
379 altsblock
.fs_fmask
!= sblock
.fs_fmask
||
380 altsblock
.fs_bshift
!= sblock
.fs_bshift
||
381 altsblock
.fs_fshift
!= sblock
.fs_fshift
||
382 altsblock
.fs_fragshift
!= sblock
.fs_fragshift
||
383 altsblock
.fs_fsbtodb
!= sblock
.fs_fsbtodb
||
384 altsblock
.fs_sbsize
!= sblock
.fs_sbsize
||
385 altsblock
.fs_nindir
!= sblock
.fs_nindir
||
386 altsblock
.fs_inopb
!= sblock
.fs_inopb
||
387 altsblock
.fs_cssize
!= sblock
.fs_cssize
||
388 altsblock
.fs_cpg
!= sblock
.fs_cpg
||
389 altsblock
.fs_ipg
!= sblock
.fs_ipg
||
390 altsblock
.fs_fpg
!= sblock
.fs_fpg
||
391 altsblock
.fs_magic
!= sblock
.fs_magic
) {
393 "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
401 badsb(int listerr
, char *s
)
407 printf("%s: ", cdevname
);
408 pfatal("BAD SUPER BLOCK: %s\n", s
);