pass1.c revision 1.6 1 /* $NetBSD: pass1.c,v 1.6 2000/05/23 01:48:54 perseant 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 SEGUSE *seg_table;
54 extern daddr_t *din_table;
55
56 static daddr_t badblk;
57 static daddr_t dupblk;
58 static void checkinode(ino_t, struct inodesc *);
59 static int i_d_cmp(const void *, const void *);
60
61 static void
62 bmapcheck(void)
63 {
64 int i;
65
66 if (testbmap(0))
67 raise(1);
68 for (i = 0; i < maxfsblock; i++)
69 if (testbmap(i) > maxino)
70 raise(1);
71 }
72
73 struct ino_daddr {
74 ino_t ino;
75 daddr_t daddr;
76 };
77
78 static int
79 i_d_cmp(const void *va, const void *vb)
80 {
81 struct ino_daddr *a, *b;
82
83 a = *((struct ino_daddr **)va);
84 b = *((struct ino_daddr **)vb);
85
86 if (a->daddr == b->daddr) {
87 return (a->ino - b->ino);
88 }
89 if (a->daddr > b->daddr) {
90 return 1;
91 }
92 return -1;
93 }
94
95 void
96 pass1()
97 {
98 ino_t inumber;
99 int i, total_segments;
100 struct inodesc idesc;
101 struct dinode *idinode, *tinode;
102 struct ifile *ifp;
103 CLEANERINFO *cp;
104 struct bufarea *bp;
105 struct ino_daddr **dins;
106
107 idinode = lfs_difind(&sblock, sblock.lfs_ifile, &ifblock);
108
109 /*
110 * We now have the ifile's inode block in core. Read out the
111 * number of segments.
112 */
113 #if 1
114 if (pbp != 0)
115 pbp->b_flags &= ~B_INUSE;
116 pbp = getddblk(idinode->di_db[0], sblock.lfs_bsize);
117
118 cp = (CLEANERINFO *)(pbp->b_un.b_buf);
119 #endif
120 total_segments = sblock.lfs_size / sblock.lfs_bsize;
121
122 /*
123 * Find all allocated blocks, initialize numdirs.
124 */
125 memset(&idesc, 0, sizeof(struct inodesc));
126 idesc.id_type = ADDR;
127 idesc.id_func = pass1check;
128 idesc.id_lblkno = 0;
129 inumber = 0;
130 n_files = n_blks = 0;
131
132 if (debug)
133 printf("creating inode address table...\n");
134 /* Sort by daddr */
135 dins = (struct ino_daddr **)malloc((maxino + 1) * sizeof(*dins));
136 for (i = 0; i <= maxino; i++) {
137 dins[i] = malloc(sizeof(**dins));
138 dins[i]->ino = i;
139 dins[i]->daddr = lfs_ino_daddr(i);
140 }
141 qsort(dins, maxino + 1, sizeof(*dins), i_d_cmp);
142
143 /* find a value for numdirs, fill in din_table */
144 if (debug)
145 printf("counting dirs...\n");
146 numdirs = 0;
147 for (i = 0; i <= maxino; i++) {
148 inumber = dins[i]->ino;
149 if (inumber == 0 || dins[i]->daddr == 0)
150 continue;
151 tinode = lfs_ginode(inumber);
152 if (tinode && (tinode->di_mode & IFMT) == IFDIR)
153 numdirs++;
154 }
155
156 /* from setup.c */
157 inplast = 0;
158 listmax = numdirs + 10;
159 inpsort = (struct inoinfo **)calloc((unsigned) listmax,
160 sizeof(struct inoinfo *));
161 inphead = (struct inoinfo **)calloc((unsigned) numdirs,
162 sizeof(struct inoinfo *));
163 if (inpsort == NULL || inphead == NULL) {
164 printf("cannot alloc %lu bytes for inphead\n",
165 (unsigned long)numdirs * sizeof(struct inoinfo *));
166 exit(1);
167 }
168 /* resetinodebuf(); */
169 if (debug)
170 printf("counting blocks...\n");
171 for (i = 0; i <= maxino; i++) {
172 inumber = dins[i]->ino;
173 if (inumber == 0 || dins[i]->daddr == 0)
174 continue;
175 ifp = lfs_ientry(inumber, &bp);
176 if (ifp && ifp->if_daddr != LFS_UNUSED_DADDR) {
177 bp->b_flags &= ~B_INUSE;
178 checkinode(inumber, &idesc);
179 } else {
180 bp->b_flags &= ~B_INUSE;
181 statemap[inumber] = USTATE;
182 }
183 free(dins[i]);
184 }
185 free(dins);
186
187 bmapcheck();
188 /* freeinodebuf(); */
189 }
190
191 static void
192 checkinode(ino_t inumber, struct inodesc * idesc)
193 {
194 register struct dinode *dp;
195 struct zlncnt *zlnp;
196 int ndb, j;
197 mode_t mode;
198 char *symbuf;
199
200 /* dp = getnextinode(inumber); */
201 dp = lfs_ginode(inumber);
202
203 if (dp == NULL) {
204 /* pwarn("Could not find inode %ld\n",(long)inumber); */
205 statemap[inumber] = USTATE;
206 return;
207 }
208 mode = dp->di_mode & IFMT;
209
210 /* XXX - LFS doesn't have this particular problem (?) */
211 if (mode == 0) {
212 if (memcmp(dp->di_db, zino.di_db, NDADDR * sizeof(daddr_t)) ||
213 memcmp(dp->di_ib, zino.di_ib, NIADDR * sizeof(daddr_t)) ||
214 dp->di_mode || dp->di_size) {
215 pwarn("mode=o%o, ifmt=o%o\n", dp->di_mode, mode);
216 pfatal("PARTIALLY ALLOCATED INODE I=%u", inumber);
217 if (reply("CLEAR") == 1) {
218 dp = ginode(inumber);
219 clearinode(dp);
220 inodirty();
221 }
222 }
223 statemap[inumber] = USTATE;
224 return;
225 }
226 lastino = inumber;
227 if ( /* dp->di_size < 0 || */
228 dp->di_size + sblock.lfs_bsize - 1 < dp->di_size) {
229 if (debug)
230 printf("bad size %qu:", (unsigned long long)dp->di_size);
231 goto unknown;
232 }
233 if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
234 dp = ginode(inumber);
235 dp->di_size = sblock.lfs_fsize;
236 dp->di_mode = IFREG | 0600;
237 inodirty();
238 }
239 ndb = howmany(dp->di_size, sblock.lfs_bsize);
240 if (ndb < 0) {
241 if (debug)
242 printf("bad size %qu ndb %d:",
243 (unsigned long long)dp->di_size, ndb);
244 goto unknown;
245 }
246 if (mode == IFBLK || mode == IFCHR)
247 ndb++;
248 if (mode == IFLNK) {
249 /*
250 * Note that the old fastlink format always had di_blocks set
251 * to 0. Other than that we no longer use the `spare' field
252 * (which is now the extended uid)for sanity checking, the
253 * new format is the same as the old. We simply ignore the
254 * conversion altogether. - mycroft, 19MAY1994
255 */
256 if (doinglevel2 &&
257 dp->di_size > 0 && dp->di_size < MAXSYMLINKLEN &&
258 dp->di_blocks != 0) {
259 symbuf = alloca(secsize);
260 if (bread(fsreadfd, symbuf,
261 fsbtodb(&sblock, dp->di_db[0]),
262 (long)secsize) != 0)
263 errexit("cannot read symlink");
264 if (debug) {
265 symbuf[dp->di_size] = 0;
266 printf("convert symlink %d(%s)of size %qd\n",
267 inumber, symbuf, (long long)dp->di_size);
268 }
269 dp = ginode(inumber);
270 memcpy(dp->di_shortlink, symbuf, (long)dp->di_size);
271 dp->di_blocks = 0;
272 inodirty();
273 }
274 /*
275 * Fake ndb value so direct/indirect block checks below
276 * will detect any garbage after symlink string.
277 */
278 if (dp->di_size < sblock.lfs_maxsymlinklen ||
279 (sblock.lfs_maxsymlinklen == 0 && dp->di_blocks == 0)) {
280 ndb = howmany(dp->di_size, sizeof(daddr_t));
281 if (ndb > NDADDR) {
282 j = ndb - NDADDR;
283 for (ndb = 1; j > 1; j--)
284 ndb *= NINDIR(&sblock);
285 ndb += NDADDR;
286 }
287 }
288 }
289 for (j = ndb; j < NDADDR; j++)
290 if (dp->di_db[j] != 0) {
291 if (debug)
292 printf("bad direct addr: %d\n", dp->di_db[j]);
293 goto unknown;
294 }
295 for (j = 0, ndb -= NDADDR; ndb > 0; j++)
296 ndb /= NINDIR(&sblock);
297 for (; j < NIADDR; j++)
298 if (dp->di_ib[j] != 0) {
299 if (debug)
300 printf("bad indirect addr: %d\n",
301 dp->di_ib[j]);
302 /* goto unknown; */
303 }
304 if (ftypeok(dp) == 0)
305 goto unknown;
306 n_files++;
307 lncntp[inumber] = dp->di_nlink;
308 if (dp->di_nlink <= 0) {
309 zlnp = (struct zlncnt *)malloc(sizeof *zlnp);
310 if (zlnp == NULL) {
311 pfatal("LINK COUNT TABLE OVERFLOW");
312 if (reply("CONTINUE") == 0)
313 errexit("%s", "");
314 } else {
315 zlnp->zlncnt = inumber;
316 zlnp->next = zlnhead;
317 zlnhead = zlnp;
318 }
319 }
320 if (mode == IFDIR) {
321 if (dp->di_size == 0)
322 statemap[inumber] = DCLEAR;
323 else
324 statemap[inumber] = DSTATE;
325 cacheino(dp, inumber);
326 } else
327 statemap[inumber] = FSTATE;
328 typemap[inumber] = IFTODT(mode);
329 #if 0 /* FFS */
330 if (doinglevel2 &&
331 (dp->di_ouid != (u_short) - 1 || dp->di_ogid != (u_short) - 1)) {
332 dp = ginode(inumber);
333 dp->di_uid = dp->di_ouid;
334 dp->di_ouid = -1;
335 dp->di_gid = dp->di_ogid;
336 dp->di_ogid = -1;
337 inodirty();
338 }
339 #endif
340 badblk = dupblk = 0;
341 idesc->id_number = inumber;
342 (void)ckinode(dp, idesc);
343 idesc->id_entryno *= btodb(sblock.lfs_fsize);
344 if (dp->di_blocks != idesc->id_entryno) {
345 pwarn("INCORRECT BLOCK COUNT I=%u (%d should be %d)",
346 inumber, dp->di_blocks, idesc->id_entryno);
347 if (preen)
348 printf(" (CORRECTED)\n");
349 else if (reply("CORRECT") == 0)
350 return;
351 dp = ginode(inumber);
352 dp->di_blocks = idesc->id_entryno;
353 inodirty();
354 }
355 return;
356 unknown:
357 pfatal("UNKNOWN FILE TYPE I=%u", inumber);
358 statemap[inumber] = FCLEAR;
359 if (reply("CLEAR") == 1) {
360 statemap[inumber] = USTATE;
361 dp = ginode(inumber);
362 clearinode(dp);
363 inodirty();
364 }
365 }
366
367 int
368 pass1check(struct inodesc * idesc)
369 {
370 int res = KEEPON;
371 int anyout, nfrags;
372 daddr_t blkno = idesc->id_blkno;
373 register struct dups *dlp;
374 struct dups *new;
375
376 if (!testbmap(blkno)) {
377 seg_table[datosn(&sblock, blkno)].su_nbytes += idesc->id_numfrags * sblock.lfs_fsize;
378 }
379 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
380 blkerror(idesc->id_number, "BAD", blkno);
381 if (badblk++ >= MAXBAD) {
382 pwarn("EXCESSIVE BAD BLKS I=%u",
383 idesc->id_number);
384 if (preen)
385 printf(" (SKIPPING)\n");
386 else if (reply("CONTINUE") == 0)
387 errexit("%s", "");
388 return (STOP);
389 }
390 }
391 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
392 if (anyout && chkrange(blkno, 1)) {
393 res = SKIP;
394 } else if (!testbmap(blkno)) {
395 n_blks++;
396 #ifndef VERBOSE_BLOCKMAP
397 setbmap(blkno);
398 #else
399 setbmap(blkno, idesc->id_number);
400 #endif
401 } else {
402 blkerror(idesc->id_number, "DUP", blkno);
403 #ifdef VERBOSE_BLOCKMAP
404 pwarn("(lbn %d: Holder is %d)\n", idesc->id_lblkno,
405 testbmap(blkno));
406 #endif
407 if (dupblk++ >= MAXDUP) {
408 pwarn("EXCESSIVE DUP BLKS I=%u",
409 idesc->id_number);
410 if (preen)
411 printf(" (SKIPPING)\n");
412 else if (reply("CONTINUE") == 0)
413 errexit("%s", "");
414 return (STOP);
415 }
416 new = (struct dups *)malloc(sizeof(struct dups));
417 if (new == NULL) {
418 pfatal("DUP TABLE OVERFLOW.");
419 if (reply("CONTINUE") == 0)
420 errexit("%s", "");
421 return (STOP);
422 }
423 new->dup = blkno;
424 if (muldup == 0) {
425 duplist = muldup = new;
426 new->next = 0;
427 } else {
428 new->next = muldup->next;
429 muldup->next = new;
430 }
431 for (dlp = duplist; dlp != muldup; dlp = dlp->next)
432 if (dlp->dup == blkno)
433 break;
434 if (dlp == muldup && dlp->dup != blkno)
435 muldup = new;
436 }
437 /*
438 * count the number of blocks found in id_entryno
439 */
440 idesc->id_entryno++;
441 }
442 return (res);
443 }
444