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