fsck: Rework standalone fsck to use as native fsck
authorAlan Cox <alan@linux.intel.com>
Sun, 22 Oct 2017 18:32:41 +0000 (19:32 +0100)
committerAlan Cox <alan@linux.intel.com>
Sun, 22 Oct 2017 18:32:41 +0000 (19:32 +0100)
- Use bitmaps not bytemaps
- Support yes() properly

Not heavily tested yet!

Applications/util/fsck.c

index 5a43173..a27c140 100644 (file)
 #include <stdint.h>
 #include <fcntl.h>
 #include <unistd.h>
-#include "fsck.h"
+#include <ctype.h>
+
+typedef uint16_t       blkno_t;
+
+struct filesys {
+    uint16_t      s_mounted;
+    uint16_t      s_isize;
+    uint16_t      s_fsize;
+    int16_t       s_nfree;
+    blkno_t     s_free[50];
+    int16_t       s_ninode;
+    uint16_t      s_inode[50];
+    uint8_t       s_fmod;
+    uint8_t    s_timeh;        /* top bits of time */
+    uint32_t      s_time;
+    blkno_t     s_tfree;
+    uint16_t      s_tinode;
+    uint16_t      s_mntpt;
+};
+
+#define ROOTINODE 1
+#define SMOUNTED 12742   /* Magic number to specify mounted filesystem */
+#define SMOUNTED_WRONGENDIAN 50737   /* byteflipped */
+
+struct dinode {
+    uint16_t i_mode;
+    uint16_t i_nlink;
+    uint16_t i_uid;
+    uint16_t i_gid;
+    uint32_t    i_size;
+    uint32_t   i_atime;
+    uint32_t   i_mtime;
+    uint32_t   i_ctime;
+    blkno_t  i_addr[20];
+};               /* Exactly 64 bytes long! */
+
+#define F_REG   0100000
+#define F_DIR   040000
+#define F_PIPE  010000
+#define F_BDEV  060000
+#define F_CDEV  020000
+
+#define F_MASK  0170000
+
+struct direct {
+        uint16_t   d_ino;
+        char     d_name[30];
+};
 
 #define MAXDEPTH 20    /* Maximum depth of directory tree to search */
 
 /* This checks a filesystem */
 
-/* WARNING: This is a test version. Take a copy of the file system first.
+static int dev = 0;
+static struct filesys superblock;
+static int swizzling = 0;              /* Wrongendian ? */
+static long offset;
+static int dev_fd;
+static int dev_offset;
+
+static unsigned char *bitmap;
+static int16_t *linkmap;
+static char *daread(uint16_t blk);
+static void dwrite(uint16_t blk, char *addr);
+static void iread(uint16_t ino, struct dinode *buf);
+static void iwrite(uint16_t ino, struct dinode *buf);
+static void setblkno(struct dinode *ino, blkno_t num, blkno_t dnum);
+static void ckdir(uint16_t inum, uint16_t pnum, char *name);
+static void dirread(struct dinode *ino, uint16_t j, struct direct *dentry);
+static void dirwrite(struct dinode *ino, uint16_t j, struct direct *dentry);
+static void mkentry(uint16_t inum);
+static blkno_t blk_alloc0(struct filesys *filesys);
+static blkno_t getblkno(struct dinode *ino, blkno_t num);
+
+static void pass1(void);
+static void pass2(void);
+static void pass3(void);
+static void pass4(void);
+static void pass5(void);
+
+static int yes(void)
+{
+    static char buf[16];
+    do {
+        if (fgets(buf, 15, stdin) == NULL)
+            exit(1);
+        if (isupper(*buf))
+            *buf = tolower(*buf);
+    } while(*buf != 'n' && *buf != 'y');
+    return (*buf == 'y') ? 1 : 0;
+}
 
