new location for ufs sources
[unix-history] / usr / src / sbin / fsck / pass2.c
CommitLineData
76797561
DF
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
ba8f3d8f 7#ifndef lint
c689da7b 8static char sccsid[] = "@(#)pass2.c 5.4 (Berkeley) %G%";
76797561 9#endif not lint
ba8f3d8f
KM
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
18int pass2check();
19
20pass2()
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 (statemap[ROOTINO]) {
31
32 case USTATE:
7e1e49f2
KM
33 pfatal("ROOT INODE UNALLOCATED");
34 if (reply("ALLOCATE") == 0)
35 errexit("");
c689da7b 36 if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
7e1e49f2
KM
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);
c689da7b 45 if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
7e1e49f2
KM
46 errexit("CANNOT ALLOCATE ROOT INODE\n");
47 descend(&rootdesc, ROOTINO);
48 break;
49 }
50 if (reply("CONTINUE") == 0)
51 errexit("");
52 statemap[ROOTINO] = DSTATE;
53 descend(&rootdesc, ROOTINO);
54 break;
ba8f3d8f
KM
55
56 case FSTATE:
993a756c 57 case FCLEAR:
ba8f3d8f 58 pfatal("ROOT INODE NOT DIRECTORY");
7e1e49f2
KM
59 if (reply("REALLOCATE")) {
60 freeino(ROOTINO);
c689da7b 61 if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
7e1e49f2
KM
62 errexit("CANNOT ALLOCATE ROOT INODE\n");
63 descend(&rootdesc, ROOTINO);
64 break;
65 }
39c18287 66 if (reply("FIX") == 0)
ba8f3d8f 67 errexit("");
39c18287 68 dp = ginode(ROOTINO);
ba8f3d8f
KM
69 dp->di_mode &= ~IFMT;
70 dp->di_mode |= IFDIR;
71 inodirty();
ba8f3d8f
KM
72 statemap[ROOTINO] = DSTATE;
73 /* fall into ... */
74
75 case DSTATE:
76 descend(&rootdesc, ROOTINO);
77 break;
78
993a756c
KM
79 default:
80 errexit("BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]);
ba8f3d8f
KM
81 }
82}
83
84pass2check(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 DIRECT proto;
3ad2f081 92 char namebuf[BUFSIZ];
ba8f3d8f
KM
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 lncntp[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 }
135chk1:
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 lncntp[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 }
175chk2:
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 {
210again:
211 switch (statemap[dirp->d_ino]) {
212 case USTATE:
213 direrr(dirp->d_ino, "UNALLOCATED");
214 n = reply("REMOVE");
215 break;
216
993a756c
KM
217 case DCLEAR:
218 case FCLEAR:
ba8f3d8f
KM
219 direrr(dirp->d_ino, "DUP/BAD");
220 if ((n = reply("REMOVE")) == 1)
221 break;
39c18287 222 dp = ginode(dirp->d_ino);
7718c0e6 223 statemap[dirp->d_ino] = DIRCT(dp) ? DSTATE : FSTATE;
77d16a71 224 lncntp[dirp->d_ino] = dp->di_nlink;
ba8f3d8f
KM
225 goto again;
226
993a756c 227 case DFOUND:
3ad2f081
KM
228 if (idesc->id_entryno > 2) {
229 getpathname(namebuf, dirp->d_ino, dirp->d_ino);
230 pwarn("%s %s %s\n", pathname,
231 "IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
232 namebuf);
233 if (preen)
234 printf(" (IGNORED)\n");
235 else if ((n = reply("REMOVE")) == 1)
236 break;
237 }
993a756c
KM
238 /* fall through */
239
ba8f3d8f
KM
240 case FSTATE:
241 lncntp[dirp->d_ino]--;
242 break;
243
244 case DSTATE:
245 descend(idesc, dirp->d_ino);
993a756c 246 if (statemap[dirp->d_ino] == DFOUND) {
ba8f3d8f 247 lncntp[dirp->d_ino]--;
993a756c 248 } else if (statemap[dirp->d_ino] == DCLEAR) {
ba8f3d8f
KM
249 dirp->d_ino = 0;
250 ret |= ALTERED;
993a756c
KM
251 } else
252 errexit("BAD RETURN STATE %d FROM DESCEND",
253 statemap[dirp->d_ino]);
ba8f3d8f 254 break;
ea4448dc
KM
255
256 default:
257 errexit("BAD STATE %d FOR INODE I=%d",
258 statemap[dirp->d_ino], dirp->d_ino);
ba8f3d8f
KM
259 }
260 }
261 pathp = curpathloc;
262 *pathp = '\0';
263 if (n == 0)
264 return (ret|KEEPON);
265 dirp->d_ino = 0;
266 return (ret|KEEPON|ALTERED);
267}