1 /* $NetBSD: pass2.c,v 1.16 2006/09/01 19:52:48 perseant Exp $ */
4 * Copyright (c) 1980, 1986, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/types.h>
33 #include <sys/param.h>
35 #include <sys/mount.h>
38 #include <ufs/ufs/inode.h>
39 #include <ufs/ufs/dir.h>
40 #include <ufs/lfs/lfs.h>
55 #define MINDIRSIZE (sizeof (struct dirtemplate))
57 static int pass2check(struct inodesc
*);
58 static int blksort(const void *, const void *);
63 struct ufs1_dinode
*dp
;
65 struct inoinfo
**inpp
, *inp
;
66 struct inoinfo
**inpend
;
67 struct inodesc curino
;
68 struct ufs1_dinode dino
;
69 char pathbuf
[MAXPATHLEN
+ 1];
71 switch (statemap
[ROOTINO
]) {
74 pfatal("ROOT INODE UNALLOCATED");
75 if (reply("ALLOCATE") == 0)
77 if (allocdir(ROOTINO
, ROOTINO
, 0755) != ROOTINO
)
78 err(EEXIT
, "CANNOT ALLOCATE ROOT INODE\n");
82 pfatal("DUPS/BAD IN ROOT INODE");
83 if (reply("REALLOCATE")) {
85 if (allocdir(ROOTINO
, ROOTINO
, 0755) != ROOTINO
)
86 err(EEXIT
, "CANNOT ALLOCATE ROOT INODE\n");
89 if (reply("CONTINUE") == 0)
95 pfatal("ROOT INODE NOT DIRECTORY");
96 if (reply("REALLOCATE")) {
98 if (allocdir(ROOTINO
, ROOTINO
, 0755) != ROOTINO
)
99 err(EEXIT
, "CANNOT ALLOCATE ROOT INODE\n");
102 if (reply("FIX") == 0)
103 errx(EEXIT
, "%s", "");
104 vp
= vget(fs
, ROOTINO
);
106 dp
->di_mode
&= ~IFMT
;
107 dp
->di_mode
|= IFDIR
;
115 errx(EEXIT
, "BAD STATE %d FOR ROOT INODE\n", statemap
[ROOTINO
]);
117 statemap
[WINO
] = FSTATE
;
118 typemap
[WINO
] = DT_WHT
;
120 * Sort the directory list into disk block order.
122 qsort((char *) inpsort
, (size_t) inplast
, sizeof *inpsort
, blksort
);
124 * Check the integrity of each directory.
126 memset(&curino
, 0, sizeof(struct inodesc
));
127 curino
.id_type
= DATA
;
128 curino
.id_func
= pass2check
;
129 inpend
= &inpsort
[inplast
];
130 for (inpp
= inpsort
; inpp
< inpend
; inpp
++) {
132 if (inp
->i_isize
== 0)
134 if (inp
->i_isize
< MINDIRSIZE
) {
135 direrror(inp
->i_number
, "DIRECTORY TOO SHORT");
136 inp
->i_isize
= roundup(MINDIRSIZE
, DIRBLKSIZ
);
137 if (reply("FIX") == 1) {
138 vp
= vget(fs
, inp
->i_number
);
140 dp
->di_size
= inp
->i_isize
;
143 } else if ((inp
->i_isize
& (DIRBLKSIZ
- 1)) != 0) {
144 getpathname(pathbuf
, sizeof(pathbuf
), inp
->i_number
,
146 pwarn("DIRECTORY %s: LENGTH %lu NOT MULTIPLE OF %d",
147 pathbuf
, (unsigned long) inp
->i_isize
, DIRBLKSIZ
);
149 printf(" (ADJUSTED)\n");
150 inp
->i_isize
= roundup(inp
->i_isize
, DIRBLKSIZ
);
151 if (preen
|| reply("ADJUST") == 1) {
152 vp
= vget(fs
, inp
->i_number
);
154 dp
->di_size
= inp
->i_isize
;
158 memset(&dino
, 0, sizeof(struct ufs1_dinode
));
159 dino
.di_mode
= IFDIR
;
160 dino
.di_size
= inp
->i_isize
;
161 memcpy(&dino
.di_db
[0], &inp
->i_blks
[0], (size_t) inp
->i_numblks
);
162 curino
.id_number
= inp
->i_number
;
163 curino
.id_parent
= inp
->i_parent
;
164 (void) ckinode(&dino
, &curino
);
167 * Now that the parents of all directories have been found,
168 * make another pass to verify the value of `..'
170 for (inpp
= inpsort
; inpp
< inpend
; inpp
++) {
172 if (inp
->i_parent
== 0 || inp
->i_isize
== 0)
174 if (inp
->i_dotdot
== inp
->i_parent
||
175 inp
->i_dotdot
== (ino_t
) - 1)
177 if (inp
->i_dotdot
== 0) {
178 inp
->i_dotdot
= inp
->i_parent
;
179 fileerror(inp
->i_parent
, inp
->i_number
, "MISSING '..'");
180 if (reply("FIX") == 0)
182 (void) makeentry(inp
->i_number
, inp
->i_parent
, "..");
183 lncntp
[inp
->i_parent
]--;
186 fileerror(inp
->i_parent
, inp
->i_number
,
187 "BAD INODE NUMBER FOR '..'");
188 if (reply("FIX") == 0)
190 lncntp
[inp
->i_dotdot
]++;
191 lncntp
[inp
->i_parent
]--;
192 inp
->i_dotdot
= inp
->i_parent
;
193 (void) changeino(inp
->i_number
, "..", inp
->i_parent
);
196 * Mark all the directories that can be found from the root.
202 pass2check(struct inodesc
* idesc
)
204 struct direct
*dirp
= idesc
->id_dirp
;
206 int n
, entrysize
, ret
= 0;
207 struct ufs1_dinode
*dp
;
210 char namebuf
[MAXPATHLEN
+ 1];
211 char pathbuf
[MAXPATHLEN
+ 1];
216 if (idesc
->id_entryno
!= 0)
218 if (dirp
->d_ino
!= 0 && strcmp(dirp
->d_name
, ".") == 0) {
219 if (dirp
->d_ino
!= idesc
->id_number
) {
220 direrror(idesc
->id_number
, "BAD INODE NUMBER FOR '.'");
221 dirp
->d_ino
= idesc
->id_number
;
222 if (reply("FIX") == 1)
225 if (dirp
->d_type
!= DT_DIR
) {
226 direrror(idesc
->id_number
, "BAD TYPE VALUE FOR '.'");
227 dirp
->d_type
= DT_DIR
;
228 if (reply("FIX") == 1)
233 direrror(idesc
->id_number
, "MISSING '.'");
234 proto
.d_ino
= idesc
->id_number
;
235 proto
.d_type
= DT_DIR
;
237 (void) strlcpy(proto
.d_name
, ".", sizeof(proto
.d_name
));
238 entrysize
= DIRSIZ(0, &proto
, 0);
239 if (dirp
->d_ino
!= 0 && strcmp(dirp
->d_name
, "..") != 0) {
240 pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
242 } else if (dirp
->d_reclen
< entrysize
) {
243 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
244 } else if (dirp
->d_reclen
< 2 * entrysize
) {
245 proto
.d_reclen
= dirp
->d_reclen
;
246 memcpy(dirp
, &proto
, (size_t) entrysize
);
247 if (reply("FIX") == 1)
250 n
= dirp
->d_reclen
- entrysize
;
251 proto
.d_reclen
= entrysize
;
252 memcpy(dirp
, &proto
, (size_t) entrysize
);
254 lncntp
[dirp
->d_ino
]--;
255 dirp
= (struct direct
*) ((char *) (dirp
) + entrysize
);
256 memset(dirp
, 0, (size_t) n
);
258 if (reply("FIX") == 1)
262 if (idesc
->id_entryno
> 1)
264 inp
= getinoinfo(idesc
->id_number
);
265 proto
.d_ino
= inp
->i_parent
;
266 proto
.d_type
= DT_DIR
;
268 (void) strlcpy(proto
.d_name
, "..", sizeof(proto
.d_name
));
269 entrysize
= DIRSIZ(0, &proto
, 0);
270 if (idesc
->id_entryno
== 0) {
271 n
= DIRSIZ(0, dirp
, 0);
272 if (dirp
->d_reclen
< n
+ entrysize
)
274 proto
.d_reclen
= dirp
->d_reclen
- n
;
277 lncntp
[dirp
->d_ino
]--;
278 dirp
= (struct direct
*) ((char *) (dirp
) + n
);
279 memset(dirp
, 0, (size_t) proto
.d_reclen
);
280 dirp
->d_reclen
= proto
.d_reclen
;
282 if (dirp
->d_ino
!= 0 && strcmp(dirp
->d_name
, "..") == 0) {
283 inp
->i_dotdot
= dirp
->d_ino
;
284 if (dirp
->d_type
!= DT_DIR
) {
285 direrror(idesc
->id_number
, "BAD TYPE VALUE FOR '..'");
286 dirp
->d_type
= DT_DIR
;
287 if (reply("FIX") == 1)
292 if (dirp
->d_ino
!= 0 && strcmp(dirp
->d_name
, ".") != 0) {
293 fileerror(inp
->i_parent
, idesc
->id_number
, "MISSING '..'");
294 pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
296 inp
->i_dotdot
= (ino_t
) - 1;
297 } else if (dirp
->d_reclen
< entrysize
) {
298 fileerror(inp
->i_parent
, idesc
->id_number
, "MISSING '..'");
299 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
300 inp
->i_dotdot
= (ino_t
) - 1;
301 } else if (inp
->i_parent
!= 0) {
303 * We know the parent, so fix now.
305 inp
->i_dotdot
= inp
->i_parent
;
306 fileerror(inp
->i_parent
, idesc
->id_number
, "MISSING '..'");
307 proto
.d_reclen
= dirp
->d_reclen
;
308 memcpy(dirp
, &proto
, (size_t) entrysize
);
309 if (reply("FIX") == 1)
313 if (dirp
->d_ino
!= 0)
314 lncntp
[dirp
->d_ino
]--;
315 return (ret
| KEEPON
);
317 if (dirp
->d_ino
== 0)
318 return (ret
| KEEPON
);
319 if (dirp
->d_namlen
<= 2 &&
320 dirp
->d_name
[0] == '.' &&
321 idesc
->id_entryno
>= 2) {
322 if (dirp
->d_namlen
== 1) {
323 direrror(idesc
->id_number
, "EXTRA '.' ENTRY");
325 if (reply("FIX") == 1)
327 return (KEEPON
| ret
);
329 if (dirp
->d_name
[1] == '.') {
330 direrror(idesc
->id_number
, "EXTRA '..' ENTRY");
332 if (reply("FIX") == 1)
334 return (KEEPON
| ret
);
339 if (dirp
->d_ino
>= maxino
) {
340 fileerror(idesc
->id_number
, dirp
->d_ino
, "I OUT OF RANGE");
342 } else if (dirp
->d_ino
== LFS_IFILE_INUM
&&
343 idesc
->id_number
== ROOTINO
) {
344 if (dirp
->d_type
!= DT_REG
) {
345 fileerror(idesc
->id_number
, dirp
->d_ino
,
346 "BAD TYPE FOR IFILE");
347 dirp
->d_type
= DT_REG
;
348 if (reply("FIX") == 1)
351 } else if (((dirp
->d_ino
== WINO
&& (dirp
->d_type
!= DT_WHT
)) ||
352 (dirp
->d_ino
!= WINO
&& dirp
->d_type
== DT_WHT
))) {
353 fileerror(idesc
->id_number
, dirp
->d_ino
, "BAD WHITEOUT ENTRY");
355 dirp
->d_type
= DT_WHT
;
356 if (reply("FIX") == 1)
360 switch (statemap
[dirp
->d_ino
]) {
362 if (idesc
->id_entryno
<= 2)
364 fileerror(idesc
->id_number
, dirp
->d_ino
, "UNALLOCATED");
370 if (idesc
->id_entryno
<= 2)
372 if (statemap
[dirp
->d_ino
] == FCLEAR
)
375 errmsg
= "ZERO LENGTH DIRECTORY";
380 fileerror(idesc
->id_number
, dirp
->d_ino
, errmsg
);
381 if ((n
= reply("REMOVE")) == 1)
383 dp
= ginode(dirp
->d_ino
);
384 statemap
[dirp
->d_ino
] =
385 (dp
->di_mode
& IFMT
) == IFDIR
? DSTATE
: FSTATE
;
386 lncntp
[dirp
->d_ino
] = dp
->di_nlink
;
391 inp
= getinoinfo(dirp
->d_ino
);
392 if (inp
->i_parent
!= 0 && idesc
->id_entryno
> 2) {
393 getpathname(pathbuf
, sizeof(pathbuf
),
394 idesc
->id_number
, idesc
->id_number
);
395 getpathname(namebuf
, sizeof(namebuf
),
396 dirp
->d_ino
, dirp
->d_ino
);
397 pwarn("%s %s %s\n", pathbuf
,
398 "IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
401 printf(" (IGNORED)\n");
402 else if ((n
= reply("REMOVE")) == 1)
405 if (idesc
->id_entryno
> 2)
406 inp
->i_parent
= idesc
->id_number
;
410 if (dirp
->d_type
!= typemap
[dirp
->d_ino
]) {
411 fileerror(idesc
->id_number
, dirp
->d_ino
,
414 pwarn("dir has %d, typemap has %d\n",
415 dirp
->d_type
, typemap
[dirp
->d_ino
]);
416 dirp
->d_type
= typemap
[dirp
->d_ino
];
417 if (reply("FIX") == 1)
420 lncntp
[dirp
->d_ino
]--;
424 errx(EEXIT
, "BAD STATE %d FOR INODE I=%d",
425 statemap
[dirp
->d_ino
], dirp
->d_ino
);
429 return (ret
| KEEPON
);
431 return (ret
| KEEPON
| ALTERED
);
434 * Routine to sort disk blocks.
437 blksort(const void *inpp1
, const void *inpp2
)
439 return ((*(const struct inoinfo
*const *) inpp1
)->i_blks
[0] -
440 (*(const struct inoinfo
*const *) inpp2
)->i_blks
[0]);