convert to BSD only copyright
[unix-history] / usr / src / sbin / fsck / pass2.c
index 55cf94b..4da68e5 100644 (file)
@@ -1,11 +1,28 @@
+/*
+ * Copyright (c) 1980, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
 #ifndef lint
 #ifndef lint
-static char version[] = "@(#)pass2.c   3.1 (Berkeley) %G%";
-#endif
+static char sccsid[] = "@(#)pass2.c    5.8 (Berkeley) %G%";
+#endif /* not lint */
 
 #include <sys/param.h>
 
 #include <sys/param.h>
-#include <sys/inode.h>
-#include <sys/fs.h>
-#include <sys/dir.h>
+#include <ufs/dinode.h>
+#include <ufs/fs.h>
+#include <ufs/dir.h>
 #include <strings.h>
 #include "fsck.h"
 
 #include <strings.h>
 #include "fsck.h"
 
@@ -13,7 +30,7 @@ int   pass2check();
 
 pass2()
 {
 
 pass2()
 {
-       register DINODE *dp;
+       register struct dinode *dp;
        struct inodesc rootdesc;
 
        bzero((char *)&rootdesc, sizeof(struct inodesc));
        struct inodesc rootdesc;
 
        bzero((char *)&rootdesc, sizeof(struct inodesc));
@@ -24,16 +41,45 @@ pass2()
        switch (statemap[ROOTINO]) {
 
        case USTATE:
        switch (statemap[ROOTINO]) {
 
        case USTATE:
-               errexit("ROOT INODE UNALLOCATED. TERMINATING.\n");
+               pfatal("ROOT INODE UNALLOCATED");
+               if (reply("ALLOCATE") == 0)
+                       errexit("");
+               if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
+                       errexit("CANNOT ALLOCATE ROOT INODE\n");
+               descend(&rootdesc, ROOTINO);
+               break;
+
+       case DCLEAR:
+               pfatal("DUPS/BAD IN ROOT INODE");
+               if (reply("REALLOCATE")) {
+                       freeino(ROOTINO);
+                       if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
+                               errexit("CANNOT ALLOCATE ROOT INODE\n");
+                       descend(&rootdesc, ROOTINO);
+                       break;
+               }
+               if (reply("CONTINUE") == 0)
+                       errexit("");
+               statemap[ROOTINO] = DSTATE;
+               descend(&rootdesc, ROOTINO);
+               break;
 
        case FSTATE:
 
        case FSTATE:
+       case FCLEAR:
                pfatal("ROOT INODE NOT DIRECTORY");
                pfatal("ROOT INODE NOT DIRECTORY");
-               if (reply("FIX") == 0 || (dp = ginode(ROOTINO)) == NULL)
+               if (reply("REALLOCATE")) {
+                       freeino(ROOTINO);
+                       if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
+                               errexit("CANNOT ALLOCATE ROOT INODE\n");
+                       descend(&rootdesc, ROOTINO);
+                       break;
+               }
+               if (reply("FIX") == 0)
                        errexit("");
                        errexit("");
+               dp = ginode(ROOTINO);
                dp->di_mode &= ~IFMT;
                dp->di_mode |= IFDIR;
                inodirty();
                dp->di_mode &= ~IFMT;
                dp->di_mode |= IFDIR;
                inodirty();
-               inosumbad++;
                statemap[ROOTINO] = DSTATE;
                /* fall into ... */
 
                statemap[ROOTINO] = DSTATE;
                /* fall into ... */
 
@@ -41,24 +87,20 @@ pass2()
                descend(&rootdesc, ROOTINO);
                break;
 
                descend(&rootdesc, ROOTINO);
                break;
 
-       case CLEAR:
-               pfatal("DUPS/BAD IN ROOT INODE");
-               printf("\n");
-               if (reply("CONTINUE") == 0)
-                       errexit("");
-               statemap[ROOTINO] = DSTATE;
-               descend(&rootdesc, ROOTINO);
+       default:
+               errexit("BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]);
        }
 }
 
 pass2check(idesc)
        struct inodesc *idesc;
 {
        }
 }
 
 pass2check(idesc)
        struct inodesc *idesc;
 {
-       register DIRECT *dirp = idesc->id_dirp;
+       register struct direct *dirp = idesc->id_dirp;
        char *curpathloc;
        int n, entrysize, ret = 0;
        char *curpathloc;
        int n, entrysize, ret = 0;
-       DINODE *dp;
-       DIRECT proto;
+       struct dinode *dp;
+       struct direct proto;
+       char namebuf[BUFSIZ];
 
        /* 
         * check for "."
 
        /* 
         * check for "."
@@ -67,14 +109,14 @@ pass2check(idesc)
                goto chk1;
        if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
                if (dirp->d_ino != idesc->id_number) {
                goto chk1;
        if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
                if (dirp->d_ino != idesc->id_number) {
-                       direrr(idesc->id_number, "BAD INODE NUMBER FOR '.'");
+                       direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
                        dirp->d_ino = idesc->id_number;
                        if (reply("FIX") == 1)
                                ret |= ALTERED;
                }
                goto chk1;
        }
                        dirp->d_ino = idesc->id_number;
                        if (reply("FIX") == 1)
                                ret |= ALTERED;
                }
                goto chk1;
        }
-       direrr(idesc->id_number, "MISSING '.'");
+       direrror(idesc->id_number, "MISSING '.'");
        proto.d_ino = idesc->id_number;
        proto.d_namlen = 1;
        (void)strcpy(proto.d_name, ".");
        proto.d_ino = idesc->id_number;
        proto.d_namlen = 1;
        (void)strcpy(proto.d_name, ".");
@@ -95,7 +137,7 @@ pass2check(idesc)
                bcopy((char *)&proto, (char *)dirp, entrysize);
                idesc->id_entryno++;
                lncntp[dirp->d_ino]--;
                bcopy((char *)&proto, (char *)dirp, entrysize);
                idesc->id_entryno++;
                lncntp[dirp->d_ino]--;
-               dirp = (DIRECT *)((char *)(dirp) + entrysize);
+               dirp = (struct direct *)((char *)(dirp) + entrysize);
                bzero((char *)dirp, n);
                dirp->d_reclen = n;
                if (reply("FIX") == 1)
                bzero((char *)dirp, n);
                dirp->d_reclen = n;
                if (reply("FIX") == 1)
@@ -116,20 +158,20 @@ chk1:
                dirp->d_reclen = n;
                idesc->id_entryno++;
                lncntp[dirp->d_ino]--;
                dirp->d_reclen = n;
                idesc->id_entryno++;
                lncntp[dirp->d_ino]--;
-               dirp = (DIRECT *)((char *)(dirp) + n);
+               dirp = (struct direct *)((char *)(dirp) + n);
                bzero((char *)dirp, n);
                dirp->d_reclen = n;
        }
        if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
                if (dirp->d_ino != idesc->id_parent) {
                bzero((char *)dirp, n);
                dirp->d_reclen = n;
        }
        if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
                if (dirp->d_ino != idesc->id_parent) {
-                       direrr(idesc->id_number, "BAD INODE NUMBER FOR '..'");
+                       direrror(idesc->id_number, "BAD INODE NUMBER FOR '..'");
                        dirp->d_ino = idesc->id_parent;
                        if (reply("FIX") == 1)
                                ret |= ALTERED;
                }
                goto chk2;
        }
                        dirp->d_ino = idesc->id_parent;
                        if (reply("FIX") == 1)
                                ret |= ALTERED;
                }
                goto chk2;
        }
-       direrr(idesc->id_number, "MISSING '..'");
+       direrror(idesc->id_number, "MISSING '..'");
        if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
                pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
                        dirp->d_name);
        if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
                pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
                        dirp->d_name);
@@ -148,14 +190,14 @@ chk2:
            dirp->d_name[0] == '.' &&
            idesc->id_entryno >= 2) {
                if (dirp->d_namlen == 1) {
            dirp->d_name[0] == '.' &&
            idesc->id_entryno >= 2) {
                if (dirp->d_namlen == 1) {
-                       direrr(idesc->id_number, "EXTRA '.' ENTRY");
+                       direrror(idesc->id_number, "EXTRA '.' ENTRY");
                        dirp->d_ino = 0;
                        if (reply("FIX") == 1)
                                ret |= ALTERED;
                        return (KEEPON | ret);
                }
                if (dirp->d_name[1] == '.') {
                        dirp->d_ino = 0;
                        if (reply("FIX") == 1)
                                ret |= ALTERED;
                        return (KEEPON | ret);
                }
                if (dirp->d_name[1] == '.') {
-                       direrr(idesc->id_number, "EXTRA '..' ENTRY");
+                       direrror(idesc->id_number, "EXTRA '..' ENTRY");
                        dirp->d_ino = 0;
                        if (reply("FIX") == 1)
                                ret |= ALTERED;
                        dirp->d_ino = 0;
                        if (reply("FIX") == 1)
                                ret |= ALTERED;
@@ -168,43 +210,64 @@ chk2:
                *pathp = '\0';
                errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name);
        }
                *pathp = '\0';
                errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name);
        }
-       bcopy(dirp->d_name, pathp, dirp->d_namlen + 1);
+       bcopy(dirp->d_name, pathp, (int)dirp->d_namlen + 1);
        pathp += dirp->d_namlen;
        idesc->id_entryno++;
        n = 0;
        pathp += dirp->d_namlen;
        idesc->id_entryno++;
        n = 0;
-       if (dirp->d_ino > imax || dirp->d_ino <= 0) {
-               direrr(dirp->d_ino, "I OUT OF RANGE");
+       if (dirp->d_ino > maxino || dirp->d_ino <= 0) {
+               direrror(dirp->d_ino, "I OUT OF RANGE");
                n = reply("REMOVE");
        } else {
 again:
                switch (statemap[dirp->d_ino]) {
                case USTATE:
                n = reply("REMOVE");
        } else {
 again:
                switch (statemap[dirp->d_ino]) {
                case USTATE:
-                       direrr(dirp->d_ino, "UNALLOCATED");
+                       direrror(dirp->d_ino, "UNALLOCATED");
                        n = reply("REMOVE");
                        break;
 
                        n = reply("REMOVE");
                        break;
 
-               case CLEAR:
-                       direrr(dirp->d_ino, "DUP/BAD");
+               case DCLEAR:
+               case FCLEAR:
+                       direrror(dirp->d_ino, "DUP/BAD");
                        if ((n = reply("REMOVE")) == 1)
                                break;
                        if ((n = reply("REMOVE")) == 1)
                                break;
-                       if ((dp = ginode(dirp->d_ino)) == NULL)
-                               break;
-                       statemap[dirp->d_ino] = DIRCT ? DSTATE : FSTATE;
+                       dp = ginode(dirp->d_ino);
+                       statemap[dirp->d_ino] =
+                           (dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE;
+                       lncntp[dirp->d_ino] = dp->di_nlink;
                        goto again;
 
                        goto again;
 
+               case DFOUND:
+                       if (idesc->id_entryno > 2) {
+                               getpathname(namebuf, dirp->d_ino, dirp->d_ino);
+                               pwarn("%s %s %s\n", pathname,
+                                   "IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
+                                   namebuf);
+                               if (preen)
+                                       printf(" (IGNORED)\n");
+                               else if ((n = reply("REMOVE")) == 1)
+                                       break;
+                       }
+                       /* fall through */
+
                case FSTATE:
                        lncntp[dirp->d_ino]--;
                        break;
 
                case DSTATE:
                        descend(idesc, dirp->d_ino);
                case FSTATE:
                        lncntp[dirp->d_ino]--;
                        break;
 
                case DSTATE:
                        descend(idesc, dirp->d_ino);
-                       if (statemap[dirp->d_ino] != CLEAR) {
+                       if (statemap[dirp->d_ino] == DFOUND) {
                                lncntp[dirp->d_ino]--;
                                lncntp[dirp->d_ino]--;
-                       } else {
+                       } else if (statemap[dirp->d_ino] == DCLEAR) {
                                dirp->d_ino = 0;
                                ret |= ALTERED;
                                dirp->d_ino = 0;
                                ret |= ALTERED;
-                       }
+                       } else
+                               errexit("BAD RETURN STATE %d FROM DESCEND",
+                                   statemap[dirp->d_ino]);
                        break;
                        break;
+
+               default:
+                       errexit("BAD STATE %d FOR INODE I=%d",
+                           statemap[dirp->d_ino], dirp->d_ino);
                }
        }
        pathp = curpathloc;
                }
        }
        pathp = curpathloc;