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