pass1.c revision 37236
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 35static 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 50static ufs_daddr_t badblk; 51static ufs_daddr_t dupblk; 52 53static void checkinode __P((ino_t inumber, struct inodesc *)); 54 55void 56pass1() 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 94static void 95checkinode(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 %lu(%s) of size %ld\n", 158 (u_long)inumber, symbuf, 159 (long)dp->di_size); 160 } 161 dp = ginode(inumber); 162 memmove(dp->di_shortlink, symbuf, (long)dp->di_size); 163 dp->di_blocks = 0; 164 inodirty(); 165 } 166 /* 167 * Fake ndb value so direct/indirect block checks below 168 * will detect any garbage after symlink string. 169 */ 170 if (dp->di_size < sblock.fs_maxsymlinklen || 171 dp->di_blocks == 0) { 172 ndb = howmany(dp->di_size, sizeof(ufs_daddr_t)); 173 if (ndb > NDADDR) { 174 j = ndb - NDADDR; 175 for (ndb = 1; j > 1; j--) 176 ndb *= NINDIR(&sblock); 177 ndb += NDADDR; 178 } 179 } 180 } 181 for (j = ndb; j < NDADDR; j++) 182 if (dp->di_db[j] != 0) { 183 if (debug) 184 printf("bad direct addr: %ld\n", 185 (long)dp->di_db[j]); 186 goto unknown; 187 } 188 for (j = 0, ndb -= NDADDR; ndb > 0; j++) 189 ndb /= NINDIR(&sblock); 190 for (; j < NIADDR; j++) 191 if (dp->di_ib[j] != 0) { 192 if (debug) 193 printf("bad indirect addr: %ld\n", 194 (long)dp->di_ib[j]); 195 goto unknown; 196 } 197 if (ftypeok(dp) == 0) 198 goto unknown; 199 n_files++; 200 lncntp[inumber] = dp->di_nlink; 201 if (dp->di_nlink <= 0) { 202 zlnp = (struct zlncnt *)malloc(sizeof *zlnp); 203 if (zlnp == NULL) { 204 pfatal("LINK COUNT TABLE OVERFLOW"); 205 if (reply("CONTINUE") == 0) { 206 ckfini(0); 207 exit(EEXIT); 208 } 209 } else { 210 zlnp->zlncnt = inumber; 211 zlnp->next = zlnhead; 212 zlnhead = zlnp; 213 } 214 } 215 if (mode == IFDIR) { 216 if (dp->di_size == 0) 217 statemap[inumber] = DCLEAR; 218 else 219 statemap[inumber] = DSTATE; 220 cacheino(dp, inumber); 221 } else 222 statemap[inumber] = FSTATE; 223 typemap[inumber] = IFTODT(mode); 224 if (doinglevel2 && 225 (dp->di_ouid != (u_short)-1 || dp->di_ogid != (u_short)-1)) { 226 dp = ginode(inumber); 227 dp->di_uid = dp->di_ouid; 228 dp->di_ouid = -1; 229 dp->di_gid = dp->di_ogid; 230 dp->di_ogid = -1; 231 inodirty(); 232 } 233 badblk = dupblk = 0; 234 idesc->id_number = inumber; 235 (void)ckinode(dp, idesc); 236 idesc->id_entryno *= btodb(sblock.fs_fsize); 237 if (dp->di_blocks != idesc->id_entryno) { 238 pwarn("INCORRECT BLOCK COUNT I=%lu (%ld should be %ld)", 239 inumber, dp->di_blocks, idesc->id_entryno); 240 if (preen) 241 printf(" (CORRECTED)\n"); 242 else if (reply("CORRECT") == 0) 243 return; 244 dp = ginode(inumber); 245 dp->di_blocks = idesc->id_entryno; 246 inodirty(); 247 } 248 return; 249unknown: 250 pfatal("UNKNOWN FILE TYPE I=%lu", inumber); 251 statemap[inumber] = FCLEAR; 252 if (reply("CLEAR") == 1) { 253 statemap[inumber] = USTATE; 254 dp = ginode(inumber); 255 clearinode(dp); 256 inodirty(); 257 } 258} 259 260int 261pass1check(idesc) 262 register struct inodesc *idesc; 263{ 264 int res = KEEPON; 265 int anyout, nfrags; 266 ufs_daddr_t blkno = idesc->id_blkno; 267 register struct dups *dlp; 268 struct dups *new; 269 270 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 271 blkerror(idesc->id_number, "BAD", blkno); 272 if (badblk++ >= MAXBAD) { 273 pwarn("EXCESSIVE BAD BLKS I=%lu", 274 idesc->id_number); 275 if (preen) 276 printf(" (SKIPPING)\n"); 277 else if (reply("CONTINUE") == 0) { 278 ckfini(0); 279 exit(EEXIT); 280 } 281 return (STOP); 282 } 283 } 284 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 285 if (anyout && chkrange(blkno, 1)) { 286 res = SKIP; 287 } else if (!testbmap(blkno)) { 288 n_blks++; 289 setbmap(blkno); 290 } else { 291 blkerror(idesc->id_number, "DUP", blkno); 292 if (dupblk++ >= MAXDUP) { 293 pwarn("EXCESSIVE DUP BLKS I=%lu", 294 idesc->id_number); 295 if (preen) 296 printf(" (SKIPPING)\n"); 297 else if (reply("CONTINUE") == 0) { 298 ckfini(0); 299 exit(EEXIT); 300 } 301 return (STOP); 302 } 303 new = (struct dups *)malloc(sizeof(struct dups)); 304 if (new == NULL) { 305 pfatal("DUP TABLE OVERFLOW."); 306 if (reply("CONTINUE") == 0) { 307 ckfini(0); 308 exit(EEXIT); 309 } 310 return (STOP); 311 } 312 new->dup = blkno; 313 if (muldup == 0) { 314 duplist = muldup = new; 315 new->next = 0; 316 } else { 317 new->next = muldup->next; 318 muldup->next = new; 319 } 320 for (dlp = duplist; dlp != muldup; dlp = dlp->next) 321 if (dlp->dup == blkno) 322 break; 323 if (dlp == muldup && dlp->dup != blkno) 324 muldup = new; 325 } 326 /* 327 * count the number of blocks found in id_entryno 328 */ 329 idesc->id_entryno++; 330 } 331 return (res); 332} 333