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