1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #if !defined(lint) && defined(DOSCCS) 8: static char sccsid[] = "@(#)pass2.c 5.2 (Berkeley) 3/5/86"; 9: #endif not lint 10: 11: #include <sys/param.h> 12: #include <sys/inode.h> 13: #include <sys/fs.h> 14: #include <sys/dir.h> 15: #include <strings.h> 16: #include "fsck.h" 17: 18: int pass2check(); 19: 20: pass2() 21: { 22: register DINODE *dp; 23: struct inodesc rootdesc; 24: 25: bzero((char *)&rootdesc, sizeof(struct inodesc)); 26: rootdesc.id_type = ADDR; 27: rootdesc.id_func = pass2check; 28: rootdesc.id_number = ROOTINO; 29: pathp = pathname; 30: switch (getstate(ROOTINO)) { 31: 32: case USTATE: 33: pfatal("ROOT INODE UNALLOCATED"); 34: if (reply("ALLOCATE") == 0) 35: errexit(""); 36: if (allocdir(ROOTINO, ROOTINO) != ROOTINO) 37: errexit("CANNOT ALLOCATE ROOT INODE\n"); 38: descend(&rootdesc, ROOTINO); 39: break; 40: 41: case DCLEAR: 42: pfatal("DUPS/BAD IN ROOT INODE"); 43: if (reply("REALLOCATE")) { 44: freeino(ROOTINO); 45: if (allocdir(ROOTINO, ROOTINO) != ROOTINO) 46: errexit("CANNOT ALLOCATE ROOT INODE\n"); 47: descend(&rootdesc, ROOTINO); 48: break; 49: } 50: if (reply("CONTINUE") == 0) 51: errexit(""); 52: setstate(ROOTINO, DSTATE); 53: descend(&rootdesc, ROOTINO); 54: break; 55: 56: case FSTATE: 57: case FCLEAR: 58: pfatal("ROOT INODE NOT DIRECTORY"); 59: if (reply("REALLOCATE")) { 60: freeino(ROOTINO); 61: if (allocdir(ROOTINO, ROOTINO) != ROOTINO) 62: errexit("CANNOT ALLOCATE ROOT INODE\n"); 63: descend(&rootdesc, ROOTINO); 64: break; 65: } 66: if (reply("FIX") == 0) 67: errexit(""); 68: dp = ginode(ROOTINO); 69: dp->di_mode &= ~IFMT; 70: dp->di_mode |= IFDIR; 71: inodirty(); 72: setstate(ROOTINO, DSTATE); 73: /* fall into ... */ 74: 75: case DSTATE: 76: descend(&rootdesc, ROOTINO); 77: break; 78: 79: default: 80: errexit("BAD STATE %d FOR ROOT INODE", getstate(ROOTINO)); 81: } 82: } 83: 84: pass2check(idesc) 85: struct inodesc *idesc; 86: { 87: register DIRECT *dirp = idesc->id_dirp; 88: char *curpathloc; 89: int n, entrysize, ret = 0; 90: DINODE *dp; 91: static DIRECT proto; 92: static char namebuf[MAXPATHLEN]; 93: 94: /* 95: * check for "." 96: */ 97: if (idesc->id_entryno != 0) 98: goto chk1; 99: if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { 100: if (dirp->d_ino != idesc->id_number) { 101: direrr(idesc->id_number, "BAD INODE NUMBER FOR '.'"); 102: dirp->d_ino = idesc->id_number; 103: if (reply("FIX") == 1) 104: ret |= ALTERED; 105: } 106: goto chk1; 107: } 108: direrr(idesc->id_number, "MISSING '.'"); 109: proto.d_ino = idesc->id_number; 110: proto.d_namlen = 1; 111: (void)strcpy(proto.d_name, "."); 112: entrysize = DIRSIZ(&proto); 113: if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { 114: pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", 115: dirp->d_name); 116: } else if (dirp->d_reclen < entrysize) { 117: pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); 118: } else if (dirp->d_reclen < 2 * entrysize) { 119: proto.d_reclen = dirp->d_reclen; 120: bcopy((char *)&proto, (char *)dirp, entrysize); 121: if (reply("FIX") == 1) 122: ret |= ALTERED; 123: } else { 124: n = dirp->d_reclen - entrysize; 125: proto.d_reclen = entrysize; 126: bcopy((char *)&proto, (char *)dirp, entrysize); 127: idesc->id_entryno++; 128: declncnt(dirp->d_ino); 129: dirp = (DIRECT *)((char *)(dirp) + entrysize); 130: bzero((char *)dirp, n); 131: dirp->d_reclen = n; 132: if (reply("FIX") == 1) 133: ret |= ALTERED; 134: } 135: chk1: 136: if (idesc->id_entryno > 1) 137: goto chk2; 138: proto.d_ino = idesc->id_parent; 139: proto.d_namlen = 2; 140: (void)strcpy(proto.d_name, ".."); 141: entrysize = DIRSIZ(&proto); 142: if (idesc->id_entryno == 0) { 143: n = DIRSIZ(dirp); 144: if (dirp->d_reclen < n + entrysize) 145: goto chk2; 146: proto.d_reclen = dirp->d_reclen - n; 147: dirp->d_reclen = n; 148: idesc->id_entryno++; 149: declncnt(dirp->d_ino); 150: dirp = (DIRECT *)((char *)(dirp) + n); 151: bzero((char *)dirp, n); 152: dirp->d_reclen = n; 153: } 154: if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) { 155: if (dirp->d_ino != idesc->id_parent) { 156: direrr(idesc->id_number, "BAD INODE NUMBER FOR '..'"); 157: dirp->d_ino = idesc->id_parent; 158: if (reply("FIX") == 1) 159: ret |= ALTERED; 160: } 161: goto chk2; 162: } 163: direrr(idesc->id_number, "MISSING '..'"); 164: if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) { 165: pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", 166: dirp->d_name); 167: } else if (dirp->d_reclen < entrysize) { 168: pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); 169: } else { 170: proto.d_reclen = dirp->d_reclen; 171: bcopy((char *)&proto, (char *)dirp, entrysize); 172: if (reply("FIX") == 1) 173: ret |= ALTERED; 174: } 175: chk2: 176: if (dirp->d_ino == 0) 177: return (ret|KEEPON); 178: if (dirp->d_namlen <= 2 && 179: dirp->d_name[0] == '.' && 180: idesc->id_entryno >= 2) { 181: if (dirp->d_namlen == 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: if (dirp->d_name[1] == '.') { 189: direrr(idesc->id_number, "EXTRA '..' ENTRY"); 190: dirp->d_ino = 0; 191: if (reply("FIX") == 1) 192: ret |= ALTERED; 193: return (KEEPON | ret); 194: } 195: } 196: curpathloc = pathp; 197: *pathp++ = '/'; 198: if (pathp + dirp->d_namlen >= endpathname) { 199: *pathp = '\0'; 200: errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name); 201: } 202: bcopy(dirp->d_name, pathp, dirp->d_namlen + 1); 203: pathp += dirp->d_namlen; 204: idesc->id_entryno++; 205: n = 0; 206: if (dirp->d_ino > imax || dirp->d_ino <= 0) { 207: direrr(dirp->d_ino, "I OUT OF RANGE"); 208: n = reply("REMOVE"); 209: } else { 210: again: 211: switch (getstate(dirp->d_ino)) { 212: case USTATE: 213: direrr(dirp->d_ino, "UNALLOCATED"); 214: n = reply("REMOVE"); 215: break; 216: 217: case DCLEAR: 218: case FCLEAR: 219: direrr(dirp->d_ino, "DUP/BAD"); 220: if ((n = reply("REMOVE")) == 1) 221: break; 222: dp = ginode(dirp->d_ino); 223: setstate(dirp->d_ino, DIRCT(dp) ? DSTATE : FSTATE); 224: goto again; 225: 226: case DFOUND: 227: if (idesc->id_entryno > 2) { 228: getpathname(namebuf, dirp->d_ino, dirp->d_ino); 229: pwarn("%s %s %s\n", pathname, 230: "IS AN EXTRANEOUS HARD LINK TO DIRECTORY", 231: namebuf); 232: if (preen) 233: printf(" (IGNORED)\n"); 234: else if ((n = reply("REMOVE")) == 1) 235: break; 236: } 237: /* fall through */ 238: 239: case FSTATE: 240: declncnt(dirp->d_ino); 241: break; 242: 243: case DSTATE: 244: descend(idesc, dirp->d_ino); 245: if (getstate(dirp->d_ino) == DFOUND) { 246: declncnt(dirp->d_ino); 247: } else if (getstate(dirp->d_ino) == DCLEAR) { 248: dirp->d_ino = 0; 249: ret |= ALTERED; 250: } else 251: errexit("BAD RETURN STATE %d FROM DESCEND", 252: getstate(dirp->d_ino)); 253: break; 254: 255: default: 256: errexit("BAD STATE %d FOR INODE I=%u", 257: getstate(dirp->d_ino), dirp->d_ino); 258: } 259: } 260: pathp = curpathloc; 261: *pathp = '\0'; 262: if (n == 0) 263: return (ret|KEEPON); 264: dirp->d_ino = 0; 265: return (ret|KEEPON|ALTERED); 266: }