setup.c revision 1.4
1/* $OpenBSD: setup.c,v 1.4 1997/06/14 05:04:12 downsj Exp $ */ 2/* $NetBSD: setup.c,v 1.1 1997/06/11 11:22:01 bouyer Exp $ */ 3 4/* 5 * Copyright (c) 1997 Manuel Bouyer. 6 * Copyright (c) 1980, 1986, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38#ifndef lint 39#if 0 40static char sccsid[] = "@(#)setup.c 8.5 (Berkeley) 11/23/94"; 41#else 42#if 0 43static char rcsid[] = "$NetBSD: setup.c,v 1.1 1997/06/11 11:22:01 bouyer Exp $"; 44#else 45static char rcsid[] = "$OpenBSD: setup.c,v 1.4 1997/06/14 05:04:12 downsj Exp $"; 46#endif 47#endif 48#endif /* not lint */ 49 50#define DKTYPENAMES 51#include <sys/param.h> 52#include <sys/time.h> 53#include <ufs/ext2fs/ext2fs_dinode.h> 54#include <ufs/ext2fs/ext2fs.h> 55#include <sys/stat.h> 56#include <sys/ioctl.h> 57#include <sys/disklabel.h> 58#include <sys/file.h> 59 60#include <errno.h> 61#include <stdio.h> 62#include <stdlib.h> 63#include <string.h> 64#include <ctype.h> 65 66#include "fsck.h" 67#include "extern.h" 68#include "fsutil.h" 69 70struct bufarea asblk; 71#define altsblock (*asblk.b_un.b_fs) 72#define POWEROF2(num) (((num) & ((num) - 1)) == 0) 73 74void badsb __P((int, char *)); 75/* int calcsb __P((char *, int, struct m_ext2fs *)); */ 76static struct disklabel *getdisklabel __P((char *, int)); 77static int readsb __P((int)); 78 79int 80setup(dev) 81 char *dev; 82{ 83 long cg, size, asked, i, j; 84 long bmapsize; 85 struct disklabel *lp; 86 off_t sizepb; 87 struct stat statb; 88 struct m_ext2fs proto; 89 int doskipclean; 90 u_int64_t maxfilesize; 91 92 havesb = 0; 93 fswritefd = -1; 94 doskipclean = skipclean; 95 if (stat(dev, &statb) < 0) { 96 printf("Can't stat %s: %s\n", dev, strerror(errno)); 97 return (0); 98 } 99 if (!S_ISCHR(statb.st_mode)) { 100 pfatal("%s is not a character device", dev); 101 if (reply("CONTINUE") == 0) 102 return (0); 103 } 104 if ((fsreadfd = open(dev, O_RDONLY)) < 0) { 105 printf("Can't open %s: %s\n", dev, strerror(errno)); 106 return (0); 107 } 108 if (preen == 0) 109 printf("** %s", dev); 110 if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) { 111 fswritefd = -1; 112 if (preen) 113 pfatal("NO WRITE ACCESS"); 114 printf(" (NO WRITE)"); 115 } 116 if (preen == 0) 117 printf("\n"); 118 fsmodified = 0; 119 lfdir = 0; 120 initbarea(&sblk); 121 initbarea(&asblk); 122 sblk.b_un.b_buf = malloc(sizeof(struct m_ext2fs)); 123 asblk.b_un.b_buf = malloc(sizeof(struct m_ext2fs)); 124 if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) 125 errexit("cannot allocate space for superblock\n"); 126 if ((lp = getdisklabel((char *)NULL, fsreadfd)) != NULL) 127 dev_bsize = secsize = lp->d_secsize; 128 else 129 dev_bsize = secsize = DEV_BSIZE; 130 /* 131 * Read in the superblock, looking for alternates if necessary 132 */ 133 if (readsb(1) == 0) { 134 if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0) 135 return(0); 136 if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) 137 return (0); 138 for (cg = 1; cg < proto.e2fs_ncg; cg++) { 139 bflag = fsbtodb(&proto, 140 cg * proto.e2fs.e2fs_bpg + proto.e2fs.e2fs_first_dblock); 141 if (readsb(0) != 0) 142 break; 143 } 144 if (cg >= proto.e2fs_ncg) { 145 printf("%s %s\n%s %s\n%s %s\n", 146 "SEARCH FOR ALTERNATE SUPER-BLOCK", 147 "FAILED. YOU MUST USE THE", 148 "-b OPTION TO FSCK_FFS TO SPECIFY THE", 149 "LOCATION OF AN ALTERNATE", 150 "SUPER-BLOCK TO SUPPLY NEEDED", 151 "INFORMATION; SEE fsck_ext2fs(8)."); 152 return(0); 153 } 154 doskipclean = 0; 155 pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); 156 } 157 if (debug) 158 printf("state = %d\n", sblock.e2fs.e2fs_state); 159 if (sblock.e2fs.e2fs_state == E2FS_ISCLEAN) { 160 if (doskipclean) { 161 pwarn("%sile system is clean; not checking\n", 162 preen ? "f" : "** F"); 163 return (-1); 164 } 165 if (!preen) 166 pwarn("** File system is already clean\n"); 167 } 168 maxfsblock = sblock.e2fs.e2fs_bcount; 169 maxino = sblock.e2fs_ncg * sblock.e2fs.e2fs_ipg; 170 sizepb = sblock.e2fs_bsize; 171 maxfilesize = sblock.e2fs_bsize * NDADDR - 1; 172 for (i = 0; i < NIADDR; i++) { 173 sizepb *= NINDIR(&sblock); 174 maxfilesize += sizepb; 175 } 176 /* 177 * Check and potentially fix certain fields in the super block. 178 */ 179 if ((sblock.e2fs.e2fs_rbcount < 0) || 180 (sblock.e2fs.e2fs_rbcount > sblock.e2fs.e2fs_bcount)) { 181 pfatal("IMPOSSIBLE RESERVED BLOCK COUNT=%d IN SUPERBLOCK", 182 sblock.e2fs.e2fs_rbcount); 183 if (reply("SET TO DEFAULT") == 1) { 184 sblock.e2fs.e2fs_rbcount = sblock.e2fs.e2fs_bcount * 0.1; 185 sbdirty(); 186 } 187 } 188 if (sblock.e2fs.e2fs_bpg != sblock.e2fs.e2fs_fpg) { 189 pfatal("WRONG FPG=%d (BPG=%d) IN SUPERBLOCK", 190 sblock.e2fs.e2fs_fpg, sblock.e2fs.e2fs_bpg); 191 return 0; 192 } 193 if (asblk.b_dirty && !bflag) { 194 memcpy(&altsblock, &sblock, (size_t)SBSIZE); 195 flush(fswritefd, &asblk); 196 } 197 /* 198 * read in the summary info. 199 */ 200 201 sblock.e2fs_gd = malloc(sblock.e2fs_ngdb * sblock.e2fs_bsize); 202 asked = 0; 203 for (i=0; i < sblock.e2fs_ngdb; i++) { 204 if (bread(fsreadfd,(char *) 205 &sblock.e2fs_gd[i* sblock.e2fs_bsize / sizeof(struct ext2_gd)], 206 fsbtodb(&sblock, ((sblock.e2fs_bsize>1024)?0:1)+i+1), 207 sblock.e2fs_bsize) != 0 && !asked) { 208 pfatal("BAD SUMMARY INFORMATION"); 209 if (reply("CONTINUE") == 0) 210 errexit("%s\n", ""); 211 asked++; 212 } 213 } 214 /* 215 * allocate and initialize the necessary maps 216 */ 217 bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); 218 blockmap = calloc((unsigned)bmapsize, sizeof (char)); 219 if (blockmap == NULL) { 220 printf("cannot alloc %u bytes for blockmap\n", 221 (unsigned)bmapsize); 222 goto badsblabel; 223 } 224 statemap = calloc((unsigned)(maxino + 2), sizeof(char)); 225 if (statemap == NULL) { 226 printf("cannot alloc %u bytes for statemap\n", 227 (unsigned)(maxino + 1)); 228 goto badsblabel; 229 } 230 lncntp = (int16_t *)calloc((unsigned)(maxino + 1), sizeof(int16_t)); 231 if (lncntp == NULL) { 232 printf("cannot alloc %u bytes for lncntp\n", 233 (unsigned)(maxino + 1) * sizeof(int16_t)); 234 goto badsblabel; 235 } 236 for (numdirs = 0, cg = 0; cg < sblock.e2fs_ncg; cg++) { 237 numdirs += sblock.e2fs_gd[cg].ext2bgd_ndirs; 238 } 239 inplast = 0; 240 listmax = numdirs + 10; 241 inpsort = (struct inoinfo **)calloc((unsigned)listmax, 242 sizeof(struct inoinfo *)); 243 inphead = (struct inoinfo **)calloc((unsigned)numdirs, 244 sizeof(struct inoinfo *)); 245 if (inpsort == NULL || inphead == NULL) { 246 printf("cannot alloc %u bytes for inphead\n", 247 (unsigned)numdirs * sizeof(struct inoinfo *)); 248 goto badsblabel; 249 } 250 bufinit(); 251 return (1); 252 253badsblabel: 254 ckfini(0); 255 return (0); 256} 257 258/* 259 * Read in the super block and its summary info. 260 */ 261static int 262readsb(listerr) 263 int listerr; 264{ 265 daddr_t super = bflag ? bflag : SBOFF / dev_bsize; 266 267 if (bread(fsreadfd, (char *)&sblock.e2fs, super, (long)SBSIZE) != 0) 268 return (0); 269 sblk.b_bno = super; 270 sblk.b_size = SBSIZE; 271 /* 272 * run a few consistency checks of the super block 273 */ 274 if (sblock.e2fs.e2fs_magic != E2FS_MAGIC) { 275 badsb(listerr, "MAGIC NUMBER WRONG"); return (0); 276 } 277 if (sblock.e2fs.e2fs_log_bsize > 2) { 278 badsb(listerr, "BAD LOG_BSIZE"); return (0); 279 } 280 281 /* compute the dynamic fields of the in-memory sb */ 282 /* compute dynamic sb infos */ 283 sblock.e2fs_ncg = 284 howmany(sblock.e2fs.e2fs_bcount - sblock.e2fs.e2fs_first_dblock, 285 sblock.e2fs.e2fs_bpg); 286 /* XXX assume hw bsize = 512 */ 287 sblock.e2fs_fsbtodb = sblock.e2fs.e2fs_log_bsize + 1; 288 sblock.e2fs_bsize = 1024 << sblock.e2fs.e2fs_log_bsize; 289 sblock.e2fs_bshift = LOG_MINBSIZE + sblock.e2fs.e2fs_log_bsize; 290 sblock.e2fs_qbmask = sblock.e2fs_bsize - 1; 291 sblock.e2fs_bmask = ~sblock.e2fs_qbmask; 292 sblock.e2fs_ngdb = howmany(sblock.e2fs_ncg, 293 sblock.e2fs_bsize / sizeof(struct ext2_gd)); 294 sblock.e2fs_ipb = sblock.e2fs_bsize / sizeof(struct ext2fs_dinode); 295 sblock.e2fs_itpg = sblock.e2fs.e2fs_ipg/sblock.e2fs_ipb; 296 297 cgoverhead = 1 /* super block */ + 298 sblock.e2fs_ngdb + 299 1 /* block bitmap */ + 300 1 /* inode bitmap */ + 301 sblock.e2fs_itpg; 302 303 if (debug) /* DDD */ 304 printf("cg overhead %d blocks \n", cgoverhead); 305 /* 306 * Compute block size that the filesystem is based on, 307 * according to fsbtodb, and adjust superblock block number 308 * so we can tell if this is an alternate later. 309 */ 310 super *= dev_bsize; 311 dev_bsize = sblock.e2fs_bsize / fsbtodb(&sblock, 1); 312 sblk.b_bno = super / dev_bsize; 313 if (bflag) { 314 havesb = 1; 315 return (1); 316 } 317 318 /* 319 * Set all possible fields that could differ, then do check 320 * of whole super block against an alternate super block. 321 * When an alternate super-block is specified this check is skipped. 322 */ 323 getblk(&asblk, 1 * sblock.e2fs.e2fs_bpg + sblock.e2fs.e2fs_first_dblock, 324 (long)SBSIZE); 325 if (asblk.b_errs) 326 return (0); 327 altsblock.e2fs.e2fs_rbcount = sblock.e2fs.e2fs_rbcount; 328 altsblock.e2fs.e2fs_fbcount = sblock.e2fs.e2fs_fbcount; 329 altsblock.e2fs.e2fs_ficount = sblock.e2fs.e2fs_ficount; 330 altsblock.e2fs.e2fs_mtime = sblock.e2fs.e2fs_mtime; 331 altsblock.e2fs.e2fs_wtime = sblock.e2fs.e2fs_wtime; 332 altsblock.e2fs.e2fs_mnt_count = sblock.e2fs.e2fs_mnt_count; 333 altsblock.e2fs.e2fs_max_mnt_count = sblock.e2fs.e2fs_max_mnt_count; 334 altsblock.e2fs.e2fs_state = sblock.e2fs.e2fs_state; 335 altsblock.e2fs.e2fs_beh = sblock.e2fs.e2fs_beh; 336 altsblock.e2fs.e2fs_lastfsck = sblock.e2fs.e2fs_lastfsck; 337 altsblock.e2fs.e2fs_fsckintv = sblock.e2fs.e2fs_fsckintv; 338 altsblock.e2fs.e2fs_ruid = sblock.e2fs.e2fs_ruid; 339 altsblock.e2fs.e2fs_rgid = sblock.e2fs.e2fs_rgid; 340 if (memcmp(&(sblock.e2fs), &(altsblock.e2fs), (int)SBSIZE)) { 341 if (debug) { 342 long *nlp, *olp, *endlp; 343 344 printf("superblock mismatches\n"); 345 nlp = (long *)&altsblock; 346 olp = (long *)&sblock; 347 endlp = olp + (SBSIZE / sizeof *olp); 348 for ( ; olp < endlp; olp++, nlp++) { 349 if (*olp == *nlp) 350 continue; 351 printf("offset %d, original %ld, alternate %ld\n", 352 olp - (long *)&sblock, *olp, *nlp); 353 } 354 } 355 badsb(listerr, 356 "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE"); 357 return (0); 358 } 359 havesb = 1; 360 return (1); 361} 362 363void 364badsb(listerr, s) 365 int listerr; 366 char *s; 367{ 368 369 if (!listerr) 370 return; 371 if (preen) 372 printf("%s: ", cdevname()); 373 pfatal("BAD SUPER BLOCK: %s\n", s); 374} 375 376/* 377 * Calculate a prototype superblock based on information in the disk label. 378 * When done the cgsblock macro can be calculated and the fs_ncg field 379 * can be used. Do NOT attempt to use other macros without verifying that 380 * their needed information is available! 381 */ 382 383int 384calcsb(dev, devfd, fs) 385 char *dev; 386 int devfd; 387 register struct m_ext2fs *fs; 388{ 389 register struct disklabel *lp; 390 register struct partition *pp; 391 register char *cp; 392 int i; 393 394 cp = strchr(dev, '\0') - 1; 395 if ((cp == (char *)-1 || (*cp < 'a' || *cp > 'h')) && !isdigit(*cp)) { 396 pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev); 397 return (0); 398 } 399 lp = getdisklabel(dev, devfd); 400 if (isdigit(*cp)) 401 pp = &lp->d_partitions[0]; 402 else 403 pp = &lp->d_partitions[*cp - 'a']; 404 if (pp->p_fstype != FS_BSDFFS) { 405 pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n", 406 dev, pp->p_fstype < FSMAXTYPES ? 407 fstypenames[pp->p_fstype] : "unknown"); 408 return (0); 409 } 410 memset(fs, 0, sizeof(struct m_ext2fs)); 411 fs->e2fs_bsize = 1024; /* XXX to look for altenate SP */ 412 fs->e2fs.e2fs_log_bsize = 0; 413 fs->e2fs.e2fs_bcount = (pp->p_size * DEV_BSIZE) / fs->e2fs_bsize; 414 fs->e2fs.e2fs_first_dblock = 1; 415 fs->e2fs.e2fs_bpg = fs->e2fs_bsize * NBBY; 416 fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize; 417 fs->e2fs_qbmask = fs->e2fs_bsize - 1; 418 fs->e2fs_bmask = ~fs->e2fs_qbmask; 419 fs->e2fs_ncg = 420 howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock, 421 fs->e2fs.e2fs_bpg); 422 fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1; 423 fs->e2fs_ngdb = howmany(fs->e2fs_ncg, 424 fs->e2fs_bsize / sizeof(struct ext2_gd)); 425 426 427 428 return (1); 429} 430 431static struct disklabel * 432getdisklabel(s, fd) 433 char *s; 434 int fd; 435{ 436 static struct disklabel lab; 437 438 if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) { 439 if (s == NULL) 440 return ((struct disklabel *)NULL); 441 pwarn("ioctl (GCINFO): %s\n", strerror(errno)); 442 errexit("%s: can't read disk label\n", s); 443 } 444 return (&lab); 445} 446