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