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