V8/usr/src/cmd/finddev.c

Compare this file to the similar file:
Show the results in this format:

#include <sys/param.h>
#include <sys/dir.h>
#include <sys/file.h>
#include <sys/user.h>
#include <sys/inode.h>
#include <sys/proc.h>
#include <sys/pte.h>
#include <sys/text.h>
#include <sys/vm.h>
#include <stdio.h>
#include <ctype.h>
#include <nlist.h>
#include <pwd.h>
#include <sys/stat.h>
#include <ftw.h>

struct nlist nl[] = {
	{ "_proc" },
#define	X_PROC		0
	{ "_Usrptmap" },
#define	X_USRPTMA	1
	{ "_usrpt" },
#define	X_USRPT		2
	{ "_nswap" },
#define	X_NSWAP		3
	{ "_nproc" },
#define	X_NPROC		4
	{ 0 },
};

#define PROCCHUNK 8		/* a few, for fewer syscalls */
struct	proc proc[PROCCHUNK];
struct	proc *mproc;


int	paduser1;		/* avoid hardware mem clobbering botch */
union {
	struct	user user;
	char	upages[UPAGES][NBPG];
} user;
#define u	user.user
int	paduser2;		/* avoid hardware mem clobbering botch */

#define clear(x) 	((int)x & 0xfffff)

int	nswap;
struct	pte *Usrptma, *usrpt;
int	nproc;

char	*kmemf, *memf, *swapf, *nlistf;
int	kmem, mem, swap;
long	lseek();

int	pcbpf;
int	argaddr;
extern	char _sobuf[];

main(argc, argv)
	char **argv;
{
	register int i, j;
	off_t procp;

	initialize (argc, argv);
	setbuf(stdout, _sobuf);
	openfiles();
	getkvars();
	procp = getw((off_t) nl[X_PROC].n_value);
	nproc = getw((off_t) nl[X_NPROC].n_value);
	for (i=0; i<nproc; i += PROCCHUNK) {
		KMlseek(kmem, (long) (char *)procp, 0);
		j = nproc - i;
		if (j > PROCCHUNK)
			j = PROCCHUNK;
		j *= sizeof (struct proc);
		if (read(kmem, (char *)proc, j) != j)
			cantread("proc table", kmemf);
		procp += j;
		for (j = j / sizeof (struct proc) - 1; j >= 0; j--) {
			mproc = &proc[j];
			if (mproc->p_stat == 0)
				continue;
			if (mproc->p_stat == SZOMB || getu() == 0)
				continue;
			doproc (mproc, &u);
		}
	}
	return 0;
}

getw(loc)
	off_t loc;
{
	long word;

	KMlseek(kmem, (long) loc, 0);
	if (read(kmem, (char *) &word, sizeof (word)) != sizeof (word))
		printf("error reading kmem at %x\n", loc);
	return (word);
}

openfiles()
{

	kmemf = "/dev/kmem";
	kmem = open(kmemf, 0);
	if (kmem < 0) {
		perror(kmemf);
		exit(1);
	}
	memf = "/dev/mem";
	mem = open(memf, 0);
	if (mem < 0) {
		perror(memf);
		exit(1);
	}
	swapf = "/dev/drum";
	swap = open(swapf, 0);
	if (swap < 0) {
		perror(swapf);
		exit(1);
	}
}

getkvars()
{
	nlistf = "/unix";
	nlist(nlistf, nl);
	if (nl[0].n_type == 0) {
		fprintf(stderr, "%s: No namelist\n", nlistf);
		exit(1);
	}
	Usrptma = (struct pte *)nl[X_USRPTMA].n_value;
	usrpt = (struct pte *)nl[X_USRPT].n_value;
	KMlseek(kmem, (long)nl[X_NSWAP].n_value, 0);
	if (read(kmem, (char *) &nswap, sizeof (nswap)) != sizeof (nswap)) {
		cantread("nswap", kmemf);
		exit(1);
	}
}

cantread(what, fromwhat)
	char *what, *fromwhat;
{
	fprintf(stderr, "ps: error reading %s from %s\n", what, fromwhat);
}



