4.4BSD snapshot (revision 8.1)
[unix-history] / usr / src / sbin / fsck / pass1.c
index 1e87677..920c744 100644 (file)
@@ -1,27 +1,21 @@
 /*
 /*
- * Copyright (c) 1980, 1986 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1980, 1986, 1993
+ *     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.
+ * %sccs.include.redist.c%
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)pass1.c    5.11 (Berkeley) %G%";
+static char sccsid[] = "@(#)pass1.c    8.1 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <sys/param.h>
 #endif /* not lint */
 
 #include <sys/param.h>
-#include <ufs/dinode.h>
-#include <ufs/fs.h>
+#include <sys/time.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ufs/dir.h>
+#include <ufs/ffs/fs.h>
+#include <stdlib.h>
+#include <string.h>
 #include "fsck.h"
 
 static daddr_t badblk;
 #include "fsck.h"
 
 static daddr_t badblk;
@@ -31,12 +25,9 @@ struct dinode *getnextinode();
 
 pass1()
 {
 
 pass1()
 {
-       register int c, i, j;
-       register struct dinode *dp;
-       struct zlncnt *zlnp;
-       int ndb, cgd;
-       struct inodesc idesc;
        ino_t inumber;
        ino_t inumber;
+       int c, i, cgd;
+       struct inodesc idesc;
 
        /*
         * Set file system reserved blocks in used block map.
 
        /*
         * Set file system reserved blocks in used block map.
@@ -64,109 +55,169 @@ pass1()
                for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
                        if (inumber < ROOTINO)
                                continue;
                for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
                        if (inumber < ROOTINO)
                                continue;
-                       dp = getnextinode(inumber);
-                       if ((dp->di_mode & IFMT) == 0) {
-                               if (bcmp((char *)dp->di_db, (char *)zino.di_db,
-                                       NDADDR * sizeof(daddr_t)) ||
-                                   bcmp((char *)dp->di_ib, (char *)zino.di_ib,
-                                       NIADDR * sizeof(daddr_t)) ||
-                                   dp->di_mode || dp->di_size) {
-                                       pfatal("PARTIALLY ALLOCATED INODE I=%u",
-                                               inumber);
-                                       if (reply("CLEAR") == 1) {
-                                               clearinode(dp);
-                                               inodirty();
-                                       }
-                               }
-                               statemap[inumber] = USTATE;
-                               continue;
-                       }
-                       lastino = inumber;
-                       if (dp->di_size < 0 ||
-                           dp->di_size + sblock.fs_bsize - 1 < 0) {
-                               if (debug)
-                                       printf("bad size %d:", dp->di_size);
-                               goto unknown;
-                       }
-                       if (!preen && (dp->di_mode & IFMT) == IFMT &&
-                           reply("HOLD BAD BLOCK") == 1) {
-                               dp->di_size = sblock.fs_fsize;
-                               dp->di_mode = IFREG|0600;
-                               inodirty();
-                       }
-                       ndb = howmany(dp->di_size, sblock.fs_bsize);
-                       if (ndb < 0) {
-                               if (debug)
-                                       printf("bad size %d ndb %d:",
-                                               dp->di_size, ndb);
-                               goto unknown;
-                       }
-                       if ((dp->di_mode & IFMT) == IFBLK ||
-                           (dp->di_mode & IFMT) == IFCHR)
-                               ndb++;
-                       for (j = ndb; j < NDADDR; j++)
-                               if (dp->di_db[j] != 0) {
-                                       if (debug)
-                                               printf("bad direct addr: %d\n",
-                                                       dp->di_db[j]);
-                                       goto unknown;
-                               }
-                       for (j = 0, ndb -= NDADDR; ndb > 0; j++)
-                               ndb /= NINDIR(&sblock);
-                       for (; j < NIADDR; j++)
-                               if (dp->di_ib[j] != 0) {
-                                       if (debug)
-                                               printf("bad indirect addr: %d\n",
-                                                       dp->di_ib[j]);
-                                       goto unknown;
-                               }
-                       if (ftypeok(dp) == 0)
-                               goto unknown;
-                       n_files++;
-                       lncntp[inumber] = dp->di_nlink;
-                       if (dp->di_nlink <= 0) {
-                               zlnp = (struct zlncnt *)malloc(sizeof *zlnp);
-                               if (zlnp == NULL) {
-                                       pfatal("LINK COUNT TABLE OVERFLOW");
-                                       if (reply("CONTINUE") == 0)
-                                               errexit("");
-                               } else {
-                                       zlnp->zlncnt = inumber;
-                                       zlnp->next = zlnhead;
-                                       zlnhead = zlnp;
-                               }
-                       }
-                       if ((dp->di_mode & IFMT) == IFDIR) {
-                               statemap[inumber] = DSTATE;
-                               cacheino(dp, inumber);
-                       } else
-                               statemap[inumber] = FSTATE;
-                       badblk = dupblk = 0;
-                       idesc.id_number = inumber;
-                       (void)ckinode(dp, &idesc);
-                       idesc.id_entryno *= btodb(sblock.fs_fsize);
-                       if (dp->di_blocks != idesc.id_entryno) {
-                               pwarn("INCORRECT BLOCK COUNT I=%u (%ld should be %ld)",
-                                   inumber, dp->di_blocks, idesc.id_entryno);
-                               if (preen)
-                                       printf(" (CORRECTED)\n");
-                               else if (reply("CORRECT") == 0)
-                                       continue;
-                               dp->di_blocks = idesc.id_entryno;
-                               inodirty();
-                       }
-                       continue;
-       unknown:
-                       pfatal("UNKNOWN FILE TYPE I=%u", inumber);
-                       statemap[inumber] = FCLEAR;
+                       checkinode(inumber, &idesc);
+               }
+       }
+       freeinodebuf();
+}
+
+checkinode(inumber, idesc)
+       ino_t inumber;
+       register struct inodesc *idesc;
+{
+       register struct dinode *dp;
+       struct zlncnt *zlnp;
+       int ndb, j;
+       mode_t mode;
+       char symbuf[MAXSYMLINKLEN];
+
+       dp = getnextinode(inumber);
+       mode = dp->di_mode & IFMT;
+       if (mode == 0) {
+               if (bcmp((char *)dp->di_db, (char *)zino.di_db,
+                       NDADDR * sizeof(daddr_t)) ||
+                   bcmp((char *)dp->di_ib, (char *)zino.di_ib,
+                       NIADDR * sizeof(daddr_t)) ||
+                   dp->di_mode || dp->di_size) {
+                       pfatal("PARTIALLY ALLOCATED INODE I=%lu", inumber);
                        if (reply("CLEAR") == 1) {
                        if (reply("CLEAR") == 1) {
-                               statemap[inumber] = USTATE;
+                               dp = ginode(inumber);
                                clearinode(dp);
                                inodirty();
                        }
                }
                                clearinode(dp);
                                inodirty();
                        }
                }
+               statemap[inumber] = USTATE;
+               return;
+       }
+       lastino = inumber;
+       if (/* dp->di_size < 0 || */
+           dp->di_size + sblock.fs_bsize - 1 < dp->di_size) {
+               if (debug)
+                       printf("bad size %qu:", dp->di_size);
+               goto unknown;
+       }
+       if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
+               dp = ginode(inumber);
+               dp->di_size = sblock.fs_fsize;
+               dp->di_mode = IFREG|0600;
+               inodirty();
+       }
+       ndb = howmany(dp->di_size, sblock.fs_bsize);
+       if (ndb < 0) {
+               if (debug)
+                       printf("bad size %qu ndb %d:",
+                               dp->di_size, ndb);
+               goto unknown;
+       }
+       if (mode == IFBLK || mode == IFCHR)
+               ndb++;
+       if (mode == IFLNK) {
+               if (doinglevel2 &&
+                   dp->di_size > 0 && dp->di_size < MAXSYMLINKLEN &&
+                   dp->di_blocks != 0) {
+                       if (bread(fsreadfd, symbuf,
+                           fsbtodb(&sblock, dp->di_db[0]),
+                           (long)dp->di_size) != 0)
+                               errexit("cannot read symlink");
+                       if (debug) {
+                               symbuf[dp->di_size] = 0;
+                               printf("convert symlink %d(%s) of size %d\n",
+                                       inumber, symbuf, (long)dp->di_size);
+                       }
+                       dp = ginode(inumber);
+                       bcopy(symbuf, (caddr_t)dp->di_shortlink,
+                           (long)dp->di_size);
+                       dp->di_blocks = 0;
+                       inodirty();
+               }
+               /*
+                * Fake ndb value so direct/indirect block checks below
+                * will detect any garbage after symlink string.
+                */
+               if (dp->di_size < sblock.fs_maxsymlinklen) {
+                       ndb = howmany(dp->di_size, sizeof(daddr_t));
+                       if (ndb > NDADDR) {
+                               j = ndb - NDADDR;
+                               for (ndb = 1; j > 1; j--)
+                                       ndb *= NINDIR(&sblock);
+                               ndb += NDADDR;
+                       }
+               }
+       }
+       for (j = ndb; j < NDADDR; j++)
+               if (dp->di_db[j] != 0) {
+                       if (debug)
+                               printf("bad direct addr: %ld\n", dp->di_db[j]);
+                       goto unknown;
+               }
+       for (j = 0, ndb -= NDADDR; ndb > 0; j++)
+               ndb /= NINDIR(&sblock);
+       for (; j < NIADDR; j++)
+               if (dp->di_ib[j] != 0) {
+                       if (debug)
+                               printf("bad indirect addr: %ld\n",
+                                       dp->di_ib[j]);
+                       goto unknown;
+               }
+       if (ftypeok(dp) == 0)
+               goto unknown;
+       n_files++;
+       lncntp[inumber] = dp->di_nlink;
+       if (dp->di_nlink <= 0) {
+               zlnp = (struct zlncnt *)malloc(sizeof *zlnp);
+               if (zlnp == NULL) {
+                       pfatal("LINK COUNT TABLE OVERFLOW");
+                       if (reply("CONTINUE") == 0)
+                               errexit("");
+               } else {
+                       zlnp->zlncnt = inumber;
+                       zlnp->next = zlnhead;
+                       zlnhead = zlnp;
+               }
+       }
+       if (mode == IFDIR) {
+               if (dp->di_size == 0)
+                       statemap[inumber] = DCLEAR;
+               else
+                       statemap[inumber] = DSTATE;
+               cacheino(dp, inumber);
+       } else
+               statemap[inumber] = FSTATE;
+       typemap[inumber] = IFTODT(mode);
+       if (doinglevel2 &&
+           (dp->di_ouid != (u_short)-1 || dp->di_ogid != (u_short)-1)) {
+               dp = ginode(inumber);
+               dp->di_uid = dp->di_ouid;
+               dp->di_ouid = -1;
+               dp->di_gid = dp->di_ogid;
+               dp->di_ogid = -1;
+               inodirty();
+       }
+       badblk = dupblk = 0;
+       idesc->id_number = inumber;
+       (void)ckinode(dp, idesc);
+       idesc->id_entryno *= btodb(sblock.fs_fsize);
+       if (dp->di_blocks != idesc->id_entryno) {
+               pwarn("INCORRECT BLOCK COUNT I=%lu (%ld should be %ld)",
+                   inumber, dp->di_blocks, idesc->id_entryno);
+               if (preen)
+                       printf(" (CORRECTED)\n");
+               else if (reply("CORRECT") == 0)
+                       return;
+               dp = ginode(inumber);
+               dp->di_blocks = idesc->id_entryno;
+               inodirty();
+       }
+       return;
+unknown:
+       pfatal("UNKNOWN FILE TYPE I=%lu", inumber);
+       statemap[inumber] = FCLEAR;
+       if (reply("CLEAR") == 1) {
+               statemap[inumber] = USTATE;
+               dp = ginode(inumber);
+               clearinode(dp);
+               inodirty();
        }
        }
