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