#define	MAXARGS	30
#include	"devlist.h"
#include	<sys/types.h>
#include	<sys/param.h>
#include	"hsubs.h"
#include	"a.out.h"
#include	<sys/file.h>
#include	<sys/filsys.h>
#include	<sys/inode.h>
#include	<sys/signal.h>
#include	<sys/proc.h>
#include	<sys/dir.h>
#include	<sys/user.h>
#include	<sys/mount.h>
#include	<sys/var.h>
#include	<sys/ino.h>


struct	nlist	nl[5];
struct	tree	{
	struct	tree	*t_parent;
	struct	tree	*t_next;
	int	t_ino;
	int	t_dev;
	char	t_path[14];
} *first, *this, *last;

struct	user	us;
struct	proc	procc;
struct	inode	inode[1];
struct dinode	dinode;
struct mount	mount[32];
struct	var	v;

int	uid[MAXARGS];
int	uidcnt;
char	*names[MAXARGS];
int	namecnt;
char	*ttys[MAXARGS];
int	ttycnt;
int	hdr = 0;
int	mem;
int	swap;
int	r;
int	fs;
int	odev;
int	dotdot;
long	indbl[128];

char	buf[514];
long	swplo;
char	*logn, *logt;

struct	inode	*geti(), *getdev();
struct	tree	*lookup(), *new(), *setup();
char	*search();


main(argc, argv)
char **argv;
{
	register i;
	register b, b1;
	long l;
	register int iblk[20];
	struct	tree	*tp;
	int j, mm;

	i = getuid();
	if(i != 47 && i != 5){
		setgid(getgid());
		execl("/bin/pwd", "pwd", 0);
		exit(0);
	}
	getargs(argc, argv);
	strcpy(&nl[0], "_proc");
	strcpy(&nl[1], "_mount");
	strcpy(&nl[2], "_swplo");
	strcpy(&nl[3], "_v");
	nlist("/unix", nl);

	if(nl[0].n_type < 0){
		printf("No namelist\n\n");
		exit(1);
	}

	if((mem = open("/dev/mem", 0)) == -1 ||
	   (mm = open("/dev/mem", 0)) == -1 ||
	   (swap = open("/dev/swap", 0)) == -1){
		printf("No mem or swap\n");
		exit(3);
	}


	getmnt();
	fs = odev = -1;
	last = first = 0;
	lseek(mm, (long)(nl[2].n_value), 0);
	read(mm, &swplo, 4);
	lseek(mm, (long)(nl[3].n_value), 0);
	read(mm, &v, sizeof (struct var));
	lseek(mm, (long)(nl[0].n_value), 0);
	for(i = 0; i < v.v_proc; i++){
		read(mm, &procc, sizeof (procc));
		if(procc.p_stat == 0)continue;
		if(procc.p_stat == 5)continue;
		if(uidcnt && !auid()) continue;
		if(procc.p_flag & 1){
			j = mem;
			l = (long)(procc.p_addr) << 6;
		} else	{
			j = swap;
			l = ((long)(procc.p_addr) + swplo) << 9;
		}
		lseek(j, l, 0);
		read(j, &us, sizeof(us));
		logt = us.u_udata+40;
		if(*logt == 't' && logt[1] == 't' && logt[2] == 'y')
			logt += 3;
		logn = us.u_udata;
		logn[8] = 0;
		if(ttycnt && !aterm()) continue;
		if(namecnt && !aname()) continue;
		if(hdr++ == 0)
			printf("Username TTY   Parent   Proc  Directory\n");
		lseek(mem, (long)(us.u_cdir), 0);
		read(mem, inode, sizeof (struct inode));
		lseek(mem, (long)(inode[0].i_addr), 0);
		read(mem, iblk, NADDR*2);
		inode[0].i_addr = iblk;
		printf("%-8.8s ", logn);
		if(strncmp(logt, "co", 2) == 0)
			printf("cnsle");
		else	printf("tty%-2.2s", logt);
		printf("  %5d  %5d: ", procc.p_ppid, procc.p_pid);
		b = inode[0].i_number;
		b1 = inode[0].i_dev;
		if(b == 2 && b1 == (0 << 8) | 0){
			printf("/");
			goto rootcase;
		}
		if((tp = lookup(b, b1)) != -1){
			traverse(tp);
			goto rootcase;
		}
		opendev(b1);
		namei(search(inode, 0, ""));

		this = 0;
		pdir(inode, b);
rootcase:
		printf("\n");
	}
	close(mem);
	close(mm);
	close(swap);
	close(fs);
}

