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