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