|
|
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: 12762 (0x31da)
Types: TextFile
Notes: UNIX file
Names: »dcheck.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/dcheck.c«
/*
* Rec'd from Lauren Weinstein, 7-16-84.
* Dcheck - check consistency of directory
* graph structure for a filesystem.
* and optionally repair faulty link counts.
*/
#include <stdio.h>
#include <filsys.h>
#include <fblk.h>
#include <dir.h>
#include <sys/ino.h>
#include <check.h>
#include <canon.h>
#define IBLK 12 /* I-node read blocking factor */
#define NINUM 20 /* Maximum number of i-numbers to look for */
#undef NI
#define NI 1
#define NII 1
#define NIII 1
#define INOORG 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 */
};
/*
* Tables used by imap.
* This effectively implements
* the access polynomial for the indirect
* blocks.
*/
static daddr_t ranges[] = {
ND,
ND + (daddr_t)NI*NBN,
ND + (daddr_t)NI*NBN + (daddr_t)NII*NBN*NBN,
ND + (daddr_t)NI*NBN + (daddr_t)NII*NBN*NBN + (daddr_t)NIII*NBN*NBN*NBN,
};
static char offsets[] = {
0,
ND,
ND+NI,
ND+NI+NII,
};
static daddr_t coeff[] = {
1, (daddr_t)NBN, (daddr_t)NBN*NBN, (daddr_t)NBN*NBN*NBN
};
char tmi[] = "Too many i-numbers given\n";
char irderr[] = "I-node read error -- pass %d\n";
int ninumber;
ino_t inums[NINUM];
struct defect *deflist;
char superb[BSIZE];
char ibuf[BSIZE*IBLK];
char dbuf[BSIZE];
int sflag; /* Repair filesystem */
int exstat; /* Exit status */
FILE *fs; /* File system i/o stream pointer */
daddr_t fsize = SUPERI+1; /* Allow read of super-block */
ino_t isize;
ino_t maxino;
unsigned nhard; /* Hard things requiring pass 3 to fix */
short unsigned *entries;
daddr_t imap();
int imark();
int icompare();
main(argc, argv)
char *argv[];
{
while (argc>1 && *argv[1]=='-') {
switch (argv[1][1]) {
case 'i':
ninumber = 0;
while(inums[ninumber] = atoi(argv[2])) {
if (ninumber++ >= NINUM) {
fprintf(stderr, tmi);
exstat |= DC_MISC;
break;
}
argv++;
argc--;
}
break;
case 's':
sflag = 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)
dcheck(*fsl++);
}
/*
* Check one filesystem
*/
dcheck(fsname)
char *fsname;
{
register i;
struct filsys *sbp;
char *mode;
mode = sflag ? "r+w" : "r";
if ((fs = fopen(fsname, mode)) == NULL) {
fprintf(stderr, "%s: cannot open\n", fsname);
exstat |= DC_MISC;
return;
}
printf("%s:\n", fsname);
if (!sflag)
sync();
bread((daddr_t)SUPERI, superb);
sbp = superb;
canshort( 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);
fsize = sbp->s_fsize;
isize = sbp->s_isize;
if (isize<INODEI+1 || isize>=fsize)
cerr("Ridiculous fsize/isize");
if ((entries=calloc(isize*INOPB, sizeof(short unsigned))) == NULL)
cerr("Not enough space");
finddefective();
maxino = (isize-INODEI) * INOPB;
/*
* The first pass runs down the
* graph filling in the array
* `entries' which is the number
* of names found in directories for
* any i-node.
*/
entries[ROOTIN-1]++;
pass(0, imark);
/*
* In the next pass, link counts
* in the i-nodes are compared with
* those pre-computed for the graph.
*/
pass(1, icompare);
/*
* This fixup pass is only
* required for some harder errors
* encountered in `-s' mode.
*/
if (nhard && sflag)
pass(2, imark);
free(entries);
freedefective();
nhard = 0;
fclose(fs);
}
/*
* A generalised pass over all i-nodes, calls
* the routine `func' for every i-node encountered.
* `n' is the pass number, used only in the diagnostics.
*/
pass(n, func)
int n;
int (*func)();
{
register struct dinode *ip;
register ino_t inum;
daddr_t seek, limit;
int thischunk;
struct defect *cdsp;
inum = 1;
seek = INOORG;
cdsp = deflist;
while (seek < isize) {
if (cdsp!=NULL && cdsp->d_start==seek) {
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);
seek += thischunk;
thischunk *= BSIZE;
if (read(fileno(fs), ibuf, thischunk) != thischunk) {
fprintf(stderr, irderr, n);
exstat |= DC_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);
if ((*func)(ip, inum, n))
return;
}
++inum;
++ip;
}
}
}
/*
* Check an i-node link count (in
* pass 2) against the entries already
* found.
*/
icompare(ip, inum, pn)
register struct dinode *ip;
register ino_t inum;
int pn;
{
register unsigned nent;
nent = entries[inum-1];
entries[inum-1] = 0;
if (nent != ip->di_nlink
|| (ip->di_mode!=0 && ip->di_nlink==0))
badnlink(ip, inum, nent);
return (0);
}
/*
* Report or fix up bad link count
* in filesystem.
* `entries' is the number found.
*/
badnlink(ip, ino, nent)
register struct dinode *ip;
ino_t ino;
int nent;
{
static int needtitle = 1;
if (sflag == 0) {
if (needtitle != 0) {
printf(" Ino Entries Link\n");
needtitle = 0;
}
printf("%4u %7u %6u", ino, nent, ip->di_nlink);
if (ip->di_mode!=0 && ip->di_nlink==0)
printf(" (u)");
putchar('\n');
}
if (nent == 0) {
if (sflag) {
bclear((char *) ip, sizeof (*ip));
iwrite(ip, ino);
} else
exstat |= DC_CLRI;
} else if (ip->di_mode != 0) {
if (sflag) {
ip->di_nlink = nent;
iwrite(ip, ino);
} else
exstat |= DC_LCE;
} else if (ip->di_mode==0 && ip->di_nlink==0) {
nhard++;
entries[ino-1] = nent;
}
}
/*
* Imark looks at all directory i-nodes
* and marks all of the subordinate nodes
* in the entries table. It also checks for
* argument i-numbers to list specially.
* Returns non-zero if we should stop
* i-list scanning in `pass'.
*/
imark(ip, inum, pn)
register struct dinode *ip;
register ino_t inum;
int pn;
{
size_t size;
daddr_t pb;
register daddr_t bn;
if (ip->di_mode == 0)
return (0);
if ((ip->di_mode&IFMT) != IFDIR)
return (0);
size = ip->di_size;
bn = 0;
if (pn==1 && (size % sizeof(struct direct))!=0) {
printf("I#%u: Directory size not mod %d\n", inum,
sizeof(struct direct));
size -= size % sizeof( struct direct);
}
while (size) {
register struct direct *dp;
if ((pb = imap(ip, bn++)) == 0)
break;
bread(pb, dbuf);
for (dp=dbuf; dp < &dbuf[BSIZE]; dp++) {
canino( dp->d_ino);
if (dp->d_ino) {
if (dp->d_ino > maxino)
dirline(inum, dp, "bad");
else if (pn == 0)
entries[dp->d_ino-1]++;
else {
if (entries[dp->d_ino-1]) {
if (--entries[dp->d_ino-1] == 0)
nhard--;
bclear(dp, sizeof(*dp));
bwrite(pb, dbuf);
}
}
if (ninumber)
iarg(inum, dp);
}
size -= sizeof( struct direct);
if (size == 0)
break;
}
}
if (pn==0)
return (0);
return (nhard == 0);
}
/*
* Iarg checks if the directory i-number is in
* the argument list of i-nodes, and if it is
* prints this out.
*/
iarg(inum, dp)
register ino_t inum;
register struct direct *dp;
{
register unsigned i;
for (i=0; i<ninumber;)
if (inums[i++] == dp->d_ino)
dirline(inum, dp, "arg");
}
/*
* Print out a line for a directory
* that is found in the search (.e.g.
* bad or argument directories).
*/
dirline(ino, dp, str)
ino_t ino;
register struct direct *dp;
char *str;
{
printf("%u %s: %u/%-*.*s\n", dp->d_ino, str, ino,
DIRSIZ, DIRSIZ, dp->d_name);
}
/*
* 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;
daddr_t pb, lb;
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;
}
lb = 0;
while ((pb=imap(ip, lb++)) != 0)
savedefective(pb);
}
/*
* 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;
}
/*
* For a given inode (`ip'),
* map a logical block number (`bn')
* onto a physical disc block number.
*/
daddr_t
imap(ip, lb)
register struct dinode *ip;
daddr_t lb;
{
register il;
daddr_t bpos, pb;
register daddr_t *bp;
register daddr_t addrs[NADDR];
l3tol(addrs, ip->di_addr, NADDR);
for (il=0; il<4; il++)
if (lb < ranges[il]) {
if (il != 0)
lb -= ranges[il-1];
bpos = lb/coeff[il];
lb %= coeff[il];
bp = &addrs[(int)bpos + offsets[il]];
if ((pb = *bp) != 0) {
/*
* Map through indirect
* blocks here.
*/
while (il-- > 0) {
bread(pb, dbuf);
bpos = lb/coeff[il];
lb %= coeff[il];
bp = (daddr_t *)dbuf + bpos;
if ((pb = *bp) == 0)
break;
pb = *bp;
candaddr( pb);
}
}
return (pb);
}
return (0);
}
/*
* Read the specified block number
* into `buf'.
*/
bread(bn, buf)
daddr_t bn;
char *buf;
{
if (bn >= fsize) {
badblock(bn, "any");
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 |= DC_HARD;
bclear(buf, BSIZE);
}
}
/*
* Write block `bn' from `buf'.
*/
bwrite(bn, buf)
daddr_t bn;
char *buf;
{
if (bn >= fsize) {
badblock(bn, "any");
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 |= DC_HARD;
}
}
/*
* Put out an i-node to disc.
* Used only for `-s' option.
*/
iwrite(ip, ino)
register struct dinode *ip;
register ino_t ino;
{
register struct dinode *ip2;
daddr_t bn;
bn = iblockn(ino);
bread(bn, dbuf);
ip2 = &((struct dinode *)dbuf)[iblocko( ino)];
*ip2 = *ip;
canshort( ip2->di_mode);
canshort( ip2->di_nlink);
canshort( ip2->di_uid);
canshort( ip2->di_gid);
cansize( ip2->di_size);
cantime( ip2->di_atime);
cantime( ip2->di_mtime);
cantime( ip2->di_ctime);
bwrite(bn, dbuf);
}
/*
* 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)
daddr_t bn;
{
printf("Bad block #%D\n", (long)bn);
exstat |= DC_HARD;
}
/*
* Unrecoverable errors
*/
cerr(x)
{
printf("%r", &x);
putchar('\n');
exit(DC_MISC);
}
usage()
{
cerr("Usage: dcheck [-s] [-i ino ...] filesystem ...");
}
/*
* Block copy routine
*/
bcopy(in, out, nb)
register char *in, *out;
register unsigned nb;
{
if (nb)
do {
*out++ = *in++;
} while (--nb);
}