#
/*
 *	Dumps in legible form the contents of the
 *	inode table
 */
#include "/usr/sys/param.h"
#include "/usr/sys/inode.h"
struct
{	char	d_minor;
	char	d_major;
};

char *namelist	"/unix";
char *corefile	"/dev/kmem";
char *devdr	"/dev";

struct devblock
{	int	d_flag;
	int	d_dev;
	int	d_name[14];
} devblock[100];
struct devblock *dmax;

struct
{	int	sd;
	int	in;
	int	flags;
	char nlinks;
	char	uid;
	char	gid;
	char	sz0;
	int	sz;
	int	specialdev;
	int	fill[11];
} statb;
#define BLK	060000
#define CHAR	020000

 
char *symname	"_inode";

int corefd;

struct nl
{	char 	n_name[8];
	int	n_type;
	int	n_value;
} nl[2];


char *lookupdev();
char *putnum();
int eflag;
int nflag;
main(argc, argv)
char **argv;
{	register char *p;
	if(--argc)
	{	argv++;
		if(**argv == '-')
		{
			for(p = *argv; *p != '\0'; p++)
			{
				if(*p == 'e') 
					eflag++;
				else if(*p == 'n')
					nflag++;
			}
		}
		else
		{	argv--;
			argc++;
		}
		if(--argc)
		{	argv++;
			corefile = *argv;
			if(--argc)
			{	argv++;
				namelist = *argv;
			}
		}
	}

	close(2);
	dup(1);
	if((corefd = open(corefile, 0)) < 0)
	{	printf("Cannot open core file\n");
		exit();
	}
	setnl(symname);
	seek(corefd, nl[0].n_value, 0);
	if(read(corefd, &inode[0], sizeof(inode[0]) * NINODE)<0)
	{	printf("Cannot read %s values\n", symname);
		exit();
	}
	printf("Dump of inode table\n");
	slots();
	getdevs();
	dataprint();
}

setnl(sn)
char *sn;
{	register char *s, *d;
	s = sn;
	for(d = &nl[0].n_name; *d++ = *s++;);
	nlist(namelist, &nl[0]);
	if(nl[0].n_type == -1)
	{	printf("Cannot find namelist entry for %s\n", sn);
		exit();
	}
}

dataprint()
{	register struct inode *ip;
	register ct;
	ct = 0;
	for(ip = &inode[0]; ip < &inode[NINODE]; ip++)
	{	if(eflag)
		{	if(ip->i_count == 0)
				entry(ip, ct);
		}
		else
		entry(ip, ct);
		ct++;
	}
}

entry(ip, ct)
register struct inode *ip;
{
	char *str;
	printf("Table entry: %d\n", ct);
	printf("Table address: %o\n", ct*sizeof(inode[0]) + nl[0].n_value);
	printf("Flag: %o\n", ip->i_flag&0377);
	printf("\t");
	if(ip->i_flag & ILOCK) printf(" Locked;");
	if(ip->i_flag & IUPD) printf(" Updated;");
	if(ip->i_flag & IACC) printf(" Access time updated;");
	if(ip->i_flag & IMOUNT) printf(" Inode mounted on;");
	if(ip->i_flag & IWANT) printf(" Inode wanted;");
	if(ip->i_flag & ITEXT) printf(" Pure text proto;");
	printf("\n");
	printf("Mode: %o\n", ip->i_mode);
	printf("Ref count: %d\n", ip->i_count);
	printf("Device major: %d, minor %d\n", ip->i_dev.d_major&0377, ip->i_dev.d_minor&0377);
	printf("\t/dev/%s\n", (str = lookupdev(ip->i_dev)));
	printf("Inode number: %d\n", ip->i_number);
	if(nflag)
	ncheck(str, ip->i_number);
	printf("Links: %d\n", ip->i_nlink&0377);
	printf("Owner: %s\n", getuser(ip->i_uid));
	printf("Last ref time: %d %u\n", ip->i_lrt, ip->i_lrt);
	printf("\n\n");
}

getuser(uu)
{	static char wk[512];
	register char *s;

	if(getpw(uu, wk) != 0)
		return("Unknown");
	for(s = wk; *s != ':'; s++);
	*s = '\0';
	return(wk);
}

getdevs()
{	int dfd;
	register struct devblock *dp;
	struct
	{	int	dir_in;
		char	dir_name[14];
	} dir;

	dp = &devblock[0];

	if((dfd = open(devdr, 0)) < 0)
	{	printf("Cannot open: %s\n", devdr);
		exit();
	}
	chdir(devdr);

	seek(dfd, 32, 0);

	while(read(dfd, &dir, sizeof dir) == sizeof dir)
	{
		if(dir.dir_in)
		{	stat(dir.dir_name, &statb);
			if((statb.flags & BLK) == BLK)
				dp->d_flag++;
			else
			if((statb.flags & BLK) != CHAR)
			{	printf("%s not got correct mode: %o\n", dir.d_name, statb.flags);
				exit();
			}
			dp->d_dev = statb.specialdev;
			copystr(dir.dir_name, dp->d_name);
			dp++;
		}
	}
	dmax = dp;
	close(dfd);
}

char *lookupdev(dvv)
{	register struct devblock *dp;

	for(dp = &devblock[0]; dp < dmax; dp++)
	{
		if(dp->d_dev == dvv)
		return(dp->d_name);
	}
	return("unknown");
}

copystr(s, d)
register char *s, *d;
{	while(*d++ = *s++);
}

ncheck(nname, nin)
char *nname;
{	int pid;
	char **av[7];

	static char device[] "/dev/xxxxxxxx";
	char numvec[8];

	av[0] = "ncheck";
	av[1] = "-i";
	putnum(nin, numvec);
	av[2] = numvec;
	copystr(nname, &device[5]);
	av[3] = device;
	av[4] = 0;
	if((pid = fork()) < 0)
	{	printf("Cannot fork\n");
		exit();
	}
	if(pid) wait();
	else
	{	execv("/bin/ncheck", av);
		printf("Cannot exec\n");
		exit();
	}
}

char *putnum(num, st)
register num;
register char *st;
{	register r;
	if( r = num/10)
		st = putnum(r, st);
	*st++ = num%10 + '0';
	*st = '\0';
	return(st);
}

slots()
{	register struct inode *ip;
	register ct = 0;

	for(ip = &inode[0]; ip < &inode[NINODE]; ip++)
		if(ip->i_count == 0) ct++;
	printf("%d free slots out of %d\n", ct, NINODE);
}
