1 /* $NetBSD: setup.c,v 1.88 2009/09/13 14:25:28 bouyer Exp $ */
4 * Copyright (c) 1980, 1986, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
35 static char sccsid
[] = "@(#)setup.c 8.10 (Berkeley) 5/9/95";
37 __RCSID("$NetBSD: setup.c,v 1.88 2009/09/13 14:25:28 bouyer Exp $");
41 #include <sys/param.h>
44 #include <sys/ioctl.h>
48 #include <ufs/ufs/dinode.h>
49 #include <ufs/ufs/dir.h>
50 #include <ufs/ufs/ufs_bswap.h>
51 #include <ufs/ffs/fs.h>
52 #include <ufs/ffs/ffs_extern.h>
65 #include "exitvalues.h"
67 #define POWEROF2(num) (((num) & ((num) - 1)) == 0)
69 static void badsb(int, const char *);
70 static int calcsb(const char *, int, struct fs
*);
71 static int readsb(int);
72 static int readappleufs(void);
74 int16_t sblkpostbl
[256];
77 * Read in a superblock finding an alternate if necessary.
78 * Return 1 if successful, 0 if unsuccessful, -1 if filesystem
79 * is already clean (preen mode only).
82 setup(const char *dev
, const char *origdev
)
84 long cg
, size
, asked
, i
, j
;
87 struct dkwedge_info dkw
;
92 u_int64_t maxfilesize
;
98 doskipclean
= skipclean
;
99 if (stat(dev
, &statb
) < 0) {
100 printf("Can't stat %s: %s\n", dev
, strerror(errno
));
103 if (!forceimage
&& !S_ISCHR(statb
.st_mode
)) {
104 pfatal("%s is not a character device", dev
);
105 if (reply("CONTINUE") == 0)
108 if ((fsreadfd
= open(dev
, O_RDONLY
)) < 0) {
109 printf("Can't open %s: %s\n", dev
, strerror(errno
));
112 if (nflag
|| (fswritefd
= open(dev
, O_WRONLY
)) < 0) {
115 pfatal("NO WRITE ACCESS");
116 printf("** %s (NO WRITE)\n", dev
);
119 if (!preen
&& !quiet
)
120 printf("** %s\n", dev
);
125 sblk
.b_un
.b_buf
= malloc(SBLOCKSIZE
);
126 sblock
= malloc(SBLOCKSIZE
);
127 asblk
.b_un
.b_buf
= malloc(SBLOCKSIZE
);
128 altsblock
= malloc(SBLOCKSIZE
);
129 if (sblk
.b_un
.b_buf
== NULL
|| asblk
.b_un
.b_buf
== NULL
||
130 sblock
== NULL
|| altsblock
== NULL
)
131 errexit("Cannot allocate space for superblock");
132 if (strcmp(dev
, origdev
) && !forceimage
) {
134 * dev isn't the original fs (for example it's a snapshot)
135 * do getdiskinfo on the original device
137 fd
= open(origdev
, O_RDONLY
);
139 warn("Can't open %s", origdev
);
145 if (!forceimage
&& getdiskinfo(origdev
, fd
, NULL
, &geo
, &dkw
) != -1)
146 dev_bsize
= secsize
= geo
.dg_secsize
;
148 dev_bsize
= secsize
= DEV_BSIZE
;
150 * Read in the superblock, looking for alternates if necessary
152 if (readsb(1) == 0) {
153 if (bflag
|| preen
|| forceimage
||
154 calcsb(dev
, fsreadfd
, &proto
) == 0)
156 if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
158 for (cg
= 0; cg
< proto
.fs_ncg
; cg
++) {
159 bflag
= fsbtodb(&proto
, cgsblock(&proto
, cg
));
163 if (cg
>= proto
.fs_ncg
) {
164 printf("%s %s\n%s %s\n%s %s\n",
165 "SEARCH FOR ALTERNATE SUPER-BLOCK",
166 "FAILED. YOU MUST USE THE",
167 "-b OPTION TO fsck_ffs TO SPECIFY THE",
168 "LOCATION OF AN ALTERNATE",
169 "SUPER-BLOCK TO SUPPLY NEEDED",
170 "INFORMATION; SEE fsck_ffs(8).");
174 pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag
);
176 /* ffs_superblock_layout() == 2 */
177 if (sblock
->fs_magic
!= FS_UFS1_MAGIC
||
178 (sblock
->fs_old_flags
& FS_FLAGS_UPDATED
) != 0) {
180 if (check_wapbl() != 0) {
183 if (sblock
->fs_flags
& FS_DOWAPBL
) {
184 if (preen
&& skipclean
) {
186 pwarn("file system is journaled; "
191 pwarn("** File system is journaled; "
192 "replaying journal\n");
195 sblock
->fs_flags
&= ~FS_DOWAPBL
;
197 /* Although we may have updated the superblock from
198 * the journal, we are still going to do a full check,
199 * so we don't bother to re-read the superblock from
201 * XXX, instead we could re-read the superblock and
202 * then not force doskipclean = 0
207 printf("clean = %d\n", sblock
->fs_clean
);
210 if (sblock
->fs_clean
& FS_ISCLEAN
) {
213 pwarn("%sile system is clean; not checking\n",
214 preen
? "f" : "** F");
217 if (!preen
&& !doswap
)
218 pwarn("** File system is already clean\n");
220 maxfsblock
= sblock
->fs_size
;
221 maxino
= sblock
->fs_ncg
* sblock
->fs_ipg
;
222 sizepb
= sblock
->fs_bsize
;
223 maxfilesize
= sblock
->fs_bsize
* NDADDR
- 1;
224 for (i
= 0; i
< NIADDR
; i
++) {
225 sizepb
*= NINDIR(sblock
);
226 maxfilesize
+= sizepb
;
228 if ((!is_ufs2
&& cvtlevel
>= 4) &&
229 (sblock
->fs_old_flags
& FS_FLAGS_UPDATED
) == 0) {
231 pwarn("CONVERTING TO NEW SUPERBLOCK LAYOUT\n");
232 else if (!reply("CONVERT TO NEW SUPERBLOCK LAYOUT"))
234 sblock
->fs_old_flags
|= FS_FLAGS_UPDATED
;
235 /* Disable the postbl tables */
236 sblock
->fs_old_cpc
= 0;
237 sblock
->fs_old_nrpos
= 1;
238 sblock
->fs_old_trackskew
= 0;
239 /* The other fields have already been updated by
240 * sb_oldfscompat_read
244 if (!is_ufs2
&& cvtlevel
== 3 &&
245 (sblock
->fs_old_flags
& FS_FLAGS_UPDATED
)) {
247 pwarn("DOWNGRADING TO OLD SUPERBLOCK LAYOUT\n");
248 else if (!reply("DOWNGRADE TO OLD SUPERBLOCK LAYOUT"))
250 sblock
->fs_old_flags
&= ~FS_FLAGS_UPDATED
;
251 sb_oldfscompat_write(sblock
, sblock
);
252 sblock
->fs_old_flags
&= ~FS_FLAGS_UPDATED
; /* just in case */
253 /* Leave postbl tables disabled, but blank its superblock region anyway */
254 sblock
->fs_old_postblformat
= FS_DYNAMICPOSTBLFMT
;
255 sblock
->fs_old_cpc
= 0;
256 sblock
->fs_old_nrpos
= 1;
257 sblock
->fs_old_trackskew
= 0;
258 memset(&sblock
->fs_old_postbl_start
, 0xff, 256);
259 sb_oldfscompat_read(sblock
, &sblocksave
);
263 * Check and potentially fix certain fields in the super block.
265 if (sblock
->fs_flags
& ~(FS_KNOWN_FLAGS
)) {
266 pfatal("UNKNOWN FLAGS=0x%08x IN SUPERBLOCK", sblock
->fs_flags
);
267 if (reply("CLEAR") == 1) {
268 sblock
->fs_flags
&= FS_KNOWN_FLAGS
;
272 if (sblock
->fs_optim
!= FS_OPTTIME
&& sblock
->fs_optim
!= FS_OPTSPACE
) {
273 pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
274 if (reply("SET TO DEFAULT") == 1) {
275 sblock
->fs_optim
= FS_OPTTIME
;
279 if ((sblock
->fs_minfree
< 0 || sblock
->fs_minfree
> 99)) {
280 pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
282 if (reply("SET TO DEFAULT") == 1) {
283 sblock
->fs_minfree
= 10;
287 if (!is_ufs2
&& sblock
->fs_old_postblformat
!= FS_42POSTBLFMT
&&
288 (sblock
->fs_old_interleave
< 1 ||
289 sblock
->fs_old_interleave
> sblock
->fs_old_nsect
)) {
290 pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK",
291 sblock
->fs_old_interleave
);
292 sblock
->fs_old_interleave
= 1;
294 printf(" (FIXED)\n");
295 if (preen
|| reply("SET TO DEFAULT") == 1) {
300 if (!is_ufs2
&& sblock
->fs_old_postblformat
!= FS_42POSTBLFMT
&&
301 (sblock
->fs_old_npsect
< sblock
->fs_old_nsect
||
302 sblock
->fs_old_npsect
> sblock
->fs_old_nsect
*2)) {
303 pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK",
304 sblock
->fs_old_npsect
);
305 sblock
->fs_old_npsect
= sblock
->fs_old_nsect
;
307 printf(" (FIXED)\n");
308 if (preen
|| reply("SET TO DEFAULT") == 1) {
313 if (sblock
->fs_bmask
!= ~(sblock
->fs_bsize
- 1)) {
314 pwarn("INCORRECT BMASK=0x%x IN SUPERBLOCK",
316 sblock
->fs_bmask
= ~(sblock
->fs_bsize
- 1);
318 printf(" (FIXED)\n");
319 if (preen
|| reply("FIX") == 1) {
324 if (sblock
->fs_fmask
!= ~(sblock
->fs_fsize
- 1)) {
325 pwarn("INCORRECT FMASK=0x%x IN SUPERBLOCK",
327 sblock
->fs_fmask
= ~(sblock
->fs_fsize
- 1);
329 printf(" (FIXED)\n");
330 if (preen
|| reply("FIX") == 1) {
335 if (is_ufs2
|| sblock
->fs_old_inodefmt
>= FS_44INODEFMT
) {
336 if (sblock
->fs_maxfilesize
!= maxfilesize
) {
337 pwarn("INCORRECT MAXFILESIZE=%lld IN SUPERBLOCK",
338 (unsigned long long)sblock
->fs_maxfilesize
);
339 sblock
->fs_maxfilesize
= maxfilesize
;
341 printf(" (FIXED)\n");
342 if (preen
|| reply("FIX") == 1) {
347 if ((is_ufs2
&& sblock
->fs_maxsymlinklen
!= MAXSYMLINKLEN_UFS2
)
349 (!is_ufs2
&& sblock
->fs_maxsymlinklen
!= MAXSYMLINKLEN_UFS1
))
351 pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK",
352 sblock
->fs_maxsymlinklen
);
353 sblock
->fs_maxsymlinklen
= is_ufs2
?
354 MAXSYMLINKLEN_UFS2
: MAXSYMLINKLEN_UFS1
;
356 printf(" (FIXED)\n");
357 if (preen
|| reply("FIX") == 1) {
362 if (sblock
->fs_qbmask
!= ~sblock
->fs_bmask
) {
363 pwarn("INCORRECT QBMASK=%#llx IN SUPERBLOCK",
364 (unsigned long long)sblock
->fs_qbmask
);
365 sblock
->fs_qbmask
= ~sblock
->fs_bmask
;
367 printf(" (FIXED)\n");
368 if (preen
|| reply("FIX") == 1) {
373 if (sblock
->fs_qfmask
!= ~sblock
->fs_fmask
) {
374 pwarn("INCORRECT QFMASK=%#llx IN SUPERBLOCK",
375 (unsigned long long)sblock
->fs_qfmask
);
376 sblock
->fs_qfmask
= ~sblock
->fs_fmask
;
378 printf(" (FIXED)\n");
379 if (preen
|| reply("FIX") == 1) {
386 sblock
->fs_qbmask
= ~sblock
->fs_bmask
;
387 sblock
->fs_qfmask
= ~sblock
->fs_fmask
;
391 * Convert to new inode format.
393 if (!is_ufs2
&& cvtlevel
>= 2 &&
394 sblock
->fs_old_inodefmt
< FS_44INODEFMT
) {
396 pwarn("CONVERTING TO NEW INODE FORMAT\n");
397 else if (!reply("CONVERT TO NEW INODE FORMAT"))
400 sblock
->fs_old_inodefmt
= FS_44INODEFMT
;
401 sblock
->fs_maxfilesize
= maxfilesize
;
402 sblock
->fs_maxsymlinklen
= MAXSYMLINKLEN_UFS1
;
403 sblock
->fs_qbmask
= ~sblock
->fs_bmask
;
404 sblock
->fs_qfmask
= ~sblock
->fs_fmask
;
409 * Convert to new cylinder group format.
411 if (!is_ufs2
&& cvtlevel
>= 1 &&
412 sblock
->fs_old_postblformat
== FS_42POSTBLFMT
) {
414 pwarn("CONVERTING TO NEW CYLINDER GROUP FORMAT\n");
415 else if (!reply("CONVERT TO NEW CYLINDER GROUP FORMAT"))
418 sblock
->fs_old_postblformat
= FS_DYNAMICPOSTBLFMT
;
419 sblock
->fs_old_nrpos
= 8;
420 sblock
->fs_old_postbloff
=
421 (char *)(&sblock
->fs_old_postbl_start
) -
422 (char *)(&sblock
->fs_firstfield
);
423 sblock
->fs_old_rotbloff
=
424 (char *)(&sblock
->fs_magic
+1) -
425 (char *)(&sblock
->fs_firstfield
);
427 fragroundup(sblock
, CGSIZE(sblock
));
431 if (asblk
.b_dirty
&& !bflag
) {
432 memmove(sblk
.b_un
.b_fs
, sblock
, SBLOCKSIZE
);
433 sb_oldfscompat_write(sblk
.b_un
.b_fs
, sblocksave
);
435 ffs_sb_swap(sblk
.b_un
.b_fs
, sblk
.b_un
.b_fs
);
436 memmove(asblk
.b_un
.b_fs
, sblk
.b_un
.b_fs
, (size_t)sblock
->fs_sbsize
);
437 flush(fswritefd
, &asblk
);
440 * read in the summary info.
443 sblock
->fs_csp
= (struct csum
*)calloc(1, sblock
->fs_cssize
);
444 if (sblock
->fs_csp
== NULL
) {
445 pwarn("cannot alloc %u bytes for summary info\n",
449 for (i
= 0, j
= 0; i
< sblock
->fs_cssize
; i
+= sblock
->fs_bsize
, j
++) {
450 size
= sblock
->fs_cssize
- i
< sblock
->fs_bsize
?
451 sblock
->fs_cssize
- i
: sblock
->fs_bsize
;
452 ccsp
= (struct csum
*)((char *)sblock
->fs_csp
+ i
);
453 if (bread(fsreadfd
, (char *)ccsp
,
454 fsbtodb(sblock
, sblock
->fs_csaddr
+ j
* sblock
->fs_frag
),
455 size
) != 0 && !asked
) {
456 pfatal("BAD SUMMARY INFORMATION");
457 if (reply("CONTINUE") == 0) {
459 exit(FSCK_EXIT_CHECK_FAILED
);
464 ffs_csum_swap(ccsp
, ccsp
, size
);
465 bwrite(fswritefd
, (char *)ccsp
,
467 sblock
->fs_csaddr
+ j
* sblock
->fs_frag
),
471 ffs_csum_swap(ccsp
, ccsp
, size
);
474 * allocate and initialize the necessary maps
476 bmapsize
= roundup(howmany(maxfsblock
, NBBY
), sizeof(int16_t));
477 blockmap
= calloc((unsigned)bmapsize
, sizeof (char));
478 if (blockmap
== NULL
) {
479 pwarn("cannot alloc %u bytes for blockmap\n",
483 inostathead
= calloc((unsigned)(sblock
->fs_ncg
),
484 sizeof(struct inostatlist
));
485 if (inostathead
== NULL
) {
486 pwarn("cannot alloc %u bytes for inostathead\n",
487 (unsigned)(sizeof(struct inostatlist
) * (sblock
->fs_ncg
)));
491 * cs_ndir may be inaccurate, particularly if we're using the -b
492 * option, so set a minimum to prevent bogus subdirectory reconnects
493 * and really inefficient directory scans.
494 * Also set a maximum in case the value is too large.
496 numdirs
= sblock
->fs_cstotal
.cs_ndir
;
499 if (numdirs
> maxino
+ 1)
500 numdirs
= maxino
+ 1;
503 listmax
= numdirs
+ 10;
504 inpsort
= (struct inoinfo
**)calloc((unsigned)listmax
,
505 sizeof(struct inoinfo
*));
506 inphead
= (struct inoinfo
**)calloc((unsigned)numdirs
,
507 sizeof(struct inoinfo
*));
508 if (inpsort
== NULL
|| inphead
== NULL
) {
509 pwarn("cannot alloc %u bytes for inphead\n",
510 (unsigned)(numdirs
* sizeof(struct inoinfo
*)));
513 cgrp
= malloc(sblock
->fs_cgsize
);
515 pwarn("cannot alloc %u bytes for cylinder group\n",
520 if (sblock
->fs_flags
& FS_DOSOFTDEP
)
525 if (!forceimage
&& dkw
.dkw_parent
[0])
526 if (strcmp(dkw
.dkw_ptype
, DKW_PTYPE_APPLEUFS
) == 0)
532 dirblksiz
= DIRBLKSIZ
;
534 dirblksiz
= APPLEUFS_DIRBLKSIZ
;
537 printf("isappleufs = %d, dirblksiz = %d\n", isappleufs
, dirblksiz
);
550 daddr_t label
= APPLEUFS_LABEL_OFFSET
/ dev_bsize
;
551 struct appleufslabel
*appleufs
;
554 /* XXX do we have to deal with APPLEUFS_LABEL_OFFSET not
555 * being block aligned (CD's?)
557 if (bread(fsreadfd
, (char *)appleufsblk
.b_un
.b_fs
, label
,
558 (long)APPLEUFS_LABEL_SIZE
) != 0)
560 appleufsblk
.b_bno
= label
;
561 appleufsblk
.b_size
= APPLEUFS_LABEL_SIZE
;
563 appleufs
= appleufsblk
.b_un
.b_appleufs
;
565 if (ntohl(appleufs
->ul_magic
) != APPLEUFS_LABEL_MAGIC
) {
569 pfatal("MISSING APPLEUFS VOLUME LABEL\n");
570 if (reply("FIX") == 0) {
573 ffs_appleufs_set(appleufs
, NULL
, -1, 0);
578 if (ntohl(appleufs
->ul_version
) != APPLEUFS_LABEL_VERSION
) {
579 pwarn("INCORRECT APPLE UFS VERSION NUMBER (%d should be %d)",
580 ntohl(appleufs
->ul_version
),APPLEUFS_LABEL_VERSION
);
582 printf(" (CORRECTED)\n");
584 if (preen
|| reply("CORRECT")) {
585 appleufs
->ul_version
= htonl(APPLEUFS_LABEL_VERSION
);
590 if (ntohs(appleufs
->ul_namelen
) > APPLEUFS_MAX_LABEL_NAME
) {
591 pwarn("APPLE UFS LABEL NAME TOO LONG");
593 printf(" (TRUNCATED)\n");
595 if (preen
|| reply("TRUNCATE")) {
596 appleufs
->ul_namelen
= htons(APPLEUFS_MAX_LABEL_NAME
);
601 if (ntohs(appleufs
->ul_namelen
) == 0) {
602 pwarn("MISSING APPLE UFS LABEL NAME");
604 printf(" (FIXED)\n");
606 if (preen
|| reply("FIX")) {
607 ffs_appleufs_set(appleufs
, NULL
, -1, 0);
612 /* Scan name for first illegal character */
613 for (i
=0;i
<ntohs(appleufs
->ul_namelen
);i
++) {
614 if ((appleufs
->ul_name
[i
] == '\0') ||
615 (appleufs
->ul_name
[i
] == ':') ||
616 (appleufs
->ul_name
[i
] == '/')) {
617 pwarn("APPLE UFS LABEL NAME CONTAINS ILLEGAL CHARACTER");
619 printf(" (TRUNCATED)\n");
621 if (preen
|| reply("TRUNCATE")) {
622 appleufs
->ul_namelen
= i
+1;
629 /* Check the checksum last, because if anything else was wrong,
630 * then the checksum gets reset anyway.
632 appleufs
->ul_checksum
= 0;
633 appleufs
->ul_checksum
= ffs_appleufs_cksum(appleufs
);
634 if (appleufsblk
.b_un
.b_appleufs
->ul_checksum
!= appleufs
->ul_checksum
) {
635 pwarn("INVALID APPLE UFS CHECKSUM (%#04x should be %#04x)",
636 appleufsblk
.b_un
.b_appleufs
->ul_checksum
, appleufs
->ul_checksum
);
638 printf(" (CORRECTED)\n");
640 if (preen
|| reply("CORRECT")) {
643 /* put the incorrect checksum back in place */
644 appleufs
->ul_checksum
= appleufsblk
.b_un
.b_appleufs
->ul_checksum
;
651 * Detect byte order. Return 0 if valid magic found, -1 otherwise.
654 detect_byteorder(struct fs
*fs
, int sblockoff
)
656 if (sblockoff
== SBLOCK_UFS2
&& (fs
->fs_magic
== FS_UFS1_MAGIC
||
657 fs
->fs_magic
== bswap32(FS_UFS1_MAGIC
)))
658 /* Likely to be the first alternate of a fs with 64k blocks */
660 if (fs
->fs_magic
== FS_UFS1_MAGIC
|| fs
->fs_magic
== FS_UFS2_MAGIC
) {
661 if (endian
== 0 || BYTE_ORDER
== endian
) {
663 doswap
= do_blkswap
= do_dirswap
= 0;
666 doswap
= do_blkswap
= do_dirswap
= 1;
669 } else if (fs
->fs_magic
== bswap32(FS_UFS1_MAGIC
) ||
670 fs
->fs_magic
== bswap32(FS_UFS2_MAGIC
)) {
671 if (endian
== 0 || BYTE_ORDER
!= endian
) {
673 doswap
= do_blkswap
= do_dirswap
= 0;
676 doswap
= do_blkswap
= do_dirswap
= 1;
684 * Possible superblock locations ordered from most to least likely.
686 static off_t sblock_try
[] = SBLOCKSEARCH
;
689 * Read in the super block and its summary info.
700 if (bread(fsreadfd
, (char *)sblk
.b_un
.b_fs
, super
,
701 (long)SBLOCKSIZE
) != 0)
704 if (detect_byteorder(fs
, -1) < 0) {
705 badsb(listerr
, "MAGIC NUMBER WRONG");
709 for (i
= 0; sblock_try
[i
] != -1; i
++) {
710 super
= sblock_try
[i
] / dev_bsize
;
711 if (bread(fsreadfd
, (char *)sblk
.b_un
.b_fs
,
712 super
, (long)SBLOCKSIZE
) != 0)
715 if (detect_byteorder(fs
, sblock_try
[i
]) == 0)
718 if (sblock_try
[i
] == -1) {
719 badsb(listerr
, "CAN'T FIND SUPERBLOCK");
725 errx(FSCK_EXIT_USAGE
,
726 "Incompatible options -B and -p");
728 errx(FSCK_EXIT_USAGE
,
729 "Incompatible options -B and -n");
730 if (endian
== LITTLE_ENDIAN
) {
731 if (!reply("CONVERT TO LITTLE ENDIAN"))
733 } else if (endian
== BIG_ENDIAN
) {
734 if (!reply("CONVERT TO BIG ENDIAN"))
737 pfatal("INTERNAL ERROR: unknown endian");
740 pwarn("** Swapped byte order\n");
741 /* swap SB byte order if asked */
743 ffs_sb_swap(sblk
.b_un
.b_fs
, sblk
.b_un
.b_fs
);
745 memmove(sblock
, sblk
.b_un
.b_fs
, SBLOCKSIZE
);
747 ffs_sb_swap(sblk
.b_un
.b_fs
, sblock
);
749 is_ufs2
= sblock
->fs_magic
== FS_UFS2_MAGIC
;
752 * run a few consistency checks of the super block
754 if (sblock
->fs_sbsize
> SBLOCKSIZE
)
755 { badsb(listerr
, "SIZE PREPOSTEROUSLY LARGE"); return (0); }
757 * Compute block size that the filesystem is based on,
758 * according to fsbtodb, and adjust superblock block number
759 * so we can tell if this is an alternate later.
762 dev_bsize
= sblock
->fs_fsize
/ fsbtodb(sblock
, 1);
763 sblk
.b_bno
= super
/ dev_bsize
;
764 sblk
.b_size
= SBLOCKSIZE
;
768 * Set all possible fields that could differ, then do check
769 * of whole super block against an alternate super block->
770 * When an alternate super-block is specified this check is skipped.
772 getblk(&asblk
, cgsblock(sblock
, sblock
->fs_ncg
- 1), sblock
->fs_sbsize
);
775 /* swap SB byte order if asked */
777 ffs_sb_swap(asblk
.b_un
.b_fs
, asblk
.b_un
.b_fs
);
779 memmove(altsblock
, asblk
.b_un
.b_fs
, sblock
->fs_sbsize
);
781 ffs_sb_swap(asblk
.b_un
.b_fs
, altsblock
);
782 if (cmpsblks(sblock
, altsblock
)) {
784 uint32_t *nlp
, *olp
, *endlp
;
786 printf("superblock mismatches\n");
787 nlp
= (uint32_t *)altsblock
;
788 olp
= (uint32_t *)sblock
;
789 endlp
= olp
+ (sblock
->fs_sbsize
/ sizeof *olp
);
790 for ( ; olp
< endlp
; olp
++, nlp
++) {
793 printf("offset %#x, original 0x%08x, alternate "
795 (int)((uint8_t *)olp
-(uint8_t *)sblock
),
800 "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
807 sb_oldfscompat_read(sblock
, &sblocksave
);
809 /* Now we know the SB is valid, we can write it back if needed */
819 cmpsblks(const struct fs
*sb
, struct fs
*asb
)
821 if (!is_ufs2
&& ((sb
->fs_old_flags
& FS_FLAGS_UPDATED
) == 0)) {
822 if (sb
->fs_old_postblformat
< FS_DYNAMICPOSTBLFMT
)
823 return cmpsblks42(sb
, asb
);
825 return cmpsblks44(sb
, asb
);
827 if (asb
->fs_sblkno
!= sb
->fs_sblkno
||
828 asb
->fs_cblkno
!= sb
->fs_cblkno
||
829 asb
->fs_iblkno
!= sb
->fs_iblkno
||
830 asb
->fs_dblkno
!= sb
->fs_dblkno
||
831 asb
->fs_ncg
!= sb
->fs_ncg
||
832 asb
->fs_bsize
!= sb
->fs_bsize
||
833 asb
->fs_fsize
!= sb
->fs_fsize
||
834 asb
->fs_frag
!= sb
->fs_frag
||
835 asb
->fs_bmask
!= sb
->fs_bmask
||
836 asb
->fs_fmask
!= sb
->fs_fmask
||
837 asb
->fs_bshift
!= sb
->fs_bshift
||
838 asb
->fs_fshift
!= sb
->fs_fshift
||
839 asb
->fs_fragshift
!= sb
->fs_fragshift
||
840 asb
->fs_fsbtodb
!= sb
->fs_fsbtodb
||
841 asb
->fs_sbsize
!= sb
->fs_sbsize
||
842 asb
->fs_nindir
!= sb
->fs_nindir
||
843 asb
->fs_inopb
!= sb
->fs_inopb
||
844 asb
->fs_cssize
!= sb
->fs_cssize
||
845 asb
->fs_ipg
!= sb
->fs_ipg
||
846 asb
->fs_fpg
!= sb
->fs_fpg
||
847 asb
->fs_magic
!= sb
->fs_magic
)
852 /* BSD 4.2 performed the following superblock comparison
853 * It should correspond to FS_42POSTBLFMT
854 * (although note that in 4.2, the fs_old_postblformat
855 * field didn't exist and the corresponding bits are
856 * located near the end of the postbl itself, where they
857 * are not likely to be used.)
860 cmpsblks42(const struct fs
*sb
, struct fs
*asb
)
862 asb
->fs_firstfield
= sb
->fs_firstfield
; /* fs_link */
863 asb
->fs_unused_1
= sb
->fs_unused_1
; /* fs_rlink */
864 asb
->fs_old_time
= sb
->fs_old_time
; /* fs_time */
865 asb
->fs_old_cstotal
= sb
->fs_old_cstotal
; /* fs_cstotal */
866 asb
->fs_cgrotor
= sb
->fs_cgrotor
;
867 asb
->fs_fmod
= sb
->fs_fmod
;
868 asb
->fs_clean
= sb
->fs_clean
;
869 asb
->fs_ronly
= sb
->fs_ronly
;
870 asb
->fs_old_flags
= sb
->fs_old_flags
;
871 asb
->fs_maxcontig
= sb
->fs_maxcontig
;
872 asb
->fs_minfree
= sb
->fs_minfree
;
873 asb
->fs_old_rotdelay
= sb
->fs_old_rotdelay
;
874 asb
->fs_maxbpg
= sb
->fs_maxbpg
;
876 /* The former fs_csp, totaling 128 bytes */
877 memmove(asb
->fs_ocsp
, sb
->fs_ocsp
, sizeof sb
->fs_ocsp
);
878 asb
->fs_contigdirs
= sb
->fs_contigdirs
;
879 asb
->fs_csp
= sb
->fs_csp
;
880 asb
->fs_maxcluster
= sb
->fs_maxcluster
;
881 asb
->fs_active
= sb
->fs_active
;
883 /* The former fs_fsmnt, totaling 512 bytes */
884 memmove(asb
->fs_fsmnt
, sb
->fs_fsmnt
, sizeof sb
->fs_fsmnt
);
885 memmove(asb
->fs_volname
, sb
->fs_volname
, sizeof sb
->fs_volname
);
887 return memcmp(sb
, asb
, sb
->fs_sbsize
);
890 /* BSD 4.4 performed the following superblock comparison
891 * This was used in NetBSD through 1.6.1
893 * Note that this implementation is destructive to asb.
896 cmpsblks44(const struct fs
*sb
, struct fs
*asb
)
899 * "Copy fields which we don't care if they're different in the
900 * alternate superblocks, as they're either likely to be
901 * different because they're per-cylinder-group specific, or
902 * because they're transient details which are only maintained
903 * in the primary superblock."
905 asb
->fs_firstfield
= sb
->fs_firstfield
;
906 asb
->fs_unused_1
= sb
->fs_unused_1
;
907 asb
->fs_old_time
= sb
->fs_old_time
;
908 asb
->fs_old_cstotal
= sb
->fs_old_cstotal
;
909 asb
->fs_cgrotor
= sb
->fs_cgrotor
;
910 asb
->fs_fmod
= sb
->fs_fmod
;
911 asb
->fs_clean
= sb
->fs_clean
;
912 asb
->fs_ronly
= sb
->fs_ronly
;
913 asb
->fs_old_flags
= sb
->fs_old_flags
;
914 asb
->fs_maxcontig
= sb
->fs_maxcontig
;
915 asb
->fs_minfree
= sb
->fs_minfree
;
916 asb
->fs_optim
= sb
->fs_optim
;
917 asb
->fs_old_rotdelay
= sb
->fs_old_rotdelay
;
918 asb
->fs_maxbpg
= sb
->fs_maxbpg
;
920 /* The former fs_csp and fs_maxcluster, totaling 128 bytes */
921 memmove(asb
->fs_ocsp
, sb
->fs_ocsp
, sizeof sb
->fs_ocsp
);
922 asb
->fs_contigdirs
= sb
->fs_contigdirs
;
923 asb
->fs_csp
= sb
->fs_csp
;
924 asb
->fs_maxcluster
= sb
->fs_maxcluster
;
925 asb
->fs_active
= sb
->fs_active
;
927 /* The former fs_fsmnt, totaling 512 bytes */
928 memmove(asb
->fs_fsmnt
, sb
->fs_fsmnt
, sizeof sb
->fs_fsmnt
);
929 memmove(asb
->fs_volname
, sb
->fs_volname
, sizeof sb
->fs_volname
);
931 /* The former fs_sparecon, totaling 200 bytes */
932 memmove(asb
->fs_snapinum
,
933 sb
->fs_snapinum
, sizeof sb
->fs_snapinum
);
934 asb
->fs_avgfilesize
= sb
->fs_avgfilesize
;
935 asb
->fs_avgfpdir
= sb
->fs_avgfpdir
;
936 asb
->fs_save_cgsize
= sb
->fs_save_cgsize
;
937 memmove(asb
->fs_sparecon32
,
938 sb
->fs_sparecon32
, sizeof sb
->fs_sparecon32
);
939 asb
->fs_flags
= sb
->fs_flags
;
942 * "The following should not have to be copied, but need to be."
944 asb
->fs_fsbtodb
= sb
->fs_fsbtodb
;
945 asb
->fs_old_interleave
= sb
->fs_old_interleave
;
946 asb
->fs_old_npsect
= sb
->fs_old_npsect
;
947 asb
->fs_old_nrpos
= sb
->fs_old_nrpos
;
948 asb
->fs_state
= sb
->fs_state
;
949 asb
->fs_qbmask
= sb
->fs_qbmask
;
950 asb
->fs_qfmask
= sb
->fs_qfmask
;
951 asb
->fs_state
= sb
->fs_state
;
952 asb
->fs_maxfilesize
= sb
->fs_maxfilesize
;
955 * "Compare the superblocks, effectively checking every other
956 * field to see if they differ."
958 return memcmp(sb
, asb
, sb
->fs_sbsize
);
963 badsb(int listerr
, const char *s
)
969 printf("%s: ", cdevname());
970 pfatal("BAD SUPER BLOCK: %s\n", s
);
974 * Calculate a prototype superblock based on information in the disk label.
975 * When done the cgsblock macro can be calculated and the fs_ncg field
976 * can be used. Do NOT attempt to use other macros without verifying that
977 * their needed information is available!
980 calcsb(const char *dev
, int devfd
, struct fs
*fs
)
982 struct dkwedge_info dkw
;
983 struct disk_geom geo
;
986 if (getdiskinfo(dev
, fsreadfd
, NULL
, &geo
, &dkw
) == -1)
987 pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev
);
988 if (dkw
.dkw_parent
[0] == '\0') {
989 pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev
);
992 if (strcmp(dkw
.dkw_ptype
, DKW_PTYPE_FFS
) &&
993 strcmp(dkw
.dkw_ptype
, DKW_PTYPE_APPLEUFS
)) {
994 pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n",
998 if (geo
.dg_secsize
== 0) {
999 pfatal("%s: CANNOT FIGURE OUT SECTOR SIZE\n", dev
);
1002 if (geo
.dg_secpercyl
== 0) {
1003 pfatal("%s: CANNOT FIGURE OUT SECTORS PER CYLINDER\n", dev
);
1006 if (sblk
.b_un
.b_fs
->fs_fsize
== 0) {
1007 pfatal("%s: CANNOT FIGURE OUT FRAG BLOCK SIZE\n", dev
);
1010 if (sblk
.b_un
.b_fs
->fs_fpg
== 0) {
1011 pfatal("%s: CANNOT FIGURE OUT FRAGS PER GROUP\n", dev
);
1014 if (sblk
.b_un
.b_fs
->fs_old_cpg
== 0) {
1015 pfatal("%s: CANNOT FIGURE OUT OLD CYLINDERS PER GROUP\n", dev
);
1018 memcpy(fs
, sblk
.b_un
.b_fs
, sizeof(struct fs
));
1019 nspf
= fs
->fs_fsize
/ geo
.dg_secsize
;
1020 fs
->fs_old_nspf
= nspf
;
1021 for (fs
->fs_fsbtodb
= 0, i
= nspf
; i
> 1; i
>>= 1)
1023 dev_bsize
= geo
.dg_secsize
;
1024 if (fs
->fs_magic
== FS_UFS2_MAGIC
) {
1025 fs
->fs_ncg
= howmany(fs
->fs_size
, fs
->fs_fpg
);
1026 } else /* if (fs->fs_magic == FS_UFS1_MAGIC) */ {
1027 fs
->fs_old_cgmask
= 0xffffffff;
1028 for (i
= geo
.dg_ntracks
; i
> 1; i
>>= 1)
1029 fs
->fs_old_cgmask
<<= 1;
1030 if (!POWEROF2(geo
.dg_ntracks
))
1031 fs
->fs_old_cgmask
<<= 1;
1032 fs
->fs_old_cgoffset
= roundup(
1033 howmany(geo
.dg_nsectors
, nspf
), fs
->fs_frag
);
1034 fs
->fs_fpg
= (fs
->fs_old_cpg
* geo
.dg_secpercyl
) / nspf
;
1035 fs
->fs_ncg
= howmany(fs
->fs_size
/ geo
.dg_secpercyl
,