#

char	*dargv[]
{
	0,
	"/dev/rk0",
	"/dev/rp0",
	0
};
int	sflg;
char	lfile[]	"/tmp/ktmp";
int	lflg;
int	lfdes;
int	lfptr;

struct	inode
{
	int	i_mode;
	char	i_nlink;
	char	i_uid;
	char	i_gid;
	char	i_size0;
	char	*i_size1;
	int	i_addr[8];
	int	i_atime[2];
	int	i_mtime[2];
};

/* modes */
#define	IALLOC	0100000
#define	IFMT	060000
#define		IFDIR	040000
#define		IFCHR	020000
#define		IFBLK	060000
#define	ILARG	010000

struct
{
	char	*s_isize;
	char	*s_fsize;
	int	s_nfree;
	int	s_free[100];
	int	s_ninode;
	int	s_inode[100];
	char	s_flock;
	char	s_ilock;
	char	s_fmod;
	int	time[2];
	int	pad[50];
} sblock;

int	ndlist;
int	dlist[100];
char	*great;
int	nblist;
int	blist[100];
int	*bmap	-1;
int	fi;
int	nfile;
int	nspcl;
int	nlarg;
int	nindir;
int	ndir;
int	nused;
int	hiwat;
int	nfree;
int	ino;
int	ndup;
int	nnf;

struct
{
	char	icnt[2];
} *icnt;

struct	fname
{
	int	inum;
	int	nptr;
	int	pnum;
} *dn, *edn;

main(argc, argv)
char **argv;
{
	char *arg;
	register *p;
	extern fout;

	argv[argc] = 0;
	if(argc == 1) {
		argv = dargv;
		for(argc = 1; dargv[argc]; argc++);
	}

	if(argc>1 && *argv[1] == '-') {
		argc--;
		argv++;
		arg = *argv;
		while(*arg)
		switch(*arg++) {

		case 'l':
			lflg++;
			continue;

		case 's':
			sflg++;
			continue;

		case 'i':
			dlist[ndlist++] = number(argv[1]);
			argc--;
			argv++;
			continue;

		case 'b':
			blist[nblist++] = number(argv[1]);
			argc--;
			argv++;
			continue;

		case 'g':
			great = number(argv[1]);
			argc--;
			argv++;
			continue;

		}
	}
	if (lflg)
		sflg = 0;
	fout = dup(1);
	argc--;
	argv++;
	fprintf("%s:\n", argv[0]);
	check(argv[0]);
	flush();
	close(fout);
	fout = 1;
	if(argc > 1)
		execv("/bin/check", argv);
}

