/*
 * System dependent file for 4.4BSD derivatives.  Works on FreeBSD 2.x.
 * Should work on NetBSD 1.x and OpenBSD
 * Based on s-bsd.c by Chris Siebenmann <cks@sys.toronto.edu>
 */
/* David O'Brien, University of California at Davis <obrien@cs.ucdavis.edu> */
/*
 * Utilizes the kvm library avalible on BSD 4.4.
 * Binary should be sgid ``kmem''
 */

/* LINTLIBRARY */

#include <sys/param.h>
#if !(defined(BSD) && (BSD >= 199306)) 	/* ie. BSD 4.4 systems */
#error This is not a 4.4BSD-Lite dervived system.
#endif

#include <sys/dkstat.h>
#include <kvm.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>		/* for perror() */

#include <nlist.h>


extern char *xmalloc(/* int nbytes */);
extern void shorten(/* char *hname */);

extern char *kernelSymbols;
static kvm_t *kmem;			/* pointer into the kmem */

long	cp_time[CPUSTATES];
long	cp_old[CPUSTATES];

struct nlist	nl[] = {
#define	X_CP_TIME	0
	{ "_cp_time" },
	{ "" },
};

#define NPROCS 1

/* Called by -version */
void
version()
{
	printf("BSD4.4+: maxcpu=%d, maxdisk=0\n", NPROCS);
}

/* Called at the beginning to inquire how many bars are needed. */
int
num_bars()
{
	return NPROCS;
}

/*
 * Indicates how many levels each bar has.  For most machines, each bar will
 * have the same stuff.  But one can, for instance, display memory use on one
 * bar, processor levels on others, etc.
 */
void
bar_items(nbars, items)
int nbars;
int items[];    /* nbars items in this */
{
    items[0] = CPUSTATES;
}

/* Called after num_bars to ask for the bar names */
/* ARGSUSED */
char **
label_bars(nbars)
{
	static char hname[MAXHOSTNAMELEN + 1];
	static char *names[NPROCS];

	names[0] = hname;
	hname[MAXHOSTNAMELEN] = '\0';
	if (gethostname(hname, MAXHOSTNAMELEN) < 0) {
		perror("gethostname");
		*hname = '\0';
	}
	shorten(hname);
	return names;
}

/* 
 *  Called after the bars are created to perform any machine dependent
 *  initializations.
 */
/* ARGSUSED */
void
init_bars(nbars)
int nbars;
{
	int j;
	char errbuf[ 1024 ];

	/* if ((kmem = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL) { */
	if ((kmem = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL) {
		perror("/dev/kmem");
		fprintf(stderr, "%s\n", errbuf );
		exit(1);
	}
	/* get the list of symbols we want to access in the kernel */
	if (kvm_nlist(kmem, nl) == -1) 
		fprintf( stderr, "kvm error, %s\n", kvm_geterr(kmem));
		
	if (nl[0].n_type == 0)
		fprintf(stderr, "nlist failed\n");

	if ((j=kvm_read(kmem, nl[X_CP_TIME].n_value, (char *) cp_old,
		sizeof cp_old)) != sizeof cp_old) {
		perror("kvm_read,1");
		fprintf( stderr, "kvm_read returns %d\n", j );
		fprintf( stderr, "kvm error, %s\n", kvm_geterr(kmem));
	}
}

/* 
 *  This procedure gets called every interval to compute and display the
 *  bars. It should call draw_bar() with the bar number, the array of
 *  integer values to display in the bar, and the number of values in
 *  the array.
 */
/* ARGSUSED */
void
display_bars(nbars)
{
	int	states[CPUSTATES];
	int	nstates;
	int	i;
	extern void draw_bar(/*int bar_num, int *states, int num_states*/);
	
	if ((i=kvm_read(kmem, nl[X_CP_TIME].n_value, (char *) cp_time,
		sizeof cp_time)) != sizeof cp_time)
	{
		perror("kvm_read,2");
		fprintf( stderr, "kvm_read returns %d\n", i );
		fprintf( stderr, "kvm error, %s\n", kvm_geterr(kmem));
	}
	
#define delta(cpustate) ((int) (cp_time[(cpustate)] - cp_old[(cpustate)]))

	nstates = 0;
	states[nstates++] = delta(CP_IDLE);
	states[nstates++] = delta(CP_USER);
	states[nstates++] = delta(CP_NICE);
	states[nstates++] = delta(CP_SYS);
	draw_bar(0, states, nstates);
	for (i = 0; i < CPUSTATES; i ++)
		cp_old[i] = cp_time[i];
}


syntax highlighted by Code2HTML, v. 0.9.1