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