-   To fsck a file system it must be unmounted. To fsck the root fs boot with
-   the root fs read only, fsck, sync, reboot
-   
-   TODO: change the bitmap to use bits to save memory. 64K blocks is then 8K
-   of RAM which should mean we can fsck a full sized fs ok
- */
+static void bitset(uint16_t b)
+{
+    bitmap[b >> 3] |= (1 << (b & 7));
+}
+
+static void bitclear(uint16_t b)
+{
+    bitmap[b >> 3] &= ~(1 << (b & 7));
+}
 
-int dev = 0;
-struct filesys superblock;
-int swizzling = 0;             /* Wrongendian ? */
-long offset;
-int dev_fd;
-int dev_offset;
-
-char *bitmap;
-int16_t *linkmap;
-char *daread(uint16_t blk);
-void dwrite(uint16_t blk, char *addr);
-void iread(uint16_t ino, struct dinode *buf);
-void iwrite(uint16_t ino, struct dinode *buf);
-void setblkno(struct dinode *ino, blkno_t num, blkno_t dnum);
-void ckdir(uint16_t inum, uint16_t pnum, char *name);
-void dirread(struct dinode *ino, uint16_t j, struct direct *dentry);
-void dirwrite(struct dinode *ino, uint16_t j, struct direct *dentry);
-void mkentry(uint16_t inum);
-blkno_t getblkno(struct dinode *ino, blkno_t num);
-blkno_t blk_alloc0(struct filesys *filesys);
-
-void pass1(void);
-void pass2(void);
-void pass3(void);
-void pass4(void);
-void pass5(void);
-
-int yes(void)
+static int bittest(uint16_t b)
 {
-    printf("YESYES!\n");
-    return 1;
+    return (bitmap[b >> 3] & (1 << (b & 7))) ? 1 : 0;
+}
+
+static int fd_open(char *name)
+{
+       char *namecopy, *sd;
+       int bias = 0;
+
+       namecopy = strdup(name);
+       sd = index(namecopy, ':');
+       if (sd) {
+               *sd = 0;
+               sd++;
+               bias = atoi(sd);
+       }
+
+       printf("Opening %s (offset %d)\n", namecopy, bias);
+       dev_offset = bias;
+       dev_fd = open(namecopy, O_RDWR | O_CREAT, 0666);
+       free(namecopy);
+
+       if (dev_fd < 0)
+               return -1;
+       /* printf("fd=%d, dev_offset = %d\n", dev_fd, dev_offset); */
+       return 0;
 }
 
 
+static void panic(char *s)
+{
+       fprintf(stderr, "panic: %s\n", s);
+       exit(1);
+}
+
+static uint16_t swizzle16(uint32_t v)
+{
+        int top = v & 0xFFFF0000UL;
+       if (top && top != 0xFFFF0000) {
+               fprintf(stderr, "swizzle16 given a 32bit input\n");
+               exit(1);
+       }
+       if (swizzling)
+               return (v & 0xFF) << 8 | ((v & 0xFF00) >> 8);
+       else
+               return v;
+}
+
+static uint32_t swizzle32(uint32_t v)
+{
+       if (!swizzling)
+               return v;
+
+       return (v & 0xFF) << 24 | (v & 0xFF00) << 8 | (v & 0xFF0000) >> 8 |
+           (v & 0xFF000000) >> 24;
+}
+
 int main(int argc, char **argv)
 {
     char *buf;
@@ -96,9 +207,12 @@ int main(int argc, char **argv)
     if (!yes())
         exit(-1);
 
-    bitmap = calloc(swizzle16(superblock.s_fsize), sizeof(char));
+    bitmap = calloc((swizzle16(superblock.s_fsize) + 7) / 8, sizeof(char));
     linkmap = (int16_t *) calloc(8 * swizzle16(superblock.s_isize), sizeof(int16_t));
 
+    printf("Memory pool %d bytes\n",
+        16 * swizzle16(superblock.s_isize) +
+        swizzle16(superblock.s_fsize + 7) / 8);
     if (!bitmap || !linkmap) {
         fprintf(stderr, "Not enough memory.\n");
         exit(-1);
@@ -130,7 +244,7 @@ int main(int argc, char **argv)
  *  numbers in the inodes, and builds the block allocation map.
  */
 
-void pass1(void)
+static void pass1(void)
 {
     uint16_t n;
     struct dinode ino;
@@ -166,7 +280,7 @@ void pass1(void)
         ++icount;
         /* Check size */
 
-        if ((int32_t)swizzle32(ino.i_size) < 0) {
+        if (swizzle32(ino.i_size) < 0) {
             printf("Inode %d offset is negative with value of %ld. Fix? ",
                     n, (long)swizzle32(ino.i_size));
             if (yes()) {
@@ -198,7 +312,7 @@ void pass1(void)
                     }
                 }
                 if (ino.i_addr[b] != 0)
-                    bitmap[swizzle16(ino.i_addr[b])] = 1;
+                    bitset(swizzle16(ino.i_addr[b]));
             }
 
             /* Check the double indirect blocks */
@@ -216,7 +330,7 @@ void pass1(void)
                         }
                     }
                     if (buf[b] != 0)
-                        bitmap[swizzle16(buf[b])] = 1;
+                        bitset(swizzle16(buf[b]));
                 }
             }
             /* Check the rest */
