1 /* $NetBSD: setup.c,v 1.17 2003/08/07 10:04:24 agc 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.h" 96 97 #include "fsck.h" 98 #include "extern.h" 99 #include "fsutil.h" 100 101 #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 102 103 u_quad_t maxtable[] = { 104 /* 1 */ -1, 105 /* 2 */ -1, 106 /* 4 */ -1, 107 /* 8 */ -1, 108 /* 16 */ -1, 109 /* 32 */ -1, 110 /* 64 */ -1, 111 /* 128 */ -1, 112 /* 256 */ -1, 113 /* 512 */ NDADDR + 128 + 128 * 128 + 128 * 128 * 128, 114 /* 1024 */ NDADDR + 256 + 256 * 256 + 256 * 256 * 256, 115 /* 2048 */ NDADDR + 512 + 512 * 512 + 512 * 512 * 512, 116 /* 4096 */ NDADDR + 1024 + 1024 * 1024 + 1024 * 1024 * 1024, 117 /* 8192 */ 1 << 31, 118 /* 16 K */ 1 << 31, 119 /* 32 K */ 1 << 31, 120 }; 121 122 static struct disklabel *getdisklabel(const char *, int); 123 124 ufs_daddr_t *din_table; 125 SEGUSE *seg_table; 126 127 #ifdef DKTYPENAMES 128 int useless(void); 129 130 int 131 useless(void) 132 { 133 char **foo = (char **) dktypenames; 134 char **bar = (char **) fscknames; 135 136 return foo - bar; 137 } 138 #endif 139 140 int 141 setup(const char *dev) 142 { 143 long bmapsize; 144 struct disklabel *lp; 145 struct stat statb; 146 int doskipclean; 147 u_int64_t maxfilesize; 148 int open_flags; 149 struct uvnode *ivp; 150 struct ubuf *bp; 151 int i; 152 SEGUSE *sup; 153 154 havesb = 0; 155 doskipclean = skipclean; 156 if (stat(dev, &statb) < 0) { 157 printf("Can't stat %s: %s\n", dev, strerror(errno)); 158 return (0); 159 } 160 if (!S_ISCHR(statb.st_mode)) { 161 pfatal("%s is not a character device", dev); 162 if (reply("CONTINUE") == 0) 163 return (0); 164 } 165 if (nflag) 166 open_flags = O_RDONLY; 167 else 168 open_flags = O_RDWR; 169 170 if ((fsreadfd = open(dev, open_flags)) < 0) { 171 printf("Can't open %s: %s\n", dev, strerror(errno)); 172 return (0); 173 } 174 if (preen == 0) 175 printf("** %s", dev); 176 if (nflag) { 177 if (preen) 178 pfatal("NO WRITE ACCESS"); 179 printf(" (NO WRITE)"); 180 } 181 if (preen == 0) 182 printf("\n"); 183 fsmodified = 0; 184 lfdir = 0; 185 186 bufinit(); 187 fs = lfs_init(fsreadfd, bflag, idaddr, debug); 188 if (fs == NULL) { 189 if (preen) 190 printf("%s: ", cdevname()); 191 pfatal("BAD SUPER BLOCK\n"); 192 } 193 if ((lp = getdisklabel((char *) NULL, fsreadfd)) != NULL) 194 dev_bsize = secsize = lp->d_secsize; 195 else 196 dev_bsize = secsize = DEV_BSIZE; 197 198 #if 0 199 if (fs->lfs_pflags & LFS_PF_CLEAN) { 200 if (doskipclean) { 201 pwarn("%sile system is clean; not checking\n", 202 preen ? "f" : "** F"); 203 return (-1); 204 } 205 if (!preen) 206 pwarn("** File system is already clean\n"); 207 } 208 #endif 209 210 if (debug) { 211 printf("idaddr = 0x%lx\n", idaddr ? (unsigned long)idaddr : 212 (unsigned long)fs->lfs_idaddr); 213 printf("dev_bsize = %lu\n", dev_bsize); 214 printf("lfs_bsize = %lu\n", (unsigned long) fs->lfs_bsize); 215 printf("lfs_fsize = %lu\n", (unsigned long) fs->lfs_fsize); 216 printf("lfs_frag = %lu\n", (unsigned long) fs->lfs_frag); 217 printf("lfs_inopb = %lu\n", (unsigned long) fs->lfs_inopb); 218 } 219 if (fs->lfs_version == 1) 220 maxfsblock = fs->lfs_size * (fs->lfs_bsize / dev_bsize); 221 else 222 maxfsblock = fs->lfs_size; 223 maxfilesize = maxtable[fs->lfs_bshift] << fs->lfs_bshift; 224 if ((fs->lfs_minfree < 0 || fs->lfs_minfree > 99)) { 225 pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 226 fs->lfs_minfree); 227 if (reply("SET TO DEFAULT") == 1) { 228 fs->lfs_minfree = 10; 229 sbdirty(); 230 } 231 } 232 if (fs->lfs_bmask != fs->lfs_bsize - 1) { 233 pwarn("INCORRECT BMASK=%x IN SUPERBLOCK (should be %x)", 234 (unsigned int) fs->lfs_bmask, 235 (unsigned int) fs->lfs_bsize - 1); 236 fs->lfs_bmask = fs->lfs_bsize - 1; 237 if (preen) 238 printf(" (FIXED)\n"); 239 if (preen || reply("FIX") == 1) { 240 sbdirty(); 241 } 242 } 243 if (fs->lfs_ffmask != fs->lfs_fsize - 1) { 244 pwarn("INCORRECT FFMASK=%" PRId64 " IN SUPERBLOCK", 245 fs->lfs_ffmask); 246 fs->lfs_ffmask = fs->lfs_fsize - 1; 247 if (preen) 248 printf(" (FIXED)\n"); 249 if (preen || reply("FIX") == 1) { 250 sbdirty(); 251 } 252 } 253 if (fs->lfs_fbmask != (1 << fs->lfs_fbshift) - 1) { 254 pwarn("INCORRECT FFMASK=%" PRId64 " IN SUPERBLOCK", 255 fs->lfs_ffmask); 256 fs->lfs_fbmask = (1 << fs->lfs_fbshift) - 1; 257 if (preen) 258 printf(" (FIXED)\n"); 259 if (preen || reply("FIX") == 1) { 260 sbdirty(); 261 } 262 } 263 if (fs->lfs_maxfilesize != maxfilesize) { 264 pwarn( 265 "INCORRECT MAXFILESIZE=%llu IN SUPERBLOCK (should be %llu)", 266 (unsigned long long) fs->lfs_maxfilesize, 267 (unsigned long long) maxfilesize); 268 fs->lfs_maxfilesize = maxfilesize; 269 if (preen) 270 printf(" (FIXED)\n"); 271 if (preen || reply("FIX") == 1) { 272 sbdirty(); 273 } 274 } 275 if (fs->lfs_maxsymlinklen != MAXSYMLINKLEN_UFS1) { 276 pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK", 277 fs->lfs_maxsymlinklen); 278 fs->lfs_maxsymlinklen = MAXSYMLINKLEN_UFS1; 279 if (preen) 280 printf(" (FIXED)\n"); 281 if (preen || reply("FIX") == 1) { 282 sbdirty(); 283 } 284 } 285 286 /* 287 * Read in the Ifile; we'll be using it a lot. 288 * XXX If the Ifile is corrupted we are in bad shape. We need to 289 * XXX run through the segment headers of the entire disk to 290 * XXX reconstruct the inode table, then pretend all segments are 291 * XXX dirty while we do the rest. 292 */ 293 ivp = fs->lfs_ivnode; 294 maxino = ((VTOI(ivp)->i_ffs1_size - (fs->lfs_cleansz + fs->lfs_segtabsz) 295 * fs->lfs_bsize) / fs->lfs_bsize) * fs->lfs_ifpb; 296 if (debug) 297 printf("maxino = %d\n", maxino); 298 for (i = 0; i < VTOI(ivp)->i_ffs1_size; i += fs->lfs_bsize) { 299 bread(ivp, i >> fs->lfs_bshift, fs->lfs_bsize, NOCRED, &bp); 300 /* XXX check B_ERROR */ 301 brelse(bp); 302 } 303 304 /* 305 * allocate and initialize the necessary maps 306 */ 307 din_table = (ufs_daddr_t *) malloc(maxino * sizeof(*din_table)); 308 memset(din_table, 0, maxino * sizeof(*din_table)); 309 seg_table = (SEGUSE *) malloc(fs->lfs_nseg * sizeof(SEGUSE)); 310 memset(seg_table, 0, fs->lfs_nseg * sizeof(SEGUSE)); 311 /* Get segment flags */ 312 for (i = 0; i < fs->lfs_nseg; i++) { 313 LFS_SEGENTRY(sup, fs, i, bp); 314 seg_table[i].su_flags = sup->su_flags & ~SEGUSE_ACTIVE; 315 if (preen) 316 seg_table[i].su_nbytes = sup->su_nbytes; 317 brelse(bp); 318 } 319 320 /* Initialize Ifile entry */ 321 din_table[fs->lfs_ifile] = fs->lfs_idaddr; 322 seg_table[dtosn(fs, fs->lfs_idaddr)].su_nbytes += DINODE1_SIZE; 323 324 #ifndef VERBOSE_BLOCKMAP 325 bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); 326 blockmap = calloc((unsigned) bmapsize, sizeof(char)); 327 #else 328 bmapsize = maxfsblock * sizeof(ino_t); 329 blockmap = (ino_t *) calloc(maxfsblock, sizeof(ino_t)); 330 #endif 331 if (blockmap == NULL) { 332 printf("cannot alloc %u bytes for blockmap\n", 333 (unsigned) bmapsize); 334 goto badsblabel; 335 } 336 statemap = calloc((unsigned) maxino, sizeof(char)); 337 if (statemap == NULL) { 338 printf("cannot alloc %u bytes for statemap\n", 339 (unsigned) maxino); 340 goto badsblabel; 341 } 342 typemap = calloc((unsigned) maxino, sizeof(char)); 343 if (typemap == NULL) { 344 printf("cannot alloc %u bytes for typemap\n", 345 (unsigned) maxino); 346 goto badsblabel; 347 } 348 lncntp = (int16_t *) calloc((unsigned) maxino, sizeof(int16_t)); 349 if (lncntp == NULL) { 350 printf("cannot alloc %lu bytes for lncntp\n", 351 (unsigned long) maxino * sizeof(int16_t)); 352 goto badsblabel; 353 } 354 355 if (preen) { 356 n_files = fs->lfs_nfiles; 357 n_blks = fs->lfs_dsize - fs->lfs_bfree; 358 numdirs = maxino; 359 inplast = 0; 360 listmax = numdirs + 10; 361 inpsort = (struct inoinfo **) calloc((unsigned) listmax, 362 sizeof(struct inoinfo *)); 363 inphead = (struct inoinfo **) calloc((unsigned) numdirs, 364 sizeof(struct inoinfo *)); 365 if (inpsort == NULL || inphead == NULL) { 366 printf("cannot alloc %lu bytes for inphead\n", 367 (unsigned long) numdirs * sizeof(struct inoinfo *)); 368 exit(1); 369 } 370 } 371 372 return (1); 373 374 badsblabel: 375 ckfini(0); 376 return (0); 377 } 378 379 static struct disklabel * 380 getdisklabel(const char *s, int fd) 381 { 382 static struct disklabel lab; 383 384 if (ioctl(fd, DIOCGDINFO, (char *) &lab) < 0) { 385 if (s == NULL) 386 return ((struct disklabel *) NULL); 387 pwarn("ioctl (GCINFO): %s\n", strerror(errno)); 388 return NULL; 389 } 390 return (&lab); 391 } 392