AUSAM/source/S/chk.c
/*
* chk: fast combination of icheck+dcheck
*
* Original from Vrije Universiteit, Amsterdam.
* Modified by Kevin Hill, University of NSW.
*/
#include <local-system>
#include <ino.h>
#include <filsys.h>
/*
* `prefix' is added to the given arguments - if this cannot be opened,
* the argument itself is tried.
* OFFSET is the char offset to the X's
* IN is the magic interleaving number
* NSEC is the number of sectors per track
* (must be <= 256 as `indbuf' is flogged in `makefree')
*/
#ifdef EECF
char prefix[] "/dev/rmsXX";
#define OFFSET 8
#define IN 10
#define NSEC 21
#endif
#ifdef AGSM
char prefix[] "/dev/rhpXX";
#define OFFSET 8
#define IN 7
#define NSEC 22
#endif
#ifdef EECF1140
char prefix[] "/dev/rrkX";
#define OFFSET 8
#define IN 3
#define NSEC 12
#endif
char *dargv[]
{
#ifdef EECF
"02", "11", "00", "01", "03", "10",
#endif
#ifdef AGSM
"00", "01", "02", "03", "10", "11", "12", "13",
#endif
#ifdef EECF1140
"0", "1",
#endif
0
};
/*
* TUNABLE CONSTANTS
*/
#define IBLKS 16 /* this many blocks of inodes read each time */
#define MAXSPECIAL 32 /* 2nd indir blks + directory indir. blks */
#define BISZ 88 /* size of blist and ilist arrays */
#define NPASS 20 /* max nr of passes in orphans() */
#define LISTSZ 20 /* nr of levels looked at per pass in orphans() */
#define BLKS fsize / 24 /* sorts and reads this many directory blocks per read in orphans() */
#define MAXDEPTH 20 /* max nr dir names printed out for inums - MUST BE < MAXSPECIAL */
#define AVLEN 7 /* average length of a directory name, plus null */
#define IINCR 10 /* allocate this many file structures each time in process */
#define NINCR 256 /* allocate this many characters each time in addname - MUST BE EVEN */
/*
* exit status bits
*/
#define COREERR 1
#define OPENERR 2
#define NONFATAL 4
#define FATAL 0200
/*
* global variables
*/
struct inode inode[IBLKS * 16]; /* buffer to read inodes */
struct filsys sblock; /* superblock of filesystem */
int fildes; /* file descriptor of filesystem */
char *ecount; /* used in checking link counts */
int *parent; /* base of parent array in orphans() */
unsigned have; /* largest chunk of core until now */
int ninodes; /* number of inodes on current device */
unsigned fsize; /* size of current device */
unsigned isize; /* size of i-list on device */
unsigned ino; /* current inumber */
unsigned pino; /* curr inum when processing in-core lists */
unsigned blknr; /* current block */
char exitcode; /* exitstatus is collected here */
int nifree; /* counts free inodes */
int nspcl; /* counts special files */
int ndir; /* nr. of directories */
int nfile; /* nr. of ordinary files */
int nlarg; /* number of large files */
int nvlarg; /* number of huge files */
int nindir; /* number of indirect blocks */
int nvindir; /* number of 2nd indirect blks */
int high; /* high water mark */
int nused; /* blocks used on this device */
char *usedbl; /* bitmap for used blocks */
char *indbl; /* bitmap for indirect blocks */
char *dirbl; /* bitmap for directory blocks */
char *np; /* current position in name array */
char *namend; /* end of name array */
int indbuf[256]; /* buffer to read indirect blocks */
unsigned blist[BISZ]; /* list for funny blocks */
unsigned ilist[BISZ]; /* list for funny inodes */
/*
* flags
* (the c-compiler will still use ints)
*/
char headpr; /* flag for nice output */
char verbose; /* verbose output */
char dotstoo; /* print out . and .. entries for -i option */
char freelist; /* recreate the free list */
char quiet; /* cut out the horsing around */
char specfind; /* look up special files */
char blook; /* currently looking up blk nrs */
char ilook; /* currently looking up inums */
char checked; /* filsystem has been checked */
char chkdot; /* currently checking . and .. entries */
char ctrlchrs; /* print out control-chars as `^x' pair */
/*
* misc
*/
char data_small[] "data (small)";
char data_lge[] "data (large)";
char indirect[] "indirect";
char indr_huge[] "indirect (huge)";
char indr2[] "2nd indirect";
char dir_inum[] "dir inum ";
char not_in[] ".' not in first 32 bytes\n";
struct specialbl
{
int blno; /* block number */
int which; /* 2nd indir. or direc. indir. or inum */
#define SP2IND 0
#define SPDIR 1
} specialbl[MAXSPECIAL], *nspecial, *dirblks, *ndirbp;
struct dirent
{
int inum, pinum;
char *namep;
} *dstart, *ilstrt, *ilp, *ilend;
main(argc, argv)
register argc;
register char **argv;
{
register n;
char c;
ecount = sbrk(0) - 1; /* points to last-used byte of core */
parent = ecount - 1; /* points to last-used word of core */
while (**++argv == '-') /* check for flags */
{
argc--;
switch (c = argv[0][1])
{
case 'a': dotstoo++;
continue;
case 'b':
case 'i': while (n = number(argv[1]))
{
addlist(n, c == 'b' ? blist : ilist);
argv++;
argc--;
}
if (headpr) headpr = 0;
else { argv++; argc--; }
continue;
case 'q': quiet++;
continue;
case 's': freelist++;
continue;
case 'v': verbose++;
continue;
case 'x': specfind++;
continue;
default: printf("Usage: chk [-a][-b list][-i list][-q][-s][-v][-x] [specials]\n");
return FATAL;
}
}
if (argc == 1) /* check default devices */
{
argv = dargv;
argc = sizeof dargv / 2;
}
while (--argc) check(*argv++); /* check devices given as arguments */
return exitcode;
}
check(file)
register char *file;
{
register i, *p;
register char *fp;
unsigned want;
int initpass();
int checklinks();
int findbad();
int findblks();
int markdirs();
int countdir();
int srchdirs();
fp = file;
i = OFFSET;
while ((prefix[i++] = *fp++) && i < sizeof prefix);
prefix[i - 1] = 0;
if ((fildes = open(fp = prefix, freelist ? 2 : 0)) < 0 &&
(fildes = open(fp = file, freelist ? 2 : 0)) < 0)
{
printf("Cannot open %s\n", fp);
exitcode =| OPENERR | FATAL;
return;
}
nspecial = specialbl;
nused = 0;
nifree = 0;
nspcl = 0;
ndir = 0;
nfile = 0;
nlarg = 0;
nvlarg = 0;
nindir = 0;
nvindir = 0;
high = 0;
checked = 0;
headpr = 0;
printf("%s:\n", fp);
sync(); /* write out in core blocks */
fsize = 2; /* bread insists on blocks in range */
bread(1, &sblock, 512); /* read super block */
fsize = sblock.s_fsize;
ninodes = (isize = sblock.s_isize) * 16;
if (*blist == 0 && *ilist == 0)
{
if (verbose) printf("Fsize\t%5u\nIsize\t%5u\n", fsize, isize);
i = freelist ? 2 : 3;
want = i * (fsize / 8) + ninodes + i;
if (chkcore(want)) return; /* not enough core */
i = want >> 1; /* number of words to clear */
p = 1 + ecount; /* address to start */
do
*p++ = 0;
while (--i);
ecount[want] = 0;
usedbl = &ecount[ninodes + 1];
indbl = &usedbl[fsize / 8 + 1];
dirbl = &indbl[fsize / 8 + 1];
scaninodes(initpass);
ino = 0; /* inum not known on error now */
dospecs();
finioff();
if (freelist)
{
makefree();
return;
}
checkfree();
scaninodes(checklinks);
if ((exitcode & FATAL) == 0) orphans();
checked++;
}
if (*blist)
{
for (p = blist; *p; p++)
if (*p > 1 && *p < isize + 2) printf("blk %u in i-list\n", *p);
nspecial = specialbl;
ndirbp = dirblks = &parent[1]; /* first usable word */
if (chkcore(BLKS * 4)) return;
blook++;
scaninodes(checked ? findbad : findblks);
chkindir();
readblks();
for (p = blist; *p; *p++ = 0); /* clear out blist */
blook = 0;
}
if (*ilist)
{
if (checked)
{
printf("\n looking for inums");
for (p = ilist; *p; printf(" %u", *p++));
putchar('\n');
}
else scaninodes(countdir);
for (p = ilist, nspcl = 0; *p++; nspcl++);
nfile = ndir;
nlarg = (nspcl + nfile) * AVLEN;
ndir =+ (ndir + 3) / 4; /* to improve the hashing */
want = (ndir + nspcl) * sizeof *dstart + BLKS * sizeof *nspecial + nlarg;
if (chkcore(want)) return;
ilook++;
p = dstart = ecount + 1;
i = (ndir * sizeof *dstart) >> 1;
do /* clean it up */
*p++ = 0;
while (--i);
nspecial = specialbl;
ndirbp = dirblks = &ecount[ndir * sizeof *dstart + 1];
np = &ndirbp[BLKS];
ilstrt = ilp = namend = &np[(nlarg + 1) & ~01];
ilend = &ilstrt[nspcl];
scaninodes(markdirs);
scaninodes(srchdirs);
getdirblks();
readblks();
printout();
for (p = ilist; *p; *p++ = 0); /* clear i-list */
ilook = 0;
}
close(fildes);
}
/*
* General-purpose inode scanning procedure
*/
scaninodes(f)
register (*f)();
{
register i, j;
for (i = 0, ino = 0; ino < ninodes; i =+ IBLKS)
{
bread(i+2, inode, sizeof inode); /* read large chunk */
for (j = 0; j < IBLKS * 16 && ino < ninodes; j++)
{
ino++;
(*f)(&inode[j]);
}
}
}
/*
* Read inodes; for each active inode update all bitmaps.
* Also fill usedbl[] with all double indirect blocks and
* all indirect directory blocks.
* There won't be a lot of those but if there are some
* they have to be read first
*/
initpass(ip)
register struct inode *ip;
{
register mode;
register i;
int n, dir;
if (((mode = ip->i_mode) & IALLOC) == 0) /* unused inode */
{
nifree++;
return;
}
if ((mode & (IFCHR & IFBLK))) /* special file */
{
nspcl++;
if (specfind)
{
printf("Spec file at %u\n", ino);
addlist(ino, ilist);
}
return;
}
dir = 0;
if ((mode & IFMT) == IFDIR)
{
dir++;
ndir++;
if (ip->i_size1 & 017 || ip->i_size0 || ip->i_size1 < 32)
{
printf("Illegal dir size; inum %u\n", ino);
addlist(ino, ilist);
exitcode =| FATAL;
}
}
else nfile++;
if ((mode & ILARG) == 0)
{
for (i = 0; i < 8; i++)
{
if ((n = ip->i_addr[i]) == 0) continue;
setbit(n, usedbl, data_small);
if (dir && freelist == 0) setbit(n, dirbl);
}
}
else
{
nlarg++;
for (i = 0; i < 7; i++)
{
if ((n = ip->i_addr[i]) == 0) continue;
nindir++;
setbit(n, usedbl, indirect);
setbit(n, indbl);
if (dir && freelist == 0) inspecial(n, SPDIR);
}
if ((n = ip->i_addr[7]))
{
nvlarg++;
setbit(n, usedbl, indr_huge);
if (dir)
{
printf("Huge directory; inum %u\n", ino);
addlist(ino, ilist);
exitcode =| FATAL;
return;
}
inspecial(n, SP2IND);
if (verbose)
{
printf("Huge file; inum %u\n", ino);
addlist(ino, ilist);
}
}
else if (dir && verbose)
{
printf("Large directory; inum %u\n", ino);
addlist(ino, ilist);
}
}
}
/*
* Read all double indirect blocks and all indirect directory blocks
* and fill in bitmaps.
*/
compar(p1, p2)
struct specialbl *p1, *p2; /* NOT registers - shorter code */
{
return p1->blno - p2->blno;
}
dospecs()
{
register struct specialbl *p;
register i, n;
if (nspecial > specialbl + 1)
qsort(specialbl, nspecial - specialbl, sizeof specialbl[0], compar);
for (p = specialbl; p < nspecial; p++)
{
bread(blknr = p->blno, indbuf, 512);
for (i = 0; i < 256; i++)
{
if ((n = indbuf[i]) == 0) continue;
if (p->which == SP2IND)
{
nvindir++;
setbit(n, usedbl, indr2);
setbit(n, indbl);
}
else setbit(n, dirbl);
}
}
}
/*
* Proceed through the bitmaps indbl and dirbl, letting the
* arm of the disk move from low to high once.
*/
finioff()
{
register i, k, b;
int ind, dir, bit, j;
char *n;
for (i = 0; i < (fsize / 8 + 1); i++)
{
ind = indbl[i];
dir = freelist ? 0 : dirbl[i];
if (ind || dir)
{
b = i * 8;
bit = 1;
for (j = 0; j < 8; j++)
{
blknr = b;
if (ind & bit) /* indirect block */
{
bread(b, indbuf, 512);
for (k = 0; k < 256; k++)
if (indbuf[k])
setbit(indbuf[k], usedbl, data_lge);
}
else if (dir & bit) /* directory block */
{
bread(b, indbuf, 512);
for (k = 0; k < 256; k =+ 8)
{
if ((n = indbuf[k]) == 0) continue;
if (n <= ninodes) ++ecount[n];
else
{
if (addlist(b, blist)) printf("Bad dir inum (%u) (blk %u)\n", n, b);
exitcode =| FATAL;
}
}
}
b++;
bit =<< 1;
}
}
}
}
/*
* Read free list and final icheck
*/
checkfree()
{
register b, n;
n = 0;
if (verbose) printf("Used\t%5u\n", nused);
while ((b = nextfree()))
{
setbit(b, usedbl, "free");
n++;
}
if (b = fsize - isize - 2 - nused)
{
printf("Missing %u blocks\n", b);
exitcode =| NONFATAL;
}
if (verbose)
{
printf("Spcl\t%5u\n", nspcl);
printf("Files\t%5u\n", nfile);
printf("Large\t%5u\n", nlarg);
if (nvlarg) printf("Huge\t%5u\n", nvlarg);
printf("Direc\t%5u\n", ndir);
printf("Indir\t%5u\n", nindir);
if (nvindir) printf("Indir2\t%5u\n", nvindir);
printf("High\t%5u\n", high);
}
if (quiet == 0) printf("Freei\t%5u\nFree\t%5u\n", nifree, n);
}
/*
* Read inodes, for each active inode check link and count
*/
checklinks(ip)
register struct inode *ip;
{
register i;
i = ino;
if ((ip->i_mode & IALLOC) == 0 && ecount[i] == 0) return;
if (ip->i_nlink == ecount[i] && ip->i_nlink) return;
if (headpr++ == 0) printf("\nInum\tDir-ent\tLnk-cnt\n");
printf("%u\t%u\t%u\n", ino, ecount[i] & 0377, ip->i_nlink & 0377);
if (ecount[i] == 0) exitcode =| NONFATAL;
else
{
exitcode =| FATAL;
addlist(i, ilist);
}
}
/*
* Look for disconnected branches
*/
orphans()
{
register j;
register unsigned k, *lp;
unsigned *lpp;
int i, notyet;
int list[LISTSZ];
int readir();
int fstblk();
k = (j = ninodes + BLKS * 2) * 2;
if (chkcore(k)) return;
lp = 1 + ecount; /* clear it out */
do
*lp++ = 0;
while (--j);
ndirbp = dirblks = &parent[ninodes + 1];
nspecial = specialbl;
/*
* Now rescan inodes looking for all directories
* These must be read, and their child inodes marked (in parent[])
* as children of the directory (inum).
* Also, check all . and .. entries.
*/
parent[1] = 1;
scaninodes(readir);
getdirblks();
readblks();
ndirbp = dirblks;
nspecial = specialbl;
chkdot++;
scaninodes(fstblk);
getdirblks();
readblks();
chkdot = 0;
/*
* Now scan through parent[] - for each slot, work back through
* parents until reach inode number 1 (you hope!).
*/
i = 0;
do
{
notyet = 1;
for (j = 2; j <= ninodes; j++)
{
if (parent[k = j] <= 1) continue;
for (lp = list; lp < &list[LISTSZ]; )
if ((*lp++ = k = parent[k]) <= 1) break;
if (k > 1) notyet = 0;
if (k == 0) { lp--; k = lp[-1]; }
lpp = lp - 2;
for (lp = list; lp < lpp; lp++) parent[*lp] = k;
parent[j] = k;
}
} while (i++ < NPASS && notyet == 0);
for (j = 2; j < ninodes; j++)
if ((i = parent[j]) != 1)
{
printf("possible orphan; inum %u", j);
if (i)
{
printf(" (from %u)", i);
addlist(i, ilist);
}
putchar('\n');
exitcode =| NONFATAL;
}
}
readir(ip)
struct inode *ip;
{
register i, n, mode;
int readblks();
if (((mode = ip->i_mode) & IALLOC) == 0 || (mode & IFMT) != IFDIR)
{
parent[ino] = 1;
return;
}
if ((mode & ILARG) == 0)
{
for (i = 0; i < 8; i++)
if (n = ip->i_addr[i]) store(n, ino);
}
else for (i = 0; i < 7; i++)
if (n = ip->i_addr[i]) storespec(n);
}
store(bno, inum)
unsigned bno;
{
if (bno < isize + 2 || bno >= fsize) return;
if (ndirbp == &dirblks[BLKS])
{
readblks();
ndirbp = dirblks;
}
ndirbp->blno = bno;
ndirbp->which = inum;
ndirbp++;
}
storespec(bno)
{
if (nspecial == &specialbl[MAXSPECIAL])
{
getdirblks();
nspecial = specialbl;
}
nspecial->blno = bno;
nspecial->which = ino;
nspecial++;
}
getdirblks()
{
register struct specialbl *p;
register i, n;
if (nspecial > specialbl + 1)
qsort(specialbl, nspecial - specialbl, sizeof specialbl[0], compar);
for (p = specialbl; p < nspecial; p++)
{
bread(p->blno, indbuf, 512);
if (chkdot) store(indbuf[0], p->which);
else for (i = 0; i < 256; i++)
if (n = indbuf[i]) store(n, p->which);
}
}
readblks()
{
register struct specialbl *p;
register k, n;
if (ndirbp > dirblks + 1)
qsort(dirblks, ndirbp - dirblks, sizeof dirblks[0], compar);
for (p = dirblks; p < ndirbp; p++)
{
bread(p->blno, indbuf, chkdot ? 32 : 512);
pino = p->which; /* do NOT use ino */
if (chkdot) { checkdots(); continue; }
for (k = 0; k < 256; k =+ (blook ? 1 : 8))
{
if ((n = indbuf[k]) == 0) continue;
if (blook)
{
chklist(n, pino, data_lge);
continue;
}
if (ilook)
{
if (n >= 1 && n <= ninodes) process(&indbuf[k]);
continue;
}
if ((parent[n] == 0) && ! dotname(&indbuf[k + 1])) parent[n] = pino;
}
}
}
dotname(s)
register *s;
{
return (*s == '.\0' || *s == '..' && s[1] == 0);
}
bread(bno, buf, cnt)
register unsigned bno;
{
register char *p;
register i;
if (bno >= fsize)
{
if (checked) abort(); /* impossible! */
exitcode =| FATAL; /* Error message will be given in setbit() */
p = buf;
i = cnt;
do
*p++ = 0;
while (--i);
return;
}
seek(fildes, bno, 3);
if (read(fildes, buf, cnt) != cnt)
{
printf("read error %u\n", bno);
exitcode =| FATAL;
exit(exitcode);
}
}
/*
* Set the bit in the given bit-map, checking for bad and dup blocks.
* `string' is only valid when map == usedbl. `string' only starts
* with `f' when checking blocks in the free list.
*/
setbit(bno, map, string)
char *map, *string;
register unsigned bno;
{
register char *b;
register bit;
if (bno < isize + 2 || bno >= fsize)
{
if (map == usedbl) prerr("%u bad;", bno, string);
exitcode =| FATAL;
return;
}
b = &map[bno >> 3]; /* unsigned; don't have to mask */
bit = 1 << (bno & 07);
if (map == usedbl)
{
if ((*b) & bit)
{
prerr("%u dup;", bno, string);
exitcode =| FATAL;
return;
}
nused++;
if (string[0] != 'f' && bno > high) high = bno;
}
*b =| bit;
}
prerr(errstrng, bno, string)
register char *string;
register unsigned bno;
char *errstrng;
{
register printed 0;
if (ino)
{
if (addlist(ino, ilist))
{
printf(errstrng, bno);
printf(" inum %u;", ino);
printed++;
}
}
else
{
if (addlist(blknr ? blknr : bno, blist))
{
printf(errstrng, bno);
if (blknr) printf(" in ind-blk %u;", bno = blknr);
printed++;
}
}
if (printed) printf(" class=%s\n", string);
}
inspecial(bno, wflag)
unsigned bno;
{
if (nspecial == &specialbl[MAXSPECIAL])
{
/*
* There are more than MAXSPECIAL strange blocks.
* Now we are forced to make an extra pass.
*/
printf("More than %u special blocks (recompile?)\n", MAXSPECIAL);
dospecs();
nspecial = specialbl;
}
nspecial->blno = bno;
nspecial->which = wflag;
nspecial++;
}
nextfree()
{
register unsigned b, i;
i = --sblock.s_nfree;
if (i >= 100) /* gets < 0 too! */
{
printf("illegal nfree (%u)\n", i + 1);
exitcode =| FATAL;
return(0);
}
b = sblock.s_free[i];
if (b == 0) return(0);
if (sblock.s_nfree <= 0)
{
bread(b, indbuf, 512);
sblock.s_nfree = indbuf[0];
for (i = 0; i < 100; i++) sblock.s_free[i] = indbuf[i+1];
}
return(b);
}
makefree()
{
register unsigned i, j, low;
int *flag, adr[NSEC];
flag = &indbuf[0];
for (i = 0; i < NSEC; flag[i++] = 0);
for (i = 0, j = 0; i < NSEC; i++)
{
while (flag[j]) j = (j + 1) % NSEC;
adr[i] = j;
flag[j]++;
j = (j + IN) % NSEC;
}
sblock.s_nfree = sblock.s_ninode = 0;
sblock.s_flock = sblock.s_ilock = sblock.s_fmod = 0;
for (i = 101; i < 256; indbuf[i++] = 0);
low = isize + 2; /* lowest potentially usable blk */
free(0); /* end-of-list sentinel */
j = lrem(0, i = sblock.s_fsize, NSEC);
while (j-- && --i >= low) freebl(i);
i--;
while (i >= low + NSEC - 1)
{
for (j = 0; j < NSEC; j++) freebl(i - adr[j]);
i =- NSEC;
}
while (i >= low) freebl(i--);
bwrite(1, &sblock); /* do NOT sync (may be root device) */
close(fildes);
}
free(bno)
{
register i;
if (sblock.s_nfree >= 100)
{
indbuf[0] = sblock.s_nfree;
for (i = 0; i < 100; i++) indbuf[i + 1] = sblock.s_free[i];
sblock.s_nfree = 0;
bwrite(bno, indbuf);
}
sblock.s_free[sblock.s_nfree++] = bno;
}
freebl(bno)
{
if ((usedbl[(bno >> 3) & 017777] & (1 << (bno & 07))) == 0) free(bno);
}
bwrite(bno, buf)
register unsigned bno;
{
seek(fildes, bno, 3);
if (write(fildes, buf, 512) != 512)
{
printf("write error %u\n", bno);
exitcode =| FATAL;
exit(exitcode);
}
}
/*
* findbad looks up blocks in `blist' to find their inode nrs
* (if they have been put there as a result of the checks).
* Note that it is not necessary to check indirect blocks of
* ordinary files, as their inums will already be known.
*/
findbad(ip)
struct inode *ip;
{
register i, n, mode;
int chkindir();
if (((mode = ip->i_mode) & IALLOC) == 0 ||
(mode & (IFCHR & IFBLK))) return;
for (i = 0; i < 8; i++)
if (n = ip->i_addr[i]) chklist(n, ino, 0);
if ((mode & ILARG) == 0) return;
if ((mode & IFMT) == IFDIR)
{
for (i = 0; i < 7; i++)
if (n = ip->i_addr[i]) build(n);
return;
}
if (n = ip->i_addr[7]) build(n);
}
build(bno)
register unsigned bno;
{
if (bno < isize + 2 || bno >= fsize) return;
if (nspecial == &specialbl[MAXSPECIAL])
{
chkindir();
nspecial = specialbl;
}
nspecial->blno = bno;
nspecial->which = ino;
nspecial++;
}
chkindir()
{
register struct specialbl *p;
register i, n;
if (nspecial > specialbl + 1)
qsort(specialbl, nspecial - specialbl, sizeof specialbl[0], compar);
for (p = specialbl; p < nspecial; p++)
{
bread(p->blno, indbuf, 512);
for (i = 0; i < 256; i++)
if (n = indbuf[i])
{
chklist(n, p->which, blook ? indr2 : 0);
if (blook) store(n, p->which);
}
}
}
chklist(bno, inum, s)
register bno;
char *s;
{
register unsigned *lp blist;
while (*lp != bno && *++lp);
if (*lp)
{
printf("blk %u from inum %u", bno, inum);
if (s) printf("; class=%s", s);
putchar('\n');
addlist(inum, ilist);
}
}
findblks(ip)
struct inode *ip;
{
register i, n, mode;
if (((mode = ip->i_mode) & IALLOC) == 0 ||
(mode & (IFCHR & IFBLK))) return;
if ((mode & ILARG) == 0)
{
for (i = 0; i < 8; i++)
if (n = ip->i_addr[i]) chklist(n, ino, data_small);
}
else
{
for (i = 0; i < 7; i++)
{
if ((n = ip->i_addr[i]) == 0) continue;
chklist(n, ino, indirect);
store(n, ino);
}
if (n = ip->i_addr[7])
{
chklist(n, ino, indr_huge);
build(n);
}
}
}
fstblk(ip)
register struct inode *ip;
{
register mode;
if (((mode = ip->i_mode) & IALLOC) == 0 || (mode & IFMT) != IFDIR) return;
if ((mode & ILARG) == 0) store(ip->i_addr[0], ino);
else storespec(ip->i_addr[0]);
}
checkdots()
{
register *dot, *dotdot, *s;
dot = dotdot = 0;
s = indbuf;
do
{
if (s[0])
if (s[1] == '.\0') dot = s;
else if (s[1] == '..' && s[2] == 0) dotdot = s;
s =+ 8;
} while (s != &indbuf[16]);
s = 0;
if (dot == 0)
{
printf("%s%u: `%s", dir_inum, pino, not_in);
s++;
}
else if (*dot != pino)
{
printf("%s%u: `.' inum %u\n", dir_inum, pino, *dot);
addlist(*dot, ilist);
s++;
}
if (dotdot == 0)
{
printf("%s%u: `.%s", dir_inum, pino, not_in);
s++;
}
else if (*dotdot != parent[pino])
{
printf("%s%u: from %u; `..' inum %u\n", dir_inum, pino, parent[pino], *dotdot);
addlist(*dotdot, ilist);
s++;
}
if (s)
{
addlist(pino, ilist);
exitcode =| FATAL;
}
}
countdir(ip)
struct inode *ip;
{
register mode;
if (((mode = ip->i_mode) & IALLOC) && (mode & IFMT) == IFDIR) ndir++;
}
markdirs(ip)
struct inode *ip;
{
register mode;
if (((mode = ip->i_mode) & IALLOC) && (mode & IFMT) == IFDIR) lookup(ino, 1);
}
lookup(inum, add)
register inum;
{
register struct dirent *d, *dend;
d = &dstart[inum % ndir];
dend = &dstart[ndir];
while (d->inum)
{
if (d->inum == inum) return d;
if (++d >= dend) d = dstart;
}
if (add) d->inum = inum;
return 0;
}
srchdirs(ip)
struct inode *ip;
{
register i, n, mode;
if (((mode = ip->i_mode) & IALLOC) == 0 || (mode & IFMT) != IFDIR) return;
if ((mode & ILARG) == 0)
{
for (i = 0; i < 8; i++)
if (n = ip->i_addr[i]) store(n, ino);
}
else
{
for (i = 0; i < 7; i++)
if (n = ip->i_addr[i]) storespec(n);
}
}
process(dp)
register *dp;
{
register i, *ip;
if ((i = dotname(dp + 1)) && ! dotstoo) return;
if (i == 0 && (ip = lookup(*dp, 0))) /* it's a directory */
{
ip->pinum = pino;
ip->namep = addname(dp + 1);
}
ip = ilist;
while (*ip != *dp && *++ip);
if (*ip)
{
if (ilp == ilend)
{
if ((i = more(&ilend, &namend, IINCR * sizeof *ilend)) == -1) return;
if (i)
{
ilp--;
ilend = i;
ilend->inum = ilp->inum;
ilend->pinum = ilp->pinum;
ilend->namep = ilp->namep;
ilp->inum = 0;
ilp = ilp->pinum = i;
ilp++;
}
ilend =+ IINCR;
}
ilp->inum = *dp;
ilp->pinum = pino;
ilp->namep = addname(dp + 1);
ilp++;
}
}
addname(nm)
char *nm;
{
register i, j;
register char *cp;
char *new;
i = 0;
cp = np;
do
{
if (cp == namend)
{
if ((j = more(&namend, &ilend, NINCR)) == -1) return;
if (new = j)
{
nm =- i;
namend = np = cp = new;
i = 0;
}
namend =+ NINCR;
}
*cp = *nm++;
} while (*cp++ && i++ < 14);
cp[-1] = 0; /* in case name is 14 chars long */
nm = np;
np = cp;
return nm;
}
more(me, him, incr)
register unsigned *me, *him, incr;
{
if (*him < *me) /* contiguous allocation possible */
{
if (chkcore(*me - ecount - 1 + incr)) return -1;
return 0;
}
if (chkcore(*him - ecount - 1 + incr)) return -1;
return *him;
}
printout()
{
register n;
register struct dirent *d, *dp;
for (d = ilstrt; d != ilp; d++)
{
if ((dp = d)->inum == 0) d = dp = dp->pinum; /* chain along */
nspecial = specialbl;
n = 0;
do
storespec(dp);
while dp->pinum != 1 && ++n != MAXDEPTH && (dp = lookup(ino = dp->pinum, 0)) != 0;
pname(dp);
}
}
pname(dp)
register struct dirent *dp;
{
register struct specialbl *p;
p = nspecial - 1;
if (dp == 0) printf("?%u?", ino);
else if (dp->pinum != 1) printf(".../%u", dp->pinum);
else putchar('1');
while (p >= specialbl) printf("/%u", (p--)->blno->inum);
printf(":\t");
p = nspecial - 1;
ctrlchrs++;
if (dp == 0) printf("?%u?", ino);
else if (dp->pinum != 1) printf("...");
else printf("%s", (p--)->blno->namep);
while (p >= specialbl) printf("/%s", (p--)->blno->namep);
ctrlchrs = 0;
putchar('\n');
}
/*
* addlist returns 1 if the given element is not already
* in the list, or if it is in the list and the verbose option is on
*/
addlist(n, list)
register unsigned n;
unsigned list[];
{
register unsigned *lp list;
static ioflw, boflw;
if (*lp)
{
while (*lp != n && *++lp);
if (*lp) return verbose;
if (lp >= &list[BISZ - 1])
{
if (list == blist && boflw++ == 0) printf("b-list overflow\n");
if (list == ilist && ioflw++ == 0) printf("i-list overflow\n");
return 1;
}
}
*lp = n;
return 1;
}
number(s)
register char *s;
{
register n 0;
if (*s < '0' || *s > '9')
{
headpr++;
return 0;
}
while (*s) n = n * 10 + *s++ - '0';
return n;
}
chkcore(want)
register unsigned want;
{
if (want > have)
{
if (sbrk(want - have) == -1)
{
printf("Not enough core\n");
exitcode =| COREERR | FATAL;
return 1;
}
have = want;
}
return 0;
}
/*
* This printf is smaller than the C-library version.
* It supports only %s, %u, and %nu (n a single digit).
*/
printf(s, a)
register char *s;
unsigned a;
{
register c;
register unsigned *p;
int fw;
p = &a;
while (c = *s++)
{
if (c == '%')
{
if ((c = *s++) >= '0' && c <= '9')
{
fw = c - '0';
c = *s++;
}
else fw = 0;
switch (c)
{
case 's': printf(*p++); /* CARE! */
continue;
case 'u': printl(*p++, fw);
continue;
case 0: return;
}
}
putchar(c);
}
}
printl(n, fw)
register unsigned n;
register fw;
{
register char *s;
char stack[10];
s = &stack[sizeof stack];
*--s = 0;
do
{
*--s = n % 10 + '0';
n =/ 10;
fw--;
} while (n);
while (fw-- > 0) *--s = ' ';
while (*s) putchar(*s++);
}
putchar(c)
{
if ((c =& 0177) < ' ' && ctrlchrs)
{
putchar('^');
c =| 0100;
}
write(1, &c, 1);
}