1 1.111 christos /* $NetBSD: setup.c,v 1.111 2025/06/23 15:07:33 christos Exp $ */ 2 1.19 cgd 3 1.1 cgd /* 4 1.10 mycroft * Copyright (c) 1980, 1986, 1993 5 1.10 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.62 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.28 lukem #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.19 cgd #if 0 35 1.30 lukem static char sccsid[] = "@(#)setup.c 8.10 (Berkeley) 5/9/95"; 36 1.19 cgd #else 37 1.111 christos __RCSID("$NetBSD: setup.c,v 1.111 2025/06/23 15:07:33 christos Exp $"); 38 1.19 cgd #endif 39 1.1 cgd #endif /* not lint */ 40 1.1 cgd 41 1.1 cgd #include <sys/param.h> 42 1.8 cgd #include <sys/time.h> 43 1.1 cgd #include <sys/stat.h> 44 1.1 cgd #include <sys/ioctl.h> 45 1.1 cgd #include <sys/file.h> 46 1.80 christos #include <sys/disk.h> 47 1.15 cgd 48 1.30 lukem #include <ufs/ufs/dinode.h> 49 1.54 dbj #include <ufs/ufs/dir.h> 50 1.33 bouyer #include <ufs/ufs/ufs_bswap.h> 51 1.91 bouyer #include <ufs/ufs/quota2.h> 52 1.30 lukem #include <ufs/ffs/fs.h> 53 1.33 bouyer #include <ufs/ffs/ffs_extern.h> 54 1.30 lukem 55 1.30 lukem #include <ctype.h> 56 1.30 lukem #include <err.h> 57 1.1 cgd #include <errno.h> 58 1.31 lukem #include <stdio.h> 59 1.31 lukem #include <stdlib.h> 60 1.1 cgd #include <string.h> 61 1.26 christos 62 1.1 cgd #include "fsck.h" 63 1.15 cgd #include "extern.h" 64 1.27 christos #include "fsutil.h" 65 1.80 christos #include "partutil.h" 66 1.82 christos #include "exitvalues.h" 67 1.1 cgd 68 1.1 cgd #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 69 1.1 cgd 70 1.78 christos static void badsb(int, const char *); 71 1.67 mrg static int calcsb(const char *, int, struct fs *); 72 1.67 mrg static int readsb(int); 73 1.101 rin #ifndef NO_APPLE_UFS 74 1.67 mrg static int readappleufs(void); 75 1.101 rin #endif 76 1.102 hannken static int check_snapinum(void); 77 1.1 cgd 78 1.65 dbj int16_t sblkpostbl[256]; 79 1.65 dbj 80 1.30 lukem /* 81 1.30 lukem * Read in a superblock finding an alternate if necessary. 82 1.30 lukem * Return 1 if successful, 0 if unsuccessful, -1 if filesystem 83 1.30 lukem * is already clean (preen mode only). 84 1.30 lukem */ 85 1.15 cgd int 86 1.84 bouyer setup(const char *dev, const char *origdev) 87 1.1 cgd { 88 1.106 chs uint32_t cg; 89 1.106 chs long size, asked, i, j; 90 1.110 mlelstv size_t bmapsize; 91 1.80 christos struct disk_geom geo; 92 1.80 christos struct dkwedge_info dkw; 93 1.10 mycroft off_t sizepb; 94 1.10 mycroft struct stat statb; 95 1.1 cgd struct fs proto; 96 1.21 mycroft int doskipclean; 97 1.24 mycroft u_int64_t maxfilesize; 98 1.46 lukem struct csum *ccsp; 99 1.84 bouyer int fd; 100 1.1 cgd 101 1.1 cgd havesb = 0; 102 1.10 mycroft fswritefd = -1; 103 1.21 mycroft doskipclean = skipclean; 104 1.1 cgd if (stat(dev, &statb) < 0) { 105 1.1 cgd printf("Can't stat %s: %s\n", dev, strerror(errno)); 106 1.1 cgd return (0); 107 1.1 cgd } 108 1.51 lukem if (!forceimage && !S_ISCHR(statb.st_mode)) { 109 1.1 cgd pfatal("%s is not a character device", dev); 110 1.1 cgd if (reply("CONTINUE") == 0) 111 1.1 cgd return (0); 112 1.1 cgd } 113 1.1 cgd if ((fsreadfd = open(dev, O_RDONLY)) < 0) { 114 1.1 cgd printf("Can't open %s: %s\n", dev, strerror(errno)); 115 1.1 cgd return (0); 116 1.1 cgd } 117 1.1 cgd if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) { 118 1.1 cgd fswritefd = -1; 119 1.1 cgd if (preen) 120 1.1 cgd pfatal("NO WRITE ACCESS"); 121 1.63 dsl printf("** %s (NO WRITE)\n", dev); 122 1.63 dsl quiet = 0; 123 1.63 dsl } else 124 1.63 dsl if (!preen && !quiet) 125 1.63 dsl printf("** %s\n", dev); 126 1.1 cgd fsmodified = 0; 127 1.1 cgd lfdir = 0; 128 1.1 cgd initbarea(&sblk); 129 1.1 cgd initbarea(&asblk); 130 1.103 jdolecek sblk.b_un.b_buf = aligned_alloc(DEV_BSIZE, SBLOCKSIZE); 131 1.103 jdolecek sblock = aligned_alloc(DEV_BSIZE, SBLOCKSIZE); 132 1.103 jdolecek asblk.b_un.b_buf = aligned_alloc(DEV_BSIZE, SBLOCKSIZE); 133 1.103 jdolecek altsblock = aligned_alloc(DEV_BSIZE, SBLOCKSIZE); 134 1.33 bouyer if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL || 135 1.33 bouyer sblock == NULL || altsblock == NULL) 136 1.82 christos errexit("Cannot allocate space for superblock"); 137 1.84 bouyer if (strcmp(dev, origdev) && !forceimage) { 138 1.84 bouyer /* 139 1.84 bouyer * dev isn't the original fs (for example it's a snapshot) 140 1.84 bouyer * do getdiskinfo on the original device 141 1.84 bouyer */ 142 1.84 bouyer fd = open(origdev, O_RDONLY); 143 1.84 bouyer if (fd < 0) { 144 1.84 bouyer warn("Can't open %s", origdev); 145 1.84 bouyer return (0); 146 1.84 bouyer } 147 1.84 bouyer } else { 148 1.84 bouyer fd = fsreadfd; 149 1.84 bouyer } 150 1.84 bouyer if (!forceimage && getdiskinfo(origdev, fd, NULL, &geo, &dkw) != -1) 151 1.80 christos dev_bsize = secsize = geo.dg_secsize; 152 1.1 cgd else 153 1.1 cgd dev_bsize = secsize = DEV_BSIZE; 154 1.1 cgd /* 155 1.1 cgd * Read in the superblock, looking for alternates if necessary 156 1.1 cgd */ 157 1.1 cgd if (readsb(1) == 0) { 158 1.51 lukem if (bflag || preen || forceimage || 159 1.51 lukem calcsb(dev, fsreadfd, &proto) == 0) 160 1.1 cgd return(0); 161 1.1 cgd if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) 162 1.1 cgd return (0); 163 1.1 cgd for (cg = 0; cg < proto.fs_ncg; cg++) { 164 1.99 dholland bflag = FFS_FSBTODB(&proto, cgsblock(&proto, cg)); 165 1.1 cgd if (readsb(0) != 0) 166 1.1 cgd break; 167 1.1 cgd } 168 1.1 cgd if (cg >= proto.fs_ncg) { 169 1.1 cgd printf("%s %s\n%s %s\n%s %s\n", 170 1.1 cgd "SEARCH FOR ALTERNATE SUPER-BLOCK", 171 1.1 cgd "FAILED. YOU MUST USE THE", 172 1.43 hubertf "-b OPTION TO fsck_ffs TO SPECIFY THE", 173 1.1 cgd "LOCATION OF AN ALTERNATE", 174 1.1 cgd "SUPER-BLOCK TO SUPPLY NEEDED", 175 1.23 cgd "INFORMATION; SEE fsck_ffs(8)."); 176 1.1 cgd return(0); 177 1.1 cgd } 178 1.21 mycroft doskipclean = 0; 179 1.1 cgd pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); 180 1.1 cgd } 181 1.91 bouyer 182 1.91 bouyer if (!quota2_check_doquota()) 183 1.91 bouyer doskipclean = 0; 184 1.108 riastrad 185 1.88 bouyer /* ffs_superblock_layout() == 2 */ 186 1.88 bouyer if (sblock->fs_magic != FS_UFS1_MAGIC || 187 1.88 bouyer (sblock->fs_old_flags & FS_FLAGS_UPDATED) != 0) { 188 1.88 bouyer /* can have WAPBL */ 189 1.88 bouyer if (check_wapbl() != 0) { 190 1.88 bouyer doskipclean = 0; 191 1.88 bouyer } 192 1.88 bouyer if (sblock->fs_flags & FS_DOWAPBL) { 193 1.91 bouyer if (preen && doskipclean) { 194 1.88 bouyer if (!quiet) 195 1.88 bouyer pwarn("file system is journaled; " 196 1.88 bouyer "not checking\n"); 197 1.88 bouyer return (-1); 198 1.88 bouyer } 199 1.83 simonb if (!quiet) 200 1.88 bouyer pwarn("** File system is journaled; " 201 1.88 bouyer "replaying journal\n"); 202 1.88 bouyer replay_wapbl(); 203 1.88 bouyer doskipclean = 0; 204 1.88 bouyer sblock->fs_flags &= ~FS_DOWAPBL; 205 1.88 bouyer sbdirty(); 206 1.88 bouyer /* Although we may have updated the superblock from 207 1.88 bouyer * the journal, we are still going to do a full check, 208 1.88 bouyer * so we don't bother to re-read the superblock from 209 1.88 bouyer * the journal. 210 1.88 bouyer * XXX, instead we could re-read the superblock and 211 1.108 riastrad * then not force doskipclean = 0 212 1.88 bouyer */ 213 1.83 simonb } 214 1.83 simonb } 215 1.21 mycroft if (debug) 216 1.33 bouyer printf("clean = %d\n", sblock->fs_clean); 217 1.91 bouyer 218 1.33 bouyer if (doswap) 219 1.33 bouyer doskipclean = 0; 220 1.91 bouyer 221 1.33 bouyer if (sblock->fs_clean & FS_ISCLEAN) { 222 1.22 cgd if (doskipclean) { 223 1.63 dsl if (!quiet) 224 1.63 dsl pwarn("%sile system is clean; not checking\n", 225 1.63 dsl preen ? "f" : "** F"); 226 1.21 mycroft return (-1); 227 1.21 mycroft } 228 1.33 bouyer if (!preen && !doswap) 229 1.21 mycroft pwarn("** File system is already clean\n"); 230 1.21 mycroft } 231 1.33 bouyer maxfsblock = sblock->fs_size; 232 1.33 bouyer maxino = sblock->fs_ncg * sblock->fs_ipg; 233 1.33 bouyer sizepb = sblock->fs_bsize; 234 1.96 dholland maxfilesize = sblock->fs_bsize * UFS_NDADDR - 1; 235 1.96 dholland for (i = 0; i < UFS_NIADDR; i++) { 236 1.98 dholland sizepb *= FFS_NINDIR(sblock); 237 1.24 mycroft maxfilesize += sizepb; 238 1.24 mycroft } 239 1.65 dbj if ((!is_ufs2 && cvtlevel >= 4) && 240 1.65 dbj (sblock->fs_old_flags & FS_FLAGS_UPDATED) == 0) { 241 1.65 dbj if (preen) 242 1.68 dbj pwarn("CONVERTING TO NEW SUPERBLOCK LAYOUT\n"); 243 1.68 dbj else if (!reply("CONVERT TO NEW SUPERBLOCK LAYOUT")) 244 1.65 dbj return(0); 245 1.65 dbj sblock->fs_old_flags |= FS_FLAGS_UPDATED; 246 1.65 dbj /* Disable the postbl tables */ 247 1.65 dbj sblock->fs_old_cpc = 0; 248 1.72 dbj sblock->fs_old_nrpos = 1; 249 1.65 dbj sblock->fs_old_trackskew = 0; 250 1.65 dbj /* The other fields have already been updated by 251 1.65 dbj * sb_oldfscompat_read 252 1.65 dbj */ 253 1.65 dbj sbdirty(); 254 1.65 dbj } 255 1.73 dbj if (!is_ufs2 && cvtlevel == 3 && 256 1.73 dbj (sblock->fs_old_flags & FS_FLAGS_UPDATED)) { 257 1.73 dbj if (preen) 258 1.73 dbj pwarn("DOWNGRADING TO OLD SUPERBLOCK LAYOUT\n"); 259 1.73 dbj else if (!reply("DOWNGRADE TO OLD SUPERBLOCK LAYOUT")) 260 1.73 dbj return(0); 261 1.73 dbj sblock->fs_old_flags &= ~FS_FLAGS_UPDATED; 262 1.73 dbj sb_oldfscompat_write(sblock, sblock); 263 1.73 dbj sblock->fs_old_flags &= ~FS_FLAGS_UPDATED; /* just in case */ 264 1.73 dbj /* Leave postbl tables disabled, but blank its superblock region anyway */ 265 1.73 dbj sblock->fs_old_postblformat = FS_DYNAMICPOSTBLFMT; 266 1.73 dbj sblock->fs_old_cpc = 0; 267 1.73 dbj sblock->fs_old_nrpos = 1; 268 1.73 dbj sblock->fs_old_trackskew = 0; 269 1.73 dbj memset(&sblock->fs_old_postbl_start, 0xff, 256); 270 1.73 dbj sb_oldfscompat_read(sblock, &sblocksave); 271 1.73 dbj sbdirty(); 272 1.73 dbj } 273 1.1 cgd /* 274 1.1 cgd * Check and potentially fix certain fields in the super block. 275 1.1 cgd */ 276 1.83 simonb if (sblock->fs_flags & ~(FS_KNOWN_FLAGS)) { 277 1.83 simonb pfatal("UNKNOWN FLAGS=0x%08x IN SUPERBLOCK", sblock->fs_flags); 278 1.83 simonb if (reply("CLEAR") == 1) { 279 1.83 simonb sblock->fs_flags &= FS_KNOWN_FLAGS; 280 1.83 simonb sbdirty(); 281 1.83 simonb } 282 1.83 simonb } 283 1.33 bouyer if (sblock->fs_optim != FS_OPTTIME && sblock->fs_optim != FS_OPTSPACE) { 284 1.1 cgd pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); 285 1.1 cgd if (reply("SET TO DEFAULT") == 1) { 286 1.33 bouyer sblock->fs_optim = FS_OPTTIME; 287 1.1 cgd sbdirty(); 288 1.1 cgd } 289 1.1 cgd } 290 1.33 bouyer if ((sblock->fs_minfree < 0 || sblock->fs_minfree > 99)) { 291 1.1 cgd pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 292 1.33 bouyer sblock->fs_minfree); 293 1.1 cgd if (reply("SET TO DEFAULT") == 1) { 294 1.33 bouyer sblock->fs_minfree = 10; 295 1.1 cgd sbdirty(); 296 1.1 cgd } 297 1.1 cgd } 298 1.58 fvdl if (!is_ufs2 && sblock->fs_old_postblformat != FS_42POSTBLFMT && 299 1.108 riastrad (sblock->fs_old_interleave < 1 || 300 1.58 fvdl sblock->fs_old_interleave > sblock->fs_old_nsect)) { 301 1.1 cgd pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK", 302 1.58 fvdl sblock->fs_old_interleave); 303 1.58 fvdl sblock->fs_old_interleave = 1; 304 1.1 cgd if (preen) 305 1.1 cgd printf(" (FIXED)\n"); 306 1.1 cgd if (preen || reply("SET TO DEFAULT") == 1) { 307 1.1 cgd sbdirty(); 308 1.1 cgd dirty(&asblk); 309 1.1 cgd } 310 1.1 cgd } 311 1.58 fvdl if (!is_ufs2 && sblock->fs_old_postblformat != FS_42POSTBLFMT && 312 1.108 riastrad (sblock->fs_old_npsect < sblock->fs_old_nsect || 313 1.58 fvdl sblock->fs_old_npsect > sblock->fs_old_nsect*2)) { 314 1.1 cgd pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK", 315 1.58 fvdl sblock->fs_old_npsect); 316 1.58 fvdl sblock->fs_old_npsect = sblock->fs_old_nsect; 317 1.1 cgd if (preen) 318 1.1 cgd printf(" (FIXED)\n"); 319 1.1 cgd if (preen || reply("SET TO DEFAULT") == 1) { 320 1.1 cgd sbdirty(); 321 1.1 cgd dirty(&asblk); 322 1.1 cgd } 323 1.1 cgd } 324 1.33 bouyer if (sblock->fs_bmask != ~(sblock->fs_bsize - 1)) { 325 1.28 lukem pwarn("INCORRECT BMASK=0x%x IN SUPERBLOCK", 326 1.33 bouyer sblock->fs_bmask); 327 1.33 bouyer sblock->fs_bmask = ~(sblock->fs_bsize - 1); 328 1.24 mycroft if (preen) 329 1.24 mycroft printf(" (FIXED)\n"); 330 1.24 mycroft if (preen || reply("FIX") == 1) { 331 1.24 mycroft sbdirty(); 332 1.24 mycroft dirty(&asblk); 333 1.24 mycroft } 334 1.24 mycroft } 335 1.33 bouyer if (sblock->fs_fmask != ~(sblock->fs_fsize - 1)) { 336 1.28 lukem pwarn("INCORRECT FMASK=0x%x IN SUPERBLOCK", 337 1.33 bouyer sblock->fs_fmask); 338 1.33 bouyer sblock->fs_fmask = ~(sblock->fs_fsize - 1); 339 1.24 mycroft if (preen) 340 1.24 mycroft printf(" (FIXED)\n"); 341 1.24 mycroft if (preen || reply("FIX") == 1) { 342 1.24 mycroft sbdirty(); 343 1.24 mycroft dirty(&asblk); 344 1.24 mycroft } 345 1.24 mycroft } 346 1.102 hannken if (check_snapinum()) { 347 1.102 hannken if (preen) 348 1.102 hannken printf(" (FIXED)\n"); 349 1.102 hannken if (preen || reply("FIX") == 1) { 350 1.102 hannken sbdirty(); 351 1.102 hannken dirty(&asblk); 352 1.102 hannken } 353 1.102 hannken } 354 1.77 dbj if (is_ufs2 || sblock->fs_old_inodefmt >= FS_44INODEFMT) { 355 1.33 bouyer if (sblock->fs_maxfilesize != maxfilesize) { 356 1.38 lukem pwarn("INCORRECT MAXFILESIZE=%lld IN SUPERBLOCK", 357 1.33 bouyer (unsigned long long)sblock->fs_maxfilesize); 358 1.33 bouyer sblock->fs_maxfilesize = maxfilesize; 359 1.24 mycroft if (preen) 360 1.24 mycroft printf(" (FIXED)\n"); 361 1.24 mycroft if (preen || reply("FIX") == 1) { 362 1.24 mycroft sbdirty(); 363 1.24 mycroft dirty(&asblk); 364 1.24 mycroft } 365 1.24 mycroft } 366 1.96 dholland if ((is_ufs2 && sblock->fs_maxsymlinklen != UFS2_MAXSYMLINKLEN) 367 1.58 fvdl || 368 1.96 dholland (!is_ufs2 && sblock->fs_maxsymlinklen != UFS1_MAXSYMLINKLEN)) 369 1.58 fvdl { 370 1.24 mycroft pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK", 371 1.33 bouyer sblock->fs_maxsymlinklen); 372 1.58 fvdl sblock->fs_maxsymlinklen = is_ufs2 ? 373 1.96 dholland UFS2_MAXSYMLINKLEN : UFS1_MAXSYMLINKLEN; 374 1.24 mycroft if (preen) 375 1.24 mycroft printf(" (FIXED)\n"); 376 1.24 mycroft if (preen || reply("FIX") == 1) { 377 1.24 mycroft sbdirty(); 378 1.24 mycroft dirty(&asblk); 379 1.24 mycroft } 380 1.24 mycroft } 381 1.33 bouyer if (sblock->fs_qbmask != ~sblock->fs_bmask) { 382 1.66 dbj pwarn("INCORRECT QBMASK=%#llx IN SUPERBLOCK", 383 1.33 bouyer (unsigned long long)sblock->fs_qbmask); 384 1.33 bouyer sblock->fs_qbmask = ~sblock->fs_bmask; 385 1.24 mycroft if (preen) 386 1.24 mycroft printf(" (FIXED)\n"); 387 1.24 mycroft if (preen || reply("FIX") == 1) { 388 1.24 mycroft sbdirty(); 389 1.24 mycroft dirty(&asblk); 390 1.24 mycroft } 391 1.24 mycroft } 392 1.33 bouyer if (sblock->fs_qfmask != ~sblock->fs_fmask) { 393 1.66 dbj pwarn("INCORRECT QFMASK=%#llx IN SUPERBLOCK", 394 1.33 bouyer (unsigned long long)sblock->fs_qfmask); 395 1.33 bouyer sblock->fs_qfmask = ~sblock->fs_fmask; 396 1.24 mycroft if (preen) 397 1.24 mycroft printf(" (FIXED)\n"); 398 1.24 mycroft if (preen || reply("FIX") == 1) { 399 1.24 mycroft sbdirty(); 400 1.24 mycroft dirty(&asblk); 401 1.24 mycroft } 402 1.24 mycroft } 403 1.10 mycroft newinofmt = 1; 404 1.10 mycroft } else { 405 1.33 bouyer sblock->fs_qbmask = ~sblock->fs_bmask; 406 1.33 bouyer sblock->fs_qfmask = ~sblock->fs_fmask; 407 1.10 mycroft newinofmt = 0; 408 1.10 mycroft } 409 1.10 mycroft /* 410 1.10 mycroft * Convert to new inode format. 411 1.10 mycroft */ 412 1.58 fvdl if (!is_ufs2 && cvtlevel >= 2 && 413 1.58 fvdl sblock->fs_old_inodefmt < FS_44INODEFMT) { 414 1.10 mycroft if (preen) 415 1.10 mycroft pwarn("CONVERTING TO NEW INODE FORMAT\n"); 416 1.10 mycroft else if (!reply("CONVERT TO NEW INODE FORMAT")) 417 1.10 mycroft return(0); 418 1.10 mycroft doinglevel2++; 419 1.58 fvdl sblock->fs_old_inodefmt = FS_44INODEFMT; 420 1.33 bouyer sblock->fs_maxfilesize = maxfilesize; 421 1.96 dholland sblock->fs_maxsymlinklen = UFS1_MAXSYMLINKLEN; 422 1.33 bouyer sblock->fs_qbmask = ~sblock->fs_bmask; 423 1.33 bouyer sblock->fs_qfmask = ~sblock->fs_fmask; 424 1.10 mycroft sbdirty(); 425 1.10 mycroft dirty(&asblk); 426 1.10 mycroft } 427 1.10 mycroft /* 428 1.10 mycroft * Convert to new cylinder group format. 429 1.10 mycroft */ 430 1.58 fvdl if (!is_ufs2 && cvtlevel >= 1 && 431 1.58 fvdl sblock->fs_old_postblformat == FS_42POSTBLFMT) { 432 1.10 mycroft if (preen) 433 1.10 mycroft pwarn("CONVERTING TO NEW CYLINDER GROUP FORMAT\n"); 434 1.10 mycroft else if (!reply("CONVERT TO NEW CYLINDER GROUP FORMAT")) 435 1.10 mycroft return(0); 436 1.10 mycroft doinglevel1++; 437 1.58 fvdl sblock->fs_old_postblformat = FS_DYNAMICPOSTBLFMT; 438 1.65 dbj sblock->fs_old_nrpos = 8; 439 1.65 dbj sblock->fs_old_postbloff = 440 1.65 dbj (char *)(&sblock->fs_old_postbl_start) - 441 1.65 dbj (char *)(&sblock->fs_firstfield); 442 1.65 dbj sblock->fs_old_rotbloff = 443 1.65 dbj (char *)(&sblock->fs_magic+1) - 444 1.65 dbj (char *)(&sblock->fs_firstfield); 445 1.65 dbj sblock->fs_cgsize = 446 1.100 dholland ffs_fragroundup(sblock, CGSIZE(sblock)); 447 1.10 mycroft sbdirty(); 448 1.10 mycroft dirty(&asblk); 449 1.1 cgd } 450 1.11 ws if (asblk.b_dirty && !bflag) { 451 1.65 dbj memmove(sblk.b_un.b_fs, sblock, SBLOCKSIZE); 452 1.65 dbj sb_oldfscompat_write(sblk.b_un.b_fs, sblocksave); 453 1.33 bouyer if (needswap) 454 1.65 dbj ffs_sb_swap(sblk.b_un.b_fs, sblk.b_un.b_fs); 455 1.33 bouyer memmove(asblk.b_un.b_fs, sblk.b_un.b_fs, (size_t)sblock->fs_sbsize); 456 1.1 cgd flush(fswritefd, &asblk); 457 1.1 cgd } 458 1.1 cgd /* 459 1.1 cgd * read in the summary info. 460 1.1 cgd */ 461 1.1 cgd asked = 0; 462 1.103 jdolecek sblock->fs_csp = (struct csum *)aligned_alloc(DEV_BSIZE, 463 1.109 riastrad sblock->fs_cssize); 464 1.79 rumble if (sblock->fs_csp == NULL) { 465 1.79 rumble pwarn("cannot alloc %u bytes for summary info\n", 466 1.108 riastrad sblock->fs_cssize); 467 1.79 rumble goto badsblabel; 468 1.79 rumble } 469 1.103 jdolecek memset(sblock->fs_csp, 0, sblock->fs_cssize); 470 1.33 bouyer for (i = 0, j = 0; i < sblock->fs_cssize; i += sblock->fs_bsize, j++) { 471 1.33 bouyer size = sblock->fs_cssize - i < sblock->fs_bsize ? 472 1.33 bouyer sblock->fs_cssize - i : sblock->fs_bsize; 473 1.46 lukem ccsp = (struct csum *)((char *)sblock->fs_csp + i); 474 1.46 lukem if (bread(fsreadfd, (char *)ccsp, 475 1.99 dholland FFS_FSBTODB(sblock, sblock->fs_csaddr + j * sblock->fs_frag), 476 1.1 cgd size) != 0 && !asked) { 477 1.1 cgd pfatal("BAD SUMMARY INFORMATION"); 478 1.37 fvdl if (reply("CONTINUE") == 0) { 479 1.37 fvdl markclean = 0; 480 1.82 christos exit(FSCK_EXIT_CHECK_FAILED); 481 1.37 fvdl } 482 1.1 cgd asked++; 483 1.1 cgd } 484 1.33 bouyer if (doswap) { 485 1.46 lukem ffs_csum_swap(ccsp, ccsp, size); 486 1.46 lukem bwrite(fswritefd, (char *)ccsp, 487 1.99 dholland FFS_FSBTODB(sblock, 488 1.37 fvdl sblock->fs_csaddr + j * sblock->fs_frag), 489 1.37 fvdl size); 490 1.33 bouyer } 491 1.46 lukem if (needswap) 492 1.46 lukem ffs_csum_swap(ccsp, ccsp, size); 493 1.1 cgd } 494 1.1 cgd /* 495 1.1 cgd * allocate and initialize the necessary maps 496 1.1 cgd */ 497 1.20 cgd bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); 498 1.110 mlelstv blockmap = aligned_alloc(DEV_BSIZE, bmapsize); 499 1.1 cgd if (blockmap == NULL) { 500 1.111 christos pwarn("cannot alloc %zu bytes for blockmap\n", bmapsize); 501 1.15 cgd goto badsblabel; 502 1.1 cgd } 503 1.103 jdolecek memset(blockmap, 0, bmapsize); 504 1.58 fvdl inostathead = calloc((unsigned)(sblock->fs_ncg), 505 1.58 fvdl sizeof(struct inostatlist)); 506 1.58 fvdl if (inostathead == NULL) { 507 1.63 dsl pwarn("cannot alloc %u bytes for inostathead\n", 508 1.58 fvdl (unsigned)(sizeof(struct inostatlist) * (sblock->fs_ncg))); 509 1.15 cgd goto badsblabel; 510 1.1 cgd } 511 1.39 mycroft /* 512 1.39 mycroft * cs_ndir may be inaccurate, particularly if we're using the -b 513 1.39 mycroft * option, so set a minimum to prevent bogus subdirectory reconnects 514 1.39 mycroft * and really inefficient directory scans. 515 1.39 mycroft * Also set a maximum in case the value is too large. 516 1.39 mycroft */ 517 1.33 bouyer numdirs = sblock->fs_cstotal.cs_ndir; 518 1.39 mycroft if (numdirs < 1024) 519 1.39 mycroft numdirs = 1024; 520 1.94 christos if ((ino_t)numdirs > maxino + 1) 521 1.39 mycroft numdirs = maxino + 1; 522 1.58 fvdl dirhash = numdirs; 523 1.1 cgd inplast = 0; 524 1.1 cgd listmax = numdirs + 10; 525 1.94 christos inpsort = calloc((unsigned)listmax, sizeof(*inpsort)); 526 1.94 christos inphead = calloc((unsigned)numdirs, sizeof(*inphead)); 527 1.1 cgd if (inpsort == NULL || inphead == NULL) { 528 1.108 riastrad pwarn("cannot alloc %u bytes for inphead\n", 529 1.29 mrg (unsigned)(numdirs * sizeof(struct inoinfo *))); 530 1.15 cgd goto badsblabel; 531 1.1 cgd } 532 1.109 riastrad cgrp = aligned_alloc(DEV_BSIZE, sblock->fs_cgsize); 533 1.37 fvdl if (cgrp == NULL) { 534 1.63 dsl pwarn("cannot alloc %u bytes for cylinder group\n", 535 1.37 fvdl sblock->fs_cgsize); 536 1.37 fvdl goto badsblabel; 537 1.37 fvdl } 538 1.1 cgd bufinit(); 539 1.37 fvdl if (sblock->fs_flags & FS_DOSOFTDEP) 540 1.37 fvdl usedsoftdep = 1; 541 1.37 fvdl else 542 1.37 fvdl usedsoftdep = 0; 543 1.54 dbj 544 1.101 rin #ifndef NO_APPLE_UFS 545 1.108 riastrad if (!forceimage && dkw.dkw_parent[0]) 546 1.80 christos if (strcmp(dkw.dkw_ptype, DKW_PTYPE_APPLEUFS) == 0) 547 1.54 dbj isappleufs = 1; 548 1.80 christos 549 1.80 christos if (readappleufs()) 550 1.54 dbj isappleufs = 1; 551 1.101 rin #endif 552 1.54 dbj 553 1.54 dbj if (isappleufs) 554 1.54 dbj dirblksiz = APPLEUFS_DIRBLKSIZ; 555 1.101 rin else 556 1.101 rin dirblksiz = UFS_DIRBLKSIZ; 557 1.54 dbj 558 1.54 dbj if (debug) 559 1.101 rin #ifndef NO_APPLE_UFS 560 1.54 dbj printf("isappleufs = %d, dirblksiz = %d\n", isappleufs, dirblksiz); 561 1.101 rin #else 562 1.101 rin printf("dirblksiz = %d\n", dirblksiz); 563 1.101 rin #endif 564 1.54 dbj 565 1.91 bouyer if (sblock->fs_flags & FS_DOQUOTA2) { 566 1.91 bouyer /* allocate the quota hash table */ 567 1.91 bouyer /* 568 1.91 bouyer * first compute the size of the hash table 569 1.91 bouyer * We know the smallest block size is 4k, so we can use 2k 570 1.91 bouyer * for the hash table; as an entry is 8 bytes we can store 571 1.91 bouyer * 256 entries. So let start q2h_hash_shift at 8 572 1.91 bouyer */ 573 1.91 bouyer for (q2h_hash_shift = 8; 574 1.91 bouyer q2h_hash_shift < 15; 575 1.91 bouyer q2h_hash_shift++) { 576 1.91 bouyer if ((sizeof(uint64_t) << (q2h_hash_shift + 1)) + 577 1.94 christos sizeof(struct quota2_header) > 578 1.94 christos (size_t)sblock->fs_bsize) 579 1.91 bouyer break; 580 1.91 bouyer } 581 1.91 bouyer q2h_hash_mask = (1 << q2h_hash_shift) - 1; 582 1.91 bouyer if (debug) { 583 1.91 bouyer printf("quota hash shift %d, %d entries, mask 0x%x\n", 584 1.91 bouyer q2h_hash_shift, (1 << q2h_hash_shift), 585 1.91 bouyer q2h_hash_mask); 586 1.91 bouyer } 587 1.91 bouyer uquot_user_hash = 588 1.92 bouyer calloc((1 << q2h_hash_shift), sizeof(struct uquot_hash)); 589 1.91 bouyer uquot_group_hash = 590 1.92 bouyer calloc((1 << q2h_hash_shift), sizeof(struct uquot_hash)); 591 1.91 bouyer if (uquot_user_hash == NULL || uquot_group_hash == NULL) 592 1.91 bouyer errexit("Cannot allocate space for quotas hash\n"); 593 1.91 bouyer } else { 594 1.91 bouyer uquot_user_hash = uquot_group_hash = NULL; 595 1.91 bouyer q2h_hash_shift = q2h_hash_mask = 0; 596 1.91 bouyer } 597 1.1 cgd return (1); 598 1.15 cgd badsblabel: 599 1.33 bouyer markclean=0; 600 1.93 christos ckfini(1); 601 1.1 cgd return (0); 602 1.1 cgd } 603 1.1 cgd 604 1.101 rin #ifndef NO_APPLE_UFS 605 1.54 dbj static int 606 1.75 xtraeme readappleufs(void) 607 1.54 dbj { 608 1.56 fvdl daddr_t label = APPLEUFS_LABEL_OFFSET / dev_bsize; 609 1.54 dbj struct appleufslabel *appleufs; 610 1.54 dbj int i; 611 1.54 dbj 612 1.54 dbj /* XXX do we have to deal with APPLEUFS_LABEL_OFFSET not 613 1.54 dbj * being block aligned (CD's?) 614 1.54 dbj */ 615 1.90 mlelstv if (APPLEUFS_LABEL_SIZE % dev_bsize != 0) 616 1.90 mlelstv return 0; 617 1.67 mrg if (bread(fsreadfd, (char *)appleufsblk.b_un.b_fs, label, 618 1.67 mrg (long)APPLEUFS_LABEL_SIZE) != 0) 619 1.54 dbj return 0; 620 1.54 dbj appleufsblk.b_bno = label; 621 1.54 dbj appleufsblk.b_size = APPLEUFS_LABEL_SIZE; 622 1.54 dbj 623 1.54 dbj appleufs = appleufsblk.b_un.b_appleufs; 624 1.54 dbj 625 1.54 dbj if (ntohl(appleufs->ul_magic) != APPLEUFS_LABEL_MAGIC) { 626 1.54 dbj if (!isappleufs) { 627 1.54 dbj return 0; 628 1.54 dbj } else { 629 1.54 dbj pfatal("MISSING APPLEUFS VOLUME LABEL\n"); 630 1.54 dbj if (reply("FIX") == 0) { 631 1.54 dbj return 1; 632 1.54 dbj } 633 1.64 dbj ffs_appleufs_set(appleufs, NULL, -1, 0); 634 1.54 dbj appleufsdirty(); 635 1.54 dbj } 636 1.54 dbj } 637 1.54 dbj 638 1.54 dbj if (ntohl(appleufs->ul_version) != APPLEUFS_LABEL_VERSION) { 639 1.54 dbj pwarn("INCORRECT APPLE UFS VERSION NUMBER (%d should be %d)", 640 1.54 dbj ntohl(appleufs->ul_version),APPLEUFS_LABEL_VERSION); 641 1.54 dbj if (preen) { 642 1.54 dbj printf(" (CORRECTED)\n"); 643 1.54 dbj } 644 1.54 dbj if (preen || reply("CORRECT")) { 645 1.54 dbj appleufs->ul_version = htonl(APPLEUFS_LABEL_VERSION); 646 1.54 dbj appleufsdirty(); 647 1.54 dbj } 648 1.54 dbj } 649 1.54 dbj 650 1.54 dbj if (ntohs(appleufs->ul_namelen) > APPLEUFS_MAX_LABEL_NAME) { 651 1.54 dbj pwarn("APPLE UFS LABEL NAME TOO LONG"); 652 1.54 dbj if (preen) { 653 1.54 dbj printf(" (TRUNCATED)\n"); 654 1.54 dbj } 655 1.54 dbj if (preen || reply("TRUNCATE")) { 656 1.54 dbj appleufs->ul_namelen = htons(APPLEUFS_MAX_LABEL_NAME); 657 1.54 dbj appleufsdirty(); 658 1.54 dbj } 659 1.54 dbj } 660 1.54 dbj 661 1.54 dbj if (ntohs(appleufs->ul_namelen) == 0) { 662 1.54 dbj pwarn("MISSING APPLE UFS LABEL NAME"); 663 1.54 dbj if (preen) { 664 1.54 dbj printf(" (FIXED)\n"); 665 1.54 dbj } 666 1.54 dbj if (preen || reply("FIX")) { 667 1.64 dbj ffs_appleufs_set(appleufs, NULL, -1, 0); 668 1.54 dbj appleufsdirty(); 669 1.54 dbj } 670 1.54 dbj } 671 1.54 dbj 672 1.54 dbj /* Scan name for first illegal character */ 673 1.54 dbj for (i=0;i<ntohs(appleufs->ul_namelen);i++) { 674 1.54 dbj if ((appleufs->ul_name[i] == '\0') || 675 1.54 dbj (appleufs->ul_name[i] == ':') || 676 1.54 dbj (appleufs->ul_name[i] == '/')) { 677 1.54 dbj pwarn("APPLE UFS LABEL NAME CONTAINS ILLEGAL CHARACTER"); 678 1.54 dbj if (preen) { 679 1.54 dbj printf(" (TRUNCATED)\n"); 680 1.54 dbj } 681 1.54 dbj if (preen || reply("TRUNCATE")) { 682 1.54 dbj appleufs->ul_namelen = i+1; 683 1.54 dbj appleufsdirty(); 684 1.54 dbj } 685 1.54 dbj break; 686 1.54 dbj } 687 1.54 dbj } 688 1.54 dbj 689 1.54 dbj /* Check the checksum last, because if anything else was wrong, 690 1.54 dbj * then the checksum gets reset anyway. 691 1.54 dbj */ 692 1.54 dbj appleufs->ul_checksum = 0; 693 1.54 dbj appleufs->ul_checksum = ffs_appleufs_cksum(appleufs); 694 1.54 dbj if (appleufsblk.b_un.b_appleufs->ul_checksum != appleufs->ul_checksum) { 695 1.54 dbj pwarn("INVALID APPLE UFS CHECKSUM (%#04x should be %#04x)", 696 1.54 dbj appleufsblk.b_un.b_appleufs->ul_checksum, appleufs->ul_checksum); 697 1.54 dbj if (preen) { 698 1.54 dbj printf(" (CORRECTED)\n"); 699 1.54 dbj } 700 1.54 dbj if (preen || reply("CORRECT")) { 701 1.54 dbj appleufsdirty(); 702 1.54 dbj } else { 703 1.54 dbj /* put the incorrect checksum back in place */ 704 1.54 dbj appleufs->ul_checksum = appleufsblk.b_un.b_appleufs->ul_checksum; 705 1.54 dbj } 706 1.54 dbj } 707 1.54 dbj return 1; 708 1.54 dbj } 709 1.101 rin #endif /* !NO_APPLE_UFS */ 710 1.54 dbj 711 1.1 cgd /* 712 1.58 fvdl * Detect byte order. Return 0 if valid magic found, -1 otherwise. 713 1.1 cgd */ 714 1.26 christos static int 715 1.70 dsl detect_byteorder(struct fs *fs, int sblockoff) 716 1.1 cgd { 717 1.70 dsl if (sblockoff == SBLOCK_UFS2 && (fs->fs_magic == FS_UFS1_MAGIC || 718 1.95 nonaka fs->fs_magic == FS_UFS1_MAGIC_SWAPPED)) 719 1.70 dsl /* Likely to be the first alternate of a fs with 64k blocks */ 720 1.70 dsl return -1; 721 1.104 chs if (fs->fs_magic == FS_UFS1_MAGIC || fs->fs_magic == FS_UFS2_MAGIC || 722 1.104 chs fs->fs_magic == FS_UFS2EA_MAGIC) { 723 1.101 rin #ifndef NO_FFS_EI 724 1.58 fvdl if (endian == 0 || BYTE_ORDER == endian) { 725 1.58 fvdl needswap = 0; 726 1.58 fvdl doswap = do_blkswap = do_dirswap = 0; 727 1.58 fvdl } else { 728 1.58 fvdl needswap = 1; 729 1.58 fvdl doswap = do_blkswap = do_dirswap = 1; 730 1.58 fvdl } 731 1.101 rin #endif 732 1.58 fvdl return 0; 733 1.101 rin } 734 1.101 rin #ifndef NO_FFS_EI 735 1.101 rin else if (fs->fs_magic == FS_UFS1_MAGIC_SWAPPED || 736 1.104 chs fs->fs_magic == FS_UFS2_MAGIC_SWAPPED || 737 1.104 chs fs->fs_magic == FS_UFS2EA_MAGIC_SWAPPED) { 738 1.33 bouyer if (endian == 0 || BYTE_ORDER != endian) { 739 1.33 bouyer needswap = 1; 740 1.33 bouyer doswap = do_blkswap = do_dirswap = 0; 741 1.33 bouyer } else { 742 1.33 bouyer needswap = 0; 743 1.33 bouyer doswap = do_blkswap = do_dirswap = 1; 744 1.33 bouyer } 745 1.58 fvdl return 0; 746 1.58 fvdl } 747 1.101 rin #endif 748 1.58 fvdl return -1; 749 1.58 fvdl } 750 1.58 fvdl 751 1.104 chs /* Update on-disk fs->fs_magic if we are converting */ 752 1.104 chs void 753 1.104 chs cvt_magic(struct fs *fs) 754 1.104 chs { 755 1.104 chs 756 1.104 chs if (is_ufs2ea || doing2ea) { 757 1.104 chs if (fs->fs_magic == FS_UFS2_MAGIC) { 758 1.104 chs fs->fs_magic = FS_UFS2EA_MAGIC; 759 1.104 chs } 760 1.104 chs if (fs->fs_magic == FS_UFS2_MAGIC_SWAPPED) { 761 1.104 chs fs->fs_magic = FS_UFS2EA_MAGIC_SWAPPED; 762 1.104 chs } 763 1.104 chs } 764 1.104 chs if (doing2noea) { 765 1.104 chs if (fs->fs_magic == FS_UFS2EA_MAGIC) { 766 1.104 chs fs->fs_magic = FS_UFS2_MAGIC; 767 1.104 chs } 768 1.104 chs if (fs->fs_magic == FS_UFS2EA_MAGIC_SWAPPED) { 769 1.104 chs fs->fs_magic = FS_UFS2_MAGIC_SWAPPED; 770 1.104 chs } 771 1.104 chs } 772 1.104 chs } 773 1.104 chs 774 1.58 fvdl /* 775 1.58 fvdl * Possible superblock locations ordered from most to least likely. 776 1.58 fvdl */ 777 1.58 fvdl static off_t sblock_try[] = SBLOCKSEARCH; 778 1.58 fvdl 779 1.58 fvdl /* 780 1.58 fvdl * Read in the super block and its summary info. 781 1.58 fvdl */ 782 1.58 fvdl static int 783 1.75 xtraeme readsb(int listerr) 784 1.58 fvdl { 785 1.76 lukem daddr_t super = 0; 786 1.58 fvdl struct fs *fs; 787 1.58 fvdl int i; 788 1.58 fvdl 789 1.58 fvdl if (bflag) { 790 1.58 fvdl super = bflag; 791 1.58 fvdl if (bread(fsreadfd, (char *)sblk.b_un.b_fs, super, 792 1.58 fvdl (long)SBLOCKSIZE) != 0) 793 1.58 fvdl return (0); 794 1.58 fvdl fs = sblk.b_un.b_fs; 795 1.70 dsl if (detect_byteorder(fs, -1) < 0) { 796 1.58 fvdl badsb(listerr, "MAGIC NUMBER WRONG"); 797 1.58 fvdl return (0); 798 1.58 fvdl } 799 1.33 bouyer } else { 800 1.58 fvdl for (i = 0; sblock_try[i] != -1; i++) { 801 1.58 fvdl super = sblock_try[i] / dev_bsize; 802 1.58 fvdl if (bread(fsreadfd, (char *)sblk.b_un.b_fs, 803 1.58 fvdl super, (long)SBLOCKSIZE) != 0) 804 1.58 fvdl continue; 805 1.58 fvdl fs = sblk.b_un.b_fs; 806 1.70 dsl if (detect_byteorder(fs, sblock_try[i]) == 0) 807 1.58 fvdl break; 808 1.58 fvdl } 809 1.58 fvdl if (sblock_try[i] == -1) { 810 1.58 fvdl badsb(listerr, "CAN'T FIND SUPERBLOCK"); 811 1.58 fvdl return (0); 812 1.58 fvdl } 813 1.33 bouyer } 814 1.33 bouyer if (doswap) { 815 1.33 bouyer if (preen) 816 1.82 christos errx(FSCK_EXIT_USAGE, 817 1.82 christos "Incompatible options -B and -p"); 818 1.33 bouyer if (nflag) 819 1.82 christos errx(FSCK_EXIT_USAGE, 820 1.82 christos "Incompatible options -B and -n"); 821 1.33 bouyer if (endian == LITTLE_ENDIAN) { 822 1.36 is if (!reply("CONVERT TO LITTLE ENDIAN")) 823 1.33 bouyer return 0; 824 1.33 bouyer } else if (endian == BIG_ENDIAN) { 825 1.36 is if (!reply("CONVERT TO BIG ENDIAN")) 826 1.33 bouyer return 0; 827 1.33 bouyer } else 828 1.33 bouyer pfatal("INTERNAL ERROR: unknown endian"); 829 1.33 bouyer } 830 1.33 bouyer if (needswap) 831 1.63 dsl pwarn("** Swapped byte order\n"); 832 1.33 bouyer /* swap SB byte order if asked */ 833 1.33 bouyer if (doswap) 834 1.45 lukem ffs_sb_swap(sblk.b_un.b_fs, sblk.b_un.b_fs); 835 1.33 bouyer 836 1.58 fvdl memmove(sblock, sblk.b_un.b_fs, SBLOCKSIZE); 837 1.33 bouyer if (needswap) 838 1.45 lukem ffs_sb_swap(sblk.b_un.b_fs, sblock); 839 1.104 chs if (sblock->fs_magic == FS_UFS2EA_MAGIC) { 840 1.104 chs is_ufs2ea = 1; 841 1.104 chs sblock->fs_magic = FS_UFS2_MAGIC; 842 1.104 chs } 843 1.104 chs is_ufs2 = sblock->fs_magic == FS_UFS2_MAGIC; 844 1.33 bouyer 845 1.104 chs /* change on-disk magic if asked */ 846 1.104 chs cvt_magic(fs); 847 1.58 fvdl 848 1.1 cgd /* 849 1.1 cgd * run a few consistency checks of the super block 850 1.1 cgd */ 851 1.58 fvdl if (sblock->fs_sbsize > SBLOCKSIZE) 852 1.1 cgd { badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); } 853 1.1 cgd /* 854 1.1 cgd * Compute block size that the filesystem is based on, 855 1.99 dholland * according to FFS_FSBTODB, and adjust superblock block number 856 1.1 cgd * so we can tell if this is an alternate later. 857 1.1 cgd */ 858 1.1 cgd super *= dev_bsize; 859 1.99 dholland dev_bsize = sblock->fs_fsize / FFS_FSBTODB(sblock, 1); 860 1.1 cgd sblk.b_bno = super / dev_bsize; 861 1.58 fvdl sblk.b_size = SBLOCKSIZE; 862 1.58 fvdl if (bflag) 863 1.58 fvdl goto out; 864 1.1 cgd /* 865 1.58 fvdl * Set all possible fields that could differ, then do check 866 1.58 fvdl * of whole super block against an alternate super block-> 867 1.1 cgd * When an alternate super-block is specified this check is skipped. 868 1.1 cgd */ 869 1.33 bouyer getblk(&asblk, cgsblock(sblock, sblock->fs_ncg - 1), sblock->fs_sbsize); 870 1.1 cgd if (asblk.b_errs) 871 1.1 cgd return (0); 872 1.33 bouyer /* swap SB byte order if asked */ 873 1.33 bouyer if (doswap) 874 1.45 lukem ffs_sb_swap(asblk.b_un.b_fs, asblk.b_un.b_fs); 875 1.33 bouyer 876 1.33 bouyer memmove(altsblock, asblk.b_un.b_fs, sblock->fs_sbsize); 877 1.33 bouyer if (needswap) 878 1.45 lukem ffs_sb_swap(asblk.b_un.b_fs, altsblock); 879 1.104 chs if (altsblock->fs_magic == FS_UFS2EA_MAGIC) { 880 1.104 chs altsblock->fs_magic = FS_UFS2_MAGIC; 881 1.104 chs } 882 1.104 chs /* change on-disk magic if asked */ 883 1.104 chs cvt_magic(asblk.b_un.b_fs); 884 1.41 thorpej if (cmpsblks(sblock, altsblock)) { 885 1.65 dbj if (debug) { 886 1.65 dbj uint32_t *nlp, *olp, *endlp; 887 1.65 dbj 888 1.65 dbj printf("superblock mismatches\n"); 889 1.65 dbj nlp = (uint32_t *)altsblock; 890 1.65 dbj olp = (uint32_t *)sblock; 891 1.65 dbj endlp = olp + (sblock->fs_sbsize / sizeof *olp); 892 1.65 dbj for ( ; olp < endlp; olp++, nlp++) { 893 1.65 dbj if (*olp == *nlp) 894 1.65 dbj continue; 895 1.71 dbj printf("offset %#x, original 0x%08x, alternate " 896 1.67 mrg "0x%08x\n", 897 1.67 mrg (int)((uint8_t *)olp-(uint8_t *)sblock), 898 1.67 mrg *olp, *nlp); 899 1.65 dbj } 900 1.65 dbj } 901 1.1 cgd badsb(listerr, 902 1.1 cgd "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE"); 903 1.80 christos /* 904 1.1 cgd return (0); 905 1.80 christos */ 906 1.1 cgd } 907 1.58 fvdl out: 908 1.65 dbj 909 1.65 dbj sb_oldfscompat_read(sblock, &sblocksave); 910 1.58 fvdl 911 1.33 bouyer /* Now we know the SB is valid, we can write it back if needed */ 912 1.104 chs if (doswap || doing2ea || doing2noea) { 913 1.33 bouyer sbdirty(); 914 1.33 bouyer dirty(&asblk); 915 1.33 bouyer } 916 1.1 cgd havesb = 1; 917 1.1 cgd return (1); 918 1.41 thorpej } 919 1.41 thorpej 920 1.41 thorpej int 921 1.41 thorpej cmpsblks(const struct fs *sb, struct fs *asb) 922 1.41 thorpej { 923 1.65 dbj if (!is_ufs2 && ((sb->fs_old_flags & FS_FLAGS_UPDATED) == 0)) { 924 1.65 dbj if (sb->fs_old_postblformat < FS_DYNAMICPOSTBLFMT) 925 1.65 dbj return cmpsblks42(sb, asb); 926 1.65 dbj else 927 1.65 dbj return cmpsblks44(sb, asb); 928 1.65 dbj } 929 1.65 dbj if (asb->fs_sblkno != sb->fs_sblkno || 930 1.57 fvdl asb->fs_cblkno != sb->fs_cblkno || 931 1.57 fvdl asb->fs_iblkno != sb->fs_iblkno || 932 1.57 fvdl asb->fs_dblkno != sb->fs_dblkno || 933 1.57 fvdl asb->fs_ncg != sb->fs_ncg || 934 1.57 fvdl asb->fs_bsize != sb->fs_bsize || 935 1.57 fvdl asb->fs_fsize != sb->fs_fsize || 936 1.57 fvdl asb->fs_frag != sb->fs_frag || 937 1.57 fvdl asb->fs_bmask != sb->fs_bmask || 938 1.57 fvdl asb->fs_fmask != sb->fs_fmask || 939 1.57 fvdl asb->fs_bshift != sb->fs_bshift || 940 1.57 fvdl asb->fs_fshift != sb->fs_fshift || 941 1.57 fvdl asb->fs_fragshift != sb->fs_fragshift || 942 1.57 fvdl asb->fs_fsbtodb != sb->fs_fsbtodb || 943 1.57 fvdl asb->fs_sbsize != sb->fs_sbsize || 944 1.57 fvdl asb->fs_nindir != sb->fs_nindir || 945 1.57 fvdl asb->fs_inopb != sb->fs_inopb || 946 1.57 fvdl asb->fs_cssize != sb->fs_cssize || 947 1.57 fvdl asb->fs_ipg != sb->fs_ipg || 948 1.57 fvdl asb->fs_fpg != sb->fs_fpg || 949 1.57 fvdl asb->fs_magic != sb->fs_magic) 950 1.58 fvdl return 1; 951 1.58 fvdl return 0; 952 1.1 cgd } 953 1.1 cgd 954 1.65 dbj /* BSD 4.2 performed the following superblock comparison 955 1.65 dbj * It should correspond to FS_42POSTBLFMT 956 1.65 dbj * (although note that in 4.2, the fs_old_postblformat 957 1.65 dbj * field didn't exist and the corresponding bits are 958 1.65 dbj * located near the end of the postbl itself, where they 959 1.65 dbj * are not likely to be used.) 960 1.65 dbj */ 961 1.65 dbj int 962 1.65 dbj cmpsblks42(const struct fs *sb, struct fs *asb) 963 1.65 dbj { 964 1.65 dbj asb->fs_firstfield = sb->fs_firstfield; /* fs_link */ 965 1.65 dbj asb->fs_unused_1 = sb->fs_unused_1; /* fs_rlink */ 966 1.65 dbj asb->fs_old_time = sb->fs_old_time; /* fs_time */ 967 1.65 dbj asb->fs_old_cstotal = sb->fs_old_cstotal; /* fs_cstotal */ 968 1.65 dbj asb->fs_cgrotor = sb->fs_cgrotor; 969 1.65 dbj asb->fs_fmod = sb->fs_fmod; 970 1.65 dbj asb->fs_clean = sb->fs_clean; 971 1.65 dbj asb->fs_ronly = sb->fs_ronly; 972 1.65 dbj asb->fs_old_flags = sb->fs_old_flags; 973 1.65 dbj asb->fs_maxcontig = sb->fs_maxcontig; 974 1.65 dbj asb->fs_minfree = sb->fs_minfree; 975 1.65 dbj asb->fs_old_rotdelay = sb->fs_old_rotdelay; 976 1.65 dbj asb->fs_maxbpg = sb->fs_maxbpg; 977 1.65 dbj 978 1.65 dbj /* The former fs_csp, totaling 128 bytes */ 979 1.65 dbj memmove(asb->fs_ocsp, sb->fs_ocsp, sizeof sb->fs_ocsp); 980 1.65 dbj asb->fs_contigdirs = sb->fs_contigdirs; 981 1.65 dbj asb->fs_csp = sb->fs_csp; 982 1.65 dbj asb->fs_maxcluster = sb->fs_maxcluster; 983 1.65 dbj asb->fs_active = sb->fs_active; 984 1.65 dbj 985 1.65 dbj /* The former fs_fsmnt, totaling 512 bytes */ 986 1.65 dbj memmove(asb->fs_fsmnt, sb->fs_fsmnt, sizeof sb->fs_fsmnt); 987 1.65 dbj memmove(asb->fs_volname, sb->fs_volname, sizeof sb->fs_volname); 988 1.65 dbj 989 1.65 dbj return memcmp(sb, asb, sb->fs_sbsize); 990 1.65 dbj } 991 1.65 dbj 992 1.65 dbj /* BSD 4.4 performed the following superblock comparison 993 1.65 dbj * This was used in NetBSD through 1.6.1 994 1.65 dbj * 995 1.65 dbj * Note that this implementation is destructive to asb. 996 1.65 dbj */ 997 1.65 dbj int 998 1.65 dbj cmpsblks44(const struct fs *sb, struct fs *asb) 999 1.65 dbj { 1000 1.65 dbj /* 1001 1.65 dbj * "Copy fields which we don't care if they're different in the 1002 1.65 dbj * alternate superblocks, as they're either likely to be 1003 1.65 dbj * different because they're per-cylinder-group specific, or 1004 1.65 dbj * because they're transient details which are only maintained 1005 1.65 dbj * in the primary superblock." 1006 1.65 dbj */ 1007 1.65 dbj asb->fs_firstfield = sb->fs_firstfield; 1008 1.65 dbj asb->fs_unused_1 = sb->fs_unused_1; 1009 1.65 dbj asb->fs_old_time = sb->fs_old_time; 1010 1.65 dbj asb->fs_old_cstotal = sb->fs_old_cstotal; 1011 1.65 dbj asb->fs_cgrotor = sb->fs_cgrotor; 1012 1.65 dbj asb->fs_fmod = sb->fs_fmod; 1013 1.65 dbj asb->fs_clean = sb->fs_clean; 1014 1.65 dbj asb->fs_ronly = sb->fs_ronly; 1015 1.65 dbj asb->fs_old_flags = sb->fs_old_flags; 1016 1.65 dbj asb->fs_maxcontig = sb->fs_maxcontig; 1017 1.65 dbj asb->fs_minfree = sb->fs_minfree; 1018 1.65 dbj asb->fs_optim = sb->fs_optim; 1019 1.65 dbj asb->fs_old_rotdelay = sb->fs_old_rotdelay; 1020 1.65 dbj asb->fs_maxbpg = sb->fs_maxbpg; 1021 1.65 dbj 1022 1.65 dbj /* The former fs_csp and fs_maxcluster, totaling 128 bytes */ 1023 1.65 dbj memmove(asb->fs_ocsp, sb->fs_ocsp, sizeof sb->fs_ocsp); 1024 1.65 dbj asb->fs_contigdirs = sb->fs_contigdirs; 1025 1.65 dbj asb->fs_csp = sb->fs_csp; 1026 1.65 dbj asb->fs_maxcluster = sb->fs_maxcluster; 1027 1.65 dbj asb->fs_active = sb->fs_active; 1028 1.65 dbj 1029 1.65 dbj /* The former fs_fsmnt, totaling 512 bytes */ 1030 1.65 dbj memmove(asb->fs_fsmnt, sb->fs_fsmnt, sizeof sb->fs_fsmnt); 1031 1.65 dbj memmove(asb->fs_volname, sb->fs_volname, sizeof sb->fs_volname); 1032 1.65 dbj 1033 1.65 dbj /* The former fs_sparecon, totaling 200 bytes */ 1034 1.65 dbj memmove(asb->fs_snapinum, 1035 1.65 dbj sb->fs_snapinum, sizeof sb->fs_snapinum); 1036 1.65 dbj asb->fs_avgfilesize = sb->fs_avgfilesize; 1037 1.65 dbj asb->fs_avgfpdir = sb->fs_avgfpdir; 1038 1.65 dbj asb->fs_save_cgsize = sb->fs_save_cgsize; 1039 1.65 dbj memmove(asb->fs_sparecon32, 1040 1.65 dbj sb->fs_sparecon32, sizeof sb->fs_sparecon32); 1041 1.65 dbj asb->fs_flags = sb->fs_flags; 1042 1.65 dbj 1043 1.65 dbj /* Original comment: 1044 1.65 dbj * "The following should not have to be copied, but need to be." 1045 1.65 dbj */ 1046 1.65 dbj asb->fs_fsbtodb = sb->fs_fsbtodb; 1047 1.65 dbj asb->fs_old_interleave = sb->fs_old_interleave; 1048 1.65 dbj asb->fs_old_npsect = sb->fs_old_npsect; 1049 1.65 dbj asb->fs_old_nrpos = sb->fs_old_nrpos; 1050 1.65 dbj asb->fs_state = sb->fs_state; 1051 1.65 dbj asb->fs_qbmask = sb->fs_qbmask; 1052 1.65 dbj asb->fs_qfmask = sb->fs_qfmask; 1053 1.65 dbj asb->fs_state = sb->fs_state; 1054 1.65 dbj asb->fs_maxfilesize = sb->fs_maxfilesize; 1055 1.65 dbj 1056 1.65 dbj /* 1057 1.65 dbj * "Compare the superblocks, effectively checking every other 1058 1.65 dbj * field to see if they differ." 1059 1.65 dbj */ 1060 1.65 dbj return memcmp(sb, asb, sb->fs_sbsize); 1061 1.65 dbj } 1062 1.65 dbj 1063 1.30 lukem static void 1064 1.78 christos badsb(int listerr, const char *s) 1065 1.1 cgd { 1066 1.1 cgd 1067 1.1 cgd if (!listerr) 1068 1.1 cgd return; 1069 1.1 cgd if (preen) 1070 1.26 christos printf("%s: ", cdevname()); 1071 1.1 cgd pfatal("BAD SUPER BLOCK: %s\n", s); 1072 1.1 cgd } 1073 1.1 cgd 1074 1.1 cgd /* 1075 1.1 cgd * Calculate a prototype superblock based on information in the disk label. 1076 1.1 cgd * When done the cgsblock macro can be calculated and the fs_ncg field 1077 1.1 cgd * can be used. Do NOT attempt to use other macros without verifying that 1078 1.1 cgd * their needed information is available! 1079 1.1 cgd */ 1080 1.30 lukem static int 1081 1.75 xtraeme calcsb(const char *dev, int devfd, struct fs *fs) 1082 1.1 cgd { 1083 1.80 christos struct dkwedge_info dkw; 1084 1.80 christos struct disk_geom geo; 1085 1.58 fvdl int i, nspf; 1086 1.1 cgd 1087 1.80 christos if (getdiskinfo(dev, fsreadfd, NULL, &geo, &dkw) == -1) 1088 1.80 christos pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev); 1089 1.80 christos if (dkw.dkw_parent[0] == '\0') { 1090 1.1 cgd pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev); 1091 1.1 cgd return (0); 1092 1.1 cgd } 1093 1.101 rin if (strcmp(dkw.dkw_ptype, DKW_PTYPE_FFS) 1094 1.101 rin #ifndef NO_APPLE_UFS 1095 1.101 rin && strcmp(dkw.dkw_ptype, DKW_PTYPE_APPLEUFS) 1096 1.101 rin #endif 1097 1.101 rin ) { 1098 1.1 cgd pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n", 1099 1.80 christos dev, dkw.dkw_ptype); 1100 1.33 bouyer return (0); 1101 1.69 dbj } 1102 1.81 christos if (geo.dg_secsize == 0) { 1103 1.81 christos pfatal("%s: CANNOT FIGURE OUT SECTOR SIZE\n", dev); 1104 1.81 christos return 0; 1105 1.81 christos } 1106 1.81 christos if (geo.dg_secpercyl == 0) { 1107 1.81 christos pfatal("%s: CANNOT FIGURE OUT SECTORS PER CYLINDER\n", dev); 1108 1.81 christos return 0; 1109 1.81 christos } 1110 1.81 christos if (sblk.b_un.b_fs->fs_fsize == 0) { 1111 1.81 christos pfatal("%s: CANNOT FIGURE OUT FRAG BLOCK SIZE\n", dev); 1112 1.81 christos return 0; 1113 1.81 christos } 1114 1.81 christos if (sblk.b_un.b_fs->fs_fpg == 0) { 1115 1.81 christos pfatal("%s: CANNOT FIGURE OUT FRAGS PER GROUP\n", dev); 1116 1.81 christos return 0; 1117 1.81 christos } 1118 1.81 christos if (sblk.b_un.b_fs->fs_old_cpg == 0) { 1119 1.81 christos pfatal("%s: CANNOT FIGURE OUT OLD CYLINDERS PER GROUP\n", dev); 1120 1.81 christos return 0; 1121 1.81 christos } 1122 1.85 christos memcpy(fs, sblk.b_un.b_fs, sizeof(struct fs)); 1123 1.80 christos nspf = fs->fs_fsize / geo.dg_secsize; 1124 1.58 fvdl fs->fs_old_nspf = nspf; 1125 1.58 fvdl for (fs->fs_fsbtodb = 0, i = nspf; i > 1; i >>= 1) 1126 1.1 cgd fs->fs_fsbtodb++; 1127 1.80 christos dev_bsize = geo.dg_secsize; 1128 1.58 fvdl if (fs->fs_magic == FS_UFS2_MAGIC) { 1129 1.58 fvdl fs->fs_ncg = howmany(fs->fs_size, fs->fs_fpg); 1130 1.58 fvdl } else /* if (fs->fs_magic == FS_UFS1_MAGIC) */ { 1131 1.58 fvdl fs->fs_old_cgmask = 0xffffffff; 1132 1.80 christos for (i = geo.dg_ntracks; i > 1; i >>= 1) 1133 1.58 fvdl fs->fs_old_cgmask <<= 1; 1134 1.80 christos if (!POWEROF2(geo.dg_ntracks)) 1135 1.58 fvdl fs->fs_old_cgmask <<= 1; 1136 1.58 fvdl fs->fs_old_cgoffset = roundup( 1137 1.80 christos howmany(geo.dg_nsectors, nspf), fs->fs_frag); 1138 1.80 christos fs->fs_fpg = (fs->fs_old_cpg * geo.dg_secpercyl) / nspf; 1139 1.80 christos fs->fs_ncg = howmany(fs->fs_size / geo.dg_secpercyl, 1140 1.58 fvdl fs->fs_old_cpg); 1141 1.58 fvdl } 1142 1.1 cgd return (1); 1143 1.1 cgd } 1144 1.102 hannken 1145 1.102 hannken /* 1146 1.102 hannken * Test the list of snapshot inode numbers for duplicates and repair. 1147 1.102 hannken */ 1148 1.102 hannken static int 1149 1.102 hannken check_snapinum(void) 1150 1.102 hannken { 1151 1.102 hannken int loc, loc2, res; 1152 1.105 chs uint32_t *snapinum = &sblock->fs_snapinum[0]; 1153 1.102 hannken 1154 1.102 hannken res = 0; 1155 1.108 riastrad 1156 1.102 hannken if (isappleufs) 1157 1.102 hannken return 0; 1158 1.102 hannken 1159 1.102 hannken for (loc = 0; loc < FSMAXSNAP; loc++) { 1160 1.102 hannken if (snapinum[loc] == 0) 1161 1.102 hannken break; 1162 1.102 hannken for (loc2 = loc + 1; loc2 < FSMAXSNAP; loc2++) { 1163 1.102 hannken if (snapinum[loc2] == 0 || 1164 1.102 hannken snapinum[loc2] == snapinum[loc]) 1165 1.102 hannken break; 1166 1.102 hannken } 1167 1.102 hannken if (loc2 >= FSMAXSNAP || snapinum[loc2] == 0) 1168 1.102 hannken continue; 1169 1.102 hannken pwarn("SNAPSHOT INODE %u ALREADY ON LIST%s", snapinum[loc2], 1170 1.102 hannken (res ? "" : "\n")); 1171 1.102 hannken res = 1; 1172 1.102 hannken for (loc2 = loc + 1; loc2 < FSMAXSNAP; loc2++) { 1173 1.102 hannken if (snapinum[loc2] == 0) 1174 1.102 hannken break; 1175 1.102 hannken snapinum[loc2 - 1] = snapinum[loc2]; 1176 1.102 hannken } 1177 1.102 hannken snapinum[loc2 - 1] = 0; 1178 1.102 hannken loc--; 1179 1.102 hannken } 1180 1.102 hannken 1181 1.102 hannken return res; 1182 1.102 hannken } 1183