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