1/*
2 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7/*	  All Rights Reserved  	*/
8
9/*
10 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
11 * All rights reserved.
12 *
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.
26 */
27
28#pragma ident	"%Z%%M%	%I%	%E% SMI"
29
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"
44
45#define	MINDIRSIZE	(sizeof (struct dirtemplate))
46
47static int blksort(const void *, const void *);
48static int pass2check(struct inodesc *);
49
50void
51pass2(void)
52{
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;
64
65	switch (statemap[UFSROOTINO] & ~INDELAYD) {
66	case USTATE:
67		pfatal("ROOT INODE UNALLOCATED");
68		if (reply("ALLOCATE") == 0) {
69			errexit("Program terminated.");
70		}
71		if (allocdir(UFSROOTINO, UFSROOTINO, 0755, 0) != UFSROOTINO)
72			errexit("CANNOT ALLOCATE ROOT INODE\n");
73		break;
74
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;
83		}
84		if (reply("CONTINUE") == 0) {
85			errexit("Program terminated.");
86		}
87		break;
88
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;
101		}
102		if (reply("FIX") == 0) {
103			ckfini();
104			errexit("Program terminated.");
105		}
106		dp = ginode(UFSROOTINO);
107		dp->di_mode &= ~IFMT;
108		dp->di_mode |= IFDIR;
109		inodirty();
110		break;
111
112	case DSTATE:
113	case DZLINK:
114		break;
115
116	default:
117		errexit("BAD STATE 0x%x FOR ROOT INODE\n",
118			statemap[UFSROOTINO]);
119	}
120	statemap[UFSROOTINO] = DFOUND;
121
122	/*
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.
126	 */
127	inp = getinoinfo(UFSROOTINO);
128	if (inp != NULL && inp->i_dotdot != 0)
129		inp->i_dotdot = 0;
130
131	/*
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.
135	 */
136	qsort((void *)inpsort, (size_t)inplast, sizeof (*inpsort), blksort);
137	/*
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.
141	 */
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;
147
148		if (inp->i_isize == 0)
149			continue;
150
151		/* != DSTATE also covers case of == USTATE */
152		if (((statemap[inp->i_number] & STMASK) != DSTATE) ||
153		    ((statemap[inp->i_number] & INCLEAR) == INCLEAR))
154			continue;
155
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 = (u_offset_t)inp->i_isize;
162				inodirty();
163			} else {
164				iscorrupt = 1;
165			}
166		}
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					(u_offset_t)roundup(inp->i_isize,
177						    (offset_t)DIRBLKSIZ);
178				inodirty();
179				if (preen)
180					(void) printf(" (ADJUSTED)\n");
181			} else {
182				iscorrupt = 1;
183			}
184		}
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");
195			}
196		}
197		dp = &dino;
198		dp->di_size = (u_offset_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);
208
209		/*
210		 * Make sure we mark attrdirs as DFOUND, since they won't
211		 * be located during normal scan of standard directories.
212		 */
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;
225					}
226				}
227			}
228		}
229	}
230	/*
231	 * Now that the parents of all directories have been found,
232	 * make another pass to verify the value of ..
233	 */
234	for (inpp = inpsort; inpp < inpend; inpp++) {
235		inp = *inpp;
236		if (inp->i_parent == 0 || inp->i_isize == 0)
237			continue;
238		/*
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.
242		 */
243		if ((statemap[inp->i_number] & STMASK) == DCLEAR ||
244		    statemap[inp->i_number] == USTATE) {
245			continue;
246		}
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);
251		}
252		if (inp->i_dotdot == inp->i_parent ||
253		    inp->i_dotdot == (fsck_ino_t)-1) {
254			continue;
255		}
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;
263			}
264			dp = ginode(inp->i_number);
265			found = 0;
266			dirtype = (dp->di_mode & IFMT);
267
268			/*
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.
273			 */
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;
282					}
283				}
284			}
285
286			/*
287			 * We've already proven there's no "..", so this
288			 * can't create a duplicate.
289			 */
290			if (makeentry(inp->i_number, inp->i_parent, "..")) {
291
292				/*
293				 * is it an orphaned attrdir?
294				 */
295				if (dirtype == IFATTRDIR && found == 0) {
296					/*
297					 * Throw it into lost+found
298					 */
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;
305					}
306					maybe_convert_attrdir_to_dir(
307					    inp->i_number);
308				}
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) {
318							/*
319							 * iscorrupt is
320							 * already set
321							 */
322							continue;
323						}
324					}
325					TRACK_LNCNTP(inp->i_parent,
326					    lncntp[inp->i_parent]--);
327				}
328
329				continue;
330			}
331			pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
332			iscorrupt = 1;
333			inp->i_dotdot = (fsck_ino_t)-1;
334			continue;
335		}
336
337		dp2 = ginode(inp->i_parent);
338
339		if ((dp2->di_mode & IFMT) == IFATTRDIR) {
340			continue;
341		}
342		fileerror(inp->i_parent, inp->i_number,
343			"BAD INODE NUMBER FOR '..'");
344		if (reply("FIX") == 0) {
345			iscorrupt = 1;
346			continue;
347		}
348
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;
355			}
356		}
357		TRACK_LNCNTP(inp->i_dotdot, lncntp[inp->i_dotdot]++);
358
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;
365			}
366		}
367		TRACK_LNCNTP(inp->i_parent, lncntp[inp->i_parent]--);
368
369		inp->i_dotdot = inp->i_parent;
370		(void) changeino(inp->i_number, "..", inp->i_parent);
371	}
372	/*
373	 * Mark all the directories that can be found from the root.
374	 */
375	propagate();
376}
377
378/*
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.
386 *
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.
391 */
392#define	PASS2B_PROMPT	"REMOVE DIRECTORY ENTRY FROM I=%d"
393
394static int
395pass2check(struct inodesc *idesc)
396{
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;
412
413	if (idesc->id_entryno != 0)
414		goto chk1;
415	/*
416	 * check for "."
417	 */
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;
426			}
427		}
428		goto chk1;
429	}
430	/*
431	 * Build up a new one, and make sure there's room to put
432	 * it where it belongs.
433	 */
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) {
447		/*
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.
451		 *
452		 * Because we don't touch id_entryno, we end up going
453		 * through the chk2 tests as well.
454		 */
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;
462		}
463	} else {
464		/*
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.
469		 *
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.
476		 */
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++;
482		/*
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.
490		 */
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) {
495				/*
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.
500				 */
501				dirp->d_ino = 0;
502				dirp->d_reclen += reclen;
503				ret |= ALTERED;
504				return (ret);
505			}
506		}
507
508		/*
509		 * Create the new empty entry.
510		 */
511		/* LINTED pointer cast alignment (entrysize is valid) */
512		dirp = (struct direct *)((char *)(dirp) + entrysize);
513		(void) memset((void *)dirp, 0, (size_t)reclen);
514		dirp->d_reclen = reclen;
515
516		/*
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.
521		 */
522		if (reply("FIX") == 1) {
523			TRACK_LNCNTP(idesc->id_number,
524			    lncntp[idesc->id_number]--);
525			ret |= ALTERED;
526		} else {
527			iscorrupt = 1;
528		}
529	}
530
531	/*
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).
540	 */
541
542chk1:
543	if (idesc->id_entryno > 1)
544		goto chk2;
545	inp = getinoinfo(idesc->id_number);
546	if (inp == NULL) {
547		/*
548		 * This is a can't-happen, since inodes get cached before
549		 * we get called on them.
550		 */
551		errexit("pass2check got NULL from getinoinfo at chk1 I=%d\n",
552			idesc->id_number);
553	}
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) {
559		/*
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.
565		 */
566		reclen = DIRSIZ(dirp);
567		if ((int)dirp->d_reclen < reclen + entrysize) {
568			/*
569			 * Not enough room for inserting a ".." after
570			 * the "." entry.
571			 */
572			goto chk2;
573		}
574		/*
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.
582		 */
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) {
587			/*
588			 * Account for the link to ourselves.
589			 */
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) {
594					/*
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.
602					 */
603					dirp->d_ino = 0;
604					dirp->d_reclen += proto.d_reclen;
605					ret |= ALTERED;
606					return (ret);
607				}
608			}
609			TRACK_LNCNTP(dirp->d_ino, lncntp[dirp->d_ino]--);
610			/*
611			 * Make sure the new entry doesn't get interpreted
612			 * as having actual content.
613			 */
614			/* LINTED pointer cast alignment (reclen is valid) */
615			dirp = (struct direct *)((char *)(dirp) + reclen);
616			(void) memset((void *)dirp, 0, (size_t)proto.d_reclen);
617			dirp->d_reclen = proto.d_reclen;
618		} else {
619			/*
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.
626			 */
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;
634			}
635		}
636	}
637	/*
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.
641	 */
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;
646	}
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) {
660		/*
661		 * We know the parent, so fix now.
662		 */
663		proto.d_ino = inp->i_dotdot = inp->i_parent;
664		fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
665		/*
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.
669		 */
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;
677		}
678	} else if (inp->i_number == UFSROOTINO) {
679		/*
680		 * Always know parent of root inode, so fix now.
681		 */
682		proto.d_ino = inp->i_dotdot = inp->i_parent = UFSROOTINO;
683		fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
684		/*
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.
688		 */
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;
695		}
696	}
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;
705			}
706		}
707		TRACK_LNCNTP(dirp->d_ino, lncntp[dirp->d_ino]--);
708	}
709	return (ret|KEEPON);
710chk2:
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;
723			}
724			return (KEEPON | ret);
725		}
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;
733			}
734			return (KEEPON | ret);
735		}
736	}
737	/*
738	 * Because of this increment, all tests for skipping . and ..
739	 * below are ``> 2'', not ``> 1'' as would logically be expected.
740	 */
741	idesc->id_entryno++;
742	act = -1;
743	/*
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.
750	 */
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 {
756again:
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;
765
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) {
778					/*
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.
784					 */
785					errexit("pass2check found a zero-len "
786						"reference to bad I=%d\n",
787						dirp->d_ino);
788				}
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;
794				}
795			} else if (statemap[dirp->d_ino] == SCLEAR) {
796				/*
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().
804				 */
805				errmsg = "ZERO LENGTH SHADOW";
806			} else {
807				errmsg = "DUP/BAD";
808			}
809			fileerror(idesc->id_number, dirp->d_ino, errmsg);
810			if ((act = reply(PASS2B_PROMPT, idesc->id_number)) == 1)
811				break;
812			/*
813			 * Not doing anything about it, so just try
814			 * again as whatever the base type was.
815			 *
816			 * fileerror() invalidated dp.  Lint thinks this
817			 * is unnecessary, but we know better.
818			 */
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;
823
824		case DSTATE:
825		case DZLINK:
826			if (statemap[idesc->id_number] == DFOUND) {
827				statemap[dirp->d_ino] = DFOUND;
828			}
829			/* FALLTHROUGH */
830
831		case DFOUND:
832			/*
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.
837			 */
838			inp = getinoinfo(dirp->d_ino);
839			if (inp == NULL) {
840				/*
841				 * Same can't-happen argument as in the
842				 * zero-len case above.
843				 */
844				errexit("pass2check found bad reference to "
845					"hard-linked directory I=%d\n",
846					dirp->d_ino);
847			}
848			dp = ginode(idesc->id_number);
849			if (inp->i_parent != 0 && idesc->id_entryno > 2 &&
850			    ((dp->di_mode & IFMT) != IFATTRDIR)) {
851				/*
852				 * XXX For nested dirs, this can report
853				 * the same name for both paths.
854				 */
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;
868				}
869			}
870
871			if ((idesc->id_entryno > 2) &&
872					(inp->i_extattr != idesc->id_number)) {
873				inp->i_parent = idesc->id_number;
874			}
875			/* FALLTHROUGH */
876
877		case FSTATE:
878		case FZLINK:
879			/*
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.
887			 */
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);
898
899					/*
900					 * is it really an attrdir?
901					 * if so, then don't do anything.
902					 */
903
904					if ((attrdirp->di_mode & IFMT) ==
905					    IFATTRDIR)
906						dontreconnect = 1;
907					dp = ginode(dirp->d_ino);
908				}
909				/*
910				 * Rare corner case - the attrdir's ..
911				 * points to the attrdir itself.
912				 */
913				if (dirp->d_ino == idesc->id_number) {
914					dontreconnect = 1;
915					TRACK_LNCNTP(idesc->id_number,
916					    lncntp[idesc->id_number]--);
917				}
918				/*
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.
923				 */
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);
948					}
949					dp = ginode(dirp->d_ino);
950				}
951
952				/*
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.
958				 */
959				if (act > 0)
960					return (KEEPON | ALTERED);
961
962				/*
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.
970				 */
971				if ((pdirtype == IFATTRDIR) &&
972				    ((dp->di_mode & IFMT) == IFDIR))
973						breakout = 1;
974				if ((dp->di_mode & IFMT) != IFDIR)
975					breakout = 1;
976
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);
991
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();
1009							}
1010						}
1011					}
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;
1023							/*
1024							 * Make sure it's a file
1025							 * while we're at it.
1026							 */
1027							dp->di_mode &= ~IFMT;
1028							dp->di_mode |= IFREG;
1029							inodirty();
1030						}
1031					}
1032				}
1033
1034			}
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);
1040			}
1041			break;
1042
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;
1048
1049		default:
1050			errexit("BAD STATE 0x%x FOR INODE I=%d",
1051			    statemap[dirp->d_ino], dirp->d_ino);
1052		}
1053	}
1054
1055	if (act == 0) {
1056		iscorrupt = 1;
1057	}
1058
1059	if (act <= 0)
1060		return (ret|KEEPON);
1061
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;
1069			}
1070		}
1071		TRACK_LNCNTP(idesc->id_number, lncntp[idesc->id_number]++);
1072	}
1073
1074	dirp->d_ino = 0;
1075
1076	return (ret|KEEPON|ALTERED);
1077}
1078
1079#undef	PASS2B_PROMPT
1080
1081/*
1082 * Routine to sort disk blocks.
1083 */
1084static int
1085blksort(const void *arg1, const void *arg2)
1086{
1087	const struct inoinfo **inpp1 = (const struct inoinfo **)arg1;
1088	const struct inoinfo **inpp2 = (const struct inoinfo **)arg2;
1089
1090	return ((*inpp1)->i_blks[0] - (*inpp2)->i_blks[0]);
1091}
1092