Home | History | Annotate | Line # | Download | only in fsck_ffs
setup.c revision 1.82.6.1
      1 /*	$NetBSD: setup.c,v 1.82.6.1 2008/06/10 14:51:21 simonb Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1980, 1986, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     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.
     18  *
     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
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 #if 0
     35 static char sccsid[] = "@(#)setup.c	8.10 (Berkeley) 5/9/95";
     36 #else
     37 __RCSID("$NetBSD: setup.c,v 1.82.6.1 2008/06/10 14:51:21 simonb Exp $");
     38 #endif
     39 #endif /* not lint */
     40 
     41 #include <sys/param.h>
     42 #include <sys/time.h>
     43 #include <sys/stat.h>
     44 #include <sys/ioctl.h>
     45 #include <sys/file.h>
     46 #include <sys/disk.h>
     47 
     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>
     53 
     54 #include <ctype.h>
     55 #include <err.h>
     56 #include <errno.h>
     57 #include <stdio.h>
     58 #include <stdlib.h>
     59 #include <string.h>
     60 
     61 #include "fsck.h"
     62 #include "extern.h"
     63 #include "fsutil.h"
     64 #include "partutil.h"
     65 #include "exitvalues.h"
     66 
     67 #define POWEROF2(num)	(((num) & ((num) - 1)) == 0)
     68 
     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);
     73 
     74 int16_t sblkpostbl[256];
     75 
     76 /*
     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).
     80  */
     81 int
     82 setup(const char *dev)
     83 {
     84 	long cg, size, asked, i, j;
     85 	long bmapsize;
     86 	struct disk_geom geo;
     87 	struct dkwedge_info dkw;
     88 	off_t sizepb;
     89 	struct stat statb;
     90 	struct fs proto;
     91 	int doskipclean;
     92 	u_int64_t maxfilesize;
     93 	struct csum *ccsp;
     94 
     95 	havesb = 0;
     96 	fswritefd = -1;
     97 	doskipclean = skipclean;
     98 	if (stat(dev, &statb) < 0) {
     99 		printf("Can't stat %s: %s\n", dev, strerror(errno));
    100 		return (0);
    101 	}
    102 	if (!forceimage && !S_ISCHR(statb.st_mode)) {
    103 		pfatal("%s is not a character device", dev);
    104 		if (reply("CONTINUE") == 0)
    105 			return (0);
    106 	}
    107 	if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
    108 		printf("Can't open %s: %s\n", dev, strerror(errno));
    109 		return (0);
    110 	}
    111 	if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) {
    112 		fswritefd = -1;
    113 		if (preen)
    114 			pfatal("NO WRITE ACCESS");
    115 		printf("** %s (NO WRITE)\n", dev);
    116 		quiet = 0;
    117 	} else
    118 		if (!preen && !quiet)
    119 			printf("** %s\n", dev);
    120 	fsmodified = 0;
    121 	lfdir = 0;
    122 	initbarea(&sblk);
    123 	initbarea(&asblk);
    124 	sblk.b_un.b_buf = malloc(SBLOCKSIZE);
    125 	sblock = malloc(SBLOCKSIZE);
    126 	asblk.b_un.b_buf = malloc(SBLOCKSIZE);
    127 	altsblock = malloc(SBLOCKSIZE);
    128 	if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL ||
    129 		sblock == NULL || altsblock == NULL)
    130 		errexit("Cannot allocate space for superblock");
    131 	if (!forceimage && getdiskinfo(dev, fsreadfd, NULL, &geo, &dkw) != -1)
    132 		dev_bsize = secsize = geo.dg_secsize;
    133 	else
    134 		dev_bsize = secsize = DEV_BSIZE;
    135 	/*
    136 	 * Read in the superblock, looking for alternates if necessary
    137 	 */
    138 	if (readsb(1) == 0) {
    139 		if (bflag || preen || forceimage ||
    140 		    calcsb(dev, fsreadfd, &proto) == 0)
    141 			return(0);
    142 		if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
    143 			return (0);
    144 		for (cg = 0; cg < proto.fs_ncg; cg++) {
    145 			bflag = fsbtodb(&proto, cgsblock(&proto, cg));
    146 			if (readsb(0) != 0)
    147 				break;
    148 		}
    149 		if (cg >= proto.fs_ncg) {
    150 			printf("%s %s\n%s %s\n%s %s\n",
    151 				"SEARCH FOR ALTERNATE SUPER-BLOCK",
    152 				"FAILED. YOU MUST USE THE",
    153 				"-b OPTION TO fsck_ffs TO SPECIFY THE",
    154 				"LOCATION OF AN ALTERNATE",
    155 				"SUPER-BLOCK TO SUPPLY NEEDED",
    156 				"INFORMATION; SEE fsck_ffs(8).");
    157 			return(0);
    158 		}
    159 		doskipclean = 0;
    160 		pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
    161 	}
    162 	if (sblock->fs_flags & FS_DOWAPBL) {
    163 		if (preen) {
    164 			if (!quiet)
    165 				pwarn("file system is journaled; not checking\n");
    166 			return (-1);
    167 		}
    168 		if (!quiet)
    169 			pwarn("** File system is journaled; replaying journal\n");
    170 		replay_wapbl();
    171 		doskipclean = 0;
    172 		sblock->fs_flags &= ~FS_DOWAPBL;
    173 		sbdirty();
    174 		/* Although we may have updated the superblock from the
    175 		 * journal, we are still going to do a full check, so we
    176 		 * don't bother to re-read the superblock from the journal.
    177 		 * XXX, instead we could re-read the superblock and then not
    178 		 * force doskipclean = 0
    179 		 */
    180 	}
    181 	if (debug)
    182 		printf("clean = %d\n", sblock->fs_clean);
    183 	if (doswap)
    184 		doskipclean = 0;
    185 	if (sblock->fs_clean & FS_ISCLEAN) {
    186 		if (doskipclean) {
    187 			if (!quiet)
    188 				pwarn("%sile system is clean; not checking\n",
    189 				    preen ? "f" : "** F");
    190 			return (-1);
    191 		}
    192 		if (!preen && !doswap)
    193 			pwarn("** File system is already clean\n");
    194 	}
    195 	maxfsblock = sblock->fs_size;
    196 	maxino = sblock->fs_ncg * sblock->fs_ipg;
    197 	sizepb = sblock->fs_bsize;
    198 	maxfilesize = sblock->fs_bsize * NDADDR - 1;
    199 	for (i = 0; i < NIADDR; i++) {
    200 		sizepb *= NINDIR(sblock);
    201 		maxfilesize += sizepb;
    202 	}
    203 	if ((!is_ufs2 && cvtlevel >= 4) &&
    204 			(sblock->fs_old_flags & FS_FLAGS_UPDATED) == 0) {
    205 		if (preen)
    206 			pwarn("CONVERTING TO NEW SUPERBLOCK LAYOUT\n");
    207 		else if (!reply("CONVERT TO NEW SUPERBLOCK LAYOUT"))
    208 			return(0);
    209 		sblock->fs_old_flags |= FS_FLAGS_UPDATED;
    210 		/* Disable the postbl tables */
    211 		sblock->fs_old_cpc = 0;
    212 		sblock->fs_old_nrpos = 1;
    213 		sblock->fs_old_trackskew = 0;
    214 		/* The other fields have already been updated by
    215 		 * sb_oldfscompat_read
    216 		 */
    217 		sbdirty();
    218 	}
    219 	if (!is_ufs2 && cvtlevel == 3 &&
    220 	    (sblock->fs_old_flags & FS_FLAGS_UPDATED)) {
    221 		if (preen)
    222 			pwarn("DOWNGRADING TO OLD SUPERBLOCK LAYOUT\n");
    223 		else if (!reply("DOWNGRADE TO OLD SUPERBLOCK LAYOUT"))
    224 			return(0);
    225 		sblock->fs_old_flags &= ~FS_FLAGS_UPDATED;
    226 		sb_oldfscompat_write(sblock, sblock);
    227 		sblock->fs_old_flags &= ~FS_FLAGS_UPDATED; /* just in case */
    228 		/* Leave postbl tables disabled, but blank its superblock region anyway */
    229 		sblock->fs_old_postblformat = FS_DYNAMICPOSTBLFMT;
    230 		sblock->fs_old_cpc = 0;
    231 		sblock->fs_old_nrpos = 1;
    232 		sblock->fs_old_trackskew = 0;
    233 		memset(&sblock->fs_old_postbl_start, 0xff, 256);
    234 		sb_oldfscompat_read(sblock, &sblocksave);
    235 		sbdirty();
    236 	}
    237 	/*
    238 	 * Check and potentially fix certain fields in the super block.
    239 	 */
    240 	if (sblock->fs_flags & ~(FS_KNOWN_FLAGS)) {
    241 		pfatal("UNKNOWN FLAGS=0x%08x IN SUPERBLOCK", sblock->fs_flags);
    242 		if (reply("CLEAR") == 1) {
    243 			sblock->fs_flags &= FS_KNOWN_FLAGS;
    244 			sbdirty();
    245 		}
    246 	}
    247 	if (sblock->fs_optim != FS_OPTTIME && sblock->fs_optim != FS_OPTSPACE) {
    248 		pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK");
    249 		if (reply("SET TO DEFAULT") == 1) {
    250 			sblock->fs_optim = FS_OPTTIME;
    251 			sbdirty();
    252 		}
    253 	}
    254 	if ((sblock->fs_minfree < 0 || sblock->fs_minfree > 99)) {
    255 		pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
    256 			sblock->fs_minfree);
    257 		if (reply("SET TO DEFAULT") == 1) {
    258 			sblock->fs_minfree = 10;
    259 			sbdirty();
    260 		}
    261 	}
    262 	if (!is_ufs2 && sblock->fs_old_postblformat != FS_42POSTBLFMT &&
    263 	    (sblock->fs_old_interleave < 1 ||
    264 	    sblock->fs_old_interleave > sblock->fs_old_nsect)) {
    265 		pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK",
    266 			sblock->fs_old_interleave);
    267 		sblock->fs_old_interleave = 1;
    268 		if (preen)
    269 			printf(" (FIXED)\n");
    270 		if (preen || reply("SET TO DEFAULT") == 1) {
    271 			sbdirty();
    272 			dirty(&asblk);
    273 		}
    274 	}
    275 	if (!is_ufs2 && sblock->fs_old_postblformat != FS_42POSTBLFMT &&
    276 	    (sblock->fs_old_npsect < sblock->fs_old_nsect ||
    277 	    sblock->fs_old_npsect > sblock->fs_old_nsect*2)) {
    278 		pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK",
    279 			sblock->fs_old_npsect);
    280 		sblock->fs_old_npsect = sblock->fs_old_nsect;
    281 		if (preen)
    282 			printf(" (FIXED)\n");
    283 		if (preen || reply("SET TO DEFAULT") == 1) {
    284 			sbdirty();
    285 			dirty(&asblk);
    286 		}
    287 	}
    288 	if (sblock->fs_bmask != ~(sblock->fs_bsize - 1)) {
    289 		pwarn("INCORRECT BMASK=0x%x IN SUPERBLOCK",
    290 			sblock->fs_bmask);
    291 		sblock->fs_bmask = ~(sblock->fs_bsize - 1);
    292 		if (preen)
    293 			printf(" (FIXED)\n");
    294 		if (preen || reply("FIX") == 1) {
    295 			sbdirty();
    296 			dirty(&asblk);
    297 		}
    298 	}
    299 	if (sblock->fs_fmask != ~(sblock->fs_fsize - 1)) {
    300 		pwarn("INCORRECT FMASK=0x%x IN SUPERBLOCK",
    301 			sblock->fs_fmask);
    302 		sblock->fs_fmask = ~(sblock->fs_fsize - 1);
    303 		if (preen)
    304 			printf(" (FIXED)\n");
    305 		if (preen || reply("FIX") == 1) {
    306 			sbdirty();
    307 			dirty(&asblk);
    308 		}
    309 	}
    310 	if (is_ufs2 || sblock->fs_old_inodefmt >= FS_44INODEFMT) {
    311 		if (sblock->fs_maxfilesize != maxfilesize) {
    312 			pwarn("INCORRECT MAXFILESIZE=%lld IN SUPERBLOCK",
    313 			    (unsigned long long)sblock->fs_maxfilesize);
    314 			sblock->fs_maxfilesize = maxfilesize;
    315 			if (preen)
    316 				printf(" (FIXED)\n");
    317 			if (preen || reply("FIX") == 1) {
    318 				sbdirty();
    319 				dirty(&asblk);
    320 			}
    321 		}
    322 		if ((is_ufs2 && sblock->fs_maxsymlinklen != MAXSYMLINKLEN_UFS2)
    323 		    ||
    324 		   (!is_ufs2 && sblock->fs_maxsymlinklen != MAXSYMLINKLEN_UFS1))
    325 		    {
    326 			pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK",
    327 				sblock->fs_maxsymlinklen);
    328 			sblock->fs_maxsymlinklen = is_ufs2 ?
    329 			    MAXSYMLINKLEN_UFS2 : MAXSYMLINKLEN_UFS1;
    330 			if (preen)
    331 				printf(" (FIXED)\n");
    332 			if (preen || reply("FIX") == 1) {
    333 				sbdirty();
    334 				dirty(&asblk);
    335 			}
    336 		}
    337 		if (sblock->fs_qbmask != ~sblock->fs_bmask) {
    338 			pwarn("INCORRECT QBMASK=%#llx IN SUPERBLOCK",
    339 			    (unsigned long long)sblock->fs_qbmask);
    340 			sblock->fs_qbmask = ~sblock->fs_bmask;
    341 			if (preen)
    342 				printf(" (FIXED)\n");
    343 			if (preen || reply("FIX") == 1) {
    344 				sbdirty();
    345 				dirty(&asblk);
    346 			}
    347 		}
    348 		if (sblock->fs_qfmask != ~sblock->fs_fmask) {
    349 			pwarn("INCORRECT QFMASK=%#llx IN SUPERBLOCK",
    350 			    (unsigned long long)sblock->fs_qfmask);
    351 			sblock->fs_qfmask = ~sblock->fs_fmask;
    352 			if (preen)
    353 				printf(" (FIXED)\n");
    354 			if (preen || reply("FIX") == 1) {
    355 				sbdirty();
    356 				dirty(&asblk);
    357 			}
    358 		}
    359 		newinofmt = 1;
    360 	} else {
    361 		sblock->fs_qbmask = ~sblock->fs_bmask;
    362 		sblock->fs_qfmask = ~sblock->fs_fmask;
    363 		newinofmt = 0;
    364 	}
    365 	/*
    366 	 * Convert to new inode format.
    367 	 */
    368 	if (!is_ufs2 && cvtlevel >= 2 &&
    369 	    sblock->fs_old_inodefmt < FS_44INODEFMT) {
    370 		if (preen)
    371 			pwarn("CONVERTING TO NEW INODE FORMAT\n");
    372 		else if (!reply("CONVERT TO NEW INODE FORMAT"))
    373 			return(0);
    374 		doinglevel2++;
    375 		sblock->fs_old_inodefmt = FS_44INODEFMT;
    376 		sblock->fs_maxfilesize = maxfilesize;
    377 		sblock->fs_maxsymlinklen = MAXSYMLINKLEN_UFS1;
    378 		sblock->fs_qbmask = ~sblock->fs_bmask;
    379 		sblock->fs_qfmask = ~sblock->fs_fmask;
    380 		sbdirty();
    381 		dirty(&asblk);
    382 	}
    383 	/*
    384 	 * Convert to new cylinder group format.
    385 	 */
    386 	if (!is_ufs2 && cvtlevel >= 1 &&
    387 	    sblock->fs_old_postblformat == FS_42POSTBLFMT) {
    388 		if (preen)
    389 			pwarn("CONVERTING TO NEW CYLINDER GROUP FORMAT\n");
    390 		else if (!reply("CONVERT TO NEW CYLINDER GROUP FORMAT"))
    391 			return(0);
    392 		doinglevel1++;
    393 		sblock->fs_old_postblformat = FS_DYNAMICPOSTBLFMT;
    394 		sblock->fs_old_nrpos = 8;
    395 		sblock->fs_old_postbloff =
    396 		    (char *)(&sblock->fs_old_postbl_start) -
    397 		    (char *)(&sblock->fs_firstfield);
    398 		sblock->fs_old_rotbloff =
    399 				(char *)(&sblock->fs_magic+1) -
    400 				(char *)(&sblock->fs_firstfield);
    401 		sblock->fs_cgsize =
    402 			fragroundup(sblock, CGSIZE(sblock));
    403 		sbdirty();
    404 		dirty(&asblk);
    405 	}
    406 	if (asblk.b_dirty && !bflag) {
    407 		memmove(sblk.b_un.b_fs, sblock, SBLOCKSIZE);
    408 		sb_oldfscompat_write(sblk.b_un.b_fs, sblocksave);
    409 		if (needswap)
    410 			ffs_sb_swap(sblk.b_un.b_fs, sblk.b_un.b_fs);
    411 		memmove(asblk.b_un.b_fs, sblk.b_un.b_fs, (size_t)sblock->fs_sbsize);
    412 		flush(fswritefd, &asblk);
    413 	}
    414 	/*
    415 	 * read in the summary info.
    416 	 */
    417 	asked = 0;
    418 	sblock->fs_csp = (struct csum *)calloc(1, sblock->fs_cssize);
    419 	if (sblock->fs_csp == NULL) {
    420 		pwarn("cannot alloc %u bytes for summary info\n",
    421 		    sblock->fs_cssize);
    422 		goto badsblabel;
    423 	}
    424 	for (i = 0, j = 0; i < sblock->fs_cssize; i += sblock->fs_bsize, j++) {
    425 		size = sblock->fs_cssize - i < sblock->fs_bsize ?
    426 		    sblock->fs_cssize - i : sblock->fs_bsize;
    427 		ccsp = (struct csum *)((char *)sblock->fs_csp + i);
    428 		if (bread(fsreadfd, (char *)ccsp,
    429 		    fsbtodb(sblock, sblock->fs_csaddr + j * sblock->fs_frag),
    430 		    size) != 0 && !asked) {
    431 			pfatal("BAD SUMMARY INFORMATION");
    432 			if (reply("CONTINUE") == 0) {
    433 				markclean = 0;
    434 				exit(FSCK_EXIT_CHECK_FAILED);
    435 			}
    436 			asked++;
    437 		}
    438 		if (doswap) {
    439 			ffs_csum_swap(ccsp, ccsp, size);
    440 			bwrite(fswritefd, (char *)ccsp,
    441 			    fsbtodb(sblock,
    442 				sblock->fs_csaddr + j * sblock->fs_frag),
    443 			    size);
    444 		}
    445 		if (needswap)
    446 			ffs_csum_swap(ccsp, ccsp, size);
    447 	}
    448 	/*
    449 	 * allocate and initialize the necessary maps
    450 	 */
    451 	bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t));
    452 	blockmap = calloc((unsigned)bmapsize, sizeof (char));
    453 	if (blockmap == NULL) {
    454 		pwarn("cannot alloc %u bytes for blockmap\n",
    455 		    (unsigned)bmapsize);
    456 		goto badsblabel;
    457 	}
    458 	inostathead = calloc((unsigned)(sblock->fs_ncg),
    459 	    sizeof(struct inostatlist));
    460 	if (inostathead == NULL) {
    461 		pwarn("cannot alloc %u bytes for inostathead\n",
    462 		    (unsigned)(sizeof(struct inostatlist) * (sblock->fs_ncg)));
    463 		goto badsblabel;
    464 	}
    465 	/*
    466 	 * cs_ndir may be inaccurate, particularly if we're using the -b
    467 	 * option, so set a minimum to prevent bogus subdirectory reconnects
    468 	 * and really inefficient directory scans.
    469 	 * Also set a maximum in case the value is too large.
    470 	 */
    471 	numdirs = sblock->fs_cstotal.cs_ndir;
    472 	if (numdirs < 1024)
    473 		numdirs = 1024;
    474 	if (numdirs > maxino + 1)
    475 		numdirs = maxino + 1;
    476 	dirhash = numdirs;
    477 	inplast = 0;
    478 	listmax = numdirs + 10;
    479 	inpsort = (struct inoinfo **)calloc((unsigned)listmax,
    480 	    sizeof(struct inoinfo *));
    481 	inphead = (struct inoinfo **)calloc((unsigned)numdirs,
    482 	    sizeof(struct inoinfo *));
    483 	if (inpsort == NULL || inphead == NULL) {
    484 		pwarn("cannot alloc %u bytes for inphead\n",
    485 		    (unsigned)(numdirs * sizeof(struct inoinfo *)));
    486 		goto badsblabel;
    487 	}
    488 	cgrp = malloc(sblock->fs_cgsize);
    489 	if (cgrp == NULL) {
    490 		pwarn("cannot alloc %u bytes for cylinder group\n",
    491 		    sblock->fs_cgsize);
    492 		goto badsblabel;
    493 	}
    494 	bufinit();
    495 	if (sblock->fs_flags & FS_DOSOFTDEP)
    496 		usedsoftdep = 1;
    497 	else
    498 		usedsoftdep = 0;
    499 
    500 	if (!forceimage && dkw.dkw_parent[0])
    501 		if (strcmp(dkw.dkw_ptype, DKW_PTYPE_APPLEUFS) == 0)
    502 			isappleufs = 1;
    503 
    504 	if (readappleufs())
    505 		isappleufs = 1;
    506 
    507 	dirblksiz = DIRBLKSIZ;
    508 	if (isappleufs)
    509 		dirblksiz = APPLEUFS_DIRBLKSIZ;
    510 
    511 	if (debug)
    512 		printf("isappleufs = %d, dirblksiz = %d\n", isappleufs, dirblksiz);
    513 
    514 	return (1);
    515 
    516 badsblabel:
    517 	markclean=0;
    518 	ckfini();
    519 	return (0);
    520 }
    521 
    522 static int
    523 readappleufs(void)
    524 {
    525 	daddr_t label = APPLEUFS_LABEL_OFFSET / dev_bsize;
    526 	struct appleufslabel *appleufs;
    527 	int i;
    528 
    529 	/* XXX do we have to deal with APPLEUFS_LABEL_OFFSET not
    530 	 * being block aligned (CD's?)
    531 	 */
    532 	if (bread(fsreadfd, (char *)appleufsblk.b_un.b_fs, label,
    533 	    (long)APPLEUFS_LABEL_SIZE) != 0)
    534 		return 0;
    535 	appleufsblk.b_bno = label;
    536 	appleufsblk.b_size = APPLEUFS_LABEL_SIZE;
    537 
    538 	appleufs = appleufsblk.b_un.b_appleufs;
    539 
    540 	if (ntohl(appleufs->ul_magic) != APPLEUFS_LABEL_MAGIC) {
    541 		if (!isappleufs) {
    542 			return 0;
    543 		} else {
    544 			pfatal("MISSING APPLEUFS VOLUME LABEL\n");
    545 			if (reply("FIX") == 0) {
    546 				return 1;
    547 			}
    548 			ffs_appleufs_set(appleufs, NULL, -1, 0);
    549 			appleufsdirty();
    550 		}
    551 	}
    552 
    553 	if (ntohl(appleufs->ul_version) != APPLEUFS_LABEL_VERSION) {
    554 		pwarn("INCORRECT APPLE UFS VERSION NUMBER (%d should be %d)",
    555 			ntohl(appleufs->ul_version),APPLEUFS_LABEL_VERSION);
    556 		if (preen) {
    557 			printf(" (CORRECTED)\n");
    558 		}
    559 		if (preen || reply("CORRECT")) {
    560 			appleufs->ul_version = htonl(APPLEUFS_LABEL_VERSION);
    561 			appleufsdirty();
    562 		}
    563 	}
    564 
    565 	if (ntohs(appleufs->ul_namelen) > APPLEUFS_MAX_LABEL_NAME) {
    566 		pwarn("APPLE UFS LABEL NAME TOO LONG");
    567 		if (preen) {
    568 			printf(" (TRUNCATED)\n");
    569 		}
    570 		if (preen || reply("TRUNCATE")) {
    571 			appleufs->ul_namelen = htons(APPLEUFS_MAX_LABEL_NAME);
    572 			appleufsdirty();
    573 		}
    574 	}
    575 
    576 	if (ntohs(appleufs->ul_namelen) == 0) {
    577 		pwarn("MISSING APPLE UFS LABEL NAME");
    578 		if (preen) {
    579 			printf(" (FIXED)\n");
    580 		}
    581 		if (preen || reply("FIX")) {
    582 			ffs_appleufs_set(appleufs, NULL, -1, 0);
    583 			appleufsdirty();
    584 		}
    585 	}
    586 
    587 	/* Scan name for first illegal character */
    588 	for (i=0;i<ntohs(appleufs->ul_namelen);i++) {
    589 		if ((appleufs->ul_name[i] == '\0') ||
    590 			(appleufs->ul_name[i] == ':') ||
    591 			(appleufs->ul_name[i] == '/')) {
    592 			pwarn("APPLE UFS LABEL NAME CONTAINS ILLEGAL CHARACTER");
    593 			if (preen) {
    594 				printf(" (TRUNCATED)\n");
    595 			}
    596 			if (preen || reply("TRUNCATE")) {
    597 				appleufs->ul_namelen = i+1;
    598 				appleufsdirty();
    599 			}
    600 			break;
    601 		}
    602 	}
    603 
    604 	/* Check the checksum last, because if anything else was wrong,
    605 	 * then the checksum gets reset anyway.
    606 	 */
    607 	appleufs->ul_checksum = 0;
    608 	appleufs->ul_checksum = ffs_appleufs_cksum(appleufs);
    609 	if (appleufsblk.b_un.b_appleufs->ul_checksum != appleufs->ul_checksum) {
    610 		pwarn("INVALID APPLE UFS CHECKSUM (%#04x should be %#04x)",
    611 			appleufsblk.b_un.b_appleufs->ul_checksum, appleufs->ul_checksum);
    612 		if (preen) {
    613 			printf(" (CORRECTED)\n");
    614 		}
    615 		if (preen || reply("CORRECT")) {
    616 			appleufsdirty();
    617 		} else {
    618 			/* put the incorrect checksum back in place */
    619 			appleufs->ul_checksum = appleufsblk.b_un.b_appleufs->ul_checksum;
    620 		}
    621 	}
    622 	return 1;
    623 }
    624 
    625 /*
    626  * Detect byte order. Return 0 if valid magic found, -1 otherwise.
    627  */
    628 static int
    629 detect_byteorder(struct fs *fs, int sblockoff)
    630 {
    631 	if (sblockoff == SBLOCK_UFS2 && (fs->fs_magic == FS_UFS1_MAGIC ||
    632 	    fs->fs_magic == bswap32(FS_UFS1_MAGIC)))
    633 		/* Likely to be the first alternate of a fs with 64k blocks */
    634 		return -1;
    635 	if (fs->fs_magic == FS_UFS1_MAGIC || fs->fs_magic == FS_UFS2_MAGIC) {
    636 		if (endian == 0 || BYTE_ORDER == endian) {
    637 			needswap = 0;
    638 			doswap = do_blkswap = do_dirswap = 0;
    639 		} else {
    640 			needswap = 1;
    641 			doswap = do_blkswap = do_dirswap = 1;
    642 		}
    643 		return 0;
    644 	} else if (fs->fs_magic == bswap32(FS_UFS1_MAGIC) ||
    645 		   fs->fs_magic == bswap32(FS_UFS2_MAGIC)) {
    646 		if (endian == 0 || BYTE_ORDER != endian) {
    647 			needswap = 1;
    648 			doswap = do_blkswap = do_dirswap = 0;
    649 		} else {
    650 			needswap = 0;
    651 			doswap = do_blkswap = do_dirswap = 1;
    652 		}
    653 		return 0;
    654 	}
    655 	return -1;
    656 }
    657 
    658 /*
    659  * Possible superblock locations ordered from most to least likely.
    660  */
    661 static off_t sblock_try[] = SBLOCKSEARCH;
    662 
    663 /*
    664  * Read in the super block and its summary info.
    665  */
    666 static int
    667 readsb(int listerr)
    668 {
    669 	daddr_t super = 0;
    670 	struct fs *fs;
    671 	int i;
    672 
    673 	if (bflag) {
    674 		super = bflag;
    675 		if (bread(fsreadfd, (char *)sblk.b_un.b_fs, super,
    676 		    (long)SBLOCKSIZE) != 0)
    677 			return (0);
    678 		fs = sblk.b_un.b_fs;
    679 		if (detect_byteorder(fs, -1) < 0) {
    680 			badsb(listerr, "MAGIC NUMBER WRONG");
    681 			return (0);
    682 		}
    683 	} else {
    684 		for (i = 0; sblock_try[i] != -1; i++) {
    685 			super = sblock_try[i] / dev_bsize;
    686 			if (bread(fsreadfd, (char *)sblk.b_un.b_fs,
    687 			    super, (long)SBLOCKSIZE) != 0)
    688 				continue;
    689 			fs = sblk.b_un.b_fs;
    690 			if (detect_byteorder(fs, sblock_try[i]) == 0)
    691 				break;
    692 		}
    693 		if (sblock_try[i] == -1) {
    694 			badsb(listerr, "CAN'T FIND SUPERBLOCK");
    695 			return (0);
    696 		}
    697 	}
    698 	if (doswap) {
    699 		if (preen)
    700 			errx(FSCK_EXIT_USAGE,
    701 			    "Incompatible options -B and -p");
    702 		if (nflag)
    703 			errx(FSCK_EXIT_USAGE,
    704 			    "Incompatible options -B and -n");
    705 		if (endian == LITTLE_ENDIAN) {
    706 			if (!reply("CONVERT TO LITTLE ENDIAN"))
    707 				return 0;
    708 		} else if (endian == BIG_ENDIAN) {
    709 			if (!reply("CONVERT TO BIG ENDIAN"))
    710 				return 0;
    711 		} else
    712 			pfatal("INTERNAL ERROR: unknown endian");
    713 	}
    714 	if (needswap)
    715 		pwarn("** Swapped byte order\n");
    716 	/* swap SB byte order if asked */
    717 	if (doswap)
    718 		ffs_sb_swap(sblk.b_un.b_fs, sblk.b_un.b_fs);
    719 
    720 	memmove(sblock, sblk.b_un.b_fs, SBLOCKSIZE);
    721 	if (needswap)
    722 		ffs_sb_swap(sblk.b_un.b_fs, sblock);
    723 
    724 	is_ufs2 = sblock->fs_magic == FS_UFS2_MAGIC;
    725 
    726 	/*
    727 	 * run a few consistency checks of the super block
    728 	 */
    729 	if (sblock->fs_sbsize > SBLOCKSIZE)
    730 		{ badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); }
    731 	/*
    732 	 * Compute block size that the filesystem is based on,
    733 	 * according to fsbtodb, and adjust superblock block number
    734 	 * so we can tell if this is an alternate later.
    735 	 */
    736 	super *= dev_bsize;
    737 	dev_bsize = sblock->fs_fsize / fsbtodb(sblock, 1);
    738 	sblk.b_bno = super / dev_bsize;
    739 	sblk.b_size = SBLOCKSIZE;
    740 	if (bflag)
    741 		goto out;
    742 	/*
    743 	 * Set all possible fields that could differ, then do check
    744 	 * of whole super block against an alternate super block->
    745 	 * When an alternate super-block is specified this check is skipped.
    746 	 */
    747 	getblk(&asblk, cgsblock(sblock, sblock->fs_ncg - 1), sblock->fs_sbsize);
    748 	if (asblk.b_errs)
    749 		return (0);
    750 	/* swap SB byte order if asked */
    751 	if (doswap)
    752 		ffs_sb_swap(asblk.b_un.b_fs, asblk.b_un.b_fs);
    753 
    754 	memmove(altsblock, asblk.b_un.b_fs, sblock->fs_sbsize);
    755 	if (needswap)
    756 		ffs_sb_swap(asblk.b_un.b_fs, altsblock);
    757 	if (cmpsblks(sblock, altsblock)) {
    758 		if (debug) {
    759 			uint32_t *nlp, *olp, *endlp;
    760 
    761 			printf("superblock mismatches\n");
    762 			nlp = (uint32_t *)altsblock;
    763 			olp = (uint32_t *)sblock;
    764 			endlp = olp + (sblock->fs_sbsize / sizeof *olp);
    765 			for ( ; olp < endlp; olp++, nlp++) {
    766 				if (*olp == *nlp)
    767 					continue;
    768 				printf("offset %#x, original 0x%08x, alternate "
    769 				       "0x%08x\n",
    770 				    (int)((uint8_t *)olp-(uint8_t *)sblock),
    771 				    *olp, *nlp);
    772 			}
    773 		}
    774 		badsb(listerr,
    775 		"VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
    776 /*
    777 		return (0);
    778 */
    779 	}
    780 out:
    781 
    782 	sb_oldfscompat_read(sblock, &sblocksave);
    783 
    784 	/* Now we know the SB is valid, we can write it back if needed */
    785 	if (doswap) {
    786 		sbdirty();
    787 		dirty(&asblk);
    788 	}
    789 	havesb = 1;
    790 	return (1);
    791 }
    792 
    793 int
    794 cmpsblks(const struct fs *sb, struct fs *asb)
    795 {
    796 	if (!is_ufs2 && ((sb->fs_old_flags & FS_FLAGS_UPDATED) == 0)) {
    797 		if (sb->fs_old_postblformat < FS_DYNAMICPOSTBLFMT)
    798 			return cmpsblks42(sb, asb);
    799 		else
    800 			return cmpsblks44(sb, asb);
    801 	}
    802 	if (asb->fs_sblkno != sb->fs_sblkno ||
    803 	    asb->fs_cblkno != sb->fs_cblkno ||
    804 	    asb->fs_iblkno != sb->fs_iblkno ||
    805 	    asb->fs_dblkno != sb->fs_dblkno ||
    806 	    asb->fs_ncg != sb->fs_ncg ||
    807 	    asb->fs_bsize != sb->fs_bsize ||
    808 	    asb->fs_fsize != sb->fs_fsize ||
    809 	    asb->fs_frag != sb->fs_frag ||
    810 	    asb->fs_bmask != sb->fs_bmask ||
    811 	    asb->fs_fmask != sb->fs_fmask ||
    812 	    asb->fs_bshift != sb->fs_bshift ||
    813 	    asb->fs_fshift != sb->fs_fshift ||
    814 	    asb->fs_fragshift != sb->fs_fragshift ||
    815 	    asb->fs_fsbtodb != sb->fs_fsbtodb ||
    816 	    asb->fs_sbsize != sb->fs_sbsize ||
    817 	    asb->fs_nindir != sb->fs_nindir ||
    818 	    asb->fs_inopb != sb->fs_inopb ||
    819 	    asb->fs_cssize != sb->fs_cssize ||
    820 	    asb->fs_ipg != sb->fs_ipg ||
    821 	    asb->fs_fpg != sb->fs_fpg ||
    822 	    asb->fs_magic != sb->fs_magic)
    823 		return 1;
    824 	return 0;
    825 }
    826 
    827 /* BSD 4.2 performed the following superblock comparison
    828  * It should correspond to FS_42POSTBLFMT
    829  * (although note that in 4.2, the fs_old_postblformat
    830  * field didn't exist and the corresponding bits are
    831  * located near the end of the postbl itself, where they
    832  * are not likely to be used.)
    833  */
    834 int
    835 cmpsblks42(const struct fs *sb, struct fs *asb)
    836 {
    837 	asb->fs_firstfield = sb->fs_firstfield; /* fs_link */
    838 	asb->fs_unused_1 = sb->fs_unused_1; /* fs_rlink */
    839 	asb->fs_old_time = sb->fs_old_time; /* fs_time */
    840 	asb->fs_old_cstotal = sb->fs_old_cstotal; /* fs_cstotal */
    841 	asb->fs_cgrotor = sb->fs_cgrotor;
    842 	asb->fs_fmod = sb->fs_fmod;
    843 	asb->fs_clean = sb->fs_clean;
    844 	asb->fs_ronly = sb->fs_ronly;
    845 	asb->fs_old_flags = sb->fs_old_flags;
    846 	asb->fs_maxcontig = sb->fs_maxcontig;
    847 	asb->fs_minfree = sb->fs_minfree;
    848 	asb->fs_old_rotdelay = sb->fs_old_rotdelay;
    849 	asb->fs_maxbpg = sb->fs_maxbpg;
    850 
    851 	/* The former fs_csp, totaling 128 bytes  */
    852 	memmove(asb->fs_ocsp, sb->fs_ocsp, sizeof sb->fs_ocsp);
    853 	asb->fs_contigdirs = sb->fs_contigdirs;
    854 	asb->fs_csp = sb->fs_csp;
    855 	asb->fs_maxcluster = sb->fs_maxcluster;
    856 	asb->fs_active = sb->fs_active;
    857 
    858 	/* The former fs_fsmnt, totaling 512 bytes */
    859 	memmove(asb->fs_fsmnt, sb->fs_fsmnt, sizeof sb->fs_fsmnt);
    860 	memmove(asb->fs_volname, sb->fs_volname, sizeof sb->fs_volname);
    861 
    862 	return memcmp(sb, asb, sb->fs_sbsize);
    863 }
    864 
    865 /* BSD 4.4 performed the following superblock comparison
    866  * This was used in NetBSD through 1.6.1
    867  *
    868  * Note that this implementation is destructive to asb.
    869  */
    870 int
    871 cmpsblks44(const struct fs *sb, struct fs *asb)
    872 {
    873 	/*
    874 	 * "Copy fields which we don't care if they're different in the
    875 	 * alternate superblocks, as they're either likely to be
    876 	 * different because they're per-cylinder-group specific, or
    877 	 * because they're transient details which are only maintained
    878 	 * in the primary superblock."
    879 	 */
    880 	asb->fs_firstfield = sb->fs_firstfield;
    881 	asb->fs_unused_1 = sb->fs_unused_1;
    882 	asb->fs_old_time = sb->fs_old_time;
    883 	asb->fs_old_cstotal = sb->fs_old_cstotal;
    884 	asb->fs_cgrotor = sb->fs_cgrotor;
    885 	asb->fs_fmod = sb->fs_fmod;
    886 	asb->fs_clean = sb->fs_clean;
    887 	asb->fs_ronly = sb->fs_ronly;
    888 	asb->fs_old_flags = sb->fs_old_flags;
    889 	asb->fs_maxcontig = sb->fs_maxcontig;
    890 	asb->fs_minfree = sb->fs_minfree;
    891 	asb->fs_optim = sb->fs_optim;
    892 	asb->fs_old_rotdelay = sb->fs_old_rotdelay;
    893 	asb->fs_maxbpg = sb->fs_maxbpg;
    894 
    895 	/* The former fs_csp and fs_maxcluster, totaling 128 bytes */
    896 	memmove(asb->fs_ocsp, sb->fs_ocsp, sizeof sb->fs_ocsp);
    897 	asb->fs_contigdirs = sb->fs_contigdirs;
    898 	asb->fs_csp = sb->fs_csp;
    899 	asb->fs_maxcluster = sb->fs_maxcluster;
    900 	asb->fs_active = sb->fs_active;
    901 
    902 	/* The former fs_fsmnt, totaling 512 bytes */
    903 	memmove(asb->fs_fsmnt, sb->fs_fsmnt, sizeof sb->fs_fsmnt);
    904 	memmove(asb->fs_volname, sb->fs_volname, sizeof sb->fs_volname);
    905 
    906 	/* The former fs_sparecon, totaling 200 bytes */
    907 	memmove(asb->fs_snapinum,
    908 		sb->fs_snapinum, sizeof sb->fs_snapinum);
    909 	asb->fs_avgfilesize = sb->fs_avgfilesize;
    910 	asb->fs_avgfpdir = sb->fs_avgfpdir;
    911 	asb->fs_save_cgsize = sb->fs_save_cgsize;
    912 	memmove(asb->fs_sparecon32,
    913 		sb->fs_sparecon32, sizeof sb->fs_sparecon32);
    914 	asb->fs_flags = sb->fs_flags;
    915 
    916 	/* Original comment:
    917 	 * "The following should not have to be copied, but need to be."
    918 	 */
    919 	asb->fs_fsbtodb = sb->fs_fsbtodb;
    920 	asb->fs_old_interleave = sb->fs_old_interleave;
    921 	asb->fs_old_npsect = sb->fs_old_npsect;
    922 	asb->fs_old_nrpos = sb->fs_old_nrpos;
    923 	asb->fs_state = sb->fs_state;
    924 	asb->fs_qbmask = sb->fs_qbmask;
    925 	asb->fs_qfmask = sb->fs_qfmask;
    926 	asb->fs_state = sb->fs_state;
    927 	asb->fs_maxfilesize = sb->fs_maxfilesize;
    928 
    929 	/*
    930 	 * "Compare the superblocks, effectively checking every other
    931 	 * field to see if they differ."
    932 	 */
    933 	return memcmp(sb, asb, sb->fs_sbsize);
    934 }
    935 
    936 
    937 static void
    938 badsb(int listerr, const char *s)
    939 {
    940 
    941 	if (!listerr)
    942 		return;
    943 	if (preen)
    944 		printf("%s: ", cdevname());
    945 	pfatal("BAD SUPER BLOCK: %s\n", s);
    946 }
    947 
    948 /*
    949  * Calculate a prototype superblock based on information in the disk label.
    950  * When done the cgsblock macro can be calculated and the fs_ncg field
    951  * can be used. Do NOT attempt to use other macros without verifying that
    952  * their needed information is available!
    953  */
    954 static int
    955 calcsb(const char *dev, int devfd, struct fs *fs)
    956 {
    957 	struct dkwedge_info dkw;
    958 	struct disk_geom geo;
    959 	int i, nspf;
    960 
    961 	if (getdiskinfo(dev, fsreadfd, NULL, &geo, &dkw) == -1)
    962 		pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
    963 	if (dkw.dkw_parent[0] == '\0') {
    964 		pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
    965 		return (0);
    966 	}
    967 	if (strcmp(dkw.dkw_ptype, DKW_PTYPE_FFS) &&
    968 	    strcmp(dkw.dkw_ptype, DKW_PTYPE_APPLEUFS)) {
    969 		pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n",
    970 		    dev, dkw.dkw_ptype);
    971 		return (0);
    972 	}
    973 	if (geo.dg_secsize == 0) {
    974 		pfatal("%s: CANNOT FIGURE OUT SECTOR SIZE\n", dev);
    975 		return 0;
    976 	}
    977 	if (geo.dg_secpercyl == 0) {
    978 		pfatal("%s: CANNOT FIGURE OUT SECTORS PER CYLINDER\n", dev);
    979 		return 0;
    980 	}
    981 	if (sblk.b_un.b_fs->fs_fsize == 0) {
    982 		pfatal("%s: CANNOT FIGURE OUT FRAG BLOCK SIZE\n", dev);
    983 		return 0;
    984 	}
    985 	if (sblk.b_un.b_fs->fs_fpg == 0) {
    986 		pfatal("%s: CANNOT FIGURE OUT FRAGS PER GROUP\n", dev);
    987 		return 0;
    988 	}
    989 	if (sblk.b_un.b_fs->fs_old_cpg == 0) {
    990 		pfatal("%s: CANNOT FIGURE OUT OLD CYLINDERS PER GROUP\n", dev);
    991 		return 0;
    992 	}
    993 	memcpy(fs, &sblk.b_un.b_fs, sizeof(struct fs));
    994 	nspf = fs->fs_fsize / geo.dg_secsize;
    995 	fs->fs_old_nspf = nspf;
    996 	for (fs->fs_fsbtodb = 0, i = nspf; i > 1; i >>= 1)
    997 		fs->fs_fsbtodb++;
    998 	dev_bsize = geo.dg_secsize;
    999 	if (fs->fs_magic == FS_UFS2_MAGIC) {
   1000 		fs->fs_ncg = howmany(fs->fs_size, fs->fs_fpg);
   1001 	} else /* if (fs->fs_magic == FS_UFS1_MAGIC) */ {
   1002 		fs->fs_old_cgmask = 0xffffffff;
   1003 		for (i = geo.dg_ntracks; i > 1; i >>= 1)
   1004 			fs->fs_old_cgmask <<= 1;
   1005 		if (!POWEROF2(geo.dg_ntracks))
   1006 			fs->fs_old_cgmask <<= 1;
   1007 		fs->fs_old_cgoffset = roundup(
   1008 			howmany(geo.dg_nsectors, nspf), fs->fs_frag);
   1009 		fs->fs_fpg = (fs->fs_old_cpg * geo.dg_secpercyl) / nspf;
   1010 		fs->fs_ncg = howmany(fs->fs_size / geo.dg_secpercyl,
   1011 		    fs->fs_old_cpg);
   1012 	}
   1013 	return (1);
   1014 }
   1015