1 /* 2 * Copyright (c) 1980, 1986 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 /*static char sccsid[] = "from: @(#)setup.c 5.33 (Berkeley) 2/22/91";*/ 36 static char rcsid[] = "$Id: setup.c,v 1.9 1994/04/25 18:33:42 cgd Exp $"; 37 #endif /* not lint */ 38 39 #define DKTYPENAMES 40 #include <sys/param.h> 41 #include <sys/time.h> 42 #include <ufs/dinode.h> 43 #include <ufs/fs.h> 44 #include <sys/stat.h> 45 #include <sys/ioctl.h> 46 #include <sys/disklabel.h> 47 #include <sys/file.h> 48 #include <sys/mount.h> 49 #include <errno.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <ctype.h> 53 #include "fsck.h" 54 55 struct bufarea asblk; 56 #define altsblock (*asblk.b_un.b_fs) 57 #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 58 59 /* 60 * The size of a cylinder group is calculated by CGSIZE. The maximum size 61 * is limited by the fact that cylinder groups are at most one block. 62 * Its size is derived from the size of the maps maintained in the 63 * cylinder group and the (struct cg) size. 64 */ 65 #define CGSIZE(fs) \ 66 /* base cg */ (sizeof(struct cg) + \ 67 /* blktot size */ (fs)->fs_cpg * sizeof(long) + \ 68 /* blks size */ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof(short) + \ 69 /* inode map */ howmany((fs)->fs_ipg, NBBY) + \ 70 /* block map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY)) 71 72 char *index(); 73 struct disklabel *getdisklabel(); 74 char *getmntdev(); 75 76 setup(dev) 77 char *dev; 78 { 79 long cg, size, asked, i, j; 80 long bmapsize; 81 struct disklabel *lp; 82 struct stat statb, statb2; 83 struct fs proto; 84 char path2[MAXPATHLEN]; 85 char *dev2; 86 87 havesb = 0; 88 if (stat(dev, &statb) < 0) { 89 printf("Can't stat %s: %s\n", dev, strerror(errno)); 90 return (0); 91 } 92 switch (statb.st_mode & S_IFMT) { 93 case S_IFCHR: 94 break; 95 case S_IFDIR: 96 dev2 = getmntdev(dev); 97 if (dev2 != NULL && !strncmp(dev2, "/dev/", 5)) { 98 snprintf(path2, sizeof(path2), "/dev/r%s", dev2 + 5); 99 if (stat(path2, &statb2) == 0 && 100 (statb2.st_mode & S_IFMT) == S_IFCHR) { 101 dev = path2; 102 statb = statb2; 103 break; 104 } 105 } 106 pfatal("%s is not a character device", dev); 107 if (reply("CONTINUE") == 0) 108 return (0); 109 break; 110 case S_IFBLK: 111 if (!strncmp(dev, "/dev/", 5)) { 112 sprintf(path2, "/dev/r%s", dev + 5); 113 if (stat(path2, &statb2) == 0 && 114 (statb2.st_mode & S_IFMT) == S_IFCHR && 115 minor(statb2.st_rdev) == minor(statb.st_rdev)) { 116 dev = path2; 117 statb = statb2; 118 break; 119 } 120 } 121 /* fall through */ 122 default: 123 pfatal("%s is not a character device", dev); 124 if (reply("CONTINUE") == 0) 125 return (0); 126 } 127 if ((fsreadfd = open(dev, O_RDONLY)) < 0) { 128 printf("Can't open %s: %s\n", dev, strerror(errno)); 129 return (0); 130 } 131 if (preen == 0) 132 printf("** %s", dev); 133 if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) { 134 fswritefd = -1; 135 if (preen) 136 pfatal("NO WRITE ACCESS"); 137 printf(" (NO WRITE)"); 138 } 139 if (preen == 0) 140 printf("\n"); 141 fsmodified = 0; 142 lfdir = 0; 143 initbarea(&sblk); 144 initbarea(&asblk); 145 sblk.b_un.b_buf = malloc(SBSIZE); 146 asblk.b_un.b_buf = malloc(SBSIZE); 147 if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) 148 errexit("cannot allocate space for superblock\n"); 149 if (lp = getdisklabel((char *)NULL, fsreadfd)) 150 dev_bsize = secsize = lp->d_secsize; 151 else 152 dev_bsize = secsize = DEV_BSIZE; 153 #ifdef tahoe 154 /* 155 * On the tahoe, the disk label and the disk driver disagree. 156 * The label knows that sectors are 512 bytes, but the disk 157 * drivers will only transfer in 1024 sized pieces. 158 */ 159 secsize = 1024; 160 #endif 161 /* 162 * Read in the superblock, looking for alternates if necessary 163 */ 164 if (readsb(1) == 0) { 165 if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0) 166 return(0); 167 if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) 168 return (0); 169 for (cg = 0; cg < proto.fs_ncg; cg++) { 170 bflag = fsbtodb(&proto, cgsblock(&proto, cg)); 171 if (readsb(0) != 0) 172 break; 173 } 174 if (cg >= proto.fs_ncg) { 175 printf("%s %s\n%s %s\n%s %s\n", 176 "SEARCH FOR ALTERNATE SUPER-BLOCK", 177 "FAILED. YOU MUST USE THE", 178 "-b OPTION TO FSCK TO SPECIFY THE", 179 "LOCATION OF AN ALTERNATE", 180 "SUPER-BLOCK TO SUPPLY NEEDED", 181 "INFORMATION; SEE fsck(8)."); 182 return(0); 183 } 184 pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); 185 } 186 maxfsblock = sblock.fs_size; 187 maxino = sblock.fs_ncg * sblock.fs_ipg; 188 /* 189 * Check and potentially fix certain fields in the super block. 190 */ 191 if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { 192 pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); 193 if (reply("SET TO DEFAULT") == 1) { 194 sblock.fs_optim = FS_OPTTIME; 195 sbdirty(); 196 } 197 } 198 if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { 199 pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 200 sblock.fs_minfree); 201 if (reply("SET TO DEFAULT") == 1) { 202 sblock.fs_minfree = 10; 203 sbdirty(); 204 } 205 } 206 if (sblock.fs_interleave < 1 || 207 sblock.fs_interleave > sblock.fs_nsect) { 208 pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK", 209 sblock.fs_interleave); 210 sblock.fs_interleave = 1; 211 if (preen) 212 printf(" (FIXED)\n"); 213 if (preen || reply("SET TO DEFAULT") == 1) { 214 sbdirty(); 215 dirty(&asblk); 216 } 217 } 218 if (sblock.fs_npsect < sblock.fs_nsect || 219 sblock.fs_npsect > sblock.fs_nsect*2) { 220 pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK", 221 sblock.fs_npsect); 222 sblock.fs_npsect = sblock.fs_nsect; 223 if (preen) 224 printf(" (FIXED)\n"); 225 if (preen || reply("SET TO DEFAULT") == 1) { 226 sbdirty(); 227 dirty(&asblk); 228 } 229 } 230 if (cvtflag) { 231 if (sblock.fs_postblformat == FS_42POSTBLFMT) { 232 /* 233 * Requested to convert from old format to new format 234 */ 235 if (preen) 236 pwarn("CONVERTING TO NEW FILE SYSTEM FORMAT\n"); 237 else if (!reply("CONVERT TO NEW FILE SYSTEM FORMAT")) 238 return(0); 239 sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT; 240 sblock.fs_nrpos = 8; 241 sblock.fs_postbloff = 242 (char *)(&sblock.fs_opostbl[0][0]) - 243 (char *)(&sblock.fs_link); 244 sblock.fs_rotbloff = &sblock.fs_space[0] - 245 (u_char *)(&sblock.fs_link); 246 sblock.fs_cgsize = 247 fragroundup(&sblock, CGSIZE(&sblock)); 248 /* 249 * Planning now for future expansion. 250 */ 251 # if (BYTE_ORDER == BIG_ENDIAN) 252 sblock.fs_qbmask.val[0] = 0; 253 sblock.fs_qbmask.val[1] = ~sblock.fs_bmask; 254 sblock.fs_qfmask.val[0] = 0; 255 sblock.fs_qfmask.val[1] = ~sblock.fs_fmask; 256 # endif /* BIG_ENDIAN */ 257 # if (BYTE_ORDER == LITTLE_ENDIAN) 258 sblock.fs_qbmask.val[0] = ~sblock.fs_bmask; 259 sblock.fs_qbmask.val[1] = 0; 260 sblock.fs_qfmask.val[0] = ~sblock.fs_fmask; 261 sblock.fs_qfmask.val[1] = 0; 262 # endif /* LITTLE_ENDIAN */ 263 sbdirty(); 264 dirty(&asblk); 265 } else if (sblock.fs_postblformat == FS_DYNAMICPOSTBLFMT) { 266 /* 267 * Requested to convert from new format to old format 268 */ 269 if (sblock.fs_nrpos != 8 || sblock.fs_ipg > 2048 || 270 sblock.fs_cpg > 32 || sblock.fs_cpc > 16) { 271 printf( 272 "PARAMETERS OF CURRENT FILE SYSTEM DO NOT\n\t"); 273 errexit( 274 "ALLOW CONVERSION TO OLD FILE SYSTEM FORMAT\n"); 275 } 276 if (preen) 277 pwarn("CONVERTING TO OLD FILE SYSTEM FORMAT\n"); 278 else if (!reply("CONVERT TO OLD FILE SYSTEM FORMAT")) 279 return(0); 280 sblock.fs_postblformat = FS_42POSTBLFMT; 281 sblock.fs_cgsize = fragroundup(&sblock, 282 sizeof(struct ocg) + howmany(sblock.fs_fpg, NBBY)); 283 sbdirty(); 284 dirty(&asblk); 285 } else { 286 errexit("UNKNOWN FILE SYSTEM FORMAT\n"); 287 } 288 } 289 if (asblk.b_dirty) { 290 bcopy((char *)&sblock, (char *)&altsblock, 291 (size_t)sblock.fs_sbsize); 292 flush(fswritefd, &asblk); 293 } 294 /* 295 * read in the summary info. 296 */ 297 asked = 0; 298 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 299 size = sblock.fs_cssize - i < sblock.fs_bsize ? 300 sblock.fs_cssize - i : sblock.fs_bsize; 301 sblock.fs_csp[j] = (struct csum *)calloc(1, (unsigned)size); 302 if (bread(fsreadfd, (char *)sblock.fs_csp[j], 303 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 304 size) != 0 && !asked) { 305 pfatal("BAD SUMMARY INFORMATION"); 306 if (reply("CONTINUE") == 0) 307 errexit(""); 308 asked++; 309 } 310 } 311 /* 312 * allocate and initialize the necessary maps 313 */ 314 bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(short)); 315 blockmap = calloc((unsigned)bmapsize, sizeof (char)); 316 if (blockmap == NULL) { 317 printf("cannot alloc %u bytes for blockmap\n", 318 (unsigned)bmapsize); 319 goto badsb; 320 } 321 statemap = calloc((unsigned)(maxino + 1), sizeof(char)); 322 if (statemap == NULL) { 323 printf("cannot alloc %u bytes for statemap\n", 324 (unsigned)(maxino + 1)); 325 goto badsb; 326 } 327 lncntp = (short *)calloc((unsigned)(maxino + 1), sizeof(short)); 328 if (lncntp == NULL) { 329 printf("cannot alloc %u bytes for lncntp\n", 330 (unsigned)(maxino + 1) * sizeof(short)); 331 goto badsb; 332 } 333 numdirs = sblock.fs_cstotal.cs_ndir; 334 inplast = 0; 335 listmax = numdirs + 10; 336 inpsort = (struct inoinfo **)calloc((unsigned)listmax, 337 sizeof(struct inoinfo *)); 338 inphead = (struct inoinfo **)calloc((unsigned)numdirs, 339 sizeof(struct inoinfo *)); 340 if (inpsort == NULL || inphead == NULL) { 341 printf("cannot alloc %u bytes for inphead\n", 342 (unsigned)numdirs * sizeof(struct inoinfo *)); 343 goto badsb; 344 } 345 bufinit(); 346 return (1); 347 348 badsb: 349 ckfini(); 350 return (0); 351 } 352 353 /* 354 * Read in the super block and its summary info. 355 */ 356 readsb(listerr) 357 int listerr; 358 { 359 daddr_t super = bflag ? bflag : SBOFF / dev_bsize; 360 361 if (bread(fsreadfd, (char *)&sblock, super, (long)SBSIZE) != 0) 362 return (0); 363 sblk.b_bno = super; 364 sblk.b_size = SBSIZE; 365 /* 366 * run a few consistency checks of the super block 367 */ 368 if (sblock.fs_magic != FS_MAGIC) 369 { badsb(listerr, "MAGIC NUMBER WRONG"); return (0); } 370 if (sblock.fs_ncg < 1) 371 { badsb(listerr, "NCG OUT OF RANGE"); return (0); } 372 if (sblock.fs_cpg < 1) 373 { badsb(listerr, "CPG OUT OF RANGE"); return (0); } 374 if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl || 375 (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) 376 { badsb(listerr, "NCYL LESS THAN NCG*CPG"); return (0); } 377 if (sblock.fs_sbsize > SBSIZE) 378 { badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); } 379 /* 380 * Compute block size that the filesystem is based on, 381 * according to fsbtodb, and adjust superblock block number 382 * so we can tell if this is an alternate later. 383 */ 384 super *= dev_bsize; 385 dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 386 sblk.b_bno = super / dev_bsize; 387 /* 388 * Set all possible fields that could differ, then do check 389 * of whole super block against an alternate super block. 390 * When an alternate super-block is specified this check is skipped. 391 */ 392 getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize); 393 if (asblk.b_errs) 394 return (0); 395 if (bflag) { 396 havesb = 1; 397 return (1); 398 } 399 altsblock.fs_link = sblock.fs_link; 400 altsblock.fs_rlink = sblock.fs_rlink; 401 altsblock.fs_time = sblock.fs_time; 402 altsblock.fs_cstotal = sblock.fs_cstotal; 403 altsblock.fs_cgrotor = sblock.fs_cgrotor; 404 altsblock.fs_fmod = sblock.fs_fmod; 405 altsblock.fs_clean = sblock.fs_clean; 406 altsblock.fs_state = sblock.fs_state; 407 altsblock.fs_ronly = sblock.fs_ronly; 408 altsblock.fs_flags = sblock.fs_flags; 409 altsblock.fs_maxcontig = sblock.fs_maxcontig; 410 altsblock.fs_minfree = sblock.fs_minfree; 411 altsblock.fs_optim = sblock.fs_optim; 412 altsblock.fs_rotdelay = sblock.fs_rotdelay; 413 altsblock.fs_maxbpg = sblock.fs_maxbpg; 414 bcopy((char *)sblock.fs_csp, (char *)altsblock.fs_csp, 415 sizeof sblock.fs_csp); 416 bcopy((char *)sblock.fs_fsmnt, (char *)altsblock.fs_fsmnt, 417 sizeof sblock.fs_fsmnt); 418 bcopy((char *)sblock.fs_sparecon, (char *)altsblock.fs_sparecon, 419 sizeof sblock.fs_sparecon); 420 /* 421 * The following should not have to be copied. 422 */ 423 altsblock.fs_fsbtodb = sblock.fs_fsbtodb; 424 altsblock.fs_interleave = sblock.fs_interleave; 425 altsblock.fs_npsect = sblock.fs_npsect; 426 altsblock.fs_nrpos = sblock.fs_nrpos; 427 if (bcmp((char *)&sblock, (char *)&altsblock, (int)sblock.fs_sbsize)) { 428 badsb(listerr, 429 "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE"); 430 return (0); 431 } 432 havesb = 1; 433 return (1); 434 } 435 436 badsb(listerr, s) 437 int listerr; 438 char *s; 439 { 440 441 if (!listerr) 442 return; 443 if (preen) 444 printf("%s: ", devname); 445 pfatal("BAD SUPER BLOCK: %s\n", s); 446 } 447 448 /* 449 * Calculate a prototype superblock based on information in the disk label. 450 * When done the cgsblock macro can be calculated and the fs_ncg field 451 * can be used. Do NOT attempt to use other macros without verifying that 452 * their needed information is available! 453 */ 454 calcsb(dev, devfd, fs) 455 char *dev; 456 int devfd; 457 register struct fs *fs; 458 { 459 register struct disklabel *lp; 460 register struct partition *pp; 461 register char *cp; 462 int i; 463 464 cp = index(dev, '\0') - 1; 465 if (cp == (char *)-1 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp)) { 466 pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev); 467 return (0); 468 } 469 lp = getdisklabel(dev, devfd); 470 if (isdigit(*cp)) 471 pp = &lp->d_partitions[0]; 472 else 473 pp = &lp->d_partitions[*cp - 'a']; 474 if (pp->p_fstype != FS_BSDFFS) { 475 pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n", 476 dev, pp->p_fstype < FSMAXTYPES ? 477 fstypenames[pp->p_fstype] : "unknown"); 478 return (0); 479 } 480 bzero((char *)fs, sizeof(struct fs)); 481 fs->fs_fsize = pp->p_fsize; 482 fs->fs_frag = pp->p_frag; 483 fs->fs_cpg = pp->p_cpg; 484 fs->fs_size = pp->p_size; 485 fs->fs_ntrak = lp->d_ntracks; 486 fs->fs_nsect = lp->d_nsectors; 487 fs->fs_spc = lp->d_secpercyl; 488 fs->fs_nspf = fs->fs_fsize / lp->d_secsize; 489 fs->fs_sblkno = roundup( 490 howmany(lp->d_bbsize + lp->d_sbsize, fs->fs_fsize), 491 fs->fs_frag); 492 fs->fs_cgmask = 0xffffffff; 493 for (i = fs->fs_ntrak; i > 1; i >>= 1) 494 fs->fs_cgmask <<= 1; 495 if (!POWEROF2(fs->fs_ntrak)) 496 fs->fs_cgmask <<= 1; 497 fs->fs_cgoffset = roundup( 498 howmany(fs->fs_nsect, NSPF(fs)), fs->fs_frag); 499 fs->fs_fpg = (fs->fs_cpg * fs->fs_spc) / NSPF(fs); 500 fs->fs_ncg = howmany(fs->fs_size / fs->fs_spc, fs->fs_cpg); 501 for (fs->fs_fsbtodb = 0, i = NSPF(fs); i > 1; i >>= 1) 502 fs->fs_fsbtodb++; 503 dev_bsize = lp->d_secsize; 504 return (1); 505 } 506 507 struct disklabel * 508 getdisklabel(s, fd) 509 char *s; 510 int fd; 511 { 512 static struct disklabel lab; 513 514 if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) { 515 if (s == NULL) 516 return ((struct disklabel *)NULL); 517 pwarn("ioctl (GCINFO): %s\n", strerror(errno)); 518 errexit("%s: can't read disk label\n", s); 519 } 520 return (&lab); 521 } 522 523 char * 524 getmntdev(name) 525 char *name; 526 { 527 long mntsize; 528 register long i; 529 struct statfs *mntbuf; 530 531 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 532 for (i = 0; i < mntsize; i++) { 533 if (!strncmp(mntbuf[i].f_fstypename, MOUNT_UFS, MFSNAMELEN) && 534 !strcmp(mntbuf[i].f_mntonname, name)) 535 return (mntbuf[i].f_mntfromname); 536 } 537 return ((char *)0); 538 } 539