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