pass1.c revision 1.13 1 /* $NetBSD: pass1.c,v 1.13 1995/03/18 14:55:49 cgd Exp $ */
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.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)pass1.c 8.1 (Berkeley) 6/5/93";
39 #else
40 static char rcsid[] = "$NetBSD: pass1.c,v 1.13 1995/03/18 14:55:49 cgd Exp $";
41 #endif
42 #endif /* not lint */
43
44 #include <sys/param.h>
45 #include <sys/time.h>
46 #include <ufs/ufs/dinode.h>
47 #include <ufs/ufs/dir.h>
48 #include <ufs/ffs/fs.h>
49
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53
54 #include "fsck.h"
55 #include "extern.h"
56
57 static daddr_t badblk;
58 static daddr_t dupblk;
59 int pass1check();
60 struct dinode *getnextinode();
61 void checkinode __P((ino_t, struct inodesc *));
62
63 void
64 pass1()
65 {
66 ino_t inumber;
67 int c, i, cgd;
68 struct inodesc idesc;
69
70 /*
71 * Set file system reserved blocks in used block map.
72 */
73 for (c = 0; c < sblock.fs_ncg; c++) {
74 cgd = cgdmin(&sblock, c);
75 if (c == 0) {
76 i = cgbase(&sblock, c);
77 cgd += howmany(sblock.fs_cssize, sblock.fs_fsize);
78 } else
79 i = cgsblock(&sblock, c);
80 for (; i < cgd; i++)
81 setbmap(i);
82 }
83 /*
84 * Find all allocated blocks.
85 */
86 memset(&idesc, 0, sizeof(struct inodesc));
87 idesc.id_type = ADDR;
88 idesc.id_func = pass1check;
89 inumber = 0;
90 n_files = n_blks = 0;
91 resetinodebuf();
92 for (c = 0; c < sblock.fs_ncg; c++) {
93 for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
94 if (inumber < ROOTINO)
95 continue;
96 checkinode(inumber, &idesc);
97 }
98 }
99 freeinodebuf();
100 }
101
102 void
103 checkinode(inumber, idesc)
104 ino_t inumber;
105 register struct inodesc *idesc;
106 {
107 register struct dinode *dp;
108 struct zlncnt *zlnp;
109 int ndb, j;
110 mode_t mode;
111 char *symbuf;
112
113 dp = getnextinode(inumber);
114 mode = dp->di_mode & IFMT;
115 if (mode == 0) {
116 if (memcmp(dp->di_db, zino.di_db, NDADDR * sizeof(daddr_t)) ||
117 memcmp(dp->di_ib, zino.di_ib, NIADDR * sizeof(daddr_t)) ||
118 dp->di_mode || dp->di_size) {
119 pfatal("PARTIALLY ALLOCATED INODE I=%lu", inumber);
120 if (reply("CLEAR") == 1) {
121 dp = ginode(inumber);
122 clearinode(dp);
123 inodirty();
124 }
125 }
126 statemap[inumber] = USTATE;
127 return;
128 }
129 lastino = inumber;
130 if (/* dp->di_size < 0 || */
131 dp->di_size + sblock.fs_bsize - 1 < dp->di_size) {
132 if (debug)
133 printf("bad size %qu:", dp->di_size);
134 goto unknown;
135 }
136 if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
137 dp = ginode(inumber);
138 dp->di_size = sblock.fs_fsize;
139 dp->di_mode = IFREG|0600;
140 inodirty();
141 }
142 ndb = howmany(dp->di_size, sblock.fs_bsize);
143 if (ndb < 0) {
144 if (debug)
145 printf("bad size %qu ndb %d:",
146 dp->di_size, ndb);
147 goto unknown;
148 }
149 if (mode == IFBLK || mode == IFCHR)
150 ndb++;
151 if (mode == IFLNK) {
152 /*
153 * Note that the old fastlink format always had di_blocks set
154 * to 0. Other than that we no longer use the `spare' field
155 * (which is now the extended uid) for sanity checking, the
156 * new format is the same as the old. We simply ignore the
157 * conversion altogether. - mycroft, 19MAY1994
158 */
159 if (doinglevel2 &&
160 dp->di_size > 0 && dp->di_size < MAXSYMLINKLEN &&
161 dp->di_blocks != 0) {
162 symbuf = alloca(secsize);
163 if (bread(fsreadfd, symbuf,
164 fsbtodb(&sblock, dp->di_db[0]),
165 (long)secsize) != 0)
166 errexit("cannot read symlink");
167 if (debug) {
168 symbuf[dp->di_size] = 0;
169 printf("convert symlink %d(%s) of size %d\n",
170 inumber, symbuf, (long)dp->di_size);
171 }
172 dp = ginode(inumber);
173 memcpy(dp->di_shortlink, symbuf, (long)dp->di_size);
174 dp->di_blocks = 0;
175 inodirty();
176 }
177 /*
178 * Fake ndb value so direct/indirect block checks below
179 * will detect any garbage after symlink string.
180 */
181 if (dp->di_size < sblock.fs_maxsymlinklen ||
182 (sblock.fs_maxsymlinklen == 0 && dp->di_blocks == 0)) {
183 ndb = howmany(dp->di_size, sizeof(daddr_t));
184 if (ndb > NDADDR) {
185 j = ndb - NDADDR;
186 for (ndb = 1; j > 1; j--)
187 ndb *= NINDIR(&sblock);
188 ndb += NDADDR;
189 }
190 }
191 }
192 for (j = ndb; j < NDADDR; j++)
193 if (dp->di_db[j] != 0) {
194 if (debug)
195 printf("bad direct addr: %ld\n", dp->di_db[j]);
196 goto unknown;
197 }
198 for (j = 0, ndb -= NDADDR; ndb > 0; j++)
199 ndb /= NINDIR(&sblock);
200 for (; j < NIADDR; j++)
201 if (dp->di_ib[j] != 0) {
202 if (debug)
203 printf("bad indirect addr: %ld\n",
204 dp->di_ib[j]);
205 goto unknown;
206 }
207 if (ftypeok(dp) == 0)
208 goto unknown;
209 n_files++;
210 lncntp[inumber] = dp->di_nlink;
211 if (dp->di_nlink <= 0) {
212 zlnp = (struct zlncnt *)malloc(sizeof *zlnp);
213 if (zlnp == NULL) {
214 pfatal("LINK COUNT TABLE OVERFLOW");
215 if (reply("CONTINUE") == 0)
216 errexit("");
217 } else {
218 zlnp->zlncnt = inumber;
219 zlnp->next = zlnhead;
220 zlnhead = zlnp;
221 }
222 }
223 if (mode == IFDIR) {
224 if (dp->di_size == 0)
225 statemap[inumber] = DCLEAR;
226 else
227 statemap[inumber] = DSTATE;
228 cacheino(dp, inumber);
229 } else
230 statemap[inumber] = FSTATE;
231 typemap[inumber] = IFTODT(mode);
232 if (doinglevel2 &&
233 (dp->di_ouid != (u_short)-1 || dp->di_ogid != (u_short)-1)) {
234 dp = ginode(inumber);
235 dp->di_uid = dp->di_ouid;
236 dp->di_ouid = -1;
237 dp->di_gid = dp->di_ogid;
238 dp->di_ogid = -1;
239 inodirty();
240 }
241 badblk = dupblk = 0;
242 idesc->id_number = inumber;
243 (void)ckinode(dp, idesc);
244 idesc->id_entryno *= btodb(sblock.fs_fsize);
245 if (dp->di_blocks != idesc->id_entryno) {
246 pwarn("INCORRECT BLOCK COUNT I=%lu (%ld should be %ld)",
247 inumber, dp->di_blocks, idesc->id_entryno);
248 if (preen)
249 printf(" (CORRECTED)\n");
250 else if (reply("CORRECT") == 0)
251 return;
252 dp = ginode(inumber);
253 dp->di_blocks = idesc->id_entryno;
254 inodirty();
255 }
256 return;
257 unknown:
258 pfatal("UNKNOWN FILE TYPE I=%lu", inumber);
259 statemap[inumber] = FCLEAR;
260 if (reply("CLEAR") == 1) {
261 statemap[inumber] = USTATE;
262 dp = ginode(inumber);
263 clearinode(dp);
264 inodirty();
265 }
266 }
267
268 int
269 pass1check(idesc)
270 register struct inodesc *idesc;
271 {
272 int res = KEEPON;
273 int anyout, nfrags;
274 daddr_t blkno = idesc->id_blkno;
275 register struct dups *dlp;
276 struct dups *new;
277
278 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
279 blkerror(idesc->id_number, "BAD", blkno);
280 if (badblk++ >= MAXBAD) {
281 pwarn("EXCESSIVE BAD BLKS I=%lu",
282 idesc->id_number);
283 if (preen)
284 printf(" (SKIPPING)\n");
285 else if (reply("CONTINUE") == 0)
286 errexit("");
287 return (STOP);
288 }
289 }
290 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
291 if (anyout && chkrange(blkno, 1)) {
292 res = SKIP;
293 } else if (!testbmap(blkno)) {
294 n_blks++;
295 setbmap(blkno);
296 } else {
297 blkerror(idesc->id_number, "DUP", blkno);
298 if (dupblk++ >= MAXDUP) {
299 pwarn("EXCESSIVE DUP BLKS I=%lu",
300 idesc->id_number);
301 if (preen)
302 printf(" (SKIPPING)\n");
303 else if (reply("CONTINUE") == 0)
304 errexit("");
305 return (STOP);
306 }
307 new = (struct dups *)malloc(sizeof(struct dups));
308 if (new == NULL) {
309 pfatal("DUP TABLE OVERFLOW.");
310 if (reply("CONTINUE") == 0)
311 errexit("");
312 return (STOP);
313 }
314 new->dup = blkno;
315 if (muldup == 0) {
316 duplist = muldup = new;
317 new->next = 0;
318 } else {
319 new->next = muldup->next;
320 muldup->next = new;
321 }
322 for (dlp = duplist; dlp != muldup; dlp = dlp->next)
323 if (dlp->dup == blkno)
324 break;
325 if (dlp == muldup && dlp->dup != blkno)
326 muldup = new;
327 }
328 /*
329 * count the number of blocks found in id_entryno
330 */
331 idesc->id_entryno++;
332 }
333 return (res);
334 }
335