1 /* $NetBSD: setup.c,v 1.3 1999/07/03 19:55:03 kleink 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 /* #define DKTYPENAMES */ 37 #define FSTYPENAMES 38 #include <sys/param.h> 39 #include <sys/time.h> 40 #include <sys/stat.h> 41 #include <sys/ioctl.h> 42 #include <sys/disklabel.h> 43 #include <sys/file.h> 44 45 #include <ufs/ufs/dinode.h> 46 #include <sys/mount.h> /* XXX ufs/lfs/lfs.h should include this for us */ 47 #include <ufs/lfs/lfs.h> 48 #include <ufs/lfs/lfs_extern.h> 49 50 #include <ctype.h> 51 #include <err.h> 52 #include <errno.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 57 #include "fsck.h" 58 #include "extern.h" 59 #include "fsutil.h" 60 61 struct bufarea asblk; 62 extern struct dinode **din_table; 63 extern SEGUSE *seg_table; 64 #define altsblock (*asblk.b_un.b_fs) 65 #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 66 67 void badsb __P((int, char *)); 68 int calcsb __P((const char *, int, struct lfs *)); 69 static struct disklabel *getdisklabel __P((const char *, int)); 70 static int readsb __P((int)); 71 int lfs_maxino(void); 72 73 #ifdef DKTYPENAMES 74 int useless __P((void)); 75 76 int 77 useless(void) 78 { 79 char **foo = (char **)dktypenames; 80 char **bar = (char **)fscknames; 81 82 return foo-bar; 83 } 84 #endif 85 86 int 87 setup(dev) 88 const char *dev; 89 { 90 long bmapsize; 91 struct disklabel *lp; 92 #if 0 93 long i; 94 off_t sizepb; 95 #endif 96 struct stat statb; 97 struct lfs proto; 98 int doskipclean; 99 u_int64_t maxfilesize; 100 struct lfs *sb0; 101 102 havesb = 0; 103 fswritefd = -1; 104 doskipclean = skipclean; 105 if (stat(dev, &statb) < 0) { 106 printf("Can't stat %s: %s\n", dev, strerror(errno)); 107 return (0); 108 } 109 if (!S_ISCHR(statb.st_mode)) { 110 pfatal("%s is not a character device", dev); 111 if (reply("CONTINUE") == 0) 112 return (0); 113 } 114 if ((fsreadfd = open(dev, O_RDONLY)) < 0) { 115 printf("Can't open %s: %s\n", dev, strerror(errno)); 116 return (0); 117 } 118 if (preen == 0) 119 printf("** %s", dev); 120 if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) { 121 fswritefd = -1; 122 if (preen) 123 pfatal("NO WRITE ACCESS"); 124 printf(" (NO WRITE)"); 125 } 126 if (preen == 0) 127 printf("\n"); 128 fsmodified = 0; 129 lfdir = 0; 130 initbarea(&sblk); 131 initbarea(&asblk); 132 sblk.b_un.b_buf = malloc(LFS_SBPAD); 133 asblk.b_un.b_buf = malloc(LFS_SBPAD); 134 if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) 135 errexit("cannot allocate space for superblock\n"); 136 if ((lp = getdisklabel((char *)NULL, fsreadfd)) != NULL) 137 dev_bsize = secsize = lp->d_secsize; 138 else 139 dev_bsize = secsize = DEV_BSIZE; 140 141 /* 142 * Read in the superblock, looking for alternates if necessary 143 */ 144 if (readsb(1) == 0) { 145 if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0) 146 return(0); 147 if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) 148 return (0); 149 #if 0 /* XXX find the LFS way to do this */ 150 for (cg = 0; cg < proto.lfs_ncg; cg++) { 151 bflag = fsbtodb(&proto, cgsblock(&proto, cg)); 152 if (readsb(0) != 0) 153 break; 154 } 155 if (cg >= proto.lfs_ncg) { 156 printf("%s %s\n%s %s\n%s %s\n", 157 "SEARCH FOR ALTERNATE SUPER-BLOCK", 158 "FAILED. YOU MUST USE THE", 159 "-b OPTION TO FSCK_FFS TO SPECIFY THE", 160 "LOCATION OF AN ALTERNATE", 161 "SUPER-BLOCK TO SUPPLY NEEDED", 162 "INFORMATION; SEE fsck_ffs(8)."); 163 return(0); 164 } 165 #else 166 pwarn("XXX Can't look for alternate superblocks yet\n"); 167 return(0); 168 #endif 169 doskipclean = 0; 170 pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); 171 } 172 if(bflag==0) { 173 /* 174 * Even if that superblock read in properly, it may not 175 * be guaranteed to point to a complete checkpoint. 176 * Read in the second superblock too, and take whichever 177 * of the two is *less* recent. --ks 178 */ 179 sb0 = malloc(sizeof(*sb0)); 180 memcpy(sb0,&sblock,sizeof(*sb0)); 181 bflag = sblock.lfs_sboffs[1]; 182 if(readsb(1)==0) { 183 pwarn("COULDN'T READ ALT SUPERBLOCK AT BLK %d",bflag); 184 if (reply("ASSUME PRIMARY SUPERBLOCK IS GOOD") == 0) { 185 return (0); 186 } else { /* use primary as good */ 187 memcpy(&sblock,sb0,sizeof(*sb0)); /* XXX cheating? */ 188 } 189 } else { 190 if(debug) 191 pwarn("sb0 %d, sb1 %d\n",sb0->lfs_tstamp,sblock.lfs_tstamp); 192 if(sblock.lfs_tstamp >= sb0->lfs_tstamp) { 193 memcpy(&sblock,sb0,sizeof(*sb0)); /* XXX cheating? */ 194 } else { 195 pwarn("Using alt superblock, disk addr 0x%x\n", 196 bflag); 197 } 198 } 199 free(sb0); 200 } 201 if(debug) { 202 printf("dev_bsize = %lu\n",dev_bsize); 203 printf("lfs_bsize = %lu\n",(unsigned long)sblock.lfs_bsize); 204 printf("lfs_fsize = %lu\n",(unsigned long)sblock.lfs_fsize); 205 printf("lfs_frag = %lu\n",(unsigned long)sblock.lfs_frag); 206 printf("INOPB(fs) = %lu\n",(unsigned long)INOPB(&sblock)); 207 /* printf("fsbtodb(fs,1) = %lu\n",fsbtodb(&sblock,1)); */ 208 } 209 #if 0 /* FFS-specific fs-clean check */ 210 if (debug) 211 printf("clean = %d\n", sblock.lfs_clean); 212 if (sblock.lfs_clean & FS_ISCLEAN) { 213 if (doskipclean) { 214 pwarn("%sile system is clean; not checking\n", 215 preen ? "f" : "** F"); 216 return (-1); 217 } 218 if (!preen) 219 pwarn("** File system is already clean\n"); 220 } 221 maxino = sblock.lfs_ncg * sblock.lfs_ipg; 222 #else 223 #if 0 224 /* XXX - count the number of inodes here */ 225 maxino = sblock.lfs_nfiles+2; 226 #else 227 initbarea(&iblk); 228 iblk.b_un.b_buf = malloc(sblock.lfs_bsize); 229 if(bread(fsreadfd, (char *)iblk.b_un.b_buf, 230 sblock.lfs_idaddr, 231 (long)sblock.lfs_bsize) != 0) 232 { 233 printf("Couldn't read disk block %d\n",sblock.lfs_idaddr); 234 exit(1); 235 } 236 maxino = lfs_maxino(); 237 #endif 238 if (debug) 239 printf("maxino=%d\n",maxino); 240 din_table = (struct dinode **)malloc(maxino*sizeof(*din_table)); 241 memset(din_table,0,maxino*sizeof(*din_table)); 242 seg_table = (SEGUSE *)malloc(sblock.lfs_nseg * sizeof(SEGUSE)); 243 memset(seg_table,0,sblock.lfs_nseg * sizeof(SEGUSE)); 244 #endif 245 maxfsblock = sblock.lfs_size * (sblock.lfs_bsize / dev_bsize); 246 #if 0 247 sizepb = sblock.lfs_bsize; 248 maxfilesize = sblock.lfs_bsize * NDADDR - 1; 249 for (i = 0; i < NIADDR; i++) { 250 sizepb *= NINDIR(&sblock); 251 maxfilesize += sizepb; 252 } 253 maxfilesize++; /* XXX */ 254 #else /* LFS way */ 255 { 256 u_quad_t maxtable[] = { 257 /* 1 */ -1, 258 /* 2 */ -1, 259 /* 4 */ -1, 260 /* 8 */ -1, 261 /* 16 */ -1, 262 /* 32 */ -1, 263 /* 64 */ -1, 264 /* 128 */ -1, 265 /* 256 */ -1, 266 /* 512 */ NDADDR + 128 + 128 * 128 + 128 * 128 * 128, 267 /* 1024 */ NDADDR + 256 + 256 * 256 + 256 * 256 * 256, 268 /* 2048 */ NDADDR + 512 + 512 * 512 + 512 * 512 * 512, 269 /* 4096 */ NDADDR + 1024 + 1024 * 1024 + 1024 * 1024 * 1024, 270 /* 8192 */ 1 << 31, 271 /* 16 K */ 1 << 31, 272 /* 32 K */ 1 << 31, 273 }; 274 maxfilesize = maxtable[sblock.lfs_bshift] << sblock.lfs_bshift; 275 } 276 #endif 277 if ((sblock.lfs_minfree < 0 || sblock.lfs_minfree > 99)) { 278 pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 279 sblock.lfs_minfree); 280 if (reply("SET TO DEFAULT") == 1) { 281 sblock.lfs_minfree = 10; 282 sbdirty(); 283 } 284 } 285 /* XXX used to be ~(sblock.lfs_bsize - 1) */ 286 if (sblock.lfs_bmask != sblock.lfs_bsize - 1) { 287 pwarn("INCORRECT BMASK=%x IN SUPERBLOCK (should be %x)", 288 (unsigned int)sblock.lfs_bmask, 289 (unsigned int)sblock.lfs_bsize - 1); 290 sblock.lfs_bmask = sblock.lfs_bsize - 1; 291 if (preen) 292 printf(" (FIXED)\n"); 293 if (preen || reply("FIX") == 1) { 294 sbdirty(); 295 dirty(&asblk); 296 } 297 } 298 #if 0 /* FFS-specific checks */ 299 if (sblock.lfs_fmask != ~(sblock.lfs_fsize - 1)) { 300 pwarn("INCORRECT FMASK=%x IN SUPERBLOCK", 301 sblock.lfs_fmask); 302 sblock.lfs_fmask = ~(sblock.lfs_fsize - 1); 303 if (preen) 304 printf(" (FIXED)\n"); 305 if (preen || reply("FIX") == 1) { 306 sbdirty(); 307 dirty(&asblk); 308 } 309 } 310 #endif 311 if (sblock.lfs_maxfilesize != maxfilesize) { 312 pwarn("INCORRECT MAXFILESIZE=%qu IN SUPERBLOCK (should be %qu)", 313 (unsigned long long)sblock.lfs_maxfilesize, 314 (unsigned long long)maxfilesize); 315 sblock.lfs_maxfilesize = maxfilesize; 316 if (preen) 317 printf(" (FIXED)\n"); 318 if (preen || reply("FIX") == 1) { 319 sbdirty(); 320 dirty(&asblk); 321 } 322 } 323 if (sblock.lfs_maxsymlinklen != MAXSYMLINKLEN) { 324 pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK", 325 sblock.lfs_maxsymlinklen); 326 sblock.lfs_maxsymlinklen = MAXSYMLINKLEN; 327 if (preen) 328 printf(" (FIXED)\n"); 329 if (preen || reply("FIX") == 1) { 330 sbdirty(); 331 dirty(&asblk); 332 } 333 } 334 newinofmt = 1; 335 /* 336 * allocate and initialize the necessary maps 337 */ 338 #ifndef VERBOSE_BLOCKMAP 339 bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); 340 blockmap = malloc((unsigned)bmapsize * sizeof (char)); 341 bzero(blockmap, bmapsize * sizeof(char)); 342 #else 343 bmapsize = maxfsblock*sizeof(ino_t); 344 blockmap = (ino_t *)malloc(maxfsblock * sizeof (ino_t)); 345 bzero(blockmap, maxfsblock * sizeof(ino_t)); 346 #endif 347 if (blockmap == NULL) { 348 printf("cannot alloc %u bytes for blockmap\n", 349 (unsigned)bmapsize); 350 goto badsblabel; 351 } 352 statemap = calloc((unsigned)(maxino + 1), sizeof(char)); 353 if (statemap == NULL) { 354 printf("cannot alloc %u bytes for statemap\n", 355 (unsigned)(maxino + 1)); 356 goto badsblabel; 357 } 358 typemap = calloc((unsigned)(maxino + 1), sizeof(char)); 359 if (typemap == NULL) { 360 printf("cannot alloc %u bytes for typemap\n", 361 (unsigned)(maxino + 1)); 362 goto badsblabel; 363 } 364 lncntp = (int16_t *)calloc((unsigned)(maxino + 1), sizeof(int16_t)); 365 if (lncntp == NULL) { 366 printf("cannot alloc %lu bytes for lncntp\n", 367 (unsigned long)(maxino + 1) * sizeof(int16_t)); 368 goto badsblabel; 369 } 370 bufinit(); 371 return (1); 372 373 badsblabel: 374 ckfini(0); 375 return (0); 376 } 377 378 /* 379 * Read in the LFS super block and its summary info. 380 */ 381 static int 382 readsb(listerr) 383 int listerr; 384 { 385 daddr_t super = bflag ? bflag : LFS_LABELPAD / dev_bsize; 386 u_int32_t checksum; 387 388 if (bread(fsreadfd, (char *)&sblock, super, (long)LFS_SBPAD) != 0) 389 return (0); 390 391 sblk.b_bno = super; 392 sblk.b_size = LFS_SBPAD; 393 /* 394 * run a few consistency checks of the super block 395 */ 396 if (sblock.lfs_magic != LFS_MAGIC) 397 { badsb(listerr, "MAGIC NUMBER WRONG"); return (0); } 398 399 /* checksum */ 400 checksum = lfs_sb_cksum(&(sblock.lfs_dlfs)); 401 if(sblock.lfs_cksum != checksum) 402 { 403 printf("Superblock checksum (%lu) does not match computed checksum %lu\n", 404 (unsigned long)sblock.lfs_cksum, (unsigned long)checksum); 405 } 406 407 #if 0 /* XXX - replace these checks with appropriate LFS sanity checks */ 408 if (sblock.lfs_ncg < 1) 409 { badsb(listerr, "NCG OUT OF RANGE"); return (0); } 410 if (sblock.lfs_cpg < 1) 411 { badsb(listerr, "CPG OUT OF RANGE"); return (0); } 412 if (sblock.lfs_ncg * sblock.lfs_cpg < sblock.lfs_ncyl || 413 (sblock.lfs_ncg - 1) * sblock.lfs_cpg >= sblock.lfs_ncyl) 414 { badsb(listerr, "NCYL LESS THAN NCG*CPG"); return (0); } 415 if (sblock.lfs_sbsize > SBSIZE) 416 { badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); } 417 #endif 418 /* 419 * Compute block size that the filesystem is based on, 420 * according to fsbtodb, and adjust superblock block number 421 * so we can tell if this is an alternate later. 422 */ 423 super *= dev_bsize; 424 #if 0 425 dev_bsize = sblock.lfs_bsize / fsbtodb(&sblock, 1); 426 #endif 427 sblk.b_bno = super / dev_bsize; 428 if (bflag) { 429 havesb = 1; 430 return (1); 431 } 432 #if 0 /* XXX - for now skip the alt. superblock test as well */ 433 /* 434 * Set all possible fields that could differ, then do check 435 * of whole super block against an alternate super block. 436 * When an alternate super-block is specified this check is skipped. 437 */ 438 getblk(&asblk, cgsblock(&sblock, sblock.lfs_ncg - 1), sblock.lfs_sbsize); 439 if (asblk.b_errs) 440 return (0); 441 altsblock.lfs_firstfield = sblock.lfs_firstfield; 442 altsblock.lfs_fscktime = sblock.lfs_fscktime; 443 altsblock.lfs_time = sblock.lfs_time; 444 altsblock.lfs_cstotal = sblock.lfs_cstotal; 445 altsblock.lfs_cgrotor = sblock.lfs_cgrotor; 446 altsblock.lfs_fmod = sblock.lfs_fmod; 447 altsblock.lfs_clean = sblock.lfs_clean; 448 altsblock.lfs_ronly = sblock.lfs_ronly; 449 altsblock.lfs_flags = sblock.lfs_flags; 450 altsblock.lfs_maxcontig = sblock.lfs_maxcontig; 451 altsblock.lfs_minfree = sblock.lfs_minfree; 452 altsblock.lfs_optim = sblock.lfs_optim; 453 altsblock.lfs_rotdelay = sblock.lfs_rotdelay; 454 altsblock.lfs_maxbpg = sblock.lfs_maxbpg; 455 memcpy(altsblock.lfs_csp, sblock.lfs_csp, 456 sizeof sblock.lfs_csp); 457 altsblock.lfs_maxcluster = sblock.lfs_maxcluster; 458 memcpy(altsblock.lfs_fsmnt, sblock.lfs_fsmnt, 459 sizeof sblock.lfs_fsmnt); 460 memcpy(altsblock.lfs_sparecon, sblock.lfs_sparecon, 461 sizeof sblock.lfs_sparecon); 462 /* 463 * The following should not have to be copied. 464 */ 465 altsblock.lfs_fsbtodb = sblock.lfs_fsbtodb; 466 altsblock.lfs_interleave = sblock.lfs_interleave; 467 altsblock.lfs_npsect = sblock.lfs_npsect; 468 altsblock.lfs_nrpos = sblock.lfs_nrpos; 469 altsblock.lfs_state = sblock.lfs_state; 470 altsblock.lfs_qbmask = sblock.lfs_qbmask; 471 altsblock.lfs_qfmask = sblock.lfs_qfmask; 472 altsblock.lfs_state = sblock.lfs_state; 473 altsblock.lfs_maxfilesize = sblock.lfs_maxfilesize; 474 if (memcmp(&sblock, &altsblock, (int)sblock.lfs_sbsize)) { 475 if (debug) { 476 long *nlp, *olp, *endlp; 477 478 printf("superblock mismatches\n"); 479 nlp = (long *)&altsblock; 480 olp = (long *)&sblock; 481 endlp = olp + (sblock.lfs_sbsize / sizeof *olp); 482 for ( ; olp < endlp; olp++, nlp++) { 483 if (*olp == *nlp) 484 continue; 485 printf("offset %d, original %ld, alternate %ld\n", 486 olp - (long *)&sblock, *olp, *nlp); 487 } 488 } 489 badsb(listerr, 490 "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE"); 491 return (0); 492 } 493 #endif 494 havesb = 1; 495 return (1); 496 } 497 498 void 499 badsb(listerr, s) 500 int listerr; 501 char *s; 502 { 503 504 if (!listerr) 505 return; 506 if (preen) 507 printf("%s: ", cdevname()); 508 pfatal("BAD SUPER BLOCK: %s\n", s); 509 } 510 511 /* 512 * Calculate a prototype superblock based on information in the disk label. 513 * When done the cgsblock macro can be calculated and the fs_ncg field 514 * can be used. Do NOT attempt to use other macros without verifying that 515 * their needed information is available! 516 */ 517 int 518 calcsb(dev, devfd, fs) 519 const char *dev; 520 int devfd; 521 register struct lfs *fs; 522 { 523 register struct disklabel *lp; 524 register struct partition *pp; 525 register char *cp; 526 int i; 527 528 cp = strchr(dev, '\0') - 1; 529 if ((cp == (char *)-1 || (*cp < 'a' || *cp > 'h')) && !isdigit(*cp)) { 530 pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev); 531 return (0); 532 } 533 lp = getdisklabel(dev, devfd); 534 if (isdigit(*cp)) 535 pp = &lp->d_partitions[0]; 536 else 537 pp = &lp->d_partitions[*cp - 'a']; 538 if (pp->p_fstype != FS_BSDLFS) { 539 pfatal("%s: NOT LABELED AS AN LFS FILE SYSTEM (%s)\n", 540 dev, pp->p_fstype < FSMAXTYPES ? 541 fstypenames[pp->p_fstype] : "unknown"); 542 return (0); 543 } 544 memset(fs, 0, sizeof(struct lfs)); 545 fs->lfs_fsize = pp->p_fsize; 546 fs->lfs_frag = pp->p_frag; 547 fs->lfs_size = pp->p_size; 548 fs->lfs_nspf = fs->lfs_fsize / lp->d_secsize; 549 dev_bsize = lp->d_secsize; 550 for (fs->lfs_fsbtodb = 0, i = fs->lfs_nspf; i > 1; i >>= 1) 551 fs->lfs_fsbtodb++; 552 return (1); 553 } 554 555 static struct disklabel * 556 getdisklabel(s, fd) 557 const char *s; 558 int fd; 559 { 560 static struct disklabel lab; 561 562 if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) { 563 if (s == NULL) 564 return ((struct disklabel *)NULL); 565 pwarn("ioctl (GCINFO): %s\n", strerror(errno)); 566 errexit("%s: can't read disk label\n", s); 567 } 568 return (&lab); 569 } 570