getargs(c, v)
register char **v;
{
	register char *s;
	register	i;

	while(--c){
		s = *++v;
		if(*s == '-'){
			switch(*++s){
			case 'h':
				hdr++;
				break;

			case 't':
				if(ttycnt < MAXARGS)
					ttys[ttycnt++] = s+1;
				while(*++s){
					if(*s == ','){
						*s = 0;
						if(ttycnt < MAXARGS)
							ttys[ttycnt++] = s+1;
					}
				}
				break;

			default:
				printf("bad option: %s\n", *v);
				exit(1);
			}
		} else 	if((i = val(s)) == -1){
			if(namecnt < MAXARGS)
				names[namecnt++] = s;
		} else {
			if(uidcnt < MAXARGS)
				uid[uidcnt++] = i;
		}
	}
}

auid()
{
	register int *up, i;
	register thisuid;

	thisuid = procc.p_uid;
	for(up=uid, i=0; i<uidcnt; i++)
		if(*up++ == thisuid)
			return(1);
	return(0);
}

aterm()
{
	register i;
	register char *thistty;

	thistty = logt;
	for(i = 0; i < ttycnt; i++)
		if(strncmp(ttys[i], thistty,2) == 0)
			return(1);
	return(0);
}

aname()
{
	register char **np;
	register i;
	register char *thisname;

	thisname = logn;
	for(np = names, i=0; i<namecnt; i++)
		if(strncmp(*np++, thisname, 8) == 0)
			return(1);
	return(0);
}

struct inode *
getdev(d)
{
	static char *dv = "/dev/rrmxx";
	register struct mount *pm;
	register i;
	register struct inode *pi;

	for(pm = mount; pm < &mount[v.v_mount]; pm++){
		if(pm->m_bufp == 0)continue;
		if(pm->m_dev == d)goto ok;
	}
	printf("pdir: Can not find dev %d/%d in Unix mount table\n",
		(d >> 8) & 0377, d & 0377);
	exit(4);

ok:
	pi = geti(pm->m_inodp);
	if(odev != pi->i_dev)
		opendev(pi->i_dev);
	return(pi);
}


struct inode *
geti(mp)
struct inode *mp;
{
	static int iblk[20];
	lseek(mem, (long)(mp), 0);
	read(mem, inode, sizeof inode);
	if(lseek(mem, (long)(inode[0].i_addr), 0) == -1L){
		printf("Seek error on iblocks\n");
		abort(8);
	}
	if(read(mem, iblk, NADDR*2) != NADDR*2){
		printf("Read error on iblks\n");
		abort(9);
	}
	inode[0].i_addr = iblk;
	return(inode);
}

namei(i)
register i;
{
	register struct dinode *pd;
	static int iblk[20];
	i--;
	lseek(fs, 1024L + (((long)(i) * (sizeof dinode)) & ~0777), 0);
	read(fs, buf, 512);
	pd = &buf[(i % INOPB) * (sizeof (struct dinode))];
	inode[0].i_number = i + 1;
	inode[0].i_dev = odev;
	inode[0].i_size = pd->di_size;
	inode[0].i_addr = iblk;
	l3tol(inode[0].i_addr, pd->di_addr, NADDR);
}

getmnt()
{
	lseek(mem, (long)(nl[1].n_value), 0);
	read(mem, mount, sizeof mount);
}

cpr(s,t)
register char *s, *t;
{
	register char *p;

	if(*s == 0)return(t);

	p = s;
	while(*s && s < p+14)s++;
	s--;
	while(s >= p)*t-- = *s--;
	*t-- = '/';
	return(t);
}

pdir(ip, i)
register struct inode *ip;
register i;
{
	char	bf[128], *p;
	register j;
	struct tree *tp;

	p = &bf[126];
	bf[127] = 0;

	while(ip->i_number != i){	/* as long as we do not hit root */
		if(find(i, ip->i_dev))
			goto print;
		p = search(ip, i, p);	/* tack preceding dirnam on bf */
		tp = setup(i, ip->i_dev, p+1);
		if(first == 0)
			first = tp;
		if(this == 0){
			if(last) last->t_next = tp;
			last = tp;
		} else
			this->t_parent = tp;
		this = tp;
		i = ip->i_number;	/* Search for me next time */
		namei(dotdot);		/* Get inode struct of .. for i */
	}				/* loop back */

	if(ip->i_dev == (0 << 8) | 0)goto print;	/* on / dir */
	ip = getdev(ip->i_dev);
	i = ip->i_number;		/* get inode of mounted on inode */
	if(find(i, ip->i_dev)) goto print;
	namei(search(ip, 0, ""));	/* get its .. dir */
	pdir(ip, i);			/* find inode i in dir ip */

print:
	printf("%s", p+1);
}

