fsck: Ok I give up split fsck into a generic fsck and per fs helper
authorAlan Cox <alan@linux.intel.com>
Sat, 1 Sep 2018 23:33:22 +0000 (00:33 +0100)
committerAlan Cox <alan@linux.intel.com>
Sat, 1 Sep 2018 23:33:22 +0000 (00:33 +0100)
If need be we can actually split the fsck.fuzix helper into two pieces one
which exec's the other without that much extra disk I/O (one extra scan of
the inodes)

Applications/util/Makefile.6502
Applications/util/Makefile.68000
Applications/util/Makefile.6809
Applications/util/Makefile.pdp11
Applications/util/Makefile.z80
Applications/util/fsck-fuzix.c [new file with mode: 0644]
Applications/util/fsck.c
Applications/util/fuzix-util.pkg

index 4047d58..51e53ed 100644 (file)
@@ -70,6 +70,7 @@ SRCS  = banner.c \
        fgrep.c \
        free.c \
        fsck.c \
+       fsck-fuzix.c \
        grep.c \
        id.c \
        kbdrate.c \
index 7946714..b686837 100644 (file)
@@ -76,6 +76,7 @@ SRCS  = \
        fgrep.c \
        free.c \
        fsck.c \
+       fsck-fuzix.c \
        gptparse.c \
        grep.c \
        id.c \
index 6584c05..35b7a4f 100644 (file)
@@ -77,6 +77,7 @@ SRCS  = \
        fgrep.c \
        free.c \
        fsck.c \
+       fsck-fuzix.c \
        gptparse.c \
        grep.c \
        id.c \
index cd18a75..c906761 100644 (file)
@@ -1,4 +1,4 @@
-PLATFORM = 68000
+PLATFORM = pdp11
 CC = pdp11-aout-gcc
 ASM = pdp11-aout-as
 AR = pdp11-aout-ar
@@ -75,6 +75,7 @@ SRCS  = \
        fgrep.c \
        free.c \
        fsck.c \
+       fsck-fuzix.c \
        grep.c \
        id.c \
        kbdrate.c \
index bf4036b..b2cbcad 100644 (file)
@@ -65,6 +65,7 @@ SRCS  = banner.c \
        fgrep.c \
        free.c \
        fsck.c \
+       fsck-fuzix.c \
        gfxtest.c \
        gptparse.c \
        grep.c \
