From: Alan Cox Date: Sat, 1 Sep 2018 23:33:22 +0000 (+0100) Subject: fsck: Ok I give up split fsck into a generic fsck and per fs helper X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=deeaa149215097b992f0eac38cc8209043f1c7da;p=FUZIX.git fsck: Ok I give up split fsck into a generic fsck and per fs helper 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) --- diff --git a/Applications/util/Makefile.6502 b/Applications/util/Makefile.6502 index 4047d58c..51e53ed9 100644 --- a/Applications/util/Makefile.6502 +++ b/Applications/util/Makefile.6502 @@ -70,6 +70,7 @@ SRCS = banner.c \ fgrep.c \ free.c \ fsck.c \ + fsck-fuzix.c \ grep.c \ id.c \ kbdrate.c \ diff --git a/Applications/util/Makefile.68000 b/Applications/util/Makefile.68000 index 79467148..b686837f 100644 --- a/Applications/util/Makefile.68000 +++ b/Applications/util/Makefile.68000 @@ -76,6 +76,7 @@ SRCS = \ fgrep.c \ free.c \ fsck.c \ + fsck-fuzix.c \ gptparse.c \ grep.c \ id.c \ diff --git a/Applications/util/Makefile.6809 b/Applications/util/Makefile.6809 index 6584c05c..35b7a4f1 100644 --- a/Applications/util/Makefile.6809 +++ b/Applications/util/Makefile.6809 @@ -77,6 +77,7 @@ SRCS = \ fgrep.c \ free.c \ fsck.c \ + fsck-fuzix.c \ gptparse.c \ grep.c \ id.c \ diff --git a/Applications/util/Makefile.pdp11 b/Applications/util/Makefile.pdp11 index cd18a75f..c9067616 100644 --- a/Applications/util/Makefile.pdp11 +++ b/Applications/util/Makefile.pdp11 @@ -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 \ diff --git a/Applications/util/Makefile.z80 b/Applications/util/Makefile.z80 index bf4036b0..b2cbcad4 100644 --- a/Applications/util/Makefile.z80 +++ b/Applications/util/Makefile.z80 @@ -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 index 00000000..41d2af98 --- /dev/null +++ b/Applications/util/fsck-fuzix.c @@ -0,0 +1,937 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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); +} diff --git a/Applications/util/fsck.c b/Applications/util/fsck.c index cfe0e4a6..d44d869c 100644 --- a/Applications/util/fsck.c +++ b/Applications/util/fsck.c @@ -1,985 +1,115 @@ #include -#include #include #include #include -#include #include #include -#include -#include #include +#include +#include +#include - -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); } diff --git a/Applications/util/fuzix-util.pkg b/Applications/util/fuzix-util.pkg index ae885ce6..a47e8941 100644 --- a/Applications/util/fuzix-util.pkg +++ b/Applications/util/fuzix-util.pkg @@ -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