check(file)
char *file;
{
	struct inode buf[16];
	int i, j;
	int compar(), cintr();
	struct fname *dnp;

	fi = open(file, 0);
	if(fi < 0) {
		fprintf("cannot open %s\n", file);
		return;
	}
	sync();
	bread(1, &sblock);
	if (lflg) {
		lfdes = creat(lfile, 0666);
		signal(2, cintr);
		dn = edn = sbrk(100*6);
	} else {
		bmap = sbrk(8192);
		icnt = sbrk(sblock.s_isize*16);
	}
	for(i=0; i<sblock.s_isize; i++) {
		bread(i+2, buf);
		for(j=0; j<16; j++) {
			ino++;
			pass1(&buf[j]);
		}
	}
	ino = 0;
	if (lflg) {
		close(lfdes);
		lfdes = open(lfile, 0);
		qsort(dn, edn-dn, 6, compar);
		i = -1;
		j = 0;
		for (dnp=dn; dnp<edn; dnp++) {
			if(dnp->pnum == 0) {
				if(dnp->inum != 1)
					j = 1;
				continue;
			}
			if (dnp->inum != i) {
				i = dnp->inum;
				printf("%d", i);
			}
			putchar('\t');
			pfilename(dnp, 0);
			if(j) {
				j = 0;
				printf("/.");
			}
			putchar('\n');
		}
		close(lfdes);
		unlink(lfile);
		return;
	}
	sync();
	bread(1, &sblock);
	if(sflg) {
		close(fi);
		fi = open(file, 1);
		if(fi < 0) {
			fprintf("cannot write %s\n", file);
			return;
		}
		sblock.s_nfree = 0;
		sblock.s_ninode = 0;
		sblock.s_flock = 0;
		sblock.s_ilock = 0;
		sblock.s_fmod = 0;
		free(0);
		for(i=sblock.s_fsize-1; i>=sblock.s_isize+2; i--) {
			ndup = 0;
			chk(i, "URK", 0);
			if(ndup == 0)
				free(i);
		}
		bwrite(1, &sblock);
		close(fi);
		sync();
		return;
	}
	while(i = alloc()) {
		if(chk(i, "free", 0))
			break;
		nfree++;
	}
	if(ndup)
		printf("%l dups in free\n", ndup);
	ndup = 0;
	for(i=sblock.s_isize+2; i<sblock.s_fsize; i++) {
		chk(i, "urk", 0);
		ndup--;
	}
	if(ndup)
		printf("%l missing\n", -ndup);
	for(i=0; i<sblock.s_isize*16; i++) {
		j = icnt->icnt[i] & 0377;
		if(j!=0 && j!=0200)
			printf("%6l %3o\n", i+1, j);
	}
	printf("spcl  %6l\n", nspcl);
	printf("files %6l\n", nfile);
	printf("large %6l\n", nlarg);
	printf("direc %6l\n", ndir);
	printf("indir %6l\n", nindir);
	printf("used  %6l\n", nused);
	printf("last  %6l\n", hiwat);
	printf("free  %6l\n", nfree);
	close(fi);
}

cintr()
{

	unlink(lfile);
	exit();
}

compar(p1, p2)
struct fname *p1, *p2;
{
	int i;

	i = p1->inum - p2->inum;
	if(i)
		return(i);
	return(p1->pnum - p2->pnum);
}

pass1(ip)
struct inode *ip;
{
	int buf[256];
	int i, j, df;

	if((ip->i_mode&IALLOC) == 0)
		return;
	if (!lflg) {
		icnt->icnt[ino-1] =+ 0100;
		if(ip->i_nlink)
			icnt->icnt[ino-1] =+ 0100 + ip->i_nlink;
	}
	if((ip->i_mode&IFCHR&IFBLK) != 0) {
		nspcl++;
		return;
	}
	df = 0;
	if((ip->i_mode&IFMT) == IFDIR) {
		df = ldiv(ip->i_size0, ip->i_size1, 16);
		if(lflg) {
			if(--nnf<0) {
				nnf = 100;
				edn = sbrk(6*101);
			}
			edn->pnum = 0;
			edn->inum = ino;
			edn++;
		}
		ndir++;
	} else if (lflg)
		return;
	nfile++;
	if((ip->i_mode&ILARG) != 0) {
		nlarg++;
		for(i=0; i<8; i++)
		if(ip->i_addr[i] != 0) {
			nindir++;
			if(chk(ip->i_addr[i], "idir", 0))
				continue;
			bread(ip->i_addr[i], buf);
			for(j=0; j<256; j++)
			if(buf[j] != 0)
				chk(buf[j], "ldir", df);
			df =- 32;
		}
		return;
	}
	for(i=0; i<8; i++) {
		if(ip->i_addr[i] != 0)
			chk(ip->i_addr[i], "sdir", df);
		df =- 32;
	}
}

