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