$OpenBSD: patch-wmmon_wmmon_c,v 1.4 2004/08/12 09:33:10 claudio Exp $
--- wmmon/wmmon.c.orig	1998-05-19 23:12:55.000000000 +0200
+++ wmmon/wmmon.c	2004-07-28 16:09:09.000000000 +0200
@@ -28,6 +28,10 @@
 	Changes:
 	----
 
+	28/09/2000 (Vladimir Popov, pva48@mail.ru)
+		* Ported to OpenBSD
+		  Based on FreeBSD port by Stephen Kiernan,
+		  OpenBSD top and vmstat
 	18/05/1998 (Antoine Nulle, warp@xs4all.nl)
 		* MEM/SWAP/UPTIME only updated when visible
 		* Using global file descriptors to reduce file
@@ -72,10 +76,20 @@
 #include <fcntl.h>
 #include <unistd.h>
 
+#include <errno.h>
+#include <signal.h>
+
 #include <sys/wait.h>
 #include <sys/param.h>
 #include <sys/types.h>
 
+#include <limits.h>
+#include <sys/disk.h>
+#include <sys/dkstat.h>
+#include <sys/malloc.h>
+#include <sys/swap.h>
+#include <sys/sysctl.h>
+
 #include <X11/Xlib.h>
 #include <X11/xpm.h>
 #include <X11/extensions/shape.h>
@@ -100,11 +114,11 @@
  /* Global Variables */
 /********************/
 
-char	*ProgName;
 int	stat_current = 0; /* now global */
-FILE	*fp_meminfo;
-FILE	*fp_stat;
-FILE	*fp_loadavg;
+int	ndrives;
+int	pagesize;
+int	pageshift;
+char	errbuf[_POSIX2_LINE_MAX];
 
 /* functions */
 void usage(void);
