stats helper
diff --git a/src/cmd/auxstats/Darwin.c b/src/cmd/auxstats/Darwin.c
new file mode 100644
index 0000000..da6c2a2
--- /dev/null
+++ b/src/cmd/auxstats/Darwin.c
@@ -0,0 +1,250 @@
+/*
+ * No idea whether this will work.  It does compile.
+ */
+
+#include <u.h>
+#include <kvm.h>
+#include <nlist.h>
+#include <sys/types.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/dkstat.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <sys/ioctl.h>
+#include <limits.h>
+#include <libc.h>
+#include <bio.h>
+#include "dat.h"
+
+void xloadavg(int);
+void xcpu(int);
+void xswap(int);
+void xsysctl(int);
+void xnet(int);
+void xkvm(int);
+
+void (*statfn[])(int) =
+{
+	xkvm,
+	xloadavg,
+	xswap,
+	xcpu,
+	xsysctl,
+	xnet,
+	0
+};
+
+static kvm_t *kvm;
+
+static struct nlist nl[] = {
+	{ "_ifnet" },
+	{ "_cp_time" },
+	{ "" },
+};
+
+void
+kvminit(void)
+{
+	char buf[_POSIX2_LINE_MAX];
+
+	if(kvm)
+		return;
+	kvm = kvm_openfiles(nil, nil, nil, OREAD, buf);
+	if(kvm == nil)
+		return;
+	if(kvm_nlist(kvm, nl) < 0 || nl[0].n_type == 0){
+		kvm = nil;
+		return;
+	}
+}
+
+void
+xkvm(int first)
+{
+	if(first)
+		kvminit();
+}
+
+int
+kread(ulong addr, char *buf, int size)
+{
+	if(kvm_read(kvm, addr, buf, size) != size){
+		memset(buf, 0, size);
+		return -1;
+	}
+	return size;
+}
+
+void
+xnet(int first)
+{
+	ulong out, in, outb, inb, err;
+	static ulong ifnetaddr;
+	ulong addr;
+	struct ifnet ifnet;
+	struct ifnethead ifnethead;
+	char name[16];
+
+	if(first)
+		return;
+
+	if(ifnetaddr == 0){
+		ifnetaddr = nl[0].n_value;
+		if(ifnetaddr == 0)
+			return;
+	}
+
+	if(kread(ifnetaddr, (char*)&ifnethead, sizeof ifnethead) < 0)
+		return;
+
+	out = in = outb = inb = err = 0;
+	addr = (ulong)TAILQ_FIRST(&ifnethead);
+	while(addr){
+		if(kread(addr, (char*)&ifnet, sizeof ifnet) < 0
+		|| kread((ulong)ifnet.if_name, name, 16) < 0)
+			return;
+		name[15] = 0;
+		addr = (ulong)TAILQ_NEXT(&ifnet, if_link);
+		out += ifnet.if_opackets;
+		in += ifnet.if_ipackets;
+		outb += ifnet.if_obytes;
+		inb += ifnet.if_ibytes;
+		err += ifnet.if_oerrors+ifnet.if_ierrors;
+	}
+	Bprint(&bout, "etherin %lud\n", in);
+	Bprint(&bout, "etherout %lud\n", out);
+	Bprint(&bout, "etherinb %lud\n", inb);
+	Bprint(&bout, "etheroutb %lud\n", outb);
+	Bprint(&bout, "ethererr %lud\n", err);
+	Bprint(&bout, "ether %lud\n", in+out);
+	Bprint(&bout, "etherb %lud\n", inb+outb);
+}
+
+
+int
+rsys(char *name, char *buf, int len)
+{
+	size_t l;
+
+	l = len;
+	if(sysctlbyname(name, buf, &l, nil, 0) < 0)
+		return -1;
+	buf[l] = 0;
+	return l;
+}
+
+vlong
+isys(char *name)
+{
+	ulong u;
+	size_t l;
+
+	l = sizeof u;
+	if(sysctlbyname(name, &u, &l, nil, 0) < 0)
+		return 0;
+	return u;
+}
+
+void
+xsysctl(int first)
+{
+	static int pgsize;
+	vlong t;
+
+	if(first){
+		pgsize = isys("vm.stats.vm.v_page_size");
+		if(pgsize == 0)
+			pgsize = 4096;
+	}
+	if((t = isys("vm.stats.vm.v_page_count")) != 0)
+		Bprint(&bout, "mem %lld %lld\n", 
+			isys("vm.stats.vm.v_active_count")*pgsize, 
+			t*pgsize);
+	Bprint(&bout, "context %lld 1000\n", isys("vm.stats.sys.v_swtch"));
+	Bprint(&bout, "syscall %lld 1000\n", isys("vm.stats.sys.v_syscall"));
+	Bprint(&bout, "intr %lld 1000\n", isys("vm.stats.sys.v_intr")+isys("vm.stats.sys.v_trap"));
+	Bprint(&bout, "fault %lld 1000\n", isys("vm.stats.vm.v_vm_faults"));
+	Bprint(&bout, "fork %lld 1000\n", isys("vm.stats.vm.v_forks")
+		+isys("vm.stats.vm.v_rforks")
+		+isys("vm.stats.vm.v_vforks"));
+}
+
+void
+xcpu(int first)
+{
+#if 0
+	static int stathz;
+	ulong x[20];
+	struct clockinfo *ci;
+	int n;
+
+	if(first){
+		if(rsys("kern.clockrate", (char*)&x, sizeof x) < sizeof ci)
+			stathz = 128;
+		else{
+			ci = (struct clockinfo*)x;
+			stathz = ci->stathz;
+		}
+		return;
+	}
+
+	if((n=rsys("kern.cp_time", (char*)x, sizeof x)) < 5*sizeof(ulong))
+		return;
+
+	Bprint(&bout, "user %lud %d\n", x[CP_USER]+x[CP_NICE], stathz);
+	Bprint(&bout, "sys %lud %d\n", x[CP_SYS], stathz);
+	Bprint(&bout, "cpu %lud %d\n", x[CP_USER]+x[CP_NICE]+x[CP_SYS], stathz);
+	Bprint(&bout, "idle %lud %d\n", x[CP_IDLE], stathz);
+#endif
+}
+
+void
+xloadavg(int first)
+{
+	double l[3];
+
+	if(first)
+		return;
+
+	if(getloadavg(l, 3) < 0)
+		return;
+	Bprint(&bout, "load %d 1000\n", (int)(l[0]*1000.0));
+}
+
+void
+xswap(int first)
+{
+#if 0
+	static struct kvm_swap s;
+	static ulong pgin, pgout;
+	int i, o;
+	static int pgsize;
+
+	if(first){
+		pgsize = getpagesize();
+		if(pgsize == 0)
+			pgsize = 4096;
+		return;
+	}
+
+	if(kvm == nil)
+		return;
+
+	i = isys("vm.stats.vm.v_swappgsin");
+	o = isys("vm.stats.vm.v_swappgsout");
+	if(i != pgin || o != pgout){
+		pgin = i;
+		pgout = o;
+		kvm_getswapinfo(kvm, &s, 1, 0);
+	}
+
+
+	Bprint(&bout, "swap %lld %lld\n", s.ksw_used*(vlong)pgsize, s.ksw_total*(vlong)pgsize);
+#endif
+}
+