char *
search(ip, i, b)	/* search in dir pointed to by ip for inode i */
char *b;		/* if i == 0, just find .. in dir ip	*/
register struct inode *ip;
{
	register struct direct *pd;
	register bsz;
	int j, k;

	k = i;
	bsz = (ip->i_size + 511) >> 9;
	dotdot = 0;
	for(j = 0; j < bsz; j++){
		getto(j, ip);	/* get block #j of file ip */
		for(pd = buf; pd < &buf[512]; pd++){
			if(pd->d_ino == 0)continue;
			if(pd->d_name[0] == '.' &&
			   pd->d_name[1] == '.' &&
			   pd->d_name[2] ==  0	) dotdot = pd->d_ino;
			else	if(pd->d_ino == i){
					b = cpr(pd->d_name, b);
					i = 0;
				}
			if(dotdot)
				if(k == 0)
					return(dotdot);
				else
					if(!i)return(b);
		}
	}
	printf("pdir: Inode %d not found in inode %d dev %d/%d, routine search\n",
		k, ip->i_number, (ip->i_dev >> 8) & 0377, ip->i_dev & 0377);
	abort(7);
}

getto(b, ip)
register int b;
register struct inode *ip;
{
	long i;

	if(b < 10)
		i = ip->i_addr[b];
	 else {
		b -= 10;
		if(b > 127){
			printf("Very large directory: i=%d dev=%o\n",
				ip->i_number, ip->i_dev);
			abort(8);
		}
		if(b == 0){
			lseek(fs, ip->i_addr[10] << 9, 0);
			read(fs, indbl, 512);
		}
		i = indbl[b];
	}
	lseek(fs, i << 9, 0);
	read(fs, buf, 512);
}


opendev(d)
{
	static char *dv = "/dev/rrmxx";
	register int i;

	odev = d;
	close(fs);
	i = 8;
	d =& 0377;
	if(d > 9) dv[i++] = d/10 + '0';
	dv[i++] = d%10 + '0';
	dv[i] = 0;
	if((fs = open(dv, 0)) == -1){
		printf("pdir: Can not open disk: %s\n", dv);
		exit(5);
	}
}

val(s)
register char *s;
{
	register int i;

	if(*s < '0' || *s > '9')
		return(-1);
	i = 0;
	while(*s >= '0' && *s <= '9')
		i = i * 10 + *s++ - '0';
	return(i);
}



find(i, d)
register i, d;
{
	register struct tree *tp;

	if((tp = lookup(i, d)) != -1){
		traverse(tp);
		if(this) this->t_parent = tp;
		return(1);
	} else	return(0);
}

struct tree *new()
{
	register i;
	register struct tree *node;

	if((node = malloc(sizeof (struct tree))) == -1){
		printf("pdir: new() out of memory\n");
		exit(17);
	}

	node->t_parent = node->t_next = 0;
	for(i = 0; i < 14; i++)
		node->t_path[i] = 0;
	return(node);
}

struct tree *setup(ino, dev, p)
int ino, dev;
register char *p;
{
	register struct tree *node;
	register i;

	node = new();
	node->t_ino = ino;
	node->t_dev = dev;
	if(*p == '/'){
		for(p++, i = 0; i < 14 && *p && *p != '/'; node->t_path[i++] = *p++);
	}
	return(node);
}

traverse(tp)
register struct tree *tp;
{
	if(tp == 0)return;
	traverse(tp->t_parent);
	printf("/%.14s", tp->t_path);
}

struct tree *lookup(i, d)
register i;
int d;
{
	register struct tree *majr, *minr;

	for(majr = first; majr; majr = majr->t_next)
		for(minr = majr; minr; minr = minr->t_parent)
			if(minr->t_ino == i && minr->t_dev == d)
				return(minr);
	return(-1);
}

/*
 * Code commented out.  Used for debuggin only to print trees
 * of directories encountered.
 *


ptree()
{
	register struct tree *p1, *p2;

	for(p1 = first; p1; p1 = p1->t_next){
		printf("\nNext tree:\n");
		for(p2 = p1; p2; p2=p2->t_parent)
			printf("%.14s  I=%d  D=%o\n", p2->t_path, p2->t_ino, p2->t_dev);
	}
}
 *
 */

l3tol(s, t, n)
register char *s, *t;
register short n;
{
	while(n--){
		t++;
		*s++ = *t++;
		*s++ = *t++;
	}
}

