ginode() succeeds or exits
[unix-history] / usr / src / sbin / fsck / pass2.c
CommitLineData
ba8f3d8f 1#ifndef lint
39c18287 2static char version[] = "@(#)pass2.c 3.4 (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:
27 errexit("ROOT INODE UNALLOCATED. TERMINATING.\n");
28
29 case FSTATE:
993a756c 30 case FCLEAR:
ba8f3d8f 31 pfatal("ROOT INODE NOT DIRECTORY");
39c18287 32 if (reply("FIX") == 0)
ba8f3d8f 33 errexit("");
39c18287 34 dp = ginode(ROOTINO);
ba8f3d8f
KM
35 dp->di_mode &= ~IFMT;
36 dp->di_mode |= IFDIR;
37 inodirty();
ba8f3d8f
KM
38 statemap[ROOTINO] = DSTATE;
39 /* fall into ... */
40
41 case DSTATE:
42 descend(&rootdesc, ROOTINO);
43 break;
44
993a756c 45 case DCLEAR:
ba8f3d8f
KM
46 pfatal("DUPS/BAD IN ROOT INODE");
47 printf("\n");
48 if (reply("CONTINUE") == 0)
49 errexit("");
50 statemap[ROOTINO] = DSTATE;
51 descend(&rootdesc, ROOTINO);
993a756c
KM
52
53 default:
54 errexit("BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]);
ba8f3d8f
KM
55 }
56}
57
58pass2check(idesc)
59 struct inodesc *idesc;
60{
61 register DIRECT *dirp = idesc->id_dirp;
62 char *curpathloc;
63 int n, entrysize, ret = 0;
64 DINODE *dp;
65 DIRECT proto;
66
67 /*
68 * check for "."
69 */
70 if (idesc->id_entryno != 0)
71 goto chk1;
72 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
73 if (dirp->d_ino != idesc->id_number) {
74 direrr(idesc->id_number, "BAD INODE NUMBER FOR '.'");
75 dirp->d_ino = idesc->id_number;
76 if (reply("FIX") == 1)
77 ret |= ALTERED;
78 }
79 goto chk1;
80 }
81 direrr(idesc->id_number, "MISSING '.'");
82 proto.d_ino = idesc->id_number;
83 proto.d_namlen = 1;
84 (void)strcpy(proto.d_name, ".");
85 entrysize = DIRSIZ(&proto);
86 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
87 pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
88 dirp->d_name);
89 } else if (dirp->d_reclen < entrysize) {
90 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
91 } else if (dirp->d_reclen < 2 * entrysize) {
92 proto.d_reclen = dirp->d_reclen;
93 bcopy((char *)&proto, (char *)dirp, entrysize);
94 if (reply("FIX") == 1)
95 ret |= ALTERED;
96 } else {
97 n = dirp->d_reclen - entrysize;
98 proto.d_reclen = entrysize;
99 bcopy((char *)&proto, (char *)dirp, entrysize);
100 idesc->id_entryno++;
101 lncntp[dirp->d_ino]--;
102 dirp = (DIRECT *)((char *)(dirp) + entrysize);
103 bzero((char *)dirp, n);
104 dirp->d_reclen = n;
105 if (reply("FIX") == 1)
106 ret |= ALTERED;
107 }
108chk1:
109 if (idesc->id_entryno > 1)
110 goto chk2;
111 proto.d_ino = idesc->id_parent;
112 proto.d_namlen = 2;
113 (void)strcpy(proto.d_name, "..");
114 entrysize = DIRSIZ(&proto);
115 if (idesc->id_entryno == 0) {
116 n = DIRSIZ(dirp);
117 if (dirp->d_reclen < n + entrysize)
118 goto chk2;
119 proto.d_reclen = dirp->d_reclen - n;
120 dirp->d_reclen = n;
121 idesc->id_entryno++;
122 lncntp[dirp->d_ino]--;
123 dirp = (DIRECT *)((char *)(dirp) + n);
124 bzero((char *)dirp, n);
125 dirp->d_reclen = n;
126 }
127 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
128 if (dirp->d_ino != idesc->id_parent) {
129 direrr(idesc->id_number, "BAD INODE NUMBER FOR '..'");
130 dirp->d_ino = idesc->id_parent;
131 if (reply("FIX") == 1)
132 ret |= ALTERED;
133 }
134 goto chk2;
135 }
136 direrr(idesc->id_number, "MISSING '..'");
137 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
138 pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
139 dirp->d_name);
140 } else if (dirp->d_reclen < entrysize) {
141 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
142 } else {
143 proto.d_reclen = dirp->d_reclen;
144 bcopy((char *)&proto, (char *)dirp, entrysize);
145 if (reply("FIX") == 1)
146 ret |= ALTERED;
147 }
148chk2:
149 if (dirp->d_ino == 0)
150 return (ret|KEEPON);
151 if (dirp->d_namlen <= 2 &&
152 dirp->d_name[0] == '.' &&
153 idesc->id_entryno >= 2) {
154 if (dirp->d_namlen == 1) {
155 direrr(idesc->id_number, "EXTRA '.' ENTRY");
156 dirp->d_ino = 0;
157 if (reply("FIX") == 1)
158 ret |= ALTERED;
159 return (KEEPON | ret);
160 }
161 if (dirp->d_name[1] == '.') {
162 direrr(idesc->id_number, "EXTRA '..' ENTRY");
163 dirp->d_ino = 0;
164 if (reply("FIX") == 1)
165 ret |= ALTERED;
166 return (KEEPON | ret);
167 }
168 }
169 curpathloc = pathp;
170 *pathp++ = '/';
171 if (pathp + dirp->d_namlen >= endpathname) {
172 *pathp = '\0';
173 errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name);
174 }
175 bcopy(dirp->d_name, pathp, dirp->d_namlen + 1);
176 pathp += dirp->d_namlen;
177 idesc->id_entryno++;
178 n = 0;
179 if (dirp->d_ino > imax || dirp->d_ino <= 0) {
180 direrr(dirp->d_ino, "I OUT OF RANGE");
181 n = reply("REMOVE");
182 } else {
183again:
184 switch (statemap[dirp->d_ino]) {
185 case USTATE:
186 direrr(dirp->d_ino, "UNALLOCATED");
187 n = reply("REMOVE");
188 break;
189
993a756c
KM
190 case DCLEAR:
191 case FCLEAR:
ba8f3d8f
KM
192 direrr(dirp->d_ino, "DUP/BAD");
193 if ((n = reply("REMOVE")) == 1)
194 break;
39c18287 195 dp = ginode(dirp->d_ino);
7718c0e6 196 statemap[dirp->d_ino] = DIRCT(dp) ? DSTATE : FSTATE;
ba8f3d8f
KM
197 goto again;
198
993a756c
KM
199 case DFOUND:
200 if (idesc->id_entryno > 2)
201 pwarn("WARNING: %s IS %s\n", pathname,
202 "AN EXTRANEOUS HARD LINK TO A DIRECTORY");
203 /* fall through */
204
ba8f3d8f
KM
205 case FSTATE:
206 lncntp[dirp->d_ino]--;
207 break;
208
209 case DSTATE:
210 descend(idesc, dirp->d_ino);
993a756c 211 if (statemap[dirp->d_ino] == DFOUND) {
ba8f3d8f 212 lncntp[dirp->d_ino]--;
993a756c 213 } else if (statemap[dirp->d_ino] == DCLEAR) {
ba8f3d8f
KM
214 dirp->d_ino = 0;
215 ret |= ALTERED;
993a756c
KM
216 } else
217 errexit("BAD RETURN STATE %d FROM DESCEND",
218 statemap[dirp->d_ino]);
ba8f3d8f
KM
219 break;
220 }
221 }
222 pathp = curpathloc;
223 *pathp = '\0';
224 if (n == 0)
225 return (ret|KEEPON);
226 dirp->d_ino = 0;
227 return (ret|KEEPON|ALTERED);
228}