-       freeinodebuf();
 }
 
 pass1check(idesc)
 }
 
 pass1check(idesc)
@@ -180,8 +231,8 @@ pass1check(idesc)
 
        if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
                blkerror(idesc->id_number, "BAD", blkno);
 
        if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
                blkerror(idesc->id_number, "BAD", blkno);
-               if (++badblk >= MAXBAD) {
-                       pwarn("EXCESSIVE BAD BLKS I=%u",
+               if (badblk++ >= MAXBAD) {
+                       pwarn("EXCESSIVE BAD BLKS I=%lu",
                                idesc->id_number);
                        if (preen)
                                printf(" (SKIPPING)\n");
                                idesc->id_number);
                        if (preen)
                                printf(" (SKIPPING)\n");
@@ -198,8 +249,8 @@ pass1check(idesc)
                        setbmap(blkno);
                } else {
                        blkerror(idesc->id_number, "DUP", blkno);
                        setbmap(blkno);
                } else {
                        blkerror(idesc->id_number, "DUP", blkno);
-                       if (++dupblk >= MAXDUP) {
-                               pwarn("EXCESSIVE DUP BLKS I=%u",
+                       if (dupblk++ >= MAXDUP) {
+                               pwarn("EXCESSIVE DUP BLKS I=%lu",
                                        idesc->id_number);
                                if (preen)
                                        printf(" (SKIPPING)\n");
                                        idesc->id_number);
                                if (preen)
                                        printf(" (SKIPPING)\n");