diff --git a/Applications/util/fsck-fuzix.c b/Applications/util/fsck-fuzix.c
new file mode 100644 (file)
index 0000000..41d2af9
--- /dev/null
@@ -0,0 +1,937 @@
+#include <stdio.h>
+#include <strings.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.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;
+#define FMOD_DIRTY     1
+#define FMOD_CLEAN     2
+    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 50737U   /* 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 */
+
+static const char no_more_free[] = { "Sorry... No more free blocks." };
+static const char block_multi[]= { "Block %u in inode %u value %u multiply allocated. Fix? " };
+static const char missing_ind_blk[] = { "Missing indirect block" };
+static const char no_memory[] = { "Not enough memory.\n" };
+static const char mbidir[] = { "Missing block in directory" };
+
+static int dev = 0;
+static struct filesys superblock;
+static int dev_fd;
+static int error;
+static int rootfs;
+static int aflag;
+
+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);
+
+/* Useful repeated values */
+static uint16_t max_inode;
+
+static int yes_noerror(void)
+{
+    static char buf[16];
+    fflush(stdout);
+    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;
+}
+
+static int yes(void) {
+    int ret = yes_noerror();
+    if (ret)
+        error |= 1;
+    else
+        error |= 4;
+    return ret;
+}
+
+static void bitset(uint16_t b)
+{
+    bitmap[b >> 3] |= (1 << (b & 7));
+}
+
+static void bitclear(uint16_t b)
+{
+    bitmap[b >> 3] &= ~(1 << (b & 7));
+}
+
+static int bittest(uint16_t b)
+{
+    return (bitmap[b >> 3] & (1 << (b & 7))) ? 1 : 0;
+}
+
+static void panic(char *s)
+{
+       fprintf(stderr, "panic: %s\n", s);
+       exit(error | 8);
+}
+
+static int fd_open(char *name)
+{
+       struct stat rootst;
+       struct stat work;
+
+       dev_fd = open(name, O_RDWR | O_CREAT, 0666);
+
+       if (dev_fd < 0)
+               return -1;
+
+       if (stat("/", &rootst) == -1)
+           panic("stat /");
+        if (fstat(dev_fd, &work) == -1)
+            panic("statfd");
+
+        if (rootst.st_dev == work.st_rdev) {
+            puts("Checking root file system.");
+            rootfs = 1;
+        }
+
+       return 0;
+}
+
+int perform_fsck(char *name)
+{
+    char *buf;
+
+    if (fd_open(name)){
+        puts("Cannot open file");
+        return 16;
+    }
+
+    buf = daread(1);
+    memcpy((char *) &superblock, buf, sizeof(struct filesys));
+
+    if (superblock.s_fmod == FMOD_DIRTY) {
+        puts("Filesystem was not cleanly unmounted.");
+        error |= 1;
+    }
+    else if (aflag)
+        return 0;
+
+    /* Verify the fsize and isize parameters */
+    if (superblock.s_mounted == SMOUNTED_WRONGENDIAN) {
+        panic("Reversed byte order.\n");
+    }
+
+    if (superblock.s_mounted != SMOUNTED) {
+        printf("Device %u has invalid magic number %u. Fix? ", dev, superblock.s_mounted);
+        if (!yes())
+            exit(error|32);
+        superblock.s_mounted = SMOUNTED;
+        dwrite((blkno_t) 1, (char *) &superblock);
+    }
+    printf("Device %u has fsize = %u and isize = %u. Continue? ",
+            dev, superblock.s_fsize, superblock.s_isize);
+    if (!yes_noerror())
+        return (error |= 32);
+
+    linkmap = (int16_t *) calloc(8 * superblock.s_isize, sizeof(int16_t));
+    bitmap = calloc((superblock.s_fsize + 7UL) / 8, sizeof(char));
+
+    if (!bitmap || !linkmap) {
+        fputs(no_memory, stderr);
+        return(error |= 8);
+    }
+
+    max_inode = 8 * (superblock.s_isize - 2);
+
+    puts("Pass 1: Checking inodes...");
+    pass1();
+
+    puts("Pass 2: Rebuilding free list...");
+    pass2();
+
+    puts("Pass 3: Checking block allocation...");
+
+    pass3();
+
+    /* We don't need the bitmap but we do need space for path buffers */
+    free(bitmap);
+
+    puts("Pass 4: Checking directory entries...");
+    pass4();
+
+    puts("Pass 5: Checking link counts...");
+    pass5();
+
+    /* If we fixed things, and no errors were left uncorrected */
+    if ((error & 69) == 1) {   /* 64 4 1 moust be 1 */
+        superblock.s_fmod = FMOD_CLEAN;
+        dwrite((blkno_t) 1, (char *) &superblock);
+        if (rootfs) {
+            error |= 2;
+            puts("**** Root filesystem was modified, immediate reboot required.");
+            sleep(5);
+            /* Sync it all out and reboot */
+            uadmin(A_REBOOT, 0, 0);
+        }
+    }
+    free(linkmap);
+    close(dev_fd);
+    return error;
+}
+
+int main(int argc, char *argv[])
+{
+    if (argc == 3 && strcmp(argv[1], "-a") == 0) {
+        aflag = 1;
+        argv++;
+    } else if(argc != 2) {
+        fputs("syntax: fsck-fuzix [-a] [devfile]\n", stderr);
+        return 16;
+    }
+    perform_fsck(argv[1]);
+    exit(error);
+}
+
+
+
+/*
+ *  Pass 1 checks each inode independently for validity, zaps bad block
+ *  numbers in the inodes, and builds the block allocation map.
+ */
+
+static void pass1(void)
+{
+    uint16_t n;
+    struct dinode ino;
+    uint16_t mode;
+    blkno_t b;
+    blkno_t bno;
+    uint16_t icount;
+    blkno_t *buf;
+    uint32_t bmax;
+
+    icount = 0;
+
+    /* Consider rescannign this basic loop in pass4 so that we don't have
+       to keep both bitmap and linkmap around at the same time */
+    for (n = ROOTINODE; n < max_inode; ++n) {
+        iread(n, &ino);
+        linkmap[n] = -1;
+        if (ino.i_mode == 0)
+            continue;
+
+        mode = ino.i_mode & F_MASK;
+        /* FIXME: named pipes.. */
+
+        /* Check mode */
+        if (mode != F_REG && mode != F_DIR && mode != F_BDEV && mode != F_CDEV) {
+            printf("Inode %u with mode 0%o is not of correct type. Zap? ",
+                    n, ino.i_mode);
+            if (yes()) {
+                ino.i_mode = 0;
+                ino.i_nlink = 0;
+                iwrite(n, &ino);
+                continue;
+            }
+        }
+        linkmap[n] = 0;
+        ++icount;
+        /* Check size */
+
+        if (ino.i_size < 0) {
+            printf("Inode %u offset is negative with value of %ld. Fix? ",
+                    n, ino.i_size);
+            if (yes()) {
+                ino.i_size = 0;
+                iwrite(n, &ino);
+            }
+        }
+        /* Check blocks and build free block map */
+        if (mode == F_REG || mode == F_DIR) {
+            /* Check singly indirect blocks */
+
+            for (b = 18; b < 20; ++b) {
+                if (ino.i_addr[b] != 0 && 
+                    (ino.i_addr[b] < superblock.s_isize ||
+                            ino.i_addr[b] >= superblock.s_fsize)) {
+                    printf("Inode %u singly ind. blk %u out of range, val = %u. Zap? ",
+                            n, b, ino.i_addr[b]);
+                    if (yes()) {
+                        ino.i_addr[b] = 0;
+                        iwrite(n, &ino);
+                    }
+                }
+                if (ino.i_addr[b] != 0 && ino.i_size < 18*512) {
+                    printf("Inode %u singly ind. blk %u past end of file, val = %u. Zap? ",
+                            n, b, ino.i_addr[b]);
+                    if (yes()) {
+                        ino.i_addr[b] = 0;
+                        iwrite(n, &ino);
+                    }
+                }
+                if (ino.i_addr[b] != 0)
+                    bitset(ino.i_addr[b]);
+            }
+
+            /* Check the double indirect blocks */
+            if (ino.i_addr[19] != 0) {
+                buf = (blkno_t *) daread(ino.i_addr[19]);
+                for (b = 0; b < 256; ++b) {
+                    if (buf[b] != 0 && (buf[b] < superblock.s_isize ||
+                                buf[b] >= superblock.s_fsize)) {
+                        printf("Inode %u doubly ind. blk %u is out of range, val = %u. Zap? ",
+                                n, b, buf[b]);
+                        /* 1.4.98 - line split.  HFB */
+                        if (yes()) {
+                            buf[b] = 0;
+                            dwrite(b, (char *) buf);
+                        }
+                    }
+                    if (buf[b] != 0)
+                        bitset(buf[b]);
+                }
+            }
+            /* Check the rest */
+            bmax = ino.i_size/512;
+            for (bno = 0; bno <= bmax ; ++bno) {
+                b = getblkno(&ino, bno);
+
+                if (b != 0 && (b < superblock.s_isize || b >= superblock.s_fsize)) {
+                    printf("Inode %u block %u out of range, val = %u. Zap? ",
+                            n, bno, b);
+                    if (yes()) {
+                        setblkno(&ino, bno, 0);
+                        iwrite(n, &ino);
+                    }
+                }
+                if (b != 0)
+                    bitset(b);
+            }
+        }
+    }
+    /* Fix free inode count in superblock block */
+    icount = max_inode - ROOTINODE - icount;
+    if (superblock.s_tinode != icount) {
+        printf("Free inode count in superblock is %u, should be %u. Fix? ",
+                superblock.s_tinode, icount);
+
+        if (yes()) {
+            superblock.s_tinode = icount;
+            dwrite((blkno_t) 1, (char *) &superblock);
+        }
+    }
+}
+
+
+/* Clear inode free list, rebuild block free list using bit map. */
+static void pass2(void)
+{
+    blkno_t j;
+    blkno_t oldtfree;
+    uint16_t imax = superblock.s_isize;
+
+    printf("Rebuild free list? ");
+    if (!yes_noerror())
+        return;
+
+    error |= 1;
+    oldtfree = superblock.s_tfree;
+
+    /* Initialize the superblock-block */
+
+    superblock.s_ninode = 0;
+    superblock.s_nfree = 1;
+    superblock.s_free[0] = 0;
+    superblock.s_tfree = 0;
+
+    /* Free each block, building the free list */
+
+    for (j = superblock.s_fsize - 1; j >= imax; --j) {
+        if (bittest(j) == 0) {
+            if (superblock.s_nfree == 50) {
+                dwrite(j, (char *) &superblock.s_nfree);
+                superblock.s_nfree = 0;
+            }
+            superblock.s_tfree++;
+            superblock.s_free[superblock.s_nfree++] = j;
+        }
+    }
+
+    dwrite((blkno_t) 1, (char *) &superblock);
+
+    if (oldtfree != superblock.s_tfree)
+        printf("s_tfree was changed to %u from %u.\n",
+                superblock.s_tfree, oldtfree);
+
+}
+
+/* Pass 3 finds and fixes multiply allocated blocks. */
+static void pass3(void)
+{
+    uint16_t n;
+    struct dinode ino;
+    uint16_t mode;
+    blkno_t b;
+    blkno_t bno;
+    blkno_t newno;
+    uint16_t bmax = superblock.s_fsize;
+    uint32_t nmax;
+    /*--- was blk_alloc ---*/
+
+    /* FIXME:
+        1. Set the bits below s_isize
+     */
+    /* FIXME: performance */
+    for (b = superblock.s_isize; b < bmax; ++b)
+        bitclear(b);
+
+    for (n = ROOTINODE; n < max_inode; ++n) {
+        iread(n, &ino);
+
+        mode = ino.i_mode & F_MASK;
+        if (mode != F_REG && mode != F_DIR)
+            continue;
+
+        /* Check singly indirect blocks */
+
+        for (b = 18; b < 20; ++b) {
+            if (ino.i_addr[b] != 0) {
+                if (bittest(ino.i_addr[b]) != 0) {
+                    puts("Indirect b");
+                    printf(block_multi + 1, b, n, ino.i_addr[b]);
+                    if (yes()) {
+                        newno = blk_alloc0(&superblock);
+                        if (newno == 0) {
+                            puts(no_more_free);
+                            error |= 4;
+                        } else {
+                            dwrite(newno, daread(ino.i_addr[b]));
+                            ino.i_addr[b] = newno;
+                            iwrite(n, &ino);
+                            error |= 64;
+                        }
+                    }
+                } else
+                    bitset(ino.i_addr[b]);
+            }
+        }
+
+        /* Check the rest */
+        nmax = ino.i_size/512;
+        for (bno = 0; bno <= nmax; ++bno) {
+            b = getblkno(&ino, bno);
+
+            if (b != 0) {
+                if (bittest(b)) {
+                    printf(block_multi,
+                            bno, n, b);
+                    if (yes()) {
+                        newno = blk_alloc0(&superblock);
+                        if (newno == 0) {
+                            puts(no_more_free);
+                            error |= 4;
+                        } else {
+                            dwrite(newno, daread(b));
+                            setblkno(&ino, bno, newno);
+                            iwrite(n, &ino);
+                            error |= 64;
+                        }
+                    }
+                } else
+                    bitset(b);
+            }
+        }
+
+    }
+
+}
+
+static int depth;
+
+/*
+ *  Pass 4 traverses the directory tree, fixing bad directory entries
+ *  and finding the actual number of references to each inode.
+ */
+
+static void pass4(void)
+{
+    depth = 0;
+    linkmap[ROOTINODE] = 1;
+    ckdir(ROOTINODE, ROOTINODE, "/");
+//if (depth != 0)
+//      panic("Inconsistent depth");
+}
+
+
+/* This recursively checks the directories */
+
+static void ckdir(uint16_t inum, uint16_t pnum, char *name)
+{
+    struct dinode ino;
+    /* We can keep this off the stack, we'd really like to keep the inode
+       off it too but that would thrash the disk horribly */
+    static struct direct dentry;
+    uint16_t j;
+    int c;
+    uint8_t i;
+    int nentries;
+    char *ename;
+
+    iread(inum, &ino);
+    if ((ino.i_mode & F_MASK) != F_DIR)
+        return;
+    ++depth;
+
+    if (((uint8_t)ino.i_size) & 31) {
+        printf("Directory inode %u has improper length. Fix? ", inum);
+        if (yes()) {
+            ino.i_size &= ~0x1fUL;
+            iwrite(inum, &ino);
+            error |= 64;
+        }
+    }
+    nentries = ino.i_size/32;
+
+    /* Each iteration we begin with a new ino/dentry. Each recursion we
+       destroy them. Be careful */
+    for (j = 0; j < nentries; ++j) {
+        dirread(&ino, j, &dentry);
+
+        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;
+
+        if (dentry.d_ino < ROOTINODE ||
+                dentry.d_ino >= max_inode) {
+            printf("Directory entry %s%-1.30s has out-of-range inode %u. Zap? ",
+                    name, dentry.d_name, dentry.d_ino);
+            if (yes()) {
+                dentry.d_ino = 0;
+                dentry.d_name[0] = '\0';
+                dirwrite(&ino, j, &dentry);
+                error |= 64;
+                continue;
+            }
+        }
+        if (dentry.d_ino && linkmap[dentry.d_ino] == -1) {
+            printf("Directory entry %s%-1.30s points to bogus inode %u. Zap? ",
+                    name, dentry.d_name, dentry.d_ino);
+            if (yes()) {
+                dentry.d_ino = 0;
+                dentry.d_name[0] = '\0';
+                dirwrite(&ino, j, &dentry);
+                continue;
+            }
+        }
+        ++linkmap[dentry.d_ino];
+
+        for (c = 0; c < 30 && dentry.d_name[c]; ++c) {
+            if (dentry.d_name[c] == '/') {
+                printf("Directory entry %s%-1.30s contains slash. Fix? ",
+                        name, dentry.d_name);
+                if (yes()) {
+                    dentry.d_name[c] = 'X';
+                    dirwrite(&ino, j, &dentry);
+                }
+            }
+        }
+
+        if (strncmp(dentry.d_name, ".", 30) == 0 && dentry.d_ino != inum) {
+            printf("Dot entry %s%-1.30s points to wrong place. Fix? ",
+                    name, dentry.d_name);
+            if (yes()) {
+                dentry.d_ino = inum;
+                dirwrite(&ino, j, &dentry);
+                error |= 64;
+            }
+        }
+        if (strncmp(dentry.d_name, "..", 30) == 0 && dentry.d_ino != pnum) {
+            printf("DotDot entry %s%-1.30s points to wrong place. Fix? ",
+                    name, dentry.d_name);
+            if (yes()) {
+                dentry.d_ino = pnum;
+                dirwrite(&ino, j, &dentry);
+                error |= 64;
+            }
+        }
+        if (dentry.d_ino != pnum &&
+                dentry.d_ino != inum && depth < MAXDEPTH) {
+            /* This is a bad approach. We ought to have some kind of
+               growing buffer, but our realloc will end up chopping up
+               the pool and stuff I think. sbrk() doesn't help as we've
+               got lots of memory in the pool from freeing bitmap that
+               won't go back FIXME */
+            ename = malloc(strlen(name) + strlen(dentry.d_name) + 2);
+            if (ename == NULL) {
+                fprintf(stderr, "Not enough memory.\n");
+                exit(error |= 8);
+            }
+            strcpy(ename, name);
+            strcat(ename, dentry.d_name);
+            strcat(ename, "/");
+            ckdir(dentry.d_ino, inum, ename);
+            free(ename);
+        }
+        /* dentry and dino are not valid any more */
+    }
+    --depth;
+}
+
+static void linkmaperr(void)
+{
+    panic("linkmap");
+}
+
+/* Pass 5 compares the link counts found in pass 4 with the inodes. */
+static void pass5(void)
+{
+    uint16_t n;
+    struct dinode ino;
+
+    for (n = ROOTINODE; n < max_inode; ++n) {
+        iread(n, &ino);
+
+        if (ino.i_mode == 0) {
+            if (linkmap[n] != -1)
+                linkmaperr();
+            continue;
+        }
+
+        if (linkmap[n] == -1 && ino.i_mode != 0)
+            linkmaperr();
+
+        if (linkmap[n] > 0 && ino.i_nlink != linkmap[n]) {
+            printf("Inode %u has link count %u should be %u. Fix? ",
+                    n, ino.i_nlink, linkmap[n]);
+            if (yes()) {
+                ino.i_nlink = linkmap[n];
+                iwrite(n, &ino);
+            }
+        }
+
+        if (linkmap[n] == 0) {
+            if ((ino.i_mode & F_MASK) == F_BDEV ||
+                    (ino.i_mode & F_MASK) == F_CDEV ||
+                    (ino.i_size == 0)) {
+                printf("Useless inode %u with mode 0%o has become detached. Link count is %u. Zap? ",
+                        n, ino.i_mode, ino.i_nlink);
+                if (yes()) {
+                    ino.i_nlink = 0;
+                    ino.i_mode = 0;
+                    iwrite(n, &ino);
+                    superblock.s_tinode++;
+                    dwrite((blkno_t) 1, (char *) &superblock);
+                    error |= 64;
+                }
+            } else {
+                printf("Inode %u has become detached. Link count is %u. ",
+                        n, ino.i_nlink);
+                puts(ino.i_nlink ? "Zap? " : "Fix? ");
+                if (yes()) {
+                    error |= 64;
+                    if (ino.i_nlink == 0) {
+                        ino.i_nlink = 0;
+                        ino.i_mode = 0;
+                        iwrite(n, &ino);
+                        superblock.s_tinode++;
+                        dwrite((blkno_t) 1, (char *) &superblock);
+                    } else {
+                        ino.i_nlink = 1;
+                        iwrite(n, &ino);
+                        mkentry(n);
+                    }
+                }
+            }
+        }
+
+    }
+}
+
+
+/* This makes an entry in "lost+found" for inode n */
+static void mkentry(uint16_t inum)
+{
+    struct dinode rootino;
+    struct direct dentry;
+    uint16_t d;
+    uint32_t dmax;
+
+    iread(ROOTINODE, &rootino);
+    dmax = rootino.i_size/32;
+    for (d = 0; d < dmax; ++d) {
+        dirread(&rootino, d, &dentry);
+        if (dentry.d_ino == 0 && dentry.d_name[0] == '\0') {
+            dentry.d_ino = inum;
+            sprintf(dentry.d_name, "l+f%u", inum);
+            dirwrite(&rootino, d, &dentry);
+            return;
+        }
+    }
+    puts("Sorry... No empty slots in root directory.");
+    error |= 4;
+}
+
+/*
+ *  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.
+ */
+
+static blkno_t getblkno(struct dinode *ino, blkno_t num)
+{
+    blkno_t indb;
+    blkno_t dindb;
+    blkno_t *buf;
+
+    if (num < 18)              /* Direct block */
+        return ino->i_addr[num];
+    if (num < 256 + 18) {      /* Single indirect */
+        indb = ino->i_addr[18];
+        if (indb == 0)
+            return 0;
+        buf = (blkno_t *) daread(indb);
+        return buf[num - 18];
+    }
+    /* Double indirect */
+    indb = ino->i_addr[19];
+    if (indb == 0)
+        return 0;
+
+    buf = (blkno_t *) daread(indb);
+
+    dindb = buf[(num - (18 + 256)) >> 8];
+    if (dindb == 0)
+        return 0;
+    buf = (blkno_t *) daread(dindb);
+    return buf[(num - (18 + 256)) & 0x00ff];
+}
+
+
+/*
+ *  Setblkno sets the given block number of the given file to the given
+ *  disk block number, possibly creating or modifiying the indirect blocks.
+ *  A return of zero means there were no blocks available to create an 
+ *  indirect block. This should never happen in fsck.
+ */
+static void setblkno(struct dinode *ino, blkno_t num, blkno_t dnum)
+{
+    blkno_t indb;
+    blkno_t dindb;
+    blkno_t *buf;
+    /*--    char *zerobuf();--*/
+
+
+    if (num < 18) {                    /* Direct block */
+        ino->i_addr[num] = dnum;
+    } else if (num < 256 + 18) {       /* Single indirect */
+        indb = ino->i_addr[18];
+        if (indb == 0)
+            panic(missing_ind_blk);
+
+        buf = (blkno_t *) daread(indb);
+        buf[num - 18] = dnum;
+        dwrite(indb, (char *) buf);
+    } else {                           /* Double indirect */
+        indb = ino->i_addr[19];
+        if (indb == 0)
+            panic(missing_ind_blk);
+
+        buf = (blkno_t *) daread(indb);
+        dindb = buf[(num - (18 + 256)) >> 8];
+        if (dindb == 0)
+            panic(missing_ind_blk);
+
+        buf = (blkno_t *) daread(dindb);
+        buf[(num - (18 + 256)) & 0x00ff] = num;
+        dwrite(indb, (char *) buf);
+    }
+}
+
+
+/*
+ *  blk_alloc0 allocates an unused block.
+ *  A returned block number of zero means no more blocks.
+ */
+
+/*--- was blk_alloc ---*/
+static blkno_t blk_alloc0(struct filesys *filesys)
+{
+    blkno_t newno;
+    blkno_t *buf;
+    int16_t j;
+
+    newno = filesys->s_free[--filesys->s_nfree];
+    if (!newno) {
+        filesys->s_nfree++;
+        return 0;
+    }
+
+    /* See if we must refill the s_free array */
+
+    if (!filesys->s_nfree) {
+        buf = (blkno_t *) daread(newno);
+        filesys->s_nfree = buf[0];
+        for (j = 0; j < 50; j++) {
+            filesys->s_free[j] = buf[j + 1];
+        }
+    }
+
+    filesys->s_tfree--;
+
+    if (newno < filesys->s_isize || newno >= filesys->s_fsize) {
+        puts("Free list is corrupt.  Did you rebuild it?");
+        return (0);
+    }
+    dwrite((blkno_t) 1, (char *) filesys);
+    return (newno);
+}
+
+
+static uint16_t lblk = 0;
+
+static char *daread(uint16_t blk)
+{
+    static char da_buf[512];
+
+    if (blk == 0)
+        panic("rb0");
+
+    if (blk == lblk)
+        return da_buf;
+
+    if (lseek(dev_fd, blk * 512L, 0) == -1) {
+        perror("lseek");
+        exit(1);
+    }
+    if(read(dev_fd, da_buf, 512) != 512) {
+        perror("read");
+        exit(1);
+    }
+    lblk = blk;
+    return da_buf;
+}
+
+static void dwrite(uint16_t blk, char *addr)
+{
+    if (lseek(dev_fd, blk * 512L, 0) == -1) {
+        perror("lseek");
+        exit(1);
+    }
+    if(write(dev_fd, addr, 512) != 512) {
+        perror("write");
+        exit(1);
+    }
+    lblk = 0;
+}
+
+static void iread(uint16_t ino, struct dinode *buf)
+{
+    struct dinode *addr;
+
+    addr = (struct dinode *) daread((ino >> 3) + 2);
+    memcpy(buf, &addr[ino & 7], sizeof(struct dinode));
+}
+
+static void iwrite(uint16_t ino, struct dinode *buf)
+{
+    struct dinode *addr;
+
+    addr = (struct dinode *) daread((ino >> 3) + 2);
+    memcpy(&addr[ino & 7], buf, sizeof(struct dinode));
+    dwrite((ino >> 3) + 2, (char *) addr);
+}
+
+static void dirread(struct dinode *ino, uint16_t j, struct direct *dentry)
+{
+    blkno_t blkno;
+    char *buf;
+
+    blkno = getblkno(ino, (blkno_t) j / 16);
+    if (blkno == 0)
+        panic(mbidir);
+    buf = daread(blkno);
+    memcpy(dentry, buf + 32 * (j % 16), 32);
+}
+
+static void dirwrite(struct dinode *ino, uint16_t j, struct direct *dentry)
+{
+    blkno_t blkno;
+    char *buf;
+
+    blkno = getblkno(ino, (blkno_t) j / 16);
+    if (blkno == 0)
+        panic(mbidir);
+    buf = daread(blkno);
+    memcpy(buf + 32 * (j % 16), dentry, 32);
+    dwrite(blkno, buf);
+}
index cfe0e4a..d44d869 100644 (file)
 #include <stdio.h>
