Annotation of src/sbin/fsck_lfs/pass1.c, Revision 1.24
1.24 ! rumble 1: /* $NetBSD: pass1.c,v 1.23 2005/09/13 04:14:17 christos Exp $ */
1.1 perseant 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.
1.17 agc 15: * 3. Neither the name of the University nor the names of its contributors
1.1 perseant 16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
32: #include <sys/param.h>
33: #include <sys/time.h>
1.14 perseant 34: #include <sys/mount.h>
35: #include <sys/buf.h>
36:
37: #include <ufs/ufs/inode.h>
1.1 perseant 38: #include <ufs/ufs/dir.h>
1.14 perseant 39: #define vnode uvnode
1.1 perseant 40: #include <ufs/lfs/lfs.h>
1.14 perseant 41: #undef vnode
1.1 perseant 42:
1.14 perseant 43: #include <err.h>
1.1 perseant 44: #include <stdio.h>
45: #include <stdlib.h>
46: #include <string.h>
47:
48: #include <signal.h>
49:
1.14 perseant 50: #include "bufcache.h"
51: #include "vnode.h"
1.23 christos 52: #include "lfs_user.h"
1.14 perseant 53:
1.1 perseant 54: #include "fsck.h"
55: #include "extern.h"
56: #include "fsutil.h"
57:
1.14 perseant 58: SEGUSE *seg_table;
59: extern ufs_daddr_t *din_table;
1.1 perseant 60:
1.14 perseant 61: ufs_daddr_t badblk;
62: static ufs_daddr_t dupblk;
63: static int i_d_cmp(const void *, const void *);
1.1 perseant 64:
1.5 perseant 65: struct ino_daddr {
1.14 perseant 66: ino_t ino;
67: ufs_daddr_t daddr;
1.5 perseant 68: };
69:
70: static int
71: i_d_cmp(const void *va, const void *vb)
72: {
1.21 christos 73: const struct ino_daddr *a, *b;
1.5 perseant 74:
1.21 christos 75: a = *((const struct ino_daddr *const *) va);
76: b = *((const struct ino_daddr *const *) vb);
1.5 perseant 77:
78: if (a->daddr == b->daddr) {
79: return (a->ino - b->ino);
80: }
81: if (a->daddr > b->daddr) {
82: return 1;
83: }
84: return -1;
85: }
86:
1.1 perseant 87: void
1.19 xtraeme 88: pass1(void)
1.1 perseant 89: {
1.14 perseant 90: ino_t inumber;
91: int i;
92: struct inodesc idesc;
1.15 fvdl 93: struct ufs1_dinode *tinode;
1.14 perseant 94: struct ifile *ifp;
95: struct ubuf *bp;
1.5 perseant 96: struct ino_daddr **dins;
1.1 perseant 97:
98: /*
99: * Find all allocated blocks, initialize numdirs.
100: */
101: memset(&idesc, 0, sizeof(struct inodesc));
102: idesc.id_type = ADDR;
103: idesc.id_func = pass1check;
104: idesc.id_lblkno = 0;
105: inumber = 0;
106: n_files = n_blks = 0;
107:
1.5 perseant 108: if (debug)
1.14 perseant 109: printf("creating sorted inode address table...\n");
1.5 perseant 110: /* Sort by daddr */
1.14 perseant 111: dins = (struct ino_daddr **) malloc(maxino * sizeof(*dins));
1.24 ! rumble 112: if (dins == NULL)
! 113: err(1, NULL);
1.8 perseant 114: for (i = 0; i < maxino; i++) {
1.5 perseant 115: dins[i] = malloc(sizeof(**dins));
1.24 ! rumble 116: if (dins[i] == NULL)
! 117: err(1, NULL);
1.5 perseant 118: dins[i]->ino = i;
1.14 perseant 119: if (i == fs->lfs_ifile)
120: dins[i]->daddr = fs->lfs_idaddr;
121: else {
122: LFS_IENTRY(ifp, fs, i, bp);
123: dins[i]->daddr = ifp->if_daddr;
124: brelse(bp);
125: }
1.5 perseant 126: }
1.8 perseant 127: qsort(dins, maxino, sizeof(*dins), i_d_cmp);
1.5 perseant 128:
129: /* find a value for numdirs, fill in din_table */
130: if (debug)
131: printf("counting dirs...\n");
1.6 perseant 132: numdirs = 0;
1.8 perseant 133: for (i = 0; i < maxino; i++) {
1.5 perseant 134: inumber = dins[i]->ino;
1.6 perseant 135: if (inumber == 0 || dins[i]->daddr == 0)
1.5 perseant 136: continue;
1.14 perseant 137: tinode = ginode(inumber);
1.6 perseant 138: if (tinode && (tinode->di_mode & IFMT) == IFDIR)
1.5 perseant 139: numdirs++;
1.1 perseant 140: }
141:
142: /* from setup.c */
1.6 perseant 143: inplast = 0;
144: listmax = numdirs + 10;
1.14 perseant 145: inpsort = (struct inoinfo **) calloc((unsigned) listmax,
146: sizeof(struct inoinfo *));
147: inphead = (struct inoinfo **) calloc((unsigned) numdirs,
148: sizeof(struct inoinfo *));
1.6 perseant 149: if (inpsort == NULL || inphead == NULL) {
150: printf("cannot alloc %lu bytes for inphead\n",
1.14 perseant 151: (unsigned long) numdirs * sizeof(struct inoinfo *));
1.1 perseant 152: exit(1);
1.6 perseant 153: }
1.5 perseant 154: if (debug)
155: printf("counting blocks...\n");
1.14 perseant 156:
1.8 perseant 157: for (i = 0; i < maxino; i++) {
1.5 perseant 158: inumber = dins[i]->ino;
1.7 perseant 159: if (inumber == 0 || dins[i]->daddr == 0) {
160: statemap[inumber] = USTATE;
1.5 perseant 161: continue;
1.7 perseant 162: }
1.14 perseant 163: if (dins[i]->daddr != LFS_UNUSED_DADDR) {
1.5 perseant 164: checkinode(inumber, &idesc);
165: } else {
166: statemap[inumber] = USTATE;
167: }
168: free(dins[i]);
1.6 perseant 169: }
1.5 perseant 170: free(dins);
1.1 perseant 171: }
172:
1.14 perseant 173: void
1.6 perseant 174: checkinode(ino_t inumber, struct inodesc * idesc)
1.1 perseant 175: {
1.15 fvdl 176: struct ufs1_dinode *dp;
1.14 perseant 177: struct uvnode *vp;
178: struct zlncnt *zlnp;
179: int ndb, j;
180: mode_t mode;
1.1 perseant 181:
1.14 perseant 182: vp = vget(fs, inumber);
1.16 yamt 183: if (vp)
184: dp = VTOD(vp);
185: else
186: dp = NULL;
1.1 perseant 187:
1.6 perseant 188: if (dp == NULL) {
189: /* pwarn("Could not find inode %ld\n",(long)inumber); */
190: statemap[inumber] = USTATE;
191: return;
192: }
1.1 perseant 193: mode = dp->di_mode & IFMT;
194:
1.6 perseant 195: /* XXX - LFS doesn't have this particular problem (?) */
1.1 perseant 196: if (mode == 0) {
1.14 perseant 197: if (memcmp(dp->di_db, zino.di_db, NDADDR * sizeof(ufs_daddr_t)) ||
198: memcmp(dp->di_ib, zino.di_ib, NIADDR * sizeof(ufs_daddr_t)) ||
1.1 perseant 199: dp->di_mode || dp->di_size) {
200: pwarn("mode=o%o, ifmt=o%o\n", dp->di_mode, mode);
1.22 christos 201: pfatal("PARTIALLY ALLOCATED INODE I=%llu",
202: (unsigned long long)inumber);
1.1 perseant 203: if (reply("CLEAR") == 1) {
1.14 perseant 204: vp = vget(fs, inumber);
1.18 yamt 205: clearinode(inumber);
206: vnode_destroy(vp);
1.1 perseant 207: }
208: }
209: statemap[inumber] = USTATE;
210: return;
211: }
212: lastino = inumber;
1.14 perseant 213: if (dp->di_size < 0 || dp->di_size + fs->lfs_bsize - 1 < dp->di_size) {
1.1 perseant 214: if (debug)
1.9 lukem 215: printf("bad size %llu:",
1.14 perseant 216: (unsigned long long) dp->di_size);
1.1 perseant 217: goto unknown;
218: }
219: if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
1.14 perseant 220: vp = vget(fs, inumber);
221: dp = VTOD(vp);
222: dp->di_size = fs->lfs_fsize;
1.6 perseant 223: dp->di_mode = IFREG | 0600;
1.14 perseant 224: inodirty(VTOI(vp));
1.1 perseant 225: }
1.14 perseant 226: ndb = howmany(dp->di_size, fs->lfs_bsize);
1.1 perseant 227: if (ndb < 0) {
228: if (debug)
1.9 lukem 229: printf("bad size %llu ndb %d:",
1.14 perseant 230: (unsigned long long) dp->di_size, ndb);
1.1 perseant 231: goto unknown;
232: }
233: if (mode == IFBLK || mode == IFCHR)
234: ndb++;
235: if (mode == IFLNK) {
236: /*
237: * Fake ndb value so direct/indirect block checks below
238: * will detect any garbage after symlink string.
239: */
1.14 perseant 240: if (dp->di_size < fs->lfs_maxsymlinklen ||
241: (fs->lfs_maxsymlinklen == 0 && dp->di_blocks == 0)) {
242: ndb = howmany(dp->di_size, sizeof(ufs_daddr_t));
1.1 perseant 243: if (ndb > NDADDR) {
244: j = ndb - NDADDR;
245: for (ndb = 1; j > 1; j--)
1.14 perseant 246: ndb *= NINDIR(fs);
1.1 perseant 247: ndb += NDADDR;
248: }
249: }
250: }
251: for (j = ndb; j < NDADDR; j++)
252: if (dp->di_db[j] != 0) {
253: if (debug)
254: printf("bad direct addr: %d\n", dp->di_db[j]);
255: goto unknown;
256: }
257: for (j = 0, ndb -= NDADDR; ndb > 0; j++)
1.14 perseant 258: ndb /= NINDIR(fs);
1.1 perseant 259: for (; j < NIADDR; j++)
260: if (dp->di_ib[j] != 0) {
261: if (debug)
262: printf("bad indirect addr: %d\n",
1.14 perseant 263: dp->di_ib[j]);
1.5 perseant 264: /* goto unknown; */
1.1 perseant 265: }
266: if (ftypeok(dp) == 0)
267: goto unknown;
268: n_files++;
269: lncntp[inumber] = dp->di_nlink;
270: if (dp->di_nlink <= 0) {
1.14 perseant 271: zlnp = (struct zlncnt *) malloc(sizeof *zlnp);
1.1 perseant 272: if (zlnp == NULL) {
273: pfatal("LINK COUNT TABLE OVERFLOW");
274: if (reply("CONTINUE") == 0)
1.14 perseant 275: err(8, "%s", "");
1.1 perseant 276: } else {
277: zlnp->zlncnt = inumber;
278: zlnp->next = zlnhead;
279: zlnhead = zlnp;
280: }
281: }
282: if (mode == IFDIR) {
283: if (dp->di_size == 0)
284: statemap[inumber] = DCLEAR;
285: else
286: statemap[inumber] = DSTATE;
287: cacheino(dp, inumber);
288: } else
289: statemap[inumber] = FSTATE;
290: typemap[inumber] = IFTODT(mode);
291: badblk = dupblk = 0;
292: idesc->id_number = inumber;
1.14 perseant 293: (void) ckinode(VTOD(vp), idesc);
1.1 perseant 294: if (dp->di_blocks != idesc->id_entryno) {
1.22 christos 295: pwarn("INCORRECT BLOCK COUNT I=%llu (%d should be %d)",
296: (unsigned long long)inumber, dp->di_blocks,
297: idesc->id_entryno);
1.1 perseant 298: if (preen)
299: printf(" (CORRECTED)\n");
300: else if (reply("CORRECT") == 0)
301: return;
1.15 fvdl 302: VTOI(vp)->i_ffs1_blocks = idesc->id_entryno;
1.14 perseant 303: inodirty(VTOI(vp));
1.1 perseant 304: }
305: return;
306: unknown:
1.22 christos 307: pfatal("UNKNOWN FILE TYPE I=%llu", (unsigned long long)inumber);
1.1 perseant 308: statemap[inumber] = FCLEAR;
309: if (reply("CLEAR") == 1) {
310: statemap[inumber] = USTATE;
1.14 perseant 311: vp = vget(fs, inumber);
1.18 yamt 312: clearinode(inumber);
313: vnode_destroy(vp);
1.1 perseant 314: }
315: }
316:
317: int
1.14 perseant 318: pass1check(struct inodesc *idesc)
1.1 perseant 319: {
1.14 perseant 320: int res = KEEPON;
321: int anyout, ndblks;
322: daddr_t blkno = idesc->id_blkno;
1.20 perry 323: struct dups *dlp;
1.14 perseant 324: struct dups *new;
1.1 perseant 325:
1.14 perseant 326: if ((anyout = chkrange(blkno, fragstofsb(fs, idesc->id_numfrags))) != 0) {
1.1 perseant 327: blkerror(idesc->id_number, "BAD", blkno);
328: if (badblk++ >= MAXBAD) {
1.22 christos 329: pwarn("EXCESSIVE BAD BLKS I=%llu",
330: (unsigned long long)idesc->id_number);
1.1 perseant 331: if (preen)
332: printf(" (SKIPPING)\n");
333: else if (reply("CONTINUE") == 0)
1.14 perseant 334: err(8, "%s", "");
1.1 perseant 335: return (STOP);
336: }
1.8 perseant 337: } else if (!testbmap(blkno)) {
1.14 perseant 338: seg_table[dtosn(fs, blkno)].su_nbytes += idesc->id_numfrags * fs->lfs_fsize;
1.1 perseant 339: }
1.14 perseant 340: for (ndblks = fragstofsb(fs, idesc->id_numfrags); ndblks > 0; blkno++, ndblks--) {
1.1 perseant 341: if (anyout && chkrange(blkno, 1)) {
342: res = SKIP;
343: } else if (!testbmap(blkno)) {
344: n_blks++;
345: #ifndef VERBOSE_BLOCKMAP
346: setbmap(blkno);
347: #else
1.6 perseant 348: setbmap(blkno, idesc->id_number);
1.1 perseant 349: #endif
350: } else {
351: blkerror(idesc->id_number, "DUP", blkno);
352: #ifdef VERBOSE_BLOCKMAP
1.6 perseant 353: pwarn("(lbn %d: Holder is %d)\n", idesc->id_lblkno,
1.14 perseant 354: testbmap(blkno));
1.1 perseant 355: #endif
356: if (dupblk++ >= MAXDUP) {
1.22 christos 357: pwarn("EXCESSIVE DUP BLKS I=%llu",
358: (unsigned long long)idesc->id_number);
1.1 perseant 359: if (preen)
360: printf(" (SKIPPING)\n");
361: else if (reply("CONTINUE") == 0)
1.14 perseant 362: err(8, "%s", "");
1.1 perseant 363: return (STOP);
364: }
1.14 perseant 365: new = (struct dups *) malloc(sizeof(struct dups));
1.1 perseant 366: if (new == NULL) {
367: pfatal("DUP TABLE OVERFLOW.");
368: if (reply("CONTINUE") == 0)
1.14 perseant 369: err(8, "%s", "");
1.1 perseant 370: return (STOP);
371: }
372: new->dup = blkno;
373: if (muldup == 0) {
374: duplist = muldup = new;
375: new->next = 0;
376: } else {
377: new->next = muldup->next;
378: muldup->next = new;
379: }
380: for (dlp = duplist; dlp != muldup; dlp = dlp->next)
381: if (dlp->dup == blkno)
382: break;
383: if (dlp == muldup && dlp->dup != blkno)
384: muldup = new;
385: }
386: /*
387: * count the number of blocks found in id_entryno
388: */
1.6 perseant 389: idesc->id_entryno++;
1.1 perseant 390: }
391: return (res);
392: }
CVSweb <webmaster@jp.NetBSD.org>