[i3] [i3status] [PATCH] Network throughput

  • From: Mathias Buhr <buhr@xxxxxxxxxxxx>
  • To: i3-discuss@xxxxxxxxxxxxx
  • Date: Mon, 12 Mar 2012 13:14:51 +0100

Hi,

just in case there is some interest:
I've patched i3status to monitor incoming & outgoing network traffic
with the help of some code from an XFCE4 panel plugin. XFCE itself took
the code from a CLI monitoring tool called wormulon. I was working on
some NFS issues and needed something to easily monitor that kind of stuff.
The new "throughput" module can be used multiple times for different
network interfaces and can (in theory) replace the ethernet module with
exception of the network speed. As this change might break existing
config files I didn't touch anything related to that.
The downside of this patch is it's size: 81kb. The size is due to the
necessary wormulon code but this solution doesn't add any external
dependancies. Worumlon compiles on many platforms too.
Network throughput can be monitored in Bytes, Kilobytes and Megabytes/s.

If there is some interest and I did something wrong just let me know and
I'll try to provide a better patch.

Regards
Mathias

From c9f58b40c63a9dabd55e73012ad695fb77ddbd96 Mon Sep 17 00:00:00 2001
From: Mathias Buhr <buhr@xxxxxxxxxxxx>
Date: Mon, 12 Mar 2012 11:10:20 +0100
Subject: [PATCH] added support for network throughput monitoring

fixed comment placements
---
i3status.c | 40 ++++-
i3status.conf | 9 ++
include/global.h | 42 ++++++
include/i3status.h | 3 +
include/net.h | 144 ++++++++++++++++++
include/os.h | 232 +++++++++++++++++++++++++++++
include/slurm.h | 56 +++++++
include/wormulon.h | 30 ++++
include/wormulon/freebsd.c | 152 +++++++++++++++++++
include/wormulon/freebsd.h | 11 ++
include/wormulon/hpux.c | 197 ++++++++++++++++++++++++
include/wormulon/hpux.h | 10 ++
include/wormulon/if_media.c | 322 ++++++++++++++++++++++++++++++++++++++++
include/wormulon/if_media.h | 5 +
include/wormulon/linux.c | 138 +++++++++++++++++
include/wormulon/linux.h | 14 ++
include/wormulon/macos.c | 171 +++++++++++++++++++++
include/wormulon/macos.h | 10 ++
include/wormulon/netbsd.c | 171 +++++++++++++++++++++
include/wormulon/netbsd.h | 10 ++
include/wormulon/openbsd.c | 173 +++++++++++++++++++++
include/wormulon/openbsd.h | 10 ++
include/wormulon/solaris.c | 151 +++++++++++++++++++
include/wormulon/solaris.h | 10 ++
include/wormulon/unsupported.c | 23 +++
include/wormulon/unsupported.h | 3 +
src/net.c | 266 +++++++++++++++++++++++++++++++++
src/print_throughput.c | 54 +++++++
28 files changed, 2456 insertions(+), 1 deletion(-)
create mode 100644 include/global.h
create mode 100644 include/net.h
create mode 100644 include/os.h
create mode 100644 include/slurm.h
create mode 100644 include/wormulon.h
create mode 100644 include/wormulon/freebsd.c
create mode 100644 include/wormulon/freebsd.h
create mode 100644 include/wormulon/hpux.c
create mode 100644 include/wormulon/hpux.h
create mode 100644 include/wormulon/if_media.c
create mode 100644 include/wormulon/if_media.h
create mode 100644 include/wormulon/linux.c
create mode 100644 include/wormulon/linux.h
create mode 100644 include/wormulon/macos.c
create mode 100644 include/wormulon/macos.h
create mode 100644 include/wormulon/netbsd.c
create mode 100644 include/wormulon/netbsd.h
create mode 100644 include/wormulon/openbsd.c
create mode 100644 include/wormulon/openbsd.h
create mode 100644 include/wormulon/solaris.c
create mode 100644 include/wormulon/solaris.h
create mode 100644 include/wormulon/unsupported.c
create mode 100644 include/wormulon/unsupported.h
create mode 100644 src/net.c
create mode 100644 src/print_throughput.c