@@ -114,17 +128,15 @@ void DrawStats_io(int *, int, int, int, 
 
 void wmmon_routine(int, char **);
 
-void main(int argc, char *argv[]) {
+/* OpenBSD specific functions */
+#define	pagetok(size)	((size) << pageshift)
+int swapmode(long *, long *);
 
+int main(int argc, char *argv[])
+{
 	int		i;
-	
 
 	/* Parse Command Line */
-
-	ProgName = argv[0];
-	if (strlen(ProgName) >= 5)
-		ProgName += (strlen(ProgName) - 5);
-	
 	for (i=1; i<argc; i++) {
 		char *arg = argv[i];
 
@@ -155,22 +167,22 @@ void main(int argc, char *argv[]) {
 	}
 
 	wmmon_routine(argc, argv);
+
+	return 0;
 }
 
-/*******************************************************************************\
-|* wmmon_routine															   *|
-\*******************************************************************************/
+/***************************************************************************\
+|* wmmon_routine							   *|
+\***************************************************************************/
 
 typedef struct {
-
-	char	name[5];			/* "cpu0..cpuz", eventually.. :) */
-	int		his[55];
-	int		hisaddcnt;
+	char	name[5];	/* "cpu0..cpuz", eventually.. :) */
+	int	his[55];
+	int	hisaddcnt;
 	long	rt_stat;
 	long	statlast;
 	long	rt_idle;
 	long	idlelast;
-	
 } stat_dev;
 
 #define MAX_STAT_DEVICES (4)
@@ -182,7 +194,6 @@ char		*middle_action;
 
 
 int checksysdevs(void);
-void get_statistics(char *, long *, long *, long *);
 void DrawActive(char *);
 
 void update_stat_cpu(stat_dev *);
@@ -213,8 +224,9 @@ void wmmon_routine(int argc, char **argv
 	long		istat;
 	long		idle;
 
-	FILE		*fp;
-	char		temp[128];
+	int			mib[2];
+	size_t		size;
+	struct	timeval boottime;
 	char		*p;
 
 	int			xpm_X = 0, xpm_Y = 0;
@@ -223,22 +235,36 @@ void wmmon_routine(int argc, char **argv
 	long		ref_time = 0;
 	long		cnt_time;
 
-
-	fp = fopen("/proc/uptime", "r");
-	fp_meminfo = fopen("/proc/meminfo", "r");
-	fp_loadavg = fopen("/proc/loadavg", "r");
-	fp_stat = fopen("/proc/stat", "r");
-
-	if (fp) {
-		fscanf(fp, "%ld", &online_time);
-		ref_time = time(0);
-		fclose(fp);
+	mib[0] = CTL_KERN;
+	mib[1] = KERN_BOOTTIME;
+	size = sizeof(boottime);
+	if ( (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1) && (boottime.tv_sec != 0) ) {
+		ref_time = time(NULL);
+		online_time = ref_time - boottime.tv_sec + 30;
+	}
+
+	/* get the page size and calculate pageshift from it */
+	pagesize = sysconf(_SC_PAGESIZE);
+	pageshift = 0;
+	while (pagesize > 1) {
+		pageshift++;
+		pagesize >>= 1;
+	}
+
+	/* we only need the amount of log(2)1024 for our conversion */
+	pageshift -= 10;
+
+	mib[0] = CTL_HW;
+	mib[1] = HW_DISKCOUNT;
+	size = sizeof(ndrives);
+	if (sysctl(mib, 2, &ndrives, &size, NULL, 0) < 0 ) {
+		warn("could not read hw.diskcount");
+		ndrives = 0;
 	}
 
 	for (i=0; i<MAX_STAT_DEVICES; i++) {
-		for (j=0; j<55; j++) {
+		for (j=0; j<55; j++)
 			stat_device[i].his[j] = 0;
-		}
 		stat_device[i].hisaddcnt = 0;
 	}
 
@@ -246,19 +272,21 @@ void wmmon_routine(int argc, char **argv
 	if (RIGHT_ACTION) right_action = strdup(RIGHT_ACTION);
 	if (MIDDLE_ACTION) middle_action = strdup(MIDDLE_ACTION);
 
-	strcpy(temp, "/etc/wmmonrc");
-	parse_rcfile(temp, wmmon_keys);
+	parse_rcfile("/etc/wmmonrc", wmmon_keys);
 
-	p = getenv("HOME");
-	strcpy(temp, p);
-	strcat(temp, "/.wmmonrc");
-	parse_rcfile(temp, wmmon_keys);
-	
-	strcpy(temp, "/etc/wmmonrc.fixed");
-	parse_rcfile(temp, wmmon_keys);
+	if ((p = getenv("HOME")) != NULL) {
+#define RCFILE "/.wmmonrc"
+		char *tmp;
 
-	stat_online = checksysdevs();
+		if (asprintf(&tmp, "%s" RCFILE, p) != -1) {
+			parse_rcfile(tmp, wmmon_keys);
+			free(tmp);
+		}
+	}
 
+	parse_rcfile("/etc/wmmonrc.fixed", wmmon_keys);
+
+	stat_online = checksysdevs();
 
 	openXwindow(argc, argv, wmmon_master_xpm, wmmon_mask_bits, wmmon_mask_width, wmmon_mask_height);
 
@@ -266,18 +294,18 @@ void wmmon_routine(int argc, char **argv
 	AddMouseRegion(0, 12, 13, 58, 57);
 	AddMouseRegion(1, 5, 5, 24, 14);
 
-	starttime = time(0);
+	starttime = time(NULL);
 	nexttime = starttime + 10;
 
 	for (i=0; i<stat_online; i++) {
-		get_statistics(stat_device[i].name, &k, &istat, &idle);
-		stat_device[i].statlast = istat;
-		stat_device[i].idlelast = idle;
+		stat_device[i].statlast = 0;
+		stat_device[i].idlelast = 0;
 	}
-	if (stat_current == 0) DrawStats(stat_device[stat_current].his, 54, 40, 5, 58);
-	if (stat_current == 1) {
+	if (stat_current == 0)
+		DrawStats(stat_device[stat_current].his, 54, 40, 5, 58);
+	if (stat_current == 1)
 		DrawStats_io(stat_device[stat_current].his, 54, 40, 5, 58);
-	}
+
 	if (stat_current == 2) {
 		xpm_X = 64;
 		setMaskXY(-64, 0);
@@ -288,7 +316,7 @@ void wmmon_routine(int argc, char **argv
 	DrawActive(stat_device[stat_current].name);
 
 	while (1) {
-		curtime = time(0);
+		curtime = time(NULL);
 
 		waitpid(0, NULL, WNOHANG);
 
@@ -338,7 +366,7 @@ void wmmon_routine(int argc, char **argv
 
 			/*----------- online tijd neerzetten! ----------*/
 			
-			cnt_time = time(0) - ref_time + online_time;
+			cnt_time = time(NULL) - ref_time + online_time;
 
 			/* cnt_time = uptime in seconden */
 			/*
@@ -405,7 +433,6 @@ void wmmon_routine(int argc, char **argv
 			case DestroyNotify:
 				XCloseDisplay(display);
 				exit(0);
-				break;
 			case ButtonPress:
 				but_stat = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
 				break;
@@ -430,7 +457,6 @@ void wmmon_routine(int argc, char **argv
 						}
 					case 1:
 						stat_current++;
-						printf("current stat is :%d\n", stat_current);
 						if (stat_current == stat_online)
 							stat_current = 0;
 
@@ -460,9 +486,28 @@ void wmmon_routine(int argc, char **argv
 
 void update_stat_cpu(stat_dev *st) {
 
-	long	k, istat, idle;
+	static int	sysload_mib[] = {CTL_VM, VM_LOADAVG};
+	static int	cp_time_mib[] = {CTL_KERN, KERN_CPTIME};
+	struct loadavg	sysload;
+	double		infoload;
+	size_t		size;
+	long		cp_time[CPUSTATES];
+	long		istat, idle;
+	int		i;
 
-	get_statistics(st->name, &k, &istat, &idle);
+	/* mostly stolen from src/usr.bin/top/machine.c */
+	size = sizeof(cp_time);
+	if (sysctl(cp_time_mib, 2, &cp_time, &size, NULL, 0) < 0)
+		warn("sysctl kern.cp_time failed");
+
+	size = sizeof(sysload);
+	if (sysctl(sysload_mib, 2, &sysload, &size, NULL, 0) < 0)
+		warn("sysctl failed");
+	infoload = ((double) sysload.ldavg[0]) / sysload.fscale;
+
+	for (i = 0, istat = 0; i < CPUSTATES; i++)
+		if (i != CP_IDLE) istat += cp_time[i];
+	idle = cp_time[CP_IDLE];
 
 	st->rt_idle = idle - st->idlelast;
 	st->idlelast = idle;
@@ -470,136 +515,80 @@ void update_stat_cpu(stat_dev *st) {
 	st->rt_stat = istat - st->statlast;
 	st->statlast = istat;
 
-	st->his[54] += k;
+	st->his[54] += (long)(100 * infoload);
 	st->hisaddcnt += 1;
 }
 
 void update_stat_io(stat_dev *st) {
 
-	long			j, k, istat, idle;
-	static long		maxdiskio = 0;
-
-	get_statistics(st->name, &k, &istat, &idle);
-
-	st->rt_idle = idle - st->idlelast;
-	st->idlelast = idle;
+	struct diskstats	*q;
+	static int		 io_mib[] = {CTL_HW, HW_DISKSTATS};
+	static long		 maxdiskxfers = 0;
+	long			 xfers, rwstat;
+	size_t			 size;
+	int			 i;
+
+	size = ndrives * sizeof(struct diskstats);
+	q = malloc(size);
+	if (q == NULL)
+		err(1, NULL);
+	if (sysctl(io_mib, 2, q, &size, NULL, 0) < 0) {
+		warn("could not read hw.diskstats");
+		bzero(q, ndrives * sizeof(struct diskstats));
+	}
+
+	for (i = 0; i < ndrives; i++) {
+		rwstat += q[i].ds_rbytes + q[i].ds_wbytes;
+		xfers += q[i].ds_rxfer + q[i].ds_wxfer;
+	}
+	free(q);
+	
+	if (st->statlast == 0)
+		st->statlast = xfers;
+	if (xfers < st->statlast)
+		xfers = st->statlast;
+	st->rt_stat = xfers - st->statlast;
+	st->statlast = xfers;
 
-	st->rt_stat = istat - st->statlast;
-	st->statlast = istat;
+	if (maxdiskxfers < st->rt_stat)
+		maxdiskxfers = st->rt_stat;
 
-	j = st->rt_stat;
-	if (maxdiskio < j) {
-		maxdiskio = j;
-	}
-	st->rt_idle = maxdiskio - j;
+	st->rt_idle = maxdiskxfers - st->rt_stat;
+	st->idlelast = 0;
 
-	st->his[54] += st->rt_stat;
+	st->his[54] += rwstat;
 	st->hisaddcnt += 1;
 }
 
 void update_stat_mem(stat_dev *st, stat_dev *st2) {
 
-	char	temp[128];
-	unsigned long free, shared, buffers, cached;
+	struct vmtotal total;
+	size_t size = sizeof(total);
+	static int mib[] = { CTL_VM, VM_METER };
 
-	freopen("/proc/meminfo", "r", fp_meminfo);
-	while (fgets(temp, 128, fp_meminfo)) {
-		if (strstr(temp, "Mem:")) {
-			sscanf(temp, "Mem: %ld %ld %ld %ld %ld %ld",
-			       &st->rt_idle, &st->rt_stat,
-			       &free, &shared, &buffers, &cached);
-			st->rt_idle >>= 10;
-			st->rt_stat -= buffers+cached;
-			st->rt_stat >>= 10;
-//			break;
-		}
-		if (strstr(temp, "Swap:")) {
-			sscanf(temp, "Swap: %ld %ld", &st2->rt_idle, &st2->rt_stat);
-			st2->rt_idle >>= 10;
-			st2->rt_stat >>= 10;
-			break;
-		}
-	}
-}
-
-void update_stat_swp(stat_dev *st) {
-
-	char	temp[128];
-
-	fseek(fp_meminfo, 0, SEEK_SET);
-	while (fgets(temp, 128, fp_meminfo)) {
-		if (strstr(temp, "Swap:")) {
-			sscanf(temp, "Swap: %ld %ld", &st->rt_idle, &st->rt_stat);
-			st->rt_idle >>= 10;
-			st->rt_stat >>= 10;
-			break;
-		}
-	}
-
-}
-
-/*******************************************************************************\
-|* get_statistics															   *|
-\*******************************************************************************/
+	/* get total -- systemwide main memory usage structure */
+	if ( sysctl(mib, 2, &total, &size, NULL, 0) < 0 )
+		bzero(&total, sizeof(total));
 
-void get_statistics(char *devname, long *is, long *ds, long *idle) {
-
-	int	i;
-	char	temp[128];
-	char	*p;
-	char	*tokens = " \t\n";
-	float	f;
-	long	maxdiskio=0;
-
-	*is = 0;
-	*ds = 0;
-	*idle = 0;
-
-	if (!strncmp(devname, "cpu", 3)) {
-		fseek(fp_stat, 0, SEEK_SET);
-		while (fgets(temp, 128, fp_stat)) {
-			if (strstr(temp, "cpu")) {
-				p = strtok(temp, tokens);
-				/* 1..3, 4 == idle, we don't want idle! */
-				for (i=0; i<3; i++) {
-					p = strtok(NULL, tokens);
-					*ds += atol(p);
-				}
-				p = strtok(NULL, tokens);
-				*idle = atol(p);
-			}
-		}
-		fp_loadavg = freopen("/proc/loadavg", "r", fp_loadavg);
-		fscanf(fp_loadavg, "%f", &f);
-		*is = (long) (100 * f);
-	}
+	/* FIXME: is it right to count memory like this */
+	st->rt_idle = pagetok(total.t_rm + total.t_free);
+	st->rt_stat = pagetok(total.t_rm);
 
-	if (!strncmp(devname, "i/o", 3)) {
-
-		fseek(fp_stat, 0, SEEK_SET);
-		while (fgets(temp, 128, fp_stat)) {
-			if (strstr(temp, "disk_rio") || strstr(temp, "disk_wio")) {
-				p = strtok(temp, tokens);
-				/* 1..4 */
-				for (i=0; i<4; i++) {
-					p = strtok(NULL, tokens);
-					*ds += atol(p);
-				}
-			}
-		}
-		if (*ds > maxdiskio) maxdiskio = *ds;
+	if ( !swapmode(&st2->rt_stat, &st2->rt_idle) ) {
+		st2->rt_idle = 0;
+		st2->rt_stat = 0;
 	}
 }
 
-/*******************************************************************************\
-|* checksysdevs																   *|
-\*******************************************************************************/
+/***************************************************************************\
+|* checksysdevs								   *|
+\***************************************************************************/
 
 int checksysdevs(void) {
 
-	strcpy(stat_device[0].name, "cpu0");
-	strcpy(stat_device[1].name, "i/o");
-	strcpy(stat_device[2].name, "sys");
+	strncpy(stat_device[0].name, "cpu0", 5);
+	strncpy(stat_device[1].name, "i/o", 5);
+	strncpy(stat_device[2].name, "sys", 5);
 
 	return 3;
 }
@@ -733,7 +722,35 @@ void usage(void) {
 
 void printversion(void) {
 
-	if (!strcmp(ProgName, "wmmon")) {
-		fprintf(stderr, "%s\n", WMMON_VERSION);
-	}
+	fprintf(stderr, "%s\n", WMMON_VERSION);
+}
+
+int swapmode(long *used, long *total) {
+	int nswap, rnswap, i;
+	struct swapent *swdev;
+
+	nswap = swapctl(SWAP_NSWAP, 0, 0);
+	if (nswap == 0) 
+		return 0;
+
+	swdev = malloc(nswap * sizeof(*swdev));
+	if(swdev == NULL)
+		return 0;
+
+	rnswap = swapctl(SWAP_STATS, swdev, nswap);
+	if(rnswap == -1)
+		return 0;
+
+	/* if rnswap != nswap, then what? */
+
+	/* Total things up */
+	*total = *used = 0;
+	for (i = 0; i < nswap; i++)
+		if (swdev[i].se_flags & SWF_ENABLE) {
+			*used += (swdev[i].se_inuse / (1024/DEV_BSIZE));
+			*total += (swdev[i].se_nblks / (1024/DEV_BSIZE));
+		}
+
+	free (swdev);
+	return 1;
 }
