dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / fs.d / ufs / fsck / pass2.c
blob6432c09a307d37edaf05c56b21e1e28d3e5688c7
1 /*
2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
9 /*
10 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
11 * All rights reserved.
13 * Redistribution and use in source and binary forms are permitted
14 * provided that: (1) source distributions retain this entire copyright
15 * notice and comment, and (2) distributions including binaries display
16 * the following acknowledgement: ``This product includes software
17 * developed by the University of California, Berkeley and its contributors''
18 * in the documentation or other materials provided with the distribution
19 * and in all advertising materials mentioning features or use of this
20 * software. Neither the name of the University nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
28 #pragma ident "%Z%%M% %I% %E% SMI"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/sysmacros.h>
35 #include <sys/mntent.h>
36 #include <sys/fs/ufs_fs.h>
37 #include <sys/vnode.h>
38 #include <sys/fs/ufs_inode.h>
39 #define _KERNEL
40 #include <sys/fs/ufs_fsdir.h>
41 #undef _KERNEL
42 #include <string.h>
43 #include "fsck.h"
45 #define MINDIRSIZE (sizeof (struct dirtemplate))
47 static int blksort(const void *, const void *);
48 static int pass2check(struct inodesc *);
50 void
51 pass2(void)
53 struct dinode *dp, *dp2, *dpattr;
54 struct inoinfo **inpp, *inp;
55 struct inoinfo **inpend;
56 struct inodesc curino;
57 struct inodesc ldesc;
58 struct dinode dino;
59 char pathbuf[MAXPATHLEN + 1];
60 int found;
61 int dirtype;
62 caddr_t errmsg;
63 struct shadowclientinfo *sci;
65 switch (statemap[UFSROOTINO] & ~INDELAYD) {
66 case USTATE:
67 pfatal("ROOT INODE UNALLOCATED");
68 if (reply("ALLOCATE") == 0) {
69 errexit("Program terminated.");
71 if (allocdir(UFSROOTINO, UFSROOTINO, 0755, 0) != UFSROOTINO)
72 errexit("CANNOT ALLOCATE ROOT INODE\n");
73 break;
75 case DCLEAR:
76 pfatal("DUPS/BAD IN ROOT INODE");
77 if (reply("REALLOCATE") == 1) {
78 freeino(UFSROOTINO, TI_NOPARENT);
79 if (allocdir(UFSROOTINO, UFSROOTINO,
80 0755, 0) != UFSROOTINO)
81 errexit("CANNOT ALLOCATE ROOT INODE\n");
82 break;
84 if (reply("CONTINUE") == 0) {
85 errexit("Program terminated.");
87 break;
89 case FSTATE:
90 case FCLEAR:
91 case FZLINK:
92 case SSTATE:
93 case SCLEAR:
94 pfatal("ROOT INODE NOT DIRECTORY");
95 if (reply("REALLOCATE") == 1) {
96 freeino(UFSROOTINO, TI_NOPARENT);
97 if (allocdir(UFSROOTINO, UFSROOTINO, 0755, 0) !=
98 UFSROOTINO)
99 errexit("CANNOT ALLOCATE ROOT INODE\n");
100 break;
102 if (reply("FIX") == 0) {
103 ckfini();
104 errexit("Program terminated.");
106 dp = ginode(UFSROOTINO);
107 dp->di_mode &= ~IFMT;
108 dp->di_mode |= IFDIR;
109 inodirty();
110 break;
112 case DSTATE:
113 case DZLINK:
114 break;
116 default:
117 errexit("BAD STATE 0x%x FOR ROOT INODE\n",
118 statemap[UFSROOTINO]);
120 statemap[UFSROOTINO] = DFOUND;
123 * Technically, we do know who the parent is. However,
124 * if this is set, then we'll get confused during the
125 * second-dir-entry-is-dotdot test for the root inode.
127 inp = getinoinfo(UFSROOTINO);
128 if (inp != NULL && inp->i_dotdot != 0)
129 inp->i_dotdot = 0;
132 * Sort the directory list into disk block order. There's no
133 * requirement to do this, but it may help improve our i/o times
134 * somewhat.
136 qsort((void *)inpsort, (size_t)inplast, sizeof (*inpsort), blksort);
138 * Check the integrity of each directory. In general, we treat
139 * attribute directories just like normal ones. Only the handling
140 * of .. is really different.
142 (void) memset(&dino, 0, sizeof (struct dinode));
143 dino.di_mode = IFDIR;
144 inpend = &inpsort[inplast];
145 for (inpp = inpsort; inpp < inpend; inpp++) {
146 inp = *inpp;
148 if (inp->i_isize == 0)
149 continue;
151 /* != DSTATE also covers case of == USTATE */
152 if (((statemap[inp->i_number] & STMASK) != DSTATE) ||
153 ((statemap[inp->i_number] & INCLEAR) == INCLEAR))
154 continue;
156 if (inp->i_isize < (offset_t)MINDIRSIZE) {
157 direrror(inp->i_number, "DIRECTORY TOO SHORT");
158 inp->i_isize = (offset_t)roundup(MINDIRSIZE, DIRBLKSIZ);
159 if (reply("FIX") == 1) {
160 dp = ginode(inp->i_number);
161 dp->di_size = (uoff_t)inp->i_isize;
162 inodirty();
163 } else {
164 iscorrupt = 1;
167 if ((inp->i_isize & (offset_t)(DIRBLKSIZ - 1)) != 0) {
168 getpathname(pathbuf, inp->i_number, inp->i_number);
169 pwarn("DIRECTORY %s: LENGTH %lld NOT MULTIPLE OF %d",
170 pathbuf, (longlong_t)inp->i_isize, DIRBLKSIZ);
171 inp->i_isize = roundup(inp->i_isize,
172 (offset_t)DIRBLKSIZ);
173 if (preen || reply("ADJUST") == 1) {
174 dp = ginode(inp->i_number);
175 dp->di_size =
176 (uoff_t)roundup(inp->i_isize,
177 (offset_t)DIRBLKSIZ);
178 inodirty();
179 if (preen)
180 (void) printf(" (ADJUSTED)\n");
181 } else {
182 iscorrupt = 1;
185 dp = ginode(inp->i_number);
186 if ((dp->di_mode & IFMT) == IFATTRDIR &&
187 (dp->di_cflags & IXATTR) == 0) {
188 pwarn("ATTRIBUTE DIRECTORY I=%d MISSING IXATTR FLAG",
189 inp->i_number);
190 if (preen || reply("CORRECT") == 1) {
191 dp->di_cflags |= IXATTR;
192 inodirty();
193 if (preen)
194 (void) printf(" (CORRECTED)\n");
197 dp = &dino;
198 dp->di_size = (uoff_t)inp->i_isize;
199 (void) memmove((void *)&dp->di_db[0], (void *)&inp->i_blks[0],
200 inp->i_blkssize);
201 init_inodesc(&curino);
202 curino.id_type = DATA;
203 curino.id_func = pass2check;
204 curino.id_number = inp->i_number;
205 curino.id_parent = inp->i_parent;
206 curino.id_fix = DONTKNOW;
207 (void) ckinode(dp, &curino, CKI_TRAVERSE);
210 * Make sure we mark attrdirs as DFOUND, since they won't
211 * be located during normal scan of standard directories.
213 if (curino.id_parent == 0) {
214 dpattr = ginode(inp->i_number);
215 if ((dpattr->di_mode & IFMT) == IFATTRDIR) {
216 for (sci = attrclientinfo; sci != NULL;
217 sci = sci->next) {
218 if (sci->shadow == inp->i_number) {
219 curino.id_parent =
220 sci->clients->client[0];
221 statemap[inp->i_number] =
222 DFOUND;
223 inp->i_parent =
224 curino.id_parent;
231 * Now that the parents of all directories have been found,
232 * make another pass to verify the value of ..
234 for (inpp = inpsort; inpp < inpend; inpp++) {
235 inp = *inpp;
236 if (inp->i_parent == 0 || inp->i_isize == 0)
237 continue;
239 * There are only directories in inpsort[], so only
240 * directory-related states need to be checked. There
241 * should never be any flags associated with USTATE.
243 if ((statemap[inp->i_number] & STMASK) == DCLEAR ||
244 statemap[inp->i_number] == USTATE) {
245 continue;
247 if (statemap[inp->i_parent] == DFOUND &&
248 S_IS_DUNFOUND(statemap[inp->i_number])) {
249 statemap[inp->i_number] = DFOUND |
250 (statemap[inp->i_number] & INCLEAR);
252 if (inp->i_dotdot == inp->i_parent ||
253 inp->i_dotdot == (fsck_ino_t)-1) {
254 continue;
256 if (inp->i_dotdot == 0) {
257 inp->i_dotdot = inp->i_parent;
258 fileerror(inp->i_parent, inp->i_number,
259 "MISSING '..'");
260 if (reply("FIX") == 0) {
261 iscorrupt = 1;
262 continue;
264 dp = ginode(inp->i_number);
265 found = 0;
266 dirtype = (dp->di_mode & IFMT);
269 * See if this is an attrdir that we located in pass1.
270 * i.e. it was on an i_oeftflag of some other inode.
271 * if it isn't found then we have an orphaned attrdir
272 * that needs to be tossed into lost+found.
274 if (dirtype == IFATTRDIR) {
275 for (sci = attrclientinfo;
276 sci != NULL;
277 sci = sci->next) {
278 if (sci->shadow == inp->i_number) {
279 inp->i_parent =
280 sci->clients->client[0];
281 found = 1;
287 * We've already proven there's no "..", so this
288 * can't create a duplicate.
290 if (makeentry(inp->i_number, inp->i_parent, "..")) {
293 * is it an orphaned attrdir?
295 if (dirtype == IFATTRDIR && found == 0) {
297 * Throw it into lost+found
299 if (linkup(inp->i_number, lfdir,
300 NULL) == 0) {
301 pwarn(
302 "Unable to move attrdir I=%d to lost+found\n",
303 inp->i_number);
304 iscorrupt = 1;
306 maybe_convert_attrdir_to_dir(
307 inp->i_number);
309 if (dirtype == IFDIR) {
310 LINK_RANGE(errmsg,
311 lncntp[inp->i_parent], -1);
312 if (errmsg != NULL) {
313 LINK_CLEAR(errmsg,
314 inp->i_parent, IFDIR,
315 &ldesc);
316 if (statemap[inp->i_parent] !=
317 USTATE) {
319 * iscorrupt is
320 * already set
322 continue;
325 TRACK_LNCNTP(inp->i_parent,
326 lncntp[inp->i_parent]--);
329 continue;
331 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
332 iscorrupt = 1;
333 inp->i_dotdot = (fsck_ino_t)-1;
334 continue;
337 dp2 = ginode(inp->i_parent);
339 if ((dp2->di_mode & IFMT) == IFATTRDIR) {
340 continue;
342 fileerror(inp->i_parent, inp->i_number,
343 "BAD INODE NUMBER FOR '..'");
344 if (reply("FIX") == 0) {
345 iscorrupt = 1;
346 continue;
349 LINK_RANGE(errmsg, lncntp[inp->i_dotdot], 1);
350 if (errmsg != NULL) {
351 LINK_CLEAR(errmsg, inp->i_dotdot, IFDIR, &ldesc);
352 if (statemap[inp->i_dotdot] != USTATE) {
353 /* iscorrupt is already set */
354 continue;
357 TRACK_LNCNTP(inp->i_dotdot, lncntp[inp->i_dotdot]++);
359 LINK_RANGE(errmsg, lncntp[inp->i_parent], -1);
360 if (errmsg != NULL) {
361 LINK_CLEAR(errmsg, inp->i_parent, IFDIR, &ldesc);
362 if (statemap[inp->i_parent] != USTATE) {
363 /* iscorrupt is already set */
364 continue;
367 TRACK_LNCNTP(inp->i_parent, lncntp[inp->i_parent]--);
369 inp->i_dotdot = inp->i_parent;
370 (void) changeino(inp->i_number, "..", inp->i_parent);
373 * Mark all the directories that can be found from the root.
375 propagate();
379 * Sanity-check a single directory entry. Which entry is being
380 * examined is tracked via idesc->id_entryno. There are two
381 * special ones, 0 (.) and 1 (..). Those have to exist in order
382 * in the first two locations in the directory, and have the usual
383 * properties. All other entries have to not be for either of
384 * the special two, and the inode they reference has to be
385 * reasonable.
387 * This is only called from dirscan(), which looks for the
388 * ALTERED flag after each invocation. If it finds it, the
389 * relevant buffer gets pushed out, so we don't have to worry
390 * about it here.
392 #define PASS2B_PROMPT "REMOVE DIRECTORY ENTRY FROM I=%d"
394 static int
395 pass2check(struct inodesc *idesc)
397 struct direct *dirp = idesc->id_dirp;
398 struct inodesc ldesc;
399 struct inoinfo *inp;
400 short reclen, entrysize;
401 int ret = 0;
402 int act, update_lncntp;
403 struct dinode *dp, *pdirp, *attrdirp;
404 caddr_t errmsg;
405 struct direct proto;
406 char namebuf[MAXPATHLEN + 1];
407 char pathbuf[MAXPATHLEN + 1];
408 int isattr;
409 int pdirtype;
410 int breakout = 0;
411 int dontreconnect;
413 if (idesc->id_entryno != 0)
414 goto chk1;
416 * check for "."
418 if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
419 if (dirp->d_ino != idesc->id_number) {
420 direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
421 dirp->d_ino = idesc->id_number;
422 if (reply("FIX") == 1) {
423 ret |= ALTERED;
424 } else {
425 iscorrupt = 1;
428 goto chk1;
431 * Build up a new one, and make sure there's room to put
432 * it where it belongs.
434 direrror(idesc->id_number, "MISSING '.'");
435 proto.d_ino = idesc->id_number;
436 proto.d_namlen = 1;
437 (void) strcpy(proto.d_name, ".");
438 entrysize = DIRSIZ(&proto);
439 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
440 pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
441 dirp->d_name);
442 iscorrupt = 1;
443 } else if ((int)dirp->d_reclen < entrysize) {
444 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
445 iscorrupt = 1;
446 } else if ((int)dirp->d_reclen < 2 * entrysize) {
448 * No room for another entry after us ("." is the
449 * smallest entry you can have), so just put all
450 * of the old entry's space into the new entry.
452 * Because we don't touch id_entryno, we end up going
453 * through the chk2 tests as well.
455 proto.d_reclen = dirp->d_reclen;
456 (void) memmove((void *)dirp, (void *)&proto,
457 (size_t)entrysize);
458 if (reply("FIX") == 1) {
459 ret |= ALTERED;
460 } else {
461 iscorrupt = 1;
463 } else {
465 * There's enough room for an entire additional entry
466 * after this, so create the "." entry and follow it
467 * with an empty entry that covers the rest of the
468 * space.
470 * The increment of id_entryno means we'll skip the
471 * "." case of chk1, doing the ".." tests instead.
472 * Since we know that there's not a ".." where it
473 * should be (because we just created an empty entry
474 * there), that's the best way of getting it recreated
475 * as well.
477 reclen = dirp->d_reclen - entrysize;
478 proto.d_reclen = entrysize;
479 (void) memmove((void *)dirp, (void *)&proto,
480 (size_t)entrysize);
481 idesc->id_entryno++;
483 * Make sure the link count is in range before updating
484 * it. This makes the assumption that the link count
485 * for this inode included one for ".", even though
486 * there wasn't a "." entry. Even if that's not true,
487 * it's a reasonable working hypothesis, and the link
488 * count verification done in pass4 will fix it for
489 * us anyway.
491 LINK_RANGE(errmsg, lncntp[dirp->d_ino], -1);
492 if (errmsg != NULL) {
493 LINK_CLEAR(errmsg, dirp->d_ino, IFDIR, &ldesc);
494 if (statemap[dirp->d_ino] == USTATE) {
496 * The inode got zapped, so reset the
497 * directory entry. Extend it to also
498 * cover the space we were going to make
499 * into a new entry.
501 dirp->d_ino = 0;
502 dirp->d_reclen += reclen;
503 ret |= ALTERED;
504 return (ret);
509 * Create the new empty entry.
511 /* LINTED pointer cast alignment (entrysize is valid) */
512 dirp = (struct direct *)((char *)(dirp) + entrysize);
513 (void) memset(dirp, 0, (size_t)reclen);
514 dirp->d_reclen = reclen;
517 * Did the user want us to create a new "."? This
518 * query assumes that the direrror(MISSING) was the
519 * last thing printed, so if the LINK_RANGE() check
520 * fails, it can't pass through here.
522 if (reply("FIX") == 1) {
523 TRACK_LNCNTP(idesc->id_number,
524 lncntp[idesc->id_number]--);
525 ret |= ALTERED;
526 } else {
527 iscorrupt = 1;
532 * XXX The next few lines are needed whether we're processing "."
533 * or "..". However, there are some extra steps still needed
534 * for the former, hence the big block of code for
535 * id_entryno == 0. Alternatively, there could be a label just
536 * before this comment, and everything through the end of that
537 * block moved there. In some ways, that might make the
538 * control flow more logical (factoring out to separate functions
539 * would be even better).
542 chk1:
543 if (idesc->id_entryno > 1)
544 goto chk2;
545 inp = getinoinfo(idesc->id_number);
546 if (inp == NULL) {
548 * This is a can't-happen, since inodes get cached before
549 * we get called on them.
551 errexit("pass2check got NULL from getinoinfo at chk1 I=%d\n",
552 idesc->id_number);
554 proto.d_ino = inp->i_parent;
555 proto.d_namlen = 2;
556 (void) strcpy(proto.d_name, "..");
557 entrysize = DIRSIZ(&proto);
558 if (idesc->id_entryno == 0) {
560 * We may not actually need to split things up, but if
561 * there's room to do so, we should, as that implies
562 * that the "." entry is larger than it is supposed
563 * to be, and therefore there's something wrong, albeit
564 * possibly harmlessly so.
566 reclen = DIRSIZ(dirp);
567 if ((int)dirp->d_reclen < reclen + entrysize) {
569 * Not enough room for inserting a ".." after
570 * the "." entry.
572 goto chk2;
575 * There's enough room for an entire additional entry
576 * after "."'s, so split it up. There's no reason "."
577 * should be bigger than the minimum, so shrink it to
578 * fit, too. Since by the time we're done with this
579 * part, dirp will be pointing at where ".." should be,
580 * update id_entryno to show that that's the entry
581 * we're on.
583 proto.d_reclen = dirp->d_reclen - reclen;
584 dirp->d_reclen = reclen;
585 idesc->id_entryno++;
586 if (dirp->d_ino > 0 && dirp->d_ino <= maxino) {
588 * Account for the link to ourselves.
590 LINK_RANGE(errmsg, lncntp[dirp->d_ino], -1);
591 if (errmsg != NULL) {
592 LINK_CLEAR(errmsg, dirp->d_ino, IFDIR, &ldesc);
593 if (statemap[dirp->d_ino] == USTATE) {
595 * We were going to split the entry
596 * up, but the link count overflowed.
597 * Since we got rid of the inode,
598 * we need to also zap the directory
599 * entry, and restoring the original
600 * state of things is the least-bad
601 * result.
603 dirp->d_ino = 0;
604 dirp->d_reclen += proto.d_reclen;
605 ret |= ALTERED;
606 return (ret);
609 TRACK_LNCNTP(dirp->d_ino, lncntp[dirp->d_ino]--);
611 * Make sure the new entry doesn't get interpreted
612 * as having actual content.
614 /* LINTED pointer cast alignment (reclen is valid) */
615 dirp = (struct direct *)((char *)(dirp) + reclen);
616 (void) memset(dirp, 0, (size_t)proto.d_reclen);
617 dirp->d_reclen = proto.d_reclen;
618 } else {
620 * Everything was fine, up until we realized that
621 * the indicated inode was impossible. By clearing
622 * d_ino here, we'll trigger the recreation of it
623 * down below, using i_parent. Unlike the other
624 * half of this if(), we're everything so it shows
625 * that we're still on the "." entry.
627 fileerror(idesc->id_number, dirp->d_ino,
628 "I OUT OF RANGE");
629 dirp->d_ino = 0;
630 if (reply("FIX") == 1) {
631 ret |= ALTERED;
632 } else {
633 iscorrupt = 1;
638 * Record this ".." inode, but only if we haven't seen one before.
639 * If this isn't the first, it'll get cleared below, and so we
640 * want to remember the entry that'll still be around later.
642 if (dirp->d_ino != 0 && inp->i_dotdot == 0 &&
643 strcmp(dirp->d_name, "..") == 0) {
644 inp->i_dotdot = dirp->d_ino;
645 goto chk2;
647 if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
648 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
649 pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
650 dirp->d_name);
651 iscorrupt = 1;
652 inp->i_dotdot = (fsck_ino_t)-1;
653 } else if ((int)dirp->d_reclen < entrysize) {
654 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
655 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
656 /* XXX Same consideration as immediately above. */
657 iscorrupt = 1;
658 inp->i_dotdot = (fsck_ino_t)-1;
659 } else if (inp->i_parent != 0) {
661 * We know the parent, so fix now.
663 proto.d_ino = inp->i_dotdot = inp->i_parent;
664 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
666 * Lint won't be quiet about d_reclen being set but not
667 * used. It apparently doesn't understand the implications
668 * of calling memmove(), and won't believe us that it's ok.
670 proto.d_reclen = dirp->d_reclen;
671 (void) memmove((void *)dirp, (void *)&proto,
672 (size_t)entrysize);
673 if (reply("FIX") == 1) {
674 ret |= ALTERED;
675 } else {
676 iscorrupt = 1;
678 } else if (inp->i_number == UFSROOTINO) {
680 * Always know parent of root inode, so fix now.
682 proto.d_ino = inp->i_dotdot = inp->i_parent = UFSROOTINO;
683 fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
685 * Lint won't be quiet about d_reclen being set but not
686 * used. It apparently doesn't understand the implications
687 * of calling memmove(), and won't believe us that it's ok.
689 proto.d_reclen = dirp->d_reclen;
690 (void) memmove((void *)dirp, (void *)&proto, (size_t)entrysize);
691 if (reply("FIX") == 1) {
692 ret |= ALTERED;
693 } else {
694 iscorrupt = 1;
697 idesc->id_entryno++;
698 if (dirp->d_ino != 0) {
699 LINK_RANGE(errmsg, lncntp[dirp->d_ino], -1);
700 if (errmsg != NULL) {
701 LINK_CLEAR(errmsg, dirp->d_ino, IFDIR, &ldesc);
702 if (statemap[dirp->d_ino] == USTATE) {
703 dirp->d_ino = 0;
704 ret |= ALTERED;
707 TRACK_LNCNTP(dirp->d_ino, lncntp[dirp->d_ino]--);
709 return (ret|KEEPON);
710 chk2:
711 if (dirp->d_ino == 0)
712 return (ret|KEEPON);
713 if (dirp->d_namlen <= 2 &&
714 dirp->d_name[0] == '.' &&
715 idesc->id_entryno >= 2) {
716 if (dirp->d_namlen == 1) {
717 direrror(idesc->id_number, "EXTRA '.' ENTRY");
718 dirp->d_ino = 0;
719 if (reply("FIX") == 1) {
720 ret |= ALTERED;
721 } else {
722 iscorrupt = 1;
724 return (KEEPON | ret);
726 if (dirp->d_name[1] == '.') {
727 direrror(idesc->id_number, "EXTRA '..' ENTRY");
728 dirp->d_ino = 0;
729 if (reply("FIX") == 1) {
730 ret |= ALTERED;
731 } else {
732 iscorrupt = 1;
734 return (KEEPON | ret);
738 * Because of this increment, all tests for skipping . and ..
739 * below are ``> 2'', not ``> 1'' as would logically be expected.
741 idesc->id_entryno++;
742 act = -1;
744 * The obvious check would be for d_ino < UFSROOTINO. However,
745 * 1 is a valid inode number. Although it isn't currently used,
746 * as it was once the bad block list, there's nothing to prevent
747 * it from acquiring a new purpose in the future. So, don't
748 * arbitrarily disallow it. We don't test for <= zero, because
749 * d_ino is unsigned.
751 update_lncntp = 0;
752 if (dirp->d_ino > maxino || dirp->d_ino == 0) {
753 fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
754 act = (reply(PASS2B_PROMPT, idesc->id_number) == 1);
755 } else {
756 again:
757 update_lncntp = 0;
758 switch (statemap[dirp->d_ino] & ~(INDELAYD)) {
759 case USTATE:
760 if (idesc->id_entryno <= 2)
761 break;
762 fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED");
763 act = (reply(PASS2B_PROMPT, idesc->id_number) == 1);
764 break;
766 case DCLEAR:
767 case FCLEAR:
768 case SCLEAR:
769 if (idesc->id_entryno <= 2)
770 break;
771 dp = ginode(dirp->d_ino);
772 if (statemap[dirp->d_ino] == DCLEAR) {
773 errmsg = ((dp->di_mode & IFMT) == IFATTRDIR) ?
774 "REFERENCE TO ZERO LENGTH ATTRIBUTE DIRECTORY" :
775 "REFERENCE TO ZERO LENGTH DIRECTORY";
776 inp = getinoinfo(dirp->d_ino);
777 if (inp == NULL) {
779 * The inode doesn't exist, as all
780 * should be cached by now. This
781 * gets caught by the range check
782 * above, and so it is a can't-happen
783 * at this point.
785 errexit("pass2check found a zero-len "
786 "reference to bad I=%d\n",
787 dirp->d_ino);
789 if (inp->i_parent != 0) {
790 (void) printf(
791 "Multiple links to I=%d, link counts wrong, rerun fsck\n",
792 inp->i_number);
793 iscorrupt = 1;
795 } else if (statemap[dirp->d_ino] == SCLEAR) {
797 * In theory, this is a can't-happen,
798 * because shadows don't appear in directory
799 * entries. However, an inode might've
800 * been reused without a stale directory
801 * entry having been cleared, so check
802 * for it just in case. We'll check for
803 * the no-dir-entry shadows in pass3b().
805 errmsg = "ZERO LENGTH SHADOW";
806 } else {
807 errmsg = "DUP/BAD";
809 fileerror(idesc->id_number, dirp->d_ino, errmsg);
810 if ((act = reply(PASS2B_PROMPT, idesc->id_number)) == 1)
811 break;
813 * Not doing anything about it, so just try
814 * again as whatever the base type was.
816 * fileerror() invalidated dp. Lint thinks this
817 * is unnecessary, but we know better.
819 dp = ginode(dirp->d_ino);
820 statemap[dirp->d_ino] &= STMASK;
821 TRACK_LNCNTP(dirp->d_ino, lncntp[dirp->d_ino] = 0);
822 goto again;
824 case DSTATE:
825 case DZLINK:
826 if (statemap[idesc->id_number] == DFOUND) {
827 statemap[dirp->d_ino] = DFOUND;
829 /* FALLTHROUGH */
831 case DFOUND:
833 * This is encouraging the best-practice of not
834 * hard-linking directories. It's legal (see POSIX),
835 * but not a good idea. So, don't consider it an
836 * instance of corruption, but offer to nuke it.
838 inp = getinoinfo(dirp->d_ino);
839 if (inp == NULL) {
841 * Same can't-happen argument as in the
842 * zero-len case above.
844 errexit("pass2check found bad reference to "
845 "hard-linked directory I=%d\n",
846 dirp->d_ino);
848 dp = ginode(idesc->id_number);
849 if (inp->i_parent != 0 && idesc->id_entryno > 2 &&
850 ((dp->di_mode & IFMT) != IFATTRDIR)) {
852 * XXX For nested dirs, this can report
853 * the same name for both paths.
855 getpathname(pathbuf, idesc->id_number,
856 dirp->d_ino);
857 getpathname(namebuf, dirp->d_ino, dirp->d_ino);
858 pwarn(
859 "%s IS AN EXTRANEOUS HARD LINK TO DIRECTORY %s\n",
860 pathbuf, namebuf);
861 if (preen)
862 (void) printf(" (IGNORED)\n");
863 else if ((act = reply(PASS2B_PROMPT,
864 idesc->id_number)) == 1) {
865 update_lncntp = 1;
866 broke_dir_link = 1;
867 break;
871 if ((idesc->id_entryno > 2) &&
872 (inp->i_extattr != idesc->id_number)) {
873 inp->i_parent = idesc->id_number;
875 /* FALLTHROUGH */
877 case FSTATE:
878 case FZLINK:
880 * There's nothing to do for normal file-like
881 * things. Extended attributes come through
882 * here as well, though, and for them, .. may point
883 * to a file. In this situation we don't want
884 * to decrement link count as it was already
885 * decremented when the entry was seen in the
886 * directory it actually lives in.
888 pdirp = ginode(idesc->id_number);
889 pdirtype = (pdirp->di_mode & IFMT);
890 dp = ginode(dirp->d_ino);
891 isattr = (dp->di_cflags & IXATTR);
892 act = -1;
893 if (pdirtype == IFATTRDIR &&
894 (strcmp(dirp->d_name, "..") == 0)) {
895 dontreconnect = 0;
896 if (dp->di_oeftflag != 0) {
897 attrdirp = ginode(dp->di_oeftflag);
900 * is it really an attrdir?
901 * if so, then don't do anything.
904 if ((attrdirp->di_mode & IFMT) ==
905 IFATTRDIR)
906 dontreconnect = 1;
907 dp = ginode(dirp->d_ino);
910 * Rare corner case - the attrdir's ..
911 * points to the attrdir itself.
913 if (dirp->d_ino == idesc->id_number) {
914 dontreconnect = 1;
915 TRACK_LNCNTP(idesc->id_number,
916 lncntp[idesc->id_number]--);
919 * Lets see if we have an orphaned attrdir
920 * that thinks it belongs to this file.
921 * Only re-connect it if the current
922 * attrdir is 0 or not an attrdir.
924 if ((dp->di_oeftflag != idesc->id_number) &&
925 (dontreconnect == 0)) {
926 fileerror(idesc->id_number,
927 dirp->d_ino,
928 "Attribute directory I=%d not "
929 "attached to file I=%d\n",
930 idesc->id_number, dirp->d_ino);
931 if ((act = reply("FIX")) == 1) {
932 dp = ginode(dirp->d_ino);
933 if (debug)
934 (void) printf(
935 "debug: changing i=%d's oeft from %d ",
936 dirp->d_ino,
937 dp->di_oeftflag);
938 dp->di_oeftflag =
939 idesc->id_number;
940 if (debug)
941 (void) printf("to %d\n",
942 dp->di_oeftflag);
943 inodirty();
944 registershadowclient(
945 idesc->id_number,
946 dirp->d_ino,
947 &attrclientinfo);
949 dp = ginode(dirp->d_ino);
953 * This can only be true if we've modified
954 * an inode/xattr connection, and we
955 * don't keep track of those in the link
956 * counts. So, skipping the checks just
957 * after this is not a problem.
959 if (act > 0)
960 return (KEEPON | ALTERED);
963 * Don't screw up link counts for directories.
964 * If we aren't careful we can perform
965 * an extra decrement, since the .. of
966 * an attrdir could be either a file or a
967 * directory. If it's a file then its link
968 * should be correct after it is seen when the
969 * directory it lives in scanned.
971 if ((pdirtype == IFATTRDIR) &&
972 ((dp->di_mode & IFMT) == IFDIR))
973 breakout = 1;
974 if ((dp->di_mode & IFMT) != IFDIR)
975 breakout = 1;
977 } else if ((pdirtype != IFATTRDIR) ||
978 (strcmp(dirp->d_name, ".") != 0)) {
979 if ((pdirtype == IFDIR) && isattr) {
980 fileerror(idesc->id_number,
981 dirp->d_ino,
982 "File should NOT be marked as "
983 "extended attribute\n");
984 if ((act = reply("FIX")) == 1) {
985 dp = ginode(dirp->d_ino);
986 if (debug)
987 (void) printf(
988 "changing i=%d's cflags from 0x%x to ",
989 dirp->d_ino,
990 dp->di_cflags);
992 dp->di_cflags &= ~IXATTR;
993 if (debug)
994 (void) printf("0x%x\n",
995 dp->di_cflags);
996 inodirty();
997 if ((dp->di_mode & IFMT) ==
998 IFATTRDIR) {
999 dp->di_mode &=
1000 ~IFATTRDIR;
1001 dp->di_mode |= IFDIR;
1002 inodirty();
1003 pdirp = ginode(
1004 idesc->id_number);
1005 if (pdirp->di_oeftflag
1006 != 0) {
1007 pdirp->di_oeftflag = 0;
1008 inodirty();
1012 } else {
1013 if (pdirtype == IFATTRDIR &&
1014 (isattr == 0)) {
1015 fileerror(idesc->id_number,
1016 dirp->d_ino,
1017 "File should BE marked as "
1018 "extended attribute\n");
1019 if ((act = reply("FIX")) == 1) {
1020 dp = ginode(
1021 dirp->d_ino);
1022 dp->di_cflags |= IXATTR;
1024 * Make sure it's a file
1025 * while we're at it.
1027 dp->di_mode &= ~IFMT;
1028 dp->di_mode |= IFREG;
1029 inodirty();
1035 if (breakout == 0 || dontreconnect == 0) {
1036 TRACK_LNCNTP(dirp->d_ino,
1037 lncntp[dirp->d_ino]--);
1038 if (act > 0)
1039 return (KEEPON | ALTERED);
1041 break;
1043 case SSTATE:
1044 errmsg = "ACL IN DIRECTORY";
1045 fileerror(idesc->id_number, dirp->d_ino, errmsg);
1046 act = (reply(PASS2B_PROMPT, idesc->id_number) == 1);
1047 break;
1049 default:
1050 errexit("BAD STATE 0x%x FOR INODE I=%d",
1051 statemap[dirp->d_ino], dirp->d_ino);
1055 if (act == 0) {
1056 iscorrupt = 1;
1059 if (act <= 0)
1060 return (ret|KEEPON);
1062 if (update_lncntp) {
1063 LINK_RANGE(errmsg, lncntp[idesc->id_number], 1);
1064 if (errmsg != NULL) {
1065 LINK_CLEAR(errmsg, idesc->id_number, IFDIR, &ldesc);
1066 if (statemap[idesc->id_number] == USTATE) {
1067 idesc->id_number = 0;
1068 ret |= ALTERED;
1071 TRACK_LNCNTP(idesc->id_number, lncntp[idesc->id_number]++);
1074 dirp->d_ino = 0;
1076 return (ret|KEEPON|ALTERED);
1079 #undef PASS2B_PROMPT
1082 * Routine to sort disk blocks.
1084 static int
1085 blksort(const void *arg1, const void *arg2)
1087 const struct inoinfo **inpp1 = (const struct inoinfo **)arg1;
1088 const struct inoinfo **inpp2 = (const struct inoinfo **)arg2;
1090 return ((*inpp1)->i_blks[0] - (*inpp2)->i_blks[0]);