need more resolution on starting time for accounting
[unix-history] / usr / src / sbin / fsck / pass2.c
CommitLineData
ba8f3d8f
KM
1#ifndef lint
2static char version[] = "@(#)pass2.c 3.1 (Berkeley) %G%";
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
12int pass2check();
13
14pass2()
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
54pass2check(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 }
104chk1:
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 }
144chk2:
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 {
179again:
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 ? 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}