4.4BSD snapshot (revision 8.1)
[unix-history] / usr / src / sbin / fsck / pass1.c
CommitLineData
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
be6e94c6 9static char sccsid[] = "@(#)pass1.c 5.21 (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
21static daddr_t badblk;
22static daddr_t dupblk;
23int pass1check();
a0cb24a2 24struct dinode *getnextinode();
19052d90
KM
25
26pass1()
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
64checkinode(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);
be6e94c6
KM
187 if (doinglevel2 &&
188 (dp->di_ouid != (u_short)-1 || dp->di_ogid != (u_short)-1)) {
bab4bc3e
KM
189 dp = ginode(inumber);
190 dp->di_uid = dp->di_ouid;
191 dp->di_ouid = -1;
192 dp->di_gid = dp->di_ogid;
193 dp->di_ogid = -1;
194 inodirty();
195 }
196 badblk = dupblk = 0;
197 idesc->id_number = inumber;
198 (void)ckinode(dp, idesc);
199 idesc->id_entryno *= btodb(sblock.fs_fsize);
200 if (dp->di_blocks != idesc->id_entryno) {
201 pwarn("INCORRECT BLOCK COUNT I=%lu (%ld should be %ld)",
202 inumber, dp->di_blocks, idesc->id_entryno);
203 if (preen)
204 printf(" (CORRECTED)\n");
205 else if (reply("CORRECT") == 0)
206 return;
207 dp = ginode(inumber);
208 dp->di_blocks = idesc->id_entryno;
209 inodirty();
210 }
211 return;
212unknown:
213 pfatal("UNKNOWN FILE TYPE I=%lu", inumber);
214 statemap[inumber] = FCLEAR;
215 if (reply("CLEAR") == 1) {
216 statemap[inumber] = USTATE;
217 dp = ginode(inumber);
218 clearinode(dp);
219 inodirty();
19052d90
KM
220 }
221}
222
223pass1check(idesc)
224 register struct inodesc *idesc;
225{
19052d90
KM
226 int res = KEEPON;
227 int anyout, nfrags;
228 daddr_t blkno = idesc->id_blkno;
62e6c152
KM
229 register struct dups *dlp;
230 struct dups *new;
19052d90 231
569ec282
KM
232 if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
233 blkerror(idesc->id_number, "BAD", blkno);
3752dfc6 234 if (badblk++ >= MAXBAD) {
d72e970b 235 pwarn("EXCESSIVE BAD BLKS I=%lu",
7718c0e6
KM
236 idesc->id_number);
237 if (preen)
238 printf(" (SKIPPING)\n");
239 else if (reply("CONTINUE") == 0)
240 errexit("");
241 return (STOP);
242 }
243 }
19052d90 244 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
569ec282 245 if (anyout && chkrange(blkno, 1)) {
19052d90 246 res = SKIP;
569ec282 247 } else if (!testbmap(blkno)) {
7718c0e6
KM
248 n_blks++;
249 setbmap(blkno);
250 } else {
569ec282 251 blkerror(idesc->id_number, "DUP", blkno);
3752dfc6 252 if (dupblk++ >= MAXDUP) {
d72e970b 253 pwarn("EXCESSIVE DUP BLKS I=%lu",
19052d90
KM
254 idesc->id_number);
255 if (preen)
256 printf(" (SKIPPING)\n");
257 else if (reply("CONTINUE") == 0)
258 errexit("");
259 return (STOP);
260 }
62e6c152
KM
261 new = (struct dups *)malloc(sizeof(struct dups));
262 if (new == NULL) {
19052d90
KM
263 pfatal("DUP TABLE OVERFLOW.");
264 if (reply("CONTINUE") == 0)
265 errexit("");
266 return (STOP);
267 }
62e6c152
KM
268 new->dup = blkno;
269 if (muldup == 0) {
270 duplist = muldup = new;
271 new->next = 0;
272 } else {
273 new->next = muldup->next;
274 muldup->next = new;
19052d90 275 }
62e6c152
KM
276 for (dlp = duplist; dlp != muldup; dlp = dlp->next)
277 if (dlp->dup == blkno)
278 break;
279 if (dlp == muldup && dlp->dup != blkno)
280 muldup = new;
19052d90 281 }
f0ed004a
KM
282 /*
283 * count the number of blocks found in id_entryno
284 */
285 idesc->id_entryno++;
19052d90
KM
286 }
287 return (res);
288}