91b466e49a877273654f2bf06443e902a8ed11ed
[openafs.git] / src / vfsck / pass2.c
1 /*
2  * Copyright (c) 1980, 1986 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21
22 #define VICE
23 #include <sys/time.h>
24 #include <sys/param.h>
25 #ifdef  AFS_OSF_ENV
26 #include <sys/vnode.h>
27 #include <sys/mount.h>
28 #include <ufs/inode.h>
29 #include <ufs/fs.h>
30 #define _BSD
31 #define _KERNEL
32 #include <ufs/dir.h>
33 #undef  _KERNEL
34 #undef  _BSD
35 #include <stdio.h>
36 #else /* AFS_OSF_ENV */
37 #ifdef AFS_VFSINCL_ENV
38 #include <sys/vnode.h>
39 #ifdef    AFS_SUN5_ENV
40 #include <stdio.h>
41 #include <unistd.h>
42 #include <sys/fs/ufs_inode.h>
43 #include <sys/fs/ufs_fs.h>
44 #define _KERNEL
45 #include <sys/fs/ufs_fsdir.h>
46 #undef _KERNEL
47 #include <sys/fs/ufs_mount.h>
48 #else
49 #include <ufs/inode.h>
50 #include <ufs/fs.h>
51 #include <ufs/fsdir.h>
52 #endif
53 #else /* AFS_VFSINCL_ENV */
54 #include <sys/inode.h>
55 #ifdef  AFS_HPUX_ENV
56 #include <ctype.h>
57 #define LONGFILENAMES   1
58 #include <sys/sysmacros.h>
59 #include <sys/ino.h>
60 #define DIRSIZ_MACRO
61 #ifdef HAVE_USR_OLD_USR_INCLUDE_NDIR_H
62 #include </usr/old/usr/include/ndir.h>
63 #else
64 #include <ndir.h>
65 #endif
66 #else
67 #include <sys/dir.h>
68 #endif
69 #include <sys/fs.h>
70
71 #endif /* AFS_VFSINCL_ENV */
72 #endif /* AFS_OSF_ENV */
73 #include <afs/osi_inode.h>
74
75 #ifdef  AFS_SUN5_ENV
76 #include <string.h>
77 #else
78 #include <strings.h>
79 #endif
80 #include "fsck.h"
81
82 int pass2check();
83
84 pass2()
85 {
86     struct dinode *dp;
87     struct inodesc rootdesc;
88
89     memset(&rootdesc, 0, sizeof(struct inodesc));
90     rootdesc.id_type = ADDR;
91     rootdesc.id_func = pass2check;
92     rootdesc.id_number = ROOTINO;
93     pathp = pathname;
94 #if defined(ACLS) && defined(AFS_HPUX_ENV)
95     switch (statemap[ROOTINO] & STATE) {
96 #else /* no ACLS */
97     switch (statemap[ROOTINO]) {
98 #endif /* ACLS */
99
100     case USTATE:
101         pfatal("ROOT INODE UNALLOCATED");
102         if (reply("ALLOCATE") == 0)
103             errexit("");
104         if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
105             errexit("CANNOT ALLOCATE ROOT INODE\n");
106         descend(&rootdesc, ROOTINO);
107         break;
108
109     case DCLEAR:
110         pfatal("DUPS/BAD IN ROOT INODE");
111         if (reply("REALLOCATE")) {
112             freeino(ROOTINO);
113             if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
114                 errexit("CANNOT ALLOCATE ROOT INODE\n");
115             descend(&rootdesc, ROOTINO);
116             break;
117         }
118         if (reply("CONTINUE") == 0)
119             errexit("");
120         statemap[ROOTINO] = DSTATE;
121         descend(&rootdesc, ROOTINO);
122         break;
123
124 #ifdef VICE
125     case VSTATE:
126 #endif /* VICE */
127     case FSTATE:
128     case FCLEAR:
129         pfatal("ROOT INODE NOT DIRECTORY");
130         if (reply("REALLOCATE")) {
131             freeino(ROOTINO);
132             if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
133                 errexit("CANNOT ALLOCATE ROOT INODE\n");
134             descend(&rootdesc, ROOTINO);
135             break;
136         }
137         if (reply("FIX") == 0)
138             errexit("");
139         dp = ginode(ROOTINO);
140         dp->di_mode &= ~IFMT;
141         dp->di_mode |= IFDIR;
142 #ifdef  AFS_SUN5_ENV
143         dp->di_smode = dp->di_mode;
144 #endif
145         inodirty();
146 #if defined(ACLS) && defined(AFS_HPUX_ENV)
147         /*
148          * Keep any info on associated continuation inode
149          */
150         if (statemap[ROOTINO] & HASCINODE)
151             statemap[ROOTINO] = DSTATE | HASCINODE;
152         else
153             statemap[ROOTINO] = DSTATE;
154 #else /* no ACLS */
155         statemap[ROOTINO] = DSTATE;
156 #endif /* ACLS */
157         /* fall into ... */
158
159     case DSTATE:
160         descend(&rootdesc, ROOTINO);
161         break;
162
163     default:
164         errexit("BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]);
165     }
166 }
167
168 pass2check(idesc)
169      struct inodesc *idesc;
170 {
171     struct direct *dirp = idesc->id_dirp;
172     char *curpathloc;
173     int n, entrysize, ret = 0;
174     struct dinode *dp;
175     struct direct proto;
176     char namebuf[BUFSIZ];
177 #if defined(ACLS) && defined(AFS_HPUX_ENV)
178     int holdstate;
179 #endif /* ACLS */
180
181     /*
182      * check for "."
183      */
184     if (idesc->id_entryno != 0)
185         goto chk1;
186     if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
187         if (dirp->d_ino != idesc->id_number) {
188             direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
189             dirp->d_ino = idesc->id_number;
190             if (reply("FIX") == 1)
191                 ret |= ALTERED;
192         }
193         goto chk1;
194     }
195     direrror(idesc->id_number, "MISSING '.'");
196     proto.d_ino = idesc->id_number;
197     proto.d_namlen = 1;
198     (void)strcpy(proto.d_name, ".");
199     entrysize = DIRSIZ(&proto);
200     if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
201         pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
202                dirp->d_name);
203 #if     defined(AFS_SUN_ENV)
204         iscorrupt = 1;
205 #endif
206     } else if (dirp->d_reclen < entrysize) {
207         pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
208 #if     defined(AFS_SUN_ENV)
209         iscorrupt = 1;
210 #endif
211     } else if (dirp->d_reclen < 2 * entrysize) {
212         proto.d_reclen = dirp->d_reclen;
213         memcpy((char *)dirp, (char *)&proto, entrysize);
214         if (reply("FIX") == 1)
215             ret |= ALTERED;
216     } else {
217         n = dirp->d_reclen - entrysize;
218         proto.d_reclen = entrysize;
219         memcpy((char *)dirp, (char *)&proto, entrysize);
220         idesc->id_entryno++;
221         lncntp[dirp->d_ino]--;
222         dirp = (struct direct *)((char *)(dirp) + entrysize);
223         memset(dirp, 0, n);
224         dirp->d_reclen = n;
225         if (reply("FIX") == 1)
226             ret |= ALTERED;
227     }
228   chk1:
229     if (idesc->id_entryno > 1)
230         goto chk2;
231     proto.d_ino = idesc->id_parent;
232     proto.d_namlen = 2;
233     (void)strcpy(proto.d_name, "..");
234     entrysize = DIRSIZ(&proto);
235     if (idesc->id_entryno == 0) {
236         n = DIRSIZ(dirp);
237         if (dirp->d_reclen < n + entrysize)
238             goto chk2;
239         proto.d_reclen = dirp->d_reclen - n;
240         dirp->d_reclen = n;
241         idesc->id_entryno++;
242         lncntp[dirp->d_ino]--;
243         dirp = (struct direct *)((char *)(dirp) + n);
244         memset(dirp, 0, n);
245         dirp->d_reclen = n;
246     }
247     if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
248         if (dirp->d_ino != idesc->id_parent) {
249             direrror(idesc->id_number, "BAD INODE NUMBER FOR '..'");
250             dirp->d_ino = idesc->id_parent;
251             if (reply("FIX") == 1)
252                 ret |= ALTERED;
253         }
254         goto chk2;
255     }
256     direrror(idesc->id_number, "MISSING '..'");
257     if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
258         pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
259                dirp->d_name);
260 #if     defined(AFS_SUN_ENV)
261         iscorrupt = 1;
262 #endif
263     } else if (dirp->d_reclen < entrysize) {
264         pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
265 #if     defined(AFS_SUN_ENV)
266         iscorrupt = 1;
267 #endif
268     } else {
269         proto.d_reclen = dirp->d_reclen;
270         memcpy((char *)dirp, (char *)&proto, entrysize);
271         if (reply("FIX") == 1)
272             ret |= ALTERED;
273     }
274   chk2:
275     if (dirp->d_ino == 0)
276         return (ret | KEEPON);
277     if (dirp->d_namlen <= 2 && dirp->d_name[0] == '.'
278         && idesc->id_entryno >= 2) {
279         if (dirp->d_namlen == 1) {
280             direrror(idesc->id_number, "EXTRA '.' ENTRY");
281             dirp->d_ino = 0;
282             if (reply("FIX") == 1)
283                 ret |= ALTERED;
284             return (KEEPON | ret);
285         }
286         if (dirp->d_name[1] == '.') {
287             direrror(idesc->id_number, "EXTRA '..' ENTRY");
288             dirp->d_ino = 0;
289             if (reply("FIX") == 1)
290                 ret |= ALTERED;
291             return (KEEPON | ret);
292         }
293     }
294     curpathloc = pathp;
295     *pathp++ = '/';
296     if (pathp + dirp->d_namlen >= endpathname) {
297         *pathp = '\0';
298         errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name);
299     }
300     memcpy(pathp, dirp->d_name, (int)dirp->d_namlen + 1);
301     pathp += dirp->d_namlen;
302     idesc->id_entryno++;
303     n = 0;
304     if (dirp->d_ino > maxino || dirp->d_ino <= 0) {
305         direrror(dirp->d_ino, "I OUT OF RANGE");
306         n = reply("REMOVE");
307     } else {
308       again:
309 #if defined(ACLS) && defined(AFS_HPUX_ENV)
310         switch (statemap[dirp->d_ino] & STATE) {
311 #else /* no ACLS */
312         switch (statemap[dirp->d_ino]) {
313 #endif /* ACLS */
314         case USTATE:
315             direrror(dirp->d_ino, "UNALLOCATED");
316             n = reply("REMOVE");
317             break;
318
319         case DCLEAR:
320         case FCLEAR:
321             direrror(dirp->d_ino, "DUP/BAD");
322             if ((n = reply("REMOVE")) == 1)
323                 break;
324             dp = ginode(dirp->d_ino);
325 #ifdef VICE
326 #if defined(ACLS) && defined(AFS_HPUX_ENV)
327             holdstate =
328                 (dp->di_mode & IFMT) ==
329                 IFDIR ? DSTATE : (VICEINODE ? VSTATE : FSTATE);
330             if (statemap[dirp->d_ino] & HASCINODE)
331                 statemap[dirp->d_ino] = holdstate | HASCINODE;
332             else
333                 statemap[dirp->d_ino] = holdstate;
334 #else
335             statemap[dirp->d_ino] =
336                 (dp->di_mode & IFMT) ==
337                 IFDIR ? DSTATE : (VICEINODE ? VSTATE : FSTATE);
338 #endif
339 #else /* VICE */
340 #if defined(ACLS) && defined(AFS_HPUX_ENV)
341             holdstate = (dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE;
342             if (statemap[dirp->d_ino] & HASCINODE)
343                 statemap[dirp->d_ino] = holdstate | HASCINODE;
344             else
345                 statemap[dirp->d_ino] = holdstate;
346 #else
347             statemap[dirp->d_ino] =
348                 (dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE;
349 #endif
350 #endif /* VICE */
351             lncntp[dirp->d_ino] = dp->di_nlink;
352             goto again;
353
354         case DFOUND:
355             if (idesc->id_entryno > 2) {
356                 getpathname(namebuf, dirp->d_ino, dirp->d_ino);
357                 pwarn("%s %s %s\n", pathname,
358                       "IS AN EXTRANEOUS HARD LINK TO DIRECTORY", namebuf);
359                 if (preen)
360                     printf(" (IGNORED)\n");
361                 else if ((n = reply("REMOVE")) == 1)
362                     break;
363             }
364             /* fall through */
365
366         case FSTATE:
367 #ifdef VICE
368           filecase:
369 #endif /* VICE */
370             lncntp[dirp->d_ino]--;
371             break;
372
373 #ifdef VICE
374         case VSTATE:
375             direrror(dirp->d_ino, "VICE INODE REFERENCED BY DIRECTORY");
376             if (reply("CONVERT TO REGULAR FILE") != 1)
377                 break;
378             if ((dp = ginode(dirp->d_ino)) == NULL)
379                 break;
380 #if     defined(AFS_SUN_ENV) && !defined(AFS_SUN56_ENV)
381             dp->di_gen = dp->di_ic.ic_flags = dp->di_ic.ic_size.val[0] = 0;
382 #else
383             CLEAR_DVICEMAGIC(dp);
384 #endif
385             inodirty();
386             statemap[dirp->d_ino] = FSTATE;
387             ret |= ALTERED;
388             goto filecase;
389 #endif /* VICE */
390
391
392         case DSTATE:
393             descend(idesc, dirp->d_ino);
394             if (statemap[dirp->d_ino] == DFOUND) {
395                 lncntp[dirp->d_ino]--;
396             } else if (statemap[dirp->d_ino] == DCLEAR) {
397                 dirp->d_ino = 0;
398                 ret |= ALTERED;
399             } else
400                 errexit("BAD RETURN STATE %d FROM DESCEND",
401                         statemap[dirp->d_ino]);
402             break;
403
404 #if defined(ACLS) && defined(AFS_HPUX_ENV)
405             /* hpux has more dynamic states (CSTATE, CRSTATE) */
406         case CSTATE:
407             break;
408         case CRSTATE:
409             break;
410 #endif
411         default:
412             errexit("BAD STATE %d FOR INODE I=%d", statemap[dirp->d_ino],
413                     dirp->d_ino);
414         }
415     }
416     pathp = curpathloc;
417     *pathp = '\0';
418     if (n == 0)
419         return (ret | KEEPON);
420     dirp->d_ino = 0;
421     return (ret | KEEPON | ALTERED);
422 }