1 /* $NetBSD: setup.c,v 1.26 2005/09/13 04:14:17 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Konrad E. Schroder <perseant@hhhh.org>. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 /* 39 * Copyright (c) 1980, 1986, 1993 40 * The Regents of the University of California. All rights reserved. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. Neither the name of the University nor the names of its contributors 51 * may be used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64 * SUCH DAMAGE. 65 */ 66 67 /* #define DKTYPENAMES */ 68 #define FSTYPENAMES 69 #include <sys/types.h> 70 #include <sys/param.h> 71 #include <sys/time.h> 72 #include <sys/buf.h> 73 #include <sys/mount.h> 74 #include <sys/queue.h> 75 #include <sys/stat.h> 76 #include <sys/ioctl.h> 77 #include <sys/disklabel.h> 78 #include <sys/file.h> 79 80 #include <ufs/ufs/inode.h> 81 #include <ufs/ufs/ufsmount.h> 82 #define vnode uvnode 83 #include <ufs/lfs/lfs.h> 84 #undef vnode 85 86 #include <ctype.h> 87 #include <err.h> 88 #include <errno.h> 89 #include <stdio.h> 90 #include <stdlib.h> 91 #include <string.h> 92 93 #include "bufcache.h" 94 #include "vnode.h" 95 #include "lfs_user.h" 96 97 #include "fsck.h" 98 #include "extern.h" 99 #include "fsutil.h" 100 101 static struct disklabel *getdisklabel(const char *, int); 102 static uint64_t calcmaxfilesize(int); 103 104 ufs_daddr_t *din_table; 105 SEGUSE *seg_table; 106 107 #ifdef DKTYPENAMES 108 int useless(void); 109 110 int 111 useless(void) 112 { 113 char **foo = (char **) dktypenames; 114 char **bar = (char **) fscknames; 115 116 return foo - bar; 117 } 118 #endif 119 120 /* 121 * calculate the maximum file size allowed with the specified block shift. 122 */ 123 static uint64_t 124 calcmaxfilesize(int bshift) 125 { 126 uint64_t nptr; /* number of block pointers per block */ 127 uint64_t maxblock; 128 129 nptr = (1 << bshift) / sizeof(uint32_t); 130 maxblock = NDADDR + nptr + nptr * nptr + nptr * nptr * nptr; 131 132 return maxblock << bshift; 133 } 134 135 void 136 reset_maxino(ino_t len) 137 { 138 din_table = (ufs_daddr_t *) realloc(din_table, len * sizeof(*din_table)); 139 statemap = realloc(statemap, len * sizeof(char)); 140 typemap = realloc(typemap, len * sizeof(char)); 141 lncntp = (int16_t *) realloc(lncntp, len * sizeof(int16_t)); 142 143 if (din_table == NULL || statemap == NULL || typemap == NULL || 144 lncntp == NULL) { 145 errexit("expanding tables failed: out of memory"); 146 } 147 148 memset(din_table + maxino, 0, (len - maxino) * sizeof(*din_table)); 149 memset(statemap + maxino, 0, (len - maxino) * sizeof(char)); 150 memset(typemap + maxino, 0, (len - maxino) * sizeof(char)); 151 memset(lncntp + maxino, 0, (len - maxino) * sizeof(int16_t)); 152 153 maxino = len; 154 155 return; 156 } 157 158 int 159 setup(const char *dev) 160 { 161 long bmapsize; 162 struct disklabel *lp; 163 struct stat statb; 164 int doskipclean; 165 u_int64_t maxfilesize; 166 int open_flags; 167 struct uvnode *ivp; 168 struct ubuf *bp; 169 int i; 170 SEGUSE *sup; 171 172 havesb = 0; 173 doskipclean = skipclean; 174 if (stat(dev, &statb) < 0) { 175 printf("Can't stat %s: %s\n", dev, strerror(errno)); 176 return (0); 177 } 178 if (!S_ISCHR(statb.st_mode)) { 179 pfatal("%s is not a character device", dev); 180 if (reply("CONTINUE") == 0) 181 return (0); 182 } 183 if (nflag) 184 open_flags = O_RDONLY; 185 else 186 open_flags = O_RDWR; 187 188 if ((fsreadfd = open(dev, open_flags)) < 0) { 189 printf("Can't open %s: %s\n", dev, strerror(errno)); 190 return (0); 191 } 192 if (nflag) { 193 if (preen) 194 pfatal("NO WRITE ACCESS"); 195 printf("** %s (NO WRITE)\n", dev); 196 quiet = 0; 197 } else if (!preen && !quiet) 198 printf("** %s\n", dev); 199 200 fsmodified = 0; 201 lfdir = 0; 202 203 bufinit(0); /* XXX we could make a better guess */ 204 fs = lfs_init(fsreadfd, bflag, idaddr, 0, debug); 205 if (fs == NULL) { 206 if (preen) 207 printf("%s: ", cdevname()); 208 pfatal("BAD SUPER BLOCK\n"); 209 } 210 if ((lp = getdisklabel((char *) NULL, fsreadfd)) != NULL) 211 dev_bsize = secsize = lp->d_secsize; 212 else 213 dev_bsize = secsize = DEV_BSIZE; 214 215 /* Resize buffer cache now that we have a superblock to guess from. */ 216 bufrehash((fs->lfs_segtabsz + maxino / fs->lfs_ifpb) << 4); 217 218 if (fs->lfs_pflags & LFS_PF_CLEAN) { 219 if (doskipclean) { 220 if (!quiet) 221 pwarn("%sile system is clean; not checking\n", 222 preen ? "f" : "** F"); 223 return (-1); 224 } 225 if (!preen) 226 pwarn("** File system is already clean\n"); 227 } 228 229 if (debug) { 230 printf("idaddr = 0x%lx\n", idaddr ? (unsigned long)idaddr : 231 (unsigned long)fs->lfs_idaddr); 232 printf("dev_bsize = %lu\n", dev_bsize); 233 printf("lfs_bsize = %lu\n", (unsigned long) fs->lfs_bsize); 234 printf("lfs_fsize = %lu\n", (unsigned long) fs->lfs_fsize); 235 printf("lfs_frag = %lu\n", (unsigned long) fs->lfs_frag); 236 printf("lfs_inopb = %lu\n", (unsigned long) fs->lfs_inopb); 237 } 238 if (fs->lfs_version == 1) 239 maxfsblock = fs->lfs_size * (fs->lfs_bsize / dev_bsize); 240 else 241 maxfsblock = fs->lfs_size; 242 maxfilesize = calcmaxfilesize(fs->lfs_bshift); 243 if ((fs->lfs_minfree < 0 || fs->lfs_minfree > 99)) { 244 pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 245 fs->lfs_minfree); 246 if (reply("SET TO DEFAULT") == 1) { 247 fs->lfs_minfree = 10; 248 sbdirty(); 249 } 250 } 251 if (fs->lfs_bmask != fs->lfs_bsize - 1) { 252 pwarn("INCORRECT BMASK=%x IN SUPERBLOCK (should be %x)", 253 (unsigned int) fs->lfs_bmask, 254 (unsigned int) fs->lfs_bsize - 1); 255 fs->lfs_bmask = fs->lfs_bsize - 1; 256 if (preen) 257 printf(" (FIXED)\n"); 258 if (preen || reply("FIX") == 1) { 259 sbdirty(); 260 } 261 } 262 if (fs->lfs_ffmask != fs->lfs_fsize - 1) { 263 pwarn("INCORRECT FFMASK=%" PRId64 " IN SUPERBLOCK", 264 fs->lfs_ffmask); 265 fs->lfs_ffmask = fs->lfs_fsize - 1; 266 if (preen) 267 printf(" (FIXED)\n"); 268 if (preen || reply("FIX") == 1) { 269 sbdirty(); 270 } 271 } 272 if (fs->lfs_fbmask != (1 << fs->lfs_fbshift) - 1) { 273 pwarn("INCORRECT FFMASK=%" PRId64 " IN SUPERBLOCK", 274 fs->lfs_ffmask); 275 fs->lfs_fbmask = (1 << fs->lfs_fbshift) - 1; 276 if (preen) 277 printf(" (FIXED)\n"); 278 if (preen || reply("FIX") == 1) { 279 sbdirty(); 280 } 281 } 282 if (fs->lfs_maxfilesize != maxfilesize) { 283 pwarn( 284 "INCORRECT MAXFILESIZE=%llu IN SUPERBLOCK (should be %llu with bshift %d)", 285 (unsigned long long) fs->lfs_maxfilesize, 286 (unsigned long long) maxfilesize, (int)fs->lfs_bshift); 287 if (preen) 288 printf(" (FIXED)\n"); 289 if (preen || reply("FIX") == 1) { 290 fs->lfs_maxfilesize = maxfilesize; 291 sbdirty(); 292 } 293 } 294 if (fs->lfs_maxsymlinklen != MAXSYMLINKLEN_UFS1) { 295 pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK", 296 fs->lfs_maxsymlinklen); 297 fs->lfs_maxsymlinklen = MAXSYMLINKLEN_UFS1; 298 if (preen) 299 printf(" (FIXED)\n"); 300 if (preen || reply("FIX") == 1) { 301 sbdirty(); 302 } 303 } 304 305 /* 306 * Read in the Ifile; we'll be using it a lot. 307 * XXX If the Ifile is corrupted we are in bad shape. We need to 308 * XXX run through the segment headers of the entire disk to 309 * XXX reconstruct the inode table, then pretend all segments are 310 * XXX dirty while we do the rest. 311 */ 312 ivp = fs->lfs_ivnode; 313 maxino = ((VTOI(ivp)->i_ffs1_size - (fs->lfs_cleansz + fs->lfs_segtabsz) 314 * fs->lfs_bsize) / fs->lfs_bsize) * fs->lfs_ifpb; 315 if (debug) 316 printf("maxino = %llu\n", (unsigned long long)maxino); 317 for (i = 0; i < VTOI(ivp)->i_ffs1_size; i += fs->lfs_bsize) { 318 bread(ivp, i >> fs->lfs_bshift, fs->lfs_bsize, NOCRED, &bp); 319 /* XXX check B_ERROR */ 320 brelse(bp); 321 } 322 323 /* 324 * allocate and initialize the necessary maps 325 */ 326 din_table = (ufs_daddr_t *) malloc(maxino * sizeof(*din_table)); 327 if (din_table == NULL) { 328 printf("cannot alloc %lu bytes for din_table\n", 329 (unsigned long) maxino * sizeof(*din_table)); 330 goto badsblabel; 331 } 332 memset(din_table, 0, maxino * sizeof(*din_table)); 333 seg_table = (SEGUSE *) malloc(fs->lfs_nseg * sizeof(SEGUSE)); 334 if (seg_table == NULL) { 335 printf("cannot alloc %lu bytes for seg_table\n", 336 (unsigned long) fs->lfs_nseg * sizeof(SEGUSE)); 337 goto badsblabel; 338 } 339 memset(seg_table, 0, fs->lfs_nseg * sizeof(SEGUSE)); 340 /* Get segment flags */ 341 for (i = 0; i < fs->lfs_nseg; i++) { 342 LFS_SEGENTRY(sup, fs, i, bp); 343 seg_table[i].su_flags = sup->su_flags & ~SEGUSE_ACTIVE; 344 if (preen) 345 seg_table[i].su_nbytes = sup->su_nbytes; 346 brelse(bp); 347 } 348 349 /* Initialize Ifile entry */ 350 din_table[fs->lfs_ifile] = fs->lfs_idaddr; 351 seg_table[dtosn(fs, fs->lfs_idaddr)].su_nbytes += DINODE1_SIZE; 352 353 #ifndef VERBOSE_BLOCKMAP 354 bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); 355 blockmap = calloc((unsigned) bmapsize, sizeof(char)); 356 #else 357 bmapsize = maxfsblock * sizeof(ino_t); 358 blockmap = (ino_t *) calloc(maxfsblock, sizeof(ino_t)); 359 #endif 360 if (blockmap == NULL) { 361 printf("cannot alloc %u bytes for blockmap\n", 362 (unsigned) bmapsize); 363 goto badsblabel; 364 } 365 statemap = calloc((unsigned) maxino, sizeof(char)); 366 if (statemap == NULL) { 367 printf("cannot alloc %u bytes for statemap\n", 368 (unsigned) maxino); 369 goto badsblabel; 370 } 371 typemap = calloc((unsigned) maxino, sizeof(char)); 372 if (typemap == NULL) { 373 printf("cannot alloc %u bytes for typemap\n", 374 (unsigned) maxino); 375 goto badsblabel; 376 } 377 lncntp = (int16_t *) calloc((unsigned) maxino, sizeof(int16_t)); 378 if (lncntp == NULL) { 379 printf("cannot alloc %lu bytes for lncntp\n", 380 (unsigned long) maxino * sizeof(int16_t)); 381 goto badsblabel; 382 } 383 384 if (preen) { 385 n_files = fs->lfs_nfiles; 386 n_blks = fs->lfs_dsize - fs->lfs_bfree; 387 numdirs = maxino; 388 inplast = 0; 389 listmax = numdirs + 10; 390 inpsort = (struct inoinfo **) calloc((unsigned) listmax, 391 sizeof(struct inoinfo *)); 392 inphead = (struct inoinfo **) calloc((unsigned) numdirs, 393 sizeof(struct inoinfo *)); 394 if (inpsort == NULL || inphead == NULL) { 395 printf("cannot alloc %lu bytes for inphead\n", 396 (unsigned long) numdirs * sizeof(struct inoinfo *)); 397 exit(1); 398 } 399 } 400 401 return (1); 402 403 badsblabel: 404 ckfini(0); 405 return (0); 406 } 407 408 static struct disklabel * 409 getdisklabel(const char *s, int fd) 410 { 411 static struct disklabel lab; 412 413 if (ioctl(fd, DIOCGDINFO, (char *) &lab) < 0) { 414 if (s == NULL) 415 return ((struct disklabel *) NULL); 416 pwarn("ioctl (GCINFO): %s\n", strerror(errno)); 417 return NULL; 418 } 419 return (&lab); 420 } 421