getu()
{
	struct pte *pteaddr, apte;
	int pad1;	/* avoid hardware botch */
	struct pte arguutl[UPAGES+CLSIZE];
	int pad2;	/* avoid hardware botch */
	register int i;
	int ncl, size;

	size = sizeof (struct user);
	if ((mproc->p_flag & SLOAD) == 0) {
		lseek(swap, (long) ctob(mproc->p_swaddr), 0);
		if (read(swap, (char *)&user.user, size) != size) {
			fprintf(stderr, "ps: cant read u for pid %d from %s\n",
			    mproc->p_pid, swapf);
			return (0);
		}
		pcbpf = 0;
		argaddr = 0;
		return (1);
	}
	pteaddr = &Usrptma[btokmx(mproc->p_p0br) + mproc->p_szpt - 1];
	KMlseek(kmem, (long)pteaddr, 0);
	if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) {
		printf("ps: cant read indir pte to get u for pid %d from %s\n",
		    mproc->p_pid, swapf);
		return (0);
	}
	lseek(mem,
	    (long) (ctob(apte.pg_pfnum+1) - (UPAGES+CLSIZE) * sizeof (struct pte)),
	    0);
	if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) {
		printf("ps: cant read page table for u of pid %d from %s\n",
		    mproc->p_pid, swapf);
		return (0);
	}
	if (arguutl[0].pg_fod == 0 && arguutl[0].pg_pfnum)
		argaddr = ctob(arguutl[0].pg_pfnum);
	else
		argaddr = 0;
	pcbpf = arguutl[CLSIZE].pg_pfnum;
	ncl = (size + NBPG*CLSIZE - 1) / (NBPG*CLSIZE);
	while (--ncl >= 0) {
		i = ncl * CLSIZE;
		lseek(mem, (long) ctob(arguutl[CLSIZE+i].pg_pfnum), 0);
		if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) {
			printf("ps: cant read page %d of u of pid %d from %s\n",
			    arguutl[CLSIZE+i].pg_pfnum, mproc->p_pid, memf);
			return(0);
		}
	}
	return (1);
}

KMlseek(f, a, c)
	long a;
{
	lseek(f, a, c);
}

#define	NMAX	8
#define	NUID	2048

char	names[NUID][NMAX+1];

/*
 * Stolen from ls...
 */
char *
getname(uid)
{
	register struct passwd *pw;
	static init;
	struct passwd *getpwent();

	if (uid >= 0 && uid < NUID && names[uid][0])
		return (&names[uid][0]);
	if (init == 2)
		return (0);
	if (init == 0)
		setpwent(), init = 1;
	while (pw = getpwent()) {
		if (pw->pw_uid >= NUID)
			continue;
		if (names[pw->pw_uid][0])
			continue;
		strncpy(names[pw->pw_uid], pw->pw_name, NMAX);
		if (pw->pw_uid == uid)
			return (&names[uid][0]);
	}
	init = 2;
	endpwent();
	return (0);
}

#define new(type) ((type *) alloc (sizeof (type)))

char	*freebase;
int	nleft;

char *
alloc(size)
	int size;
{
	register char *cp;
	register int i;

	if (size > nleft) {
		freebase = (char *)sbrk(i = size > 2048 ? size : 2048);
		if (freebase == 0) {
			fprintf(stderr, "ps: ran out of memory\n");
			exit(1);
		}
		nleft = i - size;
	} else
		nleft -= size;
	cp = freebase;
	for (i = size; --i >= 0; )
		*cp++ = 0;
	freebase = cp;
	return (cp - size);
}

char *
savestr(cp)
	char *cp;
{
	register int len;
	register char *dp;

	len = strlen(cp);
	dp = (char *)alloc(len+1);
	strcpy(dp, cp);
	return (dp);
}

/*
 *	read /dev, and record device names, block/character, and
 *	major/minor devices.
 */

#define DEVDIR "/dev"

struct devdesc {
	struct devdesc *next;
	char *name;
	int mode;
	dev_t dev;
} *devhead;

int
tryfile (name, p, code)
	char *name;
	register struct stat *p;
	int code;
{
	if (code == FTW_F) {
		register int mode = p->st_mode & S_IFMT;
		if (mode == S_IFBLK || mode == S_IFCHR) {
			register struct devdesc *dp;
			dp = new (struct devdesc);
			dp->name = savestr (name + sizeof (DEVDIR));
			dp->mode = mode;
			dp->dev = p->st_rdev;
			dp->next = devhead;
			devhead = dp;
		}
	}
	return 0;
}

struct procdesc {
	int pid;
	struct procdesc *next;
} *prochead;

struct pdevdesc {
	dev_t dev;
	int mode;
	ino_t ino;
	struct pdevdesc *next;
} *pdevhead;

initialize(c, v)
	int c;
	char **v;
{
	register int n;

	for (n = 1; n < c; n++) {
		if (isnumber (v[n])) {
			register struct procdesc *p;
			p = new (struct procdesc);
			p->pid = atoi (v[n]);
			p->next = prochead;
			prochead = p;
		} else {
			struct stat sb;
			if (stat (v[n], &sb) < 0)
				perror (v[n]);
			else {
				register int mode;
				register struct pdevdesc *pd;
				pd = new (struct pdevdesc);
				mode = sb.st_mode & S_IFMT;
				pd->mode = mode;
				if (mode == S_IFBLK || mode == S_IFCHR) {
					pd->dev = sb.st_rdev;
					pd->ino = 0;
				} else {
					pd->dev = sb.st_dev;
					pd->ino = sb.st_ino;
				}
				pd->next = pdevhead;
				pdevhead = pd;
			}
		}
	}

	if (pdevhead == NULL)
		ftw (DEVDIR, tryfile, 3);
}