-#include <strings.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdint.h>
-#include <fcntl.h>
 #include <unistd.h>
 #include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <mntent.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.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;
-#define FMOD_DIRTY     1
-#define FMOD_CLEAN     2
-    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 50737U   /* 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 */
-
-static const char no_more_free[] = { "Sorry... No more free blocks." };
-static const char block_multi[]= { "Block %u in inode %u value %u multiply allocated. Fix? " };
-static const char missing_ind_blk[] = { "Missing indirect block" };
-static const char no_memory[] = { "Not enough memory.\n" };
-static const char fstab[] = { "/etc/fstab" };
-static const char rstr[] = { "r" };
-static int dev = 0;
-static struct filesys superblock;
-static int dev_fd;
 static int error;
-static int rootfs;
 static int aflag;
 
-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);
-
-/* Useful repeated values */
-static uint16_t max_inode;
-
-static int yes_noerror(void)
-{
-    static char buf[16];
-    fflush(stdout);
-    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;
-}
-
-static int yes(void) {
-    int ret = yes_noerror();
-    if (ret)
-        error |= 1;
-    else
-        error |= 4;
-    return ret;
-}
-
-static void bitset(uint16_t b)
-{
-    bitmap[b >> 3] |= (1 << (b & 7));
-}
-
-static void bitclear(uint16_t b)
-{
-    bitmap[b >> 3] &= ~(1 << (b & 7));
-}
-
-static int bittest(uint16_t b)
-{
-    return (bitmap[b >> 3] & (1 << (b & 7))) ? 1 : 0;
-}
-
 static void panic(char *s)
 {
        fprintf(stderr, "panic: %s\n", s);
-       exit(error | 8);
+       exit(1);
 }
 
 const char *mntpoint(const char *mount)
 {
-    FILE *fp;
-    struct mntent *mnt;
+       FILE *fp;
+       struct mntent *mnt;
 
-    fp = setmntent(fstab, rstr);
-    if (fp) {
-        while (mnt = getmntent(fp)) {
-            if (strcmp(mnt->mnt_dir, mount) == 0) {
-                endmntent(fp);
-                return mnt->mnt_fsname;
-            }
-        }
-        endmntent(fp);
-    }
-    return NULL;
+       fp = setmntent("/etc/fstab", "r");
+       if (fp) {
+               while (mnt = getmntent(fp)) {
+                       if (strcmp(mnt->mnt_dir, mount) == 0) {
+                               endmntent(fp);
+                               return mnt->mnt_fsname;
+                       }
+               }
+               endmntent(fp);
+       }
+       return NULL;
 }
 
