xref: /csrg-svn/sbin/fsck/pass2.c (revision 22050)
1*22050Sdist /*
2*22050Sdist  * Copyright (c) 1980 Regents of the University of California.
3*22050Sdist  * All rights reserved.  The Berkeley software License Agreement
4*22050Sdist  * specifies the terms and conditions for redistribution.
5*22050Sdist  */
6*22050Sdist 
716264Smckusick #ifndef lint
8*22050Sdist static char sccsid[] = "@(#)pass2.c	5.1 (Berkeley) 06/05/85";
9*22050Sdist #endif not lint
1016264Smckusick 
1116264Smckusick #include <sys/param.h>
1216264Smckusick #include <sys/inode.h>
1316264Smckusick #include <sys/fs.h>
1416264Smckusick #include <sys/dir.h>
1516264Smckusick #include <strings.h>
1616264Smckusick #include "fsck.h"
1716264Smckusick 
1816264Smckusick int	pass2check();
1916264Smckusick 
2016264Smckusick pass2()
2116264Smckusick {
2216264Smckusick 	register DINODE *dp;
2316264Smckusick 	struct inodesc rootdesc;
2416264Smckusick 
2516264Smckusick 	bzero((char *)&rootdesc, sizeof(struct inodesc));
2616264Smckusick 	rootdesc.id_type = ADDR;
2716264Smckusick 	rootdesc.id_func = pass2check;
2816264Smckusick 	rootdesc.id_number = ROOTINO;
2916264Smckusick 	pathp = pathname;
3016264Smckusick 	switch (statemap[ROOTINO]) {
3116264Smckusick 
3216264Smckusick 	case USTATE:
3317966Smckusick 		pfatal("ROOT INODE UNALLOCATED");
3417966Smckusick 		if (reply("ALLOCATE") == 0)
3517966Smckusick 			errexit("");
3617966Smckusick 		if (allocdir(ROOTINO, ROOTINO) != ROOTINO)
3717966Smckusick 			errexit("CANNOT ALLOCATE ROOT INODE\n");
3817966Smckusick 		descend(&rootdesc, ROOTINO);
3917966Smckusick 		break;
4016264Smckusick 
4117966Smckusick 	case DCLEAR:
4217966Smckusick 		pfatal("DUPS/BAD IN ROOT INODE");
4317966Smckusick 		if (reply("REALLOCATE")) {
4417966Smckusick 			freeino(ROOTINO);
4517966Smckusick 			if (allocdir(ROOTINO, ROOTINO) != ROOTINO)
4617966Smckusick 				errexit("CANNOT ALLOCATE ROOT INODE\n");
4717966Smckusick 			descend(&rootdesc, ROOTINO);
4817966Smckusick 			break;
4917966Smckusick 		}
5017966Smckusick 		if (reply("CONTINUE") == 0)
5117966Smckusick 			errexit("");
5217966Smckusick 		statemap[ROOTINO] = DSTATE;
5317966Smckusick 		descend(&rootdesc, ROOTINO);
5417966Smckusick 		break;
5517966Smckusick 
5616264Smckusick 	case FSTATE:
5717937Smckusick 	case FCLEAR:
5816264Smckusick 		pfatal("ROOT INODE NOT DIRECTORY");
5917966Smckusick 		if (reply("REALLOCATE")) {
6017966Smckusick 			freeino(ROOTINO);
6117966Smckusick 			if (allocdir(ROOTINO, ROOTINO) != ROOTINO)
6217966Smckusick 				errexit("CANNOT ALLOCATE ROOT INODE\n");
6317966Smckusick 			descend(&rootdesc, ROOTINO);
6417966Smckusick 			break;
6517966Smckusick 		}
6617943Smckusick 		if (reply("FIX") == 0)
6716264Smckusick 			errexit("");
6817943Smckusick 		dp = ginode(ROOTINO);
6916264Smckusick 		dp->di_mode &= ~IFMT;
7016264Smckusick 		dp->di_mode |= IFDIR;
7116264Smckusick 		inodirty();
7216264Smckusick 		statemap[ROOTINO] = DSTATE;
7316264Smckusick 		/* fall into ... */
7416264Smckusick 
7516264Smckusick 	case DSTATE:
7616264Smckusick 		descend(&rootdesc, ROOTINO);
7716264Smckusick 		break;
7816264Smckusick 
7917937Smckusick 	default:
8017937Smckusick 		errexit("BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]);
8116264Smckusick 	}
8216264Smckusick }
8316264Smckusick 
8416264Smckusick pass2check(idesc)
8516264Smckusick 	struct inodesc *idesc;
8616264Smckusick {
8716264Smckusick 	register DIRECT *dirp = idesc->id_dirp;
8816264Smckusick 	char *curpathloc;
8916264Smckusick 	int n, entrysize, ret = 0;
9016264Smckusick 	DINODE *dp;
9116264Smckusick 	DIRECT proto;
9217991Smckusick 	char namebuf[BUFSIZ];
9316264Smckusick 
9416264Smckusick 	/*
9516264Smckusick 	 * check for "."
9616264Smckusick 	 */
9716264Smckusick 	if (idesc->id_entryno != 0)
9816264Smckusick 		goto chk1;
9916264Smckusick 	if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
10016264Smckusick 		if (dirp->d_ino != idesc->id_number) {
10116264Smckusick 			direrr(idesc->id_number, "BAD INODE NUMBER FOR '.'");
10216264Smckusick 			dirp->d_ino = idesc->id_number;
10316264Smckusick 			if (reply("FIX") == 1)
10416264Smckusick 				ret |= ALTERED;
10516264Smckusick 		}
10616264Smckusick 		goto chk1;
10716264Smckusick 	}
10816264Smckusick 	direrr(idesc->id_number, "MISSING '.'");
10916264Smckusick 	proto.d_ino = idesc->id_number;
11016264Smckusick 	proto.d_namlen = 1;
11116264Smckusick 	(void)strcpy(proto.d_name, ".");
11216264Smckusick 	entrysize = DIRSIZ(&proto);
11316264Smckusick 	if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
11416264Smckusick 		pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
11516264Smckusick 			dirp->d_name);
11616264Smckusick 	} else if (dirp->d_reclen < entrysize) {
11716264Smckusick 		pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
11816264Smckusick 	} else if (dirp->d_reclen < 2 * entrysize) {
11916264Smckusick 		proto.d_reclen = dirp->d_reclen;
12016264Smckusick 		bcopy((char *)&proto, (char *)dirp, entrysize);
12116264Smckusick 		if (reply("FIX") == 1)
12216264Smckusick 			ret |= ALTERED;
12316264Smckusick 	} else {
12416264Smckusick 		n = dirp->d_reclen - entrysize;
12516264Smckusick 		proto.d_reclen = entrysize;
12616264Smckusick 		bcopy((char *)&proto, (char *)dirp, entrysize);
12716264Smckusick 		idesc->id_entryno++;
12816264Smckusick 		lncntp[dirp->d_ino]--;
12916264Smckusick 		dirp = (DIRECT *)((char *)(dirp) + entrysize);
13016264Smckusick 		bzero((char *)dirp, n);
13116264Smckusick 		dirp->d_reclen = n;
13216264Smckusick 		if (reply("FIX") == 1)
13316264Smckusick 			ret |= ALTERED;
13416264Smckusick 	}
13516264Smckusick chk1:
13616264Smckusick 	if (idesc->id_entryno > 1)
13716264Smckusick 		goto chk2;
13816264Smckusick 	proto.d_ino = idesc->id_parent;
13916264Smckusick 	proto.d_namlen = 2;
14016264Smckusick 	(void)strcpy(proto.d_name, "..");
14116264Smckusick 	entrysize = DIRSIZ(&proto);
14216264Smckusick 	if (idesc->id_entryno == 0) {
14316264Smckusick 		n = DIRSIZ(dirp);
14416264Smckusick 		if (dirp->d_reclen < n + entrysize)
14516264Smckusick 			goto chk2;
14616264Smckusick 		proto.d_reclen = dirp->d_reclen - n;
14716264Smckusick 		dirp->d_reclen = n;
14816264Smckusick 		idesc->id_entryno++;
14916264Smckusick 		lncntp[dirp->d_ino]--;
15016264Smckusick 		dirp = (DIRECT *)((char *)(dirp) + n);
15116264Smckusick 		bzero((char *)dirp, n);
15216264Smckusick 		dirp->d_reclen = n;
15316264Smckusick 	}
15416264Smckusick 	if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
15516264Smckusick 		if (dirp->d_ino != idesc->id_parent) {
15616264Smckusick 			direrr(idesc->id_number, "BAD INODE NUMBER FOR '..'");
15716264Smckusick 			dirp->d_ino = idesc->id_parent;
15816264Smckusick 			if (reply("FIX") == 1)
15916264Smckusick 				ret |= ALTERED;
16016264Smckusick 		}
16116264Smckusick 		goto chk2;
16216264Smckusick 	}
16316264Smckusick 	direrr(idesc->id_number, "MISSING '..'");
16416264Smckusick 	if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
16516264Smckusick 		pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
16616264Smckusick 			dirp->d_name);
16716264Smckusick 	} else if (dirp->d_reclen < entrysize) {
16816264Smckusick 		pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
16916264Smckusick 	} else {
17016264Smckusick 		proto.d_reclen = dirp->d_reclen;
17116264Smckusick 		bcopy((char *)&proto, (char *)dirp, entrysize);
17216264Smckusick 		if (reply("FIX") == 1)
17316264Smckusick 			ret |= ALTERED;
17416264Smckusick 	}
17516264Smckusick chk2:
17616264Smckusick 	if (dirp->d_ino == 0)
17716264Smckusick 		return (ret|KEEPON);
17816264Smckusick 	if (dirp->d_namlen <= 2 &&
17916264Smckusick 	    dirp->d_name[0] == '.' &&
18016264Smckusick 	    idesc->id_entryno >= 2) {
18116264Smckusick 		if (dirp->d_namlen == 1) {
18216264Smckusick 			direrr(idesc->id_number, "EXTRA '.' ENTRY");
18316264Smckusick 			dirp->d_ino = 0;
18416264Smckusick 			if (reply("FIX") == 1)
18516264Smckusick 				ret |= ALTERED;
18616264Smckusick 			return (KEEPON | ret);
18716264Smckusick 		}
18816264Smckusick 		if (dirp->d_name[1] == '.') {
18916264Smckusick 			direrr(idesc->id_number, "EXTRA '..' ENTRY");
19016264Smckusick 			dirp->d_ino = 0;
19116264Smckusick 			if (reply("FIX") == 1)
19216264Smckusick 				ret |= ALTERED;
19316264Smckusick 			return (KEEPON | ret);
19416264Smckusick 		}
19516264Smckusick 	}
19616264Smckusick 	curpathloc = pathp;
19716264Smckusick 	*pathp++ = '/';
19816264Smckusick 	if (pathp + dirp->d_namlen >= endpathname) {
19916264Smckusick 		*pathp = '\0';
20016264Smckusick 		errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name);
20116264Smckusick 	}
20216264Smckusick 	bcopy(dirp->d_name, pathp, dirp->d_namlen + 1);
20316264Smckusick 	pathp += dirp->d_namlen;
20416264Smckusick 	idesc->id_entryno++;
20516264Smckusick 	n = 0;
20616264Smckusick 	if (dirp->d_ino > imax || dirp->d_ino <= 0) {
20716264Smckusick 		direrr(dirp->d_ino, "I OUT OF RANGE");
20816264Smckusick 		n = reply("REMOVE");
20916264Smckusick 	} else {
21016264Smckusick again:
21116264Smckusick 		switch (statemap[dirp->d_ino]) {
21216264Smckusick 		case USTATE:
21316264Smckusick 			direrr(dirp->d_ino, "UNALLOCATED");
21416264Smckusick 			n = reply("REMOVE");
21516264Smckusick 			break;
21616264Smckusick 
21717937Smckusick 		case DCLEAR:
21817937Smckusick 		case FCLEAR:
21916264Smckusick 			direrr(dirp->d_ino, "DUP/BAD");
22016264Smckusick 			if ((n = reply("REMOVE")) == 1)
22116264Smckusick 				break;
22217943Smckusick 			dp = ginode(dirp->d_ino);
22317931Smckusick 			statemap[dirp->d_ino] = DIRCT(dp) ? DSTATE : FSTATE;
22416264Smckusick 			goto again;
22516264Smckusick 
22617937Smckusick 		case DFOUND:
22717991Smckusick 			if (idesc->id_entryno > 2) {
22817991Smckusick 				getpathname(namebuf, dirp->d_ino, dirp->d_ino);
22917991Smckusick 				pwarn("%s %s %s\n", pathname,
23017991Smckusick 				    "IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
23117991Smckusick 				    namebuf);
23217991Smckusick 				if (preen)
23317991Smckusick 					printf(" (IGNORED)\n");
23417991Smckusick 				else if ((n = reply("REMOVE")) == 1)
23517991Smckusick 					break;
23617991Smckusick 			}
23717937Smckusick 			/* fall through */
23817937Smckusick 
23916264Smckusick 		case FSTATE:
24016264Smckusick 			lncntp[dirp->d_ino]--;
24116264Smckusick 			break;
24216264Smckusick 
24316264Smckusick 		case DSTATE:
24416264Smckusick 			descend(idesc, dirp->d_ino);
24517937Smckusick 			if (statemap[dirp->d_ino] == DFOUND) {
24616264Smckusick 				lncntp[dirp->d_ino]--;
24717937Smckusick 			} else if (statemap[dirp->d_ino] == DCLEAR) {
24816264Smckusick 				dirp->d_ino = 0;
24916264Smckusick 				ret |= ALTERED;
25017937Smckusick 			} else
25117937Smckusick 				errexit("BAD RETURN STATE %d FROM DESCEND",
25217937Smckusick 				    statemap[dirp->d_ino]);
25316264Smckusick 			break;
25416264Smckusick 		}
25516264Smckusick 	}
25616264Smckusick 	pathp = curpathloc;
25716264Smckusick 	*pathp = '\0';
25816264Smckusick 	if (n == 0)
25916264Smckusick 		return (ret|KEEPON);
26016264Smckusick 	dirp->d_ino = 0;
26116264Smckusick 	return (ret|KEEPON|ALTERED);
26216264Smckusick }
263