1 /* $NetBSD: setup.c,v 1.52 2001/12/19 10:05:20 fvdl 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)setup.c 8.10 (Berkeley) 5/9/95"; 40 #else 41 __RCSID("$NetBSD: setup.c,v 1.52 2001/12/19 10:05:20 fvdl Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 #include <sys/time.h> 47 #include <sys/stat.h> 48 #include <sys/ioctl.h> 49 #define FSTYPENAMES 50 #include <sys/disklabel.h> 51 #include <sys/file.h> 52 53 #include <ufs/ufs/dinode.h> 54 #include <ufs/ufs/ufs_bswap.h> 55 #include <ufs/ffs/fs.h> 56 #include <ufs/ffs/ffs_extern.h> 57 58 #include <ctype.h> 59 #include <err.h> 60 #include <errno.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <string.h> 64 65 #include "fsck.h" 66 #include "extern.h" 67 #include "fsutil.h" 68 69 #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 70 71 static void badsb __P((int, char *)); 72 static int calcsb __P((const char *, int, struct fs *)); 73 static struct disklabel *getdisklabel __P((const char *, int)); 74 static int readsb __P((int)); 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(dev) 83 const char *dev; 84 { 85 long cg, size, asked, i, j; 86 long bmapsize; 87 struct disklabel *lp; 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 (preen == 0) 112 printf("** %s", dev); 113 if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) { 114 fswritefd = -1; 115 if (preen) 116 pfatal("NO WRITE ACCESS"); 117 printf(" (NO WRITE)"); 118 } 119 if (preen == 0) 120 printf("\n"); 121 fsmodified = 0; 122 lfdir = 0; 123 initbarea(&sblk); 124 initbarea(&asblk); 125 sblk.b_un.b_buf = malloc(SBSIZE); 126 sblock = malloc(SBSIZE); 127 asblk.b_un.b_buf = malloc(SBSIZE); 128 altsblock = malloc(SBSIZE); 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 pwarn("%sile system is clean; not checking\n", 170 preen ? "f" : "** F"); 171 return (-1); 172 } 173 if (!preen && !doswap) 174 pwarn("** File system is already clean\n"); 175 } 176 maxfsblock = sblock->fs_size; 177 maxino = sblock->fs_ncg * sblock->fs_ipg; 178 sizepb = sblock->fs_bsize; 179 maxfilesize = sblock->fs_bsize * NDADDR - 1; 180 for (i = 0; i < NIADDR; i++) { 181 sizepb *= NINDIR(sblock); 182 maxfilesize += sizepb; 183 } 184 /* 185 * Check and potentially fix certain fields in the super block. 186 */ 187 if (sblock->fs_optim != FS_OPTTIME && sblock->fs_optim != FS_OPTSPACE) { 188 pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); 189 if (reply("SET TO DEFAULT") == 1) { 190 sblock->fs_optim = FS_OPTTIME; 191 sbdirty(); 192 } 193 } 194 if ((sblock->fs_minfree < 0 || sblock->fs_minfree > 99)) { 195 pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 196 sblock->fs_minfree); 197 if (reply("SET TO DEFAULT") == 1) { 198 sblock->fs_minfree = 10; 199 sbdirty(); 200 } 201 } 202 if (sblock->fs_interleave < 1 || 203 sblock->fs_interleave > sblock->fs_nsect) { 204 pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK", 205 sblock->fs_interleave); 206 sblock->fs_interleave = 1; 207 if (preen) 208 printf(" (FIXED)\n"); 209 if (preen || reply("SET TO DEFAULT") == 1) { 210 sbdirty(); 211 dirty(&asblk); 212 } 213 } 214 if (sblock->fs_npsect < sblock->fs_nsect || 215 sblock->fs_npsect > sblock->fs_nsect*2) { 216 pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK", 217 sblock->fs_npsect); 218 sblock->fs_npsect = sblock->fs_nsect; 219 if (preen) 220 printf(" (FIXED)\n"); 221 if (preen || reply("SET TO DEFAULT") == 1) { 222 sbdirty(); 223 dirty(&asblk); 224 } 225 } 226 if (sblock->fs_bmask != ~(sblock->fs_bsize - 1)) { 227 pwarn("INCORRECT BMASK=0x%x IN SUPERBLOCK", 228 sblock->fs_bmask); 229 sblock->fs_bmask = ~(sblock->fs_bsize - 1); 230 if (preen) 231 printf(" (FIXED)\n"); 232 if (preen || reply("FIX") == 1) { 233 sbdirty(); 234 dirty(&asblk); 235 } 236 } 237 if (sblock->fs_fmask != ~(sblock->fs_fsize - 1)) { 238 pwarn("INCORRECT FMASK=0x%x IN SUPERBLOCK", 239 sblock->fs_fmask); 240 sblock->fs_fmask = ~(sblock->fs_fsize - 1); 241 if (preen) 242 printf(" (FIXED)\n"); 243 if (preen || reply("FIX") == 1) { 244 sbdirty(); 245 dirty(&asblk); 246 } 247 } 248 if (sblock->fs_inodefmt >= FS_44INODEFMT) { 249 if (sblock->fs_maxfilesize != maxfilesize) { 250 pwarn("INCORRECT MAXFILESIZE=%lld IN SUPERBLOCK", 251 (unsigned long long)sblock->fs_maxfilesize); 252 sblock->fs_maxfilesize = maxfilesize; 253 if (preen) 254 printf(" (FIXED)\n"); 255 if (preen || reply("FIX") == 1) { 256 sbdirty(); 257 dirty(&asblk); 258 } 259 } 260 if (sblock->fs_maxsymlinklen != MAXSYMLINKLEN) { 261 pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK", 262 sblock->fs_maxsymlinklen); 263 sblock->fs_maxsymlinklen = MAXSYMLINKLEN; 264 if (preen) 265 printf(" (FIXED)\n"); 266 if (preen || reply("FIX") == 1) { 267 sbdirty(); 268 dirty(&asblk); 269 } 270 } 271 if (sblock->fs_qbmask != ~sblock->fs_bmask) { 272 pwarn("INCORRECT QBMASK=%llx IN SUPERBLOCK", 273 (unsigned long long)sblock->fs_qbmask); 274 sblock->fs_qbmask = ~sblock->fs_bmask; 275 if (preen) 276 printf(" (FIXED)\n"); 277 if (preen || reply("FIX") == 1) { 278 sbdirty(); 279 dirty(&asblk); 280 } 281 } 282 if (sblock->fs_qfmask != ~sblock->fs_fmask) { 283 pwarn("INCORRECT QFMASK=%llx IN SUPERBLOCK", 284 (unsigned long long)sblock->fs_qfmask); 285 sblock->fs_qfmask = ~sblock->fs_fmask; 286 if (preen) 287 printf(" (FIXED)\n"); 288 if (preen || reply("FIX") == 1) { 289 sbdirty(); 290 dirty(&asblk); 291 } 292 } 293 newinofmt = 1; 294 } else { 295 sblock->fs_qbmask = ~sblock->fs_bmask; 296 sblock->fs_qfmask = ~sblock->fs_fmask; 297 newinofmt = 0; 298 } 299 /* 300 * Convert to new inode format. 301 */ 302 if (cvtlevel >= 2 && sblock->fs_inodefmt < FS_44INODEFMT) { 303 if (preen) 304 pwarn("CONVERTING TO NEW INODE FORMAT\n"); 305 else if (!reply("CONVERT TO NEW INODE FORMAT")) 306 return(0); 307 doinglevel2++; 308 sblock->fs_inodefmt = FS_44INODEFMT; 309 sblock->fs_maxfilesize = maxfilesize; 310 sblock->fs_maxsymlinklen = MAXSYMLINKLEN; 311 sblock->fs_qbmask = ~sblock->fs_bmask; 312 sblock->fs_qfmask = ~sblock->fs_fmask; 313 sbdirty(); 314 dirty(&asblk); 315 } 316 /* 317 * Convert to new cylinder group format. 318 */ 319 if (cvtlevel >= 1 && sblock->fs_postblformat == FS_42POSTBLFMT) { 320 if (preen) 321 pwarn("CONVERTING TO NEW CYLINDER GROUP FORMAT\n"); 322 else if (!reply("CONVERT TO NEW CYLINDER GROUP FORMAT")) 323 return(0); 324 doinglevel1++; 325 sblock->fs_postblformat = FS_DYNAMICPOSTBLFMT; 326 sblock->fs_nrpos = 8; 327 sblock->fs_postbloff = 328 (char *)(&sblock->fs_opostbl[0][0]) - 329 (char *)(&sblock->fs_firstfield); 330 sblock->fs_rotbloff = &sblock->fs_space[0] - 331 (u_char *)(&sblock->fs_firstfield); 332 sblock->fs_cgsize = 333 fragroundup(sblock, CGSIZE(sblock)); 334 sbdirty(); 335 dirty(&asblk); 336 } 337 if (asblk.b_dirty && !bflag) { 338 memmove((struct fs*)sblk.b_un.b_fs, sblock, SBSIZE); 339 if (needswap) 340 ffs_sb_swap(sblock, (struct fs*)sblk.b_un.b_fs); 341 memmove(asblk.b_un.b_fs, sblk.b_un.b_fs, (size_t)sblock->fs_sbsize); 342 flush(fswritefd, &asblk); 343 } 344 /* 345 * read in the summary info. 346 */ 347 asked = 0; 348 sblock->fs_csp = (struct csum *)calloc(1, sblock->fs_cssize); 349 for (i = 0, j = 0; i < sblock->fs_cssize; i += sblock->fs_bsize, j++) { 350 size = sblock->fs_cssize - i < sblock->fs_bsize ? 351 sblock->fs_cssize - i : sblock->fs_bsize; 352 ccsp = (struct csum *)((char *)sblock->fs_csp + i); 353 if (bread(fsreadfd, (char *)ccsp, 354 fsbtodb(sblock, sblock->fs_csaddr + j * sblock->fs_frag), 355 size) != 0 && !asked) { 356 pfatal("BAD SUMMARY INFORMATION"); 357 if (reply("CONTINUE") == 0) { 358 markclean = 0; 359 exit(EEXIT); 360 } 361 asked++; 362 } 363 if (doswap) { 364 ffs_csum_swap(ccsp, ccsp, size); 365 bwrite(fswritefd, (char *)ccsp, 366 fsbtodb(sblock, 367 sblock->fs_csaddr + j * sblock->fs_frag), 368 size); 369 } 370 if (needswap) 371 ffs_csum_swap(ccsp, ccsp, size); 372 } 373 /* 374 * allocate and initialize the necessary maps 375 */ 376 bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); 377 blockmap = calloc((unsigned)bmapsize, sizeof (char)); 378 if (blockmap == NULL) { 379 printf("cannot alloc %u bytes for blockmap\n", 380 (unsigned)bmapsize); 381 goto badsblabel; 382 } 383 statemap = calloc((unsigned)(maxino + 1), sizeof(char)); 384 if (statemap == NULL) { 385 printf("cannot alloc %u bytes for statemap\n", 386 (unsigned)(maxino + 1)); 387 goto badsblabel; 388 } 389 typemap = calloc((unsigned)(maxino + 1), sizeof(char)); 390 if (typemap == NULL) { 391 printf("cannot alloc %u bytes for typemap\n", 392 (unsigned)(maxino + 1)); 393 goto badsblabel; 394 } 395 lncntp = (int16_t *)calloc((unsigned)(maxino + 1), sizeof(int16_t)); 396 if (lncntp == NULL) { 397 printf("cannot alloc %u bytes for lncntp\n", 398 (unsigned)((maxino + 1) * sizeof(int16_t))); 399 goto badsblabel; 400 } 401 /* 402 * cs_ndir may be inaccurate, particularly if we're using the -b 403 * option, so set a minimum to prevent bogus subdirectory reconnects 404 * and really inefficient directory scans. 405 * Also set a maximum in case the value is too large. 406 */ 407 numdirs = sblock->fs_cstotal.cs_ndir; 408 if (numdirs < 1024) 409 numdirs = 1024; 410 if (numdirs > maxino + 1) 411 numdirs = maxino + 1; 412 inplast = 0; 413 listmax = numdirs + 10; 414 inpsort = (struct inoinfo **)calloc((unsigned)listmax, 415 sizeof(struct inoinfo *)); 416 inphead = (struct inoinfo **)calloc((unsigned)numdirs, 417 sizeof(struct inoinfo *)); 418 if (inpsort == NULL || inphead == NULL) { 419 printf("cannot alloc %u bytes for inphead\n", 420 (unsigned)(numdirs * sizeof(struct inoinfo *))); 421 goto badsblabel; 422 } 423 cgrp = malloc(sblock->fs_cgsize); 424 if (cgrp == NULL) { 425 printf("cannot alloc %u bytes for cylinder group\n", 426 sblock->fs_cgsize); 427 goto badsblabel; 428 } 429 bufinit(); 430 if (sblock->fs_flags & FS_DOSOFTDEP) 431 usedsoftdep = 1; 432 else 433 usedsoftdep = 0; 434 return (1); 435 436 badsblabel: 437 markclean=0; 438 ckfini(); 439 return (0); 440 } 441 442 /* 443 * Read in the super block and its summary info. 444 */ 445 static int 446 readsb(listerr) 447 int listerr; 448 { 449 ufs_daddr_t super = bflag ? bflag : SBOFF / dev_bsize; 450 struct fs *fs; 451 452 if (bread(fsreadfd, (char *)sblk.b_un.b_fs, super, (long)SBSIZE) != 0) 453 return (0); 454 sblk.b_bno = super; 455 sblk.b_size = SBSIZE; 456 457 fs = sblk.b_un.b_fs; 458 /* auto detect byte order */ 459 if( fs->fs_magic == FS_MAGIC) { 460 if (endian == 0 || BYTE_ORDER == endian) { 461 needswap = 0; 462 doswap = do_blkswap = do_dirswap = 0; 463 } else { 464 needswap = 1; 465 doswap = do_blkswap = do_dirswap = 1; 466 } 467 } else if (fs->fs_magic == bswap32(FS_MAGIC)) { 468 if (endian == 0 || BYTE_ORDER != endian) { 469 needswap = 1; 470 doswap = do_blkswap = do_dirswap = 0; 471 } else { 472 needswap = 0; 473 doswap = do_blkswap = do_dirswap = 1; 474 } 475 } else { 476 badsb(listerr, "MAGIC NUMBER WRONG"); 477 return (0); 478 } 479 if (doswap) { 480 if (preen) 481 errx(EEXIT, "incompatible options -B and -p"); 482 if (nflag) 483 errx(EEXIT, "incompatible options -B and -n"); 484 if (endian == LITTLE_ENDIAN) { 485 if (!reply("CONVERT TO LITTLE ENDIAN")) 486 return 0; 487 } else if (endian == BIG_ENDIAN) { 488 if (!reply("CONVERT TO BIG ENDIAN")) 489 return 0; 490 } else 491 pfatal("INTERNAL ERROR: unknown endian"); 492 } 493 if (needswap) 494 printf("** Swapped byte order\n"); 495 /* swap SB byte order if asked */ 496 if (doswap) 497 ffs_sb_swap(sblk.b_un.b_fs, sblk.b_un.b_fs); 498 499 memmove(sblock, sblk.b_un.b_fs, SBSIZE); 500 if (needswap) 501 ffs_sb_swap(sblk.b_un.b_fs, sblock); 502 503 /* 504 * run a few consistency checks of the super block 505 */ 506 if (sblock->fs_ncg < 1) 507 { badsb(listerr, "NCG OUT OF RANGE"); return (0); } 508 if (sblock->fs_cpg < 1) 509 { badsb(listerr, "CPG OUT OF RANGE"); return (0); } 510 if (sblock->fs_ncg * sblock->fs_cpg < sblock->fs_ncyl || 511 (sblock->fs_ncg - 1) * sblock->fs_cpg >= sblock->fs_ncyl) 512 { badsb(listerr, "NCYL LESS THAN NCG*CPG"); return (0); } 513 if (sblock->fs_sbsize > SBSIZE) 514 { badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); } 515 /* 516 * Compute block size that the filesystem is based on, 517 * according to fsbtodb, and adjust superblock block number 518 * so we can tell if this is an alternate later. 519 */ 520 super *= dev_bsize; 521 dev_bsize = sblock->fs_fsize / fsbtodb(sblock, 1); 522 sblk.b_bno = super / dev_bsize; 523 524 if (bflag) { 525 havesb = 1; 526 return (1); 527 } 528 /* 529 * Set all possible fields that could differ, then do check 530 * of whole super block against an alternate super block. 531 * When an alternate super-block is specified this check is skipped. 532 */ 533 getblk(&asblk, cgsblock(sblock, sblock->fs_ncg - 1), sblock->fs_sbsize); 534 if (asblk.b_errs) 535 return (0); 536 /* swap SB byte order if asked */ 537 if (doswap) 538 ffs_sb_swap(asblk.b_un.b_fs, asblk.b_un.b_fs); 539 540 memmove(altsblock, asblk.b_un.b_fs, sblock->fs_sbsize); 541 if (needswap) 542 ffs_sb_swap(asblk.b_un.b_fs, altsblock); 543 if (cmpsblks(sblock, altsblock)) { 544 if (debug) { 545 long *nlp, *olp, *endlp; 546 547 printf("superblock mismatches\n"); 548 nlp = (long *)altsblock; 549 olp = (long *)sblock; 550 endlp = olp + (sblock->fs_sbsize / sizeof *olp); 551 for ( ; olp < endlp; olp++, nlp++) { 552 if (*olp == *nlp) 553 continue; 554 printf("offset %ld, original %lx, alternate %lx\n", 555 (long)(olp - (long *)sblock), *olp, *nlp); 556 } 557 } 558 badsb(listerr, 559 "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE"); 560 return (0); 561 } 562 /* Now we know the SB is valid, we can write it back if needed */ 563 if (doswap) { 564 sbdirty(); 565 dirty(&asblk); 566 } 567 havesb = 1; 568 return (1); 569 } 570 571 int 572 cmpsblks(const struct fs *sb, struct fs *asb) 573 { 574 575 /* 576 * Copy fields which we don't care if they're different in the 577 * alternate superblocks, as they're either likely to be 578 * different because they're per-cylinder-group specific, or 579 * because they're transient details which are only maintained 580 * in the primary superblock. 581 */ 582 asb->fs_firstfield = sb->fs_firstfield; 583 asb->fs_unused_1 = sb->fs_unused_1; 584 asb->fs_time = sb->fs_time; 585 asb->fs_cstotal = sb->fs_cstotal; 586 asb->fs_cgrotor = sb->fs_cgrotor; 587 asb->fs_fmod = sb->fs_fmod; 588 asb->fs_clean = sb->fs_clean; 589 asb->fs_ronly = sb->fs_ronly; 590 asb->fs_flags = sb->fs_flags; 591 asb->fs_maxcontig = sb->fs_maxcontig; 592 asb->fs_minfree = sb->fs_minfree; 593 asb->fs_optim = sb->fs_optim; 594 asb->fs_rotdelay = sb->fs_rotdelay; 595 asb->fs_maxbpg = sb->fs_maxbpg; 596 memmove(asb->fs_ocsp, sb->fs_ocsp, sizeof sb->fs_ocsp); 597 asb->fs_contigdirs = sb->fs_contigdirs; 598 asb->fs_csp = sb->fs_csp; 599 asb->fs_maxcluster = sb->fs_maxcluster; 600 memmove(asb->fs_fsmnt, sb->fs_fsmnt, sizeof sb->fs_fsmnt); 601 memmove(asb->fs_snapinum, 602 sb->fs_snapinum, sizeof sb->fs_snapinum); 603 asb->fs_avgfilesize = sb->fs_avgfilesize; 604 asb->fs_avgfpdir = sb->fs_avgfpdir; 605 asb->fs_pendingblocks = sb->fs_pendingblocks; 606 asb->fs_pendinginodes = sb->fs_pendinginodes; 607 memmove(asb->fs_sparecon, 608 sb->fs_sparecon, sizeof sb->fs_sparecon); 609 /* 610 * The following should not have to be copied, but need to be. 611 */ 612 asb->fs_fsbtodb = sb->fs_fsbtodb; 613 asb->fs_interleave = sb->fs_interleave; 614 asb->fs_npsect = sb->fs_npsect; 615 asb->fs_nrpos = sb->fs_nrpos; 616 asb->fs_qbmask = sb->fs_qbmask; 617 asb->fs_qfmask = sb->fs_qfmask; 618 asb->fs_state = sb->fs_state; 619 asb->fs_maxfilesize = sb->fs_maxfilesize; 620 621 /* 622 * Compare the superblocks, effectively checking every other 623 * field to see if they differ. 624 */ 625 return (memcmp(sb, asb, (int)sb->fs_sbsize)); 626 } 627 628 static void 629 badsb(listerr, s) 630 int listerr; 631 char *s; 632 { 633 634 if (!listerr) 635 return; 636 if (preen) 637 printf("%s: ", cdevname()); 638 pfatal("BAD SUPER BLOCK: %s\n", s); 639 } 640 641 /* 642 * Calculate a prototype superblock based on information in the disk label. 643 * When done the cgsblock macro can be calculated and the fs_ncg field 644 * can be used. Do NOT attempt to use other macros without verifying that 645 * their needed information is available! 646 */ 647 static int 648 calcsb(dev, devfd, fs) 649 const char *dev; 650 int devfd; 651 struct fs *fs; 652 { 653 struct disklabel *lp; 654 struct partition *pp; 655 char *cp; 656 int i; 657 658 cp = strchr(dev, '\0') - 1; 659 if ((cp == (char *)-1 || (*cp < 'a' || *cp > 'p')) && !isdigit(*cp)) { 660 pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev); 661 return (0); 662 } 663 lp = getdisklabel(dev, devfd); 664 if (isdigit(*cp)) 665 pp = &lp->d_partitions[0]; 666 else 667 pp = &lp->d_partitions[*cp - 'a']; 668 if (pp->p_fstype != FS_BSDFFS) { 669 pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n", 670 dev, pp->p_fstype < FSMAXTYPES ? 671 fstypenames[pp->p_fstype] : "unknown"); 672 return (0); 673 } 674 /* avoid divide by 0 */ 675 if (pp->p_fsize == 0 || pp->p_frag == 0) 676 return (0); 677 memset(fs, 0, sizeof(struct fs)); 678 fs->fs_fsize = pp->p_fsize; 679 fs->fs_frag = pp->p_frag; 680 fs->fs_cpg = pp->p_cpg; 681 fs->fs_size = pp->p_size; 682 fs->fs_ntrak = lp->d_ntracks; 683 fs->fs_nsect = lp->d_nsectors; 684 fs->fs_spc = lp->d_secpercyl; 685 fs->fs_nspf = fs->fs_fsize / lp->d_secsize; 686 fs->fs_sblkno = roundup( 687 howmany(lp->d_bbsize + lp->d_sbsize, fs->fs_fsize), 688 fs->fs_frag); 689 fs->fs_cgmask = 0xffffffff; 690 for (i = fs->fs_ntrak; i > 1; i >>= 1) 691 fs->fs_cgmask <<= 1; 692 if (!POWEROF2(fs->fs_ntrak)) 693 fs->fs_cgmask <<= 1; 694 fs->fs_cgoffset = roundup( 695 howmany(fs->fs_nsect, NSPF(fs)), fs->fs_frag); 696 fs->fs_fpg = (fs->fs_cpg * fs->fs_spc) / NSPF(fs); 697 fs->fs_ncg = howmany(fs->fs_size / fs->fs_spc, fs->fs_cpg); 698 for (fs->fs_fsbtodb = 0, i = NSPF(fs); i > 1; i >>= 1) 699 fs->fs_fsbtodb++; 700 dev_bsize = lp->d_secsize; 701 return (1); 702 } 703 704 static struct disklabel * 705 getdisklabel(s, fd) 706 const char *s; 707 int fd; 708 { 709 static struct disklabel lab; 710 711 if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) { 712 if (s == NULL) 713 return ((struct disklabel *)NULL); 714 pwarn("ioctl (GCINFO): %s\n", strerror(errno)); 715 errx(EEXIT, "%s: can't read disk label", s); 716 } 717 return (&lab); 718 } 719