Import Upstream version 1.8.5
[hcoop/debian/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 }