manual page distributed with 4.1BSD
[unix-history] / usr / src / sbin / fsck / pass2.c
CommitLineData
ba8f3d8f 1#ifndef lint
3ad2f081 2static char version[] = "@(#)pass2.c 3.6 (Berkeley) %G%";
ba8f3d8f
KM
3#endif
4
5#include <sys/param.h>
6#include <sys/inode.h>
7#include <sys/fs.h>
8#include <sys/dir.h>
9#include <strings.h>
10#include "fsck.h"
11
12int pass2check();
13
14pass2()
15{
16 register DINODE *dp;
17 struct inodesc rootdesc;
18
19 bzero((char *)&rootdesc, sizeof(struct inodesc));
20 rootdesc.id_type = ADDR;
21 rootdesc.id_func = pass2check;
22 rootdesc.id_number = ROOTINO;
23 pathp = pathname;
24 switch (statemap[ROOTINO]) {
25
26 case USTATE:
7e1e49f2
KM
27 pfatal("ROOT INODE UNALLOCATED");
28 if (reply("ALLOCATE") == 0)
29 errexit("");
30 if (allocdir(ROOTINO, ROOTINO) != ROOTINO)
31 errexit("CANNOT ALLOCATE ROOT INODE\n");
32 descend(&rootdesc, ROOTINO);
33 break;
34
35 case DCLEAR:
36 pfatal("DUPS/BAD IN ROOT INODE");
37 if (reply("REALLOCATE")) {
38 freeino(ROOTINO);
39 if (allocdir(ROOTINO, ROOTINO) != ROOTINO)
40 errexit("CANNOT ALLOCATE ROOT INODE\n");
41 descend(&rootdesc, ROOTINO);
42 break;
43 }
44 if (reply("CONTINUE") == 0)
45 errexit("");
46 statemap[ROOTINO] = DSTATE;
47 descend(&rootdesc, ROOTINO);
48 break;
ba8f3d8f
KM
49
50 case FSTATE:
993a756c 51 case FCLEAR:
ba8f3d8f 52 pfatal("ROOT INODE NOT DIRECTORY");
7e1e49f2
KM
53 if (reply("REALLOCATE")) {
54 freeino(ROOTINO);
55 if (allocdir(ROOTINO, ROOTINO) != ROOTINO)
56 errexit("CANNOT ALLOCATE ROOT INODE\n");
57 descend(&rootdesc, ROOTINO);
58 break;
59 }
39c18287 60 if (reply("FIX") == 0)
ba8f3d8f 61 errexit("");
39c18287 62 dp = ginode(ROOTINO);
ba8f3d8f
KM
63 dp->di_mode &= ~IFMT;
64 dp->di_mode |= IFDIR;
65 inodirty();
ba8f3d8f
KM
66 statemap[ROOTINO] = DSTATE;
67 /* fall into ... */
68
69 case DSTATE:
70 descend(&rootdesc, ROOTINO);
71 break;
72
993a756c
KM
73 default:
74 errexit("BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]);
ba8f3d8f
KM
75 }
76}
77
78pass2check(idesc)
79 struct inodesc *idesc;
80{
81 register DIRECT *dirp = idesc->id_dirp;
82 char *curpathloc;
83 int n, entrysize, ret = 0;
84 DINODE *dp;
85 DIRECT proto;
3ad2f081 86 char namebuf[BUFSIZ];
ba8f3d8f
KM
87
88 /*
89 * check for "."
90 */
91 if (idesc->id_entryno != 0)
92 goto chk1;
93 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
94 if (dirp->d_ino != idesc->id_number) {
95 direrr(idesc->id_number, "BAD INODE NUMBER FOR '.'");
96 dirp->d_ino = idesc->id_number;
97 if (reply("FIX") == 1)
98 ret |= ALTERED;
99 }
100 goto chk1;
101 }
102 direrr(idesc->id_number, "MISSING '.'");
103 proto.d_ino = idesc->id_number;
104 proto.d_namlen = 1;
105 (void)strcpy(proto.d_name, ".");
106 entrysize = DIRSIZ(&proto);
107 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
108 pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
109 dirp->d_name);
110 } else if (dirp->d_reclen < entrysize) {
111 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
112 } else if (dirp->d_reclen < 2 * entrysize) {
113 proto.d_reclen = dirp->d_reclen;
114 bcopy((char *)&proto, (char *)dirp, entrysize);
115 if (reply("FIX") == 1)
116 ret |= ALTERED;
117 } else {
118 n = dirp->d_reclen - entrysize;
119 proto.d_reclen = entrysize;
120 bcopy((char *)&proto, (char *)dirp, entrysize);
121 idesc->id_entryno++;
122 lncntp[dirp->d_ino]--;
123 dirp = (DIRECT *)((char *)(dirp) + entrysize);
124 bzero((char *)dirp, n);
125 dirp->d_reclen = n;
126 if (reply("FIX") == 1)
127 ret |= ALTERED;
128 }
129chk1:
130 if (idesc->id_entryno > 1)
131 goto chk2;
132 proto.d_ino = idesc->id_parent;
133 proto.d_namlen = 2;
134 (void)strcpy(proto.d_name, "..");
135 entrysize = DIRSIZ(&proto);
136 if (idesc->id_entryno == 0) {
137 n = DIRSIZ(dirp);
138 if (dirp->d_reclen < n + entrysize)
139 goto chk2;
140 proto.d_reclen = dirp->d_reclen - n;
141 dirp->d_reclen = n;
142 idesc->id_entryno++;
143 lncntp[dirp->d_ino]--;
144 dirp = (DIRECT *)((char *)(dirp) + n);
145 bzero((char *)dirp, n);
146 dirp->d_reclen = n;
147 }
148 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
149 if (dirp->d_ino != idesc->id_parent) {
150 direrr(idesc->id_number, "BAD INODE NUMBER FOR '..'");
151 dirp->d_ino = idesc->id_parent;
152 if (reply("FIX") == 1)
153 ret |= ALTERED;
154 }
155 goto chk2;
156 }
157 direrr(idesc->id_number, "MISSING '..'");
158 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
159 pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
160 dirp->d_name);
161 } else if (dirp->d_reclen < entrysize) {
162 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
163 } else {
164 proto.d_reclen = dirp->d_reclen;
165 bcopy((char *)&proto, (char *)dirp, entrysize);
166 if (reply("FIX") == 1)
167 ret |= ALTERED;
168 }
169chk2:
170 if (dirp->d_ino == 0)
171 return (ret|KEEPON);
172 if (dirp->d_namlen <= 2 &&
173 dirp->d_name[0] == '.' &&
174 idesc->id_entryno >= 2) {
175 if (dirp->d_namlen == 1) {
176 direrr(idesc->id_number, "EXTRA '.' ENTRY");
177 dirp->d_ino = 0;
178 if (reply("FIX") == 1)
179 ret |= ALTERED;
180 return (KEEPON | ret);
181 }
182 if (dirp->d_name[1] == '.') {
183 direrr(idesc->id_number, "EXTRA '..' ENTRY");
184 dirp->d_ino = 0;
185 if (reply("FIX") == 1)
186 ret |= ALTERED;
187 return (KEEPON | ret);
188 }
189 }
190 curpathloc = pathp;
191 *pathp++ = '/';
192 if (pathp + dirp->d_namlen >= endpathname) {
193 *pathp = '\0';
194 errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name);
195 }
196 bcopy(dirp->d_name, pathp, dirp->d_namlen + 1);
197 pathp += dirp->d_namlen;
198 idesc->id_entryno++;
199 n = 0;
200 if (dirp->d_ino > imax || dirp->d_ino <= 0) {
201 direrr(dirp->d_ino, "I OUT OF RANGE");
202 n = reply("REMOVE");
203 } else {
204again:
205 switch (statemap[dirp->d_ino]) {
206 case USTATE:
207 direrr(dirp->d_ino, "UNALLOCATED");
208 n = reply("REMOVE");
209 break;
210
993a756c
KM
211 case DCLEAR:
212 case FCLEAR:
ba8f3d8f
KM
213 direrr(dirp->d_ino, "DUP/BAD");
214 if ((n = reply("REMOVE")) == 1)
215 break;
39c18287 216 dp = ginode(dirp->d_ino);
7718c0e6 217 statemap[dirp->d_ino] = DIRCT(dp) ? DSTATE : FSTATE;
ba8f3d8f
KM
218 goto again;
219
993a756c 220 case DFOUND:
3ad2f081
KM
221 if (idesc->id_entryno > 2) {
222 getpathname(namebuf, dirp->d_ino, dirp->d_ino);
223 pwarn("%s %s %s\n", pathname,
224 "IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
225 namebuf);
226 if (preen)
227 printf(" (IGNORED)\n");
228 else if ((n = reply("REMOVE")) == 1)
229 break;
230 }
993a756c
KM
231 /* fall through */
232
ba8f3d8f
KM
233 case FSTATE:
234 lncntp[dirp->d_ino]--;
235 break;
236
237 case DSTATE:
238 descend(idesc, dirp->d_ino);
993a756c 239 if (statemap[dirp->d_ino] == DFOUND) {
ba8f3d8f 240 lncntp[dirp->d_ino]--;
993a756c 241 } else if (statemap[dirp->d_ino] == DCLEAR) {
ba8f3d8f
KM
242 dirp->d_ino = 0;
243 ret |= ALTERED;
993a756c
KM
244 } else
245 errexit("BAD RETURN STATE %d FROM DESCEND",
246 statemap[dirp->d_ino]);
ba8f3d8f
KM
247 break;
248 }
249 }
250 pathp = curpathloc;
251 *pathp = '\0';
252 if (n == 0)
253 return (ret|KEEPON);
254 dirp->d_ino = 0;
255 return (ret|KEEPON|ALTERED);
256}