V10/cmd/chuck/repairs.c
#include "fs.h"
repairs()
{ int i, j, k;
if(erptr <= 0) {
pmesg("all ok\n");
return;
}
i = errcnts[Einvalid] + errcnts[Esuperino] + errcnts[Esuperfree]
+ errcnts[Efreelist];
if(!flags['i'] && i == erptr) {
pmesg("fixing super block\n");
fixfree();
if(!flags['w'])
return;
if(bwrite(1, (char *)&sblk, 1))
fatal("write failed\n");
pmesg("done\n");
return;
}
if(!flags['i'] && i + errcnts[Enullable] == erptr) {
pmesg("clearing %d inodes safely\n", errcnts[Enullable]);
/* even if it is a directory. no links means Edot, Edotdot... */
for(j = 0; j < erptr; j++)
if(erlist[j].type == Enullable)
clri(erlist[j].a);
fixfree();
return;
}
/* now we enter upon the realm of the speculative */
if(!flags['i'] && !errcnts[Edup]) {
pmesg("hi ho hi ho, it's off to work we go\n");
if(j = errcnts[Enullable])
pmesg("clearing %d inodes safely\n", j);
for(j = 0; j < erptr; j++)
switch(erlist[j].done? 0: erlist[j].type) {
case 0:
continue;
default:
pmesg("%s %d %d, not handled\n", errnm(erlist[j].type),
erlist[j].a, erlist[j].b);
exitcode++;
continue;
case Ehole:
pmesg("%s ends with a hole, remove or copy\n", prino(erlist[j].a));
continue;
case Enullable:
clri(erlist[j].a);
erlist[j].done = 1;
continue;
case Enotdot: case Enotdotdot: case Edotino: case Ebadparent:
k = erlist[j].a;
if(k > ROOTINO)
fixdots(k);
continue;
case Elinkcnt:
k = erlist[j].a;
if(imap[k].type == Weird) {
if(fixweird(k))
continue;
pmesg("weird ino %d (strange type): fix manually\n", k);
exitcode = 1;
continue;
}
if(imap[k].nrefs == 0)
attach(k);
else if(imap[k].type != Unalloc)
fixlinks(erlist[j].a);
else if(imap[k].nrefs == 1)
expunge(k);
else {
pmesg("%s has %d references! Expunging.\n", prino(k),
imap[k].nrefs);
expunge(k);
exitcode = 1; /* things are not ok */
continue;
}
erlist[j].done = 1;
continue;
case Ebadname:
pmesg("%s has a weird name, look at it\n", prino(erlist[j].b));
fixnames(erlist[j].a);
continue;
case Ebadino: /* these are lost files */
pmesg("removing bad inos from %s\n", prino(erlist[j].a));
fixnames(erlist[j].a);
continue;
case Einvalid: case Efreelist: case Esuperino:
continue; /* fixfree() comes later */
case Eattach:
attach(erlist[j].a);
erlist[j].done = 1;
continue;
case Efakeroot:
attach(erlist[j].a);
fixdots(erlist[j].a);
continue;
}
fixfree();
return;
}
rpterrs();
if(flags['i'])
interact();
else
exitcode = 1;
}
rpterrs()
{ int i, j, k, cnts[32];
struct dinode *dp;
if(erptr > 30 && !flags['v']) {
pmesg("%d errors\n", erptr);
for(i = 0; i < 32; i++)
cnts[i] = 0;
for(i = 0; i < erptr; i++)
cnts[erlist[i].type]++;
for(i = 0; i < 32; i++)
if(cnts[i])
pmesg("%s\t%d\n", errnm(i), cnts[i]);
return;
}
for(i = 0; i < erptr; i++)
switch(erlist[i].type) {
default:
pmesg("%s %d %d\n", errnm(erlist[i].type),
erlist[i].a, erlist[i].b);
continue;
case Efakeroot:
pmesg("own parent %s\n", prino(erlist[i].a));
continue;
case Edup:
j = erlist[i].b;
k = bmap[erlist[i].a].ino;
pmesg("dup block %d %s %s\n", erlist[i].a, prino(j), prino(k));
continue;
case Elinkcnt:
j = erlist[i].a;
dp = (struct dinode *)(buf + 2*bsize + (j-1)*sizeof(*dp));
pmesg("Elinkcnt(%s) refs %d(parent %s)\n", prino(j), imap[j].nrefs,
prino(imap[j].parent));
continue;
case Ebadparent:
j = erlist[i].a;
k = erlist[i].b;
pmesg("Ebadparent: (%s) not in (%s)\n", prino(j), prino(k));
continue;
case Ebadname:
j = erlist[i].a;
k = erlist[i].b;
pmesg("Ebadname (%s) (in %s)\n", prino(j), prino(k));
continue;
}
}
fixfree()
{ int i, j, *p;
sblk.s_ninode = sblk.s_tfree = 0;
sblk.s_tinode = tinode;
for(i = 2, j = 0; i < ninode && j < NICINOD; i++)
if(imap[i].type == Unalloc) {
sblk.s_inode[j++] = i;
sblk.s_ninode++;
}
sblk.s_lasti = sblk.s_inode[0];
sblk.s_nbehind = 0;
if(bsize < 4096) { /* stupid test, FIX */
fix1free();
return;
}
if(pblk > lblk) {
for(i = 0; i < BITMAP; i++)
sblk.U.B.S_bfree[i] = 0;
memset(freeb, 0, (pblk-lblk)*bsize);
for(j = i = 0, p = (long *) freeb; i < pblk; i++, j++) {
if(j >= 32) {
j = 0;
p++;
}
if(bmap[i].type == Free || bmap[i].type == Unk) {
sblk.s_tfree++;
*p |= (1 << j);
}
}
if(bwrite(lblk, freeb, pblk-lblk)) {
exitcode = 1;
pmesg("bit map block write failed\n");
}
}
else {
for(i = 0, p = sblk.U.B.S_bfree; i < BITMAP; i++)
*p++ = 0;
for(i = fblk, j = 0, p = sblk.U.B.S_bfree; i < pblk; i++, j++) {
if(j >= 32) {
j = 0;
p++;
}
if(bmap[i].type == Free || bmap[i].type == Unk) {
sblk.s_tfree++;
*p |= (1 << j);
}
}
}
sblk.U.B.S_valid = 1;
if(!flags['w'])
return;
if(bwrite(1, (char *)&sblk, 1))
fatal("super block write failed\n");
}
fix1free()
{ /* fix this someday FIX */
pmesg("get fsck to fix the free list!\n");
if(!flags['w'])
return;
if(bwrite(1, (char *)&sblk, 1))
fatal("super block write failed\n");
}
fixweird(n)
{ struct dinode *dp;
dp = (struct dinode *) (buf + (n-1)*sizeof(*dp) + 2*bsize);
if(dp->di_mode)
return(0);
if(dp->di_size > 0)
return(0);
if(imap[n].nrefs > 1)
return(0);
pmesg("removing weird ino %s\n", prino(n));
if(imap[n].nrefs == 1)
expunge(n);
else {
clri(n);
pmesg("and rerun chuck\n");
}
return(1);
}
fixlinks(n)
{ struct dinode *dp;
dp = (struct dinode *) (buf + (n-1)*sizeof(*dp) + 2*bsize);
if(imap[n].type == Unalloc) {
pmesg("ino %d unallocated, link count unadjusted\n", n);
return;
}
pmesg("%s getting %d as links\n", prino(n), imap[n].nrefs);
dp->di_nlink = imap[n].nrefs;
if(flags['w'])
wrti(n);
}
wrti(n) /* write the block of inodes containing inode n */
{ int i;
i = (n-1)/inopb + 2;
if(bwrite(i, buf + i*bsize, 1))
pmesg("write of block containing ino %d failed\n", n);
}
clri(n)
{ struct dinode *dp;
static struct dinode nild;
dp = (struct dinode *) (buf + (n-1)*sizeof(*dp) + 2*bsize);
switch(imap[n].type) {
case Dir: case Reg: case Lnk:
tossblocks(n);
}
*dp = nild;
imap[n].type = Unalloc;
tinode++;
if(flags['w'])
wrti(n);
}
tossblocks(n)
{ struct dinode *dp;
int addr[NADDR], i;
dp = (struct dinode *) (buf + (n-1)*sizeof(*dp) + 2*bsize);
l3tol(addr, dp->di_addr, NADDR);
for(i = 1; i < NADDR-3; i++)
if(addr[i]) {
bmap[addr[i]].type = Free;
tfree++;
}
if(addr[10])
freeind(addr[10]);
if(addr[11])
freedbl(addr[10]);
if(addr[12])
pmesg("ino %d, triply indirect block? rerun chuck to fix free list\n",
n);
}
freeind(n)
{ int i, *p;
bmap[n].type = Free;
if(bread(n, buf, 1))
fatal("freeind, could't read block %d\n", n);
for(i = 0, p = (int *)buf; i < bsize/sizeof(int); i++, p++)
if(*p) {
bmap[*p].type = Free;
tfree++;
}
}
freedbl(n)
{ int i, *p;
bmap[n].type = Free;
if(bread(n, buf+bsize, 1))
fatal("freeind2, couldn't read %d\n", n);
for(i = 0, p = (int *)(buf+bsize); i < bsize/sizeof(int); i++, p++)
if(*p)
freeind(n);
}
interact()
{ int i, j;
struct dinode *dp;
for(i = 0; i < erptr; i++)
switch(erlist[i].type) {
default:
pmesg("%s not yet doable\n", errnm(erlist[i].type));
continue;
case Enotdot:
pmesg("Enotdot (dot not self) %s\n", prino(erlist[i].a));
continue;
case Edotino:
pmesg("Edotino (dot illegal) %s\n", prino(erlist[i].a));
continue;
case Enotdotdot:
pmesg("Enotdotdot (dotdot illegal) %s\n", prino(erlist[i].a));
continue;
case Ebadparent:
pmesg("Ebadparent (dotdot not parent) %s\n", prino(erlist[i].a));
continue;
case Elinkcnt:
j = erlist[i].a;
dp = (struct dinode *) (buf + 2*bsize + (j-1)*sizeof(*dp));
pmesg("Elinkcnt, %s, %d links %d refs\n", prino(j), dp->di_nlink,
imap[j].nrefs);
if(imap[j].nrefs > 0 || imap[j].type == Weird)
switch(qry("clri, links-changed-to-refs, skip:\n")) {
case 's':
continue;
case 'c':
pmesg("clearing ino %d\n", j);
clri(j);
continue;
case 'l':
pmesg("fixing links ino %d\n", j);
fixlinks(j);
continue;
}
switch(qry("attach to /lost+found, expunge:\n")) {
case 'a':
attach(j);
continue;
case 'e':
expunge(j);
continue;
}
continue;
case Enullable:
j = erlist[i].a;
pmesg("Enullable ino %s\n", prino(j));
if(qry("clri, or skip\n") == 'c') {
pmesg("clearing ino %d\n", j);
clri(j);
}
continue;
case Einvalid:
if(qry("valid flag not set, set it?\n") == 'y') {
sblk.U.B.S_valid = 1;
if(bwrite(1, (char *) &sblk, 1))
pmesg("couldn't rewrite super block\n");
}
continue;
}
if(qry("fix the super block?\n") == 'y') {
pmesg("fixing the superblock\n");
fixfree();
}
}