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