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. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * @(#)setup.c 8.10 (Berkeley) 5/9/95
30 * $FreeBSD: src/sbin/fsck/setup.c,v 1.17.2.4 2002/06/24 05:10:41 dillon Exp $
34 #include <sys/param.h>
36 #include <sys/diskslice.h>
39 #include <vfs/ufs/dinode.h>
40 #include <vfs/ufs/fs.h>
50 #define altsblock (*asblk.b_un.b_fs)
51 #define POWEROF2(num) (((num) & ((num) - 1)) == 0)
53 static void badsb(int listerr
, char *s
);
54 static int readsb(int listerr
);
57 * Read in a superblock finding an alternate if necessary.
58 * Return 1 if successful, 0 if unsuccessful, -1 if filesystem
59 * is already clean (preen mode only).
64 long size
, asked
, i
, j
;
65 long skipclean
, bmapsize
;
71 skipclean
= fflag
? 0 : preen
;
72 if (stat(dev
, &statb
) < 0) {
73 printf("Can't stat %s: %s\n", dev
, strerror(errno
));
76 if ((statb
.st_mode
& S_IFMT
) != S_IFCHR
&&
77 (statb
.st_mode
& S_IFMT
) != S_IFBLK
) {
78 pfatal("%s is not a disk device", dev
);
79 if (reply("CONTINUE") == 0)
82 if ((fsreadfd
= open(dev
, O_RDONLY
)) < 0) {
83 printf("Can't open %s: %s\n", dev
, strerror(errno
));
88 if (nflag
|| (fswritefd
= open(dev
, O_WRONLY
)) < 0) {
91 pfatal("NO WRITE ACCESS");
92 printf(" (NO WRITE)");
100 sblk
.b_un
.b_buf
= malloc(SBSIZE
);
101 asblk
.b_un
.b_buf
= malloc(SBSIZE
);
102 if (sblk
.b_un
.b_buf
== NULL
|| asblk
.b_un
.b_buf
== NULL
)
103 errx(EEXIT
, "cannot allocate space for superblock");
106 * Figure out the device block size and the sector size. The
107 * block size is updated by readsb() later on.
110 struct partinfo pinfo
;
112 if (ioctl(fsreadfd
, DIOCGPART
, &pinfo
) == 0) {
113 dev_bsize
= secsize
= pinfo
.media_blksize
;
115 dev_bsize
= secsize
= DEV_BSIZE
;
120 * Read in the superblock, looking for alternates if necessary
122 if (readsb(1) == 0) {
126 if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
129 if (readsb(0) == 0) {
131 "YOU MUST USE THE -b OPTION TO FSCK TO SPECIFY\n"
132 "THE LOCATION OF AN ALTERNATE SUPER-BLOCK TO\n"
133 "SUPPLY NEEDED INFORMATION; SEE fsck(8).");
137 pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag
);
140 if (skipclean
&& sblock
.fs_clean
) {
141 pwarn("FILESYSTEM CLEAN; SKIPPING CHECKS\n");
144 maxfsblock
= sblock
.fs_size
;
145 maxino
= sblock
.fs_ncg
* sblock
.fs_ipg
;
147 * Check and potentially fix certain fields in the super block.
149 if (sblock
.fs_optim
!= FS_OPTTIME
&& sblock
.fs_optim
!= FS_OPTSPACE
) {
150 pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
151 if (reply("SET TO DEFAULT") == 1) {
152 sblock
.fs_optim
= FS_OPTTIME
;
156 if ((sblock
.fs_minfree
< 0 || sblock
.fs_minfree
> 99)) {
157 pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
159 if (reply("SET TO DEFAULT") == 1) {
160 sblock
.fs_minfree
= 10;
164 if (sblock
.fs_interleave
< 1 ||
165 sblock
.fs_interleave
> sblock
.fs_nsect
) {
166 pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK",
167 sblock
.fs_interleave
);
168 sblock
.fs_interleave
= 1;
170 printf(" (FIXED)\n");
171 if (preen
|| reply("SET TO DEFAULT") == 1) {
176 if (sblock
.fs_npsect
< sblock
.fs_nsect
||
177 sblock
.fs_npsect
> sblock
.fs_nsect
*2) {
178 pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK",
180 sblock
.fs_npsect
= sblock
.fs_nsect
;
182 printf(" (FIXED)\n");
183 if (preen
|| reply("SET TO DEFAULT") == 1) {
188 if (sblock
.fs_inodefmt
>= FS_44INODEFMT
) {
191 sblock
.fs_qbmask
= ~sblock
.fs_bmask
;
192 sblock
.fs_qfmask
= ~sblock
.fs_fmask
;
193 /* This should match the kernel limit in ffs_oldfscompat(). */
194 sblock
.fs_maxfilesize
= (u_int64_t
)1 << 39;
198 * Convert to new inode format.
200 if (cvtlevel
>= 2 && sblock
.fs_inodefmt
< FS_44INODEFMT
) {
202 pwarn("CONVERTING TO NEW INODE FORMAT\n");
203 else if (!reply("CONVERT TO NEW INODE FORMAT"))
206 sblock
.fs_inodefmt
= FS_44INODEFMT
;
207 sizepb
= sblock
.fs_bsize
;
208 sblock
.fs_maxfilesize
= sblock
.fs_bsize
* NDADDR
- 1;
209 for (i
= 0; i
< NIADDR
; i
++) {
210 sizepb
*= NINDIR(&sblock
);
211 sblock
.fs_maxfilesize
+= sizepb
;
213 sblock
.fs_maxsymlinklen
= MAXSYMLINKLEN
;
214 sblock
.fs_qbmask
= ~sblock
.fs_bmask
;
215 sblock
.fs_qfmask
= ~sblock
.fs_fmask
;
220 * Convert to new cylinder group format.
222 if (cvtlevel
>= 1 && sblock
.fs_postblformat
== FS_42POSTBLFMT
) {
224 pwarn("CONVERTING TO NEW CYLINDER GROUP FORMAT\n");
225 else if (!reply("CONVERT TO NEW CYLINDER GROUP FORMAT"))
228 sblock
.fs_postblformat
= FS_DYNAMICPOSTBLFMT
;
230 sblock
.fs_postbloff
=
231 (char *)(&sblock
.fs_opostbl
[0][0]) -
232 (char *)(&sblock
.fs_firstfield
);
233 sblock
.fs_rotbloff
= &sblock
.fs_space
[0] -
234 (u_char
*)(&sblock
.fs_firstfield
);
236 fragroundup(&sblock
, CGSIZE(&sblock
));
240 if (asblk
.b_dirty
&& !bflag
) {
241 memmove(&altsblock
, &sblock
, (size_t)sblock
.fs_sbsize
);
242 flush(fswritefd
, &asblk
);
245 * read in the summary info.
248 sblock
.fs_csp
= calloc(1, sblock
.fs_cssize
);
249 for (i
= 0, j
= 0; i
< sblock
.fs_cssize
; i
+= sblock
.fs_bsize
, j
++) {
250 size
= sblock
.fs_cssize
- i
< sblock
.fs_bsize
?
251 sblock
.fs_cssize
- i
: sblock
.fs_bsize
;
252 if (bread(fsreadfd
, (char *)sblock
.fs_csp
+ i
,
253 fsbtodb(&sblock
, sblock
.fs_csaddr
+ j
* sblock
.fs_frag
),
254 size
) != 0 && !asked
) {
255 pfatal("BAD SUMMARY INFORMATION");
256 if (reply("CONTINUE") == 0) {
264 * allocate and initialize the necessary maps
266 bmapsize
= roundup(howmany(maxfsblock
, NBBY
), sizeof(short));
267 blockmap
= calloc((unsigned)bmapsize
, sizeof (char));
268 if (blockmap
== NULL
) {
269 printf("cannot alloc %u bytes for blockmap\n",
273 inostathead
= calloc((unsigned)(sblock
.fs_ncg
),
274 sizeof(struct inostatlist
));
275 if (inostathead
== NULL
) {
276 printf("cannot alloc %u bytes for inostathead\n",
277 (unsigned)(sizeof(struct inostatlist
) * (sblock
.fs_ncg
)));
280 numdirs
= sblock
.fs_cstotal
.cs_ndir
;
283 * Calculate the directory hash table size. Do not allocate
284 * a ridiculous amount of memory if we have a lot of directories.
286 for (dirhash
= 16; dirhash
< numdirs
; dirhash
<<= 1)
288 if (dirhash
> 1024*1024)
290 dirhashmask
= dirhash
- 1;
293 printf("numdirs is zero, try using an alternate superblock\n");
297 listmax
= numdirs
+ 10;
298 inpsort
= calloc((unsigned)listmax
, sizeof(struct inoinfo
*));
299 inphead
= calloc((unsigned)dirhash
, sizeof(struct inoinfo
*));
300 if (inpsort
== NULL
|| inphead
== NULL
) {
301 printf("cannot allocate base structures for %ld directories\n",
306 if (sblock
.fs_flags
& FS_DOSOFTDEP
)
318 * Read in the super block and its summary info.
323 ufs_daddr_t super
= bflag
? bflag
: SBOFF
/ dev_bsize
;
325 if (bread(fsreadfd
, (char *)&sblock
, super
, (long)SBSIZE
) != 0)
328 sblk
.b_size
= SBSIZE
;
330 * run a few consistency checks of the super block
332 if (sblock
.fs_magic
!= FS_MAGIC
)
333 { badsb(listerr
, "MAGIC NUMBER WRONG"); return (0); }
334 if (sblock
.fs_ncg
< 1)
335 { badsb(listerr
, "NCG OUT OF RANGE"); return (0); }
336 if (sblock
.fs_cpg
< 1)
337 { badsb(listerr
, "CPG OUT OF RANGE"); return (0); }
338 if (sblock
.fs_ncg
* sblock
.fs_cpg
< sblock
.fs_ncyl
||
339 (sblock
.fs_ncg
- 1) * sblock
.fs_cpg
>= sblock
.fs_ncyl
)
340 { badsb(listerr
, "NCYL LESS THAN NCG*CPG"); return (0); }
341 if (sblock
.fs_sbsize
> SBSIZE
)
342 { badsb(listerr
, "SIZE PREPOSTEROUSLY LARGE"); return (0); }
344 * Compute block size that the filesystem is based on,
345 * according to fsbtodb, and adjust superblock block number
346 * so we can tell if this is an alternate later.
349 dev_bsize
= sblock
.fs_fsize
/ fsbtodb(&sblock
, 1);
350 sblk
.b_bno
= super
/ dev_bsize
;
356 * Compare all fields that should not differ in alternate super block.
357 * When an alternate super-block is specified this check is skipped.
359 getblk(&asblk
, cgsblock(&sblock
, sblock
.fs_ncg
- 1), sblock
.fs_sbsize
);
362 if (altsblock
.fs_sblkno
!= sblock
.fs_sblkno
||
363 altsblock
.fs_cblkno
!= sblock
.fs_cblkno
||
364 altsblock
.fs_iblkno
!= sblock
.fs_iblkno
||
365 altsblock
.fs_dblkno
!= sblock
.fs_dblkno
||
366 altsblock
.fs_cgoffset
!= sblock
.fs_cgoffset
||
367 altsblock
.fs_cgmask
!= sblock
.fs_cgmask
||
368 altsblock
.fs_ncg
!= sblock
.fs_ncg
||
369 altsblock
.fs_bsize
!= sblock
.fs_bsize
||
370 altsblock
.fs_fsize
!= sblock
.fs_fsize
||
371 altsblock
.fs_frag
!= sblock
.fs_frag
||
372 altsblock
.fs_bmask
!= sblock
.fs_bmask
||
373 altsblock
.fs_fmask
!= sblock
.fs_fmask
||
374 altsblock
.fs_bshift
!= sblock
.fs_bshift
||
375 altsblock
.fs_fshift
!= sblock
.fs_fshift
||
376 altsblock
.fs_fragshift
!= sblock
.fs_fragshift
||
377 altsblock
.fs_fsbtodb
!= sblock
.fs_fsbtodb
||
378 altsblock
.fs_sbsize
!= sblock
.fs_sbsize
||
379 altsblock
.fs_nindir
!= sblock
.fs_nindir
||
380 altsblock
.fs_inopb
!= sblock
.fs_inopb
||
381 altsblock
.fs_cssize
!= sblock
.fs_cssize
||
382 altsblock
.fs_cpg
!= sblock
.fs_cpg
||
383 altsblock
.fs_ipg
!= sblock
.fs_ipg
||
384 altsblock
.fs_fpg
!= sblock
.fs_fpg
||
385 altsblock
.fs_magic
!= sblock
.fs_magic
) {
387 "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
395 badsb(int listerr
, char *s
)
401 printf("%s: ", cdevname
);
402 pfatal("BAD SUPER BLOCK: %s\n", s
);