/***********************************************************
 * getload.c                                               *
 * get system load from kernel                             *
 * Verteilte Systeme II Kapitel 10                         *
 ***********************************************************
 * 1998 by Frank Kargl (frank.kargl@informatik.uni-ulm.de) *
 ***********************************************************
 * Usage: getload (superuser only)                         *
 ***********************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <sys/cpuvar.h>
#include <sys/fault.h>
#include <sys/fcntl.h>
#include <sys/param.h>
#include <sys/sysinfo.h>
#include <sys/utsname.h>
#include <sys/types.h>
#include <unistd.h>
#include <kvm.h>

/* defines and some stuff snarfed from 'top' */
#ifndef	FSCALE
#define	FSHIFT		8	/* bits to right of fixed binary point */
#define	FSCALE		(1<<FSHIFT)
#endif

#define	LOADDOUBLE(value)	((double)(value) / FSCALE)

#define	NLIST_AVENRUN	0

/* some local identifiers */
static	kvm_t		*KernelFD;	/* kernel file-handle */
static	struct nlist	NList[] = {	/* list of needed kernel symbols */
	{"avenrun"},			/* load average */
	{0}};

/***********************************************************
 *                                                         *
 * Function:                                               *
 * void OS_Init(void)                                      *
 * open kernel for reading                                 *
 * Parameters:                                             *
 *  -                                                      *
 * Return:                                                 *
 *  -                                                      *
 *                                                         *
 ***********************************************************/

void OS_Init(void) {
    if ((KernelFD =
	kvm_open(NULL, NULL, NULL, O_RDONLY, "KERNEL")) == NULL ||
	kvm_nlist(KernelFD, NList) == -1) {
	perror("OS_Init()");
	exit(1);
    }
}
 
/***********************************************************
 *                                                         *
 * Function:                                               *
 * void OS_Exit(void)                                      *
 * close kernel                                            *
 * Parameters:                                             *
 *  -                                                      *
 * Return:                                                 *
 *  -                                                      *
 *                                                         *
 ***********************************************************/

void OS_Exit(void) {
    if (KernelFD) {
	kvm_close(KernelFD);
    }
}
 
/***********************************************************
 *                                                         *
 * Function:                                               *
 * int OS_GetLoad(void)                                    *
 * get load value from kernel                              *
 * Parameters:                                             *
 *  -                                                      *
 * Return:                                                 *
 *  int - load value (1min)                                *
 *                                                         *
 ***********************************************************/

int OS_GetLoad(void) {

    long	runqueue[3];	/* load average */
    double	load;		/* return load */

    /* get 'avenrun' symbol for load information */
    if (kvm_read(KernelFD, NList[NLIST_AVENRUN].n_value,
	(char *) runqueue, sizeof(runqueue)) == -1) {
	perror("OS_GetDynamicSystemInformation()");
	exit(1);
    }

    /* assign value */
    load = LOADDOUBLE(runqueue[0]);
    return load;

}

/* main - call the other functions */
int main() {

    double load;
    
    OS_Init();
    load = OS_GetLoad();
    OS_Exit();

    printf("The load is %lf\n", load);
    
}
