summaryrefslogtreecommitdiff
path: root/src/pmdas/freebsd/freebsd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pmdas/freebsd/freebsd.c')
-rw-r--r--src/pmdas/freebsd/freebsd.c991
1 files changed, 991 insertions, 0 deletions
diff --git a/src/pmdas/freebsd/freebsd.c b/src/pmdas/freebsd/freebsd.c
new file mode 100644
index 0000000..3170b20
--- /dev/null
+++ b/src/pmdas/freebsd/freebsd.c
@@ -0,0 +1,991 @@
+/*
+ * FreeBSD Kernel PMDA
+ *
+ * Copyright (c) 2012 Red Hat.
+ * Copyright (c) 2012 Ken McDonell. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "pmapi.h"
+#include "impl.h"
+#include "pmda.h"
+
+#include <limits.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <vm/vm_param.h>
+
+#include "domain.h"
+#include "freebsd.h"
+
+/* static instances */
+static pmdaInstid loadav_indom[] = {
+ { 1, "1 minute" }, { 5, "5 minute" }, { 15, "15 minute" }
+};
+
+/* instance domains */
+pmdaIndom indomtab[] = {
+ { LOADAV_INDOM, sizeof(loadav_indom)/sizeof(loadav_indom[0]), loadav_indom },
+ { CPU_INDOM, 0, NULL },
+ { DISK_INDOM, 0, NULL },
+ { NETIF_INDOM, 0, NULL },
+};
+static int indomtablen = sizeof(indomtab) / sizeof(indomtab[0]);
+
+#define CL_SYSCTL 0
+#define CL_SPECIAL 1
+#define CL_DISK 2
+#define CL_NETIF 3
+
+/*
+ * All the PCP metrics.
+ *
+ * For sysctl metrics, m_user (the first field) is set the the PCP
+ * name of the metric, and during initialization this is replaced by
+ * a pointer to the corresponding entry in mib[] (based on matching,
+ * or prefix matching (see matchname()) the PCP name here with
+ * m_pcpname[] in the mib[] entries.
+ *
+ * cluster map
+ * CL_SYSCTL simple sysctl() metrics, either one metric per mib, or
+ * one struct per mib
+ * CL_SPECIAL trickier sysctl() metrics involving synthesis or arithmetic
+ * or other methods
+ * CL_DISK disk metrics
+ * CL_NETIF network interface metrics
+ */
+
+static pmdaMetric metrictab[] = {
+ { (void *)"hinv.ncpu",
+ { PMDA_PMID(CL_SYSCTL,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0,0,0,0,0,0) } },
+ { (void *)"hinv.physmem",
+ { PMDA_PMID(CL_SYSCTL,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } },
+ { (void *)"kernel.all.load",
+ { PMDA_PMID(CL_SYSCTL,2), PM_TYPE_FLOAT, LOADAV_INDOM, PM_SEM_INSTANT,
+ PMDA_PMUNITS(0,0,0,0,0,0) } },
+ { (void *)"kernel.all.cpu.user",
+ { PMDA_PMID(CL_SYSCTL,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } },
+ { (void *)"kernel.all.cpu.nice",
+ { PMDA_PMID(CL_SYSCTL,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } },
+ { (void *)"kernel.all.cpu.sys",
+ { PMDA_PMID(CL_SYSCTL,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } },
+ { (void *)"kernel.all.cpu.intr",
+ { PMDA_PMID(CL_SYSCTL,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } },
+ { (void *)"kernel.all.cpu.idle",
+ { PMDA_PMID(CL_SYSCTL,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } },
+ { (void *)"kernel.percpu.cpu.user",
+ { PMDA_PMID(CL_SYSCTL,8), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } },
+ { (void *)"kernel.percpu.cpu.nice",
+ { PMDA_PMID(CL_SYSCTL,9), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } },
+ { (void *)"kernel.percpu.cpu.sys",
+ { PMDA_PMID(CL_SYSCTL,10), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } },
+ { (void *)"kernel.percpu.cpu.intr",
+ { PMDA_PMID(CL_SYSCTL,11), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } },
+ { (void *)"kernel.percpu.cpu.idle",
+ { PMDA_PMID(CL_SYSCTL,12), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } },
+ { (void *)"kernel.all.hz",
+ { PMDA_PMID(CL_SYSCTL,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0,1,0,0,PM_TIME_USEC,0) } },
+ { (void *)"hinv.cpu.vendor",
+ { PMDA_PMID(CL_SYSCTL,15), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0,0,0,0,0,0) } },
+ { (void *)"hinv.cpu.model",
+ { PMDA_PMID(CL_SYSCTL,16), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0,0,0,0,0,0) } },
+ { (void *)"hinv.cpu.arch",
+ { PMDA_PMID(CL_SYSCTL,17), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0,0,0,0,0,0) } },
+ { (void *)"swap.pagesin",
+ { PMDA_PMID(CL_SYSCTL,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { (void *)"swap.pagesout",
+ { PMDA_PMID(CL_SYSCTL,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { (void *)"swap.in",
+ { PMDA_PMID(CL_SYSCTL,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { (void *)"swap.in",
+ { PMDA_PMID(CL_SYSCTL,21), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { (void *)"kernel.all.pswitch",
+ { PMDA_PMID(CL_SYSCTL,22), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { (void *)"kernel.all.syscall",
+ { PMDA_PMID(CL_SYSCTL,23), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { (void *)"kernel.all.intr",
+ { PMDA_PMID(CL_SYSCTL,24), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { (void *)"swap.length",
+ { PMDA_PMID(CL_SYSCTL,25), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } },
+ { (void *)"swap.used",
+ { PMDA_PMID(CL_SYSCTL,26), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } },
+
+ { NULL, /* hinv.ndisk */
+ { PMDA_PMID(CL_SPECIAL,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0,0,0,0,0,0) } },
+ /*
+ * swap.free is the difference between sysctl variables vm.swap_total
+ * and vm.swap_reserved, so it is important they are kept together
+ * in mib[] below
+ */
+ { (void *)"swap.length", /* swap.free */
+ { PMDA_PMID(CL_SPECIAL,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } },
+ { NULL, /* hinv.pagesize */
+ { PMDA_PMID(CL_SPECIAL,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } },
+ { (void *)"mem.util.all",
+ { PMDA_PMID(CL_SPECIAL,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } },
+ /*
+ * mem.util.used is computed from several of the vm.stats.vm.v_*_count
+ * sysctl metrics, so it is important they are kept together in mib[]
+ * below
+ */
+ { (void *)"mem.util.all", /* mem.util.used */
+ { PMDA_PMID(CL_SPECIAL,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } },
+ { (void *)"mem.util.free",
+ { PMDA_PMID(CL_SPECIAL,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } },
+ { (void *)"mem.util.bufmem",
+ { PMDA_PMID(CL_SPECIAL,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } },
+ { (void *)"mem.util.cached",
+ { PMDA_PMID(CL_SPECIAL,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } },
+ { (void *)"mem.util.wired",
+ { PMDA_PMID(CL_SPECIAL,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } },
+ { (void *)"mem.util.active",
+ { PMDA_PMID(CL_SPECIAL,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } },
+ { (void *)"mem.util.inactive",
+ { PMDA_PMID(CL_SPECIAL,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } },
+ /*
+ * mem.util.avail is computed from several of the vm.stats.vm.v_*_count
+ * sysctl metrics, so it is important they are kept together in mib[]
+ * below
+ */
+ { (void *)"mem.util.all", /* mem.util.avail */
+ { PMDA_PMID(CL_SPECIAL,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } },
+
+ { NULL, /* disk.dev.read */
+ { PMDA_PMID(CL_DISK,0), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* disk.dev.write */
+ { PMDA_PMID(CL_DISK,1), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* disk.dev.total */
+ { PMDA_PMID(CL_DISK,2), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* disk.dev.read_bytes */
+ { PMDA_PMID(CL_DISK,3), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } },
+ { NULL, /* disk.dev.write_bytes */
+ { PMDA_PMID(CL_DISK,4), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } },
+ { NULL, /* disk.dev.total_bytes */
+ { PMDA_PMID(CL_DISK,5), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } },
+ { NULL, /* disk.all.read */
+ { PMDA_PMID(CL_DISK,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* disk.all.write */
+ { PMDA_PMID(CL_DISK,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* disk.all.total */
+ { PMDA_PMID(CL_DISK,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* disk.all.read_bytes */
+ { PMDA_PMID(CL_DISK,9), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } },
+ { NULL, /* disk.all.write_bytes */
+ { PMDA_PMID(CL_DISK,10), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } },
+ { NULL, /* disk.all.total_bytes */
+ { PMDA_PMID(CL_DISK,11), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } },
+ { NULL, /* disk.dev.blkread */
+ { PMDA_PMID(CL_DISK,12), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* disk.dev.blkwrite */
+ { PMDA_PMID(CL_DISK,13), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* disk.dev.blktotal */
+ { PMDA_PMID(CL_DISK,14), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* disk.all.blkread */
+ { PMDA_PMID(CL_DISK,15), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* disk.all.blkwrite */
+ { PMDA_PMID(CL_DISK,16), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* disk.all.blktotal */
+ { PMDA_PMID(CL_DISK,17), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+
+ { NULL, /* network.interface.mtu */
+ { PMDA_PMID(CL_NETIF,0), PM_TYPE_U32, NETIF_INDOM, PM_SEM_INSTANT,
+ PMDA_PMUNITS(0,0,0,0,0,0) } },
+ { NULL, /* network.interface.up */
+ { PMDA_PMID(CL_NETIF,1), PM_TYPE_U32, NETIF_INDOM, PM_SEM_INSTANT,
+ PMDA_PMUNITS(0,0,0,0,0,0) } },
+ { NULL, /* network.interface.baudrate */
+ { PMDA_PMID(CL_NETIF,2), PM_TYPE_U64, NETIF_INDOM, PM_SEM_INSTANT,
+ PMDA_PMUNITS(0,0,0,0,0,0) } },
+ { NULL, /* network.interface.in.bytes */
+ { PMDA_PMID(CL_NETIF,3), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } },
+ { NULL, /* network.interface.in.packets */
+ { PMDA_PMID(CL_NETIF,4), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* network.interface.in.mcasts */
+ { PMDA_PMID(CL_NETIF,5), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* network.interface.in.errors */
+ { PMDA_PMID(CL_NETIF,6), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* network.interface.in.drops */
+ { PMDA_PMID(CL_NETIF,7), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* network.interface.out.bytes */
+ { PMDA_PMID(CL_NETIF,8), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } },
+ { NULL, /* network.interface.out.packets */
+ { PMDA_PMID(CL_NETIF,9), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* network.interface.out.mcasts */
+ { PMDA_PMID(CL_NETIF,10), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* network.interface.out.errors */
+ { PMDA_PMID(CL_NETIF,11), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* network.interface.out.collisions */
+ { PMDA_PMID(CL_NETIF,12), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* network.interface.total.bytes */
+ { PMDA_PMID(CL_NETIF,13), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } },
+ { NULL, /* network.interface.total.packets */
+ { PMDA_PMID(CL_NETIF,14), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* network.interface.total.mcasts */
+ { PMDA_PMID(CL_NETIF,15), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+ { NULL, /* network.interface.total.errors */
+ { PMDA_PMID(CL_NETIF,16), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } },
+};
+static int metrictablen = sizeof(metrictab) / sizeof(metrictab[0]);
+
+/*
+ * mapping between PCP metrics and sysctl metrics
+ *
+ * initialization note ... all elments after m_pcpname and m_name are OK
+ * to be 0 or NULL
+ */
+typedef struct {
+ const char *m_pcpname; /* PCP metric name or prefix (see matchname() */
+ const char *m_name; /* sysctl metric name */
+ size_t m_miblen; /* number of elements in m_mib[] */
+ int *m_mib;
+ int m_fetched; /* 1 if m_data is current and valid */
+ size_t m_datalen; /* number of bytes in m_data[] */
+ void *m_data; /* value from sysctl */
+} mib_t;
+static mib_t map[] = {
+ { "hinv.ncpu", "hw.ncpu" },
+ { "hinv.physmem", "hw.physmem" },
+ { "hinv.cpu.vendor", "hw.machine" },
+ { "hinv.cpu.model", "hw.model" },
+ { "hinv.cpu.arch", "hw.machine_arch" },
+ { "kernel.all.load", "vm.loadavg" },
+ { "kernel.all.hz", "kern.clockrate" },
+ { "kernel.all.cpu.*", "kern.cp_time" },
+ { "kernel.percpu.cpu.*", "kern.cp_times" },
+ { "swap.pagesin", "vm.stats.vm.v_swappgsin" },
+ { "swap.pagesout", "vm.stats.vm.v_swappgsout" },
+ { "swap.in", "vm.stats.vm.v_swapin" },
+ { "swap.out", "vm.stats.vm.v_swapout" },
+ { "kernel.all.pswitch", "vm.stats.sys.v_swtch" },
+ { "kernel.all.syscall", "vm.stats.sys.v_syscall" },
+ { "kernel.all.intr", "vm.stats.sys.v_intr" },
+ { "mem.util.bufmem", "vfs.bufspace" },
+/*
+ * DO NOT MOVE next 2 entries ... see note above for swap.free
+ */
+ { "swap.length", "vm.swap_total" },
+ { "swap.used", "vm.swap_reserved" },
+/*
+ * DO NOT MOVE next 6 entries ... see note above for mem.util.avail
+ * and mem.util.used
+ */
+ { "mem.util.all", "vm.stats.vm.v_page_count" },
+ { "mem.util.free", "vm.stats.vm.v_free_count" },
+ { "mem.util.cached", "vm.stats.vm.v_cache_count" },
+ { "mem.util.wired", "vm.stats.vm.v_wire_count" },
+ { "mem.util.active", "vm.stats.vm.v_active_count" },
+ { "mem.util.inactive", "vm.stats.vm.v_inactive_count" },
+
+};
+static int maplen = sizeof(map) / sizeof(map[0]);
+static mib_t bad_mib = { "bad.mib", "bad.mib", 0, NULL, 0, 0, NULL };
+
+static char *username;
+static int isDSO = 1; /* =0 I am a daemon */
+static int cpuhz; /* frequency for CPU time metrics */
+static int ncpu; /* number of cpus in kern.cp_times data */
+static int pagesize; /* vm page size */
+
+/*
+ * Fetch values from sysctl()
+ *
+ * Expect the result to be xpect bytes to match the PCP data size or
+ * anticipated structure size, unless xpect is ==0 in which case the
+ * size test is skipped.
+ */
+static int
+do_sysctl(mib_t *mp, size_t xpect)
+{
+ /*
+ * Note zero trip if mp->m_data and mp->datalen are already valid
+ * and current
+ */
+ for ( ; mp->m_fetched == 0; ) {
+ int sts;
+ sts = sysctl(mp->m_mib, (u_int)mp->m_miblen, mp->m_data, &mp->m_datalen, NULL, 0);
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ fprintf(stderr, "sysctl(%s%s) -> %d (datalen=%d)\n", mp->m_name, mp->m_data == NULL ? " firstcall" : "", sts, (int)mp->m_datalen);
+ }
+#endif
+ if (sts == 0 && mp->m_data != NULL) {
+ mp->m_fetched = 1;
+ break;
+ }
+ if ((sts == -1 && errno == ENOMEM) || (sts == 0 && mp->m_data == NULL)) {
+ /* first call for this one, or data changed size */
+ mp->m_data = realloc(mp->m_data, mp->m_datalen);
+ if (mp->m_data == NULL) {
+ fprintf(stderr, "Error: %s: buffer alloc failed for sysctl metric \"%s\"\n", mp->m_pcpname, mp->m_name);
+ __pmNoMem("do_sysctl", mp->m_datalen, PM_FATAL_ERR);
+ /*NOTREACHED*/
+ }
+ }
+ else
+ return -errno;
+ }
+ if (xpect > 0 && mp->m_datalen != xpect) {
+ fprintf(stderr, "Error: %s: sysctl(%s) datalen=%d not %d!\n", mp->m_pcpname, mp->m_name, (int)mp->m_datalen, (int)xpect);
+ return 0;
+ }
+ return mp->m_datalen;
+}
+
+/*
+ * kernel memory reader setup
+ */
+struct nlist symbols[] = {
+ { .n_name = "_ifnet" },
+ { .n_name = NULL }
+};
+kvm_t *kvmp;
+
+static void
+kmemread_init(void)
+{
+ int sts;
+ int i;
+ char errmsg[_POSIX2_LINE_MAX];
+
+ /*
+ * If we're running as a daemon PMDA, assume we're setgid kmem,
+ * so we can open /dev/kmem, and downgrade privileges after the
+ * kvm_open().
+ * For a DSO PMDA, we have to assume pmcd has the required
+ * privileges and don't dink with them.
+ */
+ kvmp = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errmsg);
+ if (!isDSO)
+ setgid(getgid());
+ if (kvmp == NULL) {
+ fprintf(stderr, "kmemread_init: kvm_openfiles failed: %s\n", errmsg);
+ return;
+ }
+
+ sts = kvm_nlist(kvmp, symbols);
+ if (sts < 0) {
+ fprintf(stderr, "kmemread_init: kvm_nlist failed: %s\n", pmErrStr(-errno));
+ for (i = 0; i < sizeof(symbols)/sizeof(symbols[0])-1; i++)
+ symbols[i].n_value = 0;
+ return;
+ }
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ for (i = 0; i < sizeof(symbols)/sizeof(symbols[0])-1; i++) {
+ fprintf(stderr, "Info: kernel symbol %s found at 0x%08lx\n", symbols[i].n_name, symbols[i].n_value);
+ }
+ }
+#endif
+
+}
+
+/*
+ * Callback provided to pmdaFetch ... come here once per metric-instance
+ * pair in each pmFetch().
+ */
+static int
+freebsd_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom)
+{
+ int sts = PM_ERR_PMID;
+ __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid);
+ mib_t *mp;
+
+ mp = (mib_t *)mdesc->m_user;
+ if (idp->cluster == CL_SYSCTL) {
+ /* sysctl() simple cases */
+ switch (idp->item) {
+ /* 32-bit integer values */
+ case 0: /* hinv.ncpu */
+ case 18: /* swap.pagesin */
+ case 19: /* swap.pagesout */
+ case 20: /* swap.in */
+ case 21: /* swap.out */
+ case 22: /* kernel.all.pswitch */
+ case 23: /* kernel.all.syscall */
+ case 24: /* kernel.all.intr */
+ sts = do_sysctl(mp, sizeof(atom->ul));
+ if (sts > 0) {
+ atom->ul = *((__uint32_t *)mp->m_data);
+ sts = 1;
+ }
+ break;
+
+ /* 64-bit integer values */
+ case 1: /* hinv.physmem */
+ case 25: /* swap.length */
+ case 26: /* swap.used */
+ sts = do_sysctl(mp, sizeof(atom->ull));
+ if (sts > 0) {
+ atom->ull = *((__uint64_t *)mp->m_data);
+ sts = 1;
+ }
+ break;
+
+ /* string values */
+ case 15: /* hinv.cpu.vendor */
+ case 16: /* hinv.cpu.model */
+ case 17: /* hinv.cpu.arch */
+ sts = do_sysctl(mp, (size_t)0);
+ if (sts > 0) {
+ atom->cp = (char *)mp->m_data;
+ sts = 1;
+ }
+ break;
+
+ /* structs and aggregates */
+ case 2: /* kernel.all.load */
+ sts = do_sysctl(mp, 3*sizeof(atom->d));
+ if (sts > 0) {
+ int i;
+ struct loadavg *lp = (struct loadavg *)mp->m_data;
+ if (inst == 1)
+ i = 0;
+ else if (inst == 5)
+ i = 1;
+ else if (inst == 15)
+ i = 2;
+ else
+ return PM_ERR_INST;
+ atom->f = (float)((double)lp->ldavg[i] / lp->fscale);
+ sts = 1;
+ }
+ break;
+
+ case 3: /* kernel.all.cpu.user */
+ case 4: /* kernel.all.cpu.nice */
+ case 5: /* kernel.all.cpu.sys */
+ case 6: /* kernel.all.cpu.intr */
+ case 7: /* kernel.all.cpu.idle */
+ sts = do_sysctl(mp, CPUSTATES*sizeof(atom->ull));
+ if (sts > 0) {
+ /*
+ * PMID assignment is important in the "-3" below so
+ * that metrics map to consecutive elements of the
+ * returned value in the order defined for CPUSTATES,
+ * i.e. CP_USER, CP_NICE, CP_SYS, CP_INTR and
+ * CP_IDLE
+ */
+ atom->ull = 1000*((__uint64_t *)mp->m_data)[idp->item-3]/cpuhz;
+ sts = 1;
+ }
+ break;
+
+ case 8: /* kernel.percpu.cpu.user */
+ case 9: /* kernel.percpu.cpu.nice */
+ case 10: /* kernel.percpu.cpu.sys */
+ case 11: /* kernel.percpu.cpu.intr */
+ case 12: /* kernel.percpu.cpu.idle */
+ sts = do_sysctl(mp, ncpu*CPUSTATES*sizeof(atom->ull));
+ if (sts > 0) {
+ /*
+ * PMID assignment is important in the "-8" below so
+ * that metrics map to consecutive elements of the
+ * returned value in the order defined for CPUSTATES,
+ * i.e. CP_USER, CP_NICE, CP_SYS, CP_INTR and
+ * CP_IDLE, and then there is one such set for each
+ * CPU up to the maximum number of CPUs installed in
+ * the system.
+ */
+ atom->ull = 1000*((__uint64_t *)mp->m_data)[inst * CPUSTATES + idp->item-8]/cpuhz;
+ sts = 1;
+ }
+ break;
+
+ case 13: /* kernel.all.hz */
+ sts = do_sysctl(mp, sizeof(struct clockinfo));
+ if (sts > 0) {
+ struct clockinfo *cp = (struct clockinfo *)mp->m_data;
+ atom->ul = cp->hz;
+ sts = 1;
+ }
+ break;
+
+ }
+ }
+ else if (idp->cluster == CL_SPECIAL) {
+ /* special cases */
+ switch (idp->item) {
+ case 0: /* hinv.ndisk */
+ refresh_disk_metrics();
+ atom->ul = pmdaCacheOp(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_SIZE_ACTIVE);
+ sts = 1;
+ break;
+
+ case 1: /* swap.free */
+ /* first vm.swap_total */
+ sts = do_sysctl(mp, sizeof(atom->ull));
+ if (sts > 0) {
+ atom->ull = *((__uint64_t *)mp->m_data);
+ /*
+ * now subtract vm.swap_reserved ... assumes consecutive
+ * mib[] entries
+ */
+ mp++;
+ sts = do_sysctl(mp, sizeof(atom->ull));
+ if (sts > 0) {
+ atom->ull -= *((__uint64_t *)mp->m_data);
+ sts = 1;
+ }
+ }
+ break;
+
+ case 3: /* hinv.pagesize */
+ atom->ul = pagesize;
+ sts = 1;
+ break;
+
+ case 4: /* mem.util.all */
+ case 6: /* mem.util.free */
+ case 8: /* mem.util.cached */
+ case 9: /* mem.util.wired */
+ case 10: /* mem.util.active */
+ case 11: /* mem.util.inactive */
+ sts = do_sysctl(mp, sizeof(atom->ul));
+ if (sts > 0) {
+ atom->ul = *((__uint32_t *)mp->m_data) * (pagesize / 1024);
+ sts = 1;
+ }
+ break;
+
+ case 7: /* mem.util.bufmem */
+ sts = do_sysctl(mp, sizeof(atom->ul));
+ if (sts > 0) {
+ atom->ul = *((__uint32_t *)mp->m_data) / 1024;
+ sts = 1;
+ }
+ break;
+
+ case 5: /* mem.util.used */
+ /*
+ * mp-> v_page_count entry in mib[]
+ * assuming consecutive mib[] entries, we want
+ * v_page_count mp[0] - v_free_count mp[1] -
+ * v_cache_count mp[2] - v_inactive_count mp[5]
+ */
+ sts = do_sysctl(mp, sizeof(atom->ul));
+ if (sts > 0) {
+ atom->ul = *((__uint32_t *)mp->m_data);
+ sts = do_sysctl(&mp[1], sizeof(atom->ul));
+ if (sts > 0) {
+ atom->ul -= *((__uint32_t *)mp[1].m_data);
+ sts = do_sysctl(&mp[2], sizeof(atom->ul));
+ if (sts > 0) {
+ atom->ul -= *((__uint32_t *)mp[2].m_data);
+ sts = do_sysctl(&mp[5], sizeof(atom->ul));
+ if (sts > 0) {
+ atom->ul -= *((__uint32_t *)mp[5].m_data);
+ atom->ul *= (pagesize / 1024);
+ sts = 1;
+ }
+ }
+ }
+ }
+ break;
+
+ case 12: /* mem.util.avail */
+ /*
+ * mp-> v_page_count entry in mib[]
+ * assuming consecutive mib[] entries, we want
+ * v_free_count mp[1] + v_cache_count mp[2] +
+ * v_inactive_count mp[5]
+ */
+ sts = do_sysctl(&mp[1], sizeof(atom->ul));
+ if (sts > 0) {
+ atom->ul = *((__uint32_t *)mp[1].m_data);
+ sts = do_sysctl(&mp[2], sizeof(atom->ul));
+ if (sts > 0) {
+ atom->ul += *((__uint32_t *)mp[2].m_data);
+ sts = do_sysctl(&mp[5], sizeof(atom->ul));
+ if (sts > 0) {
+ atom->ul += *((__uint32_t *)mp[5].m_data);
+ atom->ul *= (pagesize / 1024);
+ sts = 1;
+ }
+ }
+ }
+ break;
+
+ }
+ }
+ else if (idp->cluster == CL_DISK) {
+ /* disk metrics */
+ sts = do_disk_metrics(mdesc, inst, atom);
+ }
+ else if (idp->cluster == CL_NETIF) {
+ /* network interface metrics */
+ sts = do_netif_metrics(mdesc, inst, atom);
+ }
+
+ return sts;
+}
+
+/*
+ * wrapper for pmdaFetch ... force value caches to be reloaded if needed,
+ * then do the fetch
+ */
+static int
+freebsd_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda)
+{
+ int i;
+ int done_disk = 0;
+ int done_netif = 0;
+
+ for (i = 0; i < maplen; i++) {
+ map[i].m_fetched = 0;
+ }
+
+ /*
+ * pre-fetch all metrics if needed, and update instance domains if
+ * they have changed
+ */
+ for (i = 0; !done_disk && !done_netif && i < numpmid; i++) {
+ if (pmid_cluster(pmidlist[i]) == CL_DISK) {
+ refresh_disk_metrics();
+ done_disk = 1;
+ }
+ else if (pmid_cluster(pmidlist[i]) == CL_NETIF) {
+ refresh_netif_metrics();
+ done_netif = 1;
+ }
+ }
+
+ return pmdaFetch(numpmid, pmidlist, resp, pmda);
+}
+
+/*
+ * wrapper for pmdaInstance ... refresh required instance domain first
+ */
+static int
+freebsd_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda)
+{
+ /*
+ * indomtab[] instance names and ids are not used for some indoms,
+ * ensure pmdaCache is current
+ */
+ if (indom == indomtab[DISK_INDOM].it_indom)
+ refresh_disk_metrics();
+ if (indom == indomtab[NETIF_INDOM].it_indom)
+ refresh_netif_metrics();
+
+ return pmdaInstance(indom, inst, name, result, pmda);
+}
+
+/*
+ * PCP metric name matching for linking metrictab[] entries to mib[]
+ * entries.
+ *
+ * Return 1 if prefix[] is equal to, or a prefix of name[]
+ *
+ * prefix[] of the form "a.bc" or "a.bc*" matches a name[] like "a.bc"
+ * or "a.bcanything", to improve readability of the initializers in
+ * mib[], and asterisk is a "match all" special case, so "a.b.*" matches
+ * "a.b.anything"
+ */
+static int
+matchname(const char *prefix, const char *name)
+{
+ while (*prefix != '\0' && *name != '\0' && *prefix == *name) {
+ prefix++;
+ name++;
+ }
+ if (*prefix == '\0' || *prefix == '*')
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * Initialise the agent (both daemon and DSO).
+ *
+ * Do mapping from sysclt(3) names to mibs.
+ * Collect some global constants.
+ * Build the system-specific, but not dynamic, instance domains,
+ * e.g. CPU_INDOM.
+ * Initialize the kernel memory reader.
+ */
+void
+freebsd_init(pmdaInterface *dp)
+{
+ int i;
+ int m;
+ int sts;
+ struct clockinfo clockrates;
+ size_t sz;
+ int mib[CTL_MAXNAME]; /* enough for longest mib key */
+ char iname[16]; /* enough for cpuNN.. */
+
+ if (isDSO) {
+ char mypath[MAXPATHLEN];
+ int sep = __pmPathSeparator();
+ snprintf(mypath, sizeof(mypath), "%s%c" "freebsd" "%c" "help",
+ pmGetConfig("PCP_PMDAS_DIR"), sep, sep);
+ pmdaDSO(dp, PMDA_INTERFACE_5, "freebsd DSO", mypath);
+ } else {
+ __pmSetProcessIdentity(username);
+ }
+
+ if (dp->status != 0)
+ return;
+
+ dp->version.four.fetch = freebsd_fetch;
+ dp->version.four.instance = freebsd_instance;
+
+ pmdaSetFetchCallBack(dp, freebsd_fetchCallBack);
+
+ pmdaInit(dp, indomtab, indomtablen, metrictab, metrictablen);
+
+ /*
+ * Link metrictab[] entries via m_user to map[] entries based on
+ * matching sysctl(3) name
+ *
+ * also translate the sysctl(3) name to a mib
+ */
+ for (m = 0; m < metrictablen; m++) {
+ if (metrictab[m].m_user == NULL) {
+ /* not using sysctl(3) */
+ continue;
+ }
+ for (i = 0; i < maplen; i++) {
+ if (matchname(map[i].m_pcpname, (char *)metrictab[m].m_user)) {
+ if (map[i].m_mib == NULL) {
+ /*
+ * multiple metrictab[] entries may point to the same
+ * mib[] entry, but this is the first time for this
+ * mib[] entry ...
+ */
+ map[i].m_miblen = sizeof(mib);
+ sts = sysctlnametomib(map[i].m_name, mib, &map[i].m_miblen);
+ if (sts == 0) {
+ map[i].m_mib = (int *)malloc(map[i].m_miblen*sizeof(map[i].m_mib[0]));
+ if (map[i].m_mib == NULL) {
+ fprintf(stderr, "Error: %s (%s): failed mib alloc for sysctl metric \"%s\"\n", map[i].m_pcpname, pmIDStr(metrictab[m].m_desc.pmid), map[i].m_name);
+ __pmNoMem("freebsd_init: mib", map[i].m_miblen*sizeof(map[i].m_mib[0]), PM_FATAL_ERR);
+ /*NOTREACHED*/
+ }
+ memcpy(map[i].m_mib, mib, map[i].m_miblen*sizeof(map[i].m_mib[0]));
+ }
+ else {
+ fprintf(stderr, "Error: %s (%s): failed sysctlnametomib(\"%s\", ...): %s\n", map[i].m_pcpname, pmIDStr(metrictab[m].m_desc.pmid), map[i].m_name, pmErrStr(-errno));
+ metrictab[m].m_user = (void *)&bad_mib;
+ }
+ }
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ int p;
+ fprintf(stderr, "Info: %s (%s): sysctl metric \"%s\" -> ", (char *)metrictab[m].m_user, pmIDStr(metrictab[m].m_desc.pmid), map[i].m_name);
+ for (p = 0; p < map[i].m_miblen; p++) {
+ if (p > 0) fputc('.', stderr);
+ fprintf(stderr, "%d", map[i].m_mib[p]);
+ }
+ fputc('\n', stderr);
+ }
+#endif
+ metrictab[m].m_user = (void *)&map[i];
+ break;
+ }
+ }
+ if (i == maplen) {
+ fprintf(stderr, "Error: %s (%s): cannot match name in sysctl map[]\n", (char *)metrictab[m].m_user, pmIDStr(metrictab[m].m_desc.pmid));
+ metrictab[m].m_user = (void *)&bad_mib;
+ }
+ }
+
+ /*
+ * Collect some global constants needed later ...
+ */
+ sz = sizeof(clockrates);
+ sts = sysctlbyname("kern.clockrate", &clockrates, &sz, NULL, 0);
+ if (sts < 0) {
+ fprintf(stderr, "Fatal Error: sysctlbyname(\"kern.clockrate\", ...) failed: %s\n", pmErrStr(-errno));
+ exit(1);
+ }
+ cpuhz = clockrates.stathz;
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ fprintf(stderr, "Info: CPU time \"hz\" = %d\n", cpuhz);
+#endif
+
+ sts = sysctlbyname("kern.cp_times", NULL, &sz, NULL, 0);
+ if (sts < 0) {
+ fprintf(stderr, "Fatal Error: sysctlbyname(\"kern.cp_times\", ...) failed: %s\n", pmErrStr(-errno));
+ exit(1);
+ }
+ /*
+ * see note below when fetching kernel.percpu.cpu.* metrics to
+ * explain this
+ */
+ ncpu = sz / (CPUSTATES * sizeof(__uint64_t));
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ fprintf(stderr, "Info: ncpu = %d\n", ncpu);
+#endif
+
+ sz = sizeof(pagesize);
+ sts = sysctlbyname("hw.pagesize", &pagesize, &sz, NULL, 0);
+ if (sts < 0) {
+ fprintf(stderr, "Fatal Error: sysctlbyname(\"hw.pagesize\", ...) failed: %s\n", pmErrStr(-errno));
+ exit(1);
+ }
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ fprintf(stderr, "Info: VM pagesize = %d\n", pagesize);
+#endif
+
+ /*
+ * Build some instance domains ...
+ */
+ indomtab[CPU_INDOM].it_numinst = ncpu;
+ indomtab[CPU_INDOM].it_set = (pmdaInstid *)malloc(ncpu * sizeof(pmdaInstid));
+ if (indomtab[CPU_INDOM].it_set == NULL) {
+ __pmNoMem("freebsd_init: CPU_INDOM it_set", ncpu * sizeof(pmdaInstid), PM_FATAL_ERR);
+ /*NOTREACHED*/
+ }
+ for (i = 0; i < ncpu; i++) {
+ indomtab[CPU_INDOM].it_set[i].i_inst = i;
+ snprintf(iname, sizeof(iname), "cpu%d", i);
+ indomtab[CPU_INDOM].it_set[i].i_name = strdup(iname);
+ if (indomtab[CPU_INDOM].it_set[i].i_name == NULL) {
+ __pmNoMem("freebsd_init: CPU_INDOM strdup iname", strlen(iname), PM_FATAL_ERR);
+ /*NOTREACHED*/
+ }
+ }
+
+ kmemread_init();
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage: %s [options]\n\n", pmProgname);
+ fputs("Options:\n"
+ " -d domain use domain (numeric) for metrics domain of PMDA\n"
+ " -l logfile write log into logfile rather than using default log name\n"
+ " -U username user account to run under (default \"pcp\")\n"
+ "\nExactly one of the following options may appear:\n"
+ " -i port expect PMCD to connect on given inet port (number or name)\n"
+ " -p expect PMCD to supply stdin/stdout (pipe)\n"
+ " -u socket expect PMCD to connect on given unix domain socket\n"
+ " -6 port expect PMCD to connect on given ipv6 port (number or name)\n",
+ stderr);
+ exit(1);
+}
+
+/*
+ * Set up the agent if running as a daemon.
+ */
+int
+main(int argc, char **argv)
+{
+ int c, err = 0;
+ int sep = __pmPathSeparator();
+ pmdaInterface dispatch;
+ char mypath[MAXPATHLEN];
+
+ isDSO = 0;
+ __pmSetProgname(argv[0]);
+ __pmGetUsername(&username);
+
+ snprintf(mypath, sizeof(mypath), "%s%c" "freebsd" "%c" "help",
+ pmGetConfig("PCP_PMDAS_DIR"), sep, sep);
+ pmdaDaemon(&dispatch, PMDA_INTERFACE_5, pmProgname, FREEBSD,
+ "freebsd.log", mypath);
+
+ while ((c = pmdaGetOpt(argc, argv, "D:d:i:l:pu:U:6:?", &dispatch, &err)) != EOF) {
+ switch(c) {
+ case 'U':
+ username = optarg;
+ break;
+ default:
+ err++;
+ }
+ }
+ if (err)
+ usage();
+
+ pmdaOpenLog(&dispatch);
+ freebsd_init(&dispatch);
+ pmdaConnect(&dispatch);
+ pmdaMain(&dispatch);
+ exit(0);
+}