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