--- asmon/asmon.c	Sun Jun 27 20:38:26 1999
+++ asmon/asmon.c.new	Sat Oct 26 06:26:34 2002
@@ -21,6 +21,24 @@
 #include "asmon-master.xpm"
 #include "asmon-mask.xbm"
 
+#ifdef __FreeBSD__
+#include <err.h>
+#include <kvm.h>
+#include <nlist.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/vmmeter.h>
+#include <sys/sysctl.h>
+#include <vm/vm.h>
+#include <vm/vm_map.h>
+#include <vm/vm_param.h>
+#include <sys/time.h>
+#if __FreeBSD_version < 400000
+#include <sys/rlist.h>
+#endif
+#endif
+
 #ifdef __solaris__
 #include <utmp.h>
 #endif
@@ -47,6 +65,56 @@
 #define B_RED   (1)
 #define B_GREEN (2)
 
+#ifdef __FreeBSD__
+kvm_t   *kd;
+
+#define SVAR(var) __STRING(var) /* to force expansion */
+#define KGET(idx, var)                          \
+  KGET1(idx, &var, sizeof(var), SVAR(var))
+#define KGET1(idx, p, s, msg)                       \
+  KGET2(nl[idx].n_value, p, s, msg)
+#define KGET2(addr, p, s, msg)                      \
+  if (kvm_read(kd, (u_long)(addr), p, s) != s)            \
+      warnx("cannot read %s: %s", msg, kvm_geterr(kd))
+
+struct nlist nl[] = {
+#if __FreeBSD_version < 400000
+#define VM_SWAPLIST 0
+  { "_swaplist" },/* list of free swap areas */
+#define VM_SWDEVT   1
+  { "_swdevt" },  /* list of swap devices and sizes */
+#define VM_NSWAP    2
+  { "_nswap" },   /* size of largest swap device */
+#define VM_NSWDEV   3
+  { "_nswdev" },  /* number of swap devices */
+#define VM_DMMAX    4
+  { "_dmmax" },   /* maximum size of a swap block */
+#define X_CNT       5
+  { "_cnt" },
+#define X_BUFSPACE  6
+  { "_bufspace" },    /* K in buffer cache */
+#define X_CP_TIME   7
+  { "_cp_time" },
+  { "" }
+};
+#else
+#define X_CCPU      0
+    { "_ccpu" },
+#define X_CP_TIME   1
+	{ "_cp_time" },
+#define X_AVENRUN   2
+	{ "_averunnable" },
+#define X_BUFSPACE  3
+	{ "_bufspace" },		/* K in buffer cache */
+#define X_CNT       4
+	{ "_cnt" },				/* struct vmmeter cnt */
+#define X_LASTPID   5
+	{ "_nextpid" },			/* Last pid */
+	{ 0 }
+};
+#endif
+#endif
+
 /* Evil globals I haven't removed yet */
 long last_pageins=0, last_pageouts=0;
 long last_swapins=0, last_swapouts=0;
@@ -77,6 +145,11 @@
 float DrawMemSwap(float total, int allmem);
 #endif
 
+#ifdef __FreeBSD__
+void open_kvm(void);
+void close_kvm(void);
+#endif
+
 int main(int argc, char *argv[]) 
 {
 	FILE *fp;
@@ -151,7 +224,17 @@
 #endif
 	/* Open 64x64 window */
 	openXwindow(argc, argv, asmon_master_xpm, asmon_mask_bits, asmon_mask_width, asmon_mask_height);
+
+#ifdef __FreeBSD__
+	open_kvm();
+#endif
+
 	asmon_routine(Xpid, allmem);
+
+#ifdef __FreeBSD__
+	close_kvm();
+#endif
+
 	return(0);
 }
 
