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 (Berkeley) 06/05/93"; 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 printf("bad indirect addr: %ld\n", 159 dp->di_ib[j]); 160 goto unknown; 161 } 162 if (ftypeok(dp) == 0) 163 goto unknown; 164 n_files++; 165 lncntp[inumber] = dp->di_nlink; 166 if (dp->di_nlink <= 0) { 167 zlnp = (struct zlncnt *)malloc(sizeof *zlnp); 168 if (zlnp == NULL) { 169 pfatal("LINK COUNT TABLE OVERFLOW"); 170 if (reply("CONTINUE") == 0) 171 errexit(""); 172 } else { 173 zlnp->zlncnt = inumber; 174 zlnp->next = zlnhead; 175 zlnhead = zlnp; 176 } 177 } 178 if (mode == IFDIR) { 179 if (dp->di_size == 0) 180 statemap[inumber] = DCLEAR; 181 else 182 statemap[inumber] = DSTATE; 183 cacheino(dp, inumber); 184 } else 185 statemap[inumber] = FSTATE; 186 typemap[inumber] = IFTODT(mode); 187 if (doinglevel2 && 188 (dp->di_ouid != (u_short)-1 || dp->di_ogid != (u_short)-1)) { 189 dp = ginode(inumber); 190 dp->di_uid = dp->di_ouid; 191 dp->di_ouid = -1; 192 dp->di_gid = dp->di_ogid; 193 dp->di_ogid = -1; 194 inodirty(); 195 } 196 badblk = dupblk = 0; 197 idesc->id_number = inumber; 198 (void)ckinode(dp, idesc); 199 idesc->id_entryno *= btodb(sblock.fs_fsize); 200 if (dp->di_blocks != idesc->id_entryno) { 201 pwarn("INCORRECT BLOCK COUNT I=%lu (%ld should be %ld)", 202 inumber, dp->di_blocks, idesc->id_entryno); 203 if (preen) 204 printf(" (CORRECTED)\n"); 205 else if (reply("CORRECT") == 0) 206 return; 207 dp = ginode(inumber); 208 dp->di_blocks = idesc->id_entryno; 209 inodirty(); 210 } 211 return; 212 unknown: 213 pfatal("UNKNOWN FILE TYPE I=%lu", inumber); 214 statemap[inumber] = FCLEAR; 215 if (reply("CLEAR") == 1) { 216 statemap[inumber] = USTATE; 217 dp = ginode(inumber); 218 clearinode(dp); 219 inodirty(); 220 } 221 } 222 223 pass1check(idesc) 224 register struct inodesc *idesc; 225 { 226 int res = KEEPON; 227 int anyout, nfrags; 228 daddr_t blkno = idesc->id_blkno; 229 register struct dups *dlp; 230 struct dups *new; 231 232 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 233 blkerror(idesc->id_number, "BAD", blkno); 234 if (badblk++ >= MAXBAD) { 235 pwarn("EXCESSIVE BAD BLKS I=%lu", 236 idesc->id_number); 237 if (preen) 238 printf(" (SKIPPING)\n"); 239 else if (reply("CONTINUE") == 0) 240 errexit(""); 241 return (STOP); 242 } 243 } 244 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 245 if (anyout && chkrange(blkno, 1)) { 246 res = SKIP; 247 } else if (!testbmap(blkno)) { 248 n_blks++; 249 setbmap(blkno); 250 } else { 251 blkerror(idesc->id_number, "DUP", blkno); 252 if (dupblk++ >= MAXDUP) { 253 pwarn("EXCESSIVE DUP BLKS I=%lu", 254 idesc->id_number); 255 if (preen) 256 printf(" (SKIPPING)\n"); 257 else if (reply("CONTINUE") == 0) 258 errexit(""); 259 return (STOP); 260 } 261 new = (struct dups *)malloc(sizeof(struct dups)); 262 if (new == NULL) { 263 pfatal("DUP TABLE OVERFLOW."); 264 if (reply("CONTINUE") == 0) 265 errexit(""); 266 return (STOP); 267 } 268 new->dup = blkno; 269 if (muldup == 0) { 270 duplist = muldup = new; 271 new->next = 0; 272 } else { 273 new->next = muldup->next; 274 muldup->next = new; 275 } 276 for (dlp = duplist; dlp != muldup; dlp = dlp->next) 277 if (dlp->dup == blkno) 278 break; 279 if (dlp == muldup && dlp->dup != blkno) 280 muldup = new; 281 } 282 /* 283 * count the number of blocks found in id_entryno 284 */ 285 idesc->id_entryno++; 286 } 287 return (res); 288 } 289