Commit | Line | Data |
---|---|---|
76797561 | 1 | /* |
fe32782c KM |
2 | * Copyright (c) 1980, 1986 The Regents of the University of California. |
3 | * All rights reserved. | |
4 | * | |
70ab3c27 | 5 | * %sccs.include.redist.c% |
76797561 DF |
6 | */ |
7 | ||
19052d90 | 8 | #ifndef lint |
a0cb9f5b | 9 | static char sccsid[] = "@(#)pass1.c 5.20 (Berkeley) %G%"; |
fe32782c | 10 | #endif /* not lint */ |
19052d90 KM |
11 | |
12 | #include <sys/param.h> | |
44357263 | 13 | #include <sys/time.h> |
558b3a30 | 14 | #include <ufs/ufs/dinode.h> |
bab4bc3e | 15 | #include <ufs/ufs/dir.h> |
558b3a30 | 16 | #include <ufs/ffs/fs.h> |
d72e970b KM |
17 | #include <stdlib.h> |
18 | #include <string.h> | |
19052d90 KM |
19 | #include "fsck.h" |
20 | ||
993a756c KM |
21 | static daddr_t badblk; |
22 | static daddr_t dupblk; | |
23 | int pass1check(); | |
a0cb24a2 | 24 | struct dinode *getnextinode(); |
19052d90 KM |
25 | |
26 | pass1() | |
27 | { | |
19052d90 | 28 | ino_t inumber; |
bab4bc3e KM |
29 | int c, i, cgd; |
30 | struct inodesc idesc; | |
19052d90 | 31 | |
7718c0e6 KM |
32 | /* |
33 | * Set file system reserved blocks in used block map. | |
34 | */ | |
35 | for (c = 0; c < sblock.fs_ncg; c++) { | |
36 | cgd = cgdmin(&sblock, c); | |
37 | if (c == 0) { | |
38 | i = cgbase(&sblock, c); | |
39 | cgd += howmany(sblock.fs_cssize, sblock.fs_fsize); | |
40 | } else | |
41 | i = cgsblock(&sblock, c); | |
42 | for (; i < cgd; i++) | |
43 | setbmap(i); | |
44 | } | |
45 | /* | |
46 | * Find all allocated blocks. | |
47 | */ | |
19052d90 KM |
48 | bzero((char *)&idesc, sizeof(struct inodesc)); |
49 | idesc.id_type = ADDR; | |
50 | idesc.id_func = pass1check; | |
51 | inumber = 0; | |
993a756c | 52 | n_files = n_blks = 0; |
a0cb24a2 | 53 | resetinodebuf(); |
19052d90 | 54 | for (c = 0; c < sblock.fs_ncg; c++) { |
19052d90 | 55 | for (i = 0; i < sblock.fs_ipg; i++, inumber++) { |
993a756c | 56 | if (inumber < ROOTINO) |
19052d90 | 57 | continue; |
bab4bc3e KM |
58 | checkinode(inumber, &idesc); |
59 | } | |
60 | } | |
61 | freeinodebuf(); | |
62 | } | |
63 | ||
64 | checkinode(inumber, idesc) | |
65 | ino_t inumber; | |
66 | register struct inodesc *idesc; | |
67 | { | |
68 | register struct dinode *dp; | |
69 | struct zlncnt *zlnp; | |
70 | int ndb, j; | |
71 | mode_t mode; | |
72 | char symbuf[MAXSYMLINKLEN]; | |
73 | ||
74 | dp = getnextinode(inumber); | |
75 | mode = dp->di_mode & IFMT; | |
76 | if (mode == 0) { | |
77 | if (bcmp((char *)dp->di_db, (char *)zino.di_db, | |
78 | NDADDR * sizeof(daddr_t)) || | |
79 | bcmp((char *)dp->di_ib, (char *)zino.di_ib, | |
80 | NIADDR * sizeof(daddr_t)) || | |
81 | dp->di_mode || dp->di_size) { | |
82 | pfatal("PARTIALLY ALLOCATED INODE I=%lu", inumber); | |
993a756c | 83 | if (reply("CLEAR") == 1) { |
0b4b70a9 | 84 | dp = ginode(inumber); |
569ec282 | 85 | clearinode(dp); |
993a756c | 86 | inodirty(); |
19052d90 KM |
87 | } |
88 | } | |
bab4bc3e KM |
89 | statemap[inumber] = USTATE; |
90 | return; | |
91 | } | |
92 | lastino = inumber; | |
93 | if (/* dp->di_size < 0 || */ | |
94 | dp->di_size + sblock.fs_bsize - 1 < dp->di_size) { | |
95 | if (debug) | |
96 | printf("bad size %qu:", dp->di_size); | |
97 | goto unknown; | |
98 | } | |
99 | if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { | |
100 | dp = ginode(inumber); | |
101 | dp->di_size = sblock.fs_fsize; | |
102 | dp->di_mode = IFREG|0600; | |
103 | inodirty(); | |
104 | } | |
105 | ndb = howmany(dp->di_size, sblock.fs_bsize); | |
106 | if (ndb < 0) { | |
107 | if (debug) | |
108 | printf("bad size %qu ndb %d:", | |
109 | dp->di_size, ndb); | |
110 | goto unknown; | |
111 | } | |
112 | if (mode == IFBLK || mode == IFCHR) | |
113 | ndb++; | |
114 | if (mode == IFLNK) { | |
a0cb9f5b KM |
115 | if (doinglevel2 && |
116 | dp->di_size > 0 && dp->di_size < MAXSYMLINKLEN && | |
117 | dp->di_blocks != 0) { | |
bab4bc3e KM |
118 | if (bread(fsreadfd, symbuf, |
119 | fsbtodb(&sblock, dp->di_db[0]), | |
120 | (long)dp->di_size) != 0) | |
121 | errexit("cannot read symlink"); | |
a0cb9f5b KM |
122 | if (debug) { |
123 | symbuf[dp->di_size] = 0; | |
124 | printf("convert symlink %d(%s) of size %d\n", | |
125 | inumber, symbuf, (long)dp->di_size); | |
126 | } | |
bab4bc3e KM |
127 | dp = ginode(inumber); |
128 | bcopy(symbuf, (caddr_t)dp->di_shortlink, | |
129 | (long)dp->di_size); | |
130 | dp->di_blocks = 0; | |
131 | inodirty(); | |
132 | } | |
a0cb9f5b KM |
133 | /* |
134 | * Fake ndb value so direct/indirect block checks below | |
135 | * will detect any garbage after symlink string. | |
136 | */ | |
137 | if (dp->di_size < sblock.fs_maxsymlinklen) { | |
bab4bc3e | 138 | ndb = howmany(dp->di_size, sizeof(daddr_t)); |
a0cb9f5b KM |
139 | if (ndb > NDADDR) { |
140 | j = ndb - NDADDR; | |
141 | for (ndb = 1; j > 1; j--) | |
142 | ndb *= NINDIR(&sblock); | |
143 | ndb += NDADDR; | |
144 | } | |
145 | } | |
bab4bc3e KM |
146 | } |
147 | for (j = ndb; j < NDADDR; j++) | |
148 | if (dp->di_db[j] != 0) { | |
149 | if (debug) | |
150 | printf("bad direct addr: %ld\n", dp->di_db[j]); | |
151 | goto unknown; | |
152 | } | |
153 | for (j = 0, ndb -= NDADDR; ndb > 0; j++) | |
154 | ndb /= NINDIR(&sblock); | |
155 | for (; j < NIADDR; j++) | |
156 | if (dp->di_ib[j] != 0) { | |
157 | if (debug) | |
158 | printf("bad indirect addr: %ld\n", | |
159 | dp->di_ib[j]); | |
160 | goto unknown; | |
161 | } | |
162 | if (ftypeok(dp) == 0) | |
163 | goto unknown; | |
164 | n_files++; | |
165 | lncntp[inumber] = dp->di_nlink; | |
166 | if (dp->di_nlink <= 0) { | |
167 | zlnp = (struct zlncnt *)malloc(sizeof *zlnp); | |
168 | if (zlnp == NULL) { | |
169 | pfatal("LINK COUNT TABLE OVERFLOW"); | |
170 | if (reply("CONTINUE") == 0) | |
171 | errexit(""); | |
172 | } else { | |
173 | zlnp->zlncnt = inumber; | |
174 | zlnp->next = zlnhead; | |
175 | zlnhead = zlnp; | |
176 | } | |
177 | } | |
178 | if (mode == IFDIR) { | |
179 | if (dp->di_size == 0) | |
180 | statemap[inumber] = DCLEAR; | |
181 | else | |
182 | statemap[inumber] = DSTATE; | |
183 | cacheino(dp, inumber); | |
184 | } else | |
185 | statemap[inumber] = FSTATE; | |
186 | typemap[inumber] = IFTODT(mode); | |
a0cb9f5b | 187 | if (doinglevel2 && (dp->di_ouid != -1 || dp->di_ogid != -1)) { |
bab4bc3e KM |
188 | dp = ginode(inumber); |
189 | dp->di_uid = dp->di_ouid; | |
190 | dp->di_ouid = -1; | |
191 | dp->di_gid = dp->di_ogid; | |
192 | dp->di_ogid = -1; | |
193 | inodirty(); | |
194 | } | |
195 | badblk = dupblk = 0; | |
196 | idesc->id_number = inumber; | |
197 | (void)ckinode(dp, idesc); | |
198 | idesc->id_entryno *= btodb(sblock.fs_fsize); | |
199 | if (dp->di_blocks != idesc->id_entryno) { | |
200 | pwarn("INCORRECT BLOCK COUNT I=%lu (%ld should be %ld)", | |
201 | inumber, dp->di_blocks, idesc->id_entryno); | |
202 | if (preen) | |
203 | printf(" (CORRECTED)\n"); | |
204 | else if (reply("CORRECT") == 0) | |
205 | return; | |
206 | dp = ginode(inumber); | |
207 | dp->di_blocks = idesc->id_entryno; | |
208 | inodirty(); | |
209 | } | |
210 | return; | |
211 | unknown: | |
212 | pfatal("UNKNOWN FILE TYPE I=%lu", inumber); | |
213 | statemap[inumber] = FCLEAR; | |
214 | if (reply("CLEAR") == 1) { | |
215 | statemap[inumber] = USTATE; | |
216 | dp = ginode(inumber); | |
217 | clearinode(dp); | |
218 | inodirty(); | |
19052d90 KM |
219 | } |
220 | } | |
221 | ||
222 | pass1check(idesc) | |
223 | register struct inodesc *idesc; | |
224 | { | |
19052d90 KM |
225 | int res = KEEPON; |
226 | int anyout, nfrags; | |
227 | daddr_t blkno = idesc->id_blkno; | |
62e6c152 KM |
228 | register struct dups *dlp; |
229 | struct dups *new; | |
19052d90 | 230 | |
569ec282 KM |
231 | if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { |
232 | blkerror(idesc->id_number, "BAD", blkno); | |
3752dfc6 | 233 | if (badblk++ >= MAXBAD) { |
d72e970b | 234 | pwarn("EXCESSIVE BAD BLKS I=%lu", |
7718c0e6 KM |
235 | idesc->id_number); |
236 | if (preen) | |
237 | printf(" (SKIPPING)\n"); | |
238 | else if (reply("CONTINUE") == 0) | |
239 | errexit(""); | |
240 | return (STOP); | |
241 | } | |
242 | } | |
19052d90 | 243 | for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { |
569ec282 | 244 | if (anyout && chkrange(blkno, 1)) { |
19052d90 | 245 | res = SKIP; |
569ec282 | 246 | } else if (!testbmap(blkno)) { |
7718c0e6 KM |
247 | n_blks++; |
248 | setbmap(blkno); | |
249 | } else { | |
569ec282 | 250 | blkerror(idesc->id_number, "DUP", blkno); |
3752dfc6 | 251 | if (dupblk++ >= MAXDUP) { |
d72e970b | 252 | pwarn("EXCESSIVE DUP BLKS I=%lu", |
19052d90 KM |
253 | idesc->id_number); |
254 | if (preen) | |
255 | printf(" (SKIPPING)\n"); | |
256 | else if (reply("CONTINUE") == 0) | |
257 | errexit(""); | |
258 | return (STOP); | |
259 | } | |
62e6c152 KM |
260 | new = (struct dups *)malloc(sizeof(struct dups)); |
261 | if (new == NULL) { | |
19052d90 KM |
262 | pfatal("DUP TABLE OVERFLOW."); |
263 | if (reply("CONTINUE") == 0) | |
264 | errexit(""); | |
265 | return (STOP); | |
266 | } | |
62e6c152 KM |
267 | new->dup = blkno; |
268 | if (muldup == 0) { | |
269 | duplist = muldup = new; | |
270 | new->next = 0; | |
271 | } else { | |
272 | new->next = muldup->next; | |
273 | muldup->next = new; | |
19052d90 | 274 | } |
62e6c152 KM |
275 | for (dlp = duplist; dlp != muldup; dlp = dlp->next) |
276 | if (dlp->dup == blkno) | |
277 | break; | |
278 | if (dlp == muldup && dlp->dup != blkno) | |
279 | muldup = new; | |
19052d90 | 280 | } |
f0ed004a KM |
281 | /* |
282 | * count the number of blocks found in id_entryno | |
283 | */ | |
284 | idesc->id_entryno++; | |
19052d90 KM |
285 | } |
286 | return (res); | |
287 | } |