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