diff --git a/i3status.c b/i3status.c
index dd7d1e6..84f35fd 100644
--- a/i3status.c
+++ b/i3status.c
@@ -171,6 +171,8 @@ static char *get_config_path() {

int main(int argc, char *argv[]) {
unsigned int j;
+ unsigned int num_throughput = 0;
+ netdata **throughput_data;

cfg_opt_t general_opts[] = {
CFG_STR("output_format", "auto", CFGF_NONE),
@@ -201,6 +203,11 @@ int main(int argc, char *argv[]) {
CFG_END()
};

+ cfg_opt_t throughput_opts[] = {
+ CFG_STR("format", "in %ik :: out %ok", CFGF_NONE),
+ CFG_END()
+ };
+
cfg_opt_t ipv6_opts[] = {
CFG_STR("format_up", "%ip", CFGF_NONE),
CFG_STR("format_down", "no IPv6", CFGF_NONE),
@@ -259,6 +266,7 @@ int main(int argc, char *argv[]) {
CFG_SEC("run_watch", run_watch_opts, CFGF_TITLE | CFGF_MULTI),
CFG_SEC("wireless", wireless_opts, CFGF_TITLE | CFGF_MULTI),
CFG_SEC("ethernet", ethernet_opts, CFGF_TITLE | CFGF_MULTI),
+ CFG_SEC("throughput", throughput_opts, CFGF_TITLE |
CFGF_MULTI),
CFG_SEC("battery", battery_opts, CFGF_TITLE | CFGF_MULTI),
CFG_SEC("cpu_temperature", temp_opts, CFGF_TITLE | CFGF_MULTI),
CFG_SEC("disk", disk_opts, CFGF_TITLE | CFGF_MULTI),
@@ -354,8 +362,28 @@ int main(int argc, char *argv[]) {

int interval = cfg_getint(cfg_general, "interval");

+ for (j = 0; j < cfg_size(cfg, "order"); j++) {
+ /* how many "throughput" sections are there? */
+ const char *current = cfg_getnstr(cfg, "order", j);
+ CASE_SEC_TITLE("throughput") {
+ ++num_throughput;
+ }
+ }
+ /* alloc & init "throughput" */
+ throughput_data = malloc(sizeof(netdata*) * num_throughput);
+ unsigned int i = 0;
+ for (j = 0; j < cfg_size(cfg, "order"); j++) {
+ const char *current = cfg_getnstr(cfg, "order", j);
+ CASE_SEC_TITLE("throughput") {
+ throughput_data[i] = malloc(sizeof(netdata));
+ init_netload(throughput_data[i], title);
+ ++i;
+ }
+ }
+
struct tm tm;
while (1) {
+ i = 0;
struct timeval tv;
gettimeofday(&tv, NULL);
time_t current_time = tv.tv_sec;
@@ -378,9 +406,14 @@ int main(int argc, char *argv[]) {
CASE_SEC_TITLE("wireless")
print_wireless_info(title, cfg_getstr(sec,
"format_up"), cfg_getstr(sec, "format_down"));

- CASE_SEC_TITLE("ethernet")
+ CASE_SEC_TITLE("ethernet")
print_eth_info(title, cfg_getstr(sec,
"format_up"), cfg_getstr(sec, "format_down"));

+ CASE_SEC_TITLE("throughput") {
+ print_throughput(title, cfg_getstr(sec,
"format"), throughput_data[i]);
+ ++i;
+ }
+
CASE_SEC_TITLE("battery")
print_battery_info(atoi(title),
cfg_getstr(sec, "path"), cfg_getstr(sec, "format"), cfg_getbool(sec,
"last_full_capacity"));

@@ -425,4 +458,9 @@ int main(int argc, char *argv[]) {
struct timespec ts = {interval - 1, (10e5 -
current_timeval.tv_usec) * 1000};
nanosleep(&ts, NULL);
}
+ for (i = 0; i < num_throughput; ++i) {
+ free(throughput_data[i]);
+ }
+ free(throughput_data);
+ return EXIT_SUCCESS;
}
diff --git a/i3status.conf b/i3status.conf
index ee0db5c..266d357 100644
--- a/i3status.conf
+++ b/i3status.conf
@@ -1,6 +1,7 @@
general {
colors = true
interval = 5
+ output_format = dzen2
}

order += "ipv6"
@@ -9,6 +10,7 @@ order += "run_watch DHCP"
order += "run_watch VPN"
order += "wireless wlan0"
order += "ethernet eth0"
+order += "throughput eth0"
order += "battery 0"
order += "cpu_temperature 0"
order += "load"
@@ -25,6 +27,13 @@ ethernet eth0 {
format_down = "E: down"
}

+throughput eth0 {
+ # syntax: %xy whereas
+ # x: 'i' in, 'o' out
+ # y: 'b' byte, 'k' kbyte, 'm' mbyte
+ format = "in %ik :: out %ok"
+}
+
battery 0 {
format = "%status %percentage %remaining"
}
diff --git a/include/global.h b/include/global.h
new file mode 100644
index 0000000..fedd617
--- /dev/null
+++ b/include/global.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2005 Bernhard Walle <bernhard@xxxxxxxxx>
+ *
-------------------------------------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+ * Ave, Cambridge, MA 02139, USA.
+ *
+ *
-------------------------------------------------------------------------------------------------

+ */
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef DEBUG
+
+# define PRINT_DBG(fmt, ...) \
+ { \
+ fprintf(stderr, "DEBUG[%s:%d]: "fmt, __FILE__, __LINE__, \
+ ## __VA_ARGS__); \
+ }
+
+#else
+
+# define PRINT_DBG(fmt, ...) { do {} while(0); }
+
+#endif
+
+#endif /* GLOBAL_H */
diff --git a/include/i3status.h b/include/i3status.h
index e40003c..b89f066 100644
--- a/include/i3status.h
+++ b/include/i3status.h
@@ -31,6 +31,8 @@ enum { O_DZEN2, O_XMOBAR, O_I3BAR, O_NONE } output_format;

#endif

+#include "net.h"
+
/* Allows for the definition of a variable without opening a new scope, thus
* suited for usage in a macro. Idea from wmii. */
#define with(type, var, init) \
@@ -75,6 +77,7 @@ void print_cpu_temperature_info(int zone, const char *path,
const char *format);
void print_cpu_usage(const char *format);
void print_eth_info(const char *interface, const char *format_up, const char
*format_down);
void print_load();
+void print_throughput(const char *interface, const char *format, netdata*
data);
void print_volume(const char *fmt, const char *device, const char *mixer, int
mixer_idx);
bool process_runs(const char *path);

diff --git a/include/net.h b/include/net.h
new file mode 100644
index 0000000..e8a48ea
--- /dev/null
+++ b/include/net.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2003,2005,2006 Bernhard Walle <bernhard@xxxxxxxxx>
+ * Copyright 2010 Florian Rivoal <frivoal@xxxxxxxxx>
+ *
-------------------------------------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+ * Ave, Cambridge, MA 02139, USA.
+ *
+ *
-------------------------------------------------------------------------------------------------

+ */
+#ifndef NET_H
+#define NET_H
+
+#include "os.h"
+#include "slurm.h"
+
+#define MSGSIZE 1024
+#define UP_UPDATE_INTERVAL 20
+#define IP_UPDATE_INTERVAL 20
+#define IP_ADDRESS_LENGTH 64
+#define INTERFACE_NAME_LENGTH 9
+
+#ifndef gettext_noop
+#define gettext_noop(String) String
+#endif
+
+/** errorcodes */
+typedef enum
+{
+ UNKNOWN_ERROR,
+ PROC_DEVICE_NOT_FOUND,
+ INTERFACE_NOT_FOUND
+} errorcode_t;
+
+
+/**
+ * We need this because we cannot use static variables. Using of static
variables allows
+ * us not to use several instances of the plugin.
+ * I know that this change makes it a bit incompatible with wormulon, but
that's the
+ * price to pay ...
+ */
+typedef struct
+{
+ char old_interface[INTERFACE_NAME_LENGTH];
+ double backup_in;
+ errorcode_t errorcode;
+ double backup_out;
+ double cur_in;
+ double cur_out;
+ struct timeval prev_time;
+ int correct_interface; /* treated as boolean */
+ IfData ifdata;
+ char ip_address[IP_ADDRESS_LENGTH];
+ int ip_update_count;
+ DataStats stats;
+ int up;
+ int up_update_count;
+#ifdef __HPUX__
+ int wait_pcks_counter;
+ nmapi_logstat* if_ptr;
+#elif __FreeBSD__ || __DragonFly__ || __FreeBSD_kernel__
+ int watchif;
+ int dev_opened;
+#elif __NetBSD__
+ int mib_name1[6];
+ int mib_name2[6];
+ char* buf1;
+ char* buf2;
+ int alloc1;
+ int alloc2;
+#elif __OpenBSD__ || __MicroBSD__ || __APPLE__
+ int mib_name1[6];
+ int mib_name2[6];
+ char* buf1;
+ char* buf2;
+ int alloc1;
+ int alloc2;
+#elif __linux__
+ FILE* proc_net_dev;
+#elif __Solaris__
+#else
+#error "OS not supported"
+#endif
+
+} netdata;
+
+
+/**
+ * Initializes the netload plugin. Used to set up inital values. This function
must
+ * be called after each change of the network interface.
+ * @param device The network device, e.g. <code>ippp0</code> for ISDN
on Linux.
+ * @return <code>true</code> if no error occurs, <code>false</code>
otherwise. If there's
+ * an error, the error message may be set
+ */
+int init_netload(netdata* data, const char* device);
+
+/**
+ * Gets the current netload. You must call init_netload() once before you use
this function!
+ * @param in Input load in byte/s.
+ * @param out Output load in byte/s.
+ * @param tot Total load in byte/s.
+ */
+void get_current_netload(netdata* data, unsigned long *in, unsigned long *out,
unsigned long *tot);
+
+/**
+ * Returns the name of the network interface.
+ * @param data object
+ * @return The name. String resides in data and you don't have to free the
string.
+ * On error, returns NULL.
+ */
+char* get_name(netdata* data);
+
+/**
+ * Check to see if an interface is up.
+ * @param data object
+ * @return <code>true</code> if interface is up, <code>false</code> otherwise.
+ */
+int get_interface_up(netdata* data);
+
+
+/**
+ * Returns the IP address of the network interface
+ * @param data object
+ * @return the IP address as string, NULL on error.
+ */
+char* get_ip_address(netdata* data);
+
+/**
+ * Should be called to do cleanup work.
+ */
+void close_netload(netdata* data);
+
+#endif /* NET_H */
diff --git a/include/os.h b/include/os.h
new file mode 100644
index 0000000..5731580
--- /dev/null
+++ b/include/os.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2003, 2005, 2006 Bernhard Walle <bernhard@xxxxxxxxx>
+ * Copyright 2010 Florian Rivoal <frivoal@xxxxxxxxx>
+ *
-------------------------------------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+ * Ave, Cambridge, MA 02139, USA.
+ *
+ *
-------------------------------------------------------------------------------------------------

+ */
+#ifndef _OS_H
+#define _OS_H
+
+#if defined (__sun__)
+# define __Solaris__ 1
+#endif
+
+#ifdef __HPUX__ /* H P U X */
+# define _XOPEN_SOURCE_EXTENDED
+# include <stdio.h>
+# include <sys/param.h>
+# include <stdlib.h>
+# include <stdarg.h>
+# include <stropts.h>
+# include <unistd.h>
+# include <string.h>
+# include <time.h>
+# include <ctype.h>
+# include <signal.h>
+# include <sys/stdsyms.h>
+# include <sys/wait.h>
+# include <sys/stat.h>
+# include <sys/ioctl.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/time.h>
+# include <netinet/in.h>
+# include <net/if.h>
+# include <sys/mib.h>
+# include <arpa/inet.h>
+# include <net/if.h>
+#elif __APPLE__ /* Mac OS X */
+# include <stdio.h>
+# include <stdlib.h>
+# include <stdarg.h>
+# include <unistd.h>
+# include <string.h>
+# include <time.h>
+# include <ctype.h>
+# include <signal.h>
+# include <curses.h>
+# include <ifaddrs.h>
+# include <sys/param.h>
+# include <sys/sysctl.h>
+# include <sys/wait.h>
+# include <sys/stat.h>
+# include <sys/ioctl.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/time.h>
+# include <netinet/in.h>
+# include <net/route.h>
+# include <net/if_dl.h>
+# include <net/if.h>
+# include <net/if_media.h>
+# include <net/if_mib.h>
+# include <arpa/inet.h>
+#elif __DragonFly__ /* D R A G O N F L Y */
+# include <stdio.h>
+# include <stdlib.h>
+# include <stdarg.h>
+# include <unistd.h>
+# include <string.h>
+# include <time.h>
+# include <ctype.h>
+# include <signal.h>
+# include <sys/param.h>
+# include <sys/sysctl.h>
+# include <sys/wait.h>
+# include <sys/stat.h>
+# include <sys/ioctl.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/time.h>
+# include <netinet/in.h>
+# include <net/if.h>
+# include <net/if_media.h>
+# include <net/if_mib.h>
+# include <arpa/inet.h>
+# include <net/ppp_layer/ppp_defs.h>
+# include <net/ppp/if_ppp.h>
+#elif __FreeBSD__ || __FreeBSD_kernel__ /* F R E E B S D */
+# include <stdio.h>
+# include <stdlib.h>
+# include <stdarg.h>
+# include <unistd.h>
+# include <string.h>
+# include <time.h>
+# include <ctype.h>
+# include <signal.h>
+# include <sys/param.h>
+# include <sys/sysctl.h>
+# include <sys/wait.h>
+# include <sys/stat.h>
+# include <sys/ioctl.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/time.h>
+# include <netinet/in.h>
+# include <net/if.h>
+# include <net/if_media.h>
+# include <net/if_mib.h>
+# include <arpa/inet.h>
+# include <net/ppp_defs.h>
+# include <net/if_ppp.h>
+#elif __NetBSD__ /* N E T B S D */
+# include <stdio.h>
+# include <sys/param.h>
+# include <sys/sysctl.h>
+# include <stdlib.h>
+# include <stdarg.h>
+# include <unistd.h>
+# include <string.h>
+# include <time.h>
+# include <ctype.h>
+# include <signal.h>
+# include <sys/wait.h>
+# include <sys/stat.h>
+# include <sys/ioctl.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/time.h>
+# include <netinet/in.h>
+# include <net/if.h>
+# include <net/if_media.h>
+# include <net/route.h>
+# include <net/if_dl.h>
+# include <arpa/inet.h>
+# include <net/ppp_defs.h>
+# include <net/if_ppp.h>
+# include <net/if.h>
+#elif __OpenBSD__ || __MicroBSD__ /* O P E N B S D */
+# include <stdio.h>
+# include <sys/param.h>
+# include <sys/sysctl.h>
+# include <stdlib.h>
+# include <stdarg.h>
+# include <unistd.h>
+# include <string.h>
+# include <time.h>
+# include <ctype.h>
+# include <signal.h>
+# include <sys/wait.h>
+# include <sys/stat.h>
+# include <sys/ioctl.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/time.h>
+# include <netinet/in.h>
+# include <net/if.h>
+# include <net/if_media.h>
+# include <net/if_dl.h>
+# include <net/route.h>
+# include <arpa/inet.h>
+# include <net/ppp_defs.h>
+# include <net/if_ppp.h>
+#elif __linux__ /* L I N U X */
+# include <stdio.h>
+# include <sys/param.h>
+# include <sys/sysctl.h>
+# include <stdlib.h>
+# include <stdarg.h>
+# include <unistd.h>
+# include <string.h>
+# include <time.h>
+# include <ctype.h>
+# include <signal.h>
+# include <sys/wait.h>
+# include <sys/stat.h>
+# include <sys/ioctl.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/time.h>
+# include <netinet/in.h>
+# include <net/if.h>
+# include <arpa/inet.h>
+# include <net/ppp_defs.h>
+# include <net/if_ppp.h>
+#elif __Solaris__ /* S O L A R I S */
+# include <stdio.h>
+# define _WIDEC_H
+# include <sys/param.h>
+# include <stdlib.h>
+# include <stdarg.h>
+# include <unistd.h>
+# include <string.h>
+# include <time.h>
+# include <ctype.h>
+# include <signal.h>
+# include <sys/wait.h>
+# include <sys/stat.h>
+# include <sys/ioctl.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/time.h>
+# include <netinet/in.h>
+# include <net/if.h>
+# include <stropts.h>
+# include <sys/socket.h>
+# include <sys/sockio.h>
+# include <net/if.h>
+# include <kstat.h>
+# include <net/if.h>
+# include <sys/sockio.h>
+# include <arpa/inet.h>
+# include <net/if.h>
+#else
+# error "OS not supported"
+#endif
+
+#endif
diff --git a/include/slurm.h b/include/slurm.h
new file mode 100644
index 0000000..3e62084
--- /dev/null
+++ b/include/slurm.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * slurm.h - structs known from slurm and used in src/
+ *
+ ******************************************************************************
+ * This file is from Wormulon. Id: slurm.h,v 1.2 2003/07/16 16:52:56 hscholz
Exp
+ *****************************************************************************/
+
+#ifndef _SLURM_H_
+#define _SLURM_H_
+
+typedef struct IfData{
+ char if_name[10]; /* The device name given as start parameter*/
+ int if_speed; /* The Interface speed */
+ char if_speedstring[12]; /* the measuring unit like Mbit, kbit */
+ int if_id; /* The ID which the interface inside the OS has */
+ int if_amount; /* The amount of all interfaces available */
+ int if_valid; /* 1 = selected interface exists
+ * 0 = interfaces does not exists */
+} IfData;
+
+
+/* This structure stays the INFO variables */
+typedef struct DataStats {
+ unsigned long rx_packets;
+ unsigned long rx_errors;
+ int rx_over;
+ unsigned long tx_packets;
+ unsigned long tx_errors;
+ int tx_over;
+ double rx_bytes;
+ double tx_bytes;
+ double rx_bytes_comp;
+ double tx_bytes_comp;
+ double rx_packets_led;
+ double tx_packets_led;
+ unsigned long connect_time;
+ unsigned long current_time;
+ float top_speed;
+ int online_days;
+ int online_hour;
+ int online_min;
+ int online_sec;
+ unsigned long rx_packets_off;
+ unsigned long rx_errors_off;
+ int rx_over_off;
+ unsigned long tx_packets_off;
+ unsigned long tx_errors_off;
+ int tx_over_off;
+ double rx_bytes_off;
+ double tx_bytes_off;
+ double rx_bytes_comp_off;
+ double tx_bytes_comp_off;
+} DataStats;
+
+#endif
diff --git a/include/wormulon.h b/include/wormulon.h
new file mode 100644
index 0000000..21da346
--- /dev/null
+++ b/include/wormulon.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+ *
+ * wormulon.h
+ *
+ * application specific defines. You should never need to tune anything here
+ *
+ *****************************************************************************/
+
+#ifndef _WORMULON_H
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifdef __linux__
+#define PATH_NET_DEV "/proc/net/dev"
+#endif
+
+/* define possible options */
+#define OPT_NONE 0x0000
+#define OPT_MRTG 0x0001
+#define OPT_FULLMRTG 0x0002
+#ifdef CUSTOM_MODE
+#define OPT_CUSTOM 0x0004
+#endif
+
+#endif
diff --git a/include/wormulon/freebsd.c b/include/wormulon/freebsd.c
new file mode 100644
index 0000000..2174ede
--- /dev/null
+++ b/include/wormulon/freebsd.c
@@ -0,0 +1,152 @@
+/*****************************************************************************
+ *
+ * init_osspecific()
+ *
+ * Init function
+ *
+ ****************************************************************************/
+
+void init_osspecific(netdata* data)
+{
+ data->watchif = -1;
+
+#ifdef DEBUG
+ fprintf( stderr, "The netload plugin was initialized for FreeBSD.\n" );
+#endif
+}
+
+
+/*****************************************************************************
+ *
+ * checkinterface()
+ *
+ * check if a given interface exists and is up.
+ * return TRUE if it does and FALSE if not
+ *
+ ****************************************************************************/
+
+int checkinterface(netdata* data)
+{
+ int validinterface = FALSE;
+
+ int i, num_iface;
+ size_t len;
+ int name[6];
+ struct ifmibdata ifmd;
+
+#ifdef DEBUG
+ fprintf( stderr, "Checking the interface '%s' now ...\n",
data->ifdata.if_name );
+#endif
+
+
+ len = sizeof(num_iface);
+ sysctlbyname("net.link.generic.system.ifcount", &num_iface, &len, NULL, 0);
+ for (i=1; i <= num_iface; i++)
+ {
+ name[0] = CTL_NET;
+ name[1] = PF_LINK;
+ name[2] = NETLINK_GENERIC;
+ name[3] = IFMIB_IFDATA;
+ name[4] = i;
+ name[5] = IFDATA_GENERAL;
+
+ len = sizeof(ifmd);
+ sysctl(name, 6, &ifmd, &len, NULL, 0);
+ if (strcmp(ifmd.ifmd_name, (char *)data->ifdata.if_name) == 0)
+ {
+ /*
+ * now we have an interface and just have to see if it's up
+ * in case we just want to debug media types we disable
+ * IFF_UP flags
+ */
+#ifndef MEDIADEBUG
+ if (ifmd.ifmd_flags & IFF_UP)
+#endif
+ validinterface = TRUE;
+ break; /* in any case we can stop searching here */
+ }
+ }
+ return validinterface;
+}
+
+/******************************************************************************
+ *
+ * get_stat()
+ *
+ * use sysctl() to read the statistics and fill statistics struct
+ *
+ ****************************************************************************/
+
+int get_stat(netdata* data)
+{
+ /*
+ * use sysctl() to get the right interface number if !dev_opened
+ * then read the data directly from the ifmd_data struct
+ */
+
+ int i, num_iface;
+ size_t len;
+ int name[6];
+ struct ifmibdata ifmd;
+ unsigned long rx_o, tx_o;
+
+ if (!data->dev_opened)
+ {
+ len = sizeof(num_iface);
+ sysctlbyname("net.link.generic.system.ifcount", &num_iface, &len,
+ NULL, 0);
+ for (i=1; i <= num_iface; i++)
+ {
+ name[0] = CTL_NET;
+ name[1] = PF_LINK;
+ name[2] = NETLINK_GENERIC;
+ name[3] = IFMIB_IFDATA;
+ name[4] = i;
+ name[5] = IFDATA_GENERAL;
+
+ len = sizeof(ifmd);
+ sysctl(name, 6, &ifmd, &len, NULL, 0);
+ if (strcmp(ifmd.ifmd_name, (char *)data->ifdata.if_name) == 0)
+ {
+ /* got the right interface */
+#ifdef DEBUG
+ fprintf( stderr, "Got the right interface.\n");
+#endif
+ data->watchif = i;
+ data->dev_opened++;
+ }
+ else
+ {
+#ifdef DEBUG
+ fprintf( stderr, "Got NOT the right interface.\n");
+#endif
+ }
+ }
+ }
+ /* in any case read the struct and record statistics */
+ name[0] = CTL_NET;
+ name[1] = PF_LINK;
+ name[2] = NETLINK_GENERIC;
+ name[3] = IFMIB_IFDATA;
+ name[4] = data->watchif;
+ name[5] = IFDATA_GENERAL;
+
+ len = sizeof(ifmd);
+ sysctl(name, 6, &ifmd, &len, NULL, 0);
+
+ rx_o = data->stats.rx_bytes; tx_o = data->stats.tx_bytes;
+
+ data->stats.tx_packets = ifmd.ifmd_data.ifi_opackets;
+ data->stats.rx_packets = ifmd.ifmd_data.ifi_ipackets;
+ data->stats.rx_bytes = ifmd.ifmd_data.ifi_ibytes;
+ data->stats.tx_bytes = ifmd.ifmd_data.ifi_obytes;
+ data->stats.rx_errors = ifmd.ifmd_data.ifi_ierrors;
+ data->stats.tx_errors = ifmd.ifmd_data.ifi_oerrors;
+
+ if (rx_o > data->stats.rx_bytes)
+ data->stats.rx_over++;
+ if (tx_o > data->stats.tx_bytes)
+ data->stats.tx_over++;
+
+ return (0);
+}
diff --git a/include/wormulon/freebsd.h b/include/wormulon/freebsd.h
new file mode 100644
index 0000000..84822f9
--- /dev/null
+++ b/include/wormulon/freebsd.h
@@ -0,0 +1,11 @@
+
+#ifndef FREEBSD_H
+#define FREEBSD_H
+
+#include "../net.h"
+
+void init_osspecific(netdata* data);
+int checkinterface(netdata* data);
+int get_stat(netdata* data);
+
+#endif
diff --git a/include/wormulon/hpux.c b/include/wormulon/hpux.c
new file mode 100644
index 0000000..ebe5c4e
--- /dev/null
+++ b/include/wormulon/hpux.c
@@ -0,0 +1,197 @@
+#include <netio.h>
+#define WAIT_PCKS_COUNTER 15
+
+/*****************************************************************************
+ *
+ * init_osspecific()
+ *
+ * Init function
+ *
+ ****************************************************************************/
+
+void init_osspecific(netdata* data)
+{
+ wait_pcks_counter = WAIT_PCKS_COUNTER+1;
+
+#ifdef DEBUG
+ fprintf( stderr, "The netload plugin was initialized for HP_UX.\n" );
+#endif
+
+}
+
+
+
+/*****************************************************************************
+ *
+ * _countinterfaces()
+ *
+ * count all network interfaces in the system. This function is intended to
+ * use it only in hpux.c
+ *
+ ****************************************************************************/
+
+int _countinterfaces(void)
+{
+ int val, num_iface=-1, sd;
+ if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return (-1);
+
+ if (ioctl(sd, SIOCGIFNUM, &val) != -1)
+ num_iface = val;
+ close(sd);
+
+ return num_iface;
+}
+
+/*****************************************************************************
+ *
+ * _getifdata()
+ *
+ * get the Interface-ID, the Interface-Speed, and over all, check if the
+ * given interface really exists. This function is intended to use it only in
+ * hpux.c
+ *
+ ****************************************************************************/
+
+void _getifdata()
+{
+ int buffer, fd, val, ret = -1;
+ unsigned int len, i;
+ char tmpinterfacestring[sizeof(data->ifdata.if_name)+1],*strstrmatch;
+ struct nmparms params;
+ mib_ifEntry * if_buf;
+
+
+ /*
+ * The interface description is more then the pure devicename.
+ * Let's do some formating to allow a propper pattern matching
+ */
+ strcpy(tmpinterfacestring,data->ifdata.if_name);
+ strcat(tmpinterfacestring," ");
+
+ for (i=0; i <= data->ifdata.if_amount; i++)
+ {
+ if ((fd = open_mib("/dev/lan", O_RDWR, i, 0)) >= 0)
+ {
+ if ((if_buf = (mib_ifEntry *) malloc (sizeof(mib_ifEntry))) != 0) {
+ params.objid = ID_ifEntry;
+ params.buffer = if_buf;
+ len = sizeof(mib_ifEntry);
+ params.len = &len;
+ if_buf->ifIndex = i+1;
+ if ((ret = get_mib_info(fd, &params)) == 0) {
+ /*
+ * The interface given by the user must start at the
+ * beginning of if_buf->ifDescr. If that's the case,
+ * strstrmatch is equal to if_buf->ifDescr. If not,
+ * strstrmatch might be a subset of if_buf->ifDescr,
+ * or NULL
+ */
+ strstrmatch = strstr(if_buf->ifDescr, (char
*)tmpinterfacestring);
+ if ( strstrmatch && (strcmp(strstrmatch,if_buf->ifDescr)==
0))
+ {
+ data->ifdata.if_valid = 1;
+ data->ifdata.if_id = i+1;
+ break;
+ }
+ }
+ }
+ }
+ free(if_buf);
+ close_mib(fd);
+ }
+ return;
+}
+
+/*****************************************************************************
+ *
+ * checkinterface()
+ *
+ * check if a given interface exists, return 1 if it does and 0 if not (This
+ * function is a wrapper function for _countinterfaces && _getifdata.)
+ *
+ ****************************************************************************/
+int checkinterface(netdata* data)
+{
+ /* == 0 no network interfaces, -1 sth. went wrong */
+ if ((data->ifdata.if_amount =_countinterfaces()) > 0)
+ _getifdata();
+ return data->ifdata.if_valid;
+}
+
+/******************************************************************************
+ *
+ * get_stat()
+ *
+ * stub function for all unsupported operating systems
+ *
+ *****************************************************************************/
+
+int get_stat(netdata* data)
+{
+ int i,fd, ret=-1;
+ unsigned int len;
+ unsigned long rx_o, tx_o;
+ struct nmparms params, params2;
+ mib_ifEntry *if_buf;
+
+ if (data->ifdata.if_valid == 1 && (fd = open_mib("/dev/lan", O_RDWR, 0,
0)) >= 0)
+ {
+ if ((if_buf = (mib_ifEntry *) malloc (sizeof(mib_ifEntry))) != 0)
+ {
+ if_buf->ifIndex = data->ifdata.if_id;
+ params.objid = ID_ifEntry;
+ params.buffer = if_buf;
+ len = (unsigned int) sizeof(mib_ifEntry);
+ params.len = &len;
+ if ((ret = get_mib_info(fd, &params)) == 0)
+ {
+ rx_o = data->stats.rx_bytes; tx_o = data->stats.tx_bytes;
+
+ data->stats.tx_bytes = if_buf->ifOutOctets;
+ data->stats.rx_bytes = if_buf->ifInOctets;
+ data->stats.tx_errors = if_buf->ifOutErrors;
+ data->stats.rx_errors = if_buf->ifInErrors;
+
+ if (rx_o > data->stats.rx_bytes)
+ data->stats.rx_over++;
+ if (tx_o > data->stats.tx_bytes)
+ data->stats.tx_over++;
+ }
+ }
+ free(if_buf);
+
+ /*
+ * Getting the tx/rx packets every run often hurts to much performance
+ * With WAIT_PCKS_COUNTER=15 i save on my system 43% cpu usage.instead
of
+ * WAIT_PCKS_COUNTER=0
+ */
+ if( data->wait_pcks_counter > WAIT_PCKS_COUNTER )
+ {
+ if ((if_ptr = (nmapi_logstat *) malloc(sizeof(nmapi_logstat) *
data->ifdata.if_amount)) != 0 )
+ {
+ len = (unsigned int) data->ifdata.if_amount
*sizeof(nmapi_logstat);
+ if ((ret = get_logical_stat(if_ptr, &len)) == 0)
+ {
+ for (i=0; i <= data->ifdata.if_amount; i++)
+ {
+ if(if_ptr[i].ifindex == data->ifdata.if_id)
+ {
+ data->stats.tx_packets = if_ptr[i].out_packets;
+ data->stats.rx_packets = if_ptr[i].in_packets;
+ }
+ }
+ }
+ }
+ free(if_ptr);
+ data->wait_pcks_counter = 0;
+ }
+ else
+ {
+ data->wait_pcks_counter++;
+ }
+ }
+ close_mib(fd);
+
+ return(0);
+}
diff --git a/include/wormulon/hpux.h b/include/wormulon/hpux.h
new file mode 100644
index 0000000..f10f403
--- /dev/null
+++ b/include/wormulon/hpux.h
@@ -0,0 +1,10 @@
+#ifndef HPUX_H
+#define HPUX_H
+
+#include "../net.h"
+
+void init_osspecific(netdata* data);
+int checkinterface(netdata* data);
+int get_stat(netdata* data);
+
+#endif /* HPUX_H */
diff --git a/include/wormulon/if_media.c b/include/wormulon/if_media.c
new file mode 100644
index 0000000..331cc49
--- /dev/null
+++ b/include/wormulon/if_media.c
@@ -0,0 +1,322 @@
+/******************************************************************************
+ *
+ * src/if_media.h - part of slurm
+ *
+ * this file handles basic network information functions for all
+ * operating systems.
+ *
+ *****************************************************************************/
+
+#if defined (__FreeBSD__) || (__OpenBSD__) || (__NetBSD__) || (__MicroBSD__)
|| (__APPLE__)
+
+#define MEDIA_H_SUPPORTED
+#endif
+
+/******************************************************************************
+ *
+ * get_if_speed()
+ *
+ * determine current interface speed, needs interface name as argument
+ * return the interface speed as an integer. unit: kbit/s
+ * in case of error return ERR_IFACE_NO_SPEED
+ *
+ * tested/supported operating systems:
+ *
+ * - FreeBSD
+ * - OpenBSD
+ * - NetBSD
+ * - MicroBSD (99% OpenBSD)
+ * - Mac OS X
+ *
+ *****************************************************************************/
+
+#ifdef MEDIA_H_SUPPORTED
+int get_if_speed (char *ifstring)
+{
+ int speed=ERR_IFACE_NO_SPEED;
+ int s; /* socket */
+ struct ifmediareq ifmr;
+ int *media_list;
+ int type, physical;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == NULL)
+ {
+ fprintf(stderr, "cannot create socket!\n");
+ return ERR_IFACE_NO_SPEED;
+ }
+
+ memset(&ifmr, 0, sizeof(ifmr));
+ strncpy(ifmr.ifm_name, (char *)ifstring, sizeof(ifmr.ifm_name));
+
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
+ {
+ fprintf(stderr, "interface does not support SIOCGIFMEDIA ioctl()\n");
+ return ERR_IFACE_NO_SPEED;
+ }
+
+ if (ifmr.ifm_count == 0)
+ {
+ fprintf(stderr, "%s: no media types?\n", (char *)ifstring);
+ return ERR_IFACE_NO_SPEED;
+ }
+
+ media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
+ if (media_list == NULL)
+ fprintf(stderr, "malloc() error in if_media.c\n");
+ ifmr.ifm_ulist = media_list;
+
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
+ {
+ fprintf(stderr, "ioctl(SIOCGIFMEDIA) failed\n");
+ return -1;
+ }
+
+ /*
+ * define type and physical
+ *
+ * bits:
+ * 0-4 Media variant
+ * 5-7 Media type
+ *
+ */
+
+ type = ifmr.ifm_active & 0xf0;
+ physical = ifmr.ifm_active & 0x0f;
+
+#ifdef MEDIADEBUG
+ printf(" all: %6d\n", ifmr.ifm_current);
+ printf(" active: %6d\n", ifmr.ifm_active);
+ printf(" status: %6d\n", ifmr.ifm_status);
+ printf(" type: %6d\n", type);
+ printf(" phys: %6d\n", physical);
+ printf("if active: %6d\n", ifmr.ifm_active & IFM_ACTIVE);
+#endif
+
+ /* switch type */
+ switch (type)
+ {
+ /* Ethernet */
+ case IFM_ETHER:
+ switch (physical)
+ {
+#ifdef __FreeBSD__
+#if __FreeBSD__ <= 4
+ case IFM_1000_FX:
+ case IFM_1000_TX:
+#endif
+#endif
+ case IFM_1000_SX:
+ case IFM_1000_LX:
+ case IFM_1000_CX:
+#ifdef IFM_1000_T
+ case IFM_1000_T:
+#endif
+ speed = 1000 * 1000;
+ break;
+ case IFM_100_TX:
+ case IFM_100_FX:
+ case IFM_100_T4:
+ case IFM_100_VG:
+ case IFM_100_T2:
+ speed = 100 * 1000;
+ break;
+ case IFM_10_T:
+ case IFM_10_2:
+ case IFM_10_5:
+ case IFM_10_FL:
+ case IFM_10_STP:
+ speed = 10 * 1000;
+ break;
+#if defined(__OpenBSD__) || (__MicroBSD__) || (__NetBSD__) || (__APPLE__)
+ case IFM_HPNA_1:
+#else
+#if __FreeBSD__ <= 4
+ case IFM_homePNA:
+#endif
+#endif
+ speed = 1 * 1000;
+ break;
+ default:
+ speed = ERR_IFACE_NO_SPEED;
+ break;
+ } /* end switch physical */
+ break;
+ /* FDDI interfaces */
+ /* fpa doesn't seem to support SIOCGIFMEDIA on FreeBSD
+ * so we won't get here but anyway ...
+ */
+ case IFM_FDDI:
+ switch (physical)
+ {
+ case IFM_FDDI_SMF:
+ case IFM_FDDI_MMF:
+ case IFM_FDDI_UTP:
+ speed = 100 * 1000;
+ break;
+ default:
+ speed = ERR_IFACE_NO_SPEED;
+ }
+ break;
+ /* IEEE 802.11 wireless interfaces */
+ case IFM_IEEE80211:
+ switch (physical)
+ {
+ case IFM_IEEE80211_FH1:
+ case IFM_IEEE80211_DS1:
+ speed = 1 * 1000;
+ break;
+ case IFM_IEEE80211_FH2:
+ case IFM_IEEE80211_DS2:
+ speed = 2 * 1000;
+ break;
+ case IFM_IEEE80211_DS5:
+ speed = (int) 5.5 * 1000;
+ break;
+ case IFM_IEEE80211_DS11:
+ speed = 11 * 1000;
+ break;
+#if __FreeBSD_version >= 460102
+ case IFM_IEEE80211_DS22:
+ speed = 22 * 1000;
+ break;
+#if __FreeBSD_version > 500111
+ case IFM_IEEE80211_OFDM6:
+ speed = 6 * 1000;
+ break;
+ case IFM_IEEE80211_OFDM9:
+ speed = 9 * 1000;
+ break;
+ case IFM_IEEE80211_OFDM12:
+ speed = 12 * 1000;
+ break;
+ case IFM_IEEE80211_OFDM18:
+ speed = 18 * 1000;
+ break;
+ case IFM_IEEE80211_OFDM24:
+ speed = 24 * 1000;
+ break;
+ case IFM_IEEE80211_OFDM36:
+ speed = 36 * 1000;
+ break;
+ case IFM_IEEE80211_OFDM48:
+ speed = 48 * 1000;
+ break;
+ case IFM_IEEE80211_OFDM54:
+ speed = 54 * 1000;
+ break;
+ case IFM_IEEE80211_OFDM72:
+ speed = 72 * 1000;
+ break;
+#else
+ /* these are the old common typos */
+ case IFM_IEEE80211_ODFM6:
+ speed = 6 * 1000;
+ break;
+ case IFM_IEEE80211_ODFM9:
+ speed = 9 * 1000;
+ break;
+ case IFM_IEEE80211_ODFM12:
+ speed = 12 * 1000;
+ break;
+ case IFM_IEEE80211_ODFM18:
+ speed = 18 * 1000;
+ break;
+ case IFM_IEEE80211_ODFM24:
+ speed = 24 * 1000;
+ break;
+ case IFM_IEEE80211_ODFM36:
+ speed = 36 * 1000;
+ break;
+ case IFM_IEEE80211_ODFM48:
+ speed = 48 * 1000;
+ break;
+ case IFM_IEEE80211_ODFM54:
+ speed = 54 * 1000;
+ break;
+ case IFM_IEEE80211_ODFM72:
+ speed = 72 * 1000;
+ break;
+#endif
+#endif
+ default:
+ speed = ERR_IFACE_NO_SPEED;
+ break;
+ }
+ break;
+ default:
+ speed = ERR_IFACE_NO_SPEED;
+ } /* end switch type */
+
+#ifdef MEDIADEBUG
+ printf(" speed: %6d\n", speed);
+#endif
+ return speed;
+}
+#elif __HPUX__
+int get_if_speed(char *ifstring)
+{
+ int speed=ERR_IFACE_NO_SPEED, buffer, fd, val, ret = -1;
+ unsigned int len, i;
+ struct nmparms params;
+ mib_ifEntry * if_buf;
+
+ for (i=0; i <= data->ifdata.if_amount; i++)
+ {
+ if ((fd = open_mib("/dev/lan", O_RDWR, i, 0)) >= 0)
+ {
+ if ((if_buf = (mib_ifEntry *) malloc (sizeof(mib_ifEntry))) != 0)
+ {
+ params.objid = ID_ifEntry;
+ params.buffer = if_buf;
+ len = sizeof(mib_ifEntry);
+ params.len = &len;
+ if_buf->ifIndex = i+1;
+ if ((ret = get_mib_info(fd, &params)) == 0)
+ {
+ if ( i+1 == data->ifdata.if_id)
+ if (if_buf->ifOper == 1)
+ speed = if_buf->ifSpeed/1000;

+ else
+ speed ERR_IFACE_DOWN;
+ }
+ }
+ }
+ free(if_buf);
+ close_mib(fd);
+ }
+ return speed;
+}
+#elif defined (__Solaris__)
+/******************************************************************************
+ *
+ * Solaris interface speed detection
+ *
+ *****************************************************************************/
+int get_if_speed(char *ifstring)
+{
+ int speed=ERR_IFACE_NO_SPEED;
+ kstat_t *ksp;
+ kstat_named_t *knp;
+ kstat_ctl_t *kc;
+
+ if ((kc = kstat_open()) == NULL)
+ return ERR_IFACE_NO_SPEED;
+
+ ksp = kstat_lookup(kc, NULL, -1, ifstring);
+ if (ksp && kstat_read(kc, ksp, NULL) >= 0)
+ {
+ knp = (kstat_named_t *)kstat_data_lookup(ksp, "ifspeed");
+ if (knp)
+ speed = (int) knp->value.ui64 / 1000;
+ }
+ kstat_close(kc);
+
+ return speed;
+}
+#else
+int get_if_speed(char *ifstring)
+{
+ ifstring++; /* ugly hack to prevent compiler warning on Linux */
+ return ERR_IFACE_NO_SPEED;
+}
+#endif
diff --git a/include/wormulon/if_media.h b/include/wormulon/if_media.h
new file mode 100644
index 0000000..8433dbf
--- /dev/null
+++ b/include/wormulon/if_media.h
@@ -0,0 +1,5 @@
+/* interface speed detection errors */
+#define ERR_IFACE_NO_SPEED -1
+#define ERR_IFACE_DOWN -2
+
+int get_if_speed(char *);
diff --git a/include/wormulon/linux.c b/include/wormulon/linux.c
new file mode 100644
index 0000000..2524a24
--- /dev/null
+++ b/include/wormulon/linux.c
@@ -0,0 +1,138 @@
+#include "linux.h"
+
+/*****************************************************************************
+ *
+ * init_osspecific()
+ *
+ * Init function
+ *
+ ****************************************************************************/
+
+void init_osspecific(netdata* data)
+{
+#ifdef DEBUG
+ fprintf( stderr, "The netload plugin was initialized for Linux.\n" );
+#endif
+}
+
+
+/*****************************************************************************
+ *
+ * checkinterface()
+ *
+ * check if a given interface exists and is up.
+ * return TRUE if found, FALSE if not
+ *
+ ****************************************************************************/
+
+int checkinterface(netdata* data)
+{
+ int interfacefound = FALSE;
+ unsigned int i;
+ struct if_nameindex *ifs;
+
+#ifdef DEBUG
+ fprintf( stderr, "Checking the interface '%s' now ...\n",
data->ifdata.if_name );
+#endif
+
+
+ if ((ifs = if_nameindex()) == NULL)
+ return FALSE;
+
+ for (i = 0; ifs[i].if_index; i++)
+ {
+ if (strcmp(ifs[i].if_name, data->ifdata.if_name) == 0)
+ {
+ interfacefound = TRUE;
+ break;
+ }
+ }
+
+ /* free the nameindex structure */
+ if_freenameindex(ifs);
+
+ /* check if the /proc/net/dev exists */
+ if (access(PATH_NET_DEV, R_OK) != 0)
+ {
+ data->errorcode = PROC_DEVICE_NOT_FOUND;
+ return FALSE;
+ }
+
+ return interfacefound;
+}
+
+/******************************************************************************
+ *
+ * get_stat()
+ *
+ * read the network statistics from /proc/net/dev (PATH_NET_DEV)
+ * if the file is not open open it. fseek() to the beginning and parse
+ * each line until we've found the right interface
+ *
+ * returns 0 if successful, 1 in case of error
+ *
+ *****************************************************************************/
+
+int get_stat(netdata* data)
+{
+ /* bwalle: Instead of the original code we open the file each time new. The
+ * performance difference is _very_ minimal. But I don't think that it's a
good
+ * idea to keep the file open for a very long time for _each_ plugin
instance.
+ */
+ char buffer[BUFSIZE];
+ char *ptr;
+ char *devname;
+ int dump;
+ int interfacefound;
+ FILE* proc_net_dev;
+ unsigned long rx_o, tx_o;
+
+ if ((proc_net_dev = fopen(PATH_NET_DEV, "r")) == NULL)
+ {
+ fprintf(stderr, "cannot open %s!\nnot running Linux?\n",
+ PATH_NET_DEV);
+ return 1;
+ }
+
+ /* backup old rx/tx values */
+ rx_o = data->stats.rx_bytes; tx_o = data->stats.tx_bytes;
+
+ /* do not parse the first two lines as they only contain static garbage */
+ fseek(proc_net_dev, 0, SEEK_SET);
+ fgets(buffer, BUFSIZE-1, proc_net_dev);
+ fgets(buffer, BUFSIZE-1, proc_net_dev);
+
+ interfacefound = 0;
+ while (fgets(buffer, BUFSIZE-1, proc_net_dev) != NULL)
+ {
+ /* find the device name and substitute ':' with '\0' */
+ ptr = buffer;
+ while (*ptr == ' ')
+ ptr++;
+ devname = ptr;
+ while (*ptr != ':')
+ ptr++;
+ *ptr = '\0';
+ ptr++;
+ if (!strcmp(devname, (char *) data->ifdata.if_name))
+ {
+ /* read stats and fill struct */
+ sscanf(ptr, "%lg %lu %lu %d %d %d %d %d %lg %lu %lu %d %d %d %d
%d",
+ &(data->stats.rx_bytes), &(data->stats.rx_packets),
&(data->stats.rx_errors),
+ &dump, &dump, &dump, &dump, &dump,
+ &(data->stats.tx_bytes), &(data->stats.tx_packets),
&(data->stats.tx_errors),
+ &dump, &dump, &dump, &dump, &dump);
+ interfacefound = 1;
+ continue; /* break, as we won't get any new information */
+ }
+ }
+ fclose( proc_net_dev );
+ if (interfacefound)
+ {
+ if (rx_o > data->stats.rx_bytes)
+ data->stats.rx_over++;
+ if (tx_o > data->stats.tx_bytes)
+ data->stats.tx_over++;
+ }
+ return (interfacefound == 1)? 0 : 1;
+}
diff --git a/include/wormulon/linux.h b/include/wormulon/linux.h
new file mode 100644
index 0000000..275c6b7
--- /dev/null
+++ b/include/wormulon/linux.h
@@ -0,0 +1,14 @@
+#ifndef LINUX_H
+#define LINUX_H
+
+#include "../net.h"
+
+void init_osspecific(netdata* data);
+int checkinterface(netdata* data);
+int get_stat(netdata* data);
+
+#ifdef __linux__
+#define BUFSIZE 256
+#endif /* _linux_ */
+
+#endif /* LINUX_H */
diff --git a/include/wormulon/macos.c b/include/wormulon/macos.c
new file mode 100644
index 0000000..595d698
--- /dev/null
+++ b/include/wormulon/macos.c
@@ -0,0 +1,171 @@
+/*****************************************************************************
+ *
+ * init_osspecific()
+ *
+ * Init function
+ *
+ ****************************************************************************/
+
+void init_osspecific(netdata* data)
+{
+ data->mib_name1[0] = CTL_NET;
+ data->mib_name1[1] = PF_ROUTE;
+ data->mib_name1[2] = 0;
+ data->mib_name1[3] = 0;
+ data->mib_name1[4] = NET_RT_IFLIST;
+ data->mib_name1[5] = 0;
+
+ data->mib_name2[0] = CTL_NET;
+ data->mib_name2[1] = PF_ROUTE;
+ data->mib_name2[2] = 0;
+ data->mib_name2[3] = 0;
+ data->mib_name2[4] = NET_RT_IFLIST;
+ data->mib_name2[5] = 0;
+
+#ifdef DEBUG
+ fprintf( stderr, "The netload plugin was initialized for NetBSD.\n" );
+#endif
+}
+
+
+/*****************************************************************************
+ *
+ * checkinterface()
+ *
+ * check if a given interface exists, return TRUE if it does and FALSE if not
+ *
+ ****************************************************************************/
+int checkinterface(netdata* data)
+{
+ int validinterface = FALSE;
+ char *lim, *next;
+ struct if_msghdr *ifm, *nextifm;
+ struct sockaddr_dl *sdl;
+ size_t needed;
+ char s[32];
+
+ if (sysctl(data->mib_name1, 6, NULL, &needed, NULL, 0) < 0)
+ return FALSE;
+ if (data->alloc1 < (signed long) needed)
+ {
+ if (data->buf1 != NULL)
+ free (data->buf1);
+ data->buf1 = malloc(needed);
+ if (data->buf1 == NULL)
+ return FALSE;
+ data->alloc1 = needed;
+ }
+
+ if (sysctl(data->mib_name1, 6, data->buf1, &needed, NULL, 0) < 0)
+ return FALSE;
+ lim = data->buf1 + needed;
+ next = data->buf1;
+ while ((next < lim) && (validinterface == 0))
+ {
+ ifm = (struct if_msghdr *)next;
+ if (ifm->ifm_type != RTM_IFINFO)
+ return FALSE;
+ next += ifm->ifm_msglen;
+
+ while (next < lim)
+ {
+ nextifm = (struct if_msghdr *)next;
+ if (nextifm->ifm_type != RTM_NEWADDR)
+ break;
+ next += nextifm->ifm_msglen;
+ }
+
+ if (ifm->ifm_flags & IFF_UP)
+ {
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+ strncpy(s, sdl->sdl_data, sdl->sdl_nlen);
+ s[sdl->sdl_nlen] = '\0';
+ /* search for the right network interface */
+ if (sdl->sdl_family != AF_LINK)
+ continue;
+ if (strcmp(s, data->ifdata.if_name) != 0)
+ continue;
+ else
+ {
+ validinterface = TRUE;
+ break; /* stop searching */
+ }
+ }
+ }
+ return validinterface;
+}
+/******************************************************************************
+ *
+ * get_stat()
+ *
+ * this code is based on gkrellm code (thanks guys!)
+ *
+ ****************************************************************************/
+
+int get_stat(netdata* data)
+{
+ char *lim, *next;
+ struct if_msghdr *ifm, *nextifm;
+ struct sockaddr_dl *sdl;
+ char s[32];
+ size_t needed;
+ unsigned long rx_o, tx_o;
+
+ if (sysctl(data->mib_name2, 6, NULL, &needed, NULL, 0) < 0)
+ return 1;
+ if (data->alloc2 < (signed long) needed)
+ {
+ if (data->buf2 != NULL)
+ free (data->buf2);
+ data->buf2 = malloc(needed);
+ if (data->buf2 == NULL)
+ return 1;
+ data->alloc2 = needed;
+ }
+
+ if (sysctl(data->mib_name2, 6, data->buf2, &needed, NULL, 0) < 0)
+ return 1;
+ lim = data->buf2 + needed;
+ next = data->buf2;
+ while (next < lim)
+ {
+ ifm = (struct if_msghdr *)next;
+ if (ifm->ifm_type != RTM_IFINFO)
+ return 1;
+ next += ifm->ifm_msglen;
+
+ while (next < lim)
+ {
+ nextifm = (struct if_msghdr *)next;
+ if (nextifm->ifm_type != RTM_NEWADDR)
+ break;
+ next += nextifm->ifm_msglen;
+ }
+
+ if (ifm->ifm_flags & IFF_UP)
+ {
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+ strncpy(s, sdl->sdl_data, sdl->sdl_nlen);
+ s[sdl->sdl_nlen] = '\0';
+
+ /* search for the right network interface */
+ if (strcmp(s, data->ifdata.if_name) != 0)
+ continue;
+
+ rx_o = data->stats.rx_bytes; tx_o = data->stats.tx_bytes;
+ /* write stats */
+ data->stats.tx_packets = ifm->ifm_data.ifi_opackets;
+ data->stats.rx_packets = ifm->ifm_data.ifi_ipackets;
+ data->stats.rx_bytes = ifm->ifm_data.ifi_ibytes;
+ data->stats.tx_bytes = ifm->ifm_data.ifi_obytes;
+ data->stats.rx_errors = ifm->ifm_data.ifi_ierrors;
+ data->stats.tx_errors = ifm->ifm_data.ifi_oerrors;
+
+ if (rx_o > data->stats.rx_bytes)
+ data->stats.rx_over++;
+ if (tx_o > data->stats.tx_bytes)
+ data->stats.tx_over++;
+ }
+ }
+ return 0;
+}
diff --git a/include/wormulon/macos.h b/include/wormulon/macos.h
new file mode 100644
index 0000000..8e8e323
--- /dev/null
+++ b/include/wormulon/macos.h
@@ -0,0 +1,10 @@
+#ifndef MACOS_H
+#define MACOS_H
+
+#include "../net.h"
+
+void init_osspecific(netdata* data);
+int checkinterface(netdata* data);
+int get_stat(netdata* data);
+
+#endif /* MACOS_H */
diff --git a/include/wormulon/netbsd.c b/include/wormulon/netbsd.c
new file mode 100644
index 0000000..595d698
--- /dev/null
+++ b/include/wormulon/netbsd.c
@@ -0,0 +1,171 @@
+/*****************************************************************************
+ *
+ * init_osspecific()
+ *
+ * Init function
+ *
+ ****************************************************************************/
+
+void init_osspecific(netdata* data)
+{
+ data->mib_name1[0] = CTL_NET;
+ data->mib_name1[1] = PF_ROUTE;
+ data->mib_name1[2] = 0;
+ data->mib_name1[3] = 0;
+ data->mib_name1[4] = NET_RT_IFLIST;
+ data->mib_name1[5] = 0;
+
+ data->mib_name2[0] = CTL_NET;
+ data->mib_name2[1] = PF_ROUTE;
+ data->mib_name2[2] = 0;
+ data->mib_name2[3] = 0;
+ data->mib_name2[4] = NET_RT_IFLIST;
+ data->mib_name2[5] = 0;
+
+#ifdef DEBUG
+ fprintf( stderr, "The netload plugin was initialized for NetBSD.\n" );
+#endif
+}
+
+
+/*****************************************************************************
+ *
+ * checkinterface()
+ *
+ * check if a given interface exists, return TRUE if it does and FALSE if not
+ *
+ ****************************************************************************/
+int checkinterface(netdata* data)
+{
+ int validinterface = FALSE;
+ char *lim, *next;
+ struct if_msghdr *ifm, *nextifm;
+ struct sockaddr_dl *sdl;
+ size_t needed;
+ char s[32];
+
+ if (sysctl(data->mib_name1, 6, NULL, &needed, NULL, 0) < 0)
+ return FALSE;
+ if (data->alloc1 < (signed long) needed)
+ {
+ if (data->buf1 != NULL)
+ free (data->buf1);
+ data->buf1 = malloc(needed);
+ if (data->buf1 == NULL)
+ return FALSE;
+ data->alloc1 = needed;
+ }
+
+ if (sysctl(data->mib_name1, 6, data->buf1, &needed, NULL, 0) < 0)
+ return FALSE;
+ lim = data->buf1 + needed;
+ next = data->buf1;
+ while ((next < lim) && (validinterface == 0))
+ {
+ ifm = (struct if_msghdr *)next;
+ if (ifm->ifm_type != RTM_IFINFO)
+ return FALSE;
+ next += ifm->ifm_msglen;
+
+ while (next < lim)
+ {
+ nextifm = (struct if_msghdr *)next;
+ if (nextifm->ifm_type != RTM_NEWADDR)
+ break;
+ next += nextifm->ifm_msglen;
+ }
+
+ if (ifm->ifm_flags & IFF_UP)
+ {
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+ strncpy(s, sdl->sdl_data, sdl->sdl_nlen);
+ s[sdl->sdl_nlen] = '\0';
+ /* search for the right network interface */
+ if (sdl->sdl_family != AF_LINK)
+ continue;
+ if (strcmp(s, data->ifdata.if_name) != 0)
+ continue;
+ else
+ {
+ validinterface = TRUE;
+ break; /* stop searching */
+ }
+ }
+ }
+ return validinterface;
+}
+/******************************************************************************
+ *
+ * get_stat()
+ *
+ * this code is based on gkrellm code (thanks guys!)
+ *
+ ****************************************************************************/
+
+int get_stat(netdata* data)
+{
+ char *lim, *next;
+ struct if_msghdr *ifm, *nextifm;
+ struct sockaddr_dl *sdl;
+ char s[32];
+ size_t needed;
+ unsigned long rx_o, tx_o;
+
+ if (sysctl(data->mib_name2, 6, NULL, &needed, NULL, 0) < 0)
+ return 1;
+ if (data->alloc2 < (signed long) needed)
+ {
+ if (data->buf2 != NULL)
+ free (data->buf2);
+ data->buf2 = malloc(needed);
+ if (data->buf2 == NULL)
+ return 1;
+ data->alloc2 = needed;
+ }
+
+ if (sysctl(data->mib_name2, 6, data->buf2, &needed, NULL, 0) < 0)
+ return 1;
+ lim = data->buf2 + needed;
+ next = data->buf2;
+ while (next < lim)
+ {
+ ifm = (struct if_msghdr *)next;
+ if (ifm->ifm_type != RTM_IFINFO)
+ return 1;
+ next += ifm->ifm_msglen;
+
+ while (next < lim)
+ {
+ nextifm = (struct if_msghdr *)next;
+ if (nextifm->ifm_type != RTM_NEWADDR)
+ break;
+ next += nextifm->ifm_msglen;
+ }
+
+ if (ifm->ifm_flags & IFF_UP)
+ {
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+ strncpy(s, sdl->sdl_data, sdl->sdl_nlen);
+ s[sdl->sdl_nlen] = '\0';
+
+ /* search for the right network interface */
+ if (strcmp(s, data->ifdata.if_name) != 0)
+ continue;
+
+ rx_o = data->stats.rx_bytes; tx_o = data->stats.tx_bytes;
+ /* write stats */
+ data->stats.tx_packets = ifm->ifm_data.ifi_opackets;
+ data->stats.rx_packets = ifm->ifm_data.ifi_ipackets;
+ data->stats.rx_bytes = ifm->ifm_data.ifi_ibytes;
+ data->stats.tx_bytes = ifm->ifm_data.ifi_obytes;
+ data->stats.rx_errors = ifm->ifm_data.ifi_ierrors;
+ data->stats.tx_errors = ifm->ifm_data.ifi_oerrors;
+
+ if (rx_o > data->stats.rx_bytes)
+ data->stats.rx_over++;
+ if (tx_o > data->stats.tx_bytes)
+ data->stats.tx_over++;
+ }
+ }
+ return 0;
+}
diff --git a/include/wormulon/netbsd.h b/include/wormulon/netbsd.h
new file mode 100644
index 0000000..87c90d5
--- /dev/null
+++ b/include/wormulon/netbsd.h
@@ -0,0 +1,10 @@
+#ifndef NETBSD_H
+#define NETBSD_H
+
+#include "../net.h"
+
+void init_osspecific(netdata* data);
+int checkinterface(netdata* data);
+int get_stat(netdata* data);
+
+#endif /* NETBSD_H */
diff --git a/include/wormulon/openbsd.c b/include/wormulon/openbsd.c
new file mode 100644
index 0000000..7a79f7b
--- /dev/null
+++ b/include/wormulon/openbsd.c
@@ -0,0 +1,173 @@
+/*****************************************************************************
+ *
+ * init_osspecific()
+ *
+ * Init function
+ *
+ ****************************************************************************/
+
+void init_osspecific(netdata* data)
+{
+ data->mib_name1[0] = CTL_NET;
+ data->mib_name1[1] = PF_ROUTE;
+ data->mib_name1[2] = 0;
+ data->mib_name1[3] = 0;
+ data->mib_name1[4] = NET_RT_IFLIST;
+ data->mib_name1[5] = 0;
+
+ data->mib_name2[0] = CTL_NET;
+ data->mib_name2[1] = PF_ROUTE;
+ data->mib_name2[2] = 0;
+ data->mib_name2[3] = 0;
+ data->mib_name2[4] = NET_RT_IFLIST;
+ data->mib_name2[5] = 0;
+
+#ifdef DEBUG
+ fprintf( stderr, "The netload plugin was initialized for OpenBSD.\n" );
+#endif
+}
+
+/*****************************************************************************
+ *
+ * checkinterface()
+ *
+ * check if a given interface exists, return TRUE if it does and FALSE if not
+ *
+ ****************************************************************************/
+int checkinterface(netdata* data)
+{
+ int validinterface = FALSE;
+ char *lim, *next;
+ struct if_msghdr *ifm, *nextifm;
+ struct sockaddr_dl *sdl;
+ size_t needed;
+ char s[32];
+
+ if (sysctl(data->mib_name1, 6, NULL, &needed, NULL, 0) < 0)
+ return FALSE;
+ if (data->alloc1 < (signed long) needed)
+ {
+ if (data->buf1 != NULL)
+ free (data->buf1);
+ data->buf1 = malloc(needed);
+ if (data->buf1 == NULL)
+ return FALSE;
+ data->alloc1 = needed;
+ }
+
+ if (sysctl(data->mib_name1, 6, data->buf1, &needed, NULL, 0) < 0)
+ return FALSE;
+
+ lim = data->buf1 + needed;
+ next = data->buf1;
+ while ((next < lim) && (validinterface == 0))
+ {
+ ifm = (struct if_msghdr *)next;
+ if (ifm->ifm_type != RTM_IFINFO)
+ return FALSE;
+ next += ifm->ifm_msglen;
+
+ while (next < lim)
+ {
+ nextifm = (struct if_msghdr *)next;
+ if (nextifm->ifm_type != RTM_NEWADDR)
+ break;
+ next += nextifm->ifm_msglen;
+ }
+
+ if (ifm->ifm_flags & IFF_UP)
+ {
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+ strncpy(s, sdl->sdl_data, sdl->sdl_nlen);
+ s[sdl->sdl_nlen] = '\0';
+ /* search for the right network interface */
+ if (sdl->sdl_family != AF_LINK)
+ continue;
+ if (strcmp(s, data->ifdata.if_name) != 0)
+ continue;
+ else
+ {
+ validinterface = TRUE;
+ break; /* stop searching */
+ }
+ }
+ }
+ return validinterface;
+}
+
+/*****************************************************************************
+ *
+ * get_stat()
+ *
+ * this code is based on gkrellm code (thanks guys!)
+ *
+ ****************************************************************************/
+
+int get_stat(netdata* data)
+{
+ char *lim, *next;
+ struct if_msghdr *ifm, *nextifm;
+ struct sockaddr_dl *sdl;
+ char s[32];
+ size_t needed;
+ unsigned long rx_o, tx_o;
+
+ if (sysctl(data->mib_name2, 6, NULL, &needed, NULL, 0) < 0)
+ return 1;
+ if (data->alloc2 < (signed long) needed)
+ {
+ if (data->buf2 != NULL)
+ free (data->buf2);
+ data->buf2 = malloc(needed);
+ if (data->buf2 == NULL)
+ return 1;
+ data->alloc2 = needed;
+ }
+
+ if (sysctl(data->mib_name2, 6, data->buf2, &needed, NULL, 0) < 0)
+ return 1;
+ lim = data->buf2 + needed;
+ next = data->buf2;
+ while (next < lim)
+ {
+ ifm = (struct if_msghdr *)next;
+ if (ifm->ifm_type != RTM_IFINFO)
+ return 1;
+ next += ifm->ifm_msglen;
+
+ while (next < lim)
+ {
+ nextifm = (struct if_msghdr *)next;
+ if (nextifm->ifm_type != RTM_NEWADDR)
+ break;
+ next += nextifm->ifm_msglen;
+ }
+
+ if (ifm->ifm_flags & IFF_UP)
+ {
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+ /* search for the right network interface */
+ if (sdl->sdl_family != AF_LINK)
+ continue;
+ if (strcmp(sdl->sdl_data, data->ifdata.if_name) != 0)
+ continue;
+ strncpy(s, sdl->sdl_data, sdl->sdl_nlen);
+ s[sdl->sdl_nlen] = '\0';
+
+ rx_o = data->stats.rx_bytes; tx_o = data->stats.tx_bytes;
+ /* write stats */
+ data->stats.tx_packets = ifm->ifm_data.ifi_opackets;
+ data->stats.rx_packets = ifm->ifm_data.ifi_ipackets;
+ data->stats.rx_bytes = ifm->ifm_data.ifi_ibytes;
+ data->stats.tx_bytes = ifm->ifm_data.ifi_obytes;
+ data->stats.rx_errors = ifm->ifm_data.ifi_ierrors;
+ data->stats.tx_errors = ifm->ifm_data.ifi_oerrors;
+
+ if (rx_o > data->stats.rx_bytes)
+ data->stats.rx_over++;
+ if (tx_o > data->stats.tx_bytes)
+ data->stats.tx_over++;
+ }
+ }
+ return 0;
+}
diff --git a/include/wormulon/openbsd.h b/include/wormulon/openbsd.h
new file mode 100644
index 0000000..6d9737a
--- /dev/null
+++ b/include/wormulon/openbsd.h
@@ -0,0 +1,10 @@
+#ifndef OPENBSD_H
+#define OPENBSD_H
+
+#include "../net.h"
+
+void init_osspecific(netdata* data);
+int checkinterface(netdata* data);
+int get_stat(netdata* data);
+
+#endif /* OPENBSD_H */
diff --git a/include/wormulon/solaris.c b/include/wormulon/solaris.c
new file mode 100644
index 0000000..7d98d38
--- /dev/null
+++ b/include/wormulon/solaris.c
@@ -0,0 +1,151 @@
+/*****************************************************************************
+ *
+ * init_osspecific()
+ *
+ * Init function
+ *
+ ****************************************************************************/
+
+void init_osspecific(netdata* data)
+{
+ /* nothing */
+
+#ifdef DEBUG
+ fprintf( stderr, "The netload plugin was initialized for Sun Solaris.\n" );
+#endif
+
+}
+
+/*****************************************************************************
+ *
+ * checkinterface()
+ *
+ * check if a given interface exists, return TRUE if it does and FALSE if not
+ *
+ ****************************************************************************/
+
+int checkinterface(netdata* data)
+{
+ int validinterface = FALSE;
+ int sockfd, i, numifs, numifreqs;
+ size_t bufsize;
+ char *buf;
+ struct ifreq ifr, *ifrp;
+ struct ifconf ifc;
+ unsigned long rx_o, tx_o;
+
+ if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ perror("socket");
+ return FALSE;
+ }
+ if (ioctl(sockfd, SIOCGIFNUM, (char *) &numifs) < 0)
+ {
+ perror("SIOCGIFNUM");
+ close(sockfd);
+ return FALSE;
+ }
+ bufsize = ((size_t) numifs) * sizeof(struct ifreq);
+ buf = (char *) malloc(bufsize);
+ if (!buf)
+ {
+ perror("malloc");
+ close(sockfd);
+ return FALSE;
+ }
+
+ ifc.ifc_len = bufsize;
+ ifc.ifc_buf = buf;
+
+ if (ioctl(sockfd, SIOCGIFCONF, (char *) &ifc) < 0)
+ {
+ perror("SIOCGIFCONF");
+ close(sockfd);
+ free(buf);
+ return FALSE;
+ }
+
+ ifrp = ifc.ifc_req;
+ numifreqs = ifc.ifc_len / sizeof(struct ifreq);
+
+ for (i = 0; i < numifreqs; i++, ifrp++)
+ {
+ memset((char *)&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
+ /* do not check for loopback device as it cannot be monitored */
+ if (!strncmp(ifr.ifr_name, "lo", 2))
+ continue;
+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0)
+ {
+ perror("SIOCGIFFLAGS");
+ continue;
+ }
+ if (!strcmp(data->ifdata.if_name, ifr.ifr_name) && (ifr.ifr_flags &
IFF_UP))
+ {
+ validinterface = TRUE;
+ break;
+ }
+ }
+ free(buf);
+ close(sockfd);
+
+ return validinterface;
+}
+
+/*****************************************************************************
+ *
+ * get_stat()
+ *
+ * use the Solaris kstat_*() interface to gather statistics
+ * We have to open/close *kc each time :(
+ *
+ ****************************************************************************/
+
+int get_stat(netdata* data)
+{
+ kstat_t *ksp;
+ kstat_named_t *knp;
+ kstat_ctl_t *kc;
+ unsigned long rx_o, tx_o;
+
+ if ((kc = kstat_open()) == NULL)
+ {
+ perror("kstat_open()");
+ return 1;
+ }
+
+ rx_o = data->stats.rx_bytes; tx_o = data->stats.tx_bytes;
+
+ ksp = kstat_lookup(kc, NULL, -1, data->ifdata.if_name);
+ if (ksp && kstat_read(kc, ksp, NULL) >= 0)
+ {
+ knp = (kstat_named_t *)kstat_data_lookup(ksp, "opackets");
+ if (knp)
+ data->stats.tx_packets = knp->value.ui32;
+ knp = (kstat_named_t *)kstat_data_lookup(ksp, "ipackets");
+ if (knp)
+ data->stats.rx_packets = knp->value.ui32;
+ knp = (kstat_named_t *)kstat_data_lookup(ksp, "obytes");
+ if (knp)
+ data->stats.tx_bytes = knp->value.ui32;
+ knp = (kstat_named_t *)kstat_data_lookup(ksp, "rbytes");
+ if (knp)
+ data->stats.rx_bytes = knp->value.ui32;
+ knp = (kstat_named_t *)kstat_data_lookup(ksp, "oerrors");
+ if (knp)
+ data->stats.tx_errors = knp->value.ui32;
+ knp = (kstat_named_t *)kstat_data_lookup(ksp, "ierrors");
+ if (knp)
+ data->stats.rx_errors = knp->value.ui32;
+ }
+
+ kstat_close(kc);
+
+ /* check for overflows */
+ if (rx_o > data->stats.rx_bytes)
+ data->stats.rx_over++;
+ if (tx_o > data->stats.tx_bytes)
+ data->stats.tx_over++;
+
+ return 0;
+}
diff --git a/include/wormulon/solaris.h b/include/wormulon/solaris.h
new file mode 100644
index 0000000..e113747
--- /dev/null
+++ b/include/wormulon/solaris.h
@@ -0,0 +1,10 @@
+#ifndef SOLARIS_H
+#define SOLARIS_H
+
+#include "../net.h"
+
+void init_osspecific(netdata* data);
+int checkinterface(netdata* data);
+int get_stat(netdata* data);
+
+#endif /* SOLARIS_H */
diff --git a/include/wormulon/unsupported.c b/include/wormulon/unsupported.c
new file mode 100644
index 0000000..0c0be26
--- /dev/null
+++ b/include/wormulon/unsupported.c
@@ -0,0 +1,23 @@
+/******************************************************************************
+ *
+ * get_stat()
+ *
+ * stub function for all unsupported operating systems
+ *
+ *****************************************************************************/
+
+int get_stat(netdata* data)
+{
+ return 0;
+}
+
+void init_osspecific(netdata* data)
+{
+ /* do nothgin */
+}
+
+
+int checkinterface(netdata* data)
+{
+ return 0;
+}
diff --git a/include/wormulon/unsupported.h b/include/wormulon/unsupported.h
new file mode 100644
index 0000000..33d7e95
--- /dev/null
+++ b/include/wormulon/unsupported.h
@@ -0,0 +1,3 @@
+void init_osspecific(netdata* data);
+int checkinterface(netdata* data);
+int get_stat(netdata* data);
diff --git a/src/net.c b/src/net.c
new file mode 100644
index 0000000..e5afd5c
--- /dev/null
+++ b/src/net.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2003,2005,2006 Bernhard Walle <bernhard@xxxxxxxxx>
+ * Copyright 2010 Florian Rivoal <frivoal@xxxxxxxxx>
+ *
-------------------------------------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+ * Ave, Cambridge, MA 02139, USA.
+ *
+ *
-------------------------------------------------------------------------------------------------

+ */
+
+/*
+ * This is just a wrapper between the netload-plugin and the wormulon source.
+ * Wormulon is a small command-line util which displays the netload. You can
find it
+ * at http://raisdorf.net/wormulon. Most sourcecode is taken from wormulon.
+ *
+ * Thanks to Hendrik Scholz. Only his work made it possible to support a large
+ * number of operating systems quickly without a library! Without him only
+ * Linux and FreeBSD (with foreign code from IceWM) would be supported.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* From Wormulon */
+#include "net.h"
+#include "os.h"
+#include "wormulon.h"
+#include "slurm.h" /* slurm structs */
+
+#include <sys/types.h>
+#include <errno.h>
+
+#include "global.h"
+
+#ifdef __HPUX__
+# include "wormulon/hpux.h"
+# include "wormulon/hpux.c"
+#elif __APPLE__
+# include "src/macos.h"
+# include "src/macos.c"
+#elif __FreeBSD__ || __DragonFly__ || __FreeBSD_kernel__
+# include "wormulon/freebsd.h"
+# include "wormulon/freebsd.c"
+#elif __linux__
+# include "wormulon/linux.h"
+# include "wormulon/linux.c"
+#elif __OpenBSD__ || __MicroBSD__
+# include "wormulon/openbsd.h"
+# include "wormulon/openbsd.c"
+#elif __NetBSD__
+# include "wormulon/netbsd.h"
+# include "wormulon/netbsd.c"
+#elif __Solaris__
+# include "wormulon/solaris.h"
+# include "wormulon/solaris.c"
+#else
+/* should not get here */
+# error "OS not supported"
+#endif
+
+
+/*
----------------------------------------------------------------------------------------------
*/
+int init_netload(netdata* data, const char* device)
+{
+ memset( data, 0, sizeof(netdata) );
+
+ if (device == NULL || strlen(device) == 0)
+ {
+ return TRUE;
+ }
+
+ strncpy( data->ifdata.if_name, device, INTERFACE_NAME_LENGTH);
+ data->ifdata.if_name[INTERFACE_NAME_LENGTH] = '\0';
+
+ init_osspecific( data );
+
+ data->ip_address[0] = 0;
+ data->ip_update_count = 0;
+ data->up = FALSE;
+ data->up_update_count = 0;
+
+ if (checkinterface(data) != TRUE)
+ {
+ data->correct_interface = FALSE;
+ return FALSE;
+ }
+
+ /* init in a sane state */
+ get_stat(data);
+ data->backup_in = data->stats.rx_bytes;
+ data->backup_out = data->stats.tx_bytes;
+
+ data->correct_interface = TRUE;
+
+ PRINT_DBG("The netload plugin was initialized for '%s'.", device);
+
+ return TRUE;
+}
+
+
+/*
----------------------------------------------------------------------------------------------
*/
+void get_current_netload(netdata* data, unsigned long *in, unsigned long *out,
unsigned long *tot)
+{
+ struct timeval curr_time;
+ double delta_t;
+
+ if (! data->correct_interface)
+ {
+ if (in != NULL && out != NULL && tot != NULL)
+ {
+ *in = *out = *tot = 0;
+ }
+ }
+
+ gettimeofday(&curr_time, NULL);
+
+ delta_t = (double) ((curr_time.tv_sec - data->prev_time.tv_sec) * 1000000L
+ + (curr_time.tv_usec - data->prev_time.tv_usec))
/ 1000000.0;
+
+ /* update */
+ get_stat(data);
+ if (data->backup_in > data->stats.rx_bytes)
+ {
+ data->cur_in = (int)( data->stats.rx_bytes / delta_t + 0.5);
+ }
+ else
+ {
+ data->cur_in = (int)( (data->stats.rx_bytes - data->backup_in) /
delta_t + 0.5);
+ }
+
+ if (data->backup_out > data->stats.tx_bytes)
+ {
+ data->cur_out = (int)( data->stats.tx_bytes / delta_t + 0.5);
+ }
+ else
+ {
+ data->cur_out = (int)( (data->stats.tx_bytes - data->backup_out) /
delta_t + 0.5);
+ }
+
+ if (in != NULL && out != NULL && tot != NULL)
+ {
+ *in = data->cur_in;
+ *out = data->cur_out;
+ *tot = *in + *out;
+ }
+
+ /* save 'new old' values */
+ data->backup_in = data->stats.rx_bytes;
+ data->backup_out = data->stats.tx_bytes;
+
+ /* do the same with time */
+ data->prev_time.tv_sec = curr_time.tv_sec;
+ data->prev_time.tv_usec = curr_time.tv_usec;
+}
+
+
+/*
----------------------------------------------------------------------------------------------
*/
+char* get_name(netdata* data)
+{
+ return data->ifdata.if_name;
+}
+
+
+/*
----------------------------------------------------------------------------------------------
*/
+int get_interface_up(netdata* data)
+{
+ int sockfd;
+ struct ifreq ifr;
+ struct sockaddr_in *p_sa;
+
+ /* if the update count is non-zero */
+ if (data->up_update_count > 0)
+ {
+ data->up_update_count--;
+ return data->up;
+ }
+
+ /* get the value from the operating system */
+ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ PRINT_DBG("Error in socket: %s", strerror(errno));
+ return FALSE;
+ }
+
+ snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", data->ifdata.if_name);
+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) != 0)
+ {
+ PRINT_DBG("Error in ioctl(sockfd): %s", strerror(errno));
+ close(sockfd);
+ return FALSE;
+ }
+ close(sockfd);
+
+ data->up = ((ifr.ifr_flags & IFF_UP) == IFF_UP) ? TRUE : FALSE;
+ data->up_update_count = UP_UPDATE_INTERVAL;
+
+ return data->up;
+}
+
+
+/*
----------------------------------------------------------------------------------------------
*/
+char* get_ip_address(netdata* data)
+{
+ int sockfd;
+ struct ifreq ifr;
+ struct sockaddr_in *p_sa;
+
+ /* use cached value if possible and if the update count is non-zero */
+ if (data->ip_address && data->ip_update_count > 0)
+ {
+ data->ip_update_count--;
+ return data->ip_address;
+ }
+
+ /* get the value from the operating system */
+ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ PRINT_DBG("Error in socket: %s", strerror(errno));
+ return NULL;
+ }
+
+ snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", data->ifdata.if_name);
+ if (ioctl(sockfd, SIOCGIFADDR, &ifr) != 0)
+ {
+ if (errno != EADDRNOTAVAIL)
+ {
+ PRINT_DBG("Error in ioctl(sockfd): %s", strerror(errno));
+ }
+ close(sockfd);
+ return NULL;
+ }
+ close(sockfd);
+
+ p_sa = (struct sockaddr_in*) &ifr.ifr_addr;
+
+ if (!inet_ntop(AF_INET, &p_sa->sin_addr, data->ip_address,
IP_ADDRESS_LENGTH))
+ {
+ PRINT_DBG("Error in inet_ntop: %s", strerror(errno));
+ return NULL;
+ }
+
+ /* now updated */
+ data->ip_update_count = IP_UPDATE_INTERVAL;
+
+ return data->ip_address;
+}
+
+
+/*
----------------------------------------------------------------------------------------------
*/
+void close_netload(netdata* data)
+{
+ /* We need not code here */
+}
+
diff --git a/src/print_throughput.c b/src/print_throughput.c
new file mode 100644
index 0000000..1b3af46
--- /dev/null
+++ b/src/print_throughput.c
@@ -0,0 +1,54 @@
+// vim:ts=8:expandtab
+#include "i3status.h"
+#include "net.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+void print_throughput(const char* interface, const char *format, netdata*
data) {
+ unsigned long in, out, tot;
+ get_current_netload(data, &in, &out, &tot );
+
+ if (!get_interface_up(data)) {
+ printf("%s", color("color_bad"));
+ (void)printf("%s down", interface);
+ (void)printf("%s", endcolor());
+ return;
+ } else {
+ printf("%s", color("color_good"));
+ }
+
+ const char *walk;
+ for (walk = format; *walk != '\0'; walk++) {
+ if (*walk != '%') {
+ putchar(*walk);
+ continue;
+ }
+ if (BEGINS_WITH(walk+1, "ib")) {
+ (void)printf("%1.2f B/s", (double)in);
+ walk+=2;
+ }
+ if (BEGINS_WITH(walk+1, "ik")) {
+ (void)printf("%1.2f kB/s", in/1024.0);
+ walk+=2;
+ }
+ if (BEGINS_WITH(walk+1, "im")) {
+ (void)printf("%1.2f MB/s", in/1048576.0);
+ walk+=2;
+ }
+ if (BEGINS_WITH(walk+1, "ob")) {
+ (void)printf("%1.2f B/s", (double)out);
+ walk+=2;
+ }
+ if (BEGINS_WITH(walk+1, "ok")) {
+ (void)printf("%1.2f kB/s", out/1024.0);
+ walk+=2;
+ }
+ if (BEGINS_WITH(walk+1, "om")) {
+ (void)printf("%1.2f MB/s", out/1048576.0);
+ walk+=2;
+ }
+ }
+
+ (void)printf("%s", endcolor());
+}
--
1.7.9.3

Other related posts:

  • » [i3] [i3status] [PATCH] Network throughput - Mathias Buhr