1 /* $NetBSD: setup.c,v 1.33 2007/10/08 21:39:50 ad 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 #include <time.h> 93 #include <util.h> 94 95 #include "bufcache.h" 96 #include "vnode.h" 97 #include "lfs_user.h" 98 99 #include "fsck.h" 100 #include "extern.h" 101 #include "fsutil.h" 102 103 extern u_int32_t cksum(void *, size_t); 104 static struct disklabel *getdisklabel(const char *, int); 105 static uint64_t calcmaxfilesize(int); 106 107 ufs_daddr_t *din_table; 108 SEGUSE *seg_table; 109 110 #ifdef DKTYPENAMES 111 int useless(void); 112 113 int 114 useless(void) 115 { 116 char **foo = (char **) dktypenames; 117 char **bar = (char **) fscknames; 118 119 return foo - bar; 120 } 121 #endif 122 123 /* 124 * calculate the maximum file size allowed with the specified block shift. 125 */ 126 static uint64_t 127 calcmaxfilesize(int bshift) 128 { 129 uint64_t nptr; /* number of block pointers per block */ 130 uint64_t maxblock; 131 132 nptr = (1 << bshift) / sizeof(uint32_t); 133 maxblock = NDADDR + nptr + nptr * nptr + nptr * nptr * nptr; 134 135 return maxblock << bshift; 136 } 137 138 void 139 reset_maxino(ino_t len) 140 { 141 if (debug) 142 pwarn("maxino reset from %lld to %lld\n", (long long)maxino, 143 (long long)len); 144 145 din_table = erealloc(din_table, len * sizeof(*din_table)); 146 statemap = erealloc(statemap, len * sizeof(char)); 147 typemap = erealloc(typemap, len * sizeof(char)); 148 lncntp = erealloc(lncntp, len * sizeof(int16_t)); 149 150 memset(din_table + maxino, 0, (len - maxino) * sizeof(*din_table)); 151 memset(statemap + maxino, USTATE, (len - maxino) * sizeof(char)); 152 memset(typemap + maxino, 0, (len - maxino) * sizeof(char)); 153 memset(lncntp + maxino, 0, (len - maxino) * sizeof(int16_t)); 154 155 maxino = len; 156 157 /* 158 * We can't roll forward after allocating new inodes in previous 159 * phases, or thy would conflict (lost+found, for example, might 160 * disappear to be replaced by a file found in roll-forward). 161 */ 162 no_roll_forward = 1; 163 164 return; 165 } 166 167 extern time_t write_time; 168 169 int 170 setup(const char *dev) 171 { 172 long bmapsize; 173 struct disklabel *lp; 174 struct stat statb; 175 int doskipclean; 176 u_int64_t maxfilesize; 177 int open_flags; 178 struct uvnode *ivp; 179 struct ubuf *bp; 180 int i, isdirty; 181 long sn, curseg; 182 SEGUSE *sup; 183 184 havesb = 0; 185 doskipclean = skipclean; 186 if (stat(dev, &statb) < 0) { 187 pfatal("Can't stat %s: %s\n", dev, strerror(errno)); 188 return (0); 189 } 190 if (!S_ISCHR(statb.st_mode) && skipclean) { 191 pfatal("%s is not a character device", dev); 192 if (reply("CONTINUE") == 0) 193 return (0); 194 } 195 if (nflag) 196 open_flags = O_RDONLY; 197 else 198 open_flags = O_RDWR; 199 200 if ((fsreadfd = open(dev, open_flags)) < 0) { 201 pfatal("Can't open %s: %s\n", dev, strerror(errno)); 202 return (0); 203 } 204 if (nflag) { 205 if (preen) 206 pfatal("NO WRITE ACCESS"); 207 printf("** %s (NO WRITE)\n", dev); 208 quiet = 0; 209 } else if (!preen && !quiet) 210 printf("** %s\n", dev); 211 212 fsmodified = 0; 213 lfdir = 0; 214 215 /* Initialize time in case we have to write */ 216 time(&write_time); 217 218 bufinit(0); /* XXX we could make a better guess */ 219 fs = lfs_init(fsreadfd, bflag, idaddr, 0, debug); 220 if (fs == NULL) { 221 if (preen) 222 printf("%s: ", cdevname()); 223 errexit("BAD SUPER BLOCK OR IFILE INODE NOT FOUND\n"); 224 } 225 if ((lp = getdisklabel((char *) NULL, fsreadfd)) != NULL) 226 dev_bsize = secsize = lp->d_secsize; 227 else 228 dev_bsize = secsize = DEV_BSIZE; 229 230 /* Resize buffer cache now that we have a superblock to guess from. */ 231 bufrehash((fs->lfs_segtabsz + maxino / fs->lfs_ifpb) << 4); 232 233 if (fs->lfs_pflags & LFS_PF_CLEAN) { 234 if (doskipclean) { 235 if (!quiet) 236 pwarn("%sile system is clean; not checking\n", 237 preen ? "f" : "** F"); 238 return (-1); 239 } 240 if (!preen) 241 pwarn("** File system is already clean\n"); 242 } 243 244 if (idaddr) { 245 daddr_t tdaddr; 246 SEGSUM *sp; 247 FINFO *fp; 248 int bc; 249 250 if (debug) 251 pwarn("adjusting offset, serial for -i 0x%lx\n", 252 (unsigned long)idaddr); 253 tdaddr = sntod(fs, dtosn(fs, idaddr)); 254 if (sntod(fs, dtosn(fs, tdaddr)) == tdaddr) { 255 if (tdaddr == fs->lfs_start) 256 tdaddr += btofsb(fs, LFS_LABELPAD); 257 for (i = 0; i < LFS_MAXNUMSB; i++) { 258 if (fs->lfs_sboffs[i] == tdaddr) 259 tdaddr += btofsb(fs, LFS_SBPAD); 260 if (fs->lfs_sboffs[i] > tdaddr) 261 break; 262 } 263 } 264 fs->lfs_offset = tdaddr; 265 if (debug) 266 pwarn("begin with offset/serial 0x%x/%d\n", 267 (int)fs->lfs_offset, (int)fs->lfs_serial); 268 while (tdaddr < idaddr) { 269 bread(fs->lfs_devvp, fsbtodb(fs, tdaddr), 270 fs->lfs_sumsize, 271 NULL, &bp); 272 sp = (SEGSUM *)bp->b_data; 273 if (sp->ss_sumsum != cksum(&sp->ss_datasum, 274 fs->lfs_sumsize - 275 sizeof(sp->ss_sumsum))) { 276 brelse(bp, 0); 277 if (debug) 278 printf("bad cksum at %x\n", 279 (unsigned)tdaddr); 280 break; 281 } 282 fp = (FINFO *)(sp + 1); 283 bc = howmany(sp->ss_ninos, INOPB(fs)) << 284 (fs->lfs_version > 1 ? fs->lfs_ffshift : 285 fs->lfs_bshift); 286 for (i = 0; i < sp->ss_nfinfo; i++) { 287 bc += fp->fi_lastlength + ((fp->fi_nblocks - 1) 288 << fs->lfs_bshift); 289 fp = (FINFO *)(fp->fi_blocks + fp->fi_nblocks); 290 } 291 292 tdaddr += btofsb(fs, bc) + 1; 293 fs->lfs_offset = tdaddr; 294 fs->lfs_serial = sp->ss_serial + 1; 295 brelse(bp, 0); 296 } 297 298 /* 299 * Set curseg, nextseg appropriately -- inlined from 300 * lfs_newseg() 301 */ 302 curseg = dtosn(fs, fs->lfs_offset); 303 fs->lfs_curseg = sntod(fs, curseg); 304 for (sn = curseg + fs->lfs_interleave;;) { 305 sn = (sn + 1) % fs->lfs_nseg; 306 if (sn == curseg) 307 errx(1, "init: no clean segments"); 308 LFS_SEGENTRY(sup, fs, sn, bp); 309 isdirty = sup->su_flags & SEGUSE_DIRTY; 310 brelse(bp, 0); 311 312 if (!isdirty) 313 break; 314 } 315 316 /* Skip superblock if necessary */ 317 for (i = 0; i < LFS_MAXNUMSB; i++) 318 if (fs->lfs_offset == fs->lfs_sboffs[i]) 319 fs->lfs_offset += btofsb(fs, LFS_SBPAD); 320 321 ++fs->lfs_nactive; 322 fs->lfs_nextseg = sntod(fs, sn); 323 if (debug) { 324 pwarn("offset = 0x%" PRIx32 ", serial = %" PRId64 "\n", 325 fs->lfs_offset, fs->lfs_serial); 326 pwarn("curseg = %" PRIx32 ", nextseg = %" PRIx32 "\n", 327 fs->lfs_curseg, fs->lfs_nextseg); 328 } 329 330 if (!nflag && !skipclean) { 331 fs->lfs_idaddr = idaddr; 332 fsmodified = 1; 333 sbdirty(); 334 } 335 } 336 337 if (debug) { 338 pwarn("idaddr = 0x%lx\n", idaddr ? (unsigned long)idaddr : 339 (unsigned long)fs->lfs_idaddr); 340 pwarn("dev_bsize = %lu\n", dev_bsize); 341 pwarn("lfs_bsize = %lu\n", (unsigned long) fs->lfs_bsize); 342 pwarn("lfs_fsize = %lu\n", (unsigned long) fs->lfs_fsize); 343 pwarn("lfs_frag = %lu\n", (unsigned long) fs->lfs_frag); 344 pwarn("lfs_inopb = %lu\n", (unsigned long) fs->lfs_inopb); 345 } 346 if (fs->lfs_version == 1) 347 maxfsblock = fs->lfs_size * (fs->lfs_bsize / dev_bsize); 348 else 349 maxfsblock = fs->lfs_size; 350 maxfilesize = calcmaxfilesize(fs->lfs_bshift); 351 if (/* fs->lfs_minfree < 0 || */ fs->lfs_minfree > 99) { 352 pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", 353 fs->lfs_minfree); 354 if (reply("SET TO DEFAULT") == 1) { 355 fs->lfs_minfree = 10; 356 sbdirty(); 357 } 358 } 359 if (fs->lfs_bmask != fs->lfs_bsize - 1) { 360 pwarn("INCORRECT BMASK=0x%x IN SUPERBLOCK (SHOULD BE 0x%x)", 361 (unsigned int) fs->lfs_bmask, 362 (unsigned int) fs->lfs_bsize - 1); 363 fs->lfs_bmask = fs->lfs_bsize - 1; 364 if (preen) 365 printf(" (FIXED)\n"); 366 if (preen || reply("FIX") == 1) { 367 sbdirty(); 368 } 369 } 370 if (fs->lfs_ffmask != fs->lfs_fsize - 1) { 371 pwarn("INCORRECT FFMASK=%" PRId64 " IN SUPERBLOCK", 372 fs->lfs_ffmask); 373 fs->lfs_ffmask = fs->lfs_fsize - 1; 374 if (preen) 375 printf(" (FIXED)\n"); 376 if (preen || reply("FIX") == 1) { 377 sbdirty(); 378 } 379 } 380 if (fs->lfs_fbmask != (1 << fs->lfs_fbshift) - 1) { 381 pwarn("INCORRECT FFMASK=%" PRId64 " IN SUPERBLOCK", 382 fs->lfs_ffmask); 383 fs->lfs_fbmask = (1 << fs->lfs_fbshift) - 1; 384 if (preen) 385 printf(" (FIXED)\n"); 386 if (preen || reply("FIX") == 1) { 387 sbdirty(); 388 } 389 } 390 if (fs->lfs_maxfilesize != maxfilesize) { 391 pwarn( 392 "INCORRECT MAXFILESIZE=%llu IN SUPERBLOCK (SHOULD BE %llu WITH BSHIFT %d)", 393 (unsigned long long) fs->lfs_maxfilesize, 394 (unsigned long long) maxfilesize, (int)fs->lfs_bshift); 395 if (preen) 396 printf(" (FIXED)\n"); 397 if (preen || reply("FIX") == 1) { 398 fs->lfs_maxfilesize = maxfilesize; 399 sbdirty(); 400 } 401 } 402 if (fs->lfs_maxsymlinklen != MAXSYMLINKLEN_UFS1) { 403 pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK", 404 fs->lfs_maxsymlinklen); 405 fs->lfs_maxsymlinklen = MAXSYMLINKLEN_UFS1; 406 if (preen) 407 printf(" (FIXED)\n"); 408 if (preen || reply("FIX") == 1) { 409 sbdirty(); 410 } 411 } 412 413 /* 414 * Read in the Ifile; we'll be using it a lot. 415 * XXX If the Ifile is corrupted we are in bad shape. We need to 416 * XXX run through the segment headers of the entire disk to 417 * XXX reconstruct the inode table, then pretend all segments are 418 * XXX dirty while we do the rest. 419 */ 420 ivp = fs->lfs_ivnode; 421 maxino = ((VTOI(ivp)->i_ffs1_size - (fs->lfs_cleansz + fs->lfs_segtabsz) 422 * fs->lfs_bsize) / fs->lfs_bsize) * fs->lfs_ifpb; 423 if (debug) 424 pwarn("maxino = %llu\n", (unsigned long long)maxino); 425 for (i = 0; i < VTOI(ivp)->i_ffs1_size; i += fs->lfs_bsize) { 426 bread(ivp, i >> fs->lfs_bshift, fs->lfs_bsize, NOCRED, &bp); 427 /* XXX check B_ERROR */ 428 brelse(bp, 0); 429 } 430 431 /* 432 * allocate and initialize the necessary maps 433 */ 434 din_table = ecalloc(maxino, sizeof(*din_table)); 435 seg_table = ecalloc(fs->lfs_nseg, sizeof(SEGUSE)); 436 /* Get segment flags */ 437 for (i = 0; i < fs->lfs_nseg; i++) { 438 LFS_SEGENTRY(sup, fs, i, bp); 439 seg_table[i].su_flags = sup->su_flags & ~SEGUSE_ACTIVE; 440 if (preen) 441 seg_table[i].su_nbytes = sup->su_nbytes; 442 brelse(bp, 0); 443 } 444 445 /* Initialize Ifile entry */ 446 din_table[fs->lfs_ifile] = fs->lfs_idaddr; 447 seg_table[dtosn(fs, fs->lfs_idaddr)].su_nbytes += DINODE1_SIZE; 448 449 #ifndef VERBOSE_BLOCKMAP 450 bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); 451 blockmap = ecalloc(bmapsize, sizeof(char)); 452 #else 453 bmapsize = maxfsblock * sizeof(ino_t); 454 blockmap = ecalloc(maxfsblock, sizeof(ino_t)); 455 #endif 456 statemap = ecalloc(maxino, sizeof(char)); 457 typemap = ecalloc(maxino, sizeof(char)); 458 lncntp = ecalloc(maxino, sizeof(int16_t)); 459 460 if (preen) { 461 n_files = fs->lfs_nfiles; 462 n_blks = fs->lfs_dsize - fs->lfs_bfree; 463 numdirs = maxino; 464 inplast = 0; 465 listmax = numdirs + 10; 466 inpsort = ecalloc(listmax, sizeof(struct inoinfo *)); 467 inphead = ecalloc(numdirs, sizeof(struct inoinfo *)); 468 } 469 470 return (1); 471 472 ckfini(0); 473 return (0); 474 } 475 476 static struct disklabel * 477 getdisklabel(const char *s, int fd) 478 { 479 static struct disklabel lab; 480 481 if (ioctl(fd, DIOCGDINFO, (char *) &lab) < 0) { 482 if (s == NULL) 483 return ((struct disklabel *) NULL); 484 pwarn("ioctl (GCINFO): %s\n", strerror(errno)); 485 return NULL; 486 } 487 return (&lab); 488 } 489