chk(i, s, df)
char *i;
{
	int n, b, j, buf[256];
	struct {
		int	ino;
		char	name[14];
	};

	for(j=0; j<nblist; j++)
		if(i == blist[j])
			fprintf("%l blk; i=%l(%s)\n", i, ino, s);
	if(great && i >= great && i)
		fprintf("%l geq; i=%l(%s)\n", i, ino, s);
	if(ino) {
		nused++;
		if(i > hiwat)
			hiwat = i;
	}
	if(i<sblock.s_isize+2 || i>=sblock.s_fsize) {
		fprintf("%l bad; i=%l(%s)\n", i, ino, s);
		return(1);
	}
	n = ldiv(0, i, 16);
	b = lrem(0, i, 16);
	if (lflg==0) {
		if(bmap[n] & (1<<b)) {
			if(ino == 0) {
				ndup++;
				return(0);
			}
			fprintf("%l dup; i=%l(%s)\n", i, ino, s);
			return(1);
		}
		bmap[n] =| 1<<b;
	}
	if(df>0) {
		bread(i, buf);
		for(n=0; n<256; n=+8) {
			if(df <= 0)
				break;
			df--;
			if((b=buf[n]) == 0)
				continue;
			if (lflg)
			if(!(buf[n].name[0]=='.' &&
			  (buf[n].name[1]=='\0' ||
			  (buf[n].name[1]=='.' && buf[n].name[2]=='\0')))) {
				if (--nnf<0) {
					nnf = 100;
					edn = sbrk(6*101);
				}
				edn->pnum = ino;
				edn->inum = buf[n];
				edn->nptr = lfptr;
				for (j=0; j<14; j++)
					if(buf[n].name[j] == '\0')
						break;
				j++;
				write(lfdes, buf[n].name, j);
				lfptr =+ j;
				edn++;
			}
			for(j=0; j<ndlist; j++)
				if(b == dlist[j])
				fprintf("%l ino; i=%l(%s) \"%.16s\"\n",
				  b, ino, s, buf+n+1);
			if(b<1 || b>16*sblock.s_isize) {
				fprintf("%l din; i=%l(%s)\n", i, ino, s);
				continue;
			}
			if (!lflg)
				icnt->icnt[b-1]--;
		}
	}
	return(0);
}

pfilename(dp, recur)
struct fname *dp;
{
	struct fname *p;
	char name[14];

	if (++recur > 10)
		printf("...");
	else if (dp->pnum != 1) {
		for (p = dn; p<edn; p++) {
			if (p->inum==dp->pnum && p->pnum!=0) {
				pfilename(p, recur);
				goto yes;
			}
		}
		printf("???");
	    yes:
		printf("/");
	}
	seek(lfdes, dp->nptr,  0);
	read(lfdes, name, 14);
	printf("%.14s", name);
}

alloc()
{
	int b, i, buf[256];

	i = --sblock.s_nfree;
	if(i<0 || i>=100) {
		fprintf("bad freeblock\n");
		return(0);
	}
	b = sblock.s_free[i];
	if(b == 0)
		return(0);
	if(sblock.s_nfree <= 0) {
		bread(b, buf);
		sblock.s_nfree = buf[0];
		for(i=0; i<100; i++)
			sblock.s_free[i] = buf[i+1];
	}
	return(b);
}

bread(bno, buf)
{

	seek(fi, bno, 3);
	if(read(fi, buf, 512) != 512) {
		fprintf("read error %d\n", bno);
		exit();
	}
}

free(in)
{
	int i;
	int buf[256];

	if(sblock.s_nfree >= 100) {
		buf[0] = sblock.s_nfree;
		for(i=0; i<100; i++)
			buf[i+1] = sblock.s_free[i];
		sblock.s_nfree = 0;
		bwrite(in, buf);
	}
	sblock.s_free[sblock.s_nfree++] = in;
}

bwrite(bno, buf)
{

	seek(fi, bno, 3);
	if(write(fi, buf, 512) != 512) {
		fprintf("write error %d\n", bno);
		exit();
	}
}

number(s)
char *s;
{
	int n, c;

	n = 0;
	while(c = *s++) {
		if(c<'0' || c>'9')
			continue;
		n = n*10+c-'0';
	}
	return(n);
}

fprintf(a, b, c, d, e)
{
	printf(a, b, c, d, e);
	flush();
}