@@ -232,7 +346,7 @@ void pass1(void)
                     }
                 }
                 if (b != 0)
-                    bitmap[b] = 1;
+                    bitset(b);
             }
         }
     }
@@ -250,12 +364,12 @@ void pass1(void)
 
 
 /* Clear inode free list, rebuild block free list using bit map. */
-
-void pass2(void)
+static void pass2(void)
 {
     blkno_t j;
     blkno_t oldtfree;
     int s;
+    int yes();
 
     printf("Rebuild free list? ");
     if (!yes())
@@ -273,7 +387,7 @@ void pass2(void)
     /* Free each block, building the free list */
 
     for (j = swizzle16(superblock.s_fsize) - 1; j >= swizzle16(superblock.s_isize); --j) {
-        if (bitmap[j] == 0) {
+        if (bittest(j) == 0) {
             if (swizzle16(superblock.s_nfree) == 50) {
                 dwrite(j, (char *) &superblock.s_nfree);
                 superblock.s_nfree = 0;
@@ -293,10 +407,8 @@ void pass2(void)
 
 }
 
-
 /* Pass 3 finds and fixes multiply allocated blocks. */
-
-void pass3(void)
+static void pass3(void)
 {
     uint16_t n;
     struct dinode ino;
@@ -307,7 +419,7 @@ void pass3(void)
     /*--- was blk_alloc ---*/
 
     for (b = swizzle16(superblock.s_isize); b < swizzle16(superblock.s_fsize); ++b)
-        bitmap[b] = 0;
+        bitclear(b);
 
     for (n = ROOTINODE; n < 8 * (swizzle16(superblock.s_isize) - 2); ++n) {
         iread(n, &ino);
@@ -320,7 +432,7 @@ void pass3(void)
 
         for (b = 18; b < 20; ++b) {
             if (ino.i_addr[b] != 0) {
-                if (bitmap[swizzle16(ino.i_addr[b])] != 0) {
+                if (bittest(swizzle16(ino.i_addr[b])) != 0) {
                     printf("Indirect block %d in inode %u value %u multiply allocated. Fix? ",
                             b, n, swizzle16(ino.i_addr[b]));
                     if (yes()) {
@@ -334,7 +446,7 @@ void pass3(void)
                         }
                     }
                 } else
-                    bitmap[swizzle16(ino.i_addr[b])] = 1;
+                    bitset(swizzle16(ino.i_addr[b]));
             }
         }
 
@@ -343,7 +455,7 @@ void pass3(void)
             b = getblkno(&ino, bno);
 
             if (b != 0) {
-                if (bitmap[b] != 0) {
+                if (bittest(b)) {
                     printf("Block %d in inode %u value %u multiply allocated. Fix? ",
                             bno, n, b);
                     if (yes()) {
@@ -357,7 +469,7 @@ void pass3(void)
                         }
                     }
                 } else
-                    bitmap[b] = 1;
+                    bitset(b);
             }
         }
 
@@ -365,14 +477,14 @@ void pass3(void)
 
 }
 
-int depth;
+static int depth;
 
 /*
  *  Pass 4 traverses the directory tree, fixing bad directory entries
  *  and finding the actual number of references to each inode.
  */
 
-void pass4(void)
+static void pass4(void)
 {
     depth = 0;
     linkmap[ROOTINODE] = 1;
@@ -383,13 +495,13 @@ void pass4(void)
 
 
 /* This recursively checks the directories */
-
-void ckdir(uint16_t inum, uint16_t pnum, char *name)
+static void ckdir(uint16_t inum, uint16_t pnum, char *name)
 {
     struct dinode ino;
     struct direct dentry;
     uint16_t j;
     int c;
+    uint8_t i;
     int nentries;
     char ename[150];
 
@@ -410,15 +522,9 @@ void ckdir(uint16_t inum, uint16_t pnum, char *name)
     for (j = 0; j < nentries; ++j) {
         dirread(&ino, j, &dentry);
 
-#if 1 /**HP**/
-        {
-            int i;
-
-            for (i = 0; i < 30; ++i) if (dentry.d_name[i] == '\0') break;
-            for (     ; i < 30; ++i) dentry.d_name[i] = '\0';
-            dirwrite(&ino, j, &dentry);
-        }
-#endif
+        for (i = 0; i < 30; ++i) if (dentry.d_name[i] == '\0') break;
+        for (     ; i < 30; ++i) dentry.d_name[i] = '\0';
+        dirwrite(&ino, j, &dentry);
 
         if (dentry.d_ino == 0)
             continue;
@@ -486,11 +592,11 @@ void ckdir(uint16_t inum, uint16_t pnum, char *name)
 
 
 /* Pass 5 compares the link counts found in pass 4 with the inodes. */
-
-void pass5(void)
+static void pass5(void)
 {
     uint16_t n;
     struct dinode ino;
+    int yes();
 
     for (n = ROOTINODE; n < 8 * (swizzle16(superblock.s_isize) - 2); ++n) {
         iread(n, &ino);
@@ -566,8 +672,7 @@ void pass5(void)
 
 
 /* This makes an entry in "lost+found" for inode n */
-
-void mkentry(uint16_t inum)
+static void mkentry(uint16_t inum)
 {
     struct dinode rootino;
     struct direct dentry;
@@ -586,15 +691,13 @@ void mkentry(uint16_t inum)
     printf("Sorry... No empty slots in root directory.\n");
 }
 
-/* Beginning of fsck1.c */
-
 /*
  *  Getblkno gets a pointer index, and a number of a block in the file.
  *  It returns the number of the block on the disk.  A value of zero
  *  means an unallocated block.
  */
 
-blkno_t getblkno(struct dinode *ino, blkno_t num)
+static blkno_t getblkno(struct dinode *ino, blkno_t num)
 {
     blkno_t indb;
     blkno_t dindb;
@@ -630,8 +733,7 @@ blkno_t getblkno(struct dinode *ino, blkno_t num)
  *  A return of zero means there were no blocks available to create an 
  *  indirect block. This should never happen in fsck.
  */
-
-void setblkno(struct dinode *ino, blkno_t num, blkno_t dnum)
+static void setblkno(struct dinode *ino, blkno_t num, blkno_t dnum)
 {
     blkno_t indb;
     blkno_t dindb;
@@ -672,8 +774,7 @@ void setblkno(struct dinode *ino, blkno_t num, blkno_t dnum)
  */
 
 /*--- was blk_alloc ---*/
-
-blkno_t blk_alloc0(struct filesys *filesys)
+static blkno_t blk_alloc0(struct filesys *filesys)
 {
     blkno_t newno;
     blkno_t *buf;
@@ -706,8 +807,7 @@ blkno_t blk_alloc0(struct filesys *filesys)
     return (newno);
 }
 
-
-char *daread(uint16_t blk)
+static char *daread(uint16_t blk)
 {
     static char da_buf[512];
     if (lseek(dev_fd, offset + blk * 512L, 0) == -1) {
@@ -721,8 +821,7 @@ char *daread(uint16_t blk)
     return da_buf;
 }
 
-
-void dwrite(uint16_t blk, char *addr)
+static void dwrite(uint16_t blk, char *addr)
 {
     if (lseek(dev_fd, offset + blk * 512L, 0) == -1) {
         perror("lseek");
@@ -734,8 +833,7 @@ void dwrite(uint16_t blk, char *addr)
     }
 }
 
-
-void iread(uint16_t ino, struct dinode *buf)
+static void iread(uint16_t ino, struct dinode *buf)
 {
     struct dinode *addr;
 
@@ -743,8 +841,7 @@ void iread(uint16_t ino, struct dinode *buf)
     bcopy((char *) &addr[ino & 7], (char *) buf, sizeof(struct dinode));
 }
 
-
-void iwrite(uint16_t ino, struct dinode *buf)
+static void iwrite(uint16_t ino, struct dinode *buf)
 {
     struct dinode *addr;
 
@@ -753,8 +850,7 @@ void iwrite(uint16_t ino, struct dinode *buf)
     dwrite((ino >> 3) + 2, (char *) addr);
 }
 
-
-void dirread(struct dinode *ino, uint16_t j, struct direct *dentry)
+static void dirread(struct dinode *ino, uint16_t j, struct direct *dentry)
 {
     blkno_t blkno;
     char *buf;
@@ -766,8 +862,7 @@ void dirread(struct dinode *ino, uint16_t j, struct direct *dentry)
     bcopy(buf + 32 * (j % 16), (char *) dentry, 32);
 }
 
-
-void dirwrite(struct dinode *ino, uint16_t j, struct direct *dentry)
+static void dirwrite(struct dinode *ino, uint16_t j, struct direct *dentry)
 {
     blkno_t blkno;
     char *buf;
@@ -780,55 +875,3 @@ void dirwrite(struct dinode *ino, uint16_t j, struct direct *dentry)
     dwrite(blkno, buf);
 }
 
-int fd_open(char *name)
-{
-       char *namecopy, *sd;
-       int bias = 0;
-
-       namecopy = strdup(name);
-       sd = index(namecopy, ':');
-       if (sd) {
-               *sd = 0;
-               sd++;
-               bias = atoi(sd);
-       }
-
-       printf("Opening %s (offset %d)\n", namecopy, bias);
-       dev_offset = bias;
-       dev_fd = open(namecopy, O_RDWR | O_CREAT, 0666);
-       free(namecopy);
-
-       if (dev_fd < 0)
-               return -1;
-       /* printf("fd=%d, dev_offset = %d\n", dev_fd, dev_offset); */
-       return 0;
-}
-
-
-void panic(char *s)
-{
-       fprintf(stderr, "panic: %s\n", s);
-       exit(1);
-}
-
-uint16_t swizzle16(uint32_t v)
-{
-        int top = v & 0xFFFF0000UL;
-       if (top && top != 0xFFFF0000) {
-               fprintf(stderr, "swizzle16 given a 32bit input\n");
-               exit(1);
-       }
-       if (swizzling)
-               return (v & 0xFF) << 8 | ((v & 0xFF00) >> 8);
-       else
-               return v;
-}
-
-uint32_t swizzle32(uint32_t v)
-{
-       if (!swizzling)
-               return v;
-
-       return (v & 0xFF) << 24 | (v & 0xFF00) << 8 | (v & 0xFF0000) >> 8 |
-           (v & 0xFF000000) >> 24;
-}