|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 15385 (0x3c19)
Types: TextFile
Notes: UNIX file
Names: »icheck.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/icheck.c«
/*
* Icheck - check i-list consistency of
* filesystems and (optionally) repair
* filesystems.
*/
#include <stdio.h>
extern char *calloc();
#include <filsys.h>
#include <fblk.h>
#include <dir.h>
#include <ino.h>
#include <check.h>
#include <canon.h>
#define ROOTINO 2 /* I-number of root */
#define NBLOCK 20 /* Maximum number of blocks to check */
#define NBPC 8 /* Bits per character */
#define BOOTB 0 /* Boot block # */
#define SUPERB 1 /* Super block */
#define INOORG 2 /* Inodes begin here */
#define IBLK 12 /* I-node read blocking factor */
#define BSIZE 512
#define ND 10 /* Number of direct block */
#undef NI
#define NI 1
#define NII 1
#define NIII 1
#undef NADDR
#define NADDR (ND+NI+NII+NIII)
/*
* Flags for crawldown.
*/
#define PLAIN 0
#define DIR 1
#define BAD 2
/*
* A chain of these structures
* holds all of the defective blocks found
* in the bad block file. The list is sorted for
* easy access by those parts of the program
* that scan blocks.
*/
struct defect
{
struct defect *d_next; /* Link to next */
daddr_t d_start; /* First bad block in cluster */
int d_length; /* Size of cluster */
};
#define test(bn) (bitmap[((unsigned)bn)/NBPC] & 1<<(((unsigned)bn)%NBPC))
#define mark(bn) (bitmap[((unsigned)bn)/NBPC] |= 1<<(((unsigned)bn)%NBPC))
char tmb[] = "Too many block numbers specified\n";
int nblock;
daddr_t blocks[NBLOCK];
ino_t freei[NICFREE]; /* Free i-nodes to put into superblock */
ino_t *freeip;
struct defect *deflist;
char superb[BSIZE];
char ibuf[IBLK*BSIZE];
char fbuf[BSIZE];
char idbuf[3][BSIZE]; /* One for each indirect level */
/*
* Offsets of levels of indirection
* into the i-node addresses.
*/
char offsets[] = {
0, ND, ND+NI, ND+NI+NII, ND+NI+NII+NIII,
};
/*
* Types of indirect and direct blocks
* by name.
*/
char *btypes[] = {
"direct",
"indirect",
"double indirect",
"triple indirect",
};
int sflag; /* Repair filesystem */
int vflag; /* More verbose information */
int exstat; /* Final exit status -- bits from <check.h> */
FILE *fs; /* File system i/o stream pointer */
char *bitmap; /* Bit map for blocks */
daddr_t fsize = SUPERB+1; /* Allow read of super-block */
unsigned isize;
/* Various counters */
unsigned nfiles;
unsigned nreg;
unsigned ndir;
unsigned nbad; /* # of bad blocks */
unsigned nibad; /* # of bad blocks that were in ilist */
unsigned nbsp;
unsigned ncsp;
unsigned nmpx;
unsigned npipe;
long nblk;
long nfblk[4]; /* # of direct, single, double, and triple indirects */
long ndirb;
long nfreeb;
long nmissing;
long nfdup;
ino_t nifree;
long atol();
main(argc, argv)
char *argv[];
{
while (argc>1 && *argv[1]=='-') {
switch (argv[1][1]) {
case 'b':
nblock = 0;
while (blocks[nblock] = atol(argv[2])) {
if (nblock++ >= NBLOCK) {
fprintf(stderr, tmb);
exstat |= IC_MISC;
break;
}
argv++;
argc--;
}
break;
case 's':
sflag = 1;
break;
case 'v':
vflag = 1;
break;
default:
usage();
}
argc--;
argv++;
}
if (argc > 1)
allcheck(argv+1);
else
usage();
exit(exstat);
}
/*
* Check the given list of filesystems
*/
allcheck(fsl)
register char **fsl;
{
while (*fsl != NULL)
if (icheck(*fsl++))
return;
}
/*
* Check one filesystem
*/
icheck(fsname)
char *fsname;
{
struct filsys *sbp;
register struct dinode *ip;
register int i;
register ino_t inum;
register char *mode;
int thischunk;
daddr_t seek, limit;
struct defect *cdsp;
nfiles = 0;
nreg = 0;
ndir = 0;
ndirb = 0;
npipe = 0;
nbsp = 0;
ncsp = 0;
nmpx = 0;
nblk = 0;
nbad = 0;
nibad = 0;
for (i=0; i<4; i++)
nfblk[i] = 0;
nmissing = 0;
nfdup = 0;
nfreeb = 0;
nifree = 0;
freeip = freei;
mode = sflag ? "r+w" : "r";
if ((fs = fopen(fsname, mode)) == NULL) {
fprintf(stderr, "%s: cannot open\n", fsname);
exstat |= IC_MISC;
return;
}
printf("%s:\n", fsname);
if (!sflag)
sync();
bread((daddr_t)SUPERB, superb);
sbp = superb;
canint(sbp->s_isize);
candaddr(sbp->s_fsize);
canshort(sbp->s_nfree);
for (i=0; i<NICFREE; ++i)
candaddr(sbp->s_free[i]);
canshort(sbp->s_ninode);
for (i=0; i<NICINOD; ++i)
canino(sbp->s_inode[i]);
cantime(sbp->s_time);
candaddr(sbp->s_tfree);
canino(sbp->s_tinode);
canshort(sbp->s_m);
canshort(sbp->s_n);
canlong(sbp->s_unique);
fsize = sbp->s_fsize;
isize = sbp->s_isize;
if (isize<INOORG+1 || isize>=fsize || fsize<INOORG+1)
cerr("Ridiculous fsize/isize");
if ((bitmap=calloc((int)((fsize+NBPC-1)/NBPC), sizeof(char))) == NULL)
cerr("No space for bitmap");
bmark((daddr_t)BOOTB, "bootstrap", 0);
bmark((daddr_t)SUPERB, "super block", 0);
finddefective();
nblk = isize;
inum = 1;
seek = INOORG;
cdsp = deflist;
while (seek < isize) {
if (cdsp!=NULL && cdsp->d_start==seek) {
nibad += cdsp->d_length;
seek += cdsp->d_length;
inum += cdsp->d_length*INOPB;
cdsp = cdsp->d_next;
continue;
}
limit = seek+IBLK;
if (cdsp!=NULL && limit>cdsp->d_start)
limit = cdsp->d_start;
if (limit > isize)
limit = isize;
thischunk = limit-seek;
lseek(fileno(fs), seek*BSIZE, 0);
for (i=0; i<thischunk; ++i)
bmark((daddr_t)seek++, "inodes", 0);
thischunk *= BSIZE;
if (read(fileno(fs), ibuf, thischunk) != thischunk) {
fprintf(stderr, "I-node read error\n");
exstat |= IC_HARD;
break;
}
ip = (struct dinode *) &ibuf[0];
while (ip < (struct dinode *) &ibuf[thischunk]) {
if (inum != BADFIN) {
canshort(ip->di_mode);
canshort(ip->di_nlink);
canshort(ip->di_uid);
canshort(ip->di_gid);
cansize(ip->di_size);
cantime(ip->di_atime);
cantime(ip->di_mtime);
cantime(ip->di_ctime);
ilook(ip, inum);
}
++inum;
++ip;
}
}
freecount();
free(bitmap);
freedefective();
if (nmissing != 0)
exstat |= IC_MISS;
if (nfdup != 0)
exstat |= IC_DUPF;
if (!sflag && vflag) {
printf("f=%u,r=%u,d=%u,b=%u,c=%u,m=%u,p=%u\n", nfiles, nreg,
ndir, nbsp, ncsp, nmpx, npipe);
printf("blks=%D, dirb=%D, d=%D, i=%D, ii=%D, iii=%D\n",
nblk, ndirb, nfblk[0], nfblk[1], nfblk[2], nfblk[3]);
printf("free = %D\n", nfreeb);
printf("bad=%u (%u in I-list)\n", nbad, nibad);
}
if (!sflag) {
if (nmissing != 0)
printf("missing = %D\n", nmissing);
if (nfdup != 0)
printf("%D dups in free\n", nfdup);
if (sbp->s_tinode != nifree) {
printf("Bad ifree list\n");
exstat |= IC_BFB;
}
}
if (sflag)
makesuper();
fclose(fs);
return (0);
}
/*
* Look at each inode marking used blocks
* and checking consistency.
*/
ilook(ip, inum)
register struct dinode *ip;
ino_t inum;
{
daddr_t addrs[NADDR];
register i, l;
int flag;
if (ip->di_mode == 0) {
if (freeip < &freei[NICFREE])
*freeip++ = inum;
nifree++;
return;
}
nfiles++;
flag = PLAIN;
switch (ip->di_mode & IFMT) {
case IFREG:
nreg++;
break;
case IFDIR:
ndir++;
flag = DIR;
break;
case IFBLK:
nbsp++;
return;
case IFCHR:
ncsp++;
return;
case IFPIPE:
npipe++;
return;
case IFMPB:
case IFMPC:
nmpx++;
return;
default:
printf("%u: Bad filetype %o\n", inum, ip->di_mode&IFMT);
return;
}
l3tol(addrs, ip->di_addr, NADDR);
for (i = NADDR-1; i >= 0; i--)
for (l=1; l<=4; l++)
if (i < offsets[l]) {
crawldown(addrs[i], l-1, flag, inum);
break;
}
}
/*
* Crawl down through `lev' levels
* of indirect blocks, starting at block
* `bn'. The `ino' argument is the inumber that
* started this all off; is just gets passed
* to `bmark'. The `flag' tells you what kind
* of blocks you have at level 0 (in can be BAD,
* DIR or PLAIN).
*/
crawldown(bn, lev, flag, ino)
daddr_t bn;
int lev;
ino_t ino;
{
register char *bp;
register char *type;
register int i;
if (bn == 0)
return;
nblk++;
if (lev==0 && flag==DIR) {
type = "dir";
ndirb++;
} else if (lev==0 && flag==BAD) {
type = "bad";
nbad++;
} else {
type = btypes[lev];
nfblk[lev]++;
}
if (bmark(bn, type, ino))
return;
if (lev==0 && flag==BAD)
savedefective(bn);
if (lev-- > 0) {
bread(bn, bp = idbuf[lev]);
for (i=0; i<NBN; i++) {
bn = ((long *)bp)[i];
candaddr(bn);
crawldown(bn, lev, flag, ino);
}
}
}
/*
* This routine finds all of the
* defective space on the filsystem by reading
* the bad block file and marking all the blocks.
* The defective space list, used by the I-list
* scanner and other guys, is constructued.
*/
finddefective()
{
register struct dinode *ip;
register i, level;
daddr_t addrs[NADDR];
++nfiles;
lseek(fileno(fs), (long)iblockn(BADFIN)*BSIZE, 0);
if (read(fileno(fs), ibuf, BSIZE) != BSIZE) {
printf("I/O error reading bad block inode\n");
exstat |= IC_HARD;
return;
}
ip = (struct dinode *) &ibuf[0] + iblocko(BADFIN);
canshort(ip->di_mode);
if (ip->di_mode == 0)
return;
if ((ip->di_mode&IFMT) != IFREG) {
printf("Bad block file has bad mode\n");
exstat |= IC_HARD;
return;
}
l3tol(addrs, ip->di_addr, NADDR);
for (i=NADDR-1; i>=0; --i) {
for (level=1; level<=4; ++level) {
if (i < offsets[level]) {
crawldown(addrs[i], level-1, BAD, BADFIN);
break;
}
}
}
}
/*
* Free all of the nodes
* in the defective space list.
*/
freedefective()
{
register struct defect *cdsp1, *cdsp2;
cdsp1 = deflist;
deflist = NULL;
while (cdsp1 != NULL) {
cdsp2 = cdsp1->d_next;
free((char *) cdsp1);
cdsp1 = cdsp2;
}
}
/*
* Add a new, defective block
* into the sorted defective block chain.
* Merge this block with the ends of
* any existing entries. No check is made
* for entries fusing; bad blocks get scooped
* (in general) up in order, and the bad blocks
* are generally sparsely placed on the disc.
*/
savedefective(bn)
daddr_t bn;
{
register struct defect *cdsp1, *cdsp2, *cdsp3;
cdsp1 = NULL;
cdsp2 = deflist;
while (cdsp2!=NULL && bn>cdsp2->d_start) {
cdsp1 = cdsp2;
cdsp2 = cdsp2->d_next;
}
if (cdsp1!=NULL && bn==cdsp1->d_start+cdsp1->d_length) {
++cdsp1->d_length;
return;
}
if (cdsp2!=NULL && bn==cdsp2->d_start-1) {
--cdsp2->d_start;
++cdsp2->d_length;
return;
}
if ((cdsp3=(struct defect *)malloc(sizeof(struct defect))) == NULL)
cerr("Out of space for bad blocks");
if (cdsp1 == NULL)
deflist = cdsp3; else
cdsp1->d_next = cdsp3;
cdsp3->d_next = cdsp2;
cdsp3->d_start = bn;
cdsp3->d_length = 1;
}
/*
* Look at the free count for a filesystem
* by chasing down the free-list.
*/
freecount()
{
register char *bmp;
register struct fblk *fbp;
struct filsys *sbp;
register unsigned i;
daddr_t bn;
long ntfree;
sbp = superb;
fbp = &sbp->s_nfree;
ntfree = sbp->s_tfree;
while ((i = fbp->df_nfree) != 0) {
if ((unsigned)(fbp->df_nfree) > NICFREE) {
badfreelist();
return;
}
for (i=0; i<fbp->df_nfree; i++) {
bn = fbp->df_free[i];
bmark(bn, "free", 0);
nfreeb++;
}
bread(fbp->df_free[0], fbuf);
fbp = fbuf;
canint(fbp->df_nfree);
for (i=0; i<NICFREE; ++i)
candaddr(fbp->df_free[i]);
}
/*
* Count number of blocks not in bitmap
*/
i = 1;
for (bn=0, bmp=bitmap; bn < fsize; bn++) {
if (i == 1<<NBPC) {
i = 1;
bmp++;
}
if ((*bmp & i) == 0)
nmissing++;
i <<= 1;
}
if (sflag)
nmissing -= isize + nfreeb;
if (nfreeb != ntfree) {
if (!sflag)
printf("Free list/tfree counts differ\n");
exstat |= IC_MISS;
}
}
/*
* Remake the superblock - reconstructing
* the free-list if sflag is set.
*/
makesuper()
{
register struct filsys *sbp;
register ino_t *fip;
register i;
daddr_t bn;
sbp = superb;
/*
* Remake list of free i-numbers.
*/
fip = sbp->s_inode;
sbp->s_ninode = freeip-freei;
while (freeip > freei)
*fip++ = *--freeip;
while (fip < &sbp->s_inode[NICFREE])
*fip++ = 0;
sbp->s_tinode = nifree;
/*
* Free all remaining blocks
* and write last one as tail of free-list
*/
sbp->s_nfree = 0;
sbp->s_tfree = 0;
bn = fsize;
for (bn=fsize-1; bn>=isize; --bn)
if (!test(bn))
bfree(bn);
canint(sbp->s_isize);
candaddr(sbp->s_fsize);
canshort(sbp->s_nfree);
for (i=0; i<NICFREE; ++i)
candaddr(sbp->s_free[i]);
canshort(sbp->s_ninode);
for (i=0; i<NICINOD; ++i)
canino(sbp->s_inode[i]);
cantime(sbp->s_time);
candaddr(sbp->s_tfree);
canino(sbp->s_tinode);
canshort(sbp->s_m);
canshort(sbp->s_n);
canlong(sbp->s_unique);
bwrite((daddr_t)SUPERB, sbp);
}
/*
* Free a block and, in so doing, construct
* the free list chain.
*/
bfree(bn)
daddr_t bn;
{
register struct filsys *sbp;
register struct fblk *fbp;
register i;
sbp = superb;
if (sbp->s_tfree == 0) {
bclear(fbuf, BSIZE);
bwrite(bn, fbuf);
}
if (sbp->s_nfree == NICFREE) {
bclear(fbp = fbuf, BSIZE);
fbp->df_nfree = sbp->s_nfree;
canint(fbp->df_nfree);
for (i=0; i<sbp->s_nfree; ++i) {
fbp->df_free[i] = sbp->s_free[i];
candaddr(fbp->df_free[i]);
}
bwrite(bn, fbuf);
sbp->s_nfree = 0;
}
sbp->s_free[sbp->s_nfree++] = bn;
sbp->s_tfree++;
}
/*
* Read the specified block number
* into `buf'.
*/
bread(bn, buf)
daddr_t bn;
char *buf;
{
if (bn<0 || bn>=fsize) {
badblock(bn, "any", 0);
bclear(buf, BSIZE);
return;
}
lseek(fileno(fs), (size_t)BSIZE * bn, 0);
if (read(fileno(fs), buf, BSIZE) != BSIZE) {
fprintf(stderr, "Read error %D\n", (long)bn);
exstat |= IC_HARD;
bclear(buf, BSIZE);
}
}
/*
* Write block `bn' from `buf'.
*/
bwrite(bn, buf)
daddr_t bn;
char *buf;
{
if (bn<0 || bn>=fsize) {
badblock(bn, "any", 0);
return;
}
lseek(fileno(fs), (size_t)BSIZE * bn, 0);
if (write(fileno(fs), buf, BSIZE) != BSIZE) {
fprintf(stderr, "Write error %D\n", (long)bn);
exstat |= IC_HARD;
}
}
/*
* Mark block # `bn' as
* seen before an check for
* duplicates.
* Bmark only marks file blocks if `sflag' is
* set so that the free list can be constructed
* again.
* Return 1 when something is wrong.
*/
bmark(bn, type, inum)
daddr_t bn;
char *type;
ino_t inum;
{
register nb;
if (bn<0 || bn>=fsize) {
badblock(bn, type, inum);
return (1);
}
if (nb = nblock) {
register i;
for (i=0; i<nb; i++)
if (blocks[i] == bn)
printf("%D arg, class=%s, inode=%u\n",
(long)bn, type, inum);
}
{
register char *bp;
register int mask;
mask = 1 << ((unsigned)bn)%NBPC;
bp = bitmap + ((unsigned)bn)/NBPC;
if (*bp & mask) /* if (test(bn)) */
dupblock(bn, type, inum);
else if (!sflag || inum!=0)
*bp |= mask; /* mark(bn) */
}
return (0);
}
/*
* Clear a block of memory
* pointed to by `bp' for size
* `nb' bytes.
*/
bclear(bp, nb)
register char *bp;
register unsigned nb;
{
if (nb)
do {
*bp++ = 0;
} while (--nb);
}
/*
* Error routines
*/
badblock(bn, type, inum)
daddr_t bn;
char *type;
ino_t inum;
{
register int perr = 0;
if (strcmp(type, "free") != 0) {
perr++;
exstat |= IC_HARD;
} else {
exstat |= IC_BADF;
if (!sflag)
perr++;
}
if (perr)
printf("%D bad, class=%s, inode=%u\n", (long)bn, type, inum);
}
dupblock(bn, type, inum)
daddr_t bn;
char *type;
ino_t inum;
{
if (inum != 0)
exstat |= IC_HARD;
else
nfdup++;
if (vflag || inum!=0)
printf("%D dup, class=%s, inode=%u\n", (long)bn, type, inum);
}
badfreelist()
{
if (!sflag) {
printf("Bad freelist\n");
exstat |= IC_BFB;
}
}
/*
* Unrecoverable errors
*/
cerr(x)
{
printf("%r", &x);
putchar('\n');
exit(IC_MISC);
}
usage()
{
cerr("Usage: icheck [-sv] [-b bn ...] filesystem ...");
}
/*
* Block copy routine
*/
bcopy(in, out, nb)
register char *in, *out;
register unsigned nb;
{
if (nb)
do {
*out++ = *in++;
} while (--nb);
}