[mod.computers.masscomp] cinfo demo program

masscomp@soma.UUCP (06/15/86)

Here is my attempt to use cinfo. It is not perfect, but perhaps
some of you can fix the problems that it has.
Use 
cc -O cinfo.c -o cinfo -lm
to compile.
==============================================================
#include <stdio.h>
#include <nlist.h>
#include <pwd.h>
#include <signal.h>
#include <sys/param.h>
#include <sys/pte.h>
#include <sys/dir.h>
#undef DIRSIZ
#define DIRSIZ 14
#include <sys/minmax.h>
#include <sys/cmap.h>
#include <sys/text.h>
#include <sys/cinfo.h>
#include <sys/user.h>
#include <sys/proc.h>

#define MAX_CMAP 2048
#define MAX_PROC 300
#define MAX_TEXT 100
#define KMEM "/dev/kmem"
#define MEM  "/dev/mem"
#define VMUNIX "/unix"

static char rcsid[]= "$Header: cinfo.c,v 1.1 86/06/14 16:40:07 sob Exp $";

extern int errno;
extern char * sys_errlist[];
struct nlist nlst[] = {
    { "_avenrun" },
#define X_AVENRUN	0
    { "_ccpu" },
#define X_CCPU		1
    { "_mpid" },
#define X_MPID          2
    { "_freemem" },
#define X_FREEMEM	3
    { 0 },
};

/* process state names for the "STATE" column of the display */

char *state_abbrev[] = {
    "", "sleep", "run", "WAIT", "idle", "", "","", "zomb","", "",
    "", "", "", "", "", "tired", "","", "","", "",
};

struct proc proc_v[MAX_PROC];
struct text text_v[MAX_TEXT];
struct cmap cmap_v[MAX_CMAP];
struct user u;

struct cu_des cu_des;
short proc_count;
short text_count;
short cmap_count;
int status,mem,kmem;
char * username();
/* this program attempts to do something like ps on a Masscomp */
/* it seems to work fine on a 5600/5700 but stil has problems on a 5500 */
static char * copyright = "Copyright 1986 Stan Barber\n";
/* This program may be freely distributed in source or binary as long as no
 * sale is made of this program in any form.
 * Stan Barber assumes no liability for the use of this program good or bad.
 * Stan Barber makes no guarentees relating to the correctness of this program
 * for any use, intended or otherwise.
 * This program may be used as source for other works as long 
 * as all material from the copyright statement to the end of this sentence
 * is retained in full without alteration.
 */
main()
{

struct proc *pp;

int i,cputime;
double pctcpu,logcpu,ccpu;

    /* open kmem and mem */
    if ((kmem = open(KMEM, 0)) < 0)
    {
	perror(KMEM);
	exit(1);
    }
    if ((mem = open(MEM, 0)) < 0)
    {
	perror(MEM);
	exit(1);
    }
    nlist(VMUNIX,nlst);
    getkval(nlst[X_CCPU].n_value,  &ccpu,  sizeof(int), nlst[X_CCPU].n_name);
    logcpu = log(ccpu);
while(1){
	system("clear");
	cu_des.p_max = MAX_PROC;
	cu_des.t_max = MAX_TEXT;
	cu_des.c_max = MAX_CMAP;
	status=cinfo(&cu_des,proc_v,text_v,cmap_v);

	if (status < 0){
	
		perror("cinfo");
		exit(-1);
	}

	proc_count = cu_des.p_ret;
	text_count = cu_des.t_ret;
	cmap_count = cu_des.c_ret;
	
	if (proc_count < 0 ){
	fprintf(stderr,"warning: not enough proc_v entries\n");
	proc_count = cu_des.p_max;
	}
	if (text_count < 0 ){
	fprintf(stderr,"warning: not enough text_v entries\n");
	text_count = cu_des.t_max;
	}
	if (cmap_count < 0 ){
	fprintf(stderr,"warning: not enough cmap_v entries\n");
	cmap_count = cu_des.c_max;
	}
	printf("\n  PID USERNAME PRI NICE   SIZE   RES STATE   TIME   WCPU    CPU COMMAND\n");

	    for (i = 0; i < proc_count; i++)
	    {
		pp = &proc_v[i];
		if (pp->p_pid !=0){
		if (getu(pp) == -1 || strlen(u.u_comm) == 0)
		{
		    strcpy(u.u_comm, "<swapped>");
		    cputime = 0;
		}
		else
		{
		    cputime = 
			(u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec);
		}

		pctcpu = pp->p_pctcpu;
		printf("%5d %-8.8s %3d %4d%6dK %4dK %-5s%4d:%02d %5.2f%% %5.2f%% %-14.14s\n",
		    pp->p_pid,
		    getpwuid(pp->p_uid)->pw_name,
		    pp->p_pri - PZERO,
		    pp->p_nice - NZERO,
		    (pp->p_tsize + pp->p_dsize + pp->p_ssize) >> 1,
		    pp->p_rssize >> 1,
		    state_abbrev[pp->p_stat],
		    cputime / 60l,
		    cputime % 60l,
		    pp->p_time == 0 ? 0.0 :
			pctcpu / (1.0 - exp(pp->p_time * logcpu)),
			pctcpu,
		    u.u_comm);
		}
	    }
      sleep(5);
    }
}

/*
 *  All of this stuff gets things out of the memory files.
 */

/*
 *  Get the user structure for the process who's proc structure is in p.  The
 *  user structure is returned in u.
 */
getu(p)

register struct proc *p;

{
    struct pte uptes[UPAGES];
    register caddr_t upage;
    register struct pte *pte;
    register nbytes, n;

    /*
     *  Check if the process is currently loaded or swapped out.  The way we
     *  get the u area is totally different for the two cases.  For this
     *  application, we just don't bother if the process is swapped out.
     */
    if ((p->p_flag & SLOAD) == 0)
    {
	return(-1);
    }

    /*
     *  Process is currently in memory, we hope!
     */
    if (!getkval(p->p_addr, uptes, sizeof(uptes), "p->p_addr"))
    {
	/* we can't seem to get to it, so pretend it's swapped out */
	return(-1);
    } 
    upage = (caddr_t)&u;
    pte = uptes;
    for (nbytes = sizeof(u); nbytes > 0; nbytes -= NBPG)
    {
    	lseek(mem, pte++->pg_pfnum * NBPG, 0);
	n = MIN(nbytes, NBPG);
	if (read(mem, upage, n) != n)
	{
	    /* we can't seem to get to it, so pretend it's swapped out */
	    return(-1);
	}
	upage += n;
    }
    return(0);
}
/*
 *  get the value of something from /dev/kmem
 */

getkval(offset, ptr, size, refstr)

long offset;
int *ptr;
int size;
char *refstr;

{
    if (lseek(kmem, offset, 0) == -1)
    {
	fprintf(stderr, "%s: lseek to %s: %s\n",
	    KMEM, refstr, sys_errlist[errno]);
	exit(1);
    }
    if (read(kmem, ptr, size) == -1)
    {
	if (strcmp(refstr, "p->p_addr") == 0) 
	{
	    /* we lost the race with the kernel, process isn't in memory */
	    return(0);
	} 
	else 
	{
	    fprintf(stderr, "%s: reading %s: %s\n",
		KMEM, refstr, sys_errlist[errno]);
	    exit(1);
	}
    }
    return(1);
}