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 static const char sccsid[] = "@(#)pass1.c 8.6 (Berkeley) 4/28/95"; 36 #endif /* not lint */ 37 38 #include <sys/param.h> 39 #include <sys/time.h> 40 41 #include <ufs/ufs/dinode.h> 42 #include <ufs/ufs/dir.h> 43 #include <ufs/ffs/fs.h> 44 45 #include <err.h> 46 #include <string.h> 47 48 #include "fsck.h" 49 50 static ufs_daddr_t badblk; 51 static ufs_daddr_t dupblk; 52 53 static void checkinode __P((ino_t inumber, struct inodesc *)); 54 55 void 56 pass1() 57 { 58 ino_t inumber; 59 int c, i, cgd; 60 struct inodesc idesc; 61 62 /* 63 * Set file system reserved blocks in used block map. 64 */ 65 for (c = 0; c < sblock.fs_ncg; c++) { 66 cgd = cgdmin(&sblock, c); 67 if (c == 0) { 68 i = cgbase(&sblock, c); 69 cgd += howmany(sblock.fs_cssize, sblock.fs_fsize); 70 } else 71 i = cgsblock(&sblock, c); 72 for (; i < cgd; i++) 73 setbmap(i); 74 } 75 /* 76 * Find all allocated blocks. 77 */ 78 memset(&idesc, 0, sizeof(struct inodesc)); 79 idesc.id_type = ADDR; 80 idesc.id_func = pass1check; 81 inumber = 0; 82 n_files = n_blks = 0; 83 resetinodebuf(); 84 for (c = 0; c < sblock.fs_ncg; c++) { 85 for (i = 0; i < sblock.fs_ipg; i++, inumber++) { 86 if (inumber < ROOTINO) 87 continue; 88 checkinode(inumber, &idesc); 89 } 90 } 91 freeinodebuf(); 92 } 93 94 static void 95 checkinode(inumber, idesc) 96 ino_t inumber; 97 register struct inodesc *idesc; 98 { 99 register struct dinode *dp; 100 struct zlncnt *zlnp; 101 int ndb, j; 102 mode_t mode; 103 char *symbuf; 104 105 dp = getnextinode(inumber); 106 mode = dp->di_mode & IFMT; 107 if (mode == 0) { 108 if (memcmp(dp->di_db, zino.di_db, 109 NDADDR * sizeof(ufs_daddr_t)) || 110 memcmp(dp->di_ib, zino.di_ib, 111 NIADDR * sizeof(ufs_daddr_t)) || 112 dp->di_mode || dp->di_size) { 113 pfatal("PARTIALLY ALLOCATED INODE I=%lu", inumber); 114 if (reply("CLEAR") == 1) { 115 dp = ginode(inumber); 116 clearinode(dp); 117 inodirty(); 118 } 119 } 120 statemap[inumber] = USTATE; 121 return; 122 } 123 lastino = inumber; 124 if (/* dp->di_size < 0 || */ 125 dp->di_size + sblock.fs_bsize - 1 < dp->di_size || 126 (mode == IFDIR && dp->di_size > MAXDIRSIZE)) { 127 if (debug) 128 printf("bad size %qu:", dp->di_size); 129 goto unknown; 130 } 131 if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { 132 dp = ginode(inumber); 133 dp->di_size = sblock.fs_fsize; 134 dp->di_mode = IFREG|0600; 135 inodirty(); 136 } 137 ndb = howmany(dp->di_size, sblock.fs_bsize); 138 if (ndb < 0) { 139 if (debug) 140 printf("bad size %qu ndb %d:", 141 dp->di_size, ndb); 142 goto unknown; 143 } 144 if (mode == IFBLK || mode == IFCHR) 145 ndb++; 146 if (mode == IFLNK) { 147 if (doinglevel2 && 148 dp->di_size > 0 && dp->di_size < MAXSYMLINKLEN && 149 dp->di_blocks != 0) { 150 symbuf = alloca(secsize); 151 if (bread(fsreadfd, symbuf, 152 fsbtodb(&sblock, dp->di_db[0]), 153 (long)secsize) != 0) 154 errx(EEXIT, "cannot read symlink"); 155 if (debug) { 156 symbuf[dp->di_size] = 0; 157 printf("convert symlink %ld(%s) of size %ld\n", 158 inumber, symbuf, (long)dp->di_size); 159 } 160 dp = ginode(inumber); 161 memmove(dp->di_shortlink, symbuf, (long)dp->di_size); 162 dp->di_blocks = 0; 163 inodirty(); 164 } 165 /* 166 * Fake ndb value so direct/indirect block checks below 167 * will detect any garbage after symlink string. 168 */ 169 if (dp->di_size < sblock.fs_maxsymlinklen || 170 dp->di_blocks == 0) { 171 ndb = howmany(dp->di_size, sizeof(ufs_daddr_t)); 172 if (ndb > NDADDR) { 173 j = ndb - NDADDR; 174 for (ndb = 1; j > 1; j--) 175 ndb *= NINDIR(&sblock); 176 ndb += NDADDR; 177 } 178 } 179 } 180 for (j = ndb; j < NDADDR; j++) 181 if (dp->di_db[j] != 0) { 182 if (debug) 183 printf("bad direct addr: %ld\n", dp->di_db[j]); 184 goto unknown; 185 } 186 for (j = 0, ndb -= NDADDR; ndb > 0; j++) 187 ndb /= NINDIR(&sblock); 188 for (; j < NIADDR; j++) 189 if (dp->di_ib[j] != 0) { 190 if (debug) 191 printf("bad indirect addr: %ld\n", 192 dp->di_ib[j]); 193 goto unknown; 194 } 195 if (ftypeok(dp) == 0) 196 goto unknown; 197 n_files++; 198 lncntp[inumber] = dp->di_nlink; 199 if (dp->di_nlink <= 0) { 200 zlnp = (struct zlncnt *)malloc(sizeof *zlnp); 201 if (zlnp == NULL) { 202 pfatal("LINK COUNT TABLE OVERFLOW"); 203 if (reply("CONTINUE") == 0) 204 exit(EEXIT); 205 } else { 206 zlnp->zlncnt = inumber; 207 zlnp->next = zlnhead; 208 zlnhead = zlnp; 209 } 210 } 211 if (mode == IFDIR) { 212 if (dp->di_size == 0) 213 statemap[inumber] = DCLEAR; 214 else 215 statemap[inumber] = DSTATE; 216 cacheino(dp, inumber); 217 } else 218 statemap[inumber] = FSTATE; 219 typemap[inumber] = IFTODT(mode); 220 if (doinglevel2 && 221 (dp->di_ouid != (u_short)-1 || dp->di_ogid != (u_short)-1)) { 222 dp = ginode(inumber); 223 dp->di_uid = dp->di_ouid; 224 dp->di_ouid = -1; 225 dp->di_gid = dp->di_ogid; 226 dp->di_ogid = -1; 227 inodirty(); 228 } 229 badblk = dupblk = 0; 230 idesc->id_number = inumber; 231 (void)ckinode(dp, idesc); 232 idesc->id_entryno *= btodb(sblock.fs_fsize); 233 if (dp->di_blocks != idesc->id_entryno) { 234 pwarn("INCORRECT BLOCK COUNT I=%lu (%ld should be %ld)", 235 inumber, dp->di_blocks, idesc->id_entryno); 236 if (preen) 237 printf(" (CORRECTED)\n"); 238 else if (reply("CORRECT") == 0) 239 return; 240 dp = ginode(inumber); 241 dp->di_blocks = idesc->id_entryno; 242 inodirty(); 243 } 244 return; 245 unknown: 246 pfatal("UNKNOWN FILE TYPE I=%lu", inumber); 247 statemap[inumber] = FCLEAR; 248 if (reply("CLEAR") == 1) { 249 statemap[inumber] = USTATE; 250 dp = ginode(inumber); 251 clearinode(dp); 252 inodirty(); 253 } 254 } 255 256 int 257 pass1check(idesc) 258 register struct inodesc *idesc; 259 { 260 int res = KEEPON; 261 int anyout, nfrags; 262 ufs_daddr_t blkno = idesc->id_blkno; 263 register struct dups *dlp; 264 struct dups *new; 265 266 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 267 blkerror(idesc->id_number, "BAD", blkno); 268 if (badblk++ >= MAXBAD) { 269 pwarn("EXCESSIVE BAD BLKS I=%lu", 270 idesc->id_number); 271 if (preen) 272 printf(" (SKIPPING)\n"); 273 else if (reply("CONTINUE") == 0) 274 exit(EEXIT); 275 return (STOP); 276 } 277 } 278 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 279 if (anyout && chkrange(blkno, 1)) { 280 res = SKIP; 281 } else if (!testbmap(blkno)) { 282 n_blks++; 283 setbmap(blkno); 284 } else { 285 blkerror(idesc->id_number, "DUP", blkno); 286 if (dupblk++ >= MAXDUP) { 287 pwarn("EXCESSIVE DUP BLKS I=%lu", 288 idesc->id_number); 289 if (preen) 290 printf(" (SKIPPING)\n"); 291 else if (reply("CONTINUE") == 0) 292 exit(EEXIT); 293 return (STOP); 294 } 295 new = (struct dups *)malloc(sizeof(struct dups)); 296 if (new == NULL) { 297 pfatal("DUP TABLE OVERFLOW."); 298 if (reply("CONTINUE") == 0) 299 exit(EEXIT); 300 return (STOP); 301 } 302 new->dup = blkno; 303 if (muldup == 0) { 304 duplist = muldup = new; 305 new->next = 0; 306 } else { 307 new->next = muldup->next; 308 muldup->next = new; 309 } 310 for (dlp = duplist; dlp != muldup; dlp = dlp->next) 311 if (dlp->dup == blkno) 312 break; 313 if (dlp == muldup && dlp->dup != blkno) 314 muldup = new; 315 } 316 /* 317 * count the number of blocks found in id_entryno 318 */ 319 idesc->id_entryno++; 320 } 321 return (res); 322 } 323