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.5 (Berkeley) 04/27/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 bzero((char *)&idesc, 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 (bcmp((char *)dp->di_db, (char *)zino.di_db, 82 NDADDR * sizeof(ufs_daddr_t)) || 83 bcmp((char *)dp->di_ib, (char *)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 bcopy(symbuf, (caddr_t)dp->di_shortlink, 135 (long)dp->di_size); 136 dp->di_blocks = 0; 137 inodirty(); 138 } 139 /* 140 * Fake ndb value so direct/indirect block checks below 141 * will detect any garbage after symlink string. 142 */ 143 if (dp->di_size < sblock.fs_maxsymlinklen) { 144 ndb = howmany(dp->di_size, sizeof(ufs_daddr_t)); 145 if (ndb > NDADDR) { 146 j = ndb - NDADDR; 147 for (ndb = 1; j > 1; j--) 148 ndb *= NINDIR(&sblock); 149 ndb += NDADDR; 150 } 151 } 152 } 153 for (j = ndb; j < NDADDR; j++) 154 if (dp->di_db[j] != 0) { 155 if (debug) 156 printf("bad direct addr: %ld\n", dp->di_db[j]); 157 goto unknown; 158 } 159 for (j = 0, ndb -= NDADDR; ndb > 0; j++) 160 ndb /= NINDIR(&sblock); 161 for (; j < NIADDR; j++) 162 if (dp->di_ib[j] != 0) { 163 if (debug) 164 printf("bad indirect addr: %ld\n", 165 dp->di_ib[j]); 166 goto unknown; 167 } 168 if (ftypeok(dp) == 0) 169 goto unknown; 170 n_files++; 171 lncntp[inumber] = dp->di_nlink; 172 if (dp->di_nlink <= 0) { 173 zlnp = (struct zlncnt *)malloc(sizeof *zlnp); 174 if (zlnp == NULL) { 175 pfatal("LINK COUNT TABLE OVERFLOW"); 176 if (reply("CONTINUE") == 0) 177 exit(EEXIT); 178 } else { 179 zlnp->zlncnt = inumber; 180 zlnp->next = zlnhead; 181 zlnhead = zlnp; 182 } 183 } 184 if (mode == IFDIR) { 185 if (dp->di_size == 0) 186 statemap[inumber] = DCLEAR; 187 else 188 statemap[inumber] = DSTATE; 189 cacheino(dp, inumber); 190 } else 191 statemap[inumber] = FSTATE; 192 typemap[inumber] = IFTODT(mode); 193 if (doinglevel2 && 194 (dp->di_ouid != (u_short)-1 || dp->di_ogid != (u_short)-1)) { 195 dp = ginode(inumber); 196 dp->di_uid = dp->di_ouid; 197 dp->di_ouid = -1; 198 dp->di_gid = dp->di_ogid; 199 dp->di_ogid = -1; 200 inodirty(); 201 } 202 badblk = dupblk = 0; 203 idesc->id_number = inumber; 204 (void)ckinode(dp, idesc); 205 idesc->id_entryno *= btodb(sblock.fs_fsize); 206 if (dp->di_blocks != idesc->id_entryno) { 207 pwarn("INCORRECT BLOCK COUNT I=%lu (%ld should be %ld)", 208 inumber, dp->di_blocks, idesc->id_entryno); 209 if (preen) 210 printf(" (CORRECTED)\n"); 211 else if (reply("CORRECT") == 0) 212 return; 213 dp = ginode(inumber); 214 dp->di_blocks = idesc->id_entryno; 215 inodirty(); 216 } 217 return; 218 unknown: 219 pfatal("UNKNOWN FILE TYPE I=%lu", inumber); 220 statemap[inumber] = FCLEAR; 221 if (reply("CLEAR") == 1) { 222 statemap[inumber] = USTATE; 223 dp = ginode(inumber); 224 clearinode(dp); 225 inodirty(); 226 } 227 } 228 229 int 230 pass1check(idesc) 231 register struct inodesc *idesc; 232 { 233 int res = KEEPON; 234 int anyout, nfrags; 235 ufs_daddr_t blkno = idesc->id_blkno; 236 register struct dups *dlp; 237 struct dups *new; 238 239 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 240 blkerror(idesc->id_number, "BAD", blkno); 241 if (badblk++ >= MAXBAD) { 242 pwarn("EXCESSIVE BAD BLKS I=%lu", 243 idesc->id_number); 244 if (preen) 245 printf(" (SKIPPING)\n"); 246 else if (reply("CONTINUE") == 0) 247 exit(EEXIT); 248 return (STOP); 249 } 250 } 251 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 252 if (anyout && chkrange(blkno, 1)) { 253 res = SKIP; 254 } else if (!testbmap(blkno)) { 255 n_blks++; 256 setbmap(blkno); 257 } else { 258 blkerror(idesc->id_number, "DUP", blkno); 259 if (dupblk++ >= MAXDUP) { 260 pwarn("EXCESSIVE DUP BLKS I=%lu", 261 idesc->id_number); 262 if (preen) 263 printf(" (SKIPPING)\n"); 264 else if (reply("CONTINUE") == 0) 265 exit(EEXIT); 266 return (STOP); 267 } 268 new = (struct dups *)malloc(sizeof(struct dups)); 269 if (new == NULL) { 270 pfatal("DUP TABLE OVERFLOW."); 271 if (reply("CONTINUE") == 0) 272 exit(EEXIT); 273 return (STOP); 274 } 275 new->dup = blkno; 276 if (muldup == 0) { 277 duplist = muldup = new; 278 new->next = 0; 279 } else { 280 new->next = muldup->next; 281 muldup->next = new; 282 } 283 for (dlp = duplist; dlp != muldup; dlp = dlp->next) 284 if (dlp->dup == blkno) 285 break; 286 if (dlp == muldup && dlp->dup != blkno) 287 muldup = new; 288 } 289 /* 290 * count the number of blocks found in id_entryno 291 */ 292 idesc->id_entryno++; 293 } 294 return (res); 295 } 296