Deleted Added
full compact
pass1.c (125036) pass1.c (126345)
1/*
2 * Copyright (c) 1980, 1986, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#if 0
35#ifndef lint
36static const char sccsid[] = "@(#)pass1.c 8.6 (Berkeley) 4/28/95";
37#endif /* not lint */
38#endif
39#include <sys/cdefs.h>
1/*
2 * Copyright (c) 1980, 1986, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#if 0
35#ifndef lint
36static const char sccsid[] = "@(#)pass1.c 8.6 (Berkeley) 4/28/95";
37#endif /* not lint */
38#endif
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: head/sbin/fsck_ffs/pass1.c 125036 2004-01-26 15:05:30Z cperciva $");
40__FBSDID("$FreeBSD: head/sbin/fsck_ffs/pass1.c 126345 2004-02-28 07:50:42Z scottl $");
41
42#include <sys/param.h>
43#include <sys/stat.h>
44#include <sys/sysctl.h>
45
46#include <ufs/ufs/dinode.h>
47#include <ufs/ufs/dir.h>
48#include <ufs/ffs/fs.h>
49
50#include <err.h>
51#include <limits.h>
52#include <stdint.h>
53#include <string.h>
54
55#include "fsck.h"
56
57static ufs2_daddr_t badblk;
58static ufs2_daddr_t dupblk;
59static ino_t lastino; /* last inode in use */
60
61static void checkinode(ino_t inumber, struct inodesc *);
62
63void
64pass1(void)
65{
66 struct inostat *info;
67 struct inodesc idesc;
68 ino_t inumber, inosused;
69 ufs2_daddr_t i, cgd;
70 u_int8_t *cp;
71 int c;
72
73 /*
74 * Set file system reserved blocks in used block map.
75 */
76 for (c = 0; c < sblock.fs_ncg; c++) {
77 cgd = cgdmin(&sblock, c);
78 if (c == 0) {
79 i = cgbase(&sblock, c);
80 } else
81 i = cgsblock(&sblock, c);
82 for (; i < cgd; i++)
83 setbmap(i);
84 }
85 i = sblock.fs_csaddr;
86 cgd = i + howmany(sblock.fs_cssize, sblock.fs_fsize);
87 for (; i < cgd; i++)
88 setbmap(i);
89
90 /*
91 * Find all allocated blocks.
92 */
93 memset(&idesc, 0, sizeof(struct inodesc));
94 idesc.id_func = pass1check;
95 n_files = n_blks = 0;
96 for (c = 0; c < sblock.fs_ncg; c++) {
97 inumber = c * sblock.fs_ipg;
98 setinodebuf(inumber);
99 getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize);
100 if (sblock.fs_magic == FS_UFS2_MAGIC)
101 inosused = cgrp.cg_initediblk;
102 else
103 inosused = sblock.fs_ipg;
104 if (got_siginfo) {
105 printf("%s: phase 1: cyl group %d of %d (%d%%)\n",
106 cdevname, c, sblock.fs_ncg,
107 c * 100 / sblock.fs_ncg);
108 got_siginfo = 0;
109 }
41
42#include <sys/param.h>
43#include <sys/stat.h>
44#include <sys/sysctl.h>
45
46#include <ufs/ufs/dinode.h>
47#include <ufs/ufs/dir.h>
48#include <ufs/ffs/fs.h>
49
50#include <err.h>
51#include <limits.h>
52#include <stdint.h>
53#include <string.h>
54
55#include "fsck.h"
56
57static ufs2_daddr_t badblk;
58static ufs2_daddr_t dupblk;
59static ino_t lastino; /* last inode in use */
60
61static void checkinode(ino_t inumber, struct inodesc *);
62
63void
64pass1(void)
65{
66 struct inostat *info;
67 struct inodesc idesc;
68 ino_t inumber, inosused;
69 ufs2_daddr_t i, cgd;
70 u_int8_t *cp;
71 int c;
72
73 /*
74 * Set file system reserved blocks in used block map.
75 */
76 for (c = 0; c < sblock.fs_ncg; c++) {
77 cgd = cgdmin(&sblock, c);
78 if (c == 0) {
79 i = cgbase(&sblock, c);
80 } else
81 i = cgsblock(&sblock, c);
82 for (; i < cgd; i++)
83 setbmap(i);
84 }
85 i = sblock.fs_csaddr;
86 cgd = i + howmany(sblock.fs_cssize, sblock.fs_fsize);
87 for (; i < cgd; i++)
88 setbmap(i);
89
90 /*
91 * Find all allocated blocks.
92 */
93 memset(&idesc, 0, sizeof(struct inodesc));
94 idesc.id_func = pass1check;
95 n_files = n_blks = 0;
96 for (c = 0; c < sblock.fs_ncg; c++) {
97 inumber = c * sblock.fs_ipg;
98 setinodebuf(inumber);
99 getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize);
100 if (sblock.fs_magic == FS_UFS2_MAGIC)
101 inosused = cgrp.cg_initediblk;
102 else
103 inosused = sblock.fs_ipg;
104 if (got_siginfo) {
105 printf("%s: phase 1: cyl group %d of %d (%d%%)\n",
106 cdevname, c, sblock.fs_ncg,
107 c * 100 / sblock.fs_ncg);
108 got_siginfo = 0;
109 }
110 if (got_sigalarm) {
111 setproctitle("%s p1 %d%%", cdevname,
112 c * 100 / sblock.fs_ncg);
113 got_sigalarm = 0;
114 }
110 /*
111 * If we are using soft updates, then we can trust the
112 * cylinder group inode allocation maps to tell us which
113 * inodes are allocated. We will scan the used inode map
114 * to find the inodes that are really in use, and then
115 * read only those inodes in from disk.
116 */
117 if (preen && usedsoftdep) {
118 if (!cg_chkmagic(&cgrp))
119 pfatal("CG %d: BAD MAGIC NUMBER\n", c);
120 cp = &cg_inosused(&cgrp)[(inosused - 1) / CHAR_BIT];
121 for ( ; inosused > 0; inosused -= CHAR_BIT, cp--) {
122 if (*cp == 0)
123 continue;
124 for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) {
125 if (*cp & i)
126 break;
127 inosused--;
128 }
129 break;
130 }
131 if (inosused < 0)
132 inosused = 0;
133 }
134 /*
135 * Allocate inoinfo structures for the allocated inodes.
136 */
137 inostathead[c].il_numalloced = inosused;
138 if (inosused == 0) {
139 inostathead[c].il_stat = 0;
140 continue;
141 }
142 info = calloc((unsigned)inosused, sizeof(struct inostat));
143 if (info == NULL)
144 errx(EEXIT, "cannot alloc %u bytes for inoinfo",
145 (unsigned)(sizeof(struct inostat) * inosused));
146 inostathead[c].il_stat = info;
147 /*
148 * Scan the allocated inodes.
149 */
150 for (i = 0; i < inosused; i++, inumber++) {
151 if (inumber < ROOTINO) {
152 (void)getnextinode(inumber);
153 continue;
154 }
155 checkinode(inumber, &idesc);
156 }
157 lastino += 1;
158 if (inosused < sblock.fs_ipg || inumber == lastino)
159 continue;
160 /*
161 * If we were not able to determine in advance which inodes
162 * were in use, then reduce the size of the inoinfo structure
163 * to the size necessary to describe the inodes that we
164 * really found.
165 */
166 if (lastino < (c * sblock.fs_ipg))
167 inosused = 0;
168 else
169 inosused = lastino - (c * sblock.fs_ipg);
170 inostathead[c].il_numalloced = inosused;
171 if (inosused == 0) {
172 free(inostathead[c].il_stat);
173 inostathead[c].il_stat = 0;
174 continue;
175 }
176 info = calloc((unsigned)inosused, sizeof(struct inostat));
177 if (info == NULL)
178 errx(EEXIT, "cannot alloc %u bytes for inoinfo",
179 (unsigned)(sizeof(struct inostat) * inosused));
180 memmove(info, inostathead[c].il_stat, inosused * sizeof(*info));
181 free(inostathead[c].il_stat);
182 inostathead[c].il_stat = info;
183 }
184 freeinodebuf();
185}
186
187static void
188checkinode(ino_t inumber, struct inodesc *idesc)
189{
190 union dinode *dp;
191 struct zlncnt *zlnp;
192 off_t kernmaxfilesize;
193 ufs2_daddr_t ndb;
194 mode_t mode;
195 int j, ret, offset;
196
197 dp = getnextinode(inumber);
198 mode = DIP(dp, di_mode) & IFMT;
199 if (mode == 0) {
200 if ((sblock.fs_magic == FS_UFS1_MAGIC &&
201 (memcmp(dp->dp1.di_db, ufs1_zino.di_db,
202 NDADDR * sizeof(ufs1_daddr_t)) ||
203 memcmp(dp->dp1.di_ib, ufs1_zino.di_ib,
204 NIADDR * sizeof(ufs1_daddr_t)) ||
205 dp->dp1.di_mode || dp->dp1.di_size)) ||
206 (sblock.fs_magic == FS_UFS2_MAGIC &&
207 (memcmp(dp->dp2.di_db, ufs2_zino.di_db,
208 NDADDR * sizeof(ufs2_daddr_t)) ||
209 memcmp(dp->dp2.di_ib, ufs2_zino.di_ib,
210 NIADDR * sizeof(ufs2_daddr_t)) ||
211 dp->dp2.di_mode || dp->dp2.di_size))) {
212 pfatal("PARTIALLY ALLOCATED INODE I=%lu",
213 (u_long)inumber);
214 if (reply("CLEAR") == 1) {
215 dp = ginode(inumber);
216 clearinode(dp);
217 inodirty();
218 }
219 }
220 inoinfo(inumber)->ino_state = USTATE;
221 return;
222 }
223 lastino = inumber;
224 /* This should match the file size limit in ffs_mountfs(). */
225 if (sblock.fs_magic == FS_UFS1_MAGIC)
226 kernmaxfilesize = (off_t)0x40000000 * sblock.fs_bsize - 1;
227 else
228 kernmaxfilesize = sblock.fs_maxfilesize;
229 if (DIP(dp, di_size) > kernmaxfilesize ||
230 DIP(dp, di_size) > sblock.fs_maxfilesize ||
231 (mode == IFDIR && DIP(dp, di_size) > MAXDIRSIZE)) {
232 if (debug)
233 printf("bad size %ju:", (uintmax_t)DIP(dp, di_size));
234 goto unknown;
235 }
236 if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
237 dp = ginode(inumber);
238 DIP(dp, di_size) = sblock.fs_fsize;
239 DIP(dp, di_mode) = IFREG|0600;
240 inodirty();
241 }
242 if ((mode == IFBLK || mode == IFCHR || mode == IFIFO ||
243 mode == IFSOCK) && DIP(dp, di_size) != 0) {
244 if (debug)
245 printf("bad special-file size %ju:",
246 (uintmax_t)DIP(dp, di_size));
247 goto unknown;
248 }
249 if ((mode == IFBLK || mode == IFCHR) &&
250 (dev_t)DIP(dp, di_rdev) == NODEV) {
251 if (debug)
252 printf("bad special-file rdev NODEV:");
253 goto unknown;
254 }
255 ndb = howmany(DIP(dp, di_size), sblock.fs_bsize);
256 if (ndb < 0) {
257 if (debug)
258 printf("bad size %ju ndb %ju:",
259 (uintmax_t)DIP(dp, di_size), (uintmax_t)ndb);
260 goto unknown;
261 }
262 if (mode == IFBLK || mode == IFCHR)
263 ndb++;
264 if (mode == IFLNK) {
265 /*
266 * Fake ndb value so direct/indirect block checks below
267 * will detect any garbage after symlink string.
268 */
269 if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) {
270 if (sblock.fs_magic == FS_UFS1_MAGIC)
271 ndb = howmany(DIP(dp, di_size),
272 sizeof(ufs1_daddr_t));
273 else
274 ndb = howmany(DIP(dp, di_size),
275 sizeof(ufs2_daddr_t));
276 if (ndb > NDADDR) {
277 j = ndb - NDADDR;
278 for (ndb = 1; j > 1; j--)
279 ndb *= NINDIR(&sblock);
280 ndb += NDADDR;
281 }
282 }
283 }
284 for (j = ndb; ndb < NDADDR && j < NDADDR; j++)
285 if (DIP(dp, di_db[j]) != 0) {
286 if (debug)
287 printf("bad direct addr[%d]: %ju\n", j,
288 (uintmax_t)DIP(dp, di_db[j]));
289 goto unknown;
290 }
291 for (j = 0, ndb -= NDADDR; ndb > 0; j++)
292 ndb /= NINDIR(&sblock);
293 for (; j < NIADDR; j++)
294 if (DIP(dp, di_ib[j]) != 0) {
295 if (debug)
296 printf("bad indirect addr: %ju\n",
297 (uintmax_t)DIP(dp, di_ib[j]));
298 goto unknown;
299 }
300 if (ftypeok(dp) == 0)
301 goto unknown;
302 n_files++;
303 inoinfo(inumber)->ino_linkcnt = DIP(dp, di_nlink);
304 if (DIP(dp, di_nlink) <= 0) {
305 zlnp = (struct zlncnt *)malloc(sizeof *zlnp);
306 if (zlnp == NULL) {
307 pfatal("LINK COUNT TABLE OVERFLOW");
308 if (reply("CONTINUE") == 0) {
309 ckfini(0);
310 exit(EEXIT);
311 }
312 } else {
313 zlnp->zlncnt = inumber;
314 zlnp->next = zlnhead;
315 zlnhead = zlnp;
316 }
317 }
318 if (mode == IFDIR) {
319 if (DIP(dp, di_size) == 0)
320 inoinfo(inumber)->ino_state = DCLEAR;
321 else
322 inoinfo(inumber)->ino_state = DSTATE;
323 cacheino(dp, inumber);
324 countdirs++;
325 } else
326 inoinfo(inumber)->ino_state = FSTATE;
327 inoinfo(inumber)->ino_type = IFTODT(mode);
328 badblk = dupblk = 0;
329 idesc->id_number = inumber;
330 if (DIP(dp, di_flags) & SF_SNAPSHOT)
331 idesc->id_type = SNAP;
332 else
333 idesc->id_type = ADDR;
334 (void)ckinode(dp, idesc);
335 if (sblock.fs_magic == FS_UFS2_MAGIC && dp->dp2.di_extsize > 0) {
336 idesc->id_type = ADDR;
337 ndb = howmany(dp->dp2.di_extsize, sblock.fs_bsize);
338 for (j = 0; j < NXADDR; j++) {
339 if (--ndb == 0 &&
340 (offset = blkoff(&sblock, dp->dp2.di_extsize)) != 0)
341 idesc->id_numfrags = numfrags(&sblock,
342 fragroundup(&sblock, offset));
343 else
344 idesc->id_numfrags = sblock.fs_frag;
345 if (dp->dp2.di_extb[j] == 0)
346 continue;
347 idesc->id_blkno = dp->dp2.di_extb[j];
348 ret = (*idesc->id_func)(idesc);
349 if (ret & STOP)
350 break;
351 }
352 }
353 if (sblock.fs_magic == FS_UFS2_MAGIC)
354 eascan(idesc, &dp->dp2);
355 idesc->id_entryno *= btodb(sblock.fs_fsize);
356 if (DIP(dp, di_blocks) != idesc->id_entryno) {
357 pwarn("INCORRECT BLOCK COUNT I=%lu (%ju should be %ju)",
358 (u_long)inumber, (uintmax_t)DIP(dp, di_blocks),
359 (uintmax_t)idesc->id_entryno);
360 if (preen)
361 printf(" (CORRECTED)\n");
362 else if (reply("CORRECT") == 0)
363 return;
364 if (bkgrdflag == 0) {
365 dp = ginode(inumber);
366 DIP(dp, di_blocks) = idesc->id_entryno;
367 inodirty();
368 } else {
369 cmd.value = idesc->id_number;
370 cmd.size = idesc->id_entryno - DIP(dp, di_blocks);
371 if (debug)
372 printf("adjblkcnt ino %ju amount %lld\n",
373 (uintmax_t)cmd.value, (long long)cmd.size);
374 if (sysctl(adjblkcnt, MIBSIZE, 0, 0,
375 &cmd, sizeof cmd) == -1)
376 rwerror("ADJUST INODE BLOCK COUNT", cmd.value);
377 }
378 }
379 return;
380unknown:
381 pfatal("UNKNOWN FILE TYPE I=%lu", (u_long)inumber);
382 inoinfo(inumber)->ino_state = FCLEAR;
383 if (reply("CLEAR") == 1) {
384 inoinfo(inumber)->ino_state = USTATE;
385 dp = ginode(inumber);
386 clearinode(dp);
387 inodirty();
388 }
389}
390
391int
392pass1check(struct inodesc *idesc)
393{
394 int res = KEEPON;
395 int anyout, nfrags;
396 ufs2_daddr_t blkno = idesc->id_blkno;
397 struct dups *dlp;
398 struct dups *new;
399
400 if (idesc->id_type == SNAP) {
401 if (blkno == BLK_NOCOPY)
402 return (KEEPON);
403 if (idesc->id_number == cursnapshot) {
404 if (blkno == blkstofrags(&sblock, idesc->id_lbn))
405 return (KEEPON);
406 if (blkno == BLK_SNAP) {
407 blkno = blkstofrags(&sblock, idesc->id_lbn);
408 idesc->id_entryno -= idesc->id_numfrags;
409 }
410 } else {
411 if (blkno == BLK_SNAP)
412 return (KEEPON);
413 }
414 }
415 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
416 blkerror(idesc->id_number, "BAD", blkno);
417 if (badblk++ >= MAXBAD) {
418 pwarn("EXCESSIVE BAD BLKS I=%lu",
419 (u_long)idesc->id_number);
420 if (preen)
421 printf(" (SKIPPING)\n");
422 else if (reply("CONTINUE") == 0) {
423 ckfini(0);
424 exit(EEXIT);
425 }
426 return (STOP);
427 }
428 }
429 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
430 if (anyout && chkrange(blkno, 1)) {
431 res = SKIP;
432 } else if (!testbmap(blkno)) {
433 n_blks++;
434 setbmap(blkno);
435 } else {
436 blkerror(idesc->id_number, "DUP", blkno);
437 if (dupblk++ >= MAXDUP) {
438 pwarn("EXCESSIVE DUP BLKS I=%lu",
439 (u_long)idesc->id_number);
440 if (preen)
441 printf(" (SKIPPING)\n");
442 else if (reply("CONTINUE") == 0) {
443 ckfini(0);
444 exit(EEXIT);
445 }
446 return (STOP);
447 }
448 new = (struct dups *)malloc(sizeof(struct dups));
449 if (new == NULL) {
450 pfatal("DUP TABLE OVERFLOW.");
451 if (reply("CONTINUE") == 0) {
452 ckfini(0);
453 exit(EEXIT);
454 }
455 return (STOP);
456 }
457 new->dup = blkno;
458 if (muldup == 0) {
459 duplist = muldup = new;
460 new->next = 0;
461 } else {
462 new->next = muldup->next;
463 muldup->next = new;
464 }
465 for (dlp = duplist; dlp != muldup; dlp = dlp->next)
466 if (dlp->dup == blkno)
467 break;
468 if (dlp == muldup && dlp->dup != blkno)
469 muldup = new;
470 }
471 /*
472 * count the number of blocks found in id_entryno
473 */
474 idesc->id_entryno++;
475 }
476 return (res);
477}
115 /*
116 * If we are using soft updates, then we can trust the
117 * cylinder group inode allocation maps to tell us which
118 * inodes are allocated. We will scan the used inode map
119 * to find the inodes that are really in use, and then
120 * read only those inodes in from disk.
121 */
122 if (preen && usedsoftdep) {
123 if (!cg_chkmagic(&cgrp))
124 pfatal("CG %d: BAD MAGIC NUMBER\n", c);
125 cp = &cg_inosused(&cgrp)[(inosused - 1) / CHAR_BIT];
126 for ( ; inosused > 0; inosused -= CHAR_BIT, cp--) {
127 if (*cp == 0)
128 continue;
129 for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) {
130 if (*cp & i)
131 break;
132 inosused--;
133 }
134 break;
135 }
136 if (inosused < 0)
137 inosused = 0;
138 }
139 /*
140 * Allocate inoinfo structures for the allocated inodes.
141 */
142 inostathead[c].il_numalloced = inosused;
143 if (inosused == 0) {
144 inostathead[c].il_stat = 0;
145 continue;
146 }
147 info = calloc((unsigned)inosused, sizeof(struct inostat));
148 if (info == NULL)
149 errx(EEXIT, "cannot alloc %u bytes for inoinfo",
150 (unsigned)(sizeof(struct inostat) * inosused));
151 inostathead[c].il_stat = info;
152 /*
153 * Scan the allocated inodes.
154 */
155 for (i = 0; i < inosused; i++, inumber++) {
156 if (inumber < ROOTINO) {
157 (void)getnextinode(inumber);
158 continue;
159 }
160 checkinode(inumber, &idesc);
161 }
162 lastino += 1;
163 if (inosused < sblock.fs_ipg || inumber == lastino)
164 continue;
165 /*
166 * If we were not able to determine in advance which inodes
167 * were in use, then reduce the size of the inoinfo structure
168 * to the size necessary to describe the inodes that we
169 * really found.
170 */
171 if (lastino < (c * sblock.fs_ipg))
172 inosused = 0;
173 else
174 inosused = lastino - (c * sblock.fs_ipg);
175 inostathead[c].il_numalloced = inosused;
176 if (inosused == 0) {
177 free(inostathead[c].il_stat);
178 inostathead[c].il_stat = 0;
179 continue;
180 }
181 info = calloc((unsigned)inosused, sizeof(struct inostat));
182 if (info == NULL)
183 errx(EEXIT, "cannot alloc %u bytes for inoinfo",
184 (unsigned)(sizeof(struct inostat) * inosused));
185 memmove(info, inostathead[c].il_stat, inosused * sizeof(*info));
186 free(inostathead[c].il_stat);
187 inostathead[c].il_stat = info;
188 }
189 freeinodebuf();
190}
191
192static void
193checkinode(ino_t inumber, struct inodesc *idesc)
194{
195 union dinode *dp;
196 struct zlncnt *zlnp;
197 off_t kernmaxfilesize;
198 ufs2_daddr_t ndb;
199 mode_t mode;
200 int j, ret, offset;
201
202 dp = getnextinode(inumber);
203 mode = DIP(dp, di_mode) & IFMT;
204 if (mode == 0) {
205 if ((sblock.fs_magic == FS_UFS1_MAGIC &&
206 (memcmp(dp->dp1.di_db, ufs1_zino.di_db,
207 NDADDR * sizeof(ufs1_daddr_t)) ||
208 memcmp(dp->dp1.di_ib, ufs1_zino.di_ib,
209 NIADDR * sizeof(ufs1_daddr_t)) ||
210 dp->dp1.di_mode || dp->dp1.di_size)) ||
211 (sblock.fs_magic == FS_UFS2_MAGIC &&
212 (memcmp(dp->dp2.di_db, ufs2_zino.di_db,
213 NDADDR * sizeof(ufs2_daddr_t)) ||
214 memcmp(dp->dp2.di_ib, ufs2_zino.di_ib,
215 NIADDR * sizeof(ufs2_daddr_t)) ||
216 dp->dp2.di_mode || dp->dp2.di_size))) {
217 pfatal("PARTIALLY ALLOCATED INODE I=%lu",
218 (u_long)inumber);
219 if (reply("CLEAR") == 1) {
220 dp = ginode(inumber);
221 clearinode(dp);
222 inodirty();
223 }
224 }
225 inoinfo(inumber)->ino_state = USTATE;
226 return;
227 }
228 lastino = inumber;
229 /* This should match the file size limit in ffs_mountfs(). */
230 if (sblock.fs_magic == FS_UFS1_MAGIC)
231 kernmaxfilesize = (off_t)0x40000000 * sblock.fs_bsize - 1;
232 else
233 kernmaxfilesize = sblock.fs_maxfilesize;
234 if (DIP(dp, di_size) > kernmaxfilesize ||
235 DIP(dp, di_size) > sblock.fs_maxfilesize ||
236 (mode == IFDIR && DIP(dp, di_size) > MAXDIRSIZE)) {
237 if (debug)
238 printf("bad size %ju:", (uintmax_t)DIP(dp, di_size));
239 goto unknown;
240 }
241 if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
242 dp = ginode(inumber);
243 DIP(dp, di_size) = sblock.fs_fsize;
244 DIP(dp, di_mode) = IFREG|0600;
245 inodirty();
246 }
247 if ((mode == IFBLK || mode == IFCHR || mode == IFIFO ||
248 mode == IFSOCK) && DIP(dp, di_size) != 0) {
249 if (debug)
250 printf("bad special-file size %ju:",
251 (uintmax_t)DIP(dp, di_size));
252 goto unknown;
253 }
254 if ((mode == IFBLK || mode == IFCHR) &&
255 (dev_t)DIP(dp, di_rdev) == NODEV) {
256 if (debug)
257 printf("bad special-file rdev NODEV:");
258 goto unknown;
259 }
260 ndb = howmany(DIP(dp, di_size), sblock.fs_bsize);
261 if (ndb < 0) {
262 if (debug)
263 printf("bad size %ju ndb %ju:",
264 (uintmax_t)DIP(dp, di_size), (uintmax_t)ndb);
265 goto unknown;
266 }
267 if (mode == IFBLK || mode == IFCHR)
268 ndb++;
269 if (mode == IFLNK) {
270 /*
271 * Fake ndb value so direct/indirect block checks below
272 * will detect any garbage after symlink string.
273 */
274 if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) {
275 if (sblock.fs_magic == FS_UFS1_MAGIC)
276 ndb = howmany(DIP(dp, di_size),
277 sizeof(ufs1_daddr_t));
278 else
279 ndb = howmany(DIP(dp, di_size),
280 sizeof(ufs2_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; ndb < NDADDR && j < NDADDR; j++)
290 if (DIP(dp, di_db[j]) != 0) {
291 if (debug)
292 printf("bad direct addr[%d]: %ju\n", j,
293 (uintmax_t)DIP(dp, di_db[j]));
294 goto unknown;
295 }
296 for (j = 0, ndb -= NDADDR; ndb > 0; j++)
297 ndb /= NINDIR(&sblock);
298 for (; j < NIADDR; j++)
299 if (DIP(dp, di_ib[j]) != 0) {
300 if (debug)
301 printf("bad indirect addr: %ju\n",
302 (uintmax_t)DIP(dp, di_ib[j]));
303 goto unknown;
304 }
305 if (ftypeok(dp) == 0)
306 goto unknown;
307 n_files++;
308 inoinfo(inumber)->ino_linkcnt = DIP(dp, di_nlink);
309 if (DIP(dp, di_nlink) <= 0) {
310 zlnp = (struct zlncnt *)malloc(sizeof *zlnp);
311 if (zlnp == NULL) {
312 pfatal("LINK COUNT TABLE OVERFLOW");
313 if (reply("CONTINUE") == 0) {
314 ckfini(0);
315 exit(EEXIT);
316 }
317 } else {
318 zlnp->zlncnt = inumber;
319 zlnp->next = zlnhead;
320 zlnhead = zlnp;
321 }
322 }
323 if (mode == IFDIR) {
324 if (DIP(dp, di_size) == 0)
325 inoinfo(inumber)->ino_state = DCLEAR;
326 else
327 inoinfo(inumber)->ino_state = DSTATE;
328 cacheino(dp, inumber);
329 countdirs++;
330 } else
331 inoinfo(inumber)->ino_state = FSTATE;
332 inoinfo(inumber)->ino_type = IFTODT(mode);
333 badblk = dupblk = 0;
334 idesc->id_number = inumber;
335 if (DIP(dp, di_flags) & SF_SNAPSHOT)
336 idesc->id_type = SNAP;
337 else
338 idesc->id_type = ADDR;
339 (void)ckinode(dp, idesc);
340 if (sblock.fs_magic == FS_UFS2_MAGIC && dp->dp2.di_extsize > 0) {
341 idesc->id_type = ADDR;
342 ndb = howmany(dp->dp2.di_extsize, sblock.fs_bsize);
343 for (j = 0; j < NXADDR; j++) {
344 if (--ndb == 0 &&
345 (offset = blkoff(&sblock, dp->dp2.di_extsize)) != 0)
346 idesc->id_numfrags = numfrags(&sblock,
347 fragroundup(&sblock, offset));
348 else
349 idesc->id_numfrags = sblock.fs_frag;
350 if (dp->dp2.di_extb[j] == 0)
351 continue;
352 idesc->id_blkno = dp->dp2.di_extb[j];
353 ret = (*idesc->id_func)(idesc);
354 if (ret & STOP)
355 break;
356 }
357 }
358 if (sblock.fs_magic == FS_UFS2_MAGIC)
359 eascan(idesc, &dp->dp2);
360 idesc->id_entryno *= btodb(sblock.fs_fsize);
361 if (DIP(dp, di_blocks) != idesc->id_entryno) {
362 pwarn("INCORRECT BLOCK COUNT I=%lu (%ju should be %ju)",
363 (u_long)inumber, (uintmax_t)DIP(dp, di_blocks),
364 (uintmax_t)idesc->id_entryno);
365 if (preen)
366 printf(" (CORRECTED)\n");
367 else if (reply("CORRECT") == 0)
368 return;
369 if (bkgrdflag == 0) {
370 dp = ginode(inumber);
371 DIP(dp, di_blocks) = idesc->id_entryno;
372 inodirty();
373 } else {
374 cmd.value = idesc->id_number;
375 cmd.size = idesc->id_entryno - DIP(dp, di_blocks);
376 if (debug)
377 printf("adjblkcnt ino %ju amount %lld\n",
378 (uintmax_t)cmd.value, (long long)cmd.size);
379 if (sysctl(adjblkcnt, MIBSIZE, 0, 0,
380 &cmd, sizeof cmd) == -1)
381 rwerror("ADJUST INODE BLOCK COUNT", cmd.value);
382 }
383 }
384 return;
385unknown:
386 pfatal("UNKNOWN FILE TYPE I=%lu", (u_long)inumber);
387 inoinfo(inumber)->ino_state = FCLEAR;
388 if (reply("CLEAR") == 1) {
389 inoinfo(inumber)->ino_state = USTATE;
390 dp = ginode(inumber);
391 clearinode(dp);
392 inodirty();
393 }
394}
395
396int
397pass1check(struct inodesc *idesc)
398{
399 int res = KEEPON;
400 int anyout, nfrags;
401 ufs2_daddr_t blkno = idesc->id_blkno;
402 struct dups *dlp;
403 struct dups *new;
404
405 if (idesc->id_type == SNAP) {
406 if (blkno == BLK_NOCOPY)
407 return (KEEPON);
408 if (idesc->id_number == cursnapshot) {
409 if (blkno == blkstofrags(&sblock, idesc->id_lbn))
410 return (KEEPON);
411 if (blkno == BLK_SNAP) {
412 blkno = blkstofrags(&sblock, idesc->id_lbn);
413 idesc->id_entryno -= idesc->id_numfrags;
414 }
415 } else {
416 if (blkno == BLK_SNAP)
417 return (KEEPON);
418 }
419 }
420 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
421 blkerror(idesc->id_number, "BAD", blkno);
422 if (badblk++ >= MAXBAD) {
423 pwarn("EXCESSIVE BAD BLKS I=%lu",
424 (u_long)idesc->id_number);
425 if (preen)
426 printf(" (SKIPPING)\n");
427 else if (reply("CONTINUE") == 0) {
428 ckfini(0);
429 exit(EEXIT);
430 }
431 return (STOP);
432 }
433 }
434 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
435 if (anyout && chkrange(blkno, 1)) {
436 res = SKIP;
437 } else if (!testbmap(blkno)) {
438 n_blks++;
439 setbmap(blkno);
440 } else {
441 blkerror(idesc->id_number, "DUP", blkno);
442 if (dupblk++ >= MAXDUP) {
443 pwarn("EXCESSIVE DUP BLKS I=%lu",
444 (u_long)idesc->id_number);
445 if (preen)
446 printf(" (SKIPPING)\n");
447 else if (reply("CONTINUE") == 0) {
448 ckfini(0);
449 exit(EEXIT);
450 }
451 return (STOP);
452 }
453 new = (struct dups *)malloc(sizeof(struct dups));
454 if (new == NULL) {
455 pfatal("DUP TABLE OVERFLOW.");
456 if (reply("CONTINUE") == 0) {
457 ckfini(0);
458 exit(EEXIT);
459 }
460 return (STOP);
461 }
462 new->dup = blkno;
463 if (muldup == 0) {
464 duplist = muldup = new;
465 new->next = 0;
466 } else {
467 new->next = muldup->next;
468 muldup->next = new;
469 }
470 for (dlp = duplist; dlp != muldup; dlp = dlp->next)
471 if (dlp->dup == blkno)
472 break;
473 if (dlp == muldup && dlp->dup != blkno)
474 muldup = new;
475 }
476 /*
477 * count the number of blocks found in id_entryno
478 */
479 idesc->id_entryno++;
480 }
481 return (res);
482}