pass1.c revision 1.2 1 /* $Id: pass1.c,v 1.2 1999/03/24 05:32:23 nathanw Exp $ */
2
3 /*
4 * Copyright (c) 1980, 1986, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/param.h>
37 #include <sys/time.h>
38 #include <ufs/ufs/dinode.h>
39 #include <ufs/ufs/dir.h>
40 #include <sys/mount.h>
41 #include <ufs/lfs/lfs.h>
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46
47 #include <signal.h>
48
49 #include "fsck.h"
50 #include "extern.h"
51 #include "fsutil.h"
52
53 extern struct dinode **din_table;
54
55 static daddr_t badblk;
56 static daddr_t dupblk;
57 static void checkinode __P((ino_t, struct inodesc *));
58
59 static void bmapcheck(void)
60 {
61 int i;
62
63 if(testbmap(0))
64 raise(1);
65 for(i=0;i<maxfsblock;i++)
66 if(testbmap(i) > maxino)
67 raise(1);
68 }
69
70 void
71 pass1()
72 {
73 ino_t inumber;
74 int total_segments;
75 struct inodesc idesc;
76 struct dinode *idinode, *tinode;
77 struct ifile *ifp;
78 CLEANERINFO *cp;
79
80 idinode = lfs_ifind(&sblock,sblock.lfs_ifile,&ifblock);
81
82 /*
83 * We now have the ifile's inode block in core. Read out the
84 * number of segments.
85 */
86 #if 1
87 if(pbp != 0)
88 pbp->b_flags &= ~B_INUSE;
89 pbp = getddblk(idinode->di_db[0], sblock.lfs_bsize);
90
91 cp = (CLEANERINFO *)(pbp->b_un.b_buf);
92 #endif
93 total_segments = sblock.lfs_size / sblock.lfs_bsize;
94
95 /*
96 * Find all allocated blocks, initialize numdirs.
97 */
98 memset(&idesc, 0, sizeof(struct inodesc));
99 idesc.id_type = ADDR;
100 idesc.id_func = pass1check;
101 idesc.id_lblkno = 0;
102 inumber = 0;
103 n_files = n_blks = 0;
104
105 /* find a value for numdirs */
106 numdirs=0;
107 for(inumber=0; inumber < maxino; inumber++) {
108 tinode = lfs_ginode(inumber);
109 #if 0 /* debug */
110 ifp = lfs_ientry(inumber);
111 if(ifp)
112 printf("Inode %lu has disk address %lx\n",
113 inumber, ifp->if_daddr);
114 #endif
115 if(tinode && (tinode->di_mode & IFMT)==IFDIR)
116 numdirs++;
117 }
118
119 /* from setup.c */
120 inplast = 0;
121 listmax = numdirs + 10;
122 inpsort = (struct inoinfo **)calloc((unsigned)listmax,
123 sizeof(struct inoinfo *));
124 inphead = (struct inoinfo **)calloc((unsigned)numdirs,
125 sizeof(struct inoinfo *));
126 if (inpsort == NULL || inphead == NULL) {
127 printf("cannot alloc %lu bytes for inphead\n",
128 (unsigned long)numdirs * sizeof(struct inoinfo *));
129 exit(1);
130 }
131
132 /* resetinodebuf(); */
133
134 for(inumber=ROOTINO; inumber <= maxino; inumber++) {
135 ifp = lfs_ientry(inumber);
136 if(ifp && ifp->if_daddr != LFS_UNUSED_DADDR) {
137 checkinode(inumber, &idesc);
138 #if 1
139 if(statemap[inumber]!=USTATE && din_table[inumber]==NULL) {
140 pwarn("Inode %d not claimed by any segment (belongs to %d)\n",inumber,datosn(&sblock,ifp->if_daddr));
141 }
142 #endif
143 } else
144 statemap[inumber] = USTATE;
145 }
146
147 bmapcheck();
148 /* freeinodebuf(); */
149 }
150
151 static void
152 checkinode(inumber, idesc)
153 ino_t inumber;
154 register struct inodesc *idesc;
155 {
156 register struct dinode *dp;
157 struct zlncnt *zlnp;
158 int ndb, j;
159 mode_t mode;
160 char *symbuf;
161
162 /* dp = getnextinode(inumber); */
163 dp = lfs_ginode(inumber);
164
165 if(dp==NULL) {
166 /* pwarn("Could not find inode %ld\n",(long)inumber); */
167 statemap[inumber]=USTATE;
168 return;
169 }
170
171 mode = dp->di_mode & IFMT;
172
173 /* XXX - LFS doesn't have this particular problem (?) */
174 if (mode == 0) {
175 if (memcmp(dp->di_db, zino.di_db, NDADDR * sizeof(daddr_t)) ||
176 memcmp(dp->di_ib, zino.di_ib, NIADDR * sizeof(daddr_t)) ||
177 dp->di_mode || dp->di_size) {
178 pwarn("mode=o%o, ifmt=o%o\n", dp->di_mode, mode);
179 pfatal("PARTIALLY ALLOCATED INODE I=%u", inumber);
180 if (reply("CLEAR") == 1) {
181 dp = ginode(inumber);
182 clearinode(dp);
183 inodirty();
184 }
185 }
186 statemap[inumber] = USTATE;
187 return;
188 }
189 lastino = inumber;
190 if (/* dp->di_size < 0 || */
191 dp->di_size + sblock.lfs_bsize - 1 < dp->di_size) {
192 if (debug)
193 printf("bad size %qu:", (unsigned long long)dp->di_size);
194 goto unknown;
195 }
196 if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
197 dp = ginode(inumber);
198 dp->di_size = sblock.lfs_fsize;
199 dp->di_mode = IFREG|0600;
200 inodirty();
201 }
202 ndb = howmany(dp->di_size, sblock.lfs_bsize);
203 if (ndb < 0) {
204 if (debug)
205 printf("bad size %qu ndb %d:",
206 (unsigned long long)dp->di_size, ndb);
207 goto unknown;
208 }
209 if (mode == IFBLK || mode == IFCHR)
210 ndb++;
211 if (mode == IFLNK) {
212 /*
213 * Note that the old fastlink format always had di_blocks set
214 * to 0. Other than that we no longer use the `spare' field
215 * (which is now the extended uid) for sanity checking, the
216 * new format is the same as the old. We simply ignore the
217 * conversion altogether. - mycroft, 19MAY1994
218 */
219 if (doinglevel2 &&
220 dp->di_size > 0 && dp->di_size < MAXSYMLINKLEN &&
221 dp->di_blocks != 0) {
222 symbuf = alloca(secsize);
223 if (bread(fsreadfd, symbuf,
224 fsbtodb(&sblock, dp->di_db[0]),
225 (long)secsize) != 0)
226 errexit("cannot read symlink");
227 if (debug) {
228 symbuf[dp->di_size] = 0;
229 printf("convert symlink %d(%s) of size %qd\n",
230 inumber, symbuf, (long long)dp->di_size);
231 }
232 dp = ginode(inumber);
233 memcpy(dp->di_shortlink, symbuf, (long)dp->di_size);
234 dp->di_blocks = 0;
235 inodirty();
236 }
237 /*
238 * Fake ndb value so direct/indirect block checks below
239 * will detect any garbage after symlink string.
240 */
241 if (dp->di_size < sblock.lfs_maxsymlinklen ||
242 (sblock.lfs_maxsymlinklen == 0 && dp->di_blocks == 0)) {
243 ndb = howmany(dp->di_size, sizeof(daddr_t));
244 if (ndb > NDADDR) {
245 j = ndb - NDADDR;
246 for (ndb = 1; j > 1; j--)
247 ndb *= NINDIR(&sblock);
248 ndb += NDADDR;
249 }
250 }
251 }
252 for (j = ndb; j < NDADDR; j++)
253 if (dp->di_db[j] != 0) {
254 if (debug)
255 printf("bad direct addr: %d\n", dp->di_db[j]);
256 goto unknown;
257 }
258 for (j = 0, ndb -= NDADDR; ndb > 0; j++)
259 ndb /= NINDIR(&sblock);
260 for (; j < NIADDR; j++)
261 if (dp->di_ib[j] != 0) {
262 if (debug)
263 printf("bad indirect addr: %d\n",
264 dp->di_ib[j]);
265 goto unknown;
266 }
267 if (ftypeok(dp) == 0)
268 goto unknown;
269 n_files++;
270 lncntp[inumber] = dp->di_nlink;
271 if (dp->di_nlink <= 0) {
272 zlnp = (struct zlncnt *)malloc(sizeof *zlnp);
273 if (zlnp == NULL) {
274 pfatal("LINK COUNT TABLE OVERFLOW");
275 if (reply("CONTINUE") == 0)
276 errexit("%s", "");
277 } else {
278 zlnp->zlncnt = inumber;
279 zlnp->next = zlnhead;
280 zlnhead = zlnp;
281 }
282 }
283 if (mode == IFDIR) {
284 if (dp->di_size == 0)
285 statemap[inumber] = DCLEAR;
286 else
287 statemap[inumber] = DSTATE;
288 cacheino(dp, inumber);
289 } else
290 statemap[inumber] = FSTATE;
291 typemap[inumber] = IFTODT(mode);
292 #if 0 /* FFS */
293 if (doinglevel2 &&
294 (dp->di_ouid != (u_short)-1 || dp->di_ogid != (u_short)-1)) {
295 dp = ginode(inumber);
296 dp->di_uid = dp->di_ouid;
297 dp->di_ouid = -1;
298 dp->di_gid = dp->di_ogid;
299 dp->di_ogid = -1;
300 inodirty();
301 }
302 #endif
303 badblk = dupblk = 0;
304 idesc->id_number = inumber;
305 (void)ckinode(dp, idesc);
306 idesc->id_entryno *= btodb(sblock.lfs_fsize);
307 if (dp->di_blocks != idesc->id_entryno) {
308 pwarn("INCORRECT BLOCK COUNT I=%u (%d should be %d)",
309 inumber, dp->di_blocks, idesc->id_entryno);
310 if (preen)
311 printf(" (CORRECTED)\n");
312 else if (reply("CORRECT") == 0)
313 return;
314 dp = ginode(inumber);
315 dp->di_blocks = idesc->id_entryno;
316 inodirty();
317 }
318 return;
319 unknown:
320 pfatal("UNKNOWN FILE TYPE I=%u", inumber);
321 statemap[inumber] = FCLEAR;
322 if (reply("CLEAR") == 1) {
323 statemap[inumber] = USTATE;
324 dp = ginode(inumber);
325 clearinode(dp);
326 inodirty();
327 }
328 }
329
330 int
331 pass1check(idesc)
332 register struct inodesc *idesc;
333 {
334 int res = KEEPON;
335 int anyout, nfrags;
336 daddr_t blkno = idesc->id_blkno;
337 register struct dups *dlp;
338 struct dups *new;
339
340 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
341 blkerror(idesc->id_number, "BAD", blkno);
342 if (badblk++ >= MAXBAD) {
343 pwarn("EXCESSIVE BAD BLKS I=%u",
344 idesc->id_number);
345 if (preen)
346 printf(" (SKIPPING)\n");
347 else if (reply("CONTINUE") == 0)
348 errexit("%s", "");
349 return (STOP);
350 }
351 }
352 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
353 if (anyout && chkrange(blkno, 1)) {
354 res = SKIP;
355 } else if (!testbmap(blkno)) {
356 n_blks++;
357 #ifndef VERBOSE_BLOCKMAP
358 setbmap(blkno);
359 #else
360 #if 0
361 if(idesc->id_number > 10000)
362 printf("Oops, inum was %d\n", idesc->id_number);
363 #endif
364 setbmap(blkno,idesc->id_number);
365 #endif
366 } else {
367 blkerror(idesc->id_number, "DUP", blkno);
368 #ifdef VERBOSE_BLOCKMAP
369 pwarn("(lbn %d: Holder is %d)\n", idesc->id_lblkno,
370 testbmap(blkno));
371 #endif
372 if (dupblk++ >= MAXDUP) {
373 pwarn("EXCESSIVE DUP BLKS I=%u",
374 idesc->id_number);
375 if (preen)
376 printf(" (SKIPPING)\n");
377 else if (reply("CONTINUE") == 0)
378 errexit("%s", "");
379 return (STOP);
380 }
381 new = (struct dups *)malloc(sizeof(struct dups));
382 if (new == NULL) {
383 pfatal("DUP TABLE OVERFLOW.");
384 if (reply("CONTINUE") == 0)
385 errexit("%s", "");
386 return (STOP);
387 }
388 new->dup = blkno;
389 if (muldup == 0) {
390 duplist = muldup = new;
391 new->next = 0;
392 } else {
393 new->next = muldup->next;
394 muldup->next = new;
395 }
396 for (dlp = duplist; dlp != muldup; dlp = dlp->next)
397 if (dlp->dup == blkno)
398 break;
399 if (dlp == muldup && dlp->dup != blkno)
400 muldup = new;
401 }
402 /*
403 * count the number of blocks found in id_entryno
404 */
405 idesc->id_entryno ++;
406 }
407 return (res);
408 }
409