-static int fd_open(char *name, int search)
+static int perform_fsck_iter(const char *path, int search)
 {
+       pid_t pid;
+       int st;
        const char *p;
-       struct stat rootst;
-       struct stat work;
-
        if (search) {
-           p = mntpoint(name);
-            if (p)
-               name = (char *)p;
-        }
-
-       dev_fd = open(name, O_RDWR | O_CREAT, 0666);
-
-       if (dev_fd < 0)
-               return -1;
-
-       if (stat("/", &rootst) == -1)
-           panic("stat /");
-        if (fstat(dev_fd, &work) == -1)
-            panic("statfd");
-
-        if (rootst.st_dev == work.st_rdev) {
-            puts("Checking root file system.");
-            rootfs = 1;
-        }
-
-       return 0;
-}
-
-int perform_fsck_iter(char *name, int search)
-{
-    char *buf;
-
-    if (fd_open(name, search)){
-        puts("Cannot open file");
-        return 16;
-    }
-
-    buf = daread(1);
-    memcpy((char *) &superblock, buf, sizeof(struct filesys));
-
-    if (superblock.s_fmod == FMOD_DIRTY) {
-        puts("Filesystem was not cleanly unmounted.");
-        error |= 1;
-    }
-    else if (aflag)
-        return 0;
-
-    /* Verify the fsize and isize parameters */
-    if (superblock.s_mounted == SMOUNTED_WRONGENDIAN) {
-        panic("Reversed byte order.\n");
-    }
-
-    if (superblock.s_mounted != SMOUNTED) {
-        printf("Device %u has invalid magic number %u. Fix? ", dev, superblock.s_mounted);
-        if (!yes())
-            exit(error|32);
-        superblock.s_mounted = SMOUNTED;
-        dwrite((blkno_t) 1, (char *) &superblock);
-    }
-    printf("Device %u has fsize = %u and isize = %u. Continue? ",
-            dev, superblock.s_fsize, superblock.s_isize);
-    if (!yes_noerror())
-        return (error |= 32);
-
-    bitmap = calloc((superblock.s_fsize + 7UL) / 8, sizeof(char));
-    linkmap = (int16_t *) calloc(8 * superblock.s_isize, sizeof(int16_t));
-
-    if (!bitmap || !linkmap) {
-        fputs(no_memory, stderr);
-        return(error |= 8);
-    }
-
-    max_inode = 8 * (superblock.s_isize - 2);
-
-    puts("Pass 1: Checking inodes...");
-    pass1();
-
-    puts("Pass 2: Rebuilding free list...");
-    pass2();
-
-    puts("Pass 3: Checking block allocation...");
-    pass3();
-
-    /* We don't need the bitmap but we do need space for path buffers */
-    free(bitmap);
-
-    puts("Pass 4: Checking directory entries...");
-    pass4();
-
-    puts("Pass 5: Checking link counts...");
-    pass5();
-
-    /* If we fixed things, and no errors were left uncorrected */
-    if ((error & 69) == 1) {   /* 64 4 1 moust be 1 */
-        superblock.s_fmod = FMOD_CLEAN;
-        dwrite((blkno_t) 1, (char *) &superblock);
-        if (rootfs) {
-            error |= 2;
-            puts("**** Root filesystem was modified, immediate reboot required.");
-            sleep(5);
-            /* Sync it all out and reboot */
-            uadmin(A_REBOOT, 0, 0);
-        }
-    }
-    free(linkmap);
-    close(dev_fd);
-    return error;
+               p = mntpoint(path);
+               if (p)
+                       path = p;
+       }
+       fflush(stdout);
+       switch (pid = fork()) {
+       case -1:
+               perror("fork");
+               exit(127);
+       case 0:
+               /* FIXME: one day bigger boxes will care about the fs type */
+               if (aflag == 0)
+                       execl("/bin/fsck-fuzix", "fsck-fuzix", path, NULL);
+               else
+                       execl("/bin/fsck-fuzix", "fsck-fuzix", "-a", path, NULL);
+               perror("fsck-fuzix");
+               exit(1);
+       default:
+               while (waitpid(pid, &st, 0) == -1) {
+                       if (errno == ECHILD) {
+                               perror("waitpid");
+                               exit(1);
+                       }
+               }
+               if (WIFEXITED(st))
+                       return WEXITSTATUS(st);
+               fprintf(stderr, "child process failed %d.\n", WTERMSIG(st));
+               exit(1);
+       }
 }
 
 int perform_fsck(char *name, int search)
 {
-    int r;
-    while((r = perform_fsck_iter(name, search)) & 64)
-        puts("Restarting fsck.\n");
-    return r;
-}
-
-int main(int argc, char *argv[])
-{
-    struct mntent *mnt;
-    if (argc > 1 && strcmp(argv[1],"-a") == 0) {
-        argc--;
-        argv++;
-        aflag = 1;
-    }
-
-    if (argc == 1 && aflag) {
-        FILE *fp = setmntent(fstab, rstr);
-        if (fp == NULL) {
-            perror(fstab);
-            exit(1);
-        }
-        while((mnt = getmntent(fp)) != NULL) {
-            if (perform_fsck(mnt->mnt_fsname, 0))
-                exit(error);
-        }
-        endmntent(fp);
-    } else {
-        if(argc != 2) {
-            fputs("syntax: fsck[-a] [devfile]\n", stderr);
-            return 16;
-        }
-        perform_fsck(argv[1], 1);
-    }
-    puts("Done.");
-    exit(error);
+       int r;
+       while ((r = perform_fsck_iter(name, search)) & 64)
+               puts("Restarting fsck.\n");
+       return r;
 }
 
 
