]> arthur.barton.de Git - netdata.git/commitdiff
Merge pull request #1321 from vlvkobal/master
authorCosta Tsaousis <costa@tsaousis.gr>
Wed, 7 Dec 2016 20:00:29 +0000 (22:00 +0200)
committerGitHub <noreply@github.com>
Wed, 7 Dec 2016 20:00:29 +0000 (22:00 +0200)
Initial FreeBSD support

configure.ac
src/Makefile.am
src/common.c
src/common.h
src/freebsd_sysctl.c [new file with mode: 0644]
src/main.c
src/plugin_freebsd.c [new file with mode: 0644]
src/plugin_freebsd.h [new file with mode: 0644]

index 8d554db3e02478a033491a6f973877423c7f4c08..9b26fcddcc584bcb7f788e6a63672206fd45af6a 100644 (file)
@@ -36,6 +36,17 @@ PKG_PROG_PKG_CONFIG
 AC_USE_SYSTEM_EXTENSIONS
 AC_CHECK_FUNCS_ONCE(accept4)
 
+# Check system type
+case "$host_os" in
+freebsd*)
+       build_target=freebsd
+       ;;
+*)
+       ;;
+esac
+
+AM_CONDITIONAL([FREEBSD], [test x$build_target = xfreebsd])
+
 AC_ARG_ENABLE(
        [plugin-nfacct],
        [AS_HELP_STRING([--enable-plugin-nfacct], [enable nfacct plugin, requires root])],
index b3b3223acc286ef86f6398536f06bddfe9cc7e06..466c699354313764e396b7367955df0b7c475aba 100644 (file)
@@ -36,16 +36,37 @@ netdata_SOURCES = \
        eval.c eval.h \
        global_statistics.c global_statistics.h \
        health.c health.h \
-       ipc.c ipc.h \
        log.c log.h \
        main.c main.h \
        plugin_checks.c plugin_checks.h \
        plugin_idlejitter.c plugin_idlejitter.h \
        plugin_nfacct.c plugin_nfacct.h \
-       plugin_proc.c plugin_proc.h \
        plugin_tc.c plugin_tc.h \
        plugins_d.c plugins_d.h \
        popen.c popen.h \
+       sys_fs_cgroup.c \
+       procfile.c procfile.h \
+       proc_self_mountinfo.c proc_self_mountinfo.h \
+       registry.c registry.h \
+       rrd.c rrd.h \
+       rrd2json.c rrd2json.h \
+       storage_number.c storage_number.h \
+       unit_test.c unit_test.h \
+       url.c url.h \
+       web_buffer.c web_buffer.h \
+       web_buffer_svg.c web_buffer_svg.h \
+       web_client.c web_client.h \
+       web_server.c web_server.h \
+       $(NULL)
+
+if FREEBSD
+netdata_SOURCES += \
+       plugin_freebsd.c plugin_freebsd.h \
+       freebsd_sysctl.c \
+       $(NULL)
+else
+netdata_SOURCES += \
+       plugin_proc.c plugin_proc.h \
        proc_diskstats.c \
        proc_interrupts.c \
        proc_softirqs.c \
@@ -62,23 +83,13 @@ netdata_SOURCES = \
        proc_net_stat_conntrack.c \
        proc_net_stat_synproxy.c \
        proc_stat.c \
-       proc_self_mountinfo.c proc_self_mountinfo.h \
        proc_sys_kernel_random_entropy_avail.c \
        proc_vmstat.c \
+       ipc.c ipc.h \
        sys_kernel_mm_ksm.c \
-       sys_fs_cgroup.c \
-       procfile.c procfile.h \
-       registry.c registry.h \
-       rrd.c rrd.h \
-       rrd2json.c rrd2json.h \
-       storage_number.c storage_number.h \
-       unit_test.c unit_test.h \
-       url.c url.h \
-       web_buffer.c web_buffer.h \
-       web_buffer_svg.c web_buffer_svg.h \
-       web_client.c web_client.h \
-       web_server.c web_server.h \
        $(NULL)
+endif
+
 netdata_LDADD = \
        $(OPTIONAL_MATH_LIBS) \
        $(OPTIONAL_NFACCT_LIBS) \
index fa69bff8568d719c765fa1452bca7940b95663e6..98093b965cd4e70a8a62eb28a44abe4f473b20ee 100644 (file)
@@ -1,5 +1,10 @@
 #include "common.h"
 
+#ifdef __FreeBSD__
+#    define O_NOATIME     0
+#    define MADV_DONTFORK INHERIT_NONE
+#endif /* __FreeBSD__ */
+
 char *global_host_prefix = "";
 int enable_ksm = 1;
 
@@ -1025,7 +1030,11 @@ int fd_is_valid(int fd) {
 }
 
 pid_t gettid(void) {
+#ifdef __FreeBSD__
+    return (pid_t)pthread_getthreadid_np();
+#else
     return (pid_t)syscall(SYS_gettid);
+#endif /* __FreeBSD__ */
 }
 
 char *fgets_trim_len(char *buf, size_t buf_size, FILE *fp, size_t *len) {
index 7b95daa8ff3a70563365477b965fff03cb0027c4..a6f185bc0da80949584f20c8c49c32c66f2cd82c 100644 (file)
@@ -20,7 +20,9 @@
 
 #else /* !defined(ENABLE_JEMALLOC) && !defined(ENABLE_TCMALLOC) */
 
+#ifndef __FreeBSD__
 #include <malloc.h>
+#endif /* __FreeBSD__ */
 
 #endif
 
@@ -52,7 +54,9 @@
 #include <signal.h>
 #include <syslog.h>
 #include <sys/mman.h>
+#ifndef __FreeBSD__
 #include <sys/prctl.h>
+#endif /* __FreeBSD__ */
 #include <sys/resource.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include "plugin_checks.h"
 #include "plugin_idlejitter.h"
 #include "plugin_nfacct.h"
+#ifndef __FreeBSD__
 #include "plugin_proc.h"
+#else
+#include "plugin_freebsd.h"
+#endif /* __FreeBSD__ */
 #include "plugin_tc.h"
 #include "plugins_d.h"
 
diff --git a/src/freebsd_sysctl.c b/src/freebsd_sysctl.c
new file mode 100644 (file)
index 0000000..73cc29b
--- /dev/null
@@ -0,0 +1,305 @@
+#include "common.h"
+
+// NEEDED BY: struct vmstat
+#include <sys/vmmeter.h>
+
+// FreeBSD calculates load averages once every 5 seconds
+#define MIN_LOADAVG_UPDATE_EVERY 5
+
+int do_freebsd_sysctl(int update_every, unsigned long long dt) {
+    (void)dt;
+
+    static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1,
+        do_loadavg = -1, do_all_processes = -1;
+
+    if(unlikely(do_cpu == -1)) {
+        do_cpu                  = config_get_boolean("plugin:freebsd:sysctl", "cpu utilization", 1);
+        do_cpu_cores            = config_get_boolean("plugin:freebsd:sysctl", "per cpu core utilization", 1);
+        do_interrupts           = config_get_boolean("plugin:freebsd:sysctl", "cpu interrupts", 1);
+        do_context              = config_get_boolean("plugin:freebsd:sysctl", "context switches", 1);
+        do_forks                = config_get_boolean("plugin:freebsd:sysctl", "processes started", 1);
+        do_processes            = config_get_boolean("plugin:freebsd:sysctl", "processes running", 1);
+        do_loadavg              = config_get_boolean("plugin:freebsd:sysctl", "enable load average", 1);
+        do_all_processes        = config_get_boolean("plugin:freebsd:sysctl", "enable total processes", 1);
+    }
+
+    RRDSET *st;
+
+    int i;
+
+// NEEDED BY: do_loadavg
+    static unsigned long long last_loadavg_usec = 0;
+    struct loadavg sysload;
+
+// NEEDED BY: do_cpu, do_cpu_cores
+    long cp_time[CPUSTATES];
+
+// NEEDED BY: do_cpu_cores
+    int ncpus;
+    static long *pcpu_cp_time = NULL;
+    char cpuid[8]; // no more than 4 digits expected
+
+// NEEDED BY: do_all_processes, do_processes
+    struct vmtotal vmtotal_data;
+
+// NEEDED BY: do_context, do_forks
+    u_int u_int_data;
+
+// NEEDED BY: do_interrupts
+    size_t intrcnt_size;
+    unsigned long nintr = 0;
+    static unsigned long *intrcnt = NULL;
+    unsigned long long totalintr = 0;
+
+    // --------------------------------------------------------------------
+
+    if(last_loadavg_usec <= dt) {
+        if(likely(do_loadavg)) {
+            if (unlikely(GETSYSCTL("vm.loadavg", sysload))) {
+                do_loadavg = 0;
+                error("DISABLED: system.load");
+            } else {
+
+                st = rrdset_find_bytype("system", "load");
+                if(unlikely(!st)) {
+                    st = rrdset_create("system", "load", NULL, "load", NULL, "System Load Average", "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY) ? MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE);
+                    rrddim_add(st, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+                    rrddim_add(st, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+                    rrddim_add(st, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "load1", (collected_number) ((double)sysload.ldavg[0] / sysload.fscale * 1000));
+                rrddim_set(st, "load5", (collected_number) ((double)sysload.ldavg[1] / sysload.fscale * 1000));
+                rrddim_set(st, "load15", (collected_number) ((double)sysload.ldavg[2] / sysload.fscale * 1000));
+                rrdset_done(st);
+            }
+        }
+
+        last_loadavg_usec = st->update_every * 1000000ULL;
+    }
+    else last_loadavg_usec -= dt;
+
+    // --------------------------------------------------------------------
+
+    if(likely(do_all_processes | do_processes)) {
+        if (unlikely(GETSYSCTL("vm.vmtotal", vmtotal_data))) {
+            do_all_processes = 0;
+            error("DISABLED: system.active_processes");
+            do_processes = 0;
+            error("DISABLED: system.processes");
+        } else {
+            if(likely(do_processes)) {
+
+                st = rrdset_find_bytype("system", "active_processes");
+                if(unlikely(!st)) {
+                    st = rrdset_create("system", "active_processes", NULL, "processes", NULL, "System Active Processes", "processes", 750, update_every, RRDSET_TYPE_LINE);
+                    rrddim_add(st, "active", NULL, 1, 1, RRDDIM_ABSOLUTE);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "active", (vmtotal_data.t_rq + vmtotal_data.t_dw + vmtotal_data.t_pw + vmtotal_data.t_sl + vmtotal_data.t_sw));
+                rrdset_done(st);
+            }
+            if(likely(do_processes)) {
+
+                st = rrdset_find_bytype("system", "processes");
+                if(unlikely(!st)) {
+                    st = rrdset_create("system", "processes", NULL, "processes", NULL, "System Processes", "processes", 600, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "running", NULL, 1, 1, RRDDIM_ABSOLUTE);
+                    rrddim_add(st, "blocked", NULL, -1, 1, RRDDIM_ABSOLUTE);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "running", vmtotal_data.t_rq);
+                rrddim_set(st, "blocked", (vmtotal_data.t_dw + vmtotal_data.t_pw));
+                rrdset_done(st);
+            }
+
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    if(likely(do_processes)) {
+
+            st = rrdset_find_bytype("system", "processes");
+            if(unlikely(!st)) {
+                st = rrdset_create("system", "processes", NULL, "processes", NULL, "System Processes", "processes", 600, update_every, RRDSET_TYPE_LINE);
+
+                rrddim_add(st, "running", NULL, 1, 1, RRDDIM_ABSOLUTE);
+                rrddim_add(st, "blocked", NULL, -1, 1, RRDDIM_ABSOLUTE);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "running", vmtotal_data.t_rq);
+            rrddim_set(st, "blocked", (vmtotal_data.t_dw + vmtotal_data.t_pw));
+            rrdset_done(st);
+        }
+
+    // --------------------------------------------------------------------
+
+    if(likely(do_cpu)) {
+        if (unlikely(CPUSTATES != 5)) {
+            error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
+            do_cpu = 0;
+            error("DISABLED: system.cpu");
+        } else {
+            if (unlikely(GETSYSCTL("kern.cp_time", cp_time))) {
+                do_cpu = 0;
+                error("DISABLED: system.cpu");
+            } else {
+
+                st = rrdset_find_bytype("system", "cpu");
+                if(unlikely(!st)) {
+                    st = rrdset_create("system", "cpu", NULL, "cpu", "system.cpu", "Total CPU utilization", "percentage", 100, update_every, RRDSET_TYPE_STACKED);
+
+                    rrddim_add(st, "user", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                    rrddim_add(st, "nice", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                    rrddim_add(st, "system", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                    rrddim_add(st, "interrupt", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                    rrddim_add(st, "idle", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                    rrddim_hide(st, "idle");
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "user", cp_time[0]);
+                rrddim_set(st, "nice", cp_time[1]);
+                rrddim_set(st, "system", cp_time[2]);
+                rrddim_set(st, "interrupt", cp_time[3]);
+                rrddim_set(st, "idle", cp_time[4]);
+                rrdset_done(st);
+            }
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    if(likely(do_cpu_cores)) {
+        if (unlikely(CPUSTATES != 5)) {
+            error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
+            do_cpu_cores = 0;
+            error("DISABLED: cpu.cpuXX");
+        } else {
+            if (unlikely(GETSYSCTL("kern.smp.cpus", ncpus))) {
+                do_cpu_cores = 0;
+                error("DISABLED: cpu.cpuXX");
+            } else {
+                pcpu_cp_time = reallocz(pcpu_cp_time, sizeof(cp_time) * ncpus);
+
+                for (i = 0; i < ncpus; i++) {
+                    if (unlikely(getsysctl("kern.cp_times", pcpu_cp_time, sizeof(cp_time) * ncpus))) {
+                        do_cpu_cores = 0;
+                        error("DISABLED: cpu.cpuXX");
+                        break;
+                    }
+                    if (unlikely(ncpus > 9999)) {
+                        error("FREEBSD: There are more than 4 digits in cpu cores number");
+                        do_cpu_cores = 0;
+                        error("DISABLED: cpu.cpuXX");
+                        break;
+                    }
+                    snprintfz(cpuid, 8, "cpu%d", i);
+
+                    st = rrdset_find_bytype("cpu", cpuid);
+                    if(unlikely(!st)) {
+                        st = rrdset_create("cpu", cpuid, NULL, "utilization", "cpu.cpu", "Core utilization", "percentage", 1000, update_every, RRDSET_TYPE_STACKED);
+
+                        rrddim_add(st, "user", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                        rrddim_add(st, "nice", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                        rrddim_add(st, "system", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                        rrddim_add(st, "interrupt", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                        rrddim_add(st, "idle", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                        rrddim_hide(st, "idle");
+                    }
+                    else rrdset_next(st);
+
+                    rrddim_set(st, "user", pcpu_cp_time[i * 5 + 0]);
+                    rrddim_set(st, "nice", pcpu_cp_time[i * 5 + 1]);
+                    rrddim_set(st, "system", pcpu_cp_time[i * 5 + 2]);
+                    rrddim_set(st, "interrupt", pcpu_cp_time[i * 5 + 3]);
+                    rrddim_set(st, "idle", pcpu_cp_time[i * 5 + 4]);
+                    rrdset_done(st);
+                }
+            }
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    if(likely(do_interrupts)) {
+        if (unlikely(sysctlbyname("hw.intrcnt", NULL, &intrcnt_size, NULL, 0) == -1)) {
+            error("FREEBSD: sysctl(hw.intrcnt...) failed: %s", strerror(errno));
+            do_interrupts = 0;
+            error("DISABLED: system.intr");
+        } else {
+            nintr = intrcnt_size / sizeof(u_long);
+            intrcnt = reallocz(intrcnt, nintr * sizeof(u_long));
+            if (unlikely(getsysctl("hw.intrcnt", intrcnt, nintr * sizeof(u_long)))){
+                do_interrupts = 0;
+                error("DISABLED: system.intr");
+            } else {
+                for (i = 0; i < nintr; i++)
+                    totalintr += intrcnt[i];
+
+                st = rrdset_find_bytype("system", "intr");
+                if(unlikely(!st)) {
+                    st = rrdset_create("system", "intr", NULL, "interrupts", NULL, "Total Device Interrupts", "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "interrupts", totalintr);
+                rrdset_done(st);
+            }
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    if(likely(do_context)) {
+        if (unlikely(GETSYSCTL("vm.stats.sys.v_swtch", u_int_data))) {
+            do_context = 0;
+            error("DISABLED: system.ctxt");
+        } else {
+
+            st = rrdset_find_bytype("system", "ctxt");
+            if(unlikely(!st)) {
+                st = rrdset_create("system", "ctxt", NULL, "processes", NULL, "CPU Context Switches", "context switches/s", 800, update_every, RRDSET_TYPE_LINE);
+
+                rrddim_add(st, "switches", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "switches", u_int_data);
+            rrdset_done(st);
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    if(likely(do_forks)) {
+        if (unlikely(GETSYSCTL("vm.stats.vm.v_forks", u_int_data))) {
+            do_forks = 0;
+            error("DISABLED: system.forks");
+        } else {
+
+            st = rrdset_find_bytype("system", "forks");
+            if(unlikely(!st)) {
+                st = rrdset_create("system", "forks", NULL, "processes", NULL, "Started Processes", "processes/s", 700, update_every, RRDSET_TYPE_LINE);
+                st->isdetail = 1;
+
+                rrddim_add(st, "started", NULL, 1, 1, RRDDIM_INCREMENTAL);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "started", u_int_data);
+            rrdset_done(st);
+        }
+    }
+
+    return 0;
+}
index 5fe9e636952babd54dd4fe6b1ce1c3f0af1cb659..b9ab4ef316148e57edb29dfbe514cd6de0e05a7c 100644 (file)
@@ -45,7 +45,11 @@ struct netdata_static_thread {
 
     {"tc",                 "plugins",   "tc",         1, NULL, NULL, tc_main},
     {"idlejitter",         "plugins",   "idlejitter", 1, NULL, NULL, cpuidlejitter_main},
+#ifndef __FreeBSD__
     {"proc",               "plugins",   "proc",       1, NULL, NULL, proc_main},
+#else
+    {"freebsd",            "plugins",   "freebsd",    1, NULL, NULL, freebsd_main},
+#endif /* __FreeBSD__ */
     {"cgroups",            "plugins",   "cgroups",    1, NULL, NULL, cgroups_main},
     {"check",              "plugins",   "checks",     0, NULL, NULL, checks_main},
     {"backends",            NULL,       NULL,         1, NULL, NULL, backends_main},
@@ -463,7 +467,9 @@ int main(int argc, char **argv)
             if(setrlimit(RLIMIT_CORE, &rl) != 0)
                 error("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
 
+#ifndef __FreeBSD__
             prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
+#endif /* __FreeBSD__ */
         }
 
         // --------------------------------------------------------------------
@@ -638,7 +644,9 @@ int main(int argc, char **argv)
         struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
         if(setrlimit(RLIMIT_CORE, &rl) != 0)
             error("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
+#ifndef __FreeBSD__
         prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
+#endif /* __FreeBSD__ */
     }
 #endif /* NETDATA_INTERNAL_CHECKS */
 
diff --git a/src/plugin_freebsd.c b/src/plugin_freebsd.c
new file mode 100644 (file)
index 0000000..47a1861
--- /dev/null
@@ -0,0 +1,79 @@
+#include "common.h"
+
+void *freebsd_main(void *ptr)
+{
+    (void)ptr;
+
+    info("FREEBSD Plugin thread created with task id %d", gettid());
+
+    if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+        error("Cannot set pthread cancel type to DEFERRED.");
+
+    if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+        error("Cannot set pthread cancel state to ENABLE.");
+
+    // disable (by default) various interface that are not needed
+    /*
+    config_get_boolean("plugin:proc:/proc/net/dev:lo", "enabled", 0);
+    config_get_boolean("plugin:proc:/proc/net/dev:fireqos_monitor", "enabled", 0);
+    */
+
+    // when ZERO, attempt to do it
+    int vdo_cpu_netdata             = !config_get_boolean("plugin:freebsd", "netdata server resources", 1);
+    int vdo_freebsd_sysctl          = !config_get_boolean("plugin:freebsd", "sysctl", 1);
+
+    // keep track of the time each module was called
+    unsigned long long sutime_freebsd_sysctl = 0ULL;
+
+    unsigned long long step = rrd_update_every * 1000000ULL;
+    for(;;) {
+        unsigned long long now = time_usec();
+        unsigned long long next = now - (now % step) + step;
+
+        while(now < next) {
+            sleep_usec(next - now);
+            now = time_usec();
+        }
+
+        if(unlikely(netdata_exit)) break;
+
+        // BEGIN -- the job to be done
+
+        if(!vdo_freebsd_sysctl) {
+            debug(D_PROCNETDEV_LOOP, "FREEBSD: calling do_freebsd_sysctl().");
+            now = time_usec();
+            vdo_freebsd_sysctl = do_freebsd_sysctl(rrd_update_every, (sutime_freebsd_sysctl > 0)?now - sutime_freebsd_sysctl:0ULL);
+            sutime_freebsd_sysctl = now;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        // END -- the job is done
+
+        // --------------------------------------------------------------------
+
+        if(!vdo_cpu_netdata) {
+            global_statistics_charts();
+            registry_statistics();
+        }
+    }
+
+    info("FREEBSD thread exiting");
+
+    pthread_exit(NULL);
+    return NULL;
+}
+
+int getsysctl(const char *name, void *ptr, size_t len)
+{
+    size_t nlen = len;
+
+    if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
+        error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
+        return 1;
+    }
+    if (unlikely(nlen != len)) {
+        error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
+        return 1;
+    }
+    return 0;
+}
diff --git a/src/plugin_freebsd.h b/src/plugin_freebsd.h
new file mode 100644 (file)
index 0000000..ee432bf
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef NETDATA_PLUGIN_FREEBSD_H
+#define NETDATA_PLUGIN_FREEBSD_H 1
+
+#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
+
+void *freebsd_main(void *ptr);
+
+int getsysctl(const char *name, void *ptr, size_t len);
+
+extern int do_freebsd_sysctl(int update_every, unsigned long long dt);
+
+#endif /* NETDATA_PLUGIN_FREEBSD_H */