URI:
       tstats helper - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit f0f4401f0cfc654646bdf21849627ebcbd5d82b5
   DIR parent d72054aa270d6f3d539e830ef9892138a255872a
  HTML Author: rsc <devnull@localhost>
       Date:   Fri, 23 Apr 2004 05:12:11 +0000
       
       stats helper
       
       Diffstat:
         A src/cmd/auxstats/Darwin.c           |     250 +++++++++++++++++++++++++++++++
         A src/cmd/auxstats/FreeBSD.c          |     262 +++++++++++++++++++++++++++++++
         A src/cmd/auxstats/Linux.c            |     177 +++++++++++++++++++++++++++++++
         A src/cmd/auxstats/NetBSD.c           |      10 ++++++++++
         A src/cmd/auxstats/OpenBSD.c          |      10 ++++++++++
         A src/cmd/auxstats/SunOS.c            |      10 ++++++++++
         A src/cmd/auxstats/core               |       0 
         A src/cmd/auxstats/dat.h              |       9 +++++++++
         A src/cmd/auxstats/main.c             |     123 +++++++++++++++++++++++++++++++
         A src/cmd/auxstats/mkfile             |      15 +++++++++++++++
       
       10 files changed, 866 insertions(+), 0 deletions(-)
       ---
   DIR diff --git a/src/cmd/auxstats/Darwin.c b/src/cmd/auxstats/Darwin.c
       t@@ -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
       +}
       +
   DIR diff --git a/src/cmd/auxstats/FreeBSD.c b/src/cmd/auxstats/FreeBSD.c
       t@@ -0,0 +1,262 @@
       +#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 <machine/apm_bios.h>
       +#include <sys/ioctl.h>
       +#include <limits.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "dat.h"
       +
       +void xapm(int);
       +void xloadavg(int);
       +void xcpu(int);
       +void xswap(int);
       +void xsysctl(int);
       +void xnet(int);
       +void xkvm(int);
       +
       +void (*statfn[])(int) =
       +{
       +        xkvm,
       +        xapm,
       +        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];
       +        int n;
       +
       +        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 1000\n", in);
       +        Bprint(&bout, "etherout %lud 1000\n", out);
       +        Bprint(&bout, "etherinb %lud 1000000\n", inb);
       +        Bprint(&bout, "etheroutb %lud 1000000\n", outb);
       +        Bprint(&bout, "ethererr %lud 1000\n", err);
       +        Bprint(&bout, "ether %lud 1000\n", in+out);
       +        Bprint(&bout, "etherb %lud 1000000\n", inb+outb);
       +}
       +
       +void
       +xapm(int first)
       +{
       +        static int fd;
       +        struct apm_info ai;
       +
       +        if(first){
       +                fd = open("/dev/apm", OREAD);
       +                return;
       +        }
       +
       +        if(ioctl(fd, APMIO_GETINFO, &ai) < 0)
       +                return;
       +
       +        if(ai.ai_batt_life <= 100)
       +                Bprint(&bout, "battery =%d 100\n", ai.ai_batt_life);
       +}
       +
       +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 -1;
       +        return u;
       +}
       +
       +void
       +xsysctl(int first)
       +{
       +        static int pgsize;
       +
       +        if(first){
       +                pgsize = isys("vm.stats.vm.v_page_size");
       +                if(pgsize == 0)
       +                        pgsize = 4096;
       +        }
       +
       +        Bprint(&bout, "mem =%lld %lld\n", 
       +                isys("vm.stats.vm.v_active_count")*pgsize, 
       +                isys("vm.stats.vm.v_page_count")*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)
       +{
       +        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);
       +}
       +
       +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)
       +{
       +        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);
       +}
       +
   DIR diff --git a/src/cmd/auxstats/Linux.c b/src/cmd/auxstats/Linux.c
       t@@ -0,0 +1,177 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "dat.h"
       +
       +void xapm(int);
       +void xloadavg(int);
       +void xmeminfo(int);
       +void xnet(int);
       +void xstat(int);
       +
       +void (*statfn[])(int) =
       +{
       +        xapm,
       +        xloadavg,
       +        xmeminfo,
       +        xnet,
       +        xstat,
       +        0
       +};
       +
       +void
       +xapm(int first)
       +{
       +        static int fd = -1;
       +
       +        if(first){
       +                fd = open("/proc/apm", OREAD);
       +                return;
       +        }
       +        readfile(fd);
       +        tokens(0);
       +        if(ntok >= 7 && atoi(tok[6]) != -1)
       +                Bprint(&bout, "battery =%d 100\n", atoi(tok[6]));
       +}
       +        
       +void
       +xloadavg(int first)
       +{
       +        static int fd = -1;
       +
       +        if(first){
       +                fd = open("/proc/loadavg", OREAD);
       +                return;
       +        }
       +
       +        readfile(fd);
       +        tokens(0);
       +        if(ntok >= 1)
       +                Bprint(&bout, "load =%d 1000\n", (int)(atof(tok[0])*1000));
       +}
       +
       +void
       +xmeminfo(int first)
       +{
       +        int i;
       +        vlong tot, used;
       +        static int fd = -1;
       +
       +        if(first){
       +                fd = open("/proc/meminfo", OREAD);
       +                return;
       +        }
       +
       +        readfile(fd);
       +        for(i=0; i<nline; i++){
       +                tokens(i);
       +                if(ntok < 4)
       +                        continue;
       +                tot = atoll(tok[1]);
       +                used = atoll(tok[2]);
       +                if(strcmp(tok[0], "Mem:") == 0)
       +                        Bprint(&bout, "mem =%lld %lld\n", used/1024, tot/1024);
       +                else if(strcmp(tok[0], "Swap:") == 0)
       +                        Bprint(&bout, "swap =%lld %lld\n", used/1024, tot/1024);
       +        }
       +}
       +
       +void
       +xnet(int first)
       +{
       +        int i, n;
       +        vlong totb, totp, tote, totin, totou, totinb, totoub, b, p, e, in, ou, inb, oub;
       +        char *q;
       +        static int fd = -1;
       +
       +        if(first){
       +                fd = open("/proc/net/dev", OREAD);
       +                return;
       +        }
       +
       +        readfile(fd);
       +        n = 0;
       +        totb = 0;
       +        tote = 0;
       +        totp = 0;
       +        totin = 0;
       +        totou = 0;
       +        totinb = 0;
       +        totoub = 0;
       +        for(i=0; i<nline; i++){
       +                tokens(i);
       +                if(ntok < 8+8)
       +                        continue;
       +                if(strncmp(tok[0], "eth", 3) != 0)
       +                        continue;
       +                q = strchr(tok[0], ':');
       +                *q++ = 0;
       +                tok[0] = q;
       +                inb = atoll(tok[0]);
       +                oub = atoll(tok[8]);
       +                in = atoll(tok[1]);
       +                ou = atoll(tok[9]);
       +                b = inb+oub;
       +                p = in+ou;
       +                e = atoll(tok[2])+atoll(tok[10]);
       +                totb += b;
       +                totp += p;
       +                tote += e;
       +                totin += in;
       +                totou += ou;
       +                totinb += inb;
       +                totoub += oub;
       +                n++;
       +        }
       +        Bprint(&bout, "etherb %lld %d\n", totb, n*1000000);
       +        Bprint(&bout, "ether %lld %d\n", totp, n*1000);
       +        Bprint(&bout, "ethererr %lld %d\n", tote, n*1000);
       +        Bprint(&bout, "etherin %lld %d\n", totin, n*1000);
       +        Bprint(&bout, "etherout %lld %d\n", totou, n*1000);
       +        Bprint(&bout, "etherinb %lld %d\n", totinb, n*1000);
       +        Bprint(&bout, "etheroutb %lld %d\n", totoub, n*1000);
       +}
       +
       +void
       +xstat(int first)
       +{
       +        static int fd = -1;
       +        int i;
       +
       +        if(first){
       +                fd = open("/proc/stat", OREAD);
       +                return;
       +        }
       +
       +        readfile(fd);
       +        for(i=0; i<nline; i++){
       +                tokens(i);
       +                if(ntok < 2)
       +                        continue;
       +                if(strcmp(tok[0], "cpu") == 0 && ntok >= 5){
       +                        Bprint(&bout, "user %lld 100\n", atoll(tok[1]));
       +                        Bprint(&bout, "sys %lld 100\n", atoll(tok[3]));
       +                        Bprint(&bout, "cpu %lld 100\n", atoll(tok[1])+atoll(tok[3]));
       +                        Bprint(&bout, "idle %lld\n", atoll(tok[4]));
       +                }
       +        /*
       +                if(strcmp(tok[0], "page") == 0 && ntok >= 3){
       +                        Bprint(&bout, "pagein %lld 500\n", atoll(tok[1]));
       +                        Bprint(&bout, "pageout %lld 500\n", atoll(tok[2]));
       +                        Bprint(&bout, "page %lld 1000\n", atoll(tok[1])+atoll(tok[2]));
       +                }
       +                if(strcmp(tok[0], "swap") == 0 && ntok >= 3){
       +                        Bprint(&bout, "swapin %lld 500\n", atoll(tok[1]));
       +                        Bprint(&bout, "swapout %lld 500\n", atoll(tok[2]));
       +                        Bprint(&bout, "swap %lld 1000\n", atoll(tok[1])+atoll(tok[2]));
       +                }
       +        */
       +                if(strcmp(tok[0], "intr") == 0)
       +                        Bprint(&bout, "interrupt %lld 1000\n", atoll(tok[1]));
       +                if(strcmp(tok[0], "ctxt") == 0)
       +                        Bprint(&bout, "context %lld 1000\n", atoll(tok[1]));
       +                if(strcmp(tok[0], "processes") == 0)
       +                        Bprint(&bout, "fork %lld 1000\n", atoll(tok[1]));
       +        }
       +}
       +
   DIR diff --git a/src/cmd/auxstats/NetBSD.c b/src/cmd/auxstats/NetBSD.c
       t@@ -0,0 +1,10 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "dat.h"
       +
       +void (*statfn[])(int) = 
       +{
       +        0
       +};
       +
   DIR diff --git a/src/cmd/auxstats/OpenBSD.c b/src/cmd/auxstats/OpenBSD.c
       t@@ -0,0 +1,10 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "dat.h"
       +
       +void (*statfn[])(int) = 
       +{
       +        0
       +};
       +
   DIR diff --git a/src/cmd/auxstats/SunOS.c b/src/cmd/auxstats/SunOS.c
       t@@ -0,0 +1,10 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "dat.h"
       +
       +void (*statfn[])(int) = 
       +{
       +        0
       +};
       +
   DIR diff --git a/src/cmd/auxstats/core b/src/cmd/auxstats/core
       Binary files differ.
   DIR diff --git a/src/cmd/auxstats/dat.h b/src/cmd/auxstats/dat.h
       t@@ -0,0 +1,9 @@
       +extern Biobuf bout;
       +extern void (*statfn[])(int);
       +extern char buf[];
       +extern char *line[];
       +extern char *tok[];
       +extern int nline, ntok;
       +
       +void readfile(int);
       +void tokens(int);
   DIR diff --git a/src/cmd/auxstats/main.c b/src/cmd/auxstats/main.c
       t@@ -0,0 +1,123 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "dat.h"
       +
       +Biobuf bout;
       +
       +void
       +usage(void)
       +{
       +        fprint(2, "usage: auxstats [system [executable]]\n");
       +        exits("usage");
       +}
       +
       +int pid;
       +
       +void
       +notifyf(void *v, char *msg)
       +{
       +        USED(v);
       +
       +        if(strcmp(msg, "child") == 0)
       +                noted(NCONT);
       +        postnote(PNPROC, pid, msg);
       +        exits(nil);
       +}
       +
       +void
       +main(int argc, char **argv)
       +{
       +        char *sys, *exe;
       +        int i;
       +        Waitmsg *w;
       +
       +        ARGBEGIN{
       +        default:
       +                usage();
       +        }ARGEND
       +
       +        notify(notifyf);
       +
       +        sys = nil;
       +        exe = nil;
       +        if(argc > 0)
       +                sys = argv[0];
       +        if(argc > 1)
       +                exe = argv[1];
       +        if(argc > 2)
       +                usage();
       +
       +        if(sys){
       +                if(exe == nil)
       +                        exe = "auxstats";
       +                for(;;){
       +                        switch(pid = fork()){
       +                        case -1:
       +                                sysfatal("fork: %r");
       +                        case 0:
       +                                rfork(RFNOTEG);
       +                                execlp("ssh", "ssh", "-C", sys, exe, nil);
       +                                _exit(12);
       +                        default:
       +                                if((w = wait()) == nil)
       +                                        sysfatal("wait: %r");
       +                                if(w->pid != pid)
       +                                        sysfatal("wait got wrong pid");
       +                                if(atoi(w->msg) == 12)
       +                                        sysfatal("exec ssh failed");
       +                                free(w);
       +                                fprint(2, "stats: %s hung up; sleeping 60\n", sys);
       +                                sleep(60*1000);
       +                                fprint(2, "stats: redialing %s\n", sys);
       +                                break;
       +                        }
       +                }
       +        }
       +
       +        for(i=0; statfn[i]; i++)
       +                statfn[i](1);
       +
       +        Binit(&bout, 1, OWRITE);
       +        for(;;){
       +                Bflush(&bout);
       +                sleep(900);
       +                for(i=0; statfn[i]; i++)
       +                        statfn[i](0);
       +        }
       +}
       +
       +char buf[16384];
       +char *line[100];
       +char *tok[100];
       +int nline, ntok;
       +
       +void
       +readfile(int fd)
       +{
       +        int n;
       +
       +        if(fd == -1){
       +                nline = 0;
       +                return;
       +        }
       +
       +        seek(fd, 0, 0);
       +        n = read(fd, buf, sizeof buf-1);
       +        if(n < 0)
       +                n = 0;
       +        buf[n] = 0;
       +
       +        nline = getfields(buf, line, nelem(line), 0, "\n");
       +}
       +
       +void
       +tokens(int i)
       +{
       +        if(i >= nline){
       +                ntok = 0;
       +                return;
       +        }
       +        ntok = tokenize(line[i], tok, nelem(tok));
       +}
       +
   DIR diff --git a/src/cmd/auxstats/mkfile b/src/cmd/auxstats/mkfile
       t@@ -0,0 +1,15 @@
       +<$PLAN9/src/mkhdr
       +
       +TARG=auxstats
       +
       +OFILES=\
       +        $SYSNAME.$O\
       +        main.$O\
       +
       +HFILES=\
       +        dat.h\
       +
       +SHORTLIB=bio 9
       +
       +<$PLAN9/src/mkone
       +