xref: /csrg-svn/sbin/fsck/pass2.c (revision 17966)
1 #ifndef lint
2 static char version[] = "@(#)pass2.c	3.5 (Berkeley) 02/14/85";
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 
12 int	pass2check();
13 
14 pass2()
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 		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;
49 
50 	case FSTATE:
51 	case FCLEAR:
52 		pfatal("ROOT INODE NOT DIRECTORY");
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 		}
60 		if (reply("FIX") == 0)
61 			errexit("");
62 		dp = ginode(ROOTINO);
63 		dp->di_mode &= ~IFMT;
64 		dp->di_mode |= IFDIR;
65 		inodirty();
66 		statemap[ROOTINO] = DSTATE;
67 		/* fall into ... */
68 
69 	case DSTATE:
70 		descend(&rootdesc, ROOTINO);
71 		break;
72 
73 	default:
74 		errexit("BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]);
75 	}
76 }
77 
78 pass2check(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;
86 
87 	/*
88 	 * check for "."
89 	 */
90 	if (idesc->id_entryno != 0)
91 		goto chk1;
92 	if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
93 		if (dirp->d_ino != idesc->id_number) {
94 			direrr(idesc->id_number, "BAD INODE NUMBER FOR '.'");
95 			dirp->d_ino = idesc->id_number;
96 			if (reply("FIX") == 1)
97 				ret |= ALTERED;
98 		}
99 		goto chk1;
100 	}
101 	direrr(idesc->id_number, "MISSING '.'");
102 	proto.d_ino = idesc->id_number;
103 	proto.d_namlen = 1;
104 	(void)strcpy(proto.d_name, ".");
105 	entrysize = DIRSIZ(&proto);
106 	if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
107 		pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
108 			dirp->d_name);
109 	} else if (dirp->d_reclen < entrysize) {
110 		pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
111 	} else if (dirp->d_reclen < 2 * entrysize) {
112 		proto.d_reclen = dirp->d_reclen;
113 		bcopy((char *)&proto, (char *)dirp, entrysize);
114 		if (reply("FIX") == 1)
115 			ret |= ALTERED;
116 	} else {
117 		n = dirp->d_reclen - entrysize;
118 		proto.d_reclen = entrysize;
119 		bcopy((char *)&proto, (char *)dirp, entrysize);
120 		idesc->id_entryno++;
121 		lncntp[dirp->d_ino]--;
122 		dirp = (DIRECT *)((char *)(dirp) + entrysize);
123 		bzero((char *)dirp, n);
124 		dirp->d_reclen = n;
125 		if (reply("FIX") == 1)
126 			ret |= ALTERED;
127 	}
128 chk1:
129 	if (idesc->id_entryno > 1)
130 		goto chk2;
131 	proto.d_ino = idesc->id_parent;
132 	proto.d_namlen = 2;
133 	(void)strcpy(proto.d_name, "..");
134 	entrysize = DIRSIZ(&proto);
135 	if (idesc->id_entryno == 0) {
136 		n = DIRSIZ(dirp);
137 		if (dirp->d_reclen < n + entrysize)
138 			goto chk2;
139 		proto.d_reclen = dirp->d_reclen - n;
140 		dirp->d_reclen = n;
141 		idesc->id_entryno++;
142 		lncntp[dirp->d_ino]--;
143 		dirp = (DIRECT *)((char *)(dirp) + n);
144 		bzero((char *)dirp, n);
145 		dirp->d_reclen = n;
146 	}
147 	if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
148 		if (dirp->d_ino != idesc->id_parent) {
149 			direrr(idesc->id_number, "BAD INODE NUMBER FOR '..'");
150 			dirp->d_ino = idesc->id_parent;
151 			if (reply("FIX") == 1)
152 				ret |= ALTERED;
153 		}
154 		goto chk2;
155 	}
156 	direrr(idesc->id_number, "MISSING '..'");
157 	if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
158 		pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
159 			dirp->d_name);
160 	} else if (dirp->d_reclen < entrysize) {
161 		pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
162 	} else {
163 		proto.d_reclen = dirp->d_reclen;
164 		bcopy((char *)&proto, (char *)dirp, entrysize);
165 		if (reply("FIX") == 1)
166 			ret |= ALTERED;
167 	}
168 chk2:
169 	if (dirp->d_ino == 0)
170 		return (ret|KEEPON);
171 	if (dirp->d_namlen <= 2 &&
172 	    dirp->d_name[0] == '.' &&
173 	    idesc->id_entryno >= 2) {
174 		if (dirp->d_namlen == 1) {
175 			direrr(idesc->id_number, "EXTRA '.' ENTRY");
176 			dirp->d_ino = 0;
177 			if (reply("FIX") == 1)
178 				ret |= ALTERED;
179 			return (KEEPON | ret);
180 		}
181 		if (dirp->d_name[1] == '.') {
182 			direrr(idesc->id_number, "EXTRA '..' ENTRY");
183 			dirp->d_ino = 0;
184 			if (reply("FIX") == 1)
185 				ret |= ALTERED;
186 			return (KEEPON | ret);
187 		}
188 	}
189 	curpathloc = pathp;
190 	*pathp++ = '/';
191 	if (pathp + dirp->d_namlen >= endpathname) {
192 		*pathp = '\0';
193 		errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name);
194 	}
195 	bcopy(dirp->d_name, pathp, dirp->d_namlen + 1);
196 	pathp += dirp->d_namlen;
197 	idesc->id_entryno++;
198 	n = 0;
199 	if (dirp->d_ino > imax || dirp->d_ino <= 0) {
200 		direrr(dirp->d_ino, "I OUT OF RANGE");
201 		n = reply("REMOVE");
202 	} else {
203 again:
204 		switch (statemap[dirp->d_ino]) {
205 		case USTATE:
206 			direrr(dirp->d_ino, "UNALLOCATED");
207 			n = reply("REMOVE");
208 			break;
209 
210 		case DCLEAR:
211 		case FCLEAR:
212 			direrr(dirp->d_ino, "DUP/BAD");
213 			if ((n = reply("REMOVE")) == 1)
214 				break;
215 			dp = ginode(dirp->d_ino);
216 			statemap[dirp->d_ino] = DIRCT(dp) ? DSTATE : FSTATE;
217 			goto again;
218 
219 		case DFOUND:
220 			if (idesc->id_entryno > 2)
221 				pwarn("WARNING: %s IS %s\n", pathname,
222 				    "AN EXTRANEOUS HARD LINK TO A DIRECTORY");
223 			/* fall through */
224 
225 		case FSTATE:
226 			lncntp[dirp->d_ino]--;
227 			break;
228 
229 		case DSTATE:
230 			descend(idesc, dirp->d_ino);
231 			if (statemap[dirp->d_ino] == DFOUND) {
232 				lncntp[dirp->d_ino]--;
233 			} else if (statemap[dirp->d_ino] == DCLEAR) {
234 				dirp->d_ino = 0;
235 				ret |= ALTERED;
236 			} else
237 				errexit("BAD RETURN STATE %d FROM DESCEND",
238 				    statemap[dirp->d_ino]);
239 			break;
240 		}
241 	}
242 	pathp = curpathloc;
243 	*pathp = '\0';
244 	if (n == 0)
245 		return (ret|KEEPON);
246 	dirp->d_ino = 0;
247 	return (ret|KEEPON|ALTERED);
248 }
249