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