1 /* 2 * Copyright (c) 1980, 1986, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 #if 0 36 static const char sccsid[] = "@(#)pass1.c 8.6 (Berkeley) 4/28/95"; 37 #endif 38 static const char rcsid[] = 39 "$Id: pass1.c,v 1.11 1998/06/15 07:07:16 charnier Exp $"; 40 #endif /* not lint */ 41 42 #include <sys/param.h> 43 44 #include <ufs/ufs/dinode.h> 45 #include <ufs/ufs/dir.h> 46 #include <ufs/ffs/fs.h> 47 48 #include <err.h> 49 #include <string.h> 50 51 #include "fsck.h" 52 53 static ufs_daddr_t badblk; 54 static ufs_daddr_t dupblk; 55 56 static void checkinode __P((ino_t inumber, struct inodesc *)); 57 58 void 59 pass1() 60 { 61 ino_t inumber; 62 int c, i, cgd; 63 struct inodesc idesc; 64 65 /* 66 * Set file system reserved blocks in used block map. 67 */ 68 for (c = 0; c < sblock.fs_ncg; c++) { 69 cgd = cgdmin(&sblock, c); 70 if (c == 0) { 71 i = cgbase(&sblock, c); 72 cgd += howmany(sblock.fs_cssize, sblock.fs_fsize); 73 } else 74 i = cgsblock(&sblock, c); 75 for (; i < cgd; i++) 76 setbmap(i); 77 } 78 /* 79 * Find all allocated blocks. 80 */ 81 memset(&idesc, 0, sizeof(struct inodesc)); 82 idesc.id_type = ADDR; 83 idesc.id_func = pass1check; 84 inumber = 0; 85 n_files = n_blks = 0; 86 resetinodebuf(); 87 for (c = 0; c < sblock.fs_ncg; c++) { 88 for (i = 0; i < sblock.fs_ipg; i++, inumber++) { 89 if (inumber < ROOTINO) 90 continue; 91 checkinode(inumber, &idesc); 92 } 93 } 94 freeinodebuf(); 95 } 96 97 static void 98 checkinode(inumber, idesc) 99 ino_t inumber; 100 register struct inodesc *idesc; 101 { 102 register struct dinode *dp; 103 struct zlncnt *zlnp; 104 int ndb, j; 105 mode_t mode; 106 char *symbuf; 107 108 dp = getnextinode(inumber); 109 mode = dp->di_mode & IFMT; 110 if (mode == 0) { 111 if (memcmp(dp->di_db, zino.di_db, 112 NDADDR * sizeof(ufs_daddr_t)) || 113 memcmp(dp->di_ib, zino.di_ib, 114 NIADDR * sizeof(ufs_daddr_t)) || 115 dp->di_mode || dp->di_size) { 116 pfatal("PARTIALLY ALLOCATED INODE I=%lu", inumber); 117 if (reply("CLEAR") == 1) { 118 dp = ginode(inumber); 119 clearinode(dp); 120 inodirty(); 121 } 122 } 123 statemap[inumber] = USTATE; 124 return; 125 } 126 lastino = inumber; 127 if (/* dp->di_size < 0 || */ 128 dp->di_size + sblock.fs_bsize - 1 < dp->di_size || 129 (mode == IFDIR && dp->di_size > MAXDIRSIZE)) { 130 if (debug) 131 printf("bad size %qu:", dp->di_size); 132 goto unknown; 133 } 134 if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { 135 dp = ginode(inumber); 136 dp->di_size = sblock.fs_fsize; 137 dp->di_mode = IFREG|0600; 138 inodirty(); 139 } 140 ndb = howmany(dp->di_size, sblock.fs_bsize); 141 if (ndb < 0) { 142 if (debug) 143 printf("bad size %qu ndb %d:", 144 dp->di_size, ndb); 145 goto unknown; 146 } 147 if (mode == IFBLK || mode == IFCHR) 148 ndb++; 149 if (mode == IFLNK) { 150 if (doinglevel2 && 151 dp->di_size > 0 && dp->di_size < MAXSYMLINKLEN && 152 dp->di_blocks != 0) { 153 symbuf = alloca(secsize); 154 if (bread(fsreadfd, symbuf, 155 fsbtodb(&sblock, dp->di_db[0]), 156 (long)secsize) != 0) 157 errx(EEXIT, "cannot read symlink"); 158 if (debug) { 159 symbuf[dp->di_size] = 0; 160 printf("convert symlink %lu(%s) of size %ld\n", 161 (u_long)inumber, symbuf, 162 (long)dp->di_size); 163 } 164 dp = ginode(inumber); 165 memmove(dp->di_shortlink, symbuf, (long)dp->di_size); 166 dp->di_blocks = 0; 167 inodirty(); 168 } 169 /* 170 * Fake ndb value so direct/indirect block checks below 171 * will detect any garbage after symlink string. 172 */ 173 if (dp->di_size < sblock.fs_maxsymlinklen || 174 dp->di_blocks == 0) { 175 ndb = howmany(dp->di_size, sizeof(ufs_daddr_t)); 176 if (ndb > NDADDR) { 177 j = ndb - NDADDR; 178 for (ndb = 1; j > 1; j--) 179 ndb *= NINDIR(&sblock); 180 ndb += NDADDR; 181 } 182 } 183 } 184 for (j = ndb; j < NDADDR; j++) 185 if (dp->di_db[j] != 0) { 186 if (debug) 187 printf("bad direct addr: %ld\n", 188 (long)dp->di_db[j]); 189 goto unknown; 190 } 191 for (j = 0, ndb -= NDADDR; ndb > 0; j++) 192 ndb /= NINDIR(&sblock); 193 for (; j < NIADDR; j++) 194 if (dp->di_ib[j] != 0) { 195 if (debug) 196 printf("bad indirect addr: %ld\n", 197 (long)dp->di_ib[j]); 198 goto unknown; 199 } 200 if (ftypeok(dp) == 0) 201 goto unknown; 202 n_files++; 203 lncntp[inumber] = dp->di_nlink; 204 if (dp->di_nlink <= 0) { 205 zlnp = (struct zlncnt *)malloc(sizeof *zlnp); 206 if (zlnp == NULL) { 207 pfatal("LINK COUNT TABLE OVERFLOW"); 208 if (reply("CONTINUE") == 0) { 209 ckfini(0); 210 exit(EEXIT); 211 } 212 } else { 213 zlnp->zlncnt = inumber; 214 zlnp->next = zlnhead; 215 zlnhead = zlnp; 216 } 217 } 218 if (mode == IFDIR) { 219 if (dp->di_size == 0) 220 statemap[inumber] = DCLEAR; 221 else 222 statemap[inumber] = DSTATE; 223 cacheino(dp, inumber); 224 } else 225 statemap[inumber] = FSTATE; 226 typemap[inumber] = IFTODT(mode); 227 if (doinglevel2 && 228 (dp->di_ouid != (u_short)-1 || dp->di_ogid != (u_short)-1)) { 229 dp = ginode(inumber); 230 dp->di_uid = dp->di_ouid; 231 dp->di_ouid = -1; 232 dp->di_gid = dp->di_ogid; 233 dp->di_ogid = -1; 234 inodirty(); 235 } 236 badblk = dupblk = 0; 237 idesc->id_number = inumber; 238 (void)ckinode(dp, idesc); 239 idesc->id_entryno *= btodb(sblock.fs_fsize); 240 if (dp->di_blocks != idesc->id_entryno) { 241 pwarn("INCORRECT BLOCK COUNT I=%lu (%ld should be %ld)", 242 inumber, dp->di_blocks, idesc->id_entryno); 243 if (preen) 244 printf(" (CORRECTED)\n"); 245 else if (reply("CORRECT") == 0) 246 return; 247 dp = ginode(inumber); 248 dp->di_blocks = idesc->id_entryno; 249 inodirty(); 250 } 251 return; 252 unknown: 253 pfatal("UNKNOWN FILE TYPE I=%lu", inumber); 254 statemap[inumber] = FCLEAR; 255 if (reply("CLEAR") == 1) { 256 statemap[inumber] = USTATE; 257 dp = ginode(inumber); 258 clearinode(dp); 259 inodirty(); 260 } 261 } 262 263 int 264 pass1check(idesc) 265 register struct inodesc *idesc; 266 { 267 int res = KEEPON; 268 int anyout, nfrags; 269 ufs_daddr_t blkno = idesc->id_blkno; 270 register struct dups *dlp; 271 struct dups *new; 272 273 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 274 blkerror(idesc->id_number, "BAD", blkno); 275 if (badblk++ >= MAXBAD) { 276 pwarn("EXCESSIVE BAD BLKS I=%lu", 277 idesc->id_number); 278 if (preen) 279 printf(" (SKIPPING)\n"); 280 else if (reply("CONTINUE") == 0) { 281 ckfini(0); 282 exit(EEXIT); 283 } 284 return (STOP); 285 } 286 } 287 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 288 if (anyout && chkrange(blkno, 1)) { 289 res = SKIP; 290 } else if (!testbmap(blkno)) { 291 n_blks++; 292 setbmap(blkno); 293 } else { 294 blkerror(idesc->id_number, "DUP", blkno); 295 if (dupblk++ >= MAXDUP) { 296 pwarn("EXCESSIVE DUP BLKS I=%lu", 297 idesc->id_number); 298 if (preen) 299 printf(" (SKIPPING)\n"); 300 else if (reply("CONTINUE") == 0) { 301 ckfini(0); 302 exit(EEXIT); 303 } 304 return (STOP); 305 } 306 new = (struct dups *)malloc(sizeof(struct dups)); 307 if (new == NULL) { 308 pfatal("DUP TABLE OVERFLOW."); 309 if (reply("CONTINUE") == 0) { 310 ckfini(0); 311 exit(EEXIT); 312 } 313 return (STOP); 314 } 315 new->dup = blkno; 316 if (muldup == 0) { 317 duplist = muldup = new; 318 new->next = 0; 319 } else { 320 new->next = muldup->next; 321 muldup->next = new; 322 } 323 for (dlp = duplist; dlp != muldup; dlp = dlp->next) 324 if (dlp->dup == blkno) 325 break; 326 if (dlp == muldup && dlp->dup != blkno) 327 muldup = new; 328 } 329 /* 330 * count the number of blocks found in id_entryno 331 */ 332 idesc->id_entryno++; 333 } 334 return (res); 335 } 336