home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
CPM
/
UZI
/
UZI-UTIL.ARK
/
FSCK.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-12-22
|
17KB
|
860 lines
/**************************************************
UZI (Unix Z80 Implementation) Utilities: fsck.c
***************************************************/
#include <stdio.h>
#include "unix.h"
#include "extern.h"
#define MAXDEPTH 20 /* Maximum depth of directory tree to search */
/* This checks a filesystem */
int dev;
struct filesys filsys;
char *bitmap;
int16 *linkmap;
char *strcpy(), *strcat(), *sprintf();
char *daread();
char *calloc();
char *da_read();
main(argc,argv)
int argc;
char *argv[];
{
char *buf;
if (argc != 2 || argv[1][0] < '0' || argv[1][0] > '9')
{
fprintf(stderr,"Usage: fsck device#\n");
exit(-1);
}
dev = atoi(argv[1]);
bufinit();
if (d_open(dev))
{
fprintf(stderr,"Can't open device number %d\n",dev);
exit(-1);
}
/* Read in the super block. */
buf = daread(1);
bcopy(buf, (char *)&filsys, sizeof(struct filesys));
/* Verify the fsize and isize parameters */
if (filsys.s_mounted != SMOUNTED)
{
printf("Device %d has invalid magic number %d. Fix? ",
dev, filsys.s_mounted);
if (!yes())
exit(-1);
filsys.s_mounted = SMOUNTED;
dwrite((blkno_t)1,(char *)&filsys);
}
printf("Device %d has fsize = %d and isize = %d. Continue? ",
dev, filsys.s_fsize, filsys.s_isize);
if (!yes())
exit(-1);
bitmap = calloc(filsys.s_fsize,sizeof(char));
linkmap = (int16 *)calloc(8 * filsys.s_isize, sizeof(int16));
if (!bitmap || !linkmap)
{
fprintf(stderr,"Not enough memory.\n");
exit(-1);
}
printf("Pass 1: Checking inodes.\n");
pass1();
printf("Pass 2: Rebuilding free list.\n");
pass2();
printf("Pass 3: Checking block allocation.\n");
pass3();
printf("Pass 4: Checking directory entries.\n");
pass4();
printf("Pass 5: Checking link counts.\n");
pass5();
bufsync();
printf("Done.\n");
exit(0);
}
/* Pass 1 checks each inode independently for validity, zaps bad block
numbers in the inodes, and builds the block allocation map. */
pass1()
{
uint16 n;
struct dinode ino;
uint16 mode;
blkno_t b;
blkno_t bno;
uint16 icount;
blkno_t *buf;
blkno_t getblkno();
icount = 0;
for (n = ROOTINODE; n < 8*(filsys.s_isize-2); ++n)
{
iread(n, &ino);
linkmap[n] = -1;
if (ino.i_mode == 0)
continue;
mode = ino.i_mode & F_MASK;
/* Check mode */
if (mode != F_REG && mode != F_DIR && mode != F_BDEV && mode != F_CDEV)
{
printf("Inode %d 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.o_offset >= 512)
{
printf("Inode %d offset is too big with value of %d. Fix? ",
n,ino.i_size.o_offset);
if (yes())
{
while (ino.i_size.o_offset >= 512)
{
ino.i_size.o_offset -= 512;
++ino.i_size.o_blkno;
}
iwrite(n,&ino);
}
}
if (ino.i_size.o_offset < 0)
{
printf("Inode %d offset is negative with value of %d. Fix? ",
n,ino.i_size.o_offset);
if (yes())
{
ino.i_size.o_offset = 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] < filsys.s_isize ||
ino.i_addr[b] >= filsys.s_fsize))
{
printf("Inode %d singly indirect block %d is out of range with value of %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.o_blkno < 18)
{
printf("Inode %d singly indirect block %d is past end of file with value of %u. Zap? ",
n, b, ino.i_addr[b]);
if (yes())
{
ino.i_addr[b] = 0;
iwrite(n, &ino);
}
}
if (ino.i_addr[b] != 0)
bitmap[ino.i_addr[b]] = 1;
}
/* 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] < filsys.s_isize ||
buf[b] >= filsys.s_fsize))
{
printf("Inode %d doubly indirect block %d is out of range with value of %u. Zap? ",
n, b, buf[b]);
if (yes())
{
buf[b] = 0;
dwrite(b, (char *)buf);
}
}
if (buf[b] != 0)
bitmap[buf[b]] = 1;
}
}
/* Check the rest */
for (bno=0; bno <= ino.i_size.o_blkno; ++bno)
{
b = getblkno(&ino, bno);
if (b != 0 && (b < filsys.s_isize ||
b >= filsys.s_fsize))
{
printf("Inode %d block %d is out of range with value of %u. Zap? ",
n, bno, b);
if (yes())
{
setblkno(&ino, bno,0);
iwrite(n, &ino);
}
}
if (b != 0)
bitmap[b] = 1;
}
}
}
/* Fix free inode count in super block */
if (filsys.s_tinode != 8*(filsys.s_isize-2) - ROOTINODE - icount)
{
printf("Free inode count in super block is %u should be %u. Fix? ",
filsys.s_tinode, 8*(filsys.s_isize-2) - ROOTINODE - icount);
if (yes())
{
filsys.s_tinode = 8*(filsys.s_isize-2) - ROOTINODE - icount;
dwrite((blkno_t)1,(char *)&filsys);
}
}
}
/* Clear inode free list, rebuild block free list using bit map. */
pass2()
{
blkno_t j;
blkno_t oldtfree;
printf("Rebuild free list? ");
if (!yes())
return;
oldtfree = filsys.s_tfree;
/* Initialize the super-block */
filsys.s_ninode = 0;
filsys.s_nfree = 1;
filsys.s_free[0] = 0;
filsys.s_tfree = 0;
/* Free each block, building the free list */
for (j= filsys.s_fsize-1; j >= filsys.s_isize; --j)
{
if (bitmap[j] == 0)
{
if (filsys.s_nfree == 50)
{
dwrite(j, (char *)&filsys.s_nfree);
filsys.s_nfree = 0;
}
++filsys.s_tfree;
filsys.s_free[(filsys.s_nfree)++] = j;
}
}
dwrite((blkno_t)1,(char *)&filsys);
if (oldtfree != filsys.s_tfree)
printf("During free list regeneration s_tfree was changed to %d from %d.\n",
filsys.s_tfree, oldtfree);
}
/* Pass 3 finds and fixes multiply allocated blocks. */
pass3()
{
uint16 n;
struct dinode ino;
uint16 mode;
blkno_t b;
blkno_t bno;
blkno_t newno;
blkno_t blk_alloc();
blkno_t getblkno();
for (b = filsys.s_isize; b < filsys.s_fsize; ++b)
bitmap[b] = 0;
for (n = ROOTINODE; n < 8*(filsys.s_isize-2); ++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 (bitmap[ino.i_addr[b]] != 0)
{
printf("Indirect block %d in inode %u value %u multiply allocated. Fix? ", b, n, ino.i_addr[b]);
if (yes())
{
newno = blk_alloc(&filsys);
if (newno == 0)
printf("Sorry... No more free blocks.\n");
else
{
dwrite(newno,daread(ino.i_addr[b]));
ino.i_addr[b] = newno;
iwrite(n, &ino);
}
}
}
else
bitmap[ino.i_addr[b]] = 1;
}
}
/* Check the rest */
for (bno=0; bno <= ino.i_size.o_blkno; ++bno)
{
b = getblkno(&ino, bno);
if (b != 0)
{
if (bitmap[b] != 0)
{
printf("Block %d in inode %u value %u multiply allocated. Fix? ",
bno, n, b);
if (yes())
{
newno = blk_alloc(&filsys);
if (newno == 0)
printf("Sorry... No more free blocks.\n");
else
{
dwrite(newno,daread(b));
setblkno(&ino, bno, newno);
iwrite(n, &ino);
}
}
}
else
bitmap[b] = 1;
}
}
}
}
int depth;
/* Pass 4 traverses the directory tree, fixing bad directory entries
and finding the actual number of references to each inode. */
pass4()
{
depth = 0;
linkmap[ROOTINODE] = 1;
ckdir(ROOTINODE,ROOTINODE,"/");
if (depth != 0)
panic("Inconsistent depth");
}
/* This recursively checks the directories */
ckdir(inum, pnum, name)
uint16 inum;
uint16 pnum;
char *name;
{
struct dinode ino;
struct direct dentry;
uint16 j;
int c;
int nentries;
char ename[150];
iread(inum, &ino);
if ((ino.i_mode & F_MASK) != F_DIR)
return;
++depth;
if (ino.i_size.o_offset % 16 != 0)
{
printf("Directory inode %d has improper length. Fix? ");
if (yes())
{
ino.i_size.o_offset &= (~0x0f);
++ino.i_size.o_offset;
iwrite(inum, &ino);
}
}
nentries = 8*ino.i_size.o_blkno + ino.i_size.o_offset/16;
for (j=0; j < nentries; ++j)
{
dirread(&ino, j, &dentry);
if (dentry.d_ino == 0)
continue;
if (dentry.d_ino < ROOTINODE || dentry.d_ino >= 8*filsys.s_isize)
{
printf("Directory entry %s%-1.14s 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);
continue;
}
}
if (dentry.d_ino && linkmap[dentry.d_ino] == -1)
{
printf("Directory entry %s%-1.14s 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<14 && dentry.d_name[c]; ++c)
{
if (dentry.d_name[c] == '/')
{
printf("Directory entry %s%-1.14s contains slash. Fix? ",
name, dentry.d_name);
if (yes())
{
dentry.d_name[c] = 'X';
dirwrite(&ino, j, &dentry);
}
}
}
if (strncmp(dentry.d_name,".",14) == 0 && dentry.d_ino != inum)
{
printf("Dot entry %s%-1.14s points to wrong place. Fix? ",
name, dentry.d_name);
if (yes())
{
dentry.d_ino = inum;
dirwrite(&ino, j, &dentry);
}
}
if (strncmp(dentry.d_name,"..",14) == 0 && dentry.d_ino != pnum)
{
printf("DotDot entry %s%-1.14s points to wrong place. Fix? ",
name, dentry.d_name);
if (yes())
{
dentry.d_ino = pnum;
dirwrite(&ino, j, &dentry);
}
}
if (dentry.d_ino != pnum && dentry.d_ino != inum && depth < MAXDEPTH)
{
strcpy(ename,name);
strcat(ename,dentry.d_name);
strcat(ename,"/");
ckdir(dentry.d_ino,inum,ename);
}
}
--depth;
}
/* Pass 5 compares the link counts found in pass 4 with the inodes. */
pass5()
{
uint16 n;
struct dinode ino;
for (n = ROOTINODE; n < 8*(filsys.s_isize-2); ++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 %d has link count %d should be %d. 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.o_blkno == 0 && ino.i_size.o_offset == 0))
{
printf("Useless inode %d with mode 0%o has become detached. Link count is %d. Zap? ",
n, ino.i_mode, ino.i_nlink);
if (yes())
{
ino.i_nlink = 0;
ino.i_mode = 0;
iwrite(n, &ino);
++filsys.s_tinode;
dwrite((blkno_t)1,(char *)&filsys);
}
}
else
{
printf("Inode %d has become detached. Link count is %d. Fix? ",
n, ino.i_nlink);
if (yes())
{
ino.i_nlink = 1;
iwrite(n, &ino);
mkentry(n);
}
}
}
}
}
/* This makes an entry in "lost+found" for inode n */
mkentry(inum)
uint16 inum;
{
struct dinode rootino;
struct direct dentry;
uint16 d;
iread(ROOTINODE,&rootino);
for (d=0; d < 32*rootino.i_size.o_blkno + rootino.i_size.o_offset/16; ++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%d",inum);
dirwrite(&rootino,d,&dentry);
return;
}
}
printf("Sorry... No empty slots in root directory.\n");
}
/* Beginning of fsck1.c */
/* Getblkno gets a pointer index, and a number of a block in the file.
It returns the number of the block on the disk. A value of zero
means an unallocated block. */
char *daread();
blkno_t
getblkno(ino,num)
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];
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. */
setblkno(ino,num,dnum)
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 indirect block");
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 indirect block");
buf = (blkno_t *)daread(indb);
dindb = buf[ (num-(18+256)) >> 8];
if (dindb==0)
panic("Missing indirect block");
buf = (blkno_t *)daread(dindb);
buf[ (num-(18+256)) & 0x00ff] = num;
dwrite(indb,(char *)buf);
}
}
/* Blk_alloc allocates an unused block.
A returned block number of zero means no more blocks. */
blkno_t
blk_alloc(filsys)
struct filesys *filsys;
{
blkno_t newno;
blkno_t *buf;
int16 j;
newno = filsys->s_free[--filsys->s_nfree];
ifnot (newno)
{
++filsys->s_nfree;
return(0);
}
/* See if we must refill the s_free array */
ifnot (filsys->s_nfree)
{
buf = (blkno_t *)daread(newno);
filsys->s_nfree = buf[0];
for (j=0; j < 50; j++)
{
filsys->s_free[j] = buf[j+1];
}
}
--filsys->s_tfree;
if (newno < filsys->s_isize || newno >= filsys->s_fsize)
{
printf("Free list is corrupt. Did you rebuild it?\n");
return(0);
}
dwrite((blkno_t)1,(char *)filsys);
return(newno);
}
char *
daread(blk)
uint16 blk;
{
char *buf;
if (da_read(dev,blk,&buf) != 512)
{
fprintf(stderr,"Read of block %d failed.\n",blk);
abort();
}
return(buf);
}
dwrite(blk, addr)
uint16 blk;
char *addr;
{
if (d_write(dev,blk,addr) != 512)
{
fprintf(stderr,"Write of block %d failed.\n",blk);
abort();
}
}
iread(ino, buf)
uint16 ino;
struct dinode *buf;
{
struct dinode *addr;
addr = (struct dinode *) daread((ino>>3) + 2);
bcopy((char *)&addr[ino & 7], (char *)buf, sizeof(struct dinode));
}
iwrite(ino, buf)
uint16 ino;
struct dinode *buf;
{
struct dinode *addr;
addr = (struct dinode *) daread((ino>>3) + 2);
bcopy((char *)buf, (char *)&addr[ino & 7], sizeof(struct dinode));
dwrite((ino>>3) + 2,(char *)addr);
}
dirread(ino, j, dentry)
struct dinode *ino;
uint16 j;
struct direct *dentry;
{
blkno_t blkno;
char *buf;
blkno = getblkno(ino,(blkno_t)j/32);
if (blkno == 0)
panic("Missing block in directory");
buf = daread(blkno);
bcopy(buf+(16*j), (char *)dentry, 16);
}
dirwrite(ino, j, dentry)
struct dinode *ino;
uint16 j;
struct direct *dentry;
{
blkno_t blkno;
char *buf;
blkno = getblkno(ino,(blkno_t)j/32);
if (blkno == 0)
panic("Missing block in directory");
buf = daread(blkno);
bcopy((char *)dentry, buf+(16*j), 16);
dwrite(blkno,buf);
}
yes()
{
char line[20];
if (!fgets(line,sizeof(line),stdin) || (*line != 'y' && *line != 'Y'))
return(0);
return(1);
}