Couple of new variables...
[unix-history] / usr / src / sbin / fsck / pass2.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
ba8f3d8f 8#ifndef lint
fca9f60c 9static char sccsid[] = "@(#)pass2.c 5.17 (Berkeley) %G%";
fe32782c 10#endif /* not lint */
ba8f3d8f
KM
11
12#include <sys/param.h>
72e5286b 13#include <ufs/dinode.h>
4d7f4685 14#include <ufs/fs.h>
987e77a3 15#define KERNEL
4d7f4685 16#include <ufs/dir.h>
987e77a3 17#undef KERNEL
d72e970b 18#include <stdlib.h>
38dde0cd 19#include <string.h>
ba8f3d8f
KM
20#include "fsck.h"
21
987e77a3
KM
22#define MINDIRSIZE (sizeof (struct dirtemplate))
23
24int pass2check(), blksort();
ba8f3d8f
KM
25
26pass2()
27{
569ec282 28 register struct dinode *dp;
987e77a3
KM
29 register struct inoinfo **inpp, *inp;
30 struct inoinfo **inpend;
31 struct inodesc curino;
32 struct dinode dino;
33 char pathbuf[MAXPATHLEN + 1];
ba8f3d8f 34
ba8f3d8f
KM
35 switch (statemap[ROOTINO]) {
36
37 case USTATE:
7e1e49f2
KM
38 pfatal("ROOT INODE UNALLOCATED");
39 if (reply("ALLOCATE") == 0)
40 errexit("");
c689da7b 41 if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
7e1e49f2 42 errexit("CANNOT ALLOCATE ROOT INODE\n");
7e1e49f2
KM
43 break;
44
45 case DCLEAR:
46 pfatal("DUPS/BAD IN ROOT INODE");
47 if (reply("REALLOCATE")) {
48 freeino(ROOTINO);
c689da7b 49 if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
7e1e49f2 50 errexit("CANNOT ALLOCATE ROOT INODE\n");
7e1e49f2
KM
51 break;
52 }
53 if (reply("CONTINUE") == 0)
54 errexit("");
7e1e49f2 55 break;
ba8f3d8f
KM
56
57 case FSTATE:
993a756c 58 case FCLEAR:
ba8f3d8f 59 pfatal("ROOT INODE NOT DIRECTORY");
7e1e49f2
KM
60 if (reply("REALLOCATE")) {
61 freeino(ROOTINO);
c689da7b 62 if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
7e1e49f2 63 errexit("CANNOT ALLOCATE ROOT INODE\n");
7e1e49f2
KM
64 break;
65 }
39c18287 66 if (reply("FIX") == 0)
ba8f3d8f 67 errexit("");
39c18287 68 dp = ginode(ROOTINO);
ba8f3d8f
KM
69 dp->di_mode &= ~IFMT;
70 dp->di_mode |= IFDIR;
71 inodirty();
987e77a3 72 break;
ba8f3d8f
KM
73
74 case DSTATE:
ba8f3d8f
KM
75 break;
76
993a756c
KM
77 default:
78 errexit("BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]);
ba8f3d8f 79 }
987e77a3
KM
80 statemap[ROOTINO] = DFOUND;
81 /*
82 * Sort the directory list into disk block order.
83 */
d72e970b 84 qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort);
987e77a3
KM
85 /*
86 * Check the integrity of each directory.
87 */
88 bzero((char *)&curino, sizeof(struct inodesc));
89 curino.id_type = DATA;
90 curino.id_func = pass2check;
7a11042a 91 dino.di_mode = IFDIR;
987e77a3
KM
92 dp = &dino;
93 inpend = &inpsort[inplast];
94 for (inpp = inpsort; inpp < inpend; inpp++) {
95 inp = *inpp;
f13c3b57
KM
96 if (inp->i_isize == 0)
97 continue;
987e77a3
KM
98 if (inp->i_isize < MINDIRSIZE) {
99 direrror(inp->i_number, "DIRECTORY TOO SHORT");
3017a9c8 100 inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ);
987e77a3
KM
101 if (reply("FIX") == 1) {
102 dp = ginode(inp->i_number);
3017a9c8 103 dp->di_size = inp->i_isize;
987e77a3
KM
104 inodirty();
105 dp = &dino;
106 }
3017a9c8 107 } else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) {
987e77a3
KM
108 getpathname(pathbuf, inp->i_number, inp->i_number);
109 pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d",
110 pathbuf, inp->i_isize, DIRBLKSIZ);
111 if (preen)
112 printf(" (ADJUSTED)\n");
113 inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ);
114 if (preen || reply("ADJUST") == 1) {
115 dp = ginode(inp->i_number);
116 dp->di_size = roundup(inp->i_isize, DIRBLKSIZ);
117 inodirty();
118 dp = &dino;
119 }
120 }
121 dp->di_size = inp->i_isize;
122 bcopy((char *)&inp->i_blks[0], (char *)&dp->di_db[0],
d72e970b 123 (size_t)inp->i_numblks);
987e77a3
KM
124 curino.id_number = inp->i_number;
125 curino.id_parent = inp->i_parent;
126 (void)ckinode(dp, &curino);
127 }
128 /*
129 * Now that the parents of all directories have been found,
130 * make another pass to verify the value of `..'
131 */
132 for (inpp = inpsort; inpp < inpend; inpp++) {
133 inp = *inpp;
f13c3b57 134 if (inp->i_parent == 0 || inp->i_isize == 0)
987e77a3
KM
135 continue;
136 if (statemap[inp->i_parent] == DFOUND &&
137 statemap[inp->i_number] == DSTATE)
138 statemap[inp->i_number] = DFOUND;
139 if (inp->i_dotdot == inp->i_parent ||
140 inp->i_dotdot == (ino_t)-1)
141 continue;
142 if (inp->i_dotdot == 0) {
143 inp->i_dotdot = inp->i_parent;
144 fileerror(inp->i_parent, inp->i_number, "MISSING '..'");
145 if (reply("FIX") == 0)
146 continue;
d72e970b 147 (void)makeentry(inp->i_number, inp->i_parent, "..");
987e77a3
KM
148 lncntp[inp->i_parent]--;
149 continue;
150 }
151 fileerror(inp->i_parent, inp->i_number,
152 "BAD INODE NUMBER FOR '..'");
153 if (reply("FIX") == 0)
154 continue;
155 lncntp[inp->i_dotdot]++;
156 lncntp[inp->i_parent]--;
157 inp->i_dotdot = inp->i_parent;
158 (void)changeino(inp->i_number, "..", inp->i_parent);
159 }
160 /*
161 * Mark all the directories that can be found from the root.
162 */
163 propagate();
ba8f3d8f
KM
164}
165
166pass2check(idesc)
167 struct inodesc *idesc;
168{
569ec282 169 register struct direct *dirp = idesc->id_dirp;
987e77a3 170 register struct inoinfo *inp;
ba8f3d8f 171 int n, entrysize, ret = 0;
569ec282 172 struct dinode *dp;
f13c3b57 173 char *errmsg;
569ec282 174 struct direct proto;
987e77a3
KM
175 char namebuf[MAXPATHLEN + 1];
176 char pathbuf[MAXPATHLEN + 1];
ba8f3d8f
KM
177
178 /*
179 * check for "."
180 */
181 if (idesc->id_entryno != 0)
182 goto chk1;
183 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
184 if (dirp->d_ino != idesc->id_number) {
569ec282 185 direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
ba8f3d8f
KM
186 dirp->d_ino = idesc->id_number;
187 if (reply("FIX") == 1)
188 ret |= ALTERED;
189 }
190 goto chk1;
191 }
569ec282 192 direrror(idesc->id_number, "MISSING '.'");
ba8f3d8f
KM
193 proto.d_ino = idesc->id_number;
194 proto.d_namlen = 1;
195 (void)strcpy(proto.d_name, ".");
196 entrysize = DIRSIZ(&proto);
197 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
198 pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
199 dirp->d_name);
200 } else if (dirp->d_reclen < entrysize) {
201 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
202 } else if (dirp->d_reclen < 2 * entrysize) {
203 proto.d_reclen = dirp->d_reclen;
d72e970b 204 bcopy((char *)&proto, (char *)dirp, (size_t)entrysize);
ba8f3d8f
KM
205 if (reply("FIX") == 1)
206 ret |= ALTERED;
207 } else {
208 n = dirp->d_reclen - entrysize;
209 proto.d_reclen = entrysize;
d72e970b 210 bcopy((char *)&proto, (char *)dirp, (size_t)entrysize);
ba8f3d8f
KM
211 idesc->id_entryno++;
212 lncntp[dirp->d_ino]--;
569ec282 213 dirp = (struct direct *)((char *)(dirp) + entrysize);
d72e970b 214 bzero((char *)dirp, (size_t)n);
ba8f3d8f
KM
215 dirp->d_reclen = n;
216 if (reply("FIX") == 1)
217 ret |= ALTERED;
218 }
219chk1:
220 if (idesc->id_entryno > 1)
221 goto chk2;
987e77a3
KM
222 inp = getinoinfo(idesc->id_number);
223 proto.d_ino = inp->i_parent;
ba8f3d8f
KM
224 proto.d_namlen = 2;
225 (void)strcpy(proto.d_name, "..");
226 entrysize = DIRSIZ(&proto);
227 if (idesc->id_entryno == 0) {
228 n = DIRSIZ(dirp);
229 if (dirp->d_reclen < n + entrysize)
230 goto chk2;
231 proto.d_reclen = dirp->d_reclen - n;
232 dirp->d_reclen = n;
233 idesc->id_entryno++;
234 lncntp[dirp->d_ino]--;
569ec282 235 dirp = (struct direct *)((char *)(dirp) + n);
d72e970b 236 bzero((char *)dirp, (size_t)proto.d_reclen);
987e77a3 237 dirp->d_reclen = proto.d_reclen;
ba8f3d8f
KM
238 }
239 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
987e77a3 240 inp->i_dotdot = dirp->d_ino;
ba8f3d8f
KM
241 goto chk2;
242 }
ba8f3d8f 243 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
987e77a3 244 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
ba8f3d8f
KM
245 pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
246 dirp->d_name);
987e77a3 247 inp->i_dotdot = (ino_t)-1;
ba8f3d8f 248 } else if (dirp->d_reclen < entrysize) {
987e77a3 249 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
ba8f3d8f 250 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
987e77a3
KM
251 inp->i_dotdot = (ino_t)-1;
252 } else if (inp->i_parent != 0) {
253 /*
254 * We know the parent, so fix now.
255 */
256 inp->i_dotdot = inp->i_parent;
257 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
ba8f3d8f 258 proto.d_reclen = dirp->d_reclen;
d72e970b 259 bcopy((char *)&proto, (char *)dirp, (size_t)entrysize);
ba8f3d8f
KM
260 if (reply("FIX") == 1)
261 ret |= ALTERED;
262 }
987e77a3
KM
263 idesc->id_entryno++;
264 if (dirp->d_ino != 0)
265 lncntp[dirp->d_ino]--;
266 return (ret|KEEPON);
ba8f3d8f
KM
267chk2:
268 if (dirp->d_ino == 0)
269 return (ret|KEEPON);
270 if (dirp->d_namlen <= 2 &&
271 dirp->d_name[0] == '.' &&
272 idesc->id_entryno >= 2) {
273 if (dirp->d_namlen == 1) {
569ec282 274 direrror(idesc->id_number, "EXTRA '.' ENTRY");
ba8f3d8f
KM
275 dirp->d_ino = 0;
276 if (reply("FIX") == 1)
277 ret |= ALTERED;
278 return (KEEPON | ret);
279 }
280 if (dirp->d_name[1] == '.') {
569ec282 281 direrror(idesc->id_number, "EXTRA '..' ENTRY");
ba8f3d8f
KM
282 dirp->d_ino = 0;
283 if (reply("FIX") == 1)
284 ret |= ALTERED;
285 return (KEEPON | ret);
286 }
287 }
ba8f3d8f
KM
288 idesc->id_entryno++;
289 n = 0;
fca9f60c 290 if (dirp->d_ino > maxino) {
987e77a3 291 fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
ba8f3d8f
KM
292 n = reply("REMOVE");
293 } else {
294again:
295 switch (statemap[dirp->d_ino]) {
296 case USTATE:
8dc4ce37
KM
297 if (idesc->id_entryno <= 2)
298 break;
987e77a3 299 fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED");
ba8f3d8f
KM
300 n = reply("REMOVE");
301 break;
302
993a756c
KM
303 case DCLEAR:
304 case FCLEAR:
8dc4ce37
KM
305 if (idesc->id_entryno <= 2)
306 break;
f13c3b57
KM
307 if (statemap[dirp->d_ino] == DCLEAR)
308 errmsg = "ZERO LENGTH DIRECTORY";
309 else
310 errmsg = "DUP/BAD";
311 fileerror(idesc->id_number, dirp->d_ino, errmsg);
ba8f3d8f
KM
312 if ((n = reply("REMOVE")) == 1)
313 break;
39c18287 314 dp = ginode(dirp->d_ino);
569ec282
KM
315 statemap[dirp->d_ino] =
316 (dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE;
77d16a71 317 lncntp[dirp->d_ino] = dp->di_nlink;
ba8f3d8f
KM
318 goto again;
319
987e77a3
KM
320 case DSTATE:
321 if (statemap[idesc->id_number] == DFOUND)
322 statemap[dirp->d_ino] = DFOUND;
323 /* fall through */
324
993a756c 325 case DFOUND:
987e77a3 326 inp = getinoinfo(dirp->d_ino);
987e77a3
KM
327 if (inp->i_parent != 0 && idesc->id_entryno > 2) {
328 getpathname(pathbuf, idesc->id_number,
329 idesc->id_number);
3ad2f081 330 getpathname(namebuf, dirp->d_ino, dirp->d_ino);
987e77a3 331 pwarn("%s %s %s\n", pathbuf,
3ad2f081
KM
332 "IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
333 namebuf);
334 if (preen)
335 printf(" (IGNORED)\n");
336 else if ((n = reply("REMOVE")) == 1)
337 break;
338 }
987e77a3
KM
339 if (idesc->id_entryno > 2)
340 inp->i_parent = idesc->id_number;
993a756c
KM
341 /* fall through */
342
ba8f3d8f
KM
343 case FSTATE:
344 lncntp[dirp->d_ino]--;
345 break;
346
ea4448dc
KM
347 default:
348 errexit("BAD STATE %d FOR INODE I=%d",
349 statemap[dirp->d_ino], dirp->d_ino);
ba8f3d8f
KM
350 }
351 }
ba8f3d8f
KM
352 if (n == 0)
353 return (ret|KEEPON);
354 dirp->d_ino = 0;
355 return (ret|KEEPON|ALTERED);
356}
987e77a3
KM
357
358/*
359 * Routine to sort disk blocks.
360 */
361blksort(inpp1, inpp2)
362 struct inoinfo **inpp1, **inpp2;
363{
364
365 return ((*inpp1)->i_blks[0] - (*inpp2)->i_blks[0]);
366}