int
isnumber (p)
	register char *p;
{
	while (isdigit (*p))
		p++;
	return *p == '\0';
}

/*
 *	Here, we handle a process.
 *
 *	Everything that has come before is essentially independent
 *	of what we are doing with the particular process.
 *
 *	If pdevhead is set, we are just going to print process numbers.
 *	The global variable "found" will greatly assist us in this:
 *	it will be set nonzero as soon as we decide to print this process.
 */

int found;

#undef u

void
printdev (str, dev, mode, rmode, ino)
	char *str;
	dev_t dev;
	int mode, rmode;
	ino_t ino;
{
	register struct devdesc *dp;
	register struct pdevdesc *pd;

	mode &= IFMT;
	rmode &= IFMT;

	if (pdevhead) {
		if (!found) {
			for (pd = pdevhead; pd; pd = pd->next) {
				if (dev == pd->dev && (pd->ino ?
				    (ino == pd->ino && rmode == pd->mode) :
				    (mode == pd->mode))) {
					found = 1;
					return;
				}
			}
		}
		return;
	}
		
	for (dp = devhead; dp; dp = dp->next) {
		if (mode == dp->mode && dev == dp->dev) {
			if (*str)
				printf ("%s ", str);
			if (ino)
				printf ("%d ", ino);
			if (*str)
				printf ("on ");
			printf ("%s", dp->name);
			return;
		}
	}

	printf ("(%d/%d)", major (dev), minor (dev));
}

struct inode *
getinode (ip, pid)
	struct inode *ip;
{
	static struct inode ibuf;
	KMlseek (kmem, (long) ip, 0);
	if (read (kmem, &ibuf, sizeof (ibuf)) != sizeof (ibuf)) {
		fprintf (stderr, "proc %d: can't read inode at %lx\n", pid, ip);
		return NULL;
	}
	return &ibuf;
}

void
doinode (str, ip, pid)
	register char *str;
	register struct inode *ip;
{
	int mode;

	if (ip && (ip = getinode (ip, pid))) {

		if (pdevhead) {
			if (found)
				return;
		} else
			printf ("\t%s: ", str);

		mode = ip->i_mode & IFMT;
		switch (mode) {

		case IFDIR:
			printdev ("dir", ip->i_dev, IFBLK, mode, ip->i_number);
			break;
		
		case IFREG:
			printdev ("file", ip->i_dev, IFBLK, mode, ip->i_number);
			break;
		
		case IFLNK:
			printdev ("slink", ip->i_dev, IFBLK, mode, ip->i_number);
			break;
		
		case IFBLK:
		case IFCHR:
			printdev ("", ip->i_un.i_rdev, ip->i_mode, mode, (ino_t) 0);
			break;
		
		default:
			fprintf (stderr, "??? mode %o", ip->i_mode);
			break;
		}
		if (pdevhead == NULL)
			printf ("\n");
	}

}

void
dotext (tp, pid)
	register struct text *tp;
{
	if (tp) {
		struct text t;
		KMlseek (kmem, (long) tp, 0);
		if (read (kmem, &t, sizeof (t)) != sizeof (t)) {
			fprintf (stderr, "can't read file at %lx\n", tp);
			return;
		}
		doinode ("prog", t.x_iptr, pid);
	}
}

void
dofile (n, fp)
	int n;
	register struct file *fp;
{
	if (fp) {
		struct file f;
		char buf[100];

		KMlseek (kmem, (long) fp, 0);
		if (read (kmem, &f, sizeof (f)) != sizeof (f)) {
			fprintf (stderr, "can't read file at %lx\n", fp);
			return;
		}
		sprintf (buf, "fd %d at %ld", n, f.f_offset);
		doinode (buf, f.f_inode);
	}
}

doproc (p, u)
	register struct proc *p;
	register struct user *u;
{
	struct inode *ip;
	register int i;

	found = 0;

	/* handle only selected processes if asked */
	if (prochead) {
		register struct procdesc *pd;

		pd = prochead;
		while (pd && pd->pid != p->p_pid)
			pd = pd->next;
		if (pd == NULL)
			return;
	}

	if (pdevhead == NULL)
		printf ("process %d, user %s\n", p->p_pid, getname(p->p_uid));

	dotext (p->p_textp, p->p_pid);
	doinode ("cdir", u->u_cdir, p->p_pid);

	if (!found)
		doinode ("rdir", u->u_rdir, p->p_pid);

	for (i = 0; i < NOFILE && !found; i++)
		dofile (i, u->u_ofile[i]);

	if (pdevhead) {
		if (found)
			printf ("%d\n", p->p_pid);
	} else {
		printf ("\n");
		fflush (stdout);
	}
}