1 1.26 christos /* $NetBSD: pass1.c,v 1.26 2017/04/21 19:33:56 christos Exp $ */ 2 1.1 bouyer 3 1.1 bouyer /* 4 1.1 bouyer * Copyright (c) 1980, 1986, 1993 5 1.1 bouyer * The Regents of the University of California. All rights reserved. 6 1.1 bouyer * 7 1.1 bouyer * Redistribution and use in source and binary forms, with or without 8 1.1 bouyer * modification, are permitted provided that the following conditions 9 1.1 bouyer * are met: 10 1.1 bouyer * 1. Redistributions of source code must retain the above copyright 11 1.1 bouyer * notice, this list of conditions and the following disclaimer. 12 1.1 bouyer * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 bouyer * notice, this list of conditions and the following disclaimer in the 14 1.1 bouyer * documentation and/or other materials provided with the distribution. 15 1.10 agc * 3. Neither the name of the University nor the names of its contributors 16 1.10 agc * may be used to endorse or promote products derived from this software 17 1.10 agc * without specific prior written permission. 18 1.10 agc * 19 1.10 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.10 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.10 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.10 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.10 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.10 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.10 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.10 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.10 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.10 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.10 agc * SUCH DAMAGE. 30 1.10 agc */ 31 1.10 agc 32 1.10 agc /* 33 1.10 agc * Copyright (c) 1997 Manuel Bouyer. 34 1.10 agc * 35 1.10 agc * Redistribution and use in source and binary forms, with or without 36 1.10 agc * modification, are permitted provided that the following conditions 37 1.10 agc * are met: 38 1.10 agc * 1. Redistributions of source code must retain the above copyright 39 1.10 agc * notice, this list of conditions and the following disclaimer. 40 1.10 agc * 2. Redistributions in binary form must reproduce the above copyright 41 1.10 agc * notice, this list of conditions and the following disclaimer in the 42 1.10 agc * documentation and/or other materials provided with the distribution. 43 1.1 bouyer * 44 1.12 bouyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 45 1.12 bouyer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46 1.12 bouyer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47 1.12 bouyer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 48 1.12 bouyer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 49 1.12 bouyer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 1.12 bouyer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 1.12 bouyer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 1.12 bouyer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 53 1.12 bouyer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 1.1 bouyer */ 55 1.1 bouyer 56 1.3 lukem #include <sys/cdefs.h> 57 1.1 bouyer #ifndef lint 58 1.1 bouyer #if 0 59 1.1 bouyer static char sccsid[] = "@(#)pass1.c 8.1 (Berkeley) 6/5/93"; 60 1.1 bouyer #else 61 1.26 christos __RCSID("$NetBSD: pass1.c,v 1.26 2017/04/21 19:33:56 christos Exp $"); 62 1.1 bouyer #endif 63 1.1 bouyer #endif /* not lint */ 64 1.1 bouyer 65 1.1 bouyer #include <sys/param.h> 66 1.1 bouyer #include <sys/time.h> 67 1.1 bouyer #include <ufs/ext2fs/ext2fs_dinode.h> 68 1.1 bouyer #include <ufs/ext2fs/ext2fs_dir.h> 69 1.1 bouyer #include <ufs/ext2fs/ext2fs.h> 70 1.1 bouyer 71 1.1 bouyer #include <ufs/ufs/dinode.h> /* for IFMT & friends */ 72 1.1 bouyer 73 1.1 bouyer #include <stdio.h> 74 1.1 bouyer #include <stdlib.h> 75 1.1 bouyer #include <string.h> 76 1.5 kleink #include <time.h> 77 1.1 bouyer 78 1.1 bouyer #include "fsck.h" 79 1.1 bouyer #include "extern.h" 80 1.1 bouyer #include "fsutil.h" 81 1.17 lukem #include "exitvalues.h" 82 1.1 bouyer 83 1.1 bouyer static daddr_t badblk; 84 1.1 bouyer static daddr_t dupblk; 85 1.13 xtraeme static void checkinode(ino_t, struct inodesc *); 86 1.1 bouyer 87 1.1 bouyer void 88 1.13 xtraeme pass1(void) 89 1.1 bouyer { 90 1.1 bouyer ino_t inumber; 91 1.8 bouyer int c, i; 92 1.19 lukem size_t j; 93 1.8 bouyer daddr_t dbase; 94 1.1 bouyer struct inodesc idesc; 95 1.1 bouyer 96 1.1 bouyer /* 97 1.1 bouyer * Set file system reserved blocks in used block map. 98 1.1 bouyer */ 99 1.1 bouyer for (c = 0; c < sblock.e2fs_ncg; c++) { 100 1.8 bouyer dbase = c * sblock.e2fs.e2fs_bpg + 101 1.8 bouyer sblock.e2fs.e2fs_first_dblock; 102 1.8 bouyer /* Mark the blocks used for the inode table */ 103 1.9 bouyer if (fs2h32(sblock.e2fs_gd[c].ext2bgd_i_tables) >= dbase) { 104 1.8 bouyer for (i = 0; i < sblock.e2fs_itpg; i++) 105 1.9 bouyer setbmap( 106 1.9 bouyer fs2h32(sblock.e2fs_gd[c].ext2bgd_i_tables) 107 1.9 bouyer + i); 108 1.8 bouyer } 109 1.8 bouyer /* Mark the blocks used for the block bitmap */ 110 1.9 bouyer if (fs2h32(sblock.e2fs_gd[c].ext2bgd_b_bitmap) >= dbase) 111 1.9 bouyer setbmap(fs2h32(sblock.e2fs_gd[c].ext2bgd_b_bitmap)); 112 1.8 bouyer /* Mark the blocks used for the inode bitmap */ 113 1.9 bouyer if (fs2h32(sblock.e2fs_gd[c].ext2bgd_i_bitmap) >= dbase) 114 1.9 bouyer setbmap(fs2h32(sblock.e2fs_gd[c].ext2bgd_i_bitmap)); 115 1.8 bouyer 116 1.8 bouyer if (sblock.e2fs.e2fs_rev == E2FS_REV0 || 117 1.8 bouyer (sblock.e2fs.e2fs_features_rocompat & 118 1.8 bouyer EXT2F_ROCOMPAT_SPARSESUPER) == 0 || 119 1.8 bouyer cg_has_sb(c)) { 120 1.8 bouyer /* Mark copuy of SB and descriptors */ 121 1.8 bouyer setbmap(dbase); 122 1.8 bouyer for (i = 1; i <= sblock.e2fs_ngdb; i++) 123 1.8 bouyer setbmap(dbase+i); 124 1.8 bouyer } 125 1.1 bouyer 126 1.8 bouyer 127 1.8 bouyer if (c == 0) { 128 1.8 bouyer for(i = 0; i < dbase; i++) 129 1.8 bouyer setbmap(i); 130 1.8 bouyer } 131 1.1 bouyer } 132 1.1 bouyer 133 1.1 bouyer /* 134 1.1 bouyer * Find all allocated blocks. 135 1.1 bouyer */ 136 1.1 bouyer memset(&idesc, 0, sizeof(struct inodesc)); 137 1.1 bouyer idesc.id_type = ADDR; 138 1.1 bouyer idesc.id_func = pass1check; 139 1.1 bouyer inumber = 1; 140 1.1 bouyer n_files = n_blks = 0; 141 1.1 bouyer resetinodebuf(); 142 1.1 bouyer for (c = 0; c < sblock.e2fs_ncg; c++) { 143 1.19 lukem for (j = 0; 144 1.19 lukem j < sblock.e2fs.e2fs_ipg && inumber <= sblock.e2fs.e2fs_icount; 145 1.19 lukem j++, inumber++) { 146 1.1 bouyer if (inumber < EXT2_ROOTINO) /* XXX */ 147 1.1 bouyer continue; 148 1.1 bouyer checkinode(inumber, &idesc); 149 1.1 bouyer } 150 1.1 bouyer } 151 1.1 bouyer freeinodebuf(); 152 1.1 bouyer } 153 1.1 bouyer 154 1.1 bouyer static void 155 1.13 xtraeme checkinode(ino_t inumber, struct inodesc *idesc) 156 1.1 bouyer { 157 1.3 lukem struct ext2fs_dinode *dp; 158 1.1 bouyer struct zlncnt *zlnp; 159 1.1 bouyer int ndb, j; 160 1.1 bouyer mode_t mode; 161 1.1 bouyer 162 1.1 bouyer dp = getnextinode(inumber); 163 1.16 tsutsui if (inumber < EXT2_FIRSTINO && 164 1.16 tsutsui inumber != EXT2_ROOTINO && 165 1.16 tsutsui !(inumber == EXT2_RESIZEINO && 166 1.16 tsutsui (sblock.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) != 0)) 167 1.1 bouyer return; 168 1.1 bouyer 169 1.4 bouyer mode = fs2h16(dp->e2di_mode) & IFMT; 170 1.1 bouyer if (mode == 0 || (dp->e2di_dtime != 0 && dp->e2di_nlink == 0)) { 171 1.1 bouyer if (mode == 0 && ( 172 1.14 ws memcmp(dp->e2di_blocks, zino.e2di_blocks, 173 1.23 dholland (EXT2FS_NDADDR + EXT2FS_NIADDR) * sizeof(u_int32_t)) || 174 1.14 ws dp->e2di_mode || inosize(dp))) { 175 1.15 christos pfatal("PARTIALLY ALLOCATED INODE I=%llu", 176 1.15 christos (unsigned long long)inumber); 177 1.1 bouyer if (reply("CLEAR") == 1) { 178 1.1 bouyer dp = ginode(inumber); 179 1.1 bouyer clearinode(dp); 180 1.1 bouyer inodirty(); 181 1.1 bouyer } 182 1.1 bouyer } 183 1.1 bouyer #ifdef notyet /* it seems that dtime == 0 is valid for a unallocated inode */ 184 1.1 bouyer if (dp->e2di_dtime == 0) { 185 1.15 christos pwarn("DELETED INODE I=%llu HAS A NULL DTIME", 186 1.15 christos (unsigned long long)inumber); 187 1.1 bouyer if (preen) { 188 1.1 bouyer printf(" (CORRECTED)\n"); 189 1.1 bouyer } 190 1.1 bouyer if (preen || reply("CORRECT")) { 191 1.1 bouyer time_t t; 192 1.1 bouyer time(&t); 193 1.4 bouyer dp->e2di_dtime = h2fs32(t); 194 1.1 bouyer dp = ginode(inumber); 195 1.1 bouyer inodirty(); 196 1.1 bouyer } 197 1.1 bouyer } 198 1.1 bouyer #endif 199 1.1 bouyer statemap[inumber] = USTATE; 200 1.1 bouyer return; 201 1.1 bouyer } 202 1.1 bouyer lastino = inumber; 203 1.1 bouyer if (dp->e2di_dtime != 0) { 204 1.21 christos pwarn("INODE I=%llu HAS DTIME=%s", 205 1.21 christos (unsigned long long)inumber, 206 1.21 christos print_mtime(fs2h32(dp->e2di_dtime))); 207 1.1 bouyer if (preen) { 208 1.1 bouyer printf(" (CORRECTED)\n"); 209 1.1 bouyer } 210 1.1 bouyer if (preen || reply("CORRECT")) { 211 1.1 bouyer dp = ginode(inumber); 212 1.1 bouyer dp->e2di_dtime = 0; 213 1.1 bouyer inodirty(); 214 1.1 bouyer } 215 1.1 bouyer } 216 1.14 ws if (inosize(dp) + sblock.e2fs_bsize - 1 < inosize(dp)) { 217 1.1 bouyer if (debug) 218 1.14 ws printf("bad size %llu:", (unsigned long long)inosize(dp)); 219 1.1 bouyer goto unknown; 220 1.1 bouyer } 221 1.1 bouyer if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { 222 1.1 bouyer dp = ginode(inumber); 223 1.4 bouyer dp->e2di_mode = h2fs16(IFREG|0600); 224 1.14 ws inossize(dp, sblock.e2fs_bsize); 225 1.1 bouyer inodirty(); 226 1.1 bouyer } 227 1.14 ws ndb = howmany(inosize(dp), sblock.e2fs_bsize); 228 1.1 bouyer if (ndb < 0) { 229 1.1 bouyer if (debug) 230 1.14 ws printf("bad size %llu ndb %d:", 231 1.14 ws (unsigned long long)inosize(dp), ndb); 232 1.1 bouyer goto unknown; 233 1.1 bouyer } 234 1.1 bouyer if (mode == IFBLK || mode == IFCHR) 235 1.1 bouyer ndb++; 236 1.1 bouyer if (mode == IFLNK) { 237 1.1 bouyer /* 238 1.1 bouyer * Fake ndb value so direct/indirect block checks below 239 1.1 bouyer * will detect any garbage after symlink string. 240 1.1 bouyer */ 241 1.14 ws if (inosize(dp) < EXT2_MAXSYMLINKLEN || 242 1.26 christos (EXT2_MAXSYMLINKLEN == 0 && inonblock(dp) == 0)) { 243 1.14 ws ndb = howmany(inosize(dp), sizeof(u_int32_t)); 244 1.23 dholland if (ndb > EXT2FS_NDADDR) { 245 1.23 dholland j = ndb - EXT2FS_NDADDR; 246 1.1 bouyer for (ndb = 1; j > 1; j--) 247 1.24 dholland ndb *= EXT2_NINDIR(&sblock); 248 1.23 dholland ndb += EXT2FS_NDADDR; 249 1.1 bouyer } 250 1.1 bouyer } 251 1.1 bouyer } 252 1.6 bouyer /* Linux puts things in blocks for FIFO, so skip this check */ 253 1.6 bouyer if (mode != IFIFO) { 254 1.23 dholland for (j = ndb; j < EXT2FS_NDADDR; j++) 255 1.6 bouyer if (dp->e2di_blocks[j] != 0) { 256 1.6 bouyer if (debug) 257 1.6 bouyer printf("bad direct addr: %d\n", 258 1.6 bouyer fs2h32(dp->e2di_blocks[j])); 259 1.6 bouyer goto unknown; 260 1.6 bouyer } 261 1.23 dholland for (j = 0, ndb -= EXT2FS_NDADDR; ndb > 0; j++) 262 1.24 dholland ndb /= EXT2_NINDIR(&sblock); 263 1.23 dholland for (; j < EXT2FS_NIADDR; j++) { 264 1.23 dholland if (dp->e2di_blocks[j+EXT2FS_NDADDR] != 0) { 265 1.6 bouyer if (debug) 266 1.6 bouyer printf("bad indirect addr: %d\n", 267 1.23 dholland fs2h32(dp->e2di_blocks[j+EXT2FS_NDADDR])); 268 1.6 bouyer goto unknown; 269 1.6 bouyer } 270 1.1 bouyer } 271 1.6 bouyer } 272 1.1 bouyer if (ftypeok(dp) == 0) 273 1.1 bouyer goto unknown; 274 1.16 tsutsui if (inumber >= EXT2_FIRSTINO || inumber == EXT2_ROOTINO) { 275 1.16 tsutsui /* Don't count reserved inodes except root */ 276 1.16 tsutsui n_files++; 277 1.16 tsutsui } 278 1.4 bouyer lncntp[inumber] = fs2h16(dp->e2di_nlink); 279 1.4 bouyer if (dp->e2di_nlink == 0) { 280 1.18 tsutsui zlnp = malloc(sizeof *zlnp); 281 1.1 bouyer if (zlnp == NULL) { 282 1.1 bouyer pfatal("LINK COUNT TABLE OVERFLOW"); 283 1.1 bouyer if (reply("CONTINUE") == 0) 284 1.17 lukem exit(FSCK_EXIT_CHECK_FAILED); 285 1.1 bouyer } else { 286 1.1 bouyer zlnp->zlncnt = inumber; 287 1.1 bouyer zlnp->next = zlnhead; 288 1.1 bouyer zlnhead = zlnp; 289 1.1 bouyer } 290 1.1 bouyer } 291 1.1 bouyer if (mode == IFDIR) { 292 1.14 ws if (inosize(dp) == 0) 293 1.1 bouyer statemap[inumber] = DCLEAR; 294 1.1 bouyer else 295 1.1 bouyer statemap[inumber] = DSTATE; 296 1.1 bouyer cacheino(dp, inumber); 297 1.1 bouyer } else { 298 1.1 bouyer statemap[inumber] = FSTATE; 299 1.1 bouyer } 300 1.8 bouyer typemap[inumber] = E2IFTODT(mode); 301 1.1 bouyer badblk = dupblk = 0; 302 1.1 bouyer idesc->id_number = inumber; 303 1.1 bouyer (void)ckinode(dp, idesc); 304 1.1 bouyer idesc->id_entryno *= btodb(sblock.e2fs_bsize); 305 1.22 jakllsch if (inonblock(dp) != (uint32_t)idesc->id_entryno) { 306 1.22 jakllsch pwarn("INCORRECT BLOCK COUNT I=%llu (%llu should be %d)", 307 1.22 jakllsch (unsigned long long)inumber, 308 1.22 jakllsch (unsigned long long)inonblock(dp), 309 1.15 christos idesc->id_entryno); 310 1.1 bouyer if (preen) 311 1.1 bouyer printf(" (CORRECTED)\n"); 312 1.1 bouyer else if (reply("CORRECT") == 0) 313 1.1 bouyer return; 314 1.1 bouyer dp = ginode(inumber); 315 1.22 jakllsch inosnblock(dp, idesc->id_entryno); 316 1.1 bouyer inodirty(); 317 1.1 bouyer } 318 1.1 bouyer return; 319 1.1 bouyer unknown: 320 1.15 christos pfatal("UNKNOWN FILE TYPE I=%llu", (unsigned long long)inumber); 321 1.1 bouyer statemap[inumber] = FCLEAR; 322 1.1 bouyer if (reply("CLEAR") == 1) { 323 1.1 bouyer statemap[inumber] = USTATE; 324 1.1 bouyer dp = ginode(inumber); 325 1.1 bouyer clearinode(dp); 326 1.1 bouyer inodirty(); 327 1.1 bouyer } 328 1.1 bouyer } 329 1.1 bouyer 330 1.1 bouyer int 331 1.13 xtraeme pass1check(struct inodesc *idesc) 332 1.1 bouyer { 333 1.1 bouyer int res = KEEPON; 334 1.1 bouyer int anyout, nfrags; 335 1.1 bouyer daddr_t blkno = idesc->id_blkno; 336 1.3 lukem struct dups *dlp; 337 1.1 bouyer struct dups *new; 338 1.1 bouyer 339 1.1 bouyer if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 340 1.1 bouyer blkerror(idesc->id_number, "BAD", blkno); 341 1.1 bouyer if (badblk++ >= MAXBAD) { 342 1.15 christos pwarn("EXCESSIVE BAD BLKS I=%llu", 343 1.15 christos (unsigned long long)idesc->id_number); 344 1.1 bouyer if (preen) 345 1.1 bouyer printf(" (SKIPPING)\n"); 346 1.1 bouyer else if (reply("CONTINUE") == 0) 347 1.17 lukem exit(FSCK_EXIT_CHECK_FAILED); 348 1.1 bouyer return (STOP); 349 1.1 bouyer } 350 1.1 bouyer } 351 1.1 bouyer for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 352 1.1 bouyer if (anyout && chkrange(blkno, 1)) { 353 1.1 bouyer res = SKIP; 354 1.1 bouyer } else if (!testbmap(blkno)) { 355 1.1 bouyer n_blks++; 356 1.1 bouyer setbmap(blkno); 357 1.1 bouyer } else { 358 1.1 bouyer blkerror(idesc->id_number, "DUP", blkno); 359 1.1 bouyer if (dupblk++ >= MAXDUP) { 360 1.15 christos pwarn("EXCESSIVE DUP BLKS I=%llu", 361 1.15 christos (unsigned long long)idesc->id_number); 362 1.1 bouyer if (preen) 363 1.1 bouyer printf(" (SKIPPING)\n"); 364 1.1 bouyer else if (reply("CONTINUE") == 0) 365 1.17 lukem exit(FSCK_EXIT_CHECK_FAILED); 366 1.1 bouyer return (STOP); 367 1.1 bouyer } 368 1.18 tsutsui new = malloc(sizeof(struct dups)); 369 1.1 bouyer if (new == NULL) { 370 1.1 bouyer pfatal("DUP TABLE OVERFLOW."); 371 1.1 bouyer if (reply("CONTINUE") == 0) 372 1.17 lukem exit(FSCK_EXIT_CHECK_FAILED); 373 1.1 bouyer return (STOP); 374 1.1 bouyer } 375 1.1 bouyer new->dup = blkno; 376 1.1 bouyer if (muldup == 0) { 377 1.1 bouyer duplist = muldup = new; 378 1.1 bouyer new->next = 0; 379 1.1 bouyer } else { 380 1.1 bouyer new->next = muldup->next; 381 1.1 bouyer muldup->next = new; 382 1.1 bouyer } 383 1.1 bouyer for (dlp = duplist; dlp != muldup; dlp = dlp->next) 384 1.1 bouyer if (dlp->dup == blkno) 385 1.1 bouyer break; 386 1.1 bouyer if (dlp == muldup && dlp->dup != blkno) 387 1.1 bouyer muldup = new; 388 1.1 bouyer } 389 1.1 bouyer /* 390 1.1 bouyer * count the number of blocks found in id_entryno 391 1.1 bouyer */ 392 1.1 bouyer idesc->id_entryno++; 393 1.1 bouyer } 394 1.1 bouyer return (res); 395 1.1 bouyer } 396