#include <stdio.h>
#include "unix.h"

struct p_tab ptab[PTABSIZE];

int swap;  /* Swap file */
int mem;  /* kemem file */

unsigned ptabaddr;  /* Address of process table in system memory */

char *ctime();
char *etime();

_main()
{
    ptptr p;

    if (symval("/unix", "ptab", &ptabaddr))
    {
	fprintf(stderr, "Can't read /unix.sym\n");
	exit (1);
    }

    swap = open("/dev/swap",0);
    if (swap < 0)
    {
  	perror("Can't open /dev/swap");
	exit(1);
    }

    mem = open("/dev/kmem",0);
    if (mem < 0)
    {
  	perror("Can't open /dev/kmem");
	exit(1);
    }

    /* Seek to and read process table in kmem */
    if (seek(mem,ptabaddr,0)==-1)
    {
	perror("Can't seek /dev/kmem");
	exit(1);
    }

    if (read(mem,ptab,sizeof(ptab)) != sizeof(ptab))
    {
	perror("Can't read /dev/kmem");
	exit(1);
    }

    printf("PID   PPID  USER  TTY WAIT SIZE  START    TIME       NAME     STAT\n");

    for (p=ptab; p < ptab+PTABSIZE; ++p)
    {
	if (p->p_status != P_EMPTY)
	    doproc(p);
    }

    exit(0);
}


char *stats[] = {
	"EMPTY???",
	"RUNNING",
	"READY",
	"SLEEPING",
	"XSLEEPING",
	"PAUSED",
	"FORKING",
	"WAITING",
	"DEFUNCT" };


char ubuf[512];

doproc(p)
ptptr p;
{
    char startstr[9];
    char uname[9];
    int j;
    struct u_data *udp;

	/* Read in the user data from the swap */
        if (seek(swap,p->p_swap,3)==-1)
        {
	    perror("Can't seek /dev/swap");
	    exit(1);
        }

        if (read(swap,ubuf,512) != 512)
        {
	    perror("Can't read /dev/swap");
	    exit(1);
        }

        /* point to u_data structure */
        udp = (struct u_data *)(ubuf);


    /* Add up user and system times */
    addtick(&(udp->u_utime), &(udp->u_stime));

    strncpy(startstr,ctime(&(udp->u_time)),8);
    startstr[8] = '\0';

    strncpy(uname, udp->u_name, 8);
    uname[8] = '\0';
    for (j=0; j<8; ++j)
	if (uname[j] && uname[j] < ' ')
	    uname[j] = '?';

    printf("%-5d %-5d %-5d %-3d %-4x %-5u %-8s %-8s %-8s %s\n",
	p->p_pid,
	((ptptr)((unsigned)ptab + ((unsigned)p->p_pptr - (unsigned)ptabaddr)))->p_pid,
	p->p_uid, p->p_tty, p->p_wait, 
        udp->u_break, startstr, etime(&(udp->u_utime)), uname,
	(p->p_status < 0 || p->p_status > P_ZOMBIE ?
		"INVALID!!" : stats[p->p_status]));

}


/* This adds two tick counts together.
The t_time field holds up to one second of ticks,
while the t_date field counts minutes */

addtick(t1,t2)
time_t *t1, *t2;
{

    t1->t_time += t2->t_time;
    t1->t_date += t2->t_date;
    if (t1->t_time >= 60*TICKSPERSEC)
    {
	t1->t_time -= 60*TICKSPERSEC;
	++t1->t_date;
    }
}





#define SLEN 6

symval(program, name, val)
char *program;
char *name;
unsigned *val;
{
	int n;
	FILE *f;
	char fname[20];
	char sname[SLEN+2];
	char rdname[20];

	strncpy(fname, program, 15);
	strcat(fname, ".sym");

	/* Copy the symbol name, adding the trailing '?', changing '_' to
	'@', and trimming to SLEN chars */

	strncat(sname, name, SLEN);
	strcat(sname, "?");
	sname[SLEN] = '\0';
	for (n=0; n < SLEN; ++n)
	{
		sname[n] = chupper(sname[n]);
		if (sname[n] == '_')
			sname[n] = '@';
	}

	f = fopen(fname, "r");

	if (f == NULL)
		return (-1);

	for(;;)
	{
		n = fscanf(f, "%x %18s", val, rdname);

		if (n != 2 || ferror(f) || feof(f))
			break;

		if (!strcmp(sname, rdname))
		{
			fclose(f);
			return (0);
		}
	}

	fclose(f);
	return (-1);
}