-
-/*
- *  Pass 1 checks each inode independently for validity, zaps bad block
- *  numbers in the inodes, and builds the block allocation map.
- */
-
-static void pass1(void)
-{
-    uint16_t n;
-    struct dinode ino;
-    uint16_t mode;
-    blkno_t b;
-    blkno_t bno;
-    uint16_t icount;
-    blkno_t *buf;
-    uint32_t bmax;
-
-    icount = 0;
-
-    /* Consider rescannign this basic loop in pass4 so that we don't have
-       to keep both bitmap and linkmap around at the same time */
-    for (n = ROOTINODE; n < max_inode; ++n) {
-        iread(n, &ino);
-        linkmap[n] = -1;
-        if (ino.i_mode == 0)
-            continue;
-
-        mode = ino.i_mode & F_MASK;
-        /* FIXME: named pipes.. */
-
-        /* Check mode */
-        if (mode != F_REG && mode != F_DIR && mode != F_BDEV && mode != F_CDEV) {
-            printf("Inode %u with mode 0%o is not of correct type. Zap? ",
-                    n, ino.i_mode);
-            if (yes()) {
-                ino.i_mode = 0;
-                ino.i_nlink = 0;
-                iwrite(n, &ino);
-                continue;
-            }
-        }
-        linkmap[n] = 0;
-        ++icount;
-        /* Check size */
-
-        if (ino.i_size < 0) {
-            printf("Inode %u offset is negative with value of %ld. Fix? ",
-                    n, ino.i_size);
-            if (yes()) {
-                ino.i_size = 0;
-                iwrite(n, &ino);
-            }
-        }
-        /* Check blocks and build free block map */
-        if (mode == F_REG || mode == F_DIR) {
-            /* Check singly indirect blocks */
-
-            for (b = 18; b < 20; ++b) {
-                if (ino.i_addr[b] != 0 && 
-                    (ino.i_addr[b] < superblock.s_isize ||
-                            ino.i_addr[b] >= superblock.s_fsize)) {
-                    printf("Inode %u singly ind. blk %u out of range, val = %u. Zap? ",
-                            n, b, ino.i_addr[b]);
-                    if (yes()) {
-                        ino.i_addr[b] = 0;
-                        iwrite(n, &ino);
-                    }
-                }
-                if (ino.i_addr[b] != 0 && ino.i_size < 18*512) {
-                    printf("Inode %u singly ind. blk %u past end of file, val = %u. Zap? ",
-                            n, b, ino.i_addr[b]);
-                    if (yes()) {
-                        ino.i_addr[b] = 0;
-                        iwrite(n, &ino);
-                    }
-                }
-                if (ino.i_addr[b] != 0)
-                    bitset(ino.i_addr[b]);
-            }
-
-            /* Check the double indirect blocks */
-            if (ino.i_addr[19] != 0) {
-                buf = (blkno_t *) daread(ino.i_addr[19]);
-                for (b = 0; b < 256; ++b) {
-                    if (buf[b] != 0 && (buf[b] < superblock.s_isize ||
-                                buf[b] >= superblock.s_fsize)) {
-                        printf("Inode %u doubly ind. blk %u is out of range, val = %u. Zap? ",
-                                n, b, buf[b]);
-                        /* 1.4.98 - line split.  HFB */
-                        if (yes()) {
-                            buf[b] = 0;
-                            dwrite(b, (char *) buf);
-                        }
-                    }
-                    if (buf[b] != 0)
-                        bitset(buf[b]);
-                }
-            }
-            /* Check the rest */
-            bmax = ino.i_size/512;
-            for (bno = 0; bno <= bmax ; ++bno) {
-                b = getblkno(&ino, bno);
-
-                if (b != 0 && (b < superblock.s_isize || b >= superblock.s_fsize)) {
-                    printf("Inode %u block %u out of range, val = %u. Zap? ",
-                            n, bno, b);
-                    if (yes()) {
-                        setblkno(&ino, bno, 0);
-                        iwrite(n, &ino);
-                    }
-                }
-                if (b != 0)
-                    bitset(b);
-            }
-        }
-    }
-    /* Fix free inode count in superblock block */
-    icount = max_inode - ROOTINODE - icount;
-    if (superblock.s_tinode != icount) {
-        printf("Free inode count in superblock is %u, should be %u. Fix? ",
-                superblock.s_tinode, icount);
-
-        if (yes()) {
-            superblock.s_tinode = icount;
-            dwrite((blkno_t) 1, (char *) &superblock);
-        }
-    }
-}
-
-
-/* Clear inode free list, rebuild block free list using bit map. */
-static void pass2(void)
-{
-    blkno_t j;
-    blkno_t oldtfree;
-    uint16_t imax = superblock.s_isize;
-
-    printf("Rebuild free list? ");
-    if (!yes_noerror())
-        return;
-
-    error |= 1;
-    oldtfree = superblock.s_tfree;
-
-    /* Initialize the superblock-block */
-
-    superblock.s_ninode = 0;
-    superblock.s_nfree = 1;
-    superblock.s_free[0] = 0;
-    superblock.s_tfree = 0;
-
-    /* Free each block, building the free list */
-
-    for (j = superblock.s_fsize - 1; j >= imax; --j) {
-        if (bittest(j) == 0) {
-            if (superblock.s_nfree == 50) {
-                dwrite(j, (char *) &superblock.s_nfree);
-                superblock.s_nfree = 0;
-            }
-            superblock.s_tfree++;
-            superblock.s_free[superblock.s_nfree++] = j;
-        }
-    }
-
-    dwrite((blkno_t) 1, (char *) &superblock);
-
-    if (oldtfree != superblock.s_tfree)
-        printf("s_tfree was changed to %u from %u.\n",
-                superblock.s_tfree, oldtfree);
-
-}
-
-/* Pass 3 finds and fixes multiply allocated blocks. */
-static void pass3(void)
-{
-    uint16_t n;
-    struct dinode ino;
-    uint16_t mode;
-    blkno_t b;
-    blkno_t bno;
-    blkno_t newno;
-    uint16_t bmax = superblock.s_fsize;
-    uint32_t nmax;
-    /*--- was blk_alloc ---*/
-
-    /* FIXME:
-        1. Set the bits below s_isize
-     */
-    /* FIXME: performance */
-    for (b = superblock.s_isize; b < bmax; ++b)
-        bitclear(b);
-
-    for (n = ROOTINODE; n < max_inode; ++n) {
-        iread(n, &ino);
-
-        mode = ino.i_mode & F_MASK;
-        if (mode != F_REG && mode != F_DIR)
-            continue;
-
-        /* Check singly indirect blocks */
-
-        for (b = 18; b < 20; ++b) {
-            if (ino.i_addr[b] != 0) {
-                if (bittest(ino.i_addr[b]) != 0) {
-                    puts("Indirect b");
-                    printf(block_multi + 1, b, n, ino.i_addr[b]);
-                    if (yes()) {
-                        newno = blk_alloc0(&superblock);
-                        if (newno == 0) {
-                            puts(no_more_free);
-                            error |= 4;
-                        } else {
-                            dwrite(newno, daread(ino.i_addr[b]));
-                            ino.i_addr[b] = newno;
-                            iwrite(n, &ino);
-                            error |= 64;
-                        }
-                    }
-                } else
-                    bitset(ino.i_addr[b]);
-            }
-        }
-
-        /* Check the rest */
-        nmax = ino.i_size/512;
-        for (bno = 0; bno <= nmax; ++bno) {
-            b = getblkno(&ino, bno);
-
-            if (b != 0) {
-                if (bittest(b)) {
-                    printf(block_multi,
-                            bno, n, b);
-                    if (yes()) {
-                        newno = blk_alloc0(&superblock);
-                        if (newno == 0) {
-                            puts(no_more_free);
-                            error |= 4;
-                        } else {
-                            dwrite(newno, daread(b));
-                            setblkno(&ino, bno, newno);
-                            iwrite(n, &ino);
-                            error |= 64;
-                        }
-                    }
-                } else
-                    bitset(b);
-            }
-        }
-
-    }
-
-}
-
-static int depth;
-
-/*
- *  Pass 4 traverses the directory tree, fixing bad directory entries
- *  and finding the actual number of references to each inode.
- */
-
-static void pass4(void)
-{
-    depth = 0;
-    linkmap[ROOTINODE] = 1;
-    ckdir(ROOTINODE, ROOTINODE, "/");
-//if (depth != 0)
-//      panic("Inconsistent depth");
-}
-
-
-/* This recursively checks the directories */
-
-static void ckdir(uint16_t inum, uint16_t pnum, char *name)
-{
-    struct dinode ino;
-    /* We can keep this off the stack, we'd really like to keep the inode
-       off it too but that would thrash the disk horribly */
-    static struct direct dentry;
-    uint16_t j;
-    int c;
-    uint8_t i;
-    int nentries;
-    char *ename;
-
-    iread(inum, &ino);
-    if ((ino.i_mode & F_MASK) != F_DIR)
-        return;
-    ++depth;
-
-    if (((uint8_t)ino.i_size) & 31) {
-        printf("Directory inode %u has improper length. Fix? ", inum);
-        if (yes()) {
-            ino.i_size &= ~0x1fUL;
-            iwrite(inum, &ino);
-            error |= 64;
-        }
-    }
-    nentries = ino.i_size/32;
-
-    /* Each iteration we begin with a new ino/dentry. Each recursion we
-       destroy them. Be careful */
-    for (j = 0; j < nentries; ++j) {
-        dirread(&ino, j, &dentry);
-
-        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;
-
-        if (dentry.d_ino < ROOTINODE ||
-                dentry.d_ino >= max_inode) {
-            printf("Directory entry %s%-1.30s has out-of-range inode %u. Zap? ",
-                    name, dentry.d_name, dentry.d_ino);
-            if (yes()) {
-                dentry.d_ino = 0;
-                dentry.d_name[0] = '\0';
-                dirwrite(&ino, j, &dentry);
-                error |= 64;
-                continue;
-            }
-        }
-        if (dentry.d_ino && linkmap[dentry.d_ino] == -1) {
-            printf("Directory entry %s%-1.30s points to bogus inode %u. Zap? ",
-                    name, dentry.d_name, dentry.d_ino);
-            if (yes()) {
-                dentry.d_ino = 0;
-                dentry.d_name[0] = '\0';
-                dirwrite(&ino, j, &dentry);
-                continue;
-            }
-        }
-        ++linkmap[dentry.d_ino];
-
-        for (c = 0; c < 30 && dentry.d_name[c]; ++c) {
-            if (dentry.d_name[c] == '/') {
-                printf("Directory entry %s%-1.30s contains slash. Fix? ",
-                        name, dentry.d_name);
-                if (yes()) {
-                    dentry.d_name[c] = 'X';
-                    dirwrite(&ino, j, &dentry);
-                }
-            }
-        }
-
-        if (strncmp(dentry.d_name, ".", 30) == 0 && dentry.d_ino != inum) {
-            printf("Dot entry %s%-1.30s points to wrong place. Fix? ",
-                    name, dentry.d_name);
-            if (yes()) {
-                dentry.d_ino = inum;
-                dirwrite(&ino, j, &dentry);
-                error |= 64;
-            }
-        }
-        if (strncmp(dentry.d_name, "..", 30) == 0 && dentry.d_ino != pnum) {
-            printf("DotDot entry %s%-1.30s points to wrong place. Fix? ",
-                    name, dentry.d_name);
-            if (yes()) {
-                dentry.d_ino = pnum;
-                dirwrite(&ino, j, &dentry);
-                error |= 64;
-            }
-        }
-        if (dentry.d_ino != pnum &&
-                dentry.d_ino != inum && depth < MAXDEPTH) {
-            /* This is a bad approach. We ought to have some kind of
-               growing buffer, but our realloc will end up chopping up
-               the pool and stuff I think. sbrk() doesn't help as we've
-               got lots of memory in the pool from freeing bitmap that
-               won't go back FIXME */
-            ename = malloc(strlen(name) + strlen(dentry.d_name) + 2);
-            if (ename == NULL) {
-                fprintf(stderr, "Not enough memory.\n");
-                exit(error |= 8);
-            }
-            strcpy(ename, name);
-            strcat(ename, dentry.d_name);
-            strcat(ename, "/");
-            ckdir(dentry.d_ino, inum, ename);
-            free(ename);
-        }
-        /* dentry and dino are not valid any more */
-    }
-    --depth;
-}
-
-
-/* Pass 5 compares the link counts found in pass 4 with the inodes. */
-static void pass5(void)
-{
-    uint16_t n;
-    struct dinode ino;
-
-    for (n = ROOTINODE; n < max_inode; ++n) {
-        iread(n, &ino);
-
-        if (ino.i_mode == 0) {
-            if (linkmap[n] != -1)
-                panic("Inconsistent linkmap");
-            continue;
-        }
-
-        if (linkmap[n] == -1 && ino.i_mode != 0)
-            panic("Inconsistent linkmap");
-
-        if (linkmap[n] > 0 && ino.i_nlink != linkmap[n]) {
-            printf("Inode %u has link count %u should be %u. Fix? ",
-                    n, ino.i_nlink, linkmap[n]);
-            if (yes()) {
-                ino.i_nlink = linkmap[n];
-                iwrite(n, &ino);
-            }
-        }
-
-        if (linkmap[n] == 0) {
-            if ((ino.i_mode & F_MASK) == F_BDEV ||
-                    (ino.i_mode & F_MASK) == F_CDEV ||
-                    (ino.i_size == 0)) {
-                printf("Useless inode %u with mode 0%o has become detached. Link count is %u. Zap? ",
-                        n, ino.i_mode, ino.i_nlink);
-                if (yes()) {
-                    ino.i_nlink = 0;
-                    ino.i_mode = 0;
-                    iwrite(n, &ino);
-                    superblock.s_tinode++;
-                    dwrite((blkno_t) 1, (char *) &superblock);
-                    error |= 64;
-                }
-            } else {
-                printf("Inode %u has become detached. Link count is %u. ",
-                        n, ino.i_nlink);
-                puts(ino.i_nlink ? "Zap? " : "Fix? ");
-                if (yes()) {
-                    error |= 64;
-                    if (ino.i_nlink == 0) {
-                        ino.i_nlink = 0;
-                        ino.i_mode = 0;
-                        iwrite(n, &ino);
-                        superblock.s_tinode++;
-                        dwrite((blkno_t) 1, (char *) &superblock);
-                    } else {
-                        ino.i_nlink = 1;
-                        iwrite(n, &ino);
-                        mkentry(n);
-                    }
-                }
-            }
-        }
-
-    }
-}
-
-
-/* This makes an entry in "lost+found" for inode n */
-static void mkentry(uint16_t inum)
-{
-    struct dinode rootino;
-    struct direct dentry;
-    uint16_t d;
-    uint32_t dmax;
-
-    iread(ROOTINODE, &rootino);
-    dmax = rootino.i_size/32;
-    for (d = 0; d < dmax; ++d) {
-        dirread(&rootino, d, &dentry);
-        if (dentry.d_ino == 0 && dentry.d_name[0] == '\0') {
-            dentry.d_ino = inum;
-            sprintf(dentry.d_name, "l+f%u", inum);
-            dirwrite(&rootino, d, &dentry);
-            return;
-        }
-    }
-    puts("Sorry... No empty slots in root directory.");
-    error |= 4;
-}
-
-/*
- *  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.
- */
-
-static blkno_t getblkno(struct dinode *ino, blkno_t num)
-{
-    blkno_t indb;
-    blkno_t dindb;
-    blkno_t *buf;
-
-    if (num < 18)              /* Direct block */
-        return ino->i_addr[num];
-    if (num < 256 + 18) {      /* Single indirect */
-        indb = ino->i_addr[18];
-        if (indb == 0)
-            return 0;
-        buf = (blkno_t *) daread(indb);
-        return buf[num - 18];
-    }
-    /* Double indirect */
-    indb = ino->i_addr[19];
-    if (indb == 0)
-        return 0;
-
-    buf = (blkno_t *) daread(indb);
-
-    dindb = buf[(num - (18 + 256)) >> 8];
-    if (dindb == 0)
-        return 0;
-    buf = (blkno_t *) daread(dindb);
-    return buf[(num - (18 + 256)) & 0x00ff];
-}
-
-
-/*
- *  Setblkno sets the given block number of the given file to the given
- *  disk block number, possibly creating or modifiying the indirect blocks.
- *  A return of zero means there were no blocks available to create an 
- *  indirect block. This should never happen in fsck.
- */
-static void setblkno(struct dinode *ino, blkno_t num, blkno_t dnum)
-{
-    blkno_t indb;
-    blkno_t dindb;
-    blkno_t *buf;
-    /*--    char *zerobuf();--*/
-
-
-    if (num < 18) {                    /* Direct block */
-        ino->i_addr[num] = dnum;
-    } else if (num < 256 + 18) {       /* Single indirect */
-        indb = ino->i_addr[18];
-        if (indb == 0)
-            panic(missing_ind_blk);
-
-        buf = (blkno_t *) daread(indb);
-        buf[num - 18] = dnum;
-        dwrite(indb, (char *) buf);
-    } else {                           /* Double indirect */
-        indb = ino->i_addr[19];
-        if (indb == 0)
-            panic(missing_ind_blk);
-
-        buf = (blkno_t *) daread(indb);
-        dindb = buf[(num - (18 + 256)) >> 8];
-        if (dindb == 0)
-            panic(missing_ind_blk);
-
-        buf = (blkno_t *) daread(dindb);
-        buf[(num - (18 + 256)) & 0x00ff] = num;
-        dwrite(indb, (char *) buf);
-    }
-}
-
-
-/*
- *  blk_alloc0 allocates an unused block.
- *  A returned block number of zero means no more blocks.
- */
-
-/*--- was blk_alloc ---*/
-static blkno_t blk_alloc0(struct filesys *filesys)
-{
-    blkno_t newno;
-    blkno_t *buf;
-    int16_t j;
-
-    newno = filesys->s_free[--filesys->s_nfree];
-    if (!newno) {
-        filesys->s_nfree++;
-        return 0;
-    }
-
-    /* See if we must refill the s_free array */
-
-    if (!filesys->s_nfree) {
-        buf = (blkno_t *) daread(newno);
-        filesys->s_nfree = buf[0];
-        for (j = 0; j < 50; j++) {
-            filesys->s_free[j] = buf[j + 1];
-        }
-    }
-
-    filesys->s_tfree--;
-
-    if (newno < filesys->s_isize || newno >= filesys->s_fsize) {
-        puts("Free list is corrupt.  Did you rebuild it?");
-        return (0);
-    }
-    dwrite((blkno_t) 1, (char *) filesys);
-    return (newno);
-}
-
-
-static uint16_t lblk = 0;
-
-static char *daread(uint16_t blk)
-{
-    static char da_buf[512];
-
-    if (blk == 0)
-        panic("reading block 0");
-
-    if (blk == lblk)
-        return da_buf;
-
-    if (lseek(dev_fd, blk * 512L, 0) == -1) {
-        perror("lseek");
-        exit(1);
-    }
-    if(read(dev_fd, da_buf, 512) != 512) {
-        perror("read");
-        exit(1);
-    }
-    lblk = blk;
-    return da_buf;
-}
-
-static void dwrite(uint16_t blk, char *addr)
-{
-    if (lseek(dev_fd, blk * 512L, 0) == -1) {
-        perror("lseek");
-        exit(1);
-    }
-    if(write(dev_fd, addr, 512) != 512) {
-        perror("write");
-        exit(1);
-    }
-    lblk = 0;
-}
-
-static void iread(uint16_t ino, struct dinode *buf)
-{
-    struct dinode *addr;
-
-    addr = (struct dinode *) daread((ino >> 3) + 2);
-    memcpy(buf, &addr[ino & 7], sizeof(struct dinode));
-}
-
-static void iwrite(uint16_t ino, struct dinode *buf)
-{
-    struct dinode *addr;
-
-    addr = (struct dinode *) daread((ino >> 3) + 2);
-    memcpy(&addr[ino & 7], buf, sizeof(struct dinode));
-    dwrite((ino >> 3) + 2, (char *) addr);
-}
-
-static void dirread(struct dinode *ino, uint16_t j, struct direct *dentry)
-{
-    blkno_t blkno;
-    char *buf;
-
-    blkno = getblkno(ino, (blkno_t) j / 16);
-    if (blkno == 0)
-        panic("Missing block in directory");
-    buf = daread(blkno);
-    memcpy(dentry, buf + 32 * (j % 16), 32);
-}
-
-static void dirwrite(struct dinode *ino, uint16_t j, struct direct *dentry)
+int main(int argc, char *argv[])
 {
-    blkno_t blkno;
-    char *buf;
-
-    blkno = getblkno(ino, (blkno_t) j / 16);
-    if (blkno == 0)
-        panic("Missing block in directory");
-    buf = daread(blkno);
-    memcpy(buf + 32 * (j % 16), dentry, 32);
-    dwrite(blkno, buf);
+       struct mntent *mnt;
+       if (argc > 1 && strcmp(argv[1], "-a") == 0) {
+               argc--;
+               argv++;
+               aflag = 1;
+       }
+
+       if (argc == 1 && aflag) {
+               FILE *fp = setmntent("/etc/fstab", "r");
+               if (fp == NULL) {
+                       perror("/etc/fstab");
+                       exit(1);
+               }
+               while ((mnt = getmntent(fp)) != NULL) {
+                       printf("%s:\n", mnt->mnt_fsname);
+                       if (perform_fsck(mnt->mnt_fsname, 0))
+                               exit(error);
+               }
+               endmntent(fp);
+       } else {
+               if (argc != 2) {
+                       fputs("syntax: fsck [-a] [devfile]\n", stderr);
+                       return 16;
+               }
+               perform_fsck(argv[1], 1);
+       }
+       puts("Done.");
+       exit(error);
 }
index ae885ce..a47e894 100644 (file)
@@ -69,6 +69,7 @@ f 0755 /bin/false       false
 f 0755 /bin/fdisk       fdisk
 f 0755 /bin/free        free
 f 0755 /bin/fsck        fsck
+f 0755 /bin/fsck-fuzix  fsck-fuzix
 f 0755 /bin/gptparse    gptparse
 f 0755 /bin/grep        grep
 f 0755 /bin/groups      groups