|
|
researchv8 Dan Cross
#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);
}
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.