|
|
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: 8377 (0x20b9)
Types: TextFile
Notes: UNIX file
Names: »bad.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/bad.c«
/*
* For manipulating bad blocks.
*/
#include <stdio.h>
#include <canon.h>
#include <filsys.h>
#include <ino.h>
#include <inode.h>
/*
* For the C compiler.
*/
int addlist();
long atol();
char *bread();
char *bclaim();
char *index();
char *realloc();
daddr_t balloc();
int dellist();
/*
* Variables.
*/
struct filsys supb; /* Super block */
INODE inol; /* Bad block inode */
char bufl[1+NI][BSIZE]; /* Buffers for bread */
daddr_t bnol[1+NI]; /* Block numbers */
daddr_t *badl; /* Bad block list */
int badn; /* Number of bad blocks in list */
int badm; /* Maximum number of bad blocks */
int filf; /* Filesystem file descriptor */
main(argc, argv)
char *argv[];
{
register int i;
if (argc < 3)
usage();
if ((filf=open(argv[2], 2)) < 0)
panic("Cannot open %s", argv[2]);
badm = 64;
if ((badl=malloc(badm*sizeof(*badl))) == NULL)
panic("No memory");
switch (argv[1][0]) {
case 'a':
gather();
for (i=3; i<argc; i++)
route(argv[i], addlist);
update();
break;
case 'c':
update();
break;
case 'd':
gather();
for (i=3; i<argc; i++)
route(argv[i], dellist);
update();
break;
case 'l':
gather();
display();
break;
default:
usage();
}
}
/*
* Print out usage.
*/
usage()
{
panic("Usage: bad [acdl] <filesystem> <bad block list>");
}
/*
* Given a string and a pointer to a function, extract a list of block
* numbers from the string and call the function with them.
*/
route(cp1, f)
register char *cp1;
int (*f)();
{
register char *cp2;
register long b;
register long l;
if ((cp2=index(cp1, '-')) == NULL)
(*f)(atol(cp1));
else {
*cp2++ = '\0';
l = atol(cp2);
for (b=atol(cp1); b<=l; b++)
(*f)(b);
}
}
/*
* List the set of bad blocks.
*/
display()
{
register int i;
for (i=0; i<badn; i++)
printf("%ld\n", badl[i]);
}
/*
* Read the list of bad blocks into the bad block list.
*/
gather()
{
register int n;
register daddr_t b;
copydm();
for (n=0; n<ND; n++) {
if ((b=inol.i_a.i_addr[n]) != 0)
addlist(b);
}
for (n=ND; n<ND+NI; n++) {
if ((b=inol.i_a.i_addr[n]) != 0)
indlist(b, 1+n-ND);
}
}
/*
* Given an indirect block, `b', with level of indirection, `l', add all
* allocated blocks onto the bad block list.
*/
indlist(b, l)
daddr_t b;
register unsigned l;
{
register int i;
register char *bp;
daddr_t b1;
if (b == 0)
return;
if (l-- > 0) {
bp = bread(l, b);
for (i=0; i<NBN; i++) {
if ((b1=((daddr_t *)bp)[i]) == 0)
continue;
candaddr(b1);
if (l == 0)
addlist(b1);
else
indlist(b1, l);
}
}
}
/*
* Add the given block onto the end of the bad block list.
*/
addlist(b)
daddr_t b;
{
register int i;
register int n;
if (badn >= badm) {
badm *= 2;
if ((badl=realloc(badl, badm*sizeof(*badl))) == NULL)
panic("Out of memory");
}
for (i=0; i<badn; i++) {
if (b == badl[i])
panic("Duplicate bad block %ld", b);
if (b < badl[i])
break;
}
for (n=badn; n>i; --n)
badl[n] = badl[n-1];
badl[i] = b;
badn++;
}
/*
* Delete the given bad block from the bad block list.
*/
dellist(b)
daddr_t b;
{
register int n;
for (n=0; n<badn; n++) {
if (b == badl[n]) {
for (--badn; n<badn; n++)
badl[n] = badl[n+1];
return;
}
}
panic("Cannot find block %ld", b);
}
/*
* Update the bad block file.
*/
update()
{
register char *bp;
register int i;
bp = bread(0, (daddr_t)SUPERI);
strcopy(bp, (char *)&supb, sizeof(struct filsys));
cansuper(&supb);
for (i=0; i<ND+NI; i++)
inol.i_a.i_addr[i] = 0;
for (i=0; i<badn; i++)
block(i, badl[i]);
copymd();
bp = bread(0, (daddr_t)SUPERI);
strcopy((char *)&supb, bp, sizeof(supb));
cansuper((struct filsys *)bp);
bwrite(bp, (daddr_t)SUPERI);
}
/*
* Canonize the super block.
*/
cansuper(sbp)
register struct filsys *sbp;
{
register int i;
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);
}
/*
* Copy the bad block inode to memory performing canonization.
*/
copydm()
{
register struct dinode *dip;
register char *bp;
bp = bread(0, (daddr_t)iblockn(BADFIN));
dip = (struct dinode *)bp+iblocko(BADFIN);
inol.i_mode = dip->di_mode;
canshort(inol.i_mode);
inol.i_nlink = dip->di_nlink;
canshort(inol.i_nlink);
inol.i_uid = dip->di_uid;
canshort(inol.i_uid);
inol.i_gid = dip->di_gid;
canshort(inol.i_gid);
inol.i_size = dip->di_size;
cansize(inol.i_size);
l3tol(inol.i_a.i_addr, dip->di_addr, NADDR);
inol.i_atime = dip->di_atime;
cantime(inol.i_atime);
inol.i_mtime = dip->di_mtime;
cantime(inol.i_mtime);
inol.i_ctime = dip->di_ctime;
cantime(inol.i_ctime);
return (1);
}
/*
* Copy the bad block inode to disk performing canonization.
*/
copymd()
{
register struct dinode *dip;
register char *bp;
bp = bread(0, (daddr_t)iblockn(BADFIN));
dip = (struct dinode *)bp+iblocko(BADFIN);
dip->di_mode = IFREG;
canshort(dip->di_mode);
dip->di_nlink = inol.i_nlink;
canshort(dip->di_nlink);
dip->di_uid = inol.i_uid;
canshort(dip->di_uid);
dip->di_gid = inol.i_gid;
canshort(dip->di_gid);
dip->di_size = badn*BSIZE;
cansize(dip->di_size);
ltol3(dip->di_addr, inol.i_a.i_addr, NADDR);
dip->di_atime = inol.i_atime;
cantime(dip->di_atime);
dip->di_mtime = inol.i_mtime;
cantime(dip->di_mtime);
dip->di_ctime = inol.i_ctime;
cantime(dip->di_ctime);
bwrite(bp, (daddr_t)iblockn(BADFIN));
}
/*
* Make the physical block, `b', logical block, `n' of the bad block file.
*/
block(n, b)
register int n;
register daddr_t b;
{
register daddr_t pb;
register char *bp;
register daddr_t pbb;
register char *bpp;
if (n < ND) {
inol.i_a.i_addr[n] = b;
return;
}
n -= ND;
if (n < NBN) {
if ((pb=inol.i_a.i_addr[ND]) != 0)
bp = bread(1, pb);
else {
inol.i_a.i_addr[ND] = pb = balloc();
bp = bclaim(1);
}
((daddr_t *)bp)[n] = b;
candaddr(((daddr_t *)bp)[n]);
bwrite(bp, pb);
return;
}
n -= NBN;
if (n < NBN*NBN) {
if ((pbb=inol.i_a.i_addr[ND+1]) != 0)
bpp = bread(2, pbb);
else {
inol.i_a.i_addr[ND+1] = pbb = balloc();
bpp = bclaim(2);
}
pb = ((daddr_t *)bpp)[n/NBN];
candaddr(pb);
if (pb != 0)
bp = bread(1, pb);
else {
((daddr_t *)bpp)[n/NBN] = pb = balloc();
candaddr(((daddr_t *)bpp)[n/NBN]);
bwrite(bpp, pbb);
bp = bclaim(1);
}
((daddr_t *)bp)[n%NBN] = b;
candaddr(((daddr_t *)bp)[n%NBN]);
bwrite(bp, pb);
return;
}
panic("Bad block file too large");
}
/*
* Allocate a block from our filesystem.
*/
daddr_t
balloc()
{
register struct fblk *fbp;
register daddr_t b;
register int i;
next:
if (supb.s_tfree==0 || (b=supb.s_free[--supb.s_nfree])==0)
panic("Out of space on filesystem");
if (supb.s_nfree == 0) {
fbp = (struct fblk *)bread(0, b);
supb.s_nfree = fbp->df_nfree;
canshort(supb.s_nfree);
for (i=0; i<sizeof(supb.s_free); i++) {
supb.s_free[i] = fbp->df_free[i];
candaddr(supb.s_free[i]);
}
}
--supb.s_tfree;
if (b>=supb.s_fsize || b<supb.s_isize)
panic("Bad block %u (alloc)", (unsigned)b);
for (i=0; i<badn; i++)
if (b == badl[i])
goto next;
return (b);
}
/*
* Given a buffer number, claim the buffer.
*/
char *
bclaim(l)
{
register char *bp;
register int n;
n = BSIZE;
bp = bufl[l];
do {
*bp++ = 0;
} while (--n);
return (bufl[l]);
}
/*
* Given a buffer number, read the given block into the given buffer and
* return a pointer to the buffer.
*/
char *
bread(l, b)
daddr_t b;
{
register char *bp;
bp = bufl[l];
if (b != bnol[l]) {
lseek(filf, (long)b*BSIZE, 0);
if (read(filf, bp, BSIZE) != BSIZE)
panic("Read error on block %ld", b);
bnol[l] = b;
}
return (bp);
}
/*
* Given a pointer to a buffer, write it out as the given block.
*/
bwrite(bp, b)
char *bp;
daddr_t b;
{
lseek(filf, (long)b*BSIZE, 0);
if (write(filf, bp, BSIZE) != BSIZE)
panic("Write error on block %ld", b);
}
/*
* Copy `n' bytes from `bp1' to `bp2'.
*/
strcopy(bp1, bp2, n)
register char *bp1;
register char *bp2;
register unsigned n;
{
if (n == 0)
return;
do {
*bp2++ = *bp1++;
} while (--n);
}
/*
* Print out an error message and exit.
*/
panic(a1)
char *a1;
{
fprintf(stderr, "%r", &a1);
fprintf(stderr, "\n");
exit(1);
}