1 /* $OpenBSD: setup.c,v 1.51 2013/11/22 04:38:02 guenther Exp $ */ 2 /* $NetBSD: setup.c,v 1.27 1996/09/27 22:45:19 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1980, 1986, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #define DKTYPENAMES 34 #include <sys/param.h> 35 #include <sys/time.h> 36 #include <ufs/ufs/dinode.h> 37 #include <ufs/ffs/fs.h> 38 #include <sys/stat.h> 39 #include <sys/ioctl.h> 40 #include <sys/dkio.h> 41 #include <sys/disklabel.h> 42 43 #include <errno.h> 44 #include <fcntl.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <util.h> 49 #include <unistd.h> 50 #include <ctype.h> 51 52 #include "fsck.h" 53 #include "extern.h" 54 #include "fsutil.h" 55 56 #define altsblock (*asblk.b_un.b_fs) 57 #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 58 59 void badsb(int, char *); 60 int calcsb(char *, int, struct fs *); 61 static struct disklabel *getdisklabel(char *, int); 62 static int readsb(int); 63 static int cmpsb(struct fs *, struct fs *); 64 static char rdevname[MAXPATHLEN]; 65 66 long numdirs, listmax, inplast; 67 68 /* 69 * Possible locations for the superblock. 70 */ 71 static const int sbtry[] = SBLOCKSEARCH; 72 /* locations the 1st alternate sb can be at */ 73 static const int altsbtry[] = { 32, 64, 128, 144, 160, 192, 256 }; 74 75 int 76 setup(char *dev) 77 { 78 long cg, size, asked, i, j, bmapsize; 79 struct disklabel *lp; 80 off_t sizepb; 81 struct stat statb; 82 struct fs proto; 83 int doskipclean; 84 int32_t maxsymlinklen, nindir, inopb; 85 u_int64_t maxfilesize; 86 char *realdev; 87 88 havesb = 0; 89 fswritefd = fsreadfd = -1; 90 doskipclean = skipclean; 91 if ((fsreadfd = opendev(dev, O_RDONLY, 0, &realdev)) < 0) { 92 printf("Can't open %s: %s\n", dev, strerror(errno)); 93 return (0); 94 } 95 if (strncmp(dev, realdev, PATH_MAX) != 0) { 96 blockcheck(unrawname(realdev)); 97 strlcpy(rdevname, realdev, sizeof(rdevname)); 98 setcdevname(rdevname, dev, preen); 99 } 100 if (fstat(fsreadfd, &statb) < 0) { 101 printf("Can't stat %s: %s\n", realdev, strerror(errno)); 102 close(fsreadfd); 103 return (0); 104 } 105 if (!S_ISCHR(statb.st_mode)) { 106 pfatal("%s is not a character device", realdev); 107 if (reply("CONTINUE") == 0) { 108 close(fsreadfd); 109 return (0); 110 } 111 } 112 if (preen == 0) { 113 printf("** %s", realdev); 114 if (strncmp(dev, realdev, PATH_MAX) != 0) 115 printf(" (%s)", dev); 116 } 117 if (nflag || (fswritefd = opendev(dev, O_WRONLY, 0, NULL)) < 0) { 118 fswritefd = -1; 119 if (preen) 120 pfatal("NO WRITE ACCESS"); 121 printf(" (NO WRITE)"); 122 } 123 if (preen == 0) 124 printf("\n"); 125 fsmodified = 0; 126 lfdir = 0; 127 initbarea(&sblk); 128 initbarea(&asblk); 129 sblk.b_un.b_buf = malloc(SBSIZE); 130 asblk.b_un.b_buf = malloc(SBSIZE); 131 if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) 132 errexit("cannot allocate space for superblock\n"); 133 if ((lp = getdisklabel(NULL, fsreadfd)) != NULL) 134 dev_bsize = secsize = lp->d_secsize; 135 else 136 dev_bsize = secsize = DEV_BSIZE; 137 /* 138 * Read in the superblock, looking for alternates if necessary 139 */ 140 if (readsb(1) == 0) { 141 if (bflag || preen || calcsb(realdev, fsreadfd, &proto) == 0) 142 return(0); 143 if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) 144 return (0); 145 for (i = 0; i < sizeof(altsbtry) / sizeof(altsbtry[0]); i++) { 146 bflag = altsbtry[i]; 147 /* proto partially setup by calcsb */ 148 if (readsb(0) != 0 && 149 proto.fs_fsize == sblock.fs_fsize && 150 proto.fs_bsize == sblock.fs_bsize) 151 goto found; 152 } 153 for (cg = 0; cg < proto.fs_ncg; cg++) { 154 bflag = fsbtodb(&proto, cgsblock(&proto, cg)); 155 if (readsb(0) != 0) 156 break; 157 } 158 if (cg >= proto.fs_ncg) { 159 printf("%s %s\n%s %s\n%s %s\n", 160 "SEARCH FOR ALTERNATE SUPER-BLOCK", 161 "FAILED. YOU MUST USE THE", 162 "-b OPTION TO FSCK_FFS TO SPECIFY THE", 163 "LOCATION OF AN ALTERNATE", 164 "SUPER-BLOCK TO SUPPLY NEEDED", 165 "INFORMATION; SEE fsck_ffs(8)."); 166 return(0); 167 } 168 found: 169 doskipclean = 0; 170 pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); 171 } 172 if (debug) 173 printf("clean = %d\n", sblock.fs_clean); 174 if (sblock.fs_clean & FS_ISCLEAN) { 175 if (doskipclean) { 176 pwarn("%sile system is clean; not checking\n", 177 preen ? "f" : "** F"); 178 return (-1); 179 } 180 if (!preen) 181 pwarn("** File system is already clean\n"); 182 } 183 maxfsblock = sblock.fs_size; 184 maxino = sblock.fs_ncg * sblock.fs_ipg; 185 sizepb = sblock.fs_bsize; 186 maxfilesize = sblock.fs_bsize * NDADDR - 1; 187 for (i = 0; i < NIADDR; i++) { 188 sizepb *= NINDIR(&sblock); 189 maxfilesize += sizepb; 190 } 191 /* 192 * Check and potentially fix certain fields in the super block. 193 */ 194 if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { 195 pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); 196 if (reply("SET TO DEFAULT") == 1) { 197 sblock.fs_optim = FS_OPTTIME; 198 sbdirty(); 199 } 200 } 201 if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { 202 pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 203 sblock.fs_minfree); 204 if (reply("SET TO DEFAULT") == 1) { 205 sblock.fs_minfree = 10; 206 sbdirty(); 207 } 208 } 209 if (sblock.fs_npsect < sblock.fs_nsect || 210 sblock.fs_npsect > sblock.fs_nsect*2) { 211 pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK", 212 sblock.fs_npsect); 213 sblock.fs_npsect = sblock.fs_nsect; 214 if (preen) 215 printf(" (FIXED)\n"); 216 if (preen || reply("SET TO DEFAULT") == 1) { 217 sbdirty(); 218 dirty(&asblk); 219 } 220 } 221 if (sblock.fs_bmask != ~(sblock.fs_bsize - 1)) { 222 pwarn("INCORRECT BMASK=%x IN SUPERBLOCK", 223 sblock.fs_bmask); 224 sblock.fs_bmask = ~(sblock.fs_bsize - 1); 225 if (preen) 226 printf(" (FIXED)\n"); 227 if (preen || reply("FIX") == 1) { 228 sbdirty(); 229 dirty(&asblk); 230 } 231 } 232 if (sblock.fs_fmask != ~(sblock.fs_fsize - 1)) { 233 pwarn("INCORRECT FMASK=%x IN SUPERBLOCK", 234 sblock.fs_fmask); 235 sblock.fs_fmask = ~(sblock.fs_fsize - 1); 236 if (preen) 237 printf(" (FIXED)\n"); 238 if (preen || reply("FIX") == 1) { 239 sbdirty(); 240 dirty(&asblk); 241 } 242 } 243 if (1 << sblock.fs_bshift != sblock.fs_bsize) { 244 pwarn("INCORRECT BSHIFT=%d IN SUPERBLOCK", sblock.fs_bshift); 245 sblock.fs_bshift = ffs(sblock.fs_bsize) - 1; 246 if (preen) 247 printf(" (FIXED)\n"); 248 if (preen || reply("FIX") == 1) { 249 sbdirty(); 250 dirty(&asblk); 251 } 252 } 253 if (1 << sblock.fs_fshift != sblock.fs_fsize) { 254 pwarn("INCORRECT FSHIFT=%d IN SUPERBLOCK", sblock.fs_fshift); 255 sblock.fs_fshift = ffs(sblock.fs_fsize) - 1; 256 if (preen) 257 printf(" (FIXED)\n"); 258 if (preen || reply("FIX") == 1) { 259 sbdirty(); 260 dirty(&asblk); 261 } 262 } 263 if (sblock.fs_inodefmt < FS_44INODEFMT) { 264 pwarn("Format of filesystem is too old.\n"); 265 pwarn("Must update to modern format using a version of fsck\n"); 266 pfatal("from before release 5.0 with the command ``fsck -c 2''\n"); 267 exit(8); 268 } 269 if (sblock.fs_maxfilesize != maxfilesize) { 270 pwarn("INCORRECT MAXFILESIZE=%llu IN SUPERBLOCK", 271 (unsigned long long)sblock.fs_maxfilesize); 272 sblock.fs_maxfilesize = maxfilesize; 273 if (preen) 274 printf(" (FIXED)\n"); 275 if (preen || reply("FIX") == 1) { 276 sbdirty(); 277 dirty(&asblk); 278 } 279 } 280 maxsymlinklen = sblock.fs_magic == FS_UFS1_MAGIC ? 281 MAXSYMLINKLEN_UFS1 : MAXSYMLINKLEN_UFS2; 282 if (sblock.fs_maxsymlinklen != maxsymlinklen) { 283 pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK", 284 sblock.fs_maxsymlinklen); 285 sblock.fs_maxsymlinklen = maxsymlinklen; 286 if (preen) 287 printf(" (FIXED)\n"); 288 if (preen || reply("FIX") == 1) { 289 sbdirty(); 290 dirty(&asblk); 291 } 292 } 293 if (sblock.fs_qbmask != ~sblock.fs_bmask) { 294 pwarn("INCORRECT QBMASK=%lx IN SUPERBLOCK", 295 (unsigned long)sblock.fs_qbmask); 296 sblock.fs_qbmask = ~sblock.fs_bmask; 297 if (preen) 298 printf(" (FIXED)\n"); 299 if (preen || reply("FIX") == 1) { 300 sbdirty(); 301 dirty(&asblk); 302 } 303 } 304 if (sblock.fs_qfmask != ~sblock.fs_fmask) { 305 pwarn("INCORRECT QFMASK=%lx IN SUPERBLOCK", 306 (unsigned long)sblock.fs_qfmask); 307 sblock.fs_qfmask = ~sblock.fs_fmask; 308 if (preen) 309 printf(" (FIXED)\n"); 310 if (preen || reply("FIX") == 1) { 311 sbdirty(); 312 dirty(&asblk); 313 } 314 } 315 if (sblock.fs_cgsize != fragroundup(&sblock, CGSIZE(&sblock))) { 316 pwarn("INCONSISTENT CGSIZE=%d\n", sblock.fs_cgsize); 317 sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock)); 318 if (preen) 319 printf(" (FIXED)\n"); 320 if (preen || reply("FIX") == 1) { 321 sbdirty(); 322 dirty(&asblk); 323 } 324 } 325 if (sblock.fs_magic == FS_UFS2_MAGIC) 326 inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode); 327 else 328 inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode); 329 if (INOPB(&sblock) != inopb) { 330 pwarn("INCONSISTENT INOPB=%d\n", INOPB(&sblock)); 331 sblock.fs_inopb = inopb; 332 if (preen) 333 printf(" (FIXED)\n"); 334 if (preen || reply("FIX") == 1) { 335 sbdirty(); 336 dirty(&asblk); 337 } 338 } 339 if (sblock.fs_magic == FS_UFS2_MAGIC) 340 nindir = sblock.fs_bsize / sizeof(int64_t); 341 else 342 nindir = sblock.fs_bsize / sizeof(int32_t); 343 if (NINDIR(&sblock) != nindir) { 344 pwarn("INCONSISTENT NINDIR=%d\n", NINDIR(&sblock)); 345 sblock.fs_nindir = nindir; 346 if (preen) 347 printf(" (FIXED)\n"); 348 if (preen || reply("FIX") == 1) { 349 sbdirty(); 350 dirty(&asblk); 351 } 352 } 353 if (asblk.b_dirty && !bflag) { 354 memcpy(&altsblock, &sblock, (size_t)sblock.fs_sbsize); 355 flush(fswritefd, &asblk); 356 } 357 /* 358 * read in the summary info. 359 */ 360 asked = 0; 361 sblock.fs_csp = calloc(1, sblock.fs_cssize); 362 if (sblock.fs_csp == NULL) { 363 printf("cannot alloc %u bytes for cylinder group summary area\n", 364 (unsigned)sblock.fs_cssize); 365 goto badsblabel; 366 } 367 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 368 size = sblock.fs_cssize - i < sblock.fs_bsize ? 369 sblock.fs_cssize - i : sblock.fs_bsize; 370 if (bread(fsreadfd, (char *)sblock.fs_csp + i, 371 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 372 size) != 0 && !asked) { 373 pfatal("BAD SUMMARY INFORMATION"); 374 if (reply("CONTINUE") == 0) { 375 ckfini(0); 376 errexit("%s", ""); 377 } 378 asked++; 379 } 380 } 381 /* 382 * allocate and initialize the necessary maps 383 */ 384 bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); 385 blockmap = calloc((unsigned)bmapsize, sizeof(char)); 386 if (blockmap == NULL) { 387 printf("cannot alloc %u bytes for blockmap\n", 388 (unsigned)bmapsize); 389 goto badsblabel; 390 } 391 inostathead = calloc((unsigned)(sblock.fs_ncg), 392 sizeof(struct inostatlist)); 393 if (inostathead == NULL) { 394 printf("cannot alloc %u bytes for inostathead\n", 395 (unsigned)(sizeof(struct inostatlist) * (sblock.fs_ncg))); 396 goto badsblabel; 397 } 398 numdirs = MAX(sblock.fs_cstotal.cs_ndir, 128); 399 inplast = 0; 400 listmax = numdirs + 10; 401 inpsort = calloc((unsigned)listmax, sizeof(struct inoinfo *)); 402 if (inpsort == NULL) { 403 printf("cannot alloc %zu bytes for inpsort\n", 404 (unsigned)listmax * sizeof(struct inoinfo *)); 405 goto badsblabel; 406 } 407 inphead = calloc((unsigned)numdirs, sizeof(struct inoinfo *)); 408 if (inphead == NULL) { 409 printf("cannot alloc %zu bytes for inphead\n", 410 (unsigned)numdirs * sizeof(struct inoinfo *)); 411 goto badsblabel; 412 } 413 bufinit(); 414 if (sblock.fs_flags & FS_DOSOFTDEP) 415 usedsoftdep = 1; 416 else 417 usedsoftdep = 0; 418 return (1); 419 420 badsblabel: 421 ckfini(0); 422 return (0); 423 } 424 425 426 /* 427 * Read in the super block and its summary info. 428 */ 429 static int 430 readsb(int listerr) 431 { 432 daddr_t super = 0; 433 int i; 434 435 if (bflag) { 436 super = bflag; 437 438 if (bread(fsreadfd, (char *)&sblock, super, (long)SBSIZE) != 0) 439 return (0); 440 441 if (sblock.fs_magic != FS_UFS1_MAGIC && 442 sblock.fs_magic != FS_UFS2_MAGIC) { 443 badsb(listerr, "MAGIC NUMBER WRONG"); 444 return (0); 445 } 446 } else { 447 for (i = 0; sbtry[i] != -1; i++) { 448 super = sbtry[i] / dev_bsize; 449 450 if (bread(fsreadfd, (char *)&sblock, super, 451 (long)SBSIZE) != 0) 452 return (0); 453 454 if (sblock.fs_magic != FS_UFS1_MAGIC && 455 sblock.fs_magic != FS_UFS2_MAGIC) 456 continue; /* Not a superblock */ 457 458 /* 459 * Do not look for an FFS1 file system at SBLOCK_UFS2. 460 * Doing so will find the wrong super-block for file 461 * systems with 64k block size. 462 */ 463 if (sblock.fs_magic == FS_UFS1_MAGIC && 464 sbtry[i] == SBLOCK_UFS2) 465 continue; 466 467 if (sblock.fs_magic == FS_UFS2_MAGIC && 468 sblock.fs_sblockloc != sbtry[i]) 469 continue; /* Not a superblock */ 470 471 break; 472 } 473 474 if (sbtry[i] == -1) { 475 badsb(listerr, "MAGIC NUMBER WRONG"); 476 return (0); 477 } 478 } 479 480 sblk.b_bno = super; 481 sblk.b_size = SBSIZE; 482 483 /* 484 * run a few consistency checks of the super block 485 */ 486 if (sblock.fs_ncg < 1) { 487 badsb(listerr, "NCG OUT OF RANGE"); 488 return (0); 489 } 490 if (sblock.fs_cpg < 1) { 491 badsb(listerr, "CPG OUT OF RANGE"); 492 return (0); 493 } 494 if (sblock.fs_magic == FS_UFS1_MAGIC) { 495 if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl || 496 (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) { 497 badsb(listerr, "NCYL LESS THAN NCG*CPG"); 498 return (0); 499 } 500 } 501 if (sblock.fs_sbsize > SBSIZE) { 502 badsb(listerr, "SBSIZE PREPOSTEROUSLY LARGE"); 503 return (0); 504 } 505 506 if (!POWEROF2(sblock.fs_bsize) || sblock.fs_bsize < MINBSIZE || 507 sblock.fs_bsize > MAXBSIZE) { 508 badsb(listerr, "ILLEGAL BLOCK SIZE IN SUPERBLOCK"); 509 return (0); 510 } 511 512 if (!POWEROF2(sblock.fs_fsize) || sblock.fs_fsize > sblock.fs_bsize || 513 sblock.fs_fsize < sblock.fs_bsize / MAXFRAG) { 514 badsb(listerr, "ILLEGAL FRAGMENT SIZE IN SUPERBLOCK"); 515 return (0); 516 } 517 518 519 /* 520 * Compute block size that the filesystem is based on, 521 * according to fsbtodb, and adjust superblock block number 522 * so we can tell if this is an alternate later. 523 */ 524 super *= dev_bsize; 525 dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 526 sblk.b_bno = super / dev_bsize; 527 if (bflag) 528 goto out; 529 getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize); 530 if (asblk.b_errs) 531 return (0); 532 if (cmpsb(&sblock, &altsblock)) { 533 if (debug) { 534 long *nlp, *olp, *endlp; 535 536 printf("superblock mismatches\n"); 537 nlp = (long *)&altsblock; 538 olp = (long *)&sblock; 539 endlp = olp + (sblock.fs_sbsize / sizeof *olp); 540 for ( ; olp < endlp; olp++, nlp++) { 541 if (*olp == *nlp) 542 continue; 543 printf("offset %d, original %ld, alternate %ld\n", 544 (int)(olp - (long *)&sblock), *olp, *nlp); 545 } 546 } 547 badsb(listerr, 548 "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN LAST ALTERNATE"); 549 return (0); 550 } 551 out: 552 if (sblock.fs_magic == FS_UFS1_MAGIC) { 553 sblock.fs_time = sblock.fs_ffs1_time; 554 sblock.fs_size = sblock.fs_ffs1_size; 555 sblock.fs_dsize = sblock.fs_ffs1_dsize; 556 sblock.fs_csaddr = sblock.fs_ffs1_csaddr; 557 sblock.fs_cstotal.cs_ndir = sblock.fs_ffs1_cstotal.cs_ndir; 558 sblock.fs_cstotal.cs_nbfree = sblock.fs_ffs1_cstotal.cs_nbfree; 559 sblock.fs_cstotal.cs_nifree = sblock.fs_ffs1_cstotal.cs_nifree; 560 sblock.fs_cstotal.cs_nffree = sblock.fs_ffs1_cstotal.cs_nffree; 561 } 562 havesb = 1; 563 return (1); 564 } 565 566 void 567 badsb(int listerr, char *s) 568 { 569 570 if (!listerr) 571 return; 572 if (preen) 573 printf("%s: ", cdevname()); 574 pfatal("BAD SUPER BLOCK: %s\n", s); 575 } 576 577 /* 578 * Calculate a prototype superblock based on information in the disk label. 579 * When done the cgsblock macro can be calculated and the fs_ncg field 580 * can be used. Do NOT attempt to use other macros without verifying that 581 * their needed information is available! 582 */ 583 int 584 calcsb(char *dev, int devfd, struct fs *fs) 585 { 586 struct disklabel *lp; 587 struct partition *pp; 588 char *cp; 589 int i; 590 591 cp = strchr(dev, '\0'); 592 if ((cp == NULL || (cp[-1] < 'a' || cp[-1] >= 'a' + MAXPARTITIONS)) && 593 !isdigit((unsigned char)cp[-1])) { 594 pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev); 595 return (0); 596 } 597 cp--; 598 lp = getdisklabel(dev, devfd); 599 if (isdigit((unsigned char)*cp)) 600 pp = &lp->d_partitions[0]; 601 else 602 pp = &lp->d_partitions[*cp - 'a']; 603 if (pp->p_fstype != FS_BSDFFS) { 604 pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n", 605 dev, pp->p_fstype < FSMAXTYPES ? 606 fstypenames[pp->p_fstype] : "unknown"); 607 return (0); 608 } 609 memset(fs, 0, sizeof(struct fs)); 610 fs->fs_fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 611 fs->fs_frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 612 fs->fs_bsize = fs->fs_fsize * fs->fs_frag; 613 fs->fs_cpg = pp->p_cpg; 614 fs->fs_nspf = fs->fs_fsize / lp->d_secsize; 615 /* unit for fs->fs_size is fragments, for DL_GETPSIZE() it is sectors */ 616 fs->fs_size = DL_GETPSIZE(pp) / fs->fs_nspf; 617 fs->fs_ntrak = lp->d_ntracks; 618 fs->fs_nsect = lp->d_nsectors; 619 fs->fs_spc = lp->d_secpercyl; 620 /* we can't use lp->d_sbsize, it is the max sb size */ 621 fs->fs_sblkno = roundup( 622 howmany(lp->d_bbsize + SBSIZE, fs->fs_fsize), 623 fs->fs_frag); 624 again: 625 fs->fs_cgmask = 0xffffffff; 626 for (i = fs->fs_ntrak; i > 1; i >>= 1) 627 fs->fs_cgmask <<= 1; 628 if (!POWEROF2(fs->fs_ntrak)) 629 fs->fs_cgmask <<= 1; 630 fs->fs_cgoffset = roundup( 631 howmany(fs->fs_nsect, NSPF(fs)), fs->fs_frag); 632 fs->fs_fpg = (fs->fs_cpg * fs->fs_spc) / NSPF(fs); 633 fs->fs_ncg = howmany(DL_GETPSIZE(pp) / fs->fs_spc, fs->fs_cpg); 634 for (fs->fs_fsbtodb = 0, i = NSPF(fs); i > 1; i >>= 1) 635 fs->fs_fsbtodb++; 636 /* 637 * Mimick what mkfs is doing to get an acceptable cgsize, 638 * not all fields used by CGSIZE() are filled in, but it's a best 639 * effort anyway. 640 */ 641 if (CGSIZE(fs) > fs->fs_bsize && fs->fs_ntrak > 1) { 642 fs->fs_ntrak >>= 1; 643 fs->fs_spc >>= 1; 644 goto again; 645 } 646 dev_bsize = lp->d_secsize; 647 return (1); 648 } 649 650 static struct disklabel * 651 getdisklabel(char *s, int fd) 652 { 653 static struct disklabel lab; 654 655 if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) { 656 if (s == NULL) 657 return (NULL); 658 pwarn("ioctl (GCINFO): %s\n", strerror(errno)); 659 errexit("%s: can't read disk label\n", s); 660 } 661 return (&lab); 662 } 663 664 /* 665 * Compare two superblocks 666 */ 667 static int 668 cmpsb(struct fs *sb, struct fs *asb) 669 { 670 /* 671 * Only compare fields which should be the same, and ignore ones 672 * likely to change to ensure future compatibility. 673 */ 674 if (asb->fs_sblkno != sb->fs_sblkno || 675 asb->fs_cblkno != sb->fs_cblkno || 676 asb->fs_iblkno != sb->fs_iblkno || 677 asb->fs_dblkno != sb->fs_dblkno || 678 asb->fs_cgoffset != sb->fs_cgoffset || 679 asb->fs_cgmask != sb->fs_cgmask || 680 asb->fs_ncg != sb->fs_ncg || 681 asb->fs_bsize != sb->fs_bsize || 682 asb->fs_fsize != sb->fs_fsize || 683 asb->fs_frag != sb->fs_frag || 684 asb->fs_bmask != sb->fs_bmask || 685 asb->fs_fmask != sb->fs_fmask || 686 asb->fs_bshift != sb->fs_bshift || 687 asb->fs_fshift != sb->fs_fshift || 688 asb->fs_fragshift != sb->fs_fragshift || 689 asb->fs_fsbtodb != sb->fs_fsbtodb || 690 asb->fs_sbsize != sb->fs_sbsize || 691 asb->fs_nindir != sb->fs_nindir || 692 asb->fs_inopb != sb->fs_inopb || 693 asb->fs_cssize != sb->fs_cssize || 694 asb->fs_cpg != sb->fs_cpg || 695 asb->fs_ipg != sb->fs_ipg || 696 asb->fs_fpg != sb->fs_fpg || 697 asb->fs_magic != sb->fs_magic) 698 return (1); 699 /* they're the same */ 700 return (0); 701 } 702