@@ -160,7 +243,11 @@
 void usage(void) {
     fprintf(stderr, "\nasmon %s - by Brad Hall (brad@rio.dhs.org)\n\t\toriginally based on Timecop's wmcpu\n\n", ASMON_VERSION);
     fprintf(stderr, "The top bar: left is the CPU usage, right is the load average\n");
+#ifdef __FreeBSD__
+	fprintf(stderr, "The middle bar: left memory usage devided by ticks into active, inactive,\n\t\twired, cached + buffers, respectively, and the number\n\t\tof megs used\n");
+#else
     fprintf(stderr, "The middle bar: left memory usage devided by ticks into shared, buffers, and\n\t\t cached, respectively, and the number of megs used\n");
+#endif
     fprintf(stderr, "The lower bar: the left swap usage and the number of megs swappedd avg\n");
     fprintf(stderr, "The bottom: the left is a set of LED's marking page's and swap's, the right is\n\t\t a bar representing the amount of memory that the X server \n\t\t is taking up, and the exact megs\n\n usage:\n");
     fprintf(stderr, "\t-display <display name>\n");
@@ -168,8 +255,13 @@
     fprintf(stderr, "\t-v\tprint the version number\n");
 #ifndef __solaris__
     fprintf(stderr, "\t-u\tforce asmon to show uptime, rather than X mem use\n");
+#else
+#ifdef __FreeBSD__
+	fprintf(stderr, "\t-m\tmake asmon show only active mem\n");
+#else
     fprintf(stderr, "\t-m\tmake asmon show only shared mem, like most other mem meters\n");
 #endif
+#endif
 #ifdef EXEC_ON_CLICK
     fprintf(stderr, "\t-e cmd\texecute 'cmd' on mouse click\n");
 #endif
@@ -229,6 +321,10 @@
 #if 0
 				fprintf(stderr,"system(%s)\n",Command);
 #endif
+				if (setgid(getgid()) != 0)
+					err(1, "Can't drop setgid privileges.");
+				if (setuid(getuid()) != 0)
+					err(1, "Can't drop setuid privileges.");
 				if (Command[ 0 ]) system(Command);
 				break;
 #endif
@@ -323,12 +419,13 @@
 /* CPU Usage Meter */
 void DrawCPU(void)
 {
-	FILE *fp;
 	static float cpustat[4];   /* remember the statistics read last time */
 	float fields[4], info[4], cputotal=0.0;
 	long pageins=0, pageouts=0, swapins=0, swapouts=0;
-	char buf[128];
 	int i;
+#ifndef __FreeBSD__
+	char buf[128];
+	FILE *fp;
 
 	if( (fp = fopen("/proc/stat", "r")) != NULL)
 	{
@@ -345,7 +442,15 @@
     		    sscanf(buf, "swap %ld %ld", &swapins, &swapouts);
 	    } 
 	    fclose(fp);
-
+#else
+	{
+		long cputime[4];
+		struct vmmeter sum;
+ 
+		kvm_read(kd, nl[X_CP_TIME].n_value, &cputime, sizeof(cputime));
+		for(i = 0; i < 4; i++)
+			info[i] = (float)cputime[i];
+#endif
 	    // Calculate CPU stuff
 	    for(i = 0; i < 4; i++)
 	    { 
@@ -365,6 +470,13 @@
 	    }
 
 	    // Page In/Out
+#ifdef __FreeBSD__
+		KGET(X_CNT, sum);
+		pageins = sum.v_vnodepgsin;
+		pageouts = sum.v_vnodepgsout;
+		swapins = sum.v_swappgsin;
+		swapouts = sum.v_swappgsout;
+#endif
 	    if (pageins > last_pageins)
 	    {
     	        DrawLite(B_RED, 5, 48);
@@ -414,12 +526,19 @@
 #ifdef __solaris__
     if (getLoad(&ftmp) != -1)
     {
-#else
+#else 
+#ifndef __FreeBSD__
     FILE *fp;
     if( (fp = fopen("/proc/loadavg", "r")) != NULL)
     {
 	fscanf(fp, "%f", &ftmp);
 	fclose(fp);
+#else
+	{
+	double avg[1];
+	getloadavg(avg, 1);
+	ftmp = (float)avg[0];
+#endif
 #endif
 	if(oldv != ftmp)
 	{
@@ -540,6 +659,7 @@
 /* Mem/Swap Meter */
 float DrawMemSwap(float total, int allmem)
 {
+#ifndef __FreeBSD__
     FILE *fp;
     if( (fp = fopen("/proc/meminfo", "r")) != NULL)
     {
@@ -553,6 +673,149 @@
 	fgets(junk, 80, fp);
 	fscanf(fp, "Mem: %f %f %f %f %f %f\nSwap: %f %f %f",  &total, &used, &freeM, &shared, &buffers, &cached, &swaptotal, &swapused, &swapfreeM);
 	fclose(fp);
+#else
+	{
+	static float stotal=0.0, sshared=0.0, sbuffers=0.0, scached=0.0;
+#if __FreeBSD_version >= 400000
+    float used, active, inactive, wired, buffers, cached, shared = 0;
+	static float swaptotal=0, swapused=0;
+	static u_int swappgsin= - 1, swappgsout = -1;
+	int n, bufspace = 0;
+	int pagesize = getpagesize();
+	struct kvm_swap swapary[1];
+#else
+	float used, active, inactive, wired, buffers, cached, swaptotal, 
+		swapused, shared;
+	int nswap, nswdev, dmmax;
+	int i, avail, nfree, kmemused, bufspace = 0;
+	struct swdevt *sw;
+	long *perdev;
+	struct rlist head;
+	struct rlisthdr swaplist;
+	struct rlist *swapptr;
+	u_long ptr;
+#endif
+	struct vmmeter sum;
+	int tempy, tempa;
+	unsigned long MEMactive,MEMinactive,MEMwired,MEMbuff,MEMcach, MEMswap;
+ 
+#if __FreeBSD_version >= 400000
+#define CONVERT(v)  ((quad_t)(v) * pagesize / 1024)
+    KGET(X_CNT, sum);
+	KGET(X_BUFSPACE, bufspace);
+	if(swappgsin < 0 || swappgsin != sum.v_swappgsin ||
+							swappgsout != sum.v_swappgsout){
+		n = kvm_getswapinfo(kd, swapary, 1, 0);
+		if (n < 0 || swapary[0].ksw_total == 0){
+			swaptotal = 0;
+			swapused = 0;
+		} else {
+			swaptotal = CONVERT(swapary[0].ksw_total);
+			swapused = CONVERT(swapary[0].ksw_used);
+			swaptotal *= 1024;
+			swapused *= 1024;
+		}
+		swappgsin = sum.v_swappgsin;
+		swappgsout = sum.v_swappgsout;
+	}
+	total = sum.v_page_size * sum.v_page_count;
+	cached = sum.v_page_size * sum.v_cache_count;
+	used = sum.v_page_size * (sum.v_page_count - sum.v_free_count);
+	buffers = bufspace;
+	active = sum.v_page_size * sum.v_active_count;
+	inactive = sum.v_page_size * sum.v_inactive_count;
+	wired = sum.v_page_size * sum.v_wire_count;
+#else
+	KGET(VM_NSWAP, nswap);
+	KGET(VM_NSWDEV, nswdev);
+	KGET(VM_DMMAX, dmmax);
+	KGET1(VM_SWAPLIST, &swaplist, sizeof swaplist, "swaplist");
+	if ((sw = (struct swdevt*)malloc(nswdev * sizeof(*sw))) == NULL ||
+			(perdev = (long *)malloc(nswdev * sizeof(*perdev))) == NULL)
+		errx(1, "malloc");
+	KGET1(VM_SWDEVT, &ptr, sizeof ptr, "swdevt");
+	KGET2(ptr, sw, nswdev * sizeof(*sw), "*swdevt");
+
+	/* Count up swap space. */
+	nfree = 0;
+	memset(perdev, 0, nswdev * sizeof(*perdev));
+	swapptr = swaplist.rlh_list;
+	while (swapptr) {
+		int top, bottom, next_block;
+ 
+		KGET2(swapptr, &head, sizeof(struct rlist), "swapptr");
+
+		top = head.rl_end;
+		bottom = head.rl_start;
+ 
+		nfree += top - bottom + 1;
+ 
+	   /*
+		* Swap space is split up among the configured disks.
+		*
+		* For interleaved swap devices, the first dmmax blocks
+		* of swap space some from the first disk, the next dmmax
+		* blocks from the next, and so on up to nswap blocks.
+		*
+		* The list of free space joins adjacent free blocks,
+		* ignoring device boundries.  If we want to keep track
+		* of this information per device, we'll just have to
+		* extract it ourselves.
+		*/
+		while (top / dmmax != bottom / dmmax) {
+			next_block = ((bottom + dmmax) / dmmax);
+			perdev[(bottom / dmmax) % nswdev] +=
+			next_block * dmmax - bottom;
+			bottom = next_block * dmmax;
+		}
+		perdev[(bottom / dmmax) % nswdev] +=
+		top - bottom + 1;
+ 
+		swapptr = head.rl_next;
+	}
+   
+	avail = 0;
+	for (i = 0; i < nswdev; i++) {
+		int xsize, xfree;
+   
+		/*
+		* Don't report statistics for partitions which have not
+		* yet been activated via swapon(8).
+		*/
+		if (!(sw[i].sw_flags & SW_FREED))
+			continue;
+ 
+		/* The first dmmax is never allocated to avoid trashing of
+		* disklabels
+		*/
+		xsize = sw[i].sw_nblks - dmmax;
+		xfree = perdev[i];
+		kmemused = xsize - xfree;
+		avail += xsize;
+	}
+   
+	/*
+	* If only one partition has been set up via swapon(8), we don't
+	* need to bother with totals.
+	*/
+	kmemused = avail - nfree;
+	KGET(X_CNT, sum);
+	KGET(X_BUFSPACE, bufspace);
+	free(sw);
+	free(perdev);
+ 
+	swaptotal = avail * 512;
+	swapused = kmemused * 512;
+#endif
+   
+	total = sum.v_page_size * sum.v_page_count;
+	cached = sum.v_page_size * sum.v_cache_count;
+	used = sum.v_page_size * (sum.v_page_count - sum.v_free_count);
+	buffers = bufspace;
+	active = sum.v_page_size * sum.v_active_count;
+	inactive = sum.v_page_size * sum.v_inactive_count;
+	wired = sum.v_page_size * sum.v_wire_count;
+#endif
 
 	if ( allmem == 1) {
 	/* All mem areas */
@@ -561,11 +824,23 @@
 			stotal = total; sshared = shared; sbuffers = buffers; scached = cached;
 			if ( (total/101048576) >= 1) 
 			{
+#ifdef __FreeBSD__
+				MEMactive=(active/total)*27;
+				MEMinactive=(inactive/total)*27;
+				MEMwired=(wired/total)*27;
+#else
 			    MEMshar=(shared/total)*27;
+#endif
 			    MEMbuff=(buffers/total)*27;
 			    MEMcach=(cached/total)*27;
 			} else {
+#ifdef __FreeBSD__
+				MEMactive=(active/total)*33;
+				MEMinactive=(inactive/total)*33;
+				MEMwired=(wired/total)*33;
+#else
 			    MEMshar=(shared/total)*33;
+#endif
 			    MEMbuff=(buffers/total)*33;
 			    MEMcach=(cached/total)*33;
 			}
@@ -579,9 +854,15 @@
 				copyXPMArea(3,75,((used/total)*34),9,5,19);
 			}
 			// Separators
+#ifdef __FreeBSD__
+			copyXPMArea(15,105,1,9,5+MEMactive,19);
+			copyXPMArea(15,105,1,9,6+MEMactive+MEMinactive,19);
+			copyXPMArea(15,105,1,9,7+MEMactive+MEMinactive+MEMwired,19);
+#else
 			copyXPMArea(15,105,1,9,5+MEMshar,19);
 			copyXPMArea(15,105,1,9,7+MEMshar+MEMbuff,19);
 			copyXPMArea(15,105,(36-(used/total)*34),9,(5+(used/total)*34),19);
+#endif
 			// Numbers			
 			tempa=used/1048576;
 			tempy=tempa%10;
@@ -601,6 +882,16 @@
 		if(stotal != total || sshared != shared)
 		{
 			stotal = total; sshared = shared; sbuffers = buffers; scached = cached;
+#ifdef __FreeBSD__
+			if ( (total/101048576) >= 1) {
+				MEMactive=(active/total)*27;
+			} else {
+				MEMactive=(active/total)*35;
+			}
+			// Bar
+			copyXPMArea(3,75,MEMactive,9,5,19);
+			copyXPMArea(3,102,(36-(active/total)*36),9,(5+(active/total)*36),19) ;
+#else
 			if ( (total/101048576) >= 1) {
 			    MEMshar=(shared/total)*27;
 			} else {
@@ -609,8 +900,13 @@
 			// Bar
 			copyXPMArea(3,75,MEMshar,9,5,19);
 			copyXPMArea(15,105,(36-(shared/total)*36),9,(5+(shared/total)*36),19);
+#endif
 			// Numbers			
+#ifdef __FreeBSD__
+			tempa=active/1048576;
+#else
 			tempa=shared/1048576;
+#endif
 			tempy=tempa%10;
     			copyXPMArea(3+(tempy*6),66,6,9,50,19);
 			tempy=(tempa/10)%10;
@@ -662,10 +957,11 @@
 /* X Mem Usage */
 void DrawXmem(int Xpid, float total) 
 {
-    FILE *fp;
-    char buf[128], XFileName[256];
     float ratio;
     long old_Xsize=-1, Xsize=0;
+#ifndef __FreeBSD__
+	FILE *fp;
+	char buf[128], XFileName[256];
 
     sprintf(XFileName, "/proc/%d/status", Xpid);
 
@@ -676,6 +974,18 @@
     	    if (strstr(buf, "VmSize"))
         	sscanf(buf, "VmSize: %ld", &Xsize);
 	}
+#else
+	{
+	struct kinfo_proc *kproc;
+	int kcnt;
+
+	kproc = kvm_getprocs(kd, KERN_PROC_PID, Xpid, &kcnt);
+#if __FreeBSD_version < 500000
+	Xsize = kproc->kp_eproc.e_vm.vm_map.size / 1024;
+#else
+	Xsize = kproc->ki_size / 1024;
+#endif
+#endif
         if(old_Xsize!=Xsize)
 	{
     	    int tempy, tempa;
@@ -692,7 +1002,9 @@
 	    copyXPMArea(3,84,((ratio)*22),11,18,47);
 	    copyXPMArea(15,105,(23-((ratio)*22)),11,(18+(ratio*22)),47);
 	}
+#ifndef __FreeBSD__
 	fclose(fp);
+#endif
     }
 }
 
@@ -713,10 +1025,28 @@
         pUtmp = getutid(&idUtmp);
         upt = (time(0) - pUtmp->ut_time);
 #else
+#ifndef __FreeBSD__
 	FILE *fp;
 	if( (fp = fopen("/proc/uptime", "r")) != NULL)
 		fscanf(fp, "%d",&upt);
 	fclose(fp);
+#else
+	int mib[2];
+	struct timeval boottime;
+	size_t bt_size;
+
+	bt_size = sizeof(boottime);
+	mib[0] = CTL_KERN;
+	mib[1] = KERN_BOOTTIME;
+
+	if (sysctl(mib, 2, &boottime, &bt_size, NULL, 0) != -1 &&
+			boottime.tv_sec != 0) {
+		upt = time(NULL) - boottime.tv_sec;
+		upt += 30;  /* top(1) does this ????  */
+	} else {
+		upt = 0;
+	}
+#endif
 #endif
 	mins=(upt/60)%60;
 	hours=(upt/3600)%24;
@@ -777,6 +1107,31 @@
         break;
     }
 
+}
+
+void
+open_kvm()
+{
+	if (kd == 0) {
+		kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, 0);
+		if (kd != NULL) {
+			if (kvm_nlist(kd, nl) < 0) {
+				errx(1, "kvm_nlist: %s", kvm_geterr(kd));
+			}
+			if (nl[0].n_type == 0) {
+				errx(1, "no namelist");
+			}
+		} else {
+			warnx("kvm not available");
+		}
+	}
+}
+
+void
+close_kvm()
+{
+	kvm_close(kd);
+	kd = NULL;
 }
 
 /* EOF */
