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