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);
}