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