876f8f8afe8efffe81476d8ea9d63541a6b33296
[openafs.git] / src / vfsck / pass1.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
22     ("$Header$");
23
24 #define VICE
25 #include <sys/param.h>
26 #include <sys/time.h>
27 #ifdef  AFS_OSF_ENV
28 #include <sys/vnode.h>
29 #include <sys/mount.h>
30 #include <ufs/inode.h>
31 #include <ufs/fs.h>
32 #define _BSD
33 #define _KERNEL
34 #include <ufs/dir.h>
35 #undef  _KERNEL
36 #undef  _BSD
37 #include <stdio.h>
38 #else /* AFS_OSF_ENV */
39 #ifdef AFS_VFSINCL_ENV
40 #include <sys/vnode.h>
41 #ifdef    AFS_SUN5_ENV
42 #include <stdio.h>
43 #include <unistd.h>
44 #include <sys/fs/ufs_inode.h>
45 #include <sys/fs/ufs_fs.h>
46 #define _KERNEL
47 #include <sys/fs/ufs_fsdir.h>
48 #undef _KERNEL
49 #include <sys/fs/ufs_mount.h>
50 #else
51 #include <ufs/inode.h>
52 #include <ufs/fs.h>
53 #endif
54 #else /* AFS_VFSINCL_ENV */
55 #include <sys/inode.h>
56 #ifdef  AFS_HPUX_ENV
57 extern int ge_danger;
58 #define DUX
59 #include <ctype.h>
60 #define LONGFILENAMES   1
61 #include <sys/sysmacros.h>
62 #include <sys/ino.h>
63 #endif
64 #include <sys/fs.h>
65 #endif /* AFS_VFSINCL_ENV */
66 #endif /* AFS_OSF_ENV */
67
68 #include <afs/osi_inode.h>
69 #include "fsck.h"
70
71 static daddr_t badblk;
72 static daddr_t dupblk;
73 int pass1check();
74 static int oldreported;
75
76 pass1()
77 {
78     register int c, i, j;
79     register struct dinode *dp;
80     struct zlncnt *zlnp;
81     int ndb, cgd;
82     struct inodesc idesc;
83     ino_t inumber;
84
85     /*
86      * Set file system reserved blocks in used block map.
87      */
88     for (c = 0; c < sblock.fs_ncg; c++) {
89         cgd = cgdmin(&sblock, c);
90         if (c == 0) {
91             i = cgbase(&sblock, c);
92             cgd += howmany(sblock.fs_cssize, sblock.fs_fsize);
93         } else
94             i = cgsblock(&sblock, c);
95         for (; i < cgd; i++)
96             setbmap(i);
97     }
98     /*
99      * Find all allocated blocks.
100      */
101     memset((char *)&idesc, 0, sizeof(struct inodesc));
102     idesc.id_type = ADDR;
103     idesc.id_func = pass1check;
104     inumber = 0;
105     n_files = n_blks = 0;
106 #ifdef VICE
107     nViceFiles = 0;
108 #endif /* VICE */
109     for (c = 0; c < sblock.fs_ncg; c++) {
110         for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
111             if (inumber < ROOTINO)
112                 continue;
113             dp = ginode(inumber);
114             if ((dp->di_mode & IFMT) == 0) {
115                 if (memcmp
116                     ((char *)dp->di_db, (char *)zino.di_db,
117                      NDADDR * sizeof(daddr_t))
118                     || memcmp((char *)dp->di_ib, (char *)zino.di_ib,
119                               NIADDR * sizeof(daddr_t)) ||
120 #if defined(ACLS) && defined(AFS_HPUX_ENV)
121                     dp->di_mode || dp->di_size || dp->di_contin) {
122                     if (dp->di_contin != 0)
123                         pwarn("UNALLOCATED INODE HAS BAD ic_contin VALUE %d",
124                               dp->di_contin);
125                     else
126 #else
127                     dp->di_mode || dp->di_size) {
128 #endif
129
130                     pfatal("PARTIALLY ALLOCATED INODE I=%u", inumber);
131                     if (reply("CLEAR") == 1) {
132 #ifdef VICE
133                         zapino(dp);
134 #else /* VICE */
135                         clearinode(dp);
136 #endif /* VICE */
137                         inodirty();
138                     }
139                 }
140                 statemap[inumber] = USTATE;
141                 continue;
142             }
143             lastino = inumber;
144 #if defined(ACLS) && defined(AFS_HPUX_ENV)
145             /* 
146              * Don't check blocks and sizes of  
147              * continuation inodes 
148              */
149             if (CONT) {
150                 statemap[inumber] = CSTATE;
151                 lncntp[inumber] = dp->di_nlink;
152                 n_cont++;
153                 continue;
154             }
155 #endif /* ACLS */
156 #if     defined(AFS_SUN56_ENV)
157             if (dp->di_size < 0 || dp->di_size > (UOFF_T) UFS_MAXOFFSET_T) {
158                 if (debug)
159                     printf("bad size %llu:", dp->di_size);
160                 goto unknown;
161             }
162 #else
163             if (dp->di_size < 0 || dp->di_size + sblock.fs_bsize - 1 < 0) {
164                 if (debug)
165                     printf("bad size %d:", dp->di_size);
166                 goto unknown;
167             }
168 #endif
169 #if defined(AFS_HPUX_ENV)
170             /* initialize all R/W activities of FIFO file */
171             /* make sure FIFO is empty (everything is 0) */
172             if ((dp->di_mode & IFMT) == IFIFO
173                 && (dp->di_frcnt != 0 || dp->di_fwcnt != 0)) {
174                 if (!qflag)
175                     pwarn("NON-ZERO READER/WRITER COUNT(S) ON PIPE I=%u",
176                           inumber);
177                 if (preen && !qflag)
178                     printf(" (CORRECTED)\n");
179                 else if (!qflag) {
180                     if (reply("CORRECT") == 0)
181                         goto no_reset;
182                 }
183                 dp->di_size = 0;
184                 dp->di_frptr = 0;
185                 dp->di_fwptr = 0;
186                 dp->di_frcnt = 0;
187                 dp->di_fwcnt = 0;
188                 dp->di_fflag = 0;
189                 dp->di_fifosize = 0;
190                 inodirty();
191                 ndb = 0;
192                 for (j = ndb; j < NDADDR; j++)
193                     dp->di_db[j] = 0;
194             }
195 #ifdef IC_FASTLINK
196             else if (FASTLNK) {
197                 /*
198                  * Fast symlink -- verify that the size is valid and that the length
199                  * of the path is correct.
200                  */
201
202                 if (dp->di_size >= MAX_FASTLINK_SIZE) {
203                     if (debug)
204                         printf("bad fastlink size %d:", dp->di_size);
205                     goto unknown;
206                 }
207                 dp->di_symlink[MAX_FASTLINK_SIZE - 1] = '\0';
208                 if (strlen(dp->di_symlink) != dp->di_size) {
209                     int len = strlen(dp->di_symlink);
210                     pwarn("BAD SYMLINK SIZE, SHOULD BE %d: size = %d", len,
211                           dp->di_size);
212                     if (preen)
213                         printf(" (CORRECTED)\n");
214                     else {
215                         printf("\n");
216                         pinode(inumber);
217                         if (reply("CORRECT") == 0)
218                             continue;
219                     }
220                     dp->di_size = len;
221                     inodirty();
222                 }
223                 goto ignore_direct_block_check;
224             }
225 #endif /* IC_FASTLINK */
226 #endif
227           no_reset:
228             if (!preen && (dp->di_mode & IFMT) == IFMT
229                 && reply("HOLD BAD BLOCK") == 1) {
230                 dp->di_size = sblock.fs_fsize;
231                 dp->di_mode = IFREG | 0600;
232                 inodirty();
233             }
234             ndb = howmany(dp->di_size, (UOFF_T) sblock.fs_bsize);
235 #ifdef  AFS_SUN5_ENV
236             if (dp->di_oeftflag == oEFT_MAGIC) {
237                 dp->di_oeftflag = 0;    /* XXX migration aid */
238                 inodirty();
239             }
240 #endif
241
242             if (ndb < 0) {
243                 if (debug)
244 #if     defined(AFS_SUN56_ENV)
245                     printf("bad size %lld ndb %d:",
246 #else
247                     printf("bad size %d ndb %d:",
248 #endif
249                            dp->di_size, ndb);
250                 goto unknown;
251             }
252             if ((dp->di_mode & IFMT) == IFBLK
253                 || (dp->di_mode & IFMT) == IFCHR)
254                 ndb++;
255 #ifdef  AFS_OSF_ENV
256             if ((dp->di_flags & IC_FASTLINK) == 0) {
257 #endif /* AFS_OSF_ENV */
258                 for (j = ndb; j < NDADDR; j++) {
259 #if defined(AFS_HPUX_ENV) && (defined(DUX) || defined(CNODE_DEV))
260                     /*  
261                      * DUX uses db[2] on cnode-specific
262                      * device files, so skip 'em 
263                      */
264                     if (j == 2 && SPECIAL)
265                         continue;
266 #endif
267                     if (dp->di_db[j] != 0) {
268                         if (debug)
269                             printf("bad direct addr: %d\n", dp->di_db[j]);
270                         goto unknown;
271                     }
272                 }
273                 for (j = 0, ndb -= NDADDR; ndb > 0; j++)
274                     ndb /= NINDIR(&sblock);
275                 for (; j < NIADDR; j++)
276                     if (dp->di_ib[j] != 0) {
277 #ifdef  AFS_HPUX_ENV
278                         if ((dp->di_mode & IFMT) != IFIFO) {
279 #endif
280                             if (debug)
281                                 printf("bad indirect addr: %d\n",
282                                        dp->di_ib[j]);
283                             goto unknown;
284 #ifdef  AFS_HPUX_ENV
285                         }
286 #endif
287
288                     }
289 #if     defined(AFS_HPUX_ENV)
290               ignore_direct_block_check:
291 #endif
292 #ifdef  AFS_OSF_ENV
293             }
294 #endif /* AFS_OSF_ENV */
295             if (ftypeok(dp) == 0)
296                 goto unknown;
297             n_files++;
298             lncntp[inumber] = dp->di_nlink;
299             if (dp->di_nlink <= 0) {
300                 zlnp = (struct zlncnt *)malloc(sizeof *zlnp);
301                 if (zlnp == NULL) {
302                     pfatal("LINK COUNT TABLE OVERFLOW");
303                     if (reply("CONTINUE") == 0)
304                         errexit("");
305                 } else {
306                     zlnp->zlncnt = inumber;
307                     zlnp->next = zlnhead;
308                     zlnhead = zlnp;
309                 }
310             }
311 #if     defined(AFS_SUN56_ENV)
312             if (OLDVICEINODE) {
313                 if (yflag) {
314                     if (!oldreported) {
315                         printf
316                             ("This vicep partition seems to contain pre Sol2.6 AFS inodes\n");
317                         printf
318                             ("You should run the AFS file conversion utility before installing Sol 2.6\n");
319                         printf("Continuing anyway.\n");
320                         oldreported++;
321                     }
322                 } else {
323                     /* This looks like a sol 2.5 AFS inode */
324                     printf
325                         ("This vicep partition seems to contain pre Sol2.6 AFS inodes\n");
326                     printf
327                         ("You should run the AFS file conversion utility before installing Sol 2.6\n");
328                     exit(100);  /* unique return code? */
329                 }
330             }
331 #endif
332             statemap[inumber] =
333 #ifdef VICE
334                 (dp->di_mode & IFMT) ==
335                 IFDIR ? DSTATE : (VICEINODE ? VSTATE : FSTATE);
336 #else /* VICE */
337                 (dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE;
338 #endif /* VICE */
339 #if defined(ACLS) && defined(AFS_HPUX_ENV)
340             /* 
341              * keep track of associated contin inodes 
342              */
343             if (dp->di_contin != 0)
344                 statemap[inumber] |= HASCINODE;
345 #endif /* ACLS */
346             badblk = dupblk = 0;
347             idesc.id_number = inumber;
348             idesc.id_entryno = 0;
349 #ifdef  AFS_SUN5_ENV
350             idesc.id_fix = DONTKNOW;
351 #endif
352             (void)ckinode(dp, &idesc);
353
354             idesc.id_entryno *= btodb(sblock.fs_fsize);
355
356             if (dp->di_blocks != idesc.id_entryno) {
357                 pwarn("INCORRECT BLOCK COUNT I=%u (%ld should be %ld)",
358                       inumber, dp->di_blocks, idesc.id_entryno);
359                 if (preen)
360                     printf(" (CORRECTED)\n");
361                 else if (reply("CORRECT") == 0)
362                     continue;
363 #ifdef  AFS_SUN5_ENV
364                 dp = ginode(inumber);
365 #endif
366                 dp->di_blocks = idesc.id_entryno;
367                 inodirty();
368             }
369 #ifdef  AFS_SUN5_ENV
370             if ((dp->di_mode & IFMT) == IFDIR)
371                 if (dp->di_blocks == 0)
372                     statemap[inumber] = DCLEAR;
373 #endif
374             continue;
375           unknown:
376             pfatal("UNKNOWN FILE TYPE I=%u", inumber);
377 #ifdef  AFS_SUN5_ENV
378             if ((dp->di_mode & IFMT) == IFDIR) {
379                 statemap[inumber] = DCLEAR;
380 #ifdef  notdef
381                 cacheino(dp, inumber);
382 #endif
383             } else
384 #endif
385                 statemap[inumber] = FCLEAR;
386             if (reply("CLEAR") == 1) {
387                 statemap[inumber] = USTATE;
388 #ifdef VICE
389                 zapino(dp);
390 #else /* VICE */
391                 clearinode(dp);
392 #endif /* VICE */
393                 inodirty();
394             }
395         }
396     }
397 }
398
399 pass1check(idesc)
400      register struct inodesc *idesc;
401 {
402     int res = KEEPON;
403     int anyout, nfrags;
404     daddr_t blkno = idesc->id_blkno;
405     register struct dups *dlp;
406     struct dups *new;
407
408     if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
409         blkerror(idesc->id_number, "BAD", blkno);
410         if (++badblk >= MAXBAD) {
411             pwarn("EXCESSIVE BAD BLKS I=%u", idesc->id_number);
412             if (preen)
413                 printf(" (SKIPPING)\n");
414             else if (reply("CONTINUE") == 0)
415                 errexit("");
416 #ifdef  AFS_HPUX_ENV
417             ge_danger = 1;
418 #endif
419             return (STOP);
420         }
421     }
422     for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
423         if (anyout && chkrange(blkno, 1)) {
424             res = SKIP;
425         } else if (!testbmap(blkno)) {
426             n_blks++;
427             setbmap(blkno);
428         } else {
429             blkerror(idesc->id_number, "DUP", blkno);
430             if (++dupblk >= MAXDUP) {
431                 pwarn("EXCESSIVE DUP BLKS I=%u", idesc->id_number);
432                 if (preen)
433                     printf(" (SKIPPING)\n");
434                 else if (reply("CONTINUE") == 0)
435                     errexit("");
436 #ifdef  AFS_HPUX_ENV
437                 ge_danger = 1;
438 #endif
439                 return (STOP);
440             }
441             new = (struct dups *)malloc(sizeof(struct dups));
442             if (new == NULL) {
443                 pfatal("DUP TABLE OVERFLOW.");
444                 if (reply("CONTINUE") == 0)
445                     errexit("");
446                 return (STOP);
447             }
448             new->dup = blkno;
449             if (muldup == 0) {
450                 duplist = muldup = new;
451                 new->next = 0;
452             } else {
453                 new->next = muldup->next;
454                 muldup->next = new;
455             }
456             for (dlp = duplist; dlp != muldup; dlp = dlp->next)
457                 if (dlp->dup == blkno)
458                     break;
459             if (dlp == muldup && dlp->dup != blkno)
460                 muldup = new;
461         }
462         /*
463          * count the number of blocks found in id_entryno
464          */
465         idesc->id_entryno++;
466     }
467     return (res);
468 }