Annotation of src/sbin/fsck_lfs/pass2.c, Revision 1.17.48.2
1.17.48.2! tls 1: /* $NetBSD$ */
1.1 perseant 2:
3: /*
4: * Copyright (c) 1980, 1986, 1993
5: * The Regents of the University of California. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
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.
1.10 agc 15: * 3. Neither the name of the University nor the names of its contributors
1.1 perseant 16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
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
29: * SUCH DAMAGE.
30: */
31:
1.7 perseant 32: #include <sys/types.h>
1.1 perseant 33: #include <sys/param.h>
34: #include <sys/time.h>
1.7 perseant 35: #include <sys/mount.h>
36: #include <sys/buf.h>
37:
1.1 perseant 38: #include <ufs/lfs/lfs.h>
1.17.48.2! tls 39: #include <ufs/lfs/lfs_inode.h>
1.1 perseant 40:
1.7 perseant 41: #include <err.h>
1.1 perseant 42: #include <stdio.h>
43: #include <stdlib.h>
44: #include <string.h>
45:
1.7 perseant 46: #include "bufcache.h"
47: #include "vnode.h"
1.15 christos 48: #include "lfs_user.h"
1.7 perseant 49:
1.1 perseant 50: #include "fsck.h"
51: #include "fsutil.h"
52: #include "extern.h"
53:
1.17.48.2! tls 54: #define MINDIRSIZE (sizeof (struct lfs_dirtemplate))
1.1 perseant 55:
1.7 perseant 56: static int pass2check(struct inodesc *);
57: static int blksort(const void *, const void *);
1.1 perseant 58:
59: void
1.11 xtraeme 60: pass2(void)
1.1 perseant 61: {
1.17.48.2! tls 62: struct ulfs1_dinode *dp;
1.7 perseant 63: struct uvnode *vp;
64: struct inoinfo **inpp, *inp;
1.1 perseant 65: struct inoinfo **inpend;
1.7 perseant 66: struct inodesc curino;
1.17.48.2! tls 67: struct ulfs1_dinode dino;
1.7 perseant 68: char pathbuf[MAXPATHLEN + 1];
1.1 perseant 69:
1.17.48.2! tls 70: switch (statemap[ULFS_ROOTINO]) {
1.1 perseant 71:
72: case USTATE:
73: pfatal("ROOT INODE UNALLOCATED");
74: if (reply("ALLOCATE") == 0)
1.17 christos 75: err(EEXIT, "%s", "");
1.17.48.2! tls 76: if (allocdir(ULFS_ROOTINO, ULFS_ROOTINO, 0755) != ULFS_ROOTINO)
1.17 christos 77: err(EEXIT, "CANNOT ALLOCATE ROOT INODE\n");
1.1 perseant 78: break;
79:
80: case DCLEAR:
81: pfatal("DUPS/BAD IN ROOT INODE");
82: if (reply("REALLOCATE")) {
1.17.48.2! tls 83: freeino(ULFS_ROOTINO);
! 84: if (allocdir(ULFS_ROOTINO, ULFS_ROOTINO, 0755) != ULFS_ROOTINO)
1.17 christos 85: err(EEXIT, "CANNOT ALLOCATE ROOT INODE\n");
1.1 perseant 86: break;
87: }
88: if (reply("CONTINUE") == 0)
1.17 christos 89: err(EEXIT, "%s", "");
1.1 perseant 90: break;
91:
92: case FSTATE:
93: case FCLEAR:
94: pfatal("ROOT INODE NOT DIRECTORY");
95: if (reply("REALLOCATE")) {
1.17.48.2! tls 96: freeino(ULFS_ROOTINO);
! 97: if (allocdir(ULFS_ROOTINO, ULFS_ROOTINO, 0755) != ULFS_ROOTINO)
1.17 christos 98: err(EEXIT, "CANNOT ALLOCATE ROOT INODE\n");
1.1 perseant 99: break;
100: }
101: if (reply("FIX") == 0)
1.17 christos 102: errx(EEXIT, "%s", "");
1.17.48.2! tls 103: vp = vget(fs, ULFS_ROOTINO);
1.7 perseant 104: dp = VTOD(vp);
1.17.48.2! tls 105: dp->di_mode &= ~LFS_IFMT;
! 106: dp->di_mode |= LFS_IFDIR;
1.7 perseant 107: inodirty(VTOI(vp));
1.1 perseant 108: break;
109:
110: case DSTATE:
111: break;
112:
113: default:
1.17.48.2! tls 114: errx(EEXIT, "BAD STATE %d FOR ROOT INODE\n", statemap[ULFS_ROOTINO]);
1.1 perseant 115: }
1.17.48.2! tls 116: statemap[ULFS_WINO] = FSTATE;
! 117: typemap[ULFS_WINO] = LFS_DT_WHT;
1.1 perseant 118: /*
119: * Sort the directory list into disk block order.
120: */
1.7 perseant 121: qsort((char *) inpsort, (size_t) inplast, sizeof *inpsort, blksort);
1.1 perseant 122: /*
123: * Check the integrity of each directory.
124: */
125: memset(&curino, 0, sizeof(struct inodesc));
126: curino.id_type = DATA;
127: curino.id_func = pass2check;
128: inpend = &inpsort[inplast];
129: for (inpp = inpsort; inpp < inpend; inpp++) {
130: inp = *inpp;
131: if (inp->i_isize == 0)
132: continue;
133: if (inp->i_isize < MINDIRSIZE) {
134: direrror(inp->i_number, "DIRECTORY TOO SHORT");
1.17.48.2! tls 135: inp->i_isize = roundup(MINDIRSIZE, LFS_DIRBLKSIZ);
1.1 perseant 136: if (reply("FIX") == 1) {
1.7 perseant 137: vp = vget(fs, inp->i_number);
138: dp = VTOD(vp);
1.1 perseant 139: dp->di_size = inp->i_isize;
1.7 perseant 140: inodirty(VTOI(vp));
1.1 perseant 141: }
1.17.48.2! tls 142: } else if ((inp->i_isize & (LFS_DIRBLKSIZ - 1)) != 0) {
1.9 itojun 143: getpathname(pathbuf, sizeof(pathbuf), inp->i_number,
144: inp->i_number);
1.2 nathanw 145: pwarn("DIRECTORY %s: LENGTH %lu NOT MULTIPLE OF %d",
1.17.48.2! tls 146: pathbuf, (unsigned long) inp->i_isize, LFS_DIRBLKSIZ);
1.1 perseant 147: if (preen)
148: printf(" (ADJUSTED)\n");
1.17.48.2! tls 149: inp->i_isize = roundup(inp->i_isize, LFS_DIRBLKSIZ);
1.1 perseant 150: if (preen || reply("ADJUST") == 1) {
1.7 perseant 151: vp = vget(fs, inp->i_number);
152: dp = VTOD(vp);
1.1 perseant 153: dp->di_size = inp->i_isize;
1.7 perseant 154: inodirty(VTOI(vp));
1.1 perseant 155: }
156: }
1.17.48.2! tls 157: memset(&dino, 0, sizeof(struct ulfs1_dinode));
! 158: dino.di_mode = LFS_IFDIR;
1.1 perseant 159: dino.di_size = inp->i_isize;
1.7 perseant 160: memcpy(&dino.di_db[0], &inp->i_blks[0], (size_t) inp->i_numblks);
1.1 perseant 161: curino.id_number = inp->i_number;
162: curino.id_parent = inp->i_parent;
1.7 perseant 163: (void) ckinode(&dino, &curino);
1.1 perseant 164: }
165: /*
166: * Now that the parents of all directories have been found,
167: * make another pass to verify the value of `..'
168: */
169: for (inpp = inpsort; inpp < inpend; inpp++) {
170: inp = *inpp;
171: if (inp->i_parent == 0 || inp->i_isize == 0)
172: continue;
173: if (inp->i_dotdot == inp->i_parent ||
1.7 perseant 174: inp->i_dotdot == (ino_t) - 1)
1.1 perseant 175: continue;
176: if (inp->i_dotdot == 0) {
177: inp->i_dotdot = inp->i_parent;
178: fileerror(inp->i_parent, inp->i_number, "MISSING '..'");
179: if (reply("FIX") == 0)
180: continue;
1.7 perseant 181: (void) makeentry(inp->i_number, inp->i_parent, "..");
1.1 perseant 182: lncntp[inp->i_parent]--;
183: continue;
184: }
185: fileerror(inp->i_parent, inp->i_number,
1.7 perseant 186: "BAD INODE NUMBER FOR '..'");
1.1 perseant 187: if (reply("FIX") == 0)
188: continue;
189: lncntp[inp->i_dotdot]++;
190: lncntp[inp->i_parent]--;
191: inp->i_dotdot = inp->i_parent;
1.7 perseant 192: (void) changeino(inp->i_number, "..", inp->i_parent);
1.1 perseant 193: }
194: /*
195: * Mark all the directories that can be found from the root.
196: */
197: propagate();
198: }
199:
200: static int
1.4 perseant 201: pass2check(struct inodesc * idesc)
1.1 perseant 202: {
1.17.48.2! tls 203: struct lfs_direct *dirp = idesc->id_dirp;
1.12 perry 204: struct inoinfo *inp;
1.7 perseant 205: int n, entrysize, ret = 0;
1.17.48.2! tls 206: struct ulfs1_dinode *dp;
1.14 christos 207: const char *errmsg;
1.17.48.2! tls 208: struct lfs_direct proto;
1.7 perseant 209: char namebuf[MAXPATHLEN + 1];
210: char pathbuf[MAXPATHLEN + 1];
1.1 perseant 211:
212: /*
213: * check for "."
214: */
215: if (idesc->id_entryno != 0)
216: goto chk1;
217: if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
218: if (dirp->d_ino != idesc->id_number) {
219: direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
220: dirp->d_ino = idesc->id_number;
221: if (reply("FIX") == 1)
222: ret |= ALTERED;
223: }
1.17.48.2! tls 224: if (dirp->d_type != LFS_DT_DIR) {
1.1 perseant 225: direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'");
1.17.48.2! tls 226: dirp->d_type = LFS_DT_DIR;
1.1 perseant 227: if (reply("FIX") == 1)
228: ret |= ALTERED;
229: }
230: goto chk1;
231: }
232: direrror(idesc->id_number, "MISSING '.'");
233: proto.d_ino = idesc->id_number;
1.17.48.2! tls 234: proto.d_type = LFS_DT_DIR;
1.1 perseant 235: proto.d_namlen = 1;
1.9 itojun 236: (void) strlcpy(proto.d_name, ".", sizeof(proto.d_name));
1.17.48.2! tls 237: entrysize = LFS_DIRSIZ(0, &proto, 0);
1.1 perseant 238: if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
239: pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
1.7 perseant 240: dirp->d_name);
1.1 perseant 241: } else if (dirp->d_reclen < entrysize) {
242: pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
243: } else if (dirp->d_reclen < 2 * entrysize) {
244: proto.d_reclen = dirp->d_reclen;
1.7 perseant 245: memcpy(dirp, &proto, (size_t) entrysize);
1.1 perseant 246: if (reply("FIX") == 1)
247: ret |= ALTERED;
248: } else {
249: n = dirp->d_reclen - entrysize;
250: proto.d_reclen = entrysize;
1.7 perseant 251: memcpy(dirp, &proto, (size_t) entrysize);
1.1 perseant 252: idesc->id_entryno++;
253: lncntp[dirp->d_ino]--;
1.17.48.2! tls 254: dirp = (struct lfs_direct *) ((char *) (dirp) + entrysize);
1.7 perseant 255: memset(dirp, 0, (size_t) n);
1.1 perseant 256: dirp->d_reclen = n;
257: if (reply("FIX") == 1)
258: ret |= ALTERED;
259: }
260: chk1:
261: if (idesc->id_entryno > 1)
262: goto chk2;
263: inp = getinoinfo(idesc->id_number);
264: proto.d_ino = inp->i_parent;
1.17.48.2! tls 265: proto.d_type = LFS_DT_DIR;
1.1 perseant 266: proto.d_namlen = 2;
1.9 itojun 267: (void) strlcpy(proto.d_name, "..", sizeof(proto.d_name));
1.17.48.2! tls 268: entrysize = LFS_DIRSIZ(0, &proto, 0);
1.1 perseant 269: if (idesc->id_entryno == 0) {
1.17.48.2! tls 270: n = LFS_DIRSIZ(0, dirp, 0);
1.1 perseant 271: if (dirp->d_reclen < n + entrysize)
272: goto chk2;
273: proto.d_reclen = dirp->d_reclen - n;
274: dirp->d_reclen = n;
275: idesc->id_entryno++;
276: lncntp[dirp->d_ino]--;
1.17.48.2! tls 277: dirp = (struct lfs_direct *) ((char *) (dirp) + n);
1.7 perseant 278: memset(dirp, 0, (size_t) proto.d_reclen);
1.1 perseant 279: dirp->d_reclen = proto.d_reclen;
280: }
281: if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
282: inp->i_dotdot = dirp->d_ino;
1.17.48.2! tls 283: if (dirp->d_type != LFS_DT_DIR) {
1.1 perseant 284: direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'");
1.17.48.2! tls 285: dirp->d_type = LFS_DT_DIR;
1.1 perseant 286: if (reply("FIX") == 1)
287: ret |= ALTERED;
288: }
289: goto chk2;
290: }
291: if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
292: fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
293: pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
1.7 perseant 294: dirp->d_name);
295: inp->i_dotdot = (ino_t) - 1;
1.1 perseant 296: } else if (dirp->d_reclen < entrysize) {
297: fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
298: pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
1.7 perseant 299: inp->i_dotdot = (ino_t) - 1;
1.1 perseant 300: } else if (inp->i_parent != 0) {
301: /*
302: * We know the parent, so fix now.
303: */
304: inp->i_dotdot = inp->i_parent;
305: fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
306: proto.d_reclen = dirp->d_reclen;
1.7 perseant 307: memcpy(dirp, &proto, (size_t) entrysize);
1.1 perseant 308: if (reply("FIX") == 1)
309: ret |= ALTERED;
310: }
311: idesc->id_entryno++;
312: if (dirp->d_ino != 0)
313: lncntp[dirp->d_ino]--;
1.4 perseant 314: return (ret | KEEPON);
1.1 perseant 315: chk2:
316: if (dirp->d_ino == 0)
1.4 perseant 317: return (ret | KEEPON);
1.1 perseant 318: if (dirp->d_namlen <= 2 &&
319: dirp->d_name[0] == '.' &&
320: idesc->id_entryno >= 2) {
321: if (dirp->d_namlen == 1) {
322: direrror(idesc->id_number, "EXTRA '.' ENTRY");
323: dirp->d_ino = 0;
324: if (reply("FIX") == 1)
325: ret |= ALTERED;
326: return (KEEPON | ret);
327: }
328: if (dirp->d_name[1] == '.') {
329: direrror(idesc->id_number, "EXTRA '..' ENTRY");
330: dirp->d_ino = 0;
331: if (reply("FIX") == 1)
332: ret |= ALTERED;
333: return (KEEPON | ret);
334: }
335: }
336: idesc->id_entryno++;
337: n = 0;
1.5 perseant 338: if (dirp->d_ino >= maxino) {
1.1 perseant 339: fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
340: n = reply("REMOVE");
1.4 perseant 341: } else if (dirp->d_ino == LFS_IFILE_INUM &&
1.17.48.2! tls 342: idesc->id_number == ULFS_ROOTINO) {
! 343: if (dirp->d_type != LFS_DT_REG) {
1.4 perseant 344: fileerror(idesc->id_number, dirp->d_ino,
1.7 perseant 345: "BAD TYPE FOR IFILE");
1.17.48.2! tls 346: dirp->d_type = LFS_DT_REG;
1.4 perseant 347: if (reply("FIX") == 1)
348: ret |= ALTERED;
349: }
1.17.48.2! tls 350: } else if (((dirp->d_ino == ULFS_WINO && (dirp->d_type != LFS_DT_WHT)) ||
! 351: (dirp->d_ino != ULFS_WINO && dirp->d_type == LFS_DT_WHT))) {
1.1 perseant 352: fileerror(idesc->id_number, dirp->d_ino, "BAD WHITEOUT ENTRY");
1.17.48.2! tls 353: dirp->d_ino = ULFS_WINO;
! 354: dirp->d_type = LFS_DT_WHT;
1.1 perseant 355: if (reply("FIX") == 1)
356: ret |= ALTERED;
357: } else {
358: again:
359: switch (statemap[dirp->d_ino]) {
360: case USTATE:
361: if (idesc->id_entryno <= 2)
362: break;
363: fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED");
364: n = reply("REMOVE");
365: break;
366:
367: case DCLEAR:
368: case FCLEAR:
369: if (idesc->id_entryno <= 2)
370: break;
371: if (statemap[dirp->d_ino] == FCLEAR)
372: errmsg = "DUP/BAD";
373: else if (!preen)
374: errmsg = "ZERO LENGTH DIRECTORY";
375: else {
376: n = 1;
377: break;
378: }
379: fileerror(idesc->id_number, dirp->d_ino, errmsg);
380: if ((n = reply("REMOVE")) == 1)
381: break;
382: dp = ginode(dirp->d_ino);
383: statemap[dirp->d_ino] =
1.17.48.2! tls 384: (dp->di_mode & LFS_IFMT) == LFS_IFDIR ? DSTATE : FSTATE;
1.1 perseant 385: lncntp[dirp->d_ino] = dp->di_nlink;
386: goto again;
387:
388: case DSTATE:
389: case DFOUND:
390: inp = getinoinfo(dirp->d_ino);
391: if (inp->i_parent != 0 && idesc->id_entryno > 2) {
1.9 itojun 392: getpathname(pathbuf, sizeof(pathbuf),
393: idesc->id_number, idesc->id_number);
394: getpathname(namebuf, sizeof(namebuf),
395: dirp->d_ino, dirp->d_ino);
1.1 perseant 396: pwarn("%s %s %s\n", pathbuf,
1.7 perseant 397: "IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
398: namebuf);
1.1 perseant 399: if (preen)
400: printf(" (IGNORED)\n");
401: else if ((n = reply("REMOVE")) == 1)
402: break;
403: }
404: if (idesc->id_entryno > 2)
405: inp->i_parent = idesc->id_number;
406: /* fall through */
407:
408: case FSTATE:
1.7 perseant 409: if (dirp->d_type != typemap[dirp->d_ino]) {
1.1 perseant 410: fileerror(idesc->id_number, dirp->d_ino,
1.7 perseant 411: "BAD TYPE VALUE");
1.13 perseant 412: if (debug)
413: pwarn("dir has %d, typemap has %d\n",
414: dirp->d_type, typemap[dirp->d_ino]);
1.1 perseant 415: dirp->d_type = typemap[dirp->d_ino];
416: if (reply("FIX") == 1)
417: ret |= ALTERED;
418: }
419: lncntp[dirp->d_ino]--;
420: break;
421:
422: default:
1.17 christos 423: errx(EEXIT, "BAD STATE %d FOR INODE I=%d",
1.7 perseant 424: statemap[dirp->d_ino], dirp->d_ino);
1.1 perseant 425: }
426: }
427: if (n == 0)
1.4 perseant 428: return (ret | KEEPON);
1.1 perseant 429: dirp->d_ino = 0;
1.4 perseant 430: return (ret | KEEPON | ALTERED);
1.1 perseant 431: }
432: /*
433: * Routine to sort disk blocks.
434: */
435: static int
1.4 perseant 436: blksort(const void *inpp1, const void *inpp2)
1.1 perseant 437: {
1.14 christos 438: return ((*(const struct inoinfo *const *) inpp1)->i_blks[0] -
439: (*(const struct inoinfo *const *) inpp2)->i_blks[0]);
1.1 perseant 440: }
CVSweb <webmaster@jp.NetBSD.org>