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