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