1 /* $OpenBSD: pass1.c,v 1.50 2024/09/15 07:14:58 jsg Exp $ */
2 /* $NetBSD: pass1.c,v 1.16 1996/09/27 22:45:15 christos Exp $ */
3
4 /*
5 * Copyright (c) 1980, 1986, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include <sys/param.h> /* MIN setbit btodb isset */
34 #include <sys/time.h>
35 #include <ufs/ufs/dinode.h>
36 #include <ufs/ufs/dir.h>
37 #include <ufs/ffs/fs.h>
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <limits.h>
44
45 #include "fsck.h"
46 #include "extern.h"
47 #include "fsutil.h"
48
49 static daddr_t badblk;
50 static daddr_t dupblk;
51 static void checkinode(ino_t, struct inodesc *);
52
53 static ino_t info_inumber;
54
55 static int
pass1_info(char * buf,size_t buflen)56 pass1_info(char *buf, size_t buflen)
57 {
58 return (snprintf(buf, buflen, "phase 1, inode %llu/%llu",
59 (unsigned long long)info_inumber,
60 (unsigned long long)sblock.fs_ipg * sblock.fs_ncg) > 0);
61 }
62
63 void
pass1(void)64 pass1(void)
65 {
66 ino_t inumber, inosused, ninosused;
67 size_t inospace;
68 struct inostat *info;
69 struct bufarea *cgbp;
70 struct cg *cgp;
71 u_int c;
72 struct inodesc idesc;
73 daddr_t i, cgd;
74
75 /*
76 * Set file system reserved blocks in used block map.
77 */
78 for (c = 0; c < sblock.fs_ncg; c++) {
79 cgd = cgdmin(&sblock, c);
80 if (c == 0)
81 i = cgbase(&sblock, c);
82 else
83 i = cgsblock(&sblock, c);
84 for (; i < cgd; i++)
85 setbmap(i);
86 }
87 i = sblock.fs_csaddr;
88 cgd = i + howmany(sblock.fs_cssize, sblock.fs_fsize);
89 for (; i < cgd; i++)
90 setbmap(i);
91 /*
92 * Find all allocated blocks.
93 */
94 memset(&idesc, 0, sizeof(struct inodesc));
95 idesc.id_type = ADDR;
96 idesc.id_func = pass1check;
97 n_files = n_blks = 0;
98 info_inumber = 0;
99 info_fn = pass1_info;
100 for (c = 0; c < sblock.fs_ncg; c++) {
101 inumber = c * sblock.fs_ipg;
102 setinodebuf(inumber);
103 cgbp = cglookup(c);
104 cgp = cgbp->b_un.b_cg;
105 if (sblock.fs_magic == FS_UFS2_MAGIC) {
106 inosused = cgp->cg_initediblk;
107 if (inosused > sblock.fs_ipg)
108 inosused = sblock.fs_ipg;
109 } else
110 inosused = sblock.fs_ipg;
111
112 /*
113 * Allocate inoinfo structures for the allocated inodes.
114 */
115 inostathead[c].il_numalloced = inosused;
116 if (inosused == 0) {
117 inostathead[c].il_stat = 0;
118 continue;
119 }
120 info = Calloc((unsigned)inosused, sizeof(struct inostat));
121 inospace = (unsigned)inosused * sizeof(struct inostat);
122 if (info == NULL)
123 errexit("cannot alloc %zu bytes for inoinfo\n", inospace);
124 inostathead[c].il_stat = info;
125 /*
126 * Scan the allocated inodes.
127 */
128 for (i = 0; i < inosused; i++, inumber++) {
129 info_inumber = inumber;
130 if (inumber < ROOTINO) {
131 (void)getnextinode(inumber);
132 continue;
133 }
134 checkinode(inumber, &idesc);
135 }
136 lastino += 1;
137 if (inosused < sblock.fs_ipg || inumber == lastino)
138 continue;
139 /*
140 * If we were not able to determine in advance which inodes
141 * were in use, then reduce the size of the inoinfo structure
142 * to the size necessary to describe the inodes that we
143 * really found.
144 */
145 if (lastino < (c * sblock.fs_ipg))
146 ninosused = 0;
147 else
148 ninosused = lastino - (c * sblock.fs_ipg);
149 inostathead[c].il_numalloced = ninosused;
150 if (ninosused == 0) {
151 free(inostathead[c].il_stat);
152 inostathead[c].il_stat = 0;
153 continue;
154 }
155 if (ninosused != inosused) {
156 struct inostat *ninfo;
157 size_t ninospace;
158
159 ninfo = Reallocarray(info, ninosused, sizeof(*ninfo));
160 if (ninfo == NULL) {
161 pfatal("too many inodes %llu, or out of memory\n",
162 (unsigned long long)ninosused);
163 exit(8);
164 }
165 ninospace = ninosused * sizeof(*ninfo);
166 if (ninosused > inosused)
167 memset(&ninfo[inosused], 0, ninospace - inospace);
168 inostathead[c].il_stat = ninfo;
169 }
170 }
171 info_fn = NULL;
172 freeinodebuf();
173 }
174
175 static void
checkinode(ino_t inumber,struct inodesc * idesc)176 checkinode(ino_t inumber, struct inodesc *idesc)
177 {
178 union dinode *dp;
179 off_t kernmaxfilesize;
180 struct zlncnt *zlnp;
181 int ndb, j;
182 mode_t mode;
183 u_int64_t lndb;
184
185 dp = getnextinode(inumber);
186 mode = DIP(dp, di_mode) & IFMT;
187 if (mode == 0) {
188 if ((sblock.fs_magic == FS_UFS1_MAGIC &&
189 (memcmp(dp->dp1.di_db, ufs1_zino.di_db,
190 NDADDR * sizeof(int32_t)) ||
191 memcmp(dp->dp1.di_ib, ufs1_zino.di_ib,
192 NIADDR * sizeof(int32_t)) ||
193 dp->dp1.di_mode || dp->dp1.di_size)) ||
194 (sblock.fs_magic == FS_UFS2_MAGIC &&
195 (memcmp(dp->dp2.di_db, ufs2_zino.di_db,
196 NDADDR * sizeof(daddr_t)) ||
197 memcmp(dp->dp2.di_ib, ufs2_zino.di_ib,
198 NIADDR * sizeof(daddr_t)) ||
199 dp->dp2.di_mode || dp->dp2.di_size))) {
200 pfatal("PARTIALLY ALLOCATED INODE I=%llu",
201 (unsigned long long)inumber);
202 if (reply("CLEAR") == 1) {
203 dp = ginode(inumber);
204 clearinode(dp);
205 inodirty();
206 }
207 }
208 SET_ISTATE(inumber, USTATE);
209 return;
210 }
211 lastino = inumber;
212 /* This should match the file size limit in ffs_mountfs(). */
213 kernmaxfilesize = FS_KERNMAXFILESIZE(getpagesize(), &sblock);
214 if (DIP(dp, di_size) > kernmaxfilesize ||
215 DIP(dp, di_size) > sblock.fs_maxfilesize ||
216 (mode == IFDIR && DIP(dp, di_size) > MAXDIRSIZE)) {
217 if (debug)
218 printf("bad size %llu:",
219 (unsigned long long)DIP(dp, di_size));
220 goto unknown;
221 }
222 if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
223 dp = ginode(inumber);
224 DIP_SET(dp, di_size, sblock.fs_fsize);
225 DIP_SET(dp, di_mode, IFREG|0600);
226 inodirty();
227 }
228 lndb = howmany(DIP(dp, di_size), sblock.fs_bsize);
229 ndb = lndb > (u_int64_t)INT_MAX ? -1 : (int)lndb;
230 if (ndb < 0) {
231 if (debug)
232 printf("bad size %llu ndb %d:",
233 (unsigned long long)DIP(dp, di_size), ndb);
234 goto unknown;
235 }
236 if (mode == IFBLK || mode == IFCHR)
237 ndb++;
238 if (mode == IFLNK) {
239 /*
240 * Fake ndb value so direct/indirect block checks below
241 * will detect any garbage after symlink string.
242 */
243 if (DIP(dp, di_size) < sblock.fs_maxsymlinklen) {
244 if (sblock.fs_magic == FS_UFS1_MAGIC)
245 ndb = howmany(DIP(dp, di_size),
246 sizeof(int32_t));
247 else
248 ndb = howmany(DIP(dp, di_size),
249 sizeof(int64_t));
250 if (ndb > NDADDR) {
251 j = ndb - NDADDR;
252 for (ndb = 1; j > 1; j--)
253 ndb *= NINDIR(&sblock);
254 ndb += NDADDR;
255 }
256 }
257 }
258 for (j = ndb; j < NDADDR; j++)
259 if (DIP(dp, di_db[j]) != 0) {
260 if (debug)
261 printf("bad direct addr: %lld\n",
262 (long long)DIP(dp, di_db[j]));
263 goto unknown;
264 }
265 for (j = 0, ndb -= NDADDR; ndb > 0; j++)
266 ndb /= NINDIR(&sblock);
267 for (; j < NIADDR; j++)
268 if (DIP(dp, di_ib[j]) != 0) {
269 if (debug)
270 printf("bad indirect addr: %lld\n",
271 (long long)DIP(dp, di_ib[j]));
272 goto unknown;
273 }
274 if (ftypeok(dp) == 0)
275 goto unknown;
276 n_files++;
277 ILNCOUNT(inumber) = DIP(dp, di_nlink);
278 if (DIP(dp, di_nlink) <= 0) {
279 zlnp = Malloc(sizeof *zlnp);
280 if (zlnp == NULL) {
281 pfatal("LINK COUNT TABLE OVERFLOW");
282 if (reply("CONTINUE") == 0) {
283 ckfini(0);
284 errexit("%s", "");
285 }
286 } else {
287 zlnp->zlncnt = inumber;
288 zlnp->next = zlnhead;
289 zlnhead = zlnp;
290 }
291 }
292 if (mode == IFDIR) {
293 if (DIP(dp, di_size) == 0)
294 SET_ISTATE(inumber, DCLEAR);
295 else
296 SET_ISTATE(inumber, DSTATE);
297 cacheino(dp, inumber);
298 } else
299 SET_ISTATE(inumber, FSTATE);
300 SET_ITYPE(inumber, IFTODT(mode));
301 badblk = dupblk = 0;
302 idesc->id_number = inumber;
303 (void)ckinode(dp, idesc);
304 idesc->id_entryno *= btodb(sblock.fs_fsize);
305 if (DIP(dp, di_blocks) != idesc->id_entryno) {
306 pwarn("INCORRECT BLOCK COUNT I=%llu (%lld should be %lld)",
307 (unsigned long long)inumber, (long long)DIP(dp, di_blocks),
308 (long long)idesc->id_entryno);
309 if (preen)
310 printf(" (CORRECTED)\n");
311 else if (reply("CORRECT") == 0)
312 return;
313 dp = ginode(inumber);
314 DIP_SET(dp, di_blocks, idesc->id_entryno);
315 inodirty();
316 }
317 return;
318 unknown:
319 pfatal("UNKNOWN FILE TYPE I=%llu", (unsigned long long)inumber);
320 SET_ISTATE(inumber, FCLEAR);
321 if (reply("CLEAR") == 1) {
322 SET_ISTATE(inumber, USTATE);
323 dp = ginode(inumber);
324 clearinode(dp);
325 inodirty();
326 }
327 }
328
329 int
pass1check(struct inodesc * idesc)330 pass1check(struct inodesc *idesc)
331 {
332 int res = KEEPON;
333 int anyout, nfrags;
334 daddr_t blkno = idesc->id_blkno;
335 struct dups *dlp;
336 struct dups *new;
337
338 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
339 blkerror(idesc->id_number, "BAD", blkno);
340 if (badblk++ >= MAXBAD) {
341 pwarn("EXCESSIVE BAD BLKS I=%llu",
342 (unsigned long long)idesc->id_number);
343 if (preen)
344 printf(" (SKIPPING)\n");
345 else if (reply("CONTINUE") == 0) {
346 ckfini(0);
347 errexit("%s", "");
348 }
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 setbmap(blkno);
358 } else {
359 blkerror(idesc->id_number, "DUP", blkno);
360 if (dupblk++ >= MAXDUP) {
361 pwarn("EXCESSIVE DUP BLKS I=%llu",
362 (unsigned long long)idesc->id_number);
363 if (preen)
364 printf(" (SKIPPING)\n");
365 else if (reply("CONTINUE") == 0) {
366 ckfini(0);
367 errexit("%s", "");
368 }
369 return (STOP);
370 }
371 new = Malloc(sizeof(struct dups));
372 if (new == NULL) {
373 pfatal("DUP TABLE OVERFLOW.");
374 if (reply("CONTINUE") == 0) {
375 ckfini(0);
376 errexit("%s", "");
377 }
378 return (STOP);
379 }
380 new->dup = blkno;
381 if (muldup == 0) {
382 duplist = muldup = new;
383 new->next = 0;
384 } else {
385 new->next = muldup->next;
386 muldup->next = new;
387 }
388 for (dlp = duplist; dlp != muldup; dlp = dlp->next)
389 if (dlp->dup == blkno)
390 break;
391 if (dlp == muldup && dlp->dup != blkno)
392 muldup = new;
393 }
394 /*
395 * count the number of blocks found in id_entryno
396 */
397 idesc->id_entryno++;
398 }
399 return (res);
400 }
401