Merge branch 'master' into collectd-4
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Sat, 31 Mar 2007 06:12:22 +0000 (08:12 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Sat, 31 Mar 2007 06:12:22 +0000 (08:12 +0200)
Conflicts:

src/iptables.c

96 files changed:
configure.in
contrib/PerlLib/Collectd/Unixsock.pm [new file with mode: 0644]
src/Makefile.am
src/apache.c
src/apcups.c
src/apple_sensors.c
src/battery.c
src/collectd-nagios.c [new file with mode: 0644]
src/collectd.c
src/collectd.conf.in
src/collectd.conf.pod
src/collectd.h
src/collectd.pod
src/common.c
src/common.h
src/configfile.c
src/configfile.h
src/cpu.c
src/cpufreq.c
src/csv.c [new file with mode: 0644]
src/df.c
src/disk.c
src/dns.c
src/email.c
src/entropy.c [new file with mode: 0644]
src/exec.c [new file with mode: 0644]
src/hddtemp.c
src/interface.c [new file with mode: 0644]
src/iptables.c
src/irq.c
src/libconfig/AUTHORS [deleted file]
src/libconfig/LICENSE [deleted file]
src/libconfig/Makefile.am [deleted file]
src/libconfig/README [deleted file]
src/libconfig/TODO [deleted file]
src/libconfig/compat.h [deleted file]
src/libconfig/conf_apache.c [deleted file]
src/libconfig/conf_apache.h [deleted file]
src/libconfig/conf_colon.c [deleted file]
src/libconfig/conf_colon.h [deleted file]
src/libconfig/conf_equal.c [deleted file]
src/libconfig/conf_equal.h [deleted file]
src/libconfig/conf_section.c [deleted file]
src/libconfig/conf_section.h [deleted file]
src/libconfig/conf_space.c [deleted file]
src/libconfig/conf_space.h [deleted file]
src/libconfig/conf_xml.c [deleted file]
src/libconfig/conf_xml.h [deleted file]
src/libconfig/libconfig.c [deleted file]
src/libconfig/libconfig.h [deleted file]
src/libconfig/libconfig_private.h [deleted file]
src/libconfig/test-lc.c [deleted file]
src/libconfig/win32.h [deleted file]
src/liboconfig/AUTHORS [new file with mode: 0644]
src/liboconfig/COPYING [new file with mode: 0644]
src/liboconfig/ChangeLog [new file with mode: 0644]
src/liboconfig/Makefile.am [new file with mode: 0644]
src/liboconfig/aux_types.h [new file with mode: 0644]
src/liboconfig/oconfig.c [new file with mode: 0644]
src/liboconfig/oconfig.h [new file with mode: 0644]
src/liboconfig/parser.y [new file with mode: 0644]
src/liboconfig/scanner.l [new file with mode: 0644]
src/load.c
src/logfile.c [new file with mode: 0644]
src/mbmon.c
src/memory.c
src/multimeter.c
src/mysql.c
src/network.c
src/network.h
src/nfs.c
src/ntpd.c
src/nut.c [new file with mode: 0644]
src/ping.c
src/plugin.c
src/plugin.h
src/processes.c
src/rrdtool.c [new file with mode: 0644]
src/sensors.c
src/serial.c
src/swap.c
src/syslog.c [new file with mode: 0644]
src/tape.c
src/traffic.c [deleted file]
src/unixsock.c [new file with mode: 0644]
src/users.c
src/utils_avltree.c [new file with mode: 0644]
src/utils_avltree.h [new file with mode: 0644]
src/utils_debug.c [deleted file]
src/utils_debug.h [deleted file]
src/utils_ignorelist.c
src/utils_llist.c [new file with mode: 0644]
src/utils_llist.h [new file with mode: 0644]
src/utils_mount.c
src/vserver.c
src/wireless.c

index 4f8bb09..3e85bff 100644 (file)
@@ -24,7 +24,8 @@ AC_SUBST(LTDLINCL)
 AC_SUBST(LIBLTDL)
 AC_LIBTOOL_DLOPEN
 AC_PROG_LIBTOOL
-#AC_PROG_RANLIB
+AC_PROG_LEX
+AC_PROG_YACC
 AC_CONFIG_SUBDIRS(libltdl)
 
 #
@@ -44,7 +45,7 @@ AC_CHECK_HEADERS(assert.h)
 AC_CHECK_HEADERS(sys/types.h)
 AC_CHECK_HEADERS(sys/socket.h)
 AC_CHECK_HEADERS(sys/select.h)
-AC_CHECK_HEADERS(sys/poll.h)
+AC_CHECK_HEADERS(poll.h)
 AC_CHECK_HEADERS(netdb.h)
 AC_CHECK_HEADERS(arpa/inet.h)
 AC_CHECK_HEADERS(sys/resource.h)
@@ -149,6 +150,23 @@ AC_CHECK_HEADERS(netinet/icmp6.h, [], [],
 # include <netinet/ip6.h>
 #endif
 ])
+AC_CHECK_HEADERS(netinet/tcp.h, [], [],
+[#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_NETINET_IN_SYSTM_H
+# include <netinet/in_systm.h>
+#endif
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#if HAVE_NETINET_IP_H
+# include <netinet/ip.h>
+#endif
+])
 AC_CHECK_HEADERS(netinet/udp.h, [], [],
 [#if HAVE_STDINT_H
 # include <stdint.h>
@@ -224,7 +242,7 @@ AC_CHECK_HEADERS(sys/swap.h)
 AC_CHECK_HEADERS(utmp.h)
 AC_CHECK_HEADERS(utmpx.h)
 
-# For traffic plugin
+# For interface plugin
 AC_CHECK_HEADERS(ifaddrs.h)
 AC_CHECK_HEADERS(net/if.h, [], [],
 [
@@ -309,6 +327,10 @@ AC_CHECK_HEADERS(net/if_arp.h)
 AC_CHECK_HEADERS(net/if_ppp.h)
 AC_CHECK_HEADERS(netinet/if_ether.h)
 
+# For the multimeter plugin
+AC_CHECK_HEADERS(termios.h)
+AC_CHECK_HEADERS(sys/ioctl.h)
+
 #
 # Checking for libraries
 #
@@ -363,9 +385,101 @@ AC_CHECK_FUNCS(getutent getutxent)
 AC_CHECK_FUNCS(quotactl)
 AC_CHECK_FUNCS(getgrgid getpwuid)
 
-# For traffic module
+# For interface module
 AC_CHECK_FUNCS(getifaddrs)
 
+# Check for NAN
+nan_type="none"
+if test "x$nan_type" = "xnone"; then
+  AC_CACHE_CHECK([whether NAN is defined by default],
+    [have_nan_default],
+    AC_COMPILE_IFELSE(
+      AC_LANG_PROGRAM(
+      [[
+#include <stdlib.h>
+#include <math.h>
+static float foo = NAN;
+      ]],
+      [[
+       if (isnan (foo))
+        return 0;
+       else
+       return 1;
+      ]]),
+      [have_nan_default="yes"],
+      [have_nan_default="no"]
+    )
+  )
+  if test "x$have_nan_default" = "xyes"
+  then
+   nan_type="default"
+   AC_DEFINE(NAN_STATIC_DEFAULT, 1,
+     [Define if NAN is defined by default and can initialize static variables.])
+  fi
+fi
+if test "x$nan_type" = "xnone"; then
+  AC_CACHE_CHECK([whether NAN is defined by __USE_ISOC99],
+    [have_nan_isoc],
+    AC_COMPILE_IFELSE(
+      AC_LANG_PROGRAM(
+      [[
+#include <stdlib.h>
+#define __USE_ISOC99 1
+#include <math.h>
+static float foo = NAN;
+      ]],
+      [[
+       if (isnan (foo))
+        return 0;
+       else
+       return 1;
+      ]]),
+      [have_nan_isoc="yes"],
+      [have_nan_isoc="no"]
+    )
+  )
+  if test "x$have_nan_isoc" = "xyes"
+  then
+   nan_type="isoc99"
+   AC_DEFINE(NAN_STATIC_ISOC, 1,
+     [Define if NAN is defined by __USE_ISOC99 and can initialize static variables.])
+  fi
+fi
+if test "x$nan_type" = "xnone"; then
+  AC_CACHE_CHECK([whether NAN can be defined by 0/0],
+    [have_nan_zero],
+    AC_RUN_IFELSE(
+      AC_LANG_PROGRAM(
+      [[
+#include <stdlib.h>
+#include <math.h>
+#define NAN (0.0 / 0.0)
+#ifndef isnan
+# define isnan(f) ((f) != (f))
+#endif
+static float foo = NAN;
+      ]],
+      [[
+       if (isnan (foo))
+        return 0;
+       else
+       return 1;
+      ]]),
+      [have_nan_zero="yes"],
+      [have_nan_zero="no"]
+    )
+  )
+  if test "x$have_nan_zero" = "xyes"
+  then
+   nan_type="zero"
+   AC_DEFINE(NAN_ZERO_ZERO, 1,
+     [Define if NAN can be defined as (0.0 / 0.0)])
+  fi
+fi
+if test "x$nan_type" = "xnone"; then
+  AC_MSG_ERROR([Didn't find out how to statically initialize variables to NAN. Sorry.])
+fi
+
 # For mount interface
 #AC_CHECK_FUNCS(getfsent getvfsent)
 
@@ -965,41 +1079,33 @@ else
 fi
 AM_CONDITIONAL(BUILD_WITH_LIBIPTC, test "x$with_libiptc" = "xyes")
 
-# Define `step' and `hearbeat' values..
-declare -i collectd_step=10
-declare -i collectd_heartbeat=25
-AC_ARG_WITH(step, [AS_HELP_STRING([--with-step=SECONDS], [Interval in which plugins are queried.])],
+AC_ARG_WITH(libupsclient, [AS_HELP_STRING([--with-libupsclient@<:@=PREFIX@:>@], [Path to libupsclient.])],
 [
-       if test "x$withval" != "xno" -a "x$withval" != "xyes"
+       if test "x$withval" != "xno" && test "x$withval" != "xyes"
        then
-               declare -i tmp_collectd_step="$withval"
-               if test $tmp_collectd_step -gt 0
-               then
-                       collectd_step=$tmp_collectd_step
-                       let "collectd_heartbeat=$collectd_step*2"
-               fi
+               LDFLAGS="$LDFLAGS -L$withval/lib"
+               CPPFLAGS="$CPPFLAGS -I$withval/include"
+               with_libupsclient="yes"
        fi
-], [])
-AC_ARG_WITH(heartbeat, [AS_HELP_STRING([--with-heartbeat=SECONDS], [Heartbeat of the DS in generated RRD files.])],
+],
 [
-       if test "x$withval" != "xno" -a "x$withval" != "xyes"
-       then
-               declare -i tmp_collectd_heartbeat="$withval"
-               if test $tmp_collectd_heartbeat -gt 0
-               then
-                       collectd_heartbeat=$tmp_collectd_heartbeat
-               fi
-       fi
-], [])
-
-if test $collectd_step -ne 10
+       with_libupsclient="yes"
+])
+if test "x$with_libupsclient" = "xyes"
 then
-       AC_DEFINE_UNQUOTED(COLLECTD_STEP, "$collectd_step", [Interval in which plugins are queried.])
+       AC_CHECK_LIB(upsclient, upscli_connect,
+       [
+               AC_DEFINE(HAVE_LIBUPSCLIENT, 1, [Define to 1 if you have the upsclient library (-lupsclient).])
+       ], [with_libupsclient="no (libupsclient not found)"])
 fi
-if test $collectd_heartbeat -ne 25
+if test "x$with_libupsclient" = "xyes"
 then
-       AC_DEFINE_UNQUOTED(COLLECTD_HEARTBEAT, "$collectd_heartbeat", [Interval in which plugins are queried.])
+       AC_CHECK_HEADERS(upsclient.h,
+       [
+               AC_DEFINE(HAVE_UPSCLIENT_H, 1, [Define to 1 if you have the <upsclient.h> header file.])
+       ], [with_libupsclient="no (upsclient.h not found)"])
 fi
+AM_CONDITIONAL(BUILD_WITH_LIBUPSCLIENT, test "x$with_libupsclient" = "xyes")
 
 # Check for enabled/disabled features
 #
@@ -1079,11 +1185,14 @@ AC_COLLECTD([battery],   [disable], [module], [battery statistics])
 AC_COLLECTD([cpu],       [disable], [module], [cpu usage statistics])
 AC_COLLECTD([cpufreq],   [disable], [module], [system cpu frequency statistics])
 AC_COLLECTD([disk],      [disable], [module], [disk/partition statistics])
+AC_COLLECTD([csv],       [disable], [module], [csv output plugin])
 AC_COLLECTD([df],        [disable], [module], [df statistics])
 AC_COLLECTD([dns],       [disable], [module], [dns statistics])
 AC_COLLECTD([email],     [disable], [module], [email statistics])
-AC_COLLECTD([quota],     [enable],  [module], [quota statistics (experimental)])
+AC_COLLECTD([entropy],   [disable], [module], [entropy statistics])
+AC_COLLECTD([exec],      [disable], [module], [exec of external programs])
 AC_COLLECTD([hddtemp],   [disable], [module], [hdd temperature statistics])
+AC_COLLECTD([interface], [disable], [module], [interface statistics])
 AC_COLLECTD([iptables],  [disable], [module], [IPtables statistics])
 AC_COLLECTD([irq],       [disable], [module], [irq statistics])
 AC_COLLECTD([load],      [disable], [module], [system load statistics])
@@ -1091,20 +1200,24 @@ AC_COLLECTD([mbmon],     [disable], [module], [motherboard monitor statistics])
 AC_COLLECTD([memory],    [disable], [module], [memory statistics])
 AC_COLLECTD([multimeter],[disable], [module], [multimeter statistics])
 AC_COLLECTD([mysql],     [disable], [module], [mysql statistics])
+AC_COLLECTD([network],   [disable], [module], [network functionality])
 AC_COLLECTD([nfs],       [disable], [module], [nfs statistics])
 AC_COLLECTD([ntpd],      [disable], [module], [ntpd statistics])
+AC_COLLECTD([nut],       [disable], [module], [network UPS tools statistics])
 AC_COLLECTD([ping],      [disable], [module], [ping statistics])
 AC_COLLECTD([processes], [disable], [module], [processes statistics])
 AC_COLLECTD([sensors],   [disable], [module], [lm_sensors statistics])
 AC_COLLECTD([serial],    [disable], [module], [serial statistics])
+AC_COLLECTD([logfile],   [disable], [module], [logfile log facility])
 AC_COLLECTD([swap],      [disable], [module], [swap statistics])
+AC_COLLECTD([syslog],    [disable], [module], [syslog log facility])
 AC_COLLECTD([tape],      [disable], [module], [tape statistics])
-AC_COLLECTD([traffic],   [disable], [module], [system traffic statistics])
+AC_COLLECTD([unixsock],  [disable], [module], [UNIX socket plugin])
 AC_COLLECTD([users],     [disable], [module], [user count statistics])
 AC_COLLECTD([vserver],   [disable], [module], [vserver statistics])
 AC_COLLECTD([wireless],  [disable], [module], [wireless link statistics])
 
-AC_OUTPUT(Makefile src/Makefile src/collectd.conf src/libconfig/Makefile src/liboping/Makefile)
+AC_OUTPUT(Makefile src/Makefile src/collectd.conf src/liboconfig/Makefile src/liboping/Makefile)
 
 cat <<EOF;
 
@@ -1125,8 +1238,6 @@ Configuration:
   Features:
     debug . . . . . . . $enable_debug
     daemon mode . . . . $enable_daemon
-    step  . . . . . . . $collectd_step seconds
-    heartbeat . . . . . $collectd_heartbeat seconds
 
   Modules:
     apache  . . . . . . $enable_apache
@@ -1135,27 +1246,35 @@ Configuration:
     battery . . . . . . $enable_battery
     cpu . . . . . . . . $enable_cpu
     cpufreq . . . . . . $enable_cpufreq
+    csv . . . . . . . . $enable_csv
     df  . . . . . . . . $enable_df
     disk  . . . . . . . $enable_disk
     dns . . . . . . . . $enable_dns
     email . . . . . . . $enable_email
+    entropy . . . . . . $enable_entropy
+    exec  . . . . . . . $enable_exec
     hddtemp . . . . . . $enable_hddtemp
-    irq . . . . . . . . $enable_irq
+    interface . . . . . $enable_interface
     iptables  . . . . . $enable_iptables
+    irq . . . . . . . . $enable_irq
     load  . . . . . . . $enable_load
+    logfile . . . . . . $enable_logfile
     mbmon . . . . . . . $enable_mbmon
     memory  . . . . . . $enable_memory
     multimeter  . . . . $enable_multimeter
     mysql . . . . . . . $enable_mysql
+    network . . . . . . $enable_network
     nfs . . . . . . . . $enable_nfs
     ntpd  . . . . . . . $enable_ntpd
+    nut . . . . . . . . $enable_nut
     ping  . . . . . . . $enable_ping
     processes . . . . . $enable_processes
     sensors . . . . . . $enable_sensors
     serial  . . . . . . $enable_serial
     swap  . . . . . . . $enable_swap
+    syslog  . . . . . . $enable_syslog
     tape  . . . . . . . $enable_tape
-    traffic . . . . . . $enable_traffic
+    unixsock  . . . . . $enable_unixsock
     users . . . . . . . $enable_users
     vserver . . . . . . $enable_vserver
     wireless  . . . . . $enable_wireless
diff --git a/contrib/PerlLib/Collectd/Unixsock.pm b/contrib/PerlLib/Collectd/Unixsock.pm
new file mode 100644 (file)
index 0000000..7afbe9d
--- /dev/null
@@ -0,0 +1,153 @@
+package Collectd::Unixsock;
+
+use strict;
+use warnings;
+
+use Carp (qw(cluck confess));
+use IO::Socket::UNIX;
+use Regexp::Common (qw(number));
+
+return (1);
+
+sub _create_socket
+{
+       my $path = shift;
+       my $sock = IO::Socket::UNIX->new (Type => SOCK_STREAM, Peer => $path);
+       if (!$sock)
+       {
+               cluck ("Cannot open UNIX-socket $path: $!");
+               return;
+       }
+       return ($sock);
+} # _create_socket
+
+sub _create_identifier
+{
+       my $args = shift;
+       my $host;
+       my $plugin;
+       my $type;
+
+       if (!$args->{'host'} || !$args->{'plugin'} || !$args->{'type'})
+       {
+               cluck ("Need `host', `plugin' and `type'");
+               return;
+       }
+
+       $host = $args->{'host'};
+       $plugin = $args->{'plugin'};
+       $plugin .= '-' . $args->{'plugin_instance'} if ($args->{'plugin_instance'});
+       $type = $args->{'type'};
+       $type .= '-' . $args->{'type_instance'} if ($args->{'type_instance'});
+
+       return ("$host/$plugin/$type");
+} # _create_identifier
+
+sub new
+{
+       my $pkg = shift;
+       my $path = @_ ? shift : '/var/run/collectd-unixsock';
+       my $sock = _create_socket ($path) or return;
+       my $obj = bless (
+               {
+                       path => $path,
+                       sock => $sock,
+                       error => 'No error'
+               }, $pkg);
+       return ($obj);
+} # new
+
+sub getval
+{
+       my $obj = shift;
+       my %args = @_;
+
+       my $status;
+       my $fh = $obj->{'sock'} or confess;
+       my $msg;
+       my $identifier;
+
+       my $ret = {};
+
+       $identifier = _create_identifier (\%args) or return;
+
+       $msg = "GETVAL $identifier\n";
+       send ($fh, $msg, 0) or confess ("send: $!");
+
+       $msg = undef;
+       recv ($fh, $msg, 1024, 0) or confess ("recv: $!");
+
+       ($status, $msg) = split (' ', $msg, 2);
+       if ($status <= 0)
+       {
+               $obj->{'error'} = $msg;
+               return;
+       }
+
+       for (split (' ', $msg))
+       {
+               my $entry = $_;
+               if ($entry =~ m/^(\w+)=($RE{num}{real})$/)
+               {
+                       $ret->{$1} = 0.0 + $2;
+               }
+       }
+
+       return ($ret);
+} # getval
+
+sub putval
+{
+       my $obj = shift;
+       my %args = @_;
+
+       my $status;
+       my $fh = $obj->{'sock'} or confess;
+       my $msg;
+       my $identifier;
+       my $values;
+
+       $identifier = _create_identifier (\%args) or return;
+       if (!$args{'values'})
+       {
+               cluck ("Need argument `values'");
+               return;
+       }
+
+       if (!ref ($args{'values'}))
+       {
+               $values = $args{'values'};
+       }
+       else
+       {
+               my $time = $args{'time'} ? $args{'time'} : time ();
+               $values = join (':', $time, map { defined ($_) ? $_ : 'U' } (@{$args{'values'}}));
+       }
+
+       $msg = "PUTVAL $identifier $values\n";
+       send ($fh, $msg, 0) or confess ("send: $!");
+       $msg = undef;
+       recv ($fh, $msg, 1024, 0) or confess ("recv: $!");
+
+       ($status, $msg) = split (' ', $msg, 2);
+       return (1) if ($status == 0);
+
+       $obj->{'error'} = $msg;
+       return;
+} # putval
+
+sub destroy
+{
+       my $obj = shift;
+       if ($obj->{'sock'})
+       {
+               close ($obj->{'sock'});
+               delete ($obj->{'sock'});
+       }
+}
+
+sub DESTROY
+{
+       my $obj = shift;
+       $obj->destroy ();
+}
index aee7479..662b49d 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS = libconfig
+SUBDIRS = liboconfig
 if BUILD_WITH_OWN_LIBOPING
 SUBDIRS += liboping
 endif
@@ -8,31 +8,27 @@ AM_CFLAGS = -Wall -Werror
 endif
 
 sbin_PROGRAMS = collectd
+bin_PROGRAMS = collectd-nagios
 
 collectd_SOURCES = collectd.c collectd.h \
-                  utils_debug.c utils_debug.h \
+                  utils_avltree.c utils_avltree.h \
                   utils_mount.c utils_mount.h \
+                  utils_llist.c utils_llist.h \
                   utils_ignorelist.c utils_ignorelist.h \
                   common.c common.h \
-                  network.c network.h \
                   plugin.c plugin.h \
                   configfile.c configfile.h
 collectd_CPPFLAGS = $(LTDLINCL)
+collectd_CPPFLAGS += -DPREFIX='"${prefix}"'
 collectd_CPPFLAGS += -DCONFIGFILE='"${sysconfdir}/${PACKAGE_NAME}.conf"'
 collectd_CPPFLAGS += -DPKGLOCALSTATEDIR='"${localstatedir}/lib/${PACKAGE_NAME}"'
 if BUILD_FEATURE_DAEMON
 collectd_CPPFLAGS += -DPIDFILE='"${localstatedir}/run/${PACKAGE_NAME}.pid"'
 endif
 collectd_CPPFLAGS += -DPLUGINDIR='"${pkglibdir}"'
-if BUILD_FEATURE_DEBUG
-collectd_CPPFLAGS += -DLOGFILE='"${localstatedir}/log/${PACKAGE_NAME}/collectd.log"'
-endif
 
 # Link to these libraries..
 collectd_LDFLAGS = -export-dynamic
-if BUILD_WITH_RRDTOOL
-collectd_LDFLAGS += -lm -lrrd
-endif
 if BUILD_WITH_LIBRT
 collectd_LDFLAGS += -lrt
 endif
@@ -42,6 +38,9 @@ endif
 if BUILD_WITH_LIBRESOLV
 collectd_LDFLAGS += -lresolv
 endif
+if BUILD_WITH_LIBPTHREAD
+collectd_LDFLAGS += -lpthread
+endif
 if BUILD_WITH_LIBKSTAT
 collectd_LDFLAGS += -lkstat
 endif
@@ -60,8 +59,10 @@ collectd_LDFLAGS += -lstatgrab
 endif
 
 
-collectd_LDADD = $(LIBLTDL) libconfig/libconfig.la "-dlopen" self
-collectd_DEPENDENCIES = $(LIBLTDL) libconfig/libconfig.la
+collectd_LDADD = $(LIBLTDL) liboconfig/liboconfig.la "-dlopen" self
+collectd_DEPENDENCIES = $(LIBLTDL) liboconfig/liboconfig.la
+
+collectd_nagios_SOURCES = collectd-nagios.c
 
 pkglib_LTLIBRARIES = 
 
@@ -131,6 +132,14 @@ collectd_LDADD += "-dlopen" cpufreq.la
 collectd_DEPENDENCIES += cpufreq.la
 endif
 
+if BUILD_MODULE_CSV
+pkglib_LTLIBRARIES += csv.la
+csv_la_SOURCES = csv.c
+csv_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" csv.la
+collectd_DEPENDENCIES += csv.la
+endif
+
 if BUILD_MODULE_DF
 pkglib_LTLIBRARIES += df.la
 df_la_SOURCES = df.c
@@ -186,16 +195,24 @@ collectd_LDADD += "-dlopen" email.la
 collectd_DEPENDENCIES += email.la
 endif
 
-#if BUILD_MODULE_QUOTA
-#pkglib_LTLIBRARIES += quota.la
-#quota_la_SOURCES = quota_plugin.c quota_plugin.h
-#quota_la_SOURCES += quota_fs.c quota_fs.h
-#quota_la_SOURCES += quota_mnt.c quota_mnt.h
-#quota_la_LDFLAGS = -module -avoid-version
-#quota_la_CFLAGS = -Werror
-#collectd_LDADD += "-dlopen" quota.la
-#collectd_DEPENDENCIES += quota.la
-#endif
+if BUILD_MODULE_ENTROPY
+pkglib_LTLIBRARIES += entropy.la
+entropy_la_SOURCES = entropy.c
+entropy_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" entropy.la
+collectd_DEPENDENCIES += entropy.la
+endif
+
+if BUILD_MODULE_EXEC
+pkglib_LTLIBRARIES += exec.la
+exec_la_SOURCES = exec.c
+exec_la_LDFLAGS = -module -avoid-version
+if BUILD_WITH_LIBPTHREAD
+exec_la_LDFLAGS += -lpthread
+endif
+collectd_LDADD += "-dlopen" exec.la
+collectd_DEPENDENCIES += exec.la
+endif
 
 if BUILD_MODULE_HDDTEMP
 pkglib_LTLIBRARIES += hddtemp.la
@@ -208,6 +225,29 @@ collectd_LDADD += "-dlopen" hddtemp.la
 collectd_DEPENDENCIES += hddtemp.la
 endif
 
+if BUILD_MODULE_INTERFACE
+pkglib_LTLIBRARIES += interface.la
+interface_la_SOURCES = interface.c
+interface_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" interface.la
+collectd_DEPENDENCIES += interface.la
+if BUILD_WITH_LIBKSTAT
+interface_la_LDFLAGS += -lkstat
+endif
+if BUILD_WITH_LIBDEVINFO
+interface_la_LDFLAGS += -ldevinfo
+endif
+if BUILD_WITH_LIBSTATGRAB
+if BUILD_WITH_LIBKVM
+interface_la_LDFLAGS += -lkvm
+endif
+if BUILD_WITH_LIBDEVSTAT
+interface_la_LDFLAGS += -ldevstat
+endif
+interface_la_LDFLAGS += -lstatgrab
+endif
+endif
+
 if BUILD_MODULE_IPTABLES
 pkglib_LTLIBRARIES += iptables.la
 iptables_la_SOURCES = iptables.c
@@ -244,6 +284,14 @@ load_la_LDFLAGS += -lstatgrab
 endif
 endif
 
+if BUILD_MODULE_LOGFILE
+pkglib_LTLIBRARIES += logfile.la
+logfile_la_SOURCES = logfile.c
+logfile_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" logfile.la
+collectd_DEPENDENCIES += logfile.la
+endif
+
 if BUILD_MODULE_MBMON
 pkglib_LTLIBRARIES += mbmon.la
 mbmon_la_SOURCES = mbmon.c
@@ -297,6 +345,20 @@ collectd_LDADD += "-dlopen" mysql.la
 collectd_DEPENDENCIES += mysql.la
 endif
 
+if BUILD_MODULE_NETWORK
+pkglib_LTLIBRARIES += network.la
+network_la_SOURCES = network.c
+network_la_LDFLAGS = -module -avoid-version
+if BUILD_WITH_LIBSOCKET
+network_la_LDFLAGS += -lsocket
+endif
+if BUILD_WITH_LIBPTHREAD
+network_la_LDFLAGS += -lpthread
+endif
+collectd_LDADD += "-dlopen" network.la
+collectd_DEPENDENCIES += network.la
+endif
+
 if BUILD_MODULE_NFS
 pkglib_LTLIBRARIES += nfs.la
 nfs_la_SOURCES = nfs.c
@@ -316,6 +378,20 @@ collectd_LDADD += "-dlopen" ntpd.la
 collectd_DEPENDENCIES += ntpd.la
 endif
 
+if BUILD_MODULE_NUT
+pkglib_LTLIBRARIES += nut.la
+nut_la_SOURCES = nut.c
+nut_la_LDFLAGS = -module -avoid-version
+if BUILD_WITH_LIBUPSCLIENT
+nut_la_LDFLAGS += -lupsclient
+if BUILD_WITH_LIBPTHREAD
+nut_la_LDFLAGS += -lpthread
+endif
+endif
+collectd_LDADD += "-dlopen" nut.la
+collectd_DEPENDENCIES += nut.la
+endif
+
 if BUILD_MODULE_PING
 pkglib_LTLIBRARIES += ping.la
 ping_la_SOURCES = ping.c
@@ -340,6 +416,14 @@ collectd_LDADD += "-dlopen" processes.la
 collectd_DEPENDENCIES += processes.la
 endif
 
+if BUILD_WITH_RRDTOOL
+pkglib_LTLIBRARIES += rrdtool.la
+rrdtool_la_SOURCES = rrdtool.c
+rrdtool_la_LDFLAGS = -module -avoid-version -lrrd
+collectd_LDADD += "-dlopen" rrdtool.la
+collectd_DEPENDENCIES += rrdtool.la
+endif
+
 if BUILD_MODULE_SENSORS
 pkglib_LTLIBRARIES += sensors.la
 sensors_la_SOURCES = sensors.c
@@ -382,6 +466,14 @@ swap_la_LDFLAGS += -lstatgrab
 endif
 endif
 
+if BUILD_MODULE_SYSLOG
+pkglib_LTLIBRARIES += syslog.la
+syslog_la_SOURCES = syslog.c
+syslog_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" syslog.la
+collectd_DEPENDENCIES += syslog.la
+endif
+
 if BUILD_MODULE_TAPE
 pkglib_LTLIBRARIES += tape.la
 tape_la_SOURCES = tape.c
@@ -396,27 +488,15 @@ collectd_LDADD += "-dlopen" tape.la
 collectd_DEPENDENCIES += tape.la
 endif
 
-if BUILD_MODULE_TRAFFIC
-pkglib_LTLIBRARIES += traffic.la
-traffic_la_SOURCES = traffic.c
-traffic_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" traffic.la
-collectd_DEPENDENCIES += traffic.la
-if BUILD_WITH_LIBKSTAT
-traffic_la_LDFLAGS += -lkstat
-endif
-if BUILD_WITH_LIBDEVINFO
-traffic_la_LDFLAGS += -ldevinfo
-endif
-if BUILD_WITH_LIBSTATGRAB
-if BUILD_WITH_LIBKVM
-traffic_la_LDFLAGS += -lkvm
-endif
-if BUILD_WITH_LIBDEVSTAT
-traffic_la_LDFLAGS += -ldevstat
-endif
-traffic_la_LDFLAGS += -lstatgrab
+if BUILD_MODULE_UNIXSOCK
+pkglib_LTLIBRARIES += unixsock.la
+unixsock_la_SOURCES = unixsock.c
+unixsock_la_LDFLAGS = -module -avoid-version
+if BUILD_WITH_LIBPTHREAD
+unixsock_la_LDFLAGS += -lpthread
 endif
+collectd_LDADD += "-dlopen" unixsock.la
+collectd_DEPENDENCIES += unixsock.la
 endif
 
 if BUILD_MODULE_USERS
index 7c48f08..4184247 100644 (file)
@@ -5,8 +5,7 @@
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -28,8 +27,6 @@
 #include "plugin.h"
 #include "configfile.h"
 
-#define MODULE_NAME "apache"
-
 #if HAVE_LIBCURL && HAVE_CURL_CURL_H
 #  define APACHE_HAVE_READ 1
 #  include <curl/curl.h>
 #  define APACHE_HAVE_READ 0
 #endif
 
-static char *url    = NULL;
-static char *user   = NULL;
-static char *pass   = NULL;
-static char *cacert = NULL;
-
-#if HAVE_LIBCURL
-static CURL *curl = NULL;
-
-#define ABUFFER_SIZE 16384
-static char apache_buffer[ABUFFER_SIZE];
-static int  apache_buffer_len = 0;
-static char apache_curl_error[CURL_ERROR_SIZE];
-#endif /* HAVE_LIBCURL */
-
 /* Limit to 2^27 bytes/s. That's what a gigabit-ethernet link can handle, in
  * theory. */
-static char *bytes_file = "apache/apache_bytes.rrd";
-static char *bytes_ds_def[] =
+static data_source_t apache_bytes_dsrc[1] =
 {
-       "DS:count:COUNTER:"COLLECTD_HEARTBEAT":0:134217728",
-       NULL
+       {"count", DS_TYPE_COUNTER, 0, 134217728.0},
+};
+
+static data_set_t apache_bytes_ds =
+{
+       "apache_bytes", 1, apache_bytes_dsrc
 };
-static int bytes_ds_num = 1;
 
 /* Limit to 2^20 requests/s */
-static char *requests_file = "apache/apache_requests.rrd";
-static char *requests_ds_def[] =
+static data_source_t apache_requests_dsrc[1] =
 {
-       "DS:count:COUNTER:"COLLECTD_HEARTBEAT":0:1048576",
-       NULL
+       {"count", DS_TYPE_COUNTER, 0, 134217728.0},
 };
-static int requests_ds_num = 1;
 
-static char *scoreboard_file = "apache/apache_scoreboard-%s.rrd";
-static char *scoreboard_ds_def[] =
+static data_set_t apache_requests_ds =
 {
-       "DS:count:GAUGE:"COLLECTD_HEARTBEAT":0:U",
-       NULL
+       "apache_requests", 1, apache_requests_dsrc
 };
-static int scoreboard_ds_num = 1;
 
-/* for lighttpd; Limit to 65536 active connections */
-static char *connections_file = "apache/apache_connections.rrd";
-static char *connections_ds_def[] =
+static data_source_t apache_scoreboard_dsrc[1] =
 {
-       "DS:connections:GAUGE:"COLLECTD_HEARTBEAT":0:65536", 
-       NULL
+       {"count", DS_TYPE_GAUGE, 0, 65535.0},
 };
-static int connections_ds_num = 1;
 
-static char *config_keys[] =
+static data_set_t apache_scoreboard_ds =
+{
+       "apache_scoreboard", 1, apache_scoreboard_dsrc
+};
+
+static data_source_t apache_connections_dsrc[1] =
+{
+       {"count", DS_TYPE_GAUGE, 0, 65535.0},
+};
+
+static data_set_t apache_connections_ds =
+{
+       "apache_connections", 1, apache_connections_dsrc
+};
+
+#if APACHE_HAVE_READ
+static char *url    = NULL;
+static char *user   = NULL;
+static char *pass   = NULL;
+static char *cacert = NULL;
+
+static CURL *curl = NULL;
+
+#define ABUFFER_SIZE 16384
+static char apache_buffer[ABUFFER_SIZE];
+static int  apache_buffer_len = 0;
+static char apache_curl_error[CURL_ERROR_SIZE];
+
+static const char *config_keys[] =
 {
        "URL",
        "User",
@@ -97,7 +100,6 @@ static char *config_keys[] =
 };
 static int config_keys_num = 4;
 
-#if HAVE_LIBCURL
 static size_t apache_curl_callback (void *buf, size_t size, size_t nmemb, void *stream)
 {
        size_t len = size * nmemb;
@@ -116,9 +118,8 @@ static size_t apache_curl_callback (void *buf, size_t size, size_t nmemb, void *
 
        return (len);
 }
-#endif /* HAVE_LIBCURL */
 
-static int config_set (char **var, char *value)
+static int config_set (char **var, const char *value)
 {
        if (*var != NULL)
        {
@@ -132,7 +133,7 @@ static int config_set (char **var, char *value)
                return (0);
 }
 
-static int config (char *key, char *value)
+static int config (const char *key, const char *value)
 {
        if (strcasecmp (key, "url") == 0)
                return (config_set (&url, value));
@@ -146,9 +147,8 @@ static int config (char *key, char *value)
                return (-1);
 }
 
-static void init (void)
+static int init (void)
 {
-#if HAVE_LIBCURL
        static char credentials[1024];
 
        if (curl != NULL)
@@ -158,8 +158,8 @@ static void init (void)
 
        if ((curl = curl_easy_init ()) == NULL)
        {
-               syslog (LOG_ERR, "apache: `curl_easy_init' failed.");
-               return;
+               ERROR ("apache: `curl_easy_init' failed.");
+               return (-1);
        }
 
        curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, apache_curl_callback);
@@ -170,8 +170,8 @@ static void init (void)
        {
                if (snprintf (credentials, 1024, "%s:%s", user, pass == NULL ? "" : pass) >= 1024)
                {
-                       syslog (LOG_ERR, "apache: Credentials would have been truncated.");
-                       return;
+                       ERROR ("apache: Credentials would have been truncated.");
+                       return (-1);
                }
 
                curl_easy_setopt (curl, CURLOPT_USERPWD, credentials);
@@ -186,55 +186,56 @@ static void init (void)
        {
                curl_easy_setopt (curl, CURLOPT_CAINFO, cacert);
        }
-#endif /* HAVE_LIBCURL */
-}
 
-static void bytes_write (char *host, char *inst, char *val)
-{
-       rrd_update_file (host, bytes_file, val, bytes_ds_def, bytes_ds_num);
-}
+       return (0);
+} /* int init */
 
-static void requests_write (char *host, char *inst, char *val)
+static void submit_counter (const char *type, const char *type_instance,
+               unsigned long long value)
 {
-       rrd_update_file (host, requests_file, val, requests_ds_def, requests_ds_num);
-}
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-static void scoreboard_write (char *host, char *inst, char *val)
-{
-       char buf[1024];
+       DEBUG ("type = %s; type_instance = %s; value = %llu;",
+                       type, type_instance, value);
 
-       if (snprintf (buf, 1024, scoreboard_file, inst) >= 1024)
-               return;
+       values[0].counter = value;
 
-       rrd_update_file (host, buf, val, scoreboard_ds_def, scoreboard_ds_num);
-}
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "apache");
+       strcpy (vl.plugin_instance, "");
+       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-static void connections_write (char *host, char *inst, char *val)
-{
-       rrd_update_file (host, connections_file, val, connections_ds_def,
-                       connections_ds_num);
-}
+       plugin_dispatch_values (type, &vl);
+} /* void submit_counter */
 
-#if APACHE_HAVE_READ
-static void submit (char *type, char *inst, long long value)
+static void submit_gauge (const char *type, const char *type_instance,
+               double value)
 {
-       char buf[1024];
-       int  status;
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       status = snprintf (buf, 1024, "%u:%lli", (unsigned int) curtime, value);
-       if (status < 0)
-       {
-               syslog (LOG_ERR, "apache: bytes_submit: snprintf failed");
-               return;
-       }
-       else if (status >= 1024)
-       {
-               syslog (LOG_WARNING, "apache: bytes_submit: snprintf was truncated");
-               return;
-       }
+       DEBUG ("type = %s; type_instance = %s; value = %lf;",
+                       type, type_instance, value);
 
-       plugin_submit (type, inst, buf);
-}
+       values[0].gauge = value;
+
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "apache");
+       strcpy (vl.plugin_instance, "");
+
+       if (type_instance != NULL)
+               strncpy (vl.type_instance, type_instance,
+                               sizeof (vl.type_instance));
+
+       plugin_dispatch_values (type, &vl);
+} /* void submit_counter */
 
 static void submit_scoreboard (char *buf)
 {
@@ -274,24 +275,25 @@ static void submit_scoreboard (char *buf)
                else if (buf[i] == 'I') idle_cleanup++;
        }
 
-       submit ("apache_scoreboard", "open"     , open);
-       submit ("apache_scoreboard", "waiting"  , waiting);
-       submit ("apache_scoreboard", "starting" , starting);
-       submit ("apache_scoreboard", "reading"  , reading);
-       submit ("apache_scoreboard", "sending"  , sending);
-       submit ("apache_scoreboard", "keepalive", keepalive);
-       submit ("apache_scoreboard", "dnslookup", dnslookup);
-       submit ("apache_scoreboard", "closing"  , closing);
-       submit ("apache_scoreboard", "logging"  , logging);
-       submit ("apache_scoreboard", "finishing", finishing);
-       submit ("apache_scoreboard", "idle_cleanup", idle_cleanup);
+       submit_gauge ("apache_scoreboard", "open"     , open);
+       submit_gauge ("apache_scoreboard", "waiting"  , waiting);
+       submit_gauge ("apache_scoreboard", "starting" , starting);
+       submit_gauge ("apache_scoreboard", "reading"  , reading);
+       submit_gauge ("apache_scoreboard", "sending"  , sending);
+       submit_gauge ("apache_scoreboard", "keepalive", keepalive);
+       submit_gauge ("apache_scoreboard", "dnslookup", dnslookup);
+       submit_gauge ("apache_scoreboard", "closing"  , closing);
+       submit_gauge ("apache_scoreboard", "logging"  , logging);
+       submit_gauge ("apache_scoreboard", "finishing", finishing);
+       submit_gauge ("apache_scoreboard", "idle_cleanup", idle_cleanup);
 }
 
-static void apache_read (void)
+static int apache_read (void)
 {
        int i;
 
        char *ptr;
+       char *saveptr;
        char *lines[16];
        int   lines_num = 0;
 
@@ -299,19 +301,21 @@ static void apache_read (void)
        int   fields_num;
 
        if (curl == NULL)
-               return;
+               return (-1);
        if (url == NULL)
-               return;
+               return (-1);
 
        apache_buffer_len = 0;
        if (curl_easy_perform (curl) != 0)
        {
-               syslog (LOG_WARNING, "apache: curl_easy_perform failed: %s", apache_curl_error);
-               return;
+               ERROR ("apache: curl_easy_perform failed: %s",
+                               apache_curl_error);
+               return (-1);
        }
 
        ptr = apache_buffer;
-       while ((lines[lines_num] = strtok (ptr, "\n\r")) != NULL)
+       saveptr = NULL;
+       while ((lines[lines_num] = strtok_r (ptr, "\n\r", &saveptr)) != NULL)
        {
                ptr = NULL;
                lines_num++;
@@ -328,34 +332,45 @@ static void apache_read (void)
                {
                        if ((strcmp (fields[0], "Total") == 0)
                                        && (strcmp (fields[1], "Accesses:") == 0))
-                               submit ("apache_requests", NULL, atoll (fields[2]));
+                               submit_counter ("apache_requests", "",
+                                               atoll (fields[2]));
                        else if ((strcmp (fields[0], "Total") == 0)
                                        && (strcmp (fields[1], "kBytes:") == 0))
-                               submit ("apache_bytes", NULL, 1024LL * atoll (fields[2]));
+                               submit_counter ("apache_bytes", "",
+                                               1024LL * atoll (fields[2]));
                }
                else if (fields_num == 2)
                {
                        if (strcmp (fields[0], "Scoreboard:") == 0)
                                submit_scoreboard (fields[1]);
                        else if (strcmp (fields[0], "BusyServers:") == 0)
-                               submit ("apache_connections", NULL, atol (fields[1]));
+                               submit_gauge ("apache_connections", NULL, atol (fields[1]));
                }
        }
 
        apache_buffer_len = 0;
-}
-#else
-#  define apache_read NULL
+
+       return (0);
+} /* int apache_read */
 #endif /* APACHE_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, init, apache_read, NULL);
-       plugin_register ("apache_requests",   NULL, NULL, requests_write);
-       plugin_register ("apache_bytes",      NULL, NULL, bytes_write);
-       plugin_register ("apache_scoreboard", NULL, NULL, scoreboard_write);
-       plugin_register ("apache_connections", NULL, NULL, connections_write);
-       cf_register (MODULE_NAME, config, config_keys, config_keys_num);
-}
+       if (load & MR_DATASETS)
+       {
+               plugin_register_data_set (&apache_bytes_ds);
+               plugin_register_data_set (&apache_requests_ds);
+               plugin_register_data_set (&apache_scoreboard_ds);
+               plugin_register_data_set (&apache_connections_ds);
+       }
 
-#undef MODULE_NAME
+#if APACHE_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_config ("apache", config,
+                               config_keys, config_keys_num);
+               plugin_register_init ("apache", init);
+               plugin_register_read ("apache", apache_read);
+       }
+#endif
+} /* void module_register */
index cd64426..2539c32 100644 (file)
@@ -33,7 +33,6 @@
 #include "common.h"      /* rrd_update_file */
 #include "plugin.h"      /* plugin_register, plugin_submit */
 #include "configfile.h"  /* cf_register */
-#include "utils_debug.h"
 
 #if HAVE_SYS_TYPES_H
 # include <sys/types.h>
 # include <netinet/in.h>
 #endif
 
-#ifndef APCMAIN
-# define APCMAIN 0
-#endif
-
 #define NISPORT 3551
 #define MAXSTRING               256
 #define MODULE_NAME "apcups"
 
 #define APCUPS_DEFAULT_HOST "localhost"
 
+/*
+ * Private data types
+ */
+struct apc_detail_s
+{
+       double linev;
+       double loadpct;
+       double bcharge;
+       double timeleft;
+       double outputv;
+       double itemp;
+       double battv;
+       double linefreq;
+};
+
+/*
+ * Private variables
+ */
 /* Default values for contacting daemon */
-static char *global_host = NULL;
-static int   global_port = NISPORT;
+static char *conf_host = NULL;
+static int   conf_port = NISPORT;
+
+static int global_sockfd = -1;
 
 /* 
  * The following are only if not compiled to test the module with its own main.
 */
-#if !APCMAIN
-static char *bvolt_file_template = "apcups/voltage-%s.rrd";
-static char *bvolt_ds_def[] = 
+static data_source_t data_source_voltage[1] =
 {
-       "DS:voltage:GAUGE:"COLLECTD_HEARTBEAT":0:U",
+       {"value", DS_TYPE_GAUGE, NAN, NAN}
 };
-static int bvolt_ds_num = 1;
 
-static char *load_file_template = "apcups/load_percent.rrd";
-static char *load_ds_def[] = 
+static data_set_t ds_voltage =
 {
-       "DS:percent:GAUGE:"COLLECTD_HEARTBEAT":0:110",
+       "voltage", 1, data_source_voltage
 };
-static int load_ds_num = 1;
 
-static char *charge_file_template = "apcups/charge_percent.rrd";
-static char *charge_ds_def[] = 
+static data_source_t data_source_percent[1] =
 {
-       "DS:percent:GAUGE:"COLLECTD_HEARTBEAT":0:110",
+       {"percent", DS_TYPE_GAUGE, 0, 100.1}
 };
-static int charge_ds_num = 1;
 
-static char *time_file_template = "apcups/timeleft.rrd";
-static char *time_ds_def[] = 
+static data_set_t ds_percent =
 {
-       "DS:timeleft:GAUGE:"COLLECTD_HEARTBEAT":0:100",
+       "percent", 1, data_source_percent
 };
-static int time_ds_num = 1;
 
-static char *temp_file_template = "apcups/temperature.rrd";
-static char *temp_ds_def[] = 
+static data_source_t data_source_timeleft[1] =
 {
-       /* -273.15 is absolute zero */
-       "DS:value:GAUGE:"COLLECTD_HEARTBEAT":-274:U",
+       {"timeleft", DS_TYPE_GAUGE, 0, 100.0}
 };
-static int temp_ds_num = 1;
 
-static char *freq_file_template = "apcups/frequency-%s.rrd";
-static char *freq_ds_def[] = 
+static data_set_t ds_timeleft =
 {
-       "DS:frequency:GAUGE:"COLLECTD_HEARTBEAT":0:U",
+       "timeleft", 1, data_source_timeleft
 };
-static int freq_ds_num = 1;
 
-static char *config_keys[] =
+static data_source_t data_source_temperature[1] =
 {
-       "Host",
-       "Port",
-       NULL
+       {"value", DS_TYPE_GAUGE, -273.15, NAN}
 };
-static int config_keys_num = 2;
 
-#endif /* if APCMAIN */
+static data_set_t ds_temperature =
+{
+       "temperature", 1, data_source_temperature
+};
 
-struct apc_detail_s
+static data_source_t data_source_frequency[1] =
 {
-       double linev;
-       double loadpct;
-       double bcharge;
-       double timeleft;
-       double outputv;
-       double itemp;
-       double battv;
-       double linefreq;
+       {"frequency", DS_TYPE_GAUGE, 0, NAN}
 };
 
-#define BIG_BUF 4096
+static data_set_t ds_frequency =
+{
+       "frequency", 1, data_source_frequency
+};
+
+static const char *config_keys[] =
+{
+       "Host",
+       "Port",
+       NULL
+};
+static int config_keys_num = 2;
 
-#if APCMAIN
 /* Close the network connection */
-static void net_close (int *fd)
+static int apcups_shutdown (void)
 {
        uint16_t packet_size = 0;
 
-       assert (*fd >= 0);
+       if (global_sockfd < 0)
+               return (0);
 
-       DBG ("Gracefully shutting down socket %i.", *fd);
+       DEBUG ("Gracefully shutting down socket %i.", global_sockfd);
 
        /* send EOF sentinel */
-       swrite (*fd, (void *) &packet_size, sizeof (packet_size));
+       swrite (global_sockfd, (void *) &packet_size, sizeof (packet_size));
 
-       close (*fd);
-       *fd = -1;
-}
-#endif /* APCMAIN */
+       close (global_sockfd);
+       global_sockfd = -1;
+
+       return (0);
+} /* int apcups_shutdown */
 
 /*     
  * Open a TCP connection to the UPS network server
@@ -180,7 +186,11 @@ static int net_open (char *host, char *service, int port)
        status = getaddrinfo (host, port_str, &ai_hints, &ai_return);
        if (status != 0)
        {
-               DBG ("getaddrinfo failed: %s", status == EAI_SYSTEM ? strerror (errno) : gai_strerror (status));
+               char errbuf[1024];
+               DEBUG ("getaddrinfo failed: %s",
+                               (status == EAI_SYSTEM)
+                               ? sstrerror (errno, errbuf, sizeof (errbuf))
+                               : gai_strerror (status));
                return (-1);
        }
 
@@ -196,7 +206,7 @@ static int net_open (char *host, char *service, int port)
 
        if (sd < 0)
        {
-               DBG ("Unable to open a socket");
+               DEBUG ("Unable to open a socket");
                freeaddrinfo (ai_return);
                return (-1);
        }
@@ -207,12 +217,14 @@ static int net_open (char *host, char *service, int port)
 
        if (status != 0) /* `connect(2)' failed */
        {
-               DBG ("connect failed: %s", strerror (errno));
+               char errbuf[1024];
+               DEBUG ("connect failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                close (sd);
                return (-1);
        }
 
-       DBG ("Done opening a socket %i", sd);
+       DEBUG ("Done opening a socket %i", sd);
 
        return (sd);
 } /* int net_open (char *host, char *service, int port) */
@@ -240,7 +252,7 @@ static int net_recv (int *sockfd, char *buf, int buflen)
        packet_size = ntohs (packet_size);
        if (packet_size > buflen)
        {
-               DBG ("record length too large");
+               DEBUG ("record length too large");
                return (-2);
        }
 
@@ -297,10 +309,10 @@ static int apc_query_server (char *host, int port,
        int     n;
        char    recvline[1024];
        char   *tokptr;
+       char   *toksaveptr;
        char   *key;
        double  value;
 
-       static int sockfd   = -1;
        static complain_t compl;
 
 #if APCMAIN
@@ -309,9 +321,9 @@ static int apc_query_server (char *host, int port,
 # define PRINT_VALUE(name, val) /**/
 #endif
 
-       if (sockfd < 0)
+       if (global_sockfd < 0)
        {
-               if ((sockfd = net_open (host, NULL, port)) < 0)
+               if ((global_sockfd = net_open (host, NULL, port)) < 0)
                {
                        plugin_complain (LOG_ERR, &compl, "apcups plugin: "
                                        "Connecting to the apcupsd failed.");
@@ -324,13 +336,13 @@ static int apc_query_server (char *host, int port,
                }
        }
 
-       if (net_send (&sockfd, "status", 6) < 0)
+       if (net_send (&global_sockfd, "status", 6) < 0)
        {
-               syslog (LOG_ERR, "apcups plugin: Writing to the socket failed.");
+               ERROR ("apcups plugin: Writing to the socket failed.");
                return (-1);
        }
 
-       while ((n = net_recv (&sockfd, recvline, sizeof (recvline) - 1)) > 0)
+       while ((n = net_recv (&global_sockfd, recvline, sizeof (recvline) - 1)) > 0)
        {
                assert (n < sizeof (recvline));
                recvline[n] = '\0';
@@ -338,11 +350,12 @@ static int apc_query_server (char *host, int port,
                printf ("net_recv = `%s';\n", recvline);
 #endif /* if APCMAIN */
 
-               tokptr = strtok (recvline, " :\t");
+               toksaveptr = NULL;
+               tokptr = strtok_r (recvline, " :\t", &toksaveptr);
                while (tokptr != NULL)
                {
                        key = tokptr;
-                       if ((tokptr = strtok (NULL, " :\t")) == NULL)
+                       if ((tokptr = strtok_r (NULL, " :\t", &toksaveptr)) == NULL)
                                continue;
                        value = atof (tokptr);
 
@@ -365,60 +378,29 @@ static int apc_query_server (char *host, int port,
                        else if (strcmp ("TIMELEFT", key) == 0)
                                apcups_detail->timeleft = value;
 
-                       tokptr = strtok (NULL, ":");
+                       tokptr = strtok_r (NULL, ":", &toksaveptr);
                } /* while (tokptr != NULL) */
        }
        
        if (n < 0)
        {
-               syslog (LOG_WARNING, "apcups plugin: Error reading from socket");
+               WARNING ("apcups plugin: Error reading from socket");
                return (-1);
        }
-#if APCMAIN
-       else
-       {
-               /* close the opened socket */
-               net_close (&sockfd);
-       }
-#endif /* APCMAIN */
 
        return (0);
 }
 
-#if APCMAIN
-/*
- * This is used for testing apcups in a standalone mode.
- * Usefull for debugging.
- */
-int main (int argc, char **argv)
-{
-       /* we are not really going to use this */
-       struct apc_detail_s apcups_detail;
-
-       openlog ("apcups", LOG_PID | LOG_NDELAY | LOG_LOCAL1, LOG_USER);
-
-       if (global_host == NULL || strcmp (global_host, "0.0.0.0") == 0)
-               global_host = "localhost";
-
-       if(apc_query_server (global_host, global_port, &apcups_detail) < 0)
-       {
-               printf("apcups: Failed...\n");
-               return(-1);
-       }
-
-       return 0;
-}
-#else
-static int apcups_config (char *key, char *value)
+static int apcups_config (const char *key, const char *value)
 {
        if (strcasecmp (key, "host") == 0)
        {
-               if (global_host != NULL)
+               if (conf_host != NULL)
                {
-                       free (global_host);
-                       global_host = NULL;
+                       free (conf_host);
+                       conf_host = NULL;
                }
-               if ((global_host = strdup (value)) == NULL)
+               if ((conf_host = strdup (value)) == NULL)
                        return (1);
        }
        else if (strcasecmp (key, "Port") == 0)
@@ -426,10 +408,10 @@ static int apcups_config (char *key, char *value)
                int port_tmp = atoi (value);
                if (port_tmp < 1 || port_tmp > 65535)
                {
-                       syslog (LOG_WARNING, "apcups plugin: Invalid port: %i", port_tmp);
+                       WARNING ("apcups plugin: Invalid port: %i", port_tmp);
                        return (1);
                }
-               global_port = port_tmp;
+               conf_port = port_tmp;
        }
        else
        {
@@ -438,68 +420,22 @@ static int apcups_config (char *key, char *value)
        return (0);
 }
 
-static void apcups_init (void)
-{
-       return;
-}
-
-static void apc_write_voltage (char *host, char *inst, char *val)
+static void apc_submit_generic (char *type, char *type_inst, double value)
 {
-       char file[512];
-       int  status;
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       status = snprintf (file, 512, bvolt_file_template, inst);
-       if ((status < 1) || (status >= 512))
-               return;
+       values[0].gauge = value;
 
-       rrd_update_file (host, file, val, bvolt_ds_def, bvolt_ds_num);
-}
-
-static void apc_write_charge (char *host, char *inst, char *val)
-{
-       rrd_update_file (host, charge_file_template, val, charge_ds_def, charge_ds_num);
-}
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "apcups");
+       strcpy (vl.plugin_instance, "");
+       strncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
 
-static void apc_write_percent (char *host, char *inst, char *val)
-{
-       rrd_update_file (host, load_file_template, val, load_ds_def, load_ds_num);
-}
-
-static void apc_write_timeleft (char *host, char *inst, char *val)
-{
-       rrd_update_file (host, time_file_template, val, time_ds_def, time_ds_num);
-}
-
-static void apc_write_temperature (char *host, char *inst, char *val)
-{
-       rrd_update_file (host, temp_file_template, val, temp_ds_def, temp_ds_num);
-}
-
-static void apc_write_frequency (char *host, char *inst, char *val)
-{
-       char file[512];
-       int  status;
-
-       status = snprintf (file, 512, freq_file_template, inst);
-       if ((status < 1) || (status >= 512))
-               return;
-
-       rrd_update_file (host, file, val, freq_ds_def, freq_ds_num);
-}
-
-static void apc_submit_generic (char *type, char *inst,
-               double value)
-{
-       char buf[512];
-       int  status;
-
-       status = snprintf (buf, 512, "%u:%f",
-                       (unsigned int) curtime, value);
-       if ((status < 1) || (status >= 512))
-               return;
-
-       DBG ("plugin_submit (%s, %s, %s);", type, inst, buf);
-       plugin_submit (type, inst, buf);
+       plugin_dispatch_values (type, &vl);
 }
 
 static void apc_submit (struct apc_detail_s *apcups_detail)
@@ -507,14 +443,14 @@ static void apc_submit (struct apc_detail_s *apcups_detail)
        apc_submit_generic ("apcups_voltage",    "input",   apcups_detail->linev);
        apc_submit_generic ("apcups_voltage",    "output",  apcups_detail->outputv);
        apc_submit_generic ("apcups_voltage",    "battery", apcups_detail->battv);
-       apc_submit_generic ("apcups_charge",     "-",       apcups_detail->bcharge);
-       apc_submit_generic ("apcups_charge_pct", "-",       apcups_detail->loadpct);
-       apc_submit_generic ("apcups_timeleft",   "-",       apcups_detail->timeleft);
-       apc_submit_generic ("apcups_temp",       "-",       apcups_detail->itemp);
+       apc_submit_generic ("apcups_charge",     "",        apcups_detail->bcharge);
+       apc_submit_generic ("apcups_charge_pct", "",        apcups_detail->loadpct);
+       apc_submit_generic ("apcups_timeleft",   "",        apcups_detail->timeleft);
+       apc_submit_generic ("apcups_temp",       "",        apcups_detail->itemp);
        apc_submit_generic ("apcups_frequency",  "input",   apcups_detail->linefreq);
 }
 
-static void apcups_read (void)
+static int apcups_read (void)
 {
        struct apc_detail_s apcups_detail;
        int status;
@@ -528,10 +464,10 @@ static void apcups_read (void)
        apcups_detail.itemp    = -300.0;
        apcups_detail.linefreq =   -1.0;
   
-       status = apc_query_server (global_host == NULL
+       status = apc_query_server (conf_host == NULL
                        ? APCUPS_DEFAULT_HOST
-                       : global_host,
-                       global_port, &apcups_detail);
+                       : conf_host,
+                       conf_port, &apcups_detail);
  
        /*
         * if we did not connect then do not bother submitting
@@ -539,28 +475,35 @@ static void apcups_read (void)
         */
        if (status != 0)
        {
-               DBG ("apc_query_server (%s, %i) = %i",
-                               global_host == NULL
+               DEBUG ("apc_query_server (%s, %i) = %i",
+                               conf_host == NULL
                                ? APCUPS_DEFAULT_HOST
-                               : global_host,
-                               global_port, status);
-               return;
+                               : conf_host,
+                               conf_port, status);
+               return (-1);
        }
 
        apc_submit (&apcups_detail);
+
+       return (0);
 } /* apcups_read */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, apcups_init, apcups_read, NULL);
-       plugin_register ("apcups_voltage",    NULL, NULL, apc_write_voltage);
-       plugin_register ("apcups_charge",     NULL, NULL, apc_write_charge);
-       plugin_register ("apcups_charge_pct", NULL, NULL, apc_write_percent);
-       plugin_register ("apcups_timeleft",   NULL, NULL, apc_write_timeleft);
-       plugin_register ("apcups_temp",       NULL, NULL, apc_write_temperature);
-       plugin_register ("apcups_frequency",  NULL, NULL, apc_write_frequency);
-       cf_register (MODULE_NAME, apcups_config, config_keys, config_keys_num);
-}
+       if (load & MR_DATASETS)
+       {
+               plugin_register_data_set (&ds_voltage);
+               plugin_register_data_set (&ds_percent);
+               plugin_register_data_set (&ds_timeleft);
+               plugin_register_data_set (&ds_temperature);
+               plugin_register_data_set (&ds_frequency);
+       }
 
-#endif /* if APCMAIN */
-#undef MODULE_NAME
+       if (load & MR_READ)
+       {
+               plugin_register_config ("apcups", apcups_config, config_keys,
+                               config_keys_num);
+               plugin_register_read ("apcups", apcups_read);
+               plugin_register_shutdown ("apcups", apcups_shutdown);
+       }
+} /* void module_register */
index 37bd5c3..6b3cfc5 100644 (file)
@@ -1,11 +1,10 @@
 /**
  * collectd - src/apple_sensors.c
- * Copyright (C) 2006  Florian octo Forster
+ * Copyright (C) 2006,2007  Florian octo Forster
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -23,9 +22,6 @@
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
-#include "utils_debug.h"
-
-#define MODULE_NAME "apple_sensors"
 
 #if HAVE_CTYPE_H
 #  include <ctype.h>
 static mach_port_t io_master_port = MACH_PORT_NULL;
 #endif
 
-static char *temperature_file = "apple_sensors/temperature-%s.rrd";
-static char *fanspeed_file    = "apple_sensors/fanspeed-%s.rrd";
+static data_source_t data_source_fanspeed[1] =
+{
+       {"value", DS_TYPE_GAUGE, 0, NAN}
+};
+
+static data_set_t fanspeed_ds =
+{
+       "fanspeed", 1, data_source_fanspeed
+};
 
-static char *ds_def[] =
+static data_source_t data_source_temperature[1] =
 {
-       "DS:value:GAUGE:"COLLECTD_HEARTBEAT":U:U",
-       NULL
+       {"value", DS_TYPE_GAUGE, -273.15, NAN}
 };
-static int ds_num = 1;
 
-static void as_init (void)
+static data_set_t temperature_ds =
 {
+       "temperature", 1, data_source_temperature
+};
+
 #if IOKIT_HAVE_READ
+static int as_init (void)
+{
        kern_return_t status;
        
        if (io_master_port != MACH_PORT_NULL)
@@ -88,51 +94,38 @@ static void as_init (void)
        status = IOMasterPort (MACH_PORT_NULL, &io_master_port);
        if (status != kIOReturnSuccess)
        {
-               syslog (LOG_ERR, "IOMasterPort failed: %s",
+               ERROR ("IOMasterPort failed: %s",
                                mach_error_string (status));
                io_master_port = MACH_PORT_NULL;
-               return;
+               return (-1);
        }
-#endif /* IOKIT_HAVE_READ */
-
-       return;
-}
-
-static void as_write (char *host, char *inst, char *val, const char *template)
-{
-       char filename[256];
-       int  status;
-
-       status = snprintf (filename, 256, template, inst);
-       if ((status < 1) || (status >= 256))
-               return;
 
-       rrd_update_file (host, filename, val, ds_def, ds_num);
+       return (0);
 }
 
-static void temperature_write (char *host, char *inst, char *val)
+static void as_submit (const char *type, const char *type_instance,
+               double val)
 {
-       as_write (host, inst, val, temperature_file);
-}
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-static void fanspeed_write (char *host, char *inst, char *val)
-{
-       as_write (host, inst, val, fanspeed_file);
-}
+       DEBUG ("type = %s; type_instance = %s; val = %f;",
+                       type, type_instance, val);
 
-#if IOKIT_HAVE_READ
-static void as_submit (char *type, char *inst, double value)
-{
-       char buf[128];
+       values[0].gauge = val;
 
-       if (snprintf (buf, 1024, "%u:%f", (unsigned int) curtime,
-                               value) >= 128)
-               return;
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "apple_sensors");
+       strcpy (vl.plugin_instance, "");
+       strcpy (vl.type_instance, type_instance);
 
-       plugin_submit (type, inst, buf);
+       plugin_dispatch_values (type, &vl);
 }
 
-static void as_read (void)
+static int as_read (void)
 {
        kern_return_t   status;
        io_iterator_t   iterator;
@@ -147,16 +140,16 @@ static void as_read (void)
        int    i;
 
        if (!io_master_port || (io_master_port == MACH_PORT_NULL))
-               return;
+               return (-1);
 
        status = IOServiceGetMatchingServices (io_master_port,
                        IOServiceNameMatching("IOHWSensor"),
                        &iterator);
        if (status != kIOReturnSuccess)
                {
-               syslog (LOG_ERR, "IOServiceGetMatchingServices failed: %s",
+               ERROR ("IOServiceGetMatchingServices failed: %s",
                                mach_error_string (status));
-               return;
+               return (-1);
        }
 
        while ((io_obj = IOIteratorNext (iterator)))
@@ -168,7 +161,7 @@ static void as_read (void)
                                kNilOptions);
                if (status != kIOReturnSuccess)
                {
-                       DBG ("IORegistryEntryCreateCFProperties failed: %s",
+                       DEBUG ("IORegistryEntryCreateCFProperties failed: %s",
                                        mach_error_string (status));
                        continue;
                }
@@ -228,17 +221,17 @@ static void as_read (void)
                if (strcmp (type, "temperature") == 0)
                {
                        value_double = ((double) value_int) / 65536.0;
-                       strncpy (type, "apple_temperature", 128);
+                       strcpy (type, "temperature");
                }
                else if (strcmp (type, "temp") == 0)
                {
                        value_double = ((double) value_int) / 10.0;
-                       strncpy (type, "apple_temperature", 128);
+                       strcpy (type, "temperature");
                }
                else if (strcmp (type, "fanspeed") == 0)
                {
                        value_double = ((double) value_int) / 65536.0;
-                       strncpy (type, "apple_fanspeed", 128);
+                       strcpy (type, "fanspeed");
                }
                else if (strcmp (type, "voltage") == 0)
                {
@@ -248,11 +241,11 @@ static void as_read (void)
                else if (strcmp (type, "adc") == 0)
                {
                        value_double = ((double) value_int) / 10.0;
-                       strncpy (type, "apple_temperature", 128);
+                       strcpy (type, "fanspeed");
                }
                else
                {
-                       DBG ("apple_sensors: Read unknown sensor type: %s",
+                       DEBUG ("apple_sensors: Read unknown sensor type: %s",
                                        type);
                        value_double = (double) value_int;
                }
@@ -264,16 +257,24 @@ static void as_read (void)
        } /* while (iterator) */
 
        IOObjectRelease (iterator);
-}
-#else
-# define as_read NULL
+
+       return (0);
+} /* int as_read */
 #endif /* IOKIT_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, as_init, as_read, NULL);
-       plugin_register ("apple_temperature", NULL, NULL, temperature_write);
-       plugin_register ("apple_fanspeed",    NULL, NULL, fanspeed_write);
-}
+       if (load & MR_DATASETS)
+       {
+               plugin_register_data_set (&fanspeed_ds);
+               plugin_register_data_set (&temperature_ds);
+       }
 
-#undef MODULE_NAME
+#if IOKIT_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_init ("apple_sensors", as_init);
+               plugin_register_read ("apple_sensors", as_read);
+       }
+#endif /* IOKIT_HAVE_READ */
+} /* void module_register */
index 2141a58..bdf4619 100644 (file)
@@ -1,11 +1,10 @@
 /**
  * collectd - src/battery.c
- * Copyright (C) 2006  Florian octo Forster
+ * Copyright (C) 2006,2007  Florian octo Forster
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
-#include "utils_debug.h"
-
-#define MODULE_NAME "battery"
-#define BUFSIZE 512
 
 #if HAVE_MACH_MACH_TYPES_H
 #  include <mach/mach_types.h>
 
 #define INVALID_VALUE 47841.29
 
-static char *battery_current_file = "battery-%s/current.rrd";
-static char *battery_voltage_file = "battery-%s/voltage.rrd";
-static char *battery_charge_file  = "battery-%s/charge.rrd";
+static data_source_t data_source_charge[1] =
+{
+       {"value", DS_TYPE_GAUGE, 0, NAN}
+};
+
+static data_set_t charge_ds =
+{
+       "charge", 1, data_source_charge
+};
+
+static data_source_t data_source_current[1] =
+{
+       {"value", DS_TYPE_GAUGE, NAN, NAN}
+};
 
-static char *ds_def_current[] =
+static data_set_t current_ds =
 {
-       "DS:current:GAUGE:"COLLECTD_HEARTBEAT":U:U",
-       NULL
+       "current", 1, data_source_current
 };
-static int ds_num_current = 1;
 
-static char *ds_def_voltage[] =
+static data_source_t data_source_voltage[1] =
 {
-       "DS:voltage:GAUGE:"COLLECTD_HEARTBEAT":U:U",
-       NULL
+       {"value", DS_TYPE_GAUGE, NAN, NAN}
 };
-static int ds_num_voltage = 1;
 
-static char *ds_def_charge[] =
+static data_set_t voltage_ds =
 {
-       "DS:charge:GAUGE:"COLLECTD_HEARTBEAT":0:U",
-       NULL
+       "voltage", 1, data_source_voltage
 };
-static int ds_num_charge = 1;
 
+#if BATTERY_HAVE_READ
 #if HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H
        /* No global variables */
 /* #endif HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H */
@@ -95,7 +96,7 @@ static int   battery_pmu_num = 0;
 static char *battery_pmu_file = "/proc/pmu/battery_%i";
 #endif /* KERNEL_LINUX */
 
-static void battery_init (void)
+static int battery_init (void)
 {
 #if HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H
        /* No init neccessary */
@@ -103,13 +104,13 @@ static void battery_init (void)
 
 #elif KERNEL_LINUX
        int len;
-       char filename[BUFSIZE];
+       char filename[128];
 
        for (battery_pmu_num = 0; ; battery_pmu_num++)
        {
-               len = snprintf (filename, BUFSIZE, battery_pmu_file, battery_pmu_num);
+               len = snprintf (filename, sizeof (filename), battery_pmu_file, battery_pmu_num);
 
-               if ((len >= BUFSIZE) || (len < 0))
+               if ((len >= sizeof (filename)) || (len < 0))
                        break;
 
                if (access (filename, R_OK))
@@ -117,90 +118,25 @@ static void battery_init (void)
        }
 #endif /* KERNEL_LINUX */
 
-       return;
+       return (0);
 }
 
-static void battery_current_write (char *host, char *inst, char *val)
+static void battery_submit (const char *plugin_instance, const char *type, double value)
 {
-       char filename[BUFSIZE];
-       int len;
-
-       len = snprintf (filename, BUFSIZE, battery_current_file, inst);
-       if ((len >= BUFSIZE) || (len < 0))
-               return;
-
-       rrd_update_file (host, filename, val,
-                       ds_def_current, ds_num_current);
-}
-
-static void battery_voltage_write (char *host, char *inst, char *val)
-{
-       char filename[BUFSIZE];
-       int len;
-
-       len = snprintf (filename, BUFSIZE, battery_voltage_file, inst);
-       if ((len >= BUFSIZE) || (len < 0))
-               return;
-
-       rrd_update_file (host, filename, val,
-                       ds_def_voltage, ds_num_voltage);
-}
-
-static void battery_charge_write (char *host, char *inst, char *val)
-{
-       char filename[BUFSIZE];
-       int len;
-
-       len = snprintf (filename, BUFSIZE, battery_charge_file, inst);
-       if ((len >= BUFSIZE) || (len < 0))
-               return;
-
-       rrd_update_file (host, filename, val,
-                       ds_def_charge, ds_num_charge);
-}
-
-#if BATTERY_HAVE_READ
-static void battery_submit (char *inst, double current, double voltage, double charge)
-{
-       int len;
-       char buffer[BUFSIZE];
-
-       if (current != INVALID_VALUE)
-       {
-               len = snprintf (buffer, BUFSIZE, "N:%.3f", current);
-
-               if ((len > 0) && (len < BUFSIZE))
-                       plugin_submit ("battery_current", inst, buffer);
-       }
-       else
-       {
-               plugin_submit ("battery_current", inst, "N:U");
-       }
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       if (voltage != INVALID_VALUE)
-       {
-               len = snprintf (buffer, BUFSIZE, "N:%.3f", voltage);
+       values[0].gauge = value;
 
-               if ((len > 0) && (len < BUFSIZE))
-                       plugin_submit ("battery_voltage", inst, buffer);
-       }
-       else
-       {
-               plugin_submit ("battery_voltage", inst, "N:U");
-       }
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "battery");
+       strcpy (vl.plugin_instance, plugin_instance);
 
-       if (charge != INVALID_VALUE)
-       {
-               len = snprintf (buffer, BUFSIZE, "N:%.3f", charge);
-
-               if ((len > 0) && (len < BUFSIZE))
-                       plugin_submit ("battery_charge", inst, buffer);
-       }
-       else
-       {
-               plugin_submit ("battery_charge", inst, "N:U");
-       }
-}
+       plugin_dispatch_values (type, &vl);
+} /* void battery_submit */
 
 #if HAVE_IOKIT_PS_IOPOWERSOURCES_H || HAVE_IOKIT_IOKITLIB_H
 double dict_get_double (CFDictionaryRef dict, char *key_string)
@@ -214,13 +150,13 @@ double dict_get_double (CFDictionaryRef dict, char *key_string)
                        kCFStringEncodingASCII);
        if (key_obj == NULL)
        {
-               DBG ("CFStringCreateWithCString (%s) failed.\n", key_string);
+               DEBUG ("CFStringCreateWithCString (%s) failed.\n", key_string);
                return (INVALID_VALUE);
        }
 
        if ((val_obj = CFDictionaryGetValue (dict, key_obj)) == NULL)
        {
-               DBG ("CFDictionaryGetValue (%s) failed.", key_string);
+               DEBUG ("CFDictionaryGetValue (%s) failed.", key_string);
                CFRelease (key_obj);
                return (INVALID_VALUE);
        }
@@ -244,7 +180,7 @@ double dict_get_double (CFDictionaryRef dict, char *key_string)
        }
        else
        {
-               DBG ("CFGetTypeID (val_obj) = %i", (int) CFGetTypeID (val_obj));
+               DEBUG ("CFGetTypeID (val_obj) = %i", (int) CFGetTypeID (val_obj));
                return (INVALID_VALUE);
        }
 
@@ -270,7 +206,7 @@ static void get_via_io_power_sources (double *ret_charge,
        ps_array     = IOPSCopyPowerSourcesList (ps_raw);
        ps_array_len = CFArrayGetCount (ps_array);
 
-       DBG ("ps_array_len == %i", ps_array_len);
+       DEBUG ("ps_array_len == %i", ps_array_len);
 
        for (i = 0; i < ps_array_len; i++)
        {
@@ -279,13 +215,13 @@ static void get_via_io_power_sources (double *ret_charge,
 
                if (ps_dict == NULL)
                {
-                       DBG ("IOPSGetPowerSourceDescription failed.");
+                       DEBUG ("IOPSGetPowerSourceDescription failed.");
                        continue;
                }
 
                if (CFGetTypeID (ps_dict) != CFDictionaryGetTypeID ())
                {
-                       DBG ("IOPSGetPowerSourceDescription did not return a CFDictionaryRef");
+                       DEBUG ("IOPSGetPowerSourceDescription did not return a CFDictionaryRef");
                        continue;
                }
 
@@ -346,7 +282,7 @@ static void get_via_generic_iokit (double *ret_charge,
                        &iterator);
        if (status != kIOReturnSuccess)
        {
-               DBG ("IOServiceGetMatchingServices failed.");
+               DEBUG ("IOServiceGetMatchingServices failed.");
                return;
        }
 
@@ -358,7 +294,7 @@ static void get_via_generic_iokit (double *ret_charge,
                                kNilOptions);
                if (status != kIOReturnSuccess)
                {
-                       DBG ("IORegistryEntryCreateCFProperties failed.");
+                       DEBUG ("IORegistryEntryCreateCFProperties failed.");
                        continue;
                }
 
@@ -409,7 +345,7 @@ static void get_via_generic_iokit (double *ret_charge,
 }
 #endif /* HAVE_IOKIT_IOKITLIB_H */
 
-static void battery_read (void)
+static int battery_read (void)
 {
 #if HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H
        double charge  = INVALID_VALUE; /* Current charge in Ah */
@@ -429,16 +365,18 @@ static void battery_read (void)
        if ((charge_rel != INVALID_VALUE) && (charge_abs != INVALID_VALUE))
                charge = charge_abs * charge_rel / 100.0;
 
-       if ((charge != INVALID_VALUE)
-                       || (current != INVALID_VALUE)
-                       || (voltage != INVALID_VALUE))
-               battery_submit ("0", current, voltage, charge);
+       if (charge != INVALID_VALUE)
+               battery_submit ("0", "charge", charge);
+       if (current != INVALID_VALUE)
+               battery_submit ("0", "current", current);
+       if (voltage != INVALID_VALUE)
+               battery_submit ("0", "voltage", voltage);
 /* #endif HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H */
 
 #elif KERNEL_LINUX
        FILE *fh;
-       char buffer[BUFSIZE];
-       char filename[BUFSIZE];
+       char buffer[1024];
+       char filename[256];
        
        char *fields[8];
        int numfields;
@@ -448,24 +386,24 @@ static void battery_read (void)
 
        for (i = 0; i < battery_pmu_num; i++)
        {
-               char    batnum_str[BUFSIZE];
+               char    batnum_str[256];
                double  current = INVALID_VALUE;
                double  voltage = INVALID_VALUE;
                double  charge  = INVALID_VALUE;
                double *valptr = NULL;
 
-               len = snprintf (filename, BUFSIZE, battery_pmu_file, i);
-               if ((len >= BUFSIZE) || (len < 0))
+               len = snprintf (filename, sizeof (filename), battery_pmu_file, i);
+               if ((len >= sizeof (filename)) || (len < 0))
                        continue;
 
-               len = snprintf (batnum_str, BUFSIZE, "%i", i);
-               if ((len >= BUFSIZE) || (len < 0))
+               len = snprintf (batnum_str, sizeof (batnum_str), "%i", i);
+               if ((len >= sizeof (batnum_str)) || (len < 0))
                        continue;
 
                if ((fh = fopen (filename, "r")) == NULL)
                        continue;
 
-               while (fgets (buffer, BUFSIZE, fh) != NULL)
+               while (fgets (buffer, sizeof (buffer), fh) != NULL)
                {
                        numfields = strsplit (buffer, fields, 8);
 
@@ -495,13 +433,15 @@ static void battery_read (void)
                        }
                }
 
-               if ((current != INVALID_VALUE)
-                               || (voltage != INVALID_VALUE)
-                               || (charge  != INVALID_VALUE))
-                       battery_submit (batnum_str, current, voltage, charge);
-
                fclose (fh);
                fh = NULL;
+
+               if (charge != INVALID_VALUE)
+                       battery_submit ("0", "charge", charge);
+               if (current != INVALID_VALUE)
+                       battery_submit ("0", "current", current);
+               if (voltage != INVALID_VALUE)
+                       battery_submit ("0", "voltage", voltage);
        }
 
        if (access ("/proc/acpi/battery", R_OK | X_OK) == 0)
@@ -517,8 +457,10 @@ static void battery_read (void)
 
                if ((dh = opendir ("/proc/acpi/battery")) == NULL)
                {
-                       syslog (LOG_ERR, "Cannot open `/proc/acpi/battery': %s", strerror (errno));
-                       return;
+                       char errbuf[1024];
+                       ERROR ("Cannot open `/proc/acpi/battery': %s",
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+                       return (-1);
                }
 
                while ((ent = readdir (dh)) != NULL)
@@ -526,13 +468,18 @@ static void battery_read (void)
                        if (ent->d_name[0] == '.')
                                continue;
 
-                       len = snprintf (filename, BUFSIZE, "/proc/acpi/battery/%s/state", ent->d_name);
-                       if ((len >= BUFSIZE) || (len < 0))
+                       len = snprintf (filename, sizeof (filename),
+                                       "/proc/acpi/battery/%s/state",
+                                       ent->d_name);
+                       if ((len >= sizeof (filename)) || (len < 0))
                                continue;
 
                        if ((fh = fopen (filename, "r")) == NULL)
                        {
-                               syslog (LOG_ERR, "Cannot open `%s': %s", filename, strerror (errno));
+                               char errbuf[1024];
+                               ERROR ("Cannot open `%s': %s", filename,
+                                               sstrerror (errno, errbuf,
+                                                       sizeof (errbuf)));
                                continue;
                        }
 
@@ -545,7 +492,7 @@ static void battery_read (void)
                         * [11:00] <@tokkee> remaining capacity:      4136 mAh
                         * [11:00] <@tokkee> present voltage:         12428 mV
                         */
-                       while (fgets (buffer, BUFSIZE, fh) != NULL)
+                       while (fgets (buffer, sizeof (buffer), fh) != NULL)
                        {
                                numfields = strsplit (buffer, fields, 8);
 
@@ -585,34 +532,43 @@ static void battery_read (void)
                                        if ((fields[2] == endptr) || (errno != 0))
                                                *valptr = INVALID_VALUE;
                                }
-                       }
+                       } /* while (fgets (buffer, sizeof (buffer), fh) != NULL) */
+
+                       fclose (fh);
 
                        if ((current != INVALID_VALUE) && (charging == 0))
                                        current *= -1;
 
-                       if ((current != INVALID_VALUE)
-                                       || (voltage != INVALID_VALUE)
-                                       || (charge  != INVALID_VALUE))
-                               battery_submit (ent->d_name, current, voltage, charge);
-
-                       fclose (fh);
+                       if (charge != INVALID_VALUE)
+                               battery_submit ("0", "charge", charge);
+                       if (current != INVALID_VALUE)
+                               battery_submit ("0", "current", current);
+                       if (voltage != INVALID_VALUE)
+                               battery_submit ("0", "voltage", voltage);
                }
 
                closedir (dh);
        }
 #endif /* KERNEL_LINUX */
+
+       return (0);
 }
-#else
-# define battery_read NULL
 #endif /* BATTERY_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, battery_init, battery_read, NULL);
-       plugin_register ("battery_current", NULL, NULL, battery_current_write);
-       plugin_register ("battery_voltage", NULL, NULL, battery_voltage_write);
-       plugin_register ("battery_charge",  NULL, NULL, battery_charge_write);
-}
+       if (load & MR_DATASETS)
+       {
+               plugin_register_data_set (&charge_ds);
+               plugin_register_data_set (&current_ds);
+               plugin_register_data_set (&voltage_ds);
+       }
 
-#undef BUFSIZE
-#undef MODULE_NAME
+#if BATTERY_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_init ("battery", battery_init);
+               plugin_register_read ("battery", battery_read);
+       }
+#endif /* BATTERY_HAVE_READ */
+} /* void module_register */
diff --git a/src/collectd-nagios.c b/src/collectd-nagios.c
new file mode 100644 (file)
index 0000000..b7c3ffa
--- /dev/null
@@ -0,0 +1,492 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+/*
+ * This weird macro cascade forces the glibc to define `NAN'. I don't know
+ * another way to solve this, so more intelligent solutions are welcome. -octo
+ */
+#ifndef __USE_ISOC99
+# define DISABLE__USE_ISOC99 1
+# define __USE_ISOC99 1
+#endif
+#include <math.h>
+#ifdef DISABLE__USE_ISOC99
+# undef DISABLE__USE_ISOC99
+# undef __USE_ISOC99
+#endif
+
+#define RET_OKAY     0
+#define RET_WARNING  1
+#define RET_CRITICAL 2
+#define RET_UNKNOWN  3
+
+#define CON_NONE     0
+#define CON_AVERAGE  1
+#define CON_SUM      2
+
+struct range_s
+{
+       double min;
+       double max;
+       int    invert;
+};
+typedef struct range_s range_t;
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+
+static char *socket_file_g = NULL;
+static char *value_string_g = NULL;
+static char *hostname_g = NULL;
+
+static range_t range_critical_g;
+static range_t range_warning_g;
+static int consolitation_g = CON_NONE;
+
+static char **match_ds_g = NULL;
+static int    match_ds_num_g = 0;
+
+static int ignore_ds (const char *name)
+{
+       int i;
+
+       if (match_ds_g == NULL)
+               return (0);
+
+       for (i = 0; i < match_ds_num_g; i++)
+               if (strcasecmp (match_ds_g[i], name) == 0)
+                       return (0);
+
+       return (1);
+} /* int ignore_ds */
+
+static void parse_range (char *string, range_t *range)
+{
+       char *min_ptr;
+       char *max_ptr;
+
+       if (*string == '@')
+       {
+               range->invert = 1;
+               string++;
+       }
+
+       max_ptr = strchr (string, ':');
+       if (max_ptr == NULL)
+       {
+               min_ptr = NULL;
+               max_ptr = string;
+       }
+       else
+       {
+               min_ptr = string;
+               *max_ptr = '\0';
+               max_ptr++;
+       }
+
+       assert (max_ptr != NULL);
+
+       /* `10' == `0:10' */
+       if (min_ptr == NULL)
+               range->min = 0.0;
+       /* :10 == ~:10 == -inf:10 */
+       else if ((*min_ptr == '\0') || (*min_ptr == '~'))
+               range->min = NAN;
+       else
+               range->min = atof (min_ptr);
+
+       if ((*max_ptr == '\0') || (*max_ptr == '~'))
+               range->max = NAN;
+       else
+               range->max = atof (max_ptr);
+} /* void parse_range */
+
+int match_range (range_t *range, double value)
+{
+       int ret = 0;
+
+       if (!isnan (range->min) && (range->min > value))
+               ret = 1;
+       if (!isnan (range->max) && (range->max < value))
+               ret = 1;
+
+       return (((ret - range->invert) == 0) ? 0 : 1);
+}
+
+static int get_values (int *ret_values_num, double **ret_values,
+               char ***ret_values_names)
+{
+       struct sockaddr_un sa;
+       int status;
+       int fd;
+       FILE *fh;
+       char buffer[4096];
+
+       int values_num;
+       double *values;
+       char **values_names;
+
+       int i;
+
+       fd = socket (PF_UNIX, SOCK_STREAM, 0);
+       if (fd < 0)
+       {
+               fprintf (stderr, "socket failed: %s\n",
+                               strerror (errno));
+               return (-1);
+       }
+
+       memset (&sa, '\0', sizeof (sa));
+       sa.sun_family = AF_UNIX;
+       strncpy (sa.sun_path, socket_file_g,
+                       sizeof (sa.sun_path) - 1);
+
+       status = connect (fd, (struct sockaddr *) &sa, sizeof (sa));
+       if (status != 0)
+       {
+               fprintf (stderr, "connect failed: %s\n",
+                               strerror (errno));
+               return (-1);
+       }
+
+       fh = fdopen (fd, "r+");
+       if (fh == NULL)
+       {
+               fprintf (stderr, "fdopen failed: %s\n",
+                               strerror (errno));
+               close (fd);
+               return (-1);
+       }
+
+       fprintf (fh, "GETVAL %s/%s\n", hostname_g, value_string_g);
+       fflush (fh);
+
+       if (fgets (buffer, sizeof (buffer), fh) == NULL)
+       {
+               fprintf (stderr, "fgets failed: %s\n",
+                               strerror (errno));
+               close (fd);
+               return (-1);
+       }
+       close (fd); fd = -1;
+
+       values_num = atoi (buffer);
+       if (values_num < 1)
+               return (-1);
+
+       values = (double *) malloc (values_num * sizeof (double));
+       if (values == NULL)
+       {
+               fprintf (stderr, "malloc failed: %s\n",
+                               strerror (errno));
+               return (-1);
+       }
+
+       values_names = (char **) malloc (values_num * sizeof (char *));
+       if (values_names == NULL)
+       {
+               fprintf (stderr, "malloc failed: %s\n",
+                               strerror (errno));
+               free (values);
+               return (-1);
+       }
+
+       {
+               char *ptr = strchr (buffer, ' ') + 1;
+               char *key;
+               char *value;
+
+               i = 0;
+               while ((key = strtok (ptr, " \t")) != NULL)
+               {
+                       ptr = NULL;
+                       value = strchr (key, '=');
+                       if (value == NULL)
+                               continue;
+                       *value = '\0'; value++;
+
+                       if (ignore_ds (key) != 0)
+                               continue;
+
+                       values_names[i] = strdup (key);
+                       values[i] = atof (value);
+
+                       i++;
+                       if (i >= values_num)
+                               break;
+               }
+               values_num = i;
+       }
+
+       *ret_values_num = values_num;
+       *ret_values = values;
+       *ret_values_names = values_names;
+
+       return (0);
+} /* int get_values */
+
+static void usage (const char *name)
+{
+       fprintf (stderr, "Usage: %s <-s socket> <-n value_spec> <-H hostname> [options]\n"
+                       "\n"
+                       "Valid options are:\n"
+                       "  -s <socket>    Path to collectd's UNIX-socket.\n"
+                       "  -n <v_spec>    Value specification to get from collectd.\n"
+                       "                 Format: `plugin-instance/type-instance'\n"
+                       "  -d <ds>        Select the DS to examine. May be repeated to examine multiple\n"
+                       "                 DSes. By default all DSes are used.\n"
+                       "  -g <consol>    Method to use to consolidate several DSes.\n"
+                       "                 Valid arguments are `none', `average' and `sum'\n"
+                       "  -H <host>      Hostname to query the values for.\n"
+                       "  -c <range>     Critical range\n"
+                       "  -w <range>     Warning range\n"
+                       "\n"
+                       "Consolidation functions:\n"
+                       "  none:          Apply the warning- and critical-ranges to each data-source\n"
+                       "                 individually.\n"
+                       "  average:       Calculate the average of all matching DSes and apply the\n"
+                       "                 warning- and critical-ranges to the calculated average.\n"
+                       "  sum:           Apply the ranges to the sum of all DSes.\n"
+                       "\n", name);
+       exit (1);
+} /* void usage */
+
+int do_check_con_none (int values_num, double *values, char **values_names)
+{
+       int i;
+
+       int num_critical = 0;
+       int num_warning  = 0;
+       int num_okay = 0;
+
+       for (i = 0; i < values_num; i++)
+       {
+               if (isnan (values[i]))
+                       num_warning++;
+               else if (match_range (&range_critical_g, values[i]) != 0)
+                       num_critical++;
+               else if (match_range (&range_warning_g, values[i]) != 0)
+                       num_warning++;
+               else
+                       num_okay++;
+       }
+
+       if ((num_critical != 0) || (values_num == 0))
+       {
+               printf ("CRITICAL: %i critical, %i warning, %i okay\n",
+                               num_critical, num_warning, num_okay);
+               return (RET_CRITICAL);
+       }
+       else if (num_warning != 0)
+       {
+               printf ("WARNING: %i warning, %i okay\n",
+                               num_warning, num_okay);
+               return (RET_WARNING);
+       }
+       else
+       {
+               printf ("OKAY: %i okay\n", num_okay);
+               return (RET_OKAY);
+       }
+
+       return (RET_UNKNOWN);
+} /* int do_check_con_none */
+
+int do_check_con_average (int values_num, double *values, char **values_names)
+{
+       int i;
+       double total;
+       int total_num;
+
+       total = 0.0;
+       total_num = 0;
+       for (i = 0; i < values_num; i++)
+       {
+               if (!isnan (values[i]))
+               {
+                       total += values[i];
+                       total_num++;
+               }
+       }
+
+       if (total_num == 0)
+       {
+               printf ("WARNING: No defined values found\n");
+               return (RET_WARNING);
+       }
+
+       if (match_range (&range_critical_g, total / total_num) != 0)
+       {
+               printf ("CRITICAL: Average = %lf\n",
+                               (double) (total / total_num));
+               return (RET_CRITICAL);
+       }
+       else if (match_range (&range_warning_g, total / total_num) != 0)
+       {
+               printf ("WARNING: Average = %lf\n",
+                               (double) (total / total_num));
+               return (RET_WARNING);
+       }
+       else
+       {
+               printf ("OKAY: Average = %lf\n",
+                               (double) (total / total_num));
+               return (RET_OKAY);
+       }
+
+       return (RET_UNKNOWN);
+} /* int do_check_con_average */
+
+int do_check_con_sum (int values_num, double *values, char **values_names)
+{
+       int i;
+       double total;
+       int total_num;
+
+       total = 0.0;
+       total_num = 0;
+       for (i = 0; i < values_num; i++)
+       {
+               if (!isnan (values[i]))
+               {
+                       total += values[i];
+                       total_num++;
+               }
+       }
+
+       if (total_num == 0)
+       {
+               printf ("WARNING: No defined values found\n");
+               return (RET_WARNING);
+       }
+
+       if (match_range (&range_critical_g, total) != 0)
+       {
+               printf ("CRITICAL: Sum = %lf\n", total);
+               return (RET_CRITICAL);
+       }
+       else if (match_range (&range_warning_g, total) != 0)
+       {
+               printf ("WARNING: Sum = %lf\n", total);
+               return (RET_WARNING);
+       }
+       else
+       {
+               printf ("OKAY: Sum = %lf\n", total);
+               return (RET_OKAY);
+       }
+
+       return (RET_UNKNOWN);
+} /* int do_check_con_sum */
+
+int do_check (void)
+{
+       double  *values;
+       char   **values_names;
+       int      values_num;
+
+       if (get_values (&values_num, &values, &values_names) != 0)
+       {
+               fputs ("ERROR: Cannot get values from daemon\n", stdout);
+               return (RET_CRITICAL);
+       }
+
+       if (consolitation_g == CON_NONE)
+               return (do_check_con_none (values_num, values, values_names));
+       else if (consolitation_g == CON_AVERAGE)
+               return (do_check_con_average (values_num, values, values_names));
+       else if (consolitation_g == CON_SUM)
+               return (do_check_con_sum (values_num, values, values_names));
+
+       free (values);
+       free (values_names);
+
+       return (RET_UNKNOWN);
+}
+
+int main (int argc, char **argv)
+{
+       range_critical_g.min = NAN;
+       range_critical_g.max = NAN;
+       range_critical_g.invert = 0;
+
+       range_warning_g.min = NAN;
+       range_warning_g.max = NAN;
+       range_warning_g.invert = 0;
+
+       while (42)
+       {
+               int c;
+
+               c = getopt (argc, argv, "w:c:s:n:H:g:d:h");
+               if (c < 0)
+                       break;
+
+               switch (c)
+               {
+                       case 'c':
+                               parse_range (optarg, &range_critical_g);
+                               break;
+                       case 'w':
+                               parse_range (optarg, &range_warning_g);
+                               break;
+                       case 's':
+                               socket_file_g = optarg;
+                               break;
+                       case 'n':
+                               value_string_g = optarg;
+                               break;
+                       case 'H':
+                               hostname_g = optarg;
+                               break;
+                       case 'g':
+                               if (strcasecmp (optarg, "none") == 0)
+                                       consolitation_g = CON_NONE;
+                               else if (strcasecmp (optarg, "average") == 0)
+                                       consolitation_g = CON_AVERAGE;
+                               else if (strcasecmp (optarg, "sum") == 0)
+                                       consolitation_g = CON_SUM;
+                               else
+                                       usage (argv[0]);
+                               break;
+                       case 'd':
+                       {
+                               char **tmp;
+                               tmp = (char **) realloc (match_ds_g,
+                                               (match_ds_num_g + 1)
+                                               * sizeof (char *));
+                               if (tmp == NULL)
+                               {
+                                       fprintf (stderr, "realloc failed: %s\n",
+                                                       strerror (errno));
+                                       return (RET_UNKNOWN);
+                               }
+                               match_ds_g = tmp;
+                               match_ds_g[match_ds_num_g] = strdup (optarg);
+                               if (match_ds_g[match_ds_num_g] == NULL)
+                               {
+                                       fprintf (stderr, "strdup failed: %s\n",
+                                                       strerror (errno));
+                                       return (RET_UNKNOWN);
+                               }
+                               match_ds_num_g++;
+                               break;
+                       }
+                       default:
+                               usage (argv[0]);
+               } /* switch (c) */
+       }
+
+       if ((socket_file_g == NULL) || (value_string_g == NULL)
+                       || (hostname_g == NULL))
+               usage (argv[0]);
+
+       return (do_check ());
+} /* int main */
index a93cc28..f8f2fcc 100644 (file)
@@ -1,11 +1,10 @@
 /**
  * collectd - src/collectd.c
- * Copyright (C) 2005,2006  Florian octo Forster
+ * Copyright (C) 2005-2007  Florian octo Forster
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
 
 #include "collectd.h"
 #include "common.h"
-#include "utils_debug.h"
 
 #include "network.h"
 #include "plugin.h"
 #include "configfile.h"
 
-static int loop = 0;
-
+/*
+ * Global variables
+ */
+char hostname_g[DATA_MAX_NAME_LEN];
+int  interval_g;
 #if HAVE_LIBKSTAT
 kstat_ctl_t *kc;
 #endif /* HAVE_LIBKSTAT */
 
-/*
- * exported variables
- */
-time_t curtime;
-int    operating_mode;
+static int loop = 0;
 
 static void sigIntHandler (int signal)
 {
@@ -51,34 +48,92 @@ static void sigTermHandler (int signal)
        loop++;
 }
 
-static int change_basedir (char *dir)
+static int init_global_variables (void)
+{
+       const char *str;
+
+       str = global_option_get ("Hostname");
+       if (str != NULL)
+       {
+               strncpy (hostname_g, str, sizeof (hostname_g));
+       }
+       else
+       {
+               if (gethostname (hostname_g, sizeof (hostname_g)) != 0)
+               {
+                       fprintf (stderr, "`gethostname' failed and no "
+                                       "hostname was configured.\n");
+                       return (-1);
+               }
+       }
+       DEBUG ("hostname_g = %s;", hostname_g);
+
+       str = global_option_get ("Interval");
+       if (str == NULL)
+               str = "10";
+       interval_g = atoi (str);
+       if (interval_g <= 0)
+       {
+               fprintf (stderr, "Cannot set the interval to a correct value.\n"
+                               "Please check your settings.\n");
+               return (-1);
+       }
+       DEBUG ("interval_g = %i;", interval_g);
+
+       return (0);
+} /* int init_global_variables */
+
+static int change_basedir (const char *orig_dir)
 {
-       int dirlen = strlen (dir);
+       char *dir = strdup (orig_dir);
+       int dirlen;
+       int status;
+
+       if (dir == NULL)
+       {
+               char errbuf[1024];
+               ERROR ("strdup failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
        
+       dirlen = strlen (dir);
        while ((dirlen > 0) && (dir[dirlen - 1] == '/'))
                dir[--dirlen] = '\0';
 
        if (dirlen <= 0)
                return (-1);
 
-       if (chdir (dir) == -1)
+       status = chdir (dir);
+       free (dir);
+
+       if (status != 0)
        {
                if (errno == ENOENT)
                {
-                       if (mkdir (dir, 0755) == -1)
+                       if (mkdir (orig_dir, 0755) == -1)
                        {
-                               syslog (LOG_ERR, "mkdir (%s): %s", dir, strerror (errno));
+                               char errbuf[1024];
+                               ERROR ("mkdir (%s): %s", orig_dir,
+                                               sstrerror (errno, errbuf,
+                                                       sizeof (errbuf)));
                                return (-1);
                        }
-                       else if (chdir (dir) == -1)
+                       else if (chdir (orig_dir) == -1)
                        {
-                               syslog (LOG_ERR, "chdir (%s): %s", dir, strerror (errno));
+                               char errbuf[1024];
+                               ERROR ("chdir (%s): %s", orig_dir,
+                                               sstrerror (errno, errbuf,
+                                                       sizeof (errbuf)));
                                return (-1);
                        }
                }
                else
                {
-                       syslog (LOG_ERR, "chdir: %s", strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("chdir (%s): %s", orig_dir,
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        return (-1);
                }
        }
@@ -92,7 +147,7 @@ static void update_kstat (void)
        if (kc == NULL)
        {
                if ((kc = kstat_open ()) == NULL)
-                       syslog (LOG_ERR, "Unable to open kstat control structure");
+                       ERROR ("Unable to open kstat control structure");
        }
        else
        {
@@ -100,11 +155,11 @@ static void update_kstat (void)
                kid = kstat_chain_update (kc);
                if (kid > 0)
                {
-                       syslog (LOG_INFO, "kstat chain has been updated");
+                       INFO ("kstat chain has been updated");
                        plugin_init_all ();
                }
                else if (kid < 0)
-                       syslog (LOG_ERR, "kstat chain update failed");
+                       ERROR ("kstat chain update failed");
                /* else: everything works as expected */
        }
 
@@ -132,29 +187,14 @@ static void exit_usage (char *name)
                        "  Config-File       "CONFIGFILE"\n"
                        "  PID-File          "PIDFILE"\n"
                        "  Data-Directory    "PKGLOCALSTATEDIR"\n"
-#if COLLECT_DEBUG
-                       "  Log-File          "LOGFILE"\n"
-#endif
-                       "  Step              "COLLECTD_STEP" seconds\n"
-                       "  Heartbeat         "COLLECTD_HEARTBEAT" seconds\n"
                        "\n"PACKAGE" "VERSION", http://collectd.org/\n"
                        "by Florian octo Forster <octo@verplant.org>\n"
                        "for contributions see `AUTHORS'\n");
        exit (0);
 } /* static void exit_usage (char *name) */
 
-static int start_client (void)
+static int do_init (void)
 {
-       int step;
-
-       struct timeval tv_now;
-       struct timeval tv_next;
-       struct timespec ts_wait;
-
-       step = atoi (COLLECTD_STEP);
-       if (step <= 0)
-               step = 10;
-
 #if HAVE_LIBKSTAT
        kc = NULL;
        update_kstat ();
@@ -163,47 +203,62 @@ static int start_client (void)
 #if HAVE_LIBSTATGRAB
        if (sg_init ())
        {
-               syslog (LOG_ERR, "sg_init: %s", sg_str_error (sg_get_error ()));
+               ERROR ("sg_init: %s", sg_str_error (sg_get_error ()));
                return (-1);
        }
 
        if (sg_drop_privileges ())
        {
-               syslog (LOG_ERR, "sg_drop_privileges: %s", sg_str_error (sg_get_error ()));
+               ERROR ("sg_drop_privileges: %s", sg_str_error (sg_get_error ()));
                return (-1);
        }
 #endif
 
        plugin_init_all ();
 
+       return (0);
+} /* int do_init () */
+
+
+static int do_loop (void)
+{
+       struct timeval tv_now;
+       struct timeval tv_next;
+       struct timespec ts_wait;
+
        while (loop == 0)
        {
                if (gettimeofday (&tv_next, NULL) < 0)
                {
-                       syslog (LOG_ERR, "gettimeofday failed: %s", strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("gettimeofday failed: %s",
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        return (-1);
                }
-               tv_next.tv_sec += step;
+               tv_next.tv_sec += interval_g;
 
 #if HAVE_LIBKSTAT
                update_kstat ();
 #endif
-               /* `curtime' is used by many (all?) plugins as the
-                * data-sample-time passed to RRDTool */
-               curtime = time (NULL);
 
                /* Issue all plugins */
                plugin_read_all (&loop);
 
                if (gettimeofday (&tv_now, NULL) < 0)
                {
-                       syslog (LOG_ERR, "gettimeofday failed: %s", strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("gettimeofday failed: %s",
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        return (-1);
                }
 
                if (timeval_sub_timespec (&tv_next, &tv_now, &ts_wait) != 0)
                {
-                       syslog (LOG_WARNING, "Not sleeping because `timeval_sub_timespec' returned non-zero!");
+                       WARNING ("Not sleeping because "
+                                       "`timeval_sub_timespec' returned "
+                                       "non-zero!");
                        continue;
                }
 
@@ -211,61 +266,36 @@ static int start_client (void)
                {
                        if (errno != EINTR)
                        {
-                               syslog (LOG_ERR, "nanosleep failed: %s", strerror (errno));
-                               break;
+                               char errbuf[1024];
+                               ERROR ("nanosleep failed: %s",
+                                               sstrerror (errno, errbuf,
+                                                       sizeof (errbuf)));
+                               return (-1);
                        }
                }
-       }
+       } /* while (loop == 0) */
 
+       DEBUG ("return (0);");
        return (0);
-} /* static int start_client (void) */
+} /* int do_loop */
 
-#if HAVE_LIBRRD
-static int start_server (void)
+static int do_shutdown (void)
 {
-       char *host;
-       char *type;
-       char *instance;
-       char *values;
-
-       int  error_counter = 0;
-       int  status;
-
-       while ((loop == 0) && (error_counter < 3))
-       {
-               status = network_receive (&host, &type, &instance, &values);
-
-               if (status != 0)
-               {
-                       if (status < 0)
-                               error_counter++;
-                       continue;
-               }
-               error_counter = 0;
-
-               plugin_write (host, type, instance, values);
-
-               if (host     != NULL) free (host);     host     = NULL;
-               if (type     != NULL) free (type);     type     = NULL;
-               if (instance != NULL) free (instance); instance = NULL;
-               if (values   != NULL) free (values);   values   = NULL;
-       }
-       
+       plugin_shutdown_all ();
        return (0);
-} /* static int start_server (void) */
-#endif /* HAVE_LIBRRD */
+} /* int do_shutdown */
 
 #if COLLECT_DAEMON
-static int pidfile_create (const char *file)
+static int pidfile_create (void)
 {
        FILE *fh;
-
-       if (file == NULL)
-               file = PIDFILE;
+       const char *file = global_option_get ("PIDFile");
 
        if ((fh = fopen (file, "w")) == NULL)
        {
-               syslog (LOG_ERR, "fopen (%s): %s", file, strerror (errno));
+               char errbuf[1024];
+               ERROR ("fopen (%s): %s", file,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                return (1);
        }
 
@@ -274,14 +304,12 @@ static int pidfile_create (const char *file)
 
        return (0);
 } /* static int pidfile_create (const char *file) */
-#endif /* COLLECT_DAEMON */
 
-#if COLLECT_DAEMON
-static int pidfile_remove (const char *file)
+static int pidfile_remove (void)
 {
-       if (file == NULL) {
-               file = PIDFILE;
-       }
+       const char *file = global_option_get ("PIDFile");
+
+       DEBUG ("unlink (%s)", (file != NULL) ? file : "<null>");
        return (unlink (file));
 } /* static int pidfile_remove (const char *file) */
 #endif /* COLLECT_DAEMON */
@@ -290,26 +318,13 @@ int main (int argc, char **argv)
 {
        struct sigaction sigIntAction;
        struct sigaction sigTermAction;
-       char *datadir    = PKGLOCALSTATEDIR;
        char *configfile = CONFIGFILE;
+       const char *basedir;
 #if COLLECT_DAEMON
        struct sigaction sigChldAction;
-       char *pidfile    = NULL;
        pid_t pid;
        int daemonize    = 1;
 #endif
-#if COLLECT_DEBUG
-       char *logfile    = LOGFILE;
-#endif
-
-#if HAVE_LIBRRD
-       operating_mode = MODE_LOCAL;
-#else
-       operating_mode = MODE_CLIENT;
-#endif
-
-       /* open syslog */
-       openlog (PACKAGE, LOG_CONS | LOG_PID, LOG_DAEMON);
 
        /* read options */
        while (1)
@@ -332,7 +347,7 @@ int main (int argc, char **argv)
                                break;
 #if COLLECT_DAEMON
                        case 'P':
-                               pidfile = optarg;
+                               global_option_set ("PIDFile", optarg);
                                break;
                        case 'f':
                                daemonize = 0;
@@ -344,11 +359,6 @@ int main (int argc, char **argv)
                } /* switch (c) */
        } /* while (1) */
 
-#if COLLECT_DEBUG
-       if ((logfile = cf_get_option ("LogFile", LOGFILE)) != NULL)
-               DBG_STARTFILE (logfile, "Debug file opened.");
-#endif
-
        /*
         * Read options from the config file, the environment and the command
         * line (in that order, with later options overwriting previous ones in
@@ -366,37 +376,43 @@ int main (int argc, char **argv)
         * Change directory. We do this _after_ reading the config and loading
         * modules to relative paths work as expected.
         */
-       if ((datadir = cf_get_option ("DataDir", PKGLOCALSTATEDIR)) == NULL)
+       if ((basedir = global_option_get ("BaseDir")) == NULL)
        {
-               fprintf (stderr, "Don't have a datadir to use. This should not happen. Ever.");
+               fprintf (stderr, "Don't have a basedir to use. This should not happen. Ever.");
                return (1);
        }
-       if (change_basedir (datadir))
+       else if (change_basedir (basedir))
        {
-               fprintf (stderr, "Error: Unable to change to directory `%s'.\n", datadir);
+               fprintf (stderr, "Error: Unable to change to directory `%s'.\n", basedir);
                return (1);
        }
 
+       /*
+        * Set global variables or, if that failes, exit. We cannot run with
+        * them being uninitialized. If nothing is configured, then defaults
+        * are being used. So this means that the user has actually done
+        * something wrong.
+        */
+       if (init_global_variables () != 0)
+               return (1);
+
 #if COLLECT_DAEMON
        /*
         * fork off child
         */
+       memset (&sigChldAction, '\0', sizeof (sigChldAction));
        sigChldAction.sa_handler = SIG_IGN;
        sigaction (SIGCHLD, &sigChldAction, NULL);
 
-       if ((pidfile == NULL)
-                       && ((pidfile = cf_get_option ("PIDFile", PIDFILE)) == NULL))
-       {
-               fprintf (stderr, "Cannot obtain pidfile. This shoud not happen. Ever.");
-               return (1);
-       }
-
        if (daemonize)
        {
                if ((pid = fork ()) == -1)
                {
                        /* error */
-                       fprintf (stderr, "fork: %s", strerror (errno));
+                       char errbuf[1024];
+                       fprintf (stderr, "fork: %s",
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        return (1);
                }
                else if (pid != 0)
@@ -410,7 +426,7 @@ int main (int argc, char **argv)
                setsid ();
 
                /* Write pidfile */
-               if (pidfile_create (pidfile))
+               if (pidfile_create ())
                        exit (2);
 
                /* close standard descriptors */
@@ -420,17 +436,17 @@ int main (int argc, char **argv)
 
                if (open ("/dev/null", O_RDWR) != 0)
                {
-                       syslog (LOG_ERR, "Error: Could not connect `STDIN' to `/dev/null'");
+                       ERROR ("Error: Could not connect `STDIN' to `/dev/null'");
                        return (1);
                }
                if (dup (0) != 1)
                {
-                       syslog (LOG_ERR, "Error: Could not connect `STDOUT' to `/dev/null'");
+                       ERROR ("Error: Could not connect `STDOUT' to `/dev/null'");
                        return (1);
                }
                if (dup (0) != 2)
                {
-                       syslog (LOG_ERR, "Error: Could not connect `STDERR' to `/dev/null'");
+                       ERROR ("Error: Could not connect `STDERR' to `/dev/null'");
                        return (1);
                }
        } /* if (daemonize) */
@@ -439,37 +455,29 @@ int main (int argc, char **argv)
        /*
         * install signal handlers
         */
+       memset (&sigIntAction, '\0', sizeof (sigIntAction));
        sigIntAction.sa_handler = sigIntHandler;
        sigaction (SIGINT, &sigIntAction, NULL);
 
+       memset (&sigTermAction, '\0', sizeof (sigTermAction));
        sigTermAction.sa_handler = sigTermHandler;
        sigaction (SIGTERM, &sigTermAction, NULL);
 
        /*
         * run the actual loops
         */
-#if HAVE_LIBRRD
-       if (operating_mode == MODE_SERVER)
-               start_server ();
-       else /* if (operating_mode == MODE_CLIENT || operating_mode == MODE_LOCAL || operating_mode == MODE_LOG) */
-#endif
-               start_client ();
-
-       plugin_shutdown_all ();
-
-#if COLLECT_DEBUG
-       if (logfile != NULL)
-               DBG_STOPFILE("debug file closed.");
-#endif
+       do_init ();
+       do_loop ();
 
        /* close syslog */
-       syslog (LOG_INFO, "Exiting normally");
-       closelog ();
+       INFO ("Exiting normally");
+
+       do_shutdown ();
 
 #if COLLECT_DAEMON
        if (daemonize)
-               pidfile_remove (pidfile);
+               pidfile_remove ();
 #endif /* COLLECT_DAEMON */
 
        return (0);
-} /* int main (int argc, char **argv) */
+} /* int main */
index b3f9963..020bdeb 100644 (file)
@@ -4,21 +4,11 @@
 # http://collectd.org/
 #
 
-# Select one of the following modes:
-@BUILD_WITH_RRDTOOL_TRUE@Mode Local
-#Mode Server
-@BUILD_WITH_RRDTOOL_FALSE@Mode Client
-#Mode Log
-
-# Set the IP-address(es) and UDP-port(s) to send packets to. `Listen' can be
-# used as a synonym for `Server' to make the config file more readable when in
-# server mode. The port option is optional.
-#Server ff18::efc0:4a42 25826
-#Server 239.192.74.66 25826
-
-#DataDir   /opt/collectd/var/lib/collectd
-#PIDFile   /opt/collectd/var/run/collectd.pid
-#PluginDir /opt/collectd/lib/collectd
+#BaseDir     "@prefix@/var/lib/@PACKAGE_NAME@"
+#PIDFile     "@prefix@/var/run/@PACKAGE_NAME@.pid"
+#PluginDir   "@prefix@/lib/@PACKAGE_NAME@"
+#Interval     10
+#ReadThreads  5
 
 @BUILD_MODULE_APACHE_TRUE@LoadPlugin apache
 @BUILD_MODULE_APCUPS_TRUE@LoadPlugin apcups
 @BUILD_MODULE_BATTERY_TRUE@LoadPlugin battery
 @BUILD_MODULE_CPU_TRUE@LoadPlugin cpu
 @BUILD_MODULE_CPUFREQ_TRUE@LoadPlugin cpufreq
+@BUILD_MODULE_CSV_TRUE@LoadPlugin csv
 @BUILD_MODULE_DF_TRUE@LoadPlugin df
 @BUILD_MODULE_DISK_TRUE@LoadPlugin disk
 @BUILD_MODULE_DNS_TRUE@LoadPlugin dns
+@BUILD_MODULE_EMAIL_TRUE@LoadPlugin email
+@BUILD_MODULE_ENTROPY_TRUE@LoadPlugin entropy
+@BUILD_MODULE_EXEC_TRUE@LoadPlugin exec
 @BUILD_MODULE_HDDTEMP_TRUE@LoadPlugin hddtemp
+@BUILD_MODULE_INTERFACE_TRUE@LoadPlugin interface
 @BUILD_MODULE_IPTABLES_TRUE@LoadPlugin iptables
 @BUILD_MODULE_IRQ_TRUE@LoadPlugin irq
 @BUILD_MODULE_LOAD_TRUE@LoadPlugin load
+@BUILD_MODULE_LOGFILE_TRUE@LoadPlugin logfile
 @BUILD_MODULE_MBMON_TRUE@LoadPlugin mbmon
 @BUILD_MODULE_MEMORY_TRUE@LoadPlugin memory
 @BUILD_MODULE_MULTIMETER_TRUE@LoadPlugin multimeter
 @BUILD_MODULE_MYSQL_TRUE@LoadPlugin mysql
+@BUILD_MODULE_NETWORK_TRUE@LoadPlugin network
 @BUILD_MODULE_NFS_TRUE@LoadPlugin nfs
 @BUILD_MODULE_NTPD_TRUE@LoadPlugin ntpd
+@BUILD_MODULE_NUT_TRUE@LoadPlugin nut
 @BUILD_MODULE_PING_TRUE@LoadPlugin ping
 @BUILD_MODULE_PROCESSES_TRUE@LoadPlugin processes
+@BUILD_WITH_RRDTOOL_TRUE@LoadPlugin rrdtool
 @BUILD_MODULE_SENSORS_TRUE@LoadPlugin sensors
 @BUILD_MODULE_SERIAL_TRUE@LoadPlugin serial
 @BUILD_MODULE_SWAP_TRUE@LoadPlugin swap
+@BUILD_MODULE_SYSLOG_TRUE@LoadPlugin syslog
 @BUILD_MODULE_TAPE_TRUE@LoadPlugin tape
-@BUILD_MODULE_TRAFFIC_TRUE@LoadPlugin traffic
+@BUILD_MODULE_UNIXSOCK_TRUE@LoadPlugin unixsock
 @BUILD_MODULE_USERS_TRUE@LoadPlugin users
 @BUILD_MODULE_VSERVER_TRUE@LoadPlugin vserver
 @BUILD_MODULE_WIRELESS_TRUE@LoadPlugin wireless
 
 #<Plugin apache>
-#      URL http://localhost/status?auto
-#      User www-user
-#      Password secret
-#      CACert /etc/ssl/ca.crt
+#      URL "http://localhost/status?auto"
+#      User "www-user"
+#      Password "secret"
+#      CACert "/etc/ssl/ca.crt"
 #</Plugin>
 
 #<Plugin apcups>
-#      Host localhost
-#      Port 3551
+#      Host "localhost"
+#      Port "3551"
+#</Plugin>
+
+#<Plugin csv>
+#      DataDir "@prefix@/var/lib/@PACKAGE_NAME@/csv"
+#</Plugin>
+
+#<Plugin df>
+#      Device "/dev/hda1"
+#      Device "192.168.0.2:/mnt/nfs"
+#      MountPoint "/home"
+#      FSType "ext3"
+#      IgnoreSelected false
 #</Plugin>
 
 #<Plugin dns>
-#      Interface eth0
-#      IgnoreSource 192.168.0.1
+#      Interface "eth0"
+#      IgnoreSource "192.168.0.1"
+#</Plugin>
+
+#<Plugin email>
+#      SocketGroup "collectd"
+#      SocketPerms "0770"
+#      MaxConns 5
+#</Plugin>
+
+#<Plugin exec>
+#      Exec user "/path/to/exec"
 #</Plugin>
 
 #<Plugin hddtemp>
-#      Host 127.0.0.1
+#      Host "127.0.0.1"
 #      Port 7634
 #</Plugin>
 
+#<Plugin interface>
+#      Interface "eth0"
+#      IgnoreSelected false
+#</Plugin>
+
 #<Plugin iptables>
 #      Chain table chain
 #</Plugin>
 #      IgnoreSelected true
 #</Plugin>
 
+#<Plugin logfile>
+#      LogLevel info
+#      File STDOUT
+#</Plugin>
+
 #<Plugin mbmon>
-#      Host 127.0.0.1
+#      Host "127.0.0.1"
 #      Port 411
 #</Plugin>
 
+#<Plugin mysql>
+#      Host "database.serv.er"
+#      User "db_user"
+#      Password "secret"
+#      Database "db_name"
+#</Plugin>
+
+#<Plugin network>
+#      Server "ff18::efc0:4a42" "25826"
+#      Server "239.192.74.66" "25826"
+#      Listen "ff18::efc0:4a42" "25826"
+#      Listen "239.192.74.66" "25826"
+#      TimeToLive "128"
+#      Forward false
+#      CacheFlush 1800
+#</Plugin>
+
 #<Plugin ntpd>
-#      Host localhost
+#      Host "localhost"
 #      Port 123
 #</Plugin>
 
-#<Plugin mysql>
-#      Host database.serv.er
-#      User db_user
-#      Password secret
-#      Database db_name
+#<Plugin nut>
+#      UPS "upsname@hostname:port"
 #</Plugin>
 
 #<Plugin ping>
-#      Host host.foo.bar
+#      Host "host.foo.bar"
 #</Plugin>
 
 #<Plugin processes>
-#      Process name
+#      Process "name"
+#</Plugin>
+
+#<Plugin rrdtool>
+#      DataDir "@prefix@/var/lib/@PACKAGE_NAME@/rrd"
+#      StepSize      10
+#      HeartBeat     20
+#      RRARows     1200
+#      XFF            0.1
+#      CacheTimeout 120
+#      CacheFlush   900
 #</Plugin>
 
-## There are two different naming schemes for the sensors plugin, to preserver
-## backwards compatibility. The `extended naming' is prefered, but not the
-## default for this reason. See `collectd.conf(5)' for more information.
 #<Plugin sensors>
-#      ExtendedSensorNaming false
-#      Sensor it8712-temp1
-#      Sensor it8712-fan3
-#      Sensor it8712-in8
-## -- OR --
-#      ExtendedSensorNaming true
-#      Sensor it8712-isa-0290/temperature-temp1
-#      Sensor it8712-isa-0290/fanspeed-fan3
-#      Sensor it8712-isa-0290/voltage-in8
-#
+#      Sensor "it8712-isa-0290/temperature-temp1"
+#      Sensor "it8712-isa-0290/fanspeed-fan3"
+#      Sensor "it8712-isa-0290/voltage-in8"
 #      IgnoreSelected false
 #</Plugin>
 
-#<Plugin traffic>
-#      Interface eth0
-#      IgnoreSelected false
+#<Plugin syslog>
+#      LogLevel info
+#</Plugin>
+
+#<Plugin unixsock>
+#      SocketFile "@prefix@/var/run/@PACKAGE_NAME@-unixsock"
+#      SocketGroup "collectd"
+#      SocketPerms "0660"
 #</Plugin>
index 803df8b..07a49cc 100644 (file)
@@ -4,42 +4,43 @@ collectd.conf - Configuration for the system statistics collection daemon B<coll
 
 =head1 SYNOPSIS
 
-  Mode    Client
-  DataDir /path/to/data/
-  PIDFile /path/to/pidfile/collectd.pid
-  LogFile /path/to/logfile/collectd.log
-  Server  123.123.123.123 12345
+  BaseDir "/path/to/data/"
+  PIDFile "/path/to/pidfile/collectd.pid"
+  Server  "123.123.123.123" 12345
 
   LoadPlugin cpu
   LoadPlugin load
   LoadPlugin ping
 
   <Plugin ping>
-    Host example.org
-    Host provider.net
+    Host "example.org"
+    Host "provider.net"
   </Plugin>
 
 =head1 DESCRIPTION
 
 This config file controls how the system statistics collection daemon
-B<collectd> behaves. The most significant options are B<Mode>, which controlls
-if the daemon will act as client, server or will be independent in local mode,
-and B<LoadPlugin> which controls which plugins to load.
+B<collectd> behaves. The most significant option is B<LoadPlugin>, which
+controls which plugins to load. These plugins ultimately define collectd's
+behavior.
 
 The syntax of this config file is similar to the config file of the famos
 B<Apache Webserver>. Each line containes either a key-value-pair or a
 section-start or -end. Empty lines and everything after the hash-symbol `#' is
-ignored.
+ignored. Values are either string, enclosed in double-quotes,
+(floating-point-)numbers or a boolean extression, i.E<nbsp>e. either B<true> or
+B<false>. String containing of only alphanumeric characters and underscores do
+not need to be quoted.
 
 =head1 GLOBAL OPTIONS
 
 =over 4
 
-=item B<Mode> (B<Local>|B<Client>|B<Server>|B<Log>)
+=item B<BaseDir> I<Directory>
 
-Sets the operating mode. See the section B<MODES> in L<collectd(1)> for a
-description. This option determines which other options are allowed. Defaults
-to B<Local>.
+Sets the base directory. This is the directory beneath all RRD-files are
+created. Possibly more subdirectories are created. This is also the working
+directory for the daemon.
 
 =item B<LoadPlugin> I<Plugin>
 
@@ -50,52 +51,20 @@ will be mostly useless. The names of the plugins are listed in L<collectd(1)>.
 
 Sets where to write the PID file to. This file is overwritten when it exists
 and deleted when the program ist stopped. Some init-scripts might override this
-setting using the B<-P> commandline option. Available in B<all modes>.
-
-=item B<DataDir> I<Directory>
+setting using the B<-P> commandline option.
 
-Sets the data directory. This is the directory beneath all RRD-files are
-created. Possibly more subdirectories are created. This is also the working
-directory for the daemon. Available in B<all modes>, though the B<Client> mode
-won't write to this directory.
+=item B<Interval> I<Seconds>
 
-=item B<LogFile> I<File>
+Configures the interval in which to query the read plugins. Obviously smaller
+values lead to a higher system load produces by collectd, while higher values
+lead to more coarse statistics.
 
-Sets the file to write debugging output to. This is only used if compiled with
-debugging enabled. It's ignored otherwise. Available in B<all modes>.
+=item B<ReadThreads> I<Num>
 
-=item B<Listen> I<Host> [I<Port>]
-
-=item B<Server> I<Host> [I<Port>]
-
-In B<client mode> the B<Server> statement sets the server to send datagrams to.
-The statement may occur multiple times to send each datagram to multiple
-destinations.
-
-In B<server mode> the B<Listen> statement sets the interfaces to bind to. When
-multiple statements are found the daemon will bind to multiple interfaces.
-
-The argument I<Host> may be a hostname, an IPv4 address or an IPv6 address. If
-the argument is a multicast address the daemon will join that multicast group.
-
-If no B<Listen> statement is found the server tries join both, the IPv6
-multicast group and the IPv4 multicast group. If no B<Server> statement is
-found the client will try to send data to the IPv6 multicast group first. If
-that failes the client will try the IPv4 multicast group.
-
-The default IPv6 multicast group is C<ff18::efc0:4a42>. The default IPv4
-multicast group is C<239.192.74.66>.
-
-The optional I<Port> argument sets the port to use. It can either be given
-using a numeric port number or a service name. If the argument is omited the
-default port B<25826> is assumed.
-
-=item B<TimeToLive> I<1-255>
-
-Set the time-to-live of sent packets. This applies to all, unicast and
-multicast, and IPv4 and IPv6 packets. The default is to not change this value.
-That means that multicast packets will be sent with a TTL of C<1> (one) on most
-operating systems.
+Number of threads to start for reading plugins. The default value if B<5>, but
+you may want to increase this if you have more than five plugins that take a
+long time to read. Mostly those are plugin that do network-IO. Setting this to
+a value higher than the number of plugins you've loaded is totally useless.
 
 =back
 
@@ -164,6 +133,17 @@ TCP-Port to connect to. Defaults to B<3551>.
 
 =back
 
+=head2 Plugin C<csv>
+
+=over 4
+
+=item B<DataDir> I<Directory>
+
+Set the directory to store RRD-files under. Per default RRD-files are generated
+beneath the daemon's working directory, i.E<nbsp>e. the B<BaseDir>.
+
+=back
+
 =head2 Plugin C<df>
 
 =over 4
@@ -230,6 +210,20 @@ at most B<16384> to prevent typos and dumb mistakes.
 
 =back
 
+=head2 Plugin C<exec>
+
+Please make sure to read L<collectd/"SPECIAL PLUGINS"> before using this
+plugin. It containes valueable information on when the executable is executed
+and the output that is expected from it.
+
+=over 4
+
+=item B<Exec> I<User> I<Executable>
+
+Execute the executable I<Executable> as user I<User>.
+
+=back
+
 =head2 Plugin C<hddtemp>
 
 =over 4
@@ -244,6 +238,47 @@ TCP-Port to connect to. Defaults to B<7634>.
 
 =back
 
+=head2 Plugin C<interface>
+
+=over 4
+
+=item B<Interface> I<Interface>
+
+Select this interface. By default these interfaces will then be collected. For
+a more detailed description see B<IgnoreSelected> below.
+
+=item B<IgnoreSelected> I<true>|I<false>
+
+If no configuration if given, the B<traffic>-plugin will collect data from
+all interfaces. This may not be practical, especially for loopback- and
+similar interfaces. Thus, you can use the B<Interface>-option to pick the
+interfaces you're interested in. Sometimes, however, it's easier/prefered
+to collect all interfaces I<except> a few ones. This option enables you to
+do that: By setting B<IgnoreSelected> to I<true> the effect of
+B<Interface> is inversed: All selected interfaces are ignored and all
+other interfaces are collected.
+
+=back
+
+=head2 Plugin C<iptables>
+
+=over 4
+
+=item B<Chain> I<Table> I<Chain> [I<Comment|Number> [I<Name>]]
+
+Select the rules to count. If only I<Table> and I<Chain> are given, this plugin
+will collect the counters of all rules which have a comment-match. The comment
+is then used as type-instance.
+
+If I<Comment> or I<Number> is given, only the rule with the matching comment or
+the I<n>th rule will be collected. Again, the comment (or the number) will be
+used as the type-instance.
+
+If I<Name> is supplied, it will be used as the type-instance instead of the
+comment or the number.
+
+=back
+
 =head2 Plugin C<irq>
 
 =over 4
@@ -265,31 +300,35 @@ and all other interupts are collected.
 
 =back
 
-=head2 Plugin C<mbmon>
+=head2 Plugin C<logfile>
 
 =over 4
 
-=item B<Host> I<Hostname>
+=item B<LogLevel> B<debug|info|notice|warning|err>
 
-Hostname to connect to. Defaults to B<127.0.0.1>.
+Sets the log-level. If, for example, set to B<notice>, then all events with
+severity B<notice>, B<warning>, or B<err> will be written to the logfile.
 
-=item B<Port> I<Port>
+=item B<File> I<File>
 
-TCP-Port to connect to. Defaults to B<411>.
+Sets the file to write log messages to. The special strings B<stdout> and
+B<stderr> can be used to write to the standard output and standard error
+channels, respectively. This, of course, only makes much sense when collectd is
+running in foreground- or non-daemon-mode.
 
 =back
 
-=head2 Plugin C<ntpd>
+=head2 Plugin C<mbmon>
 
 =over 4
 
 =item B<Host> I<Hostname>
 
-Hostname of the host running B<ntpd>. Defaults to B<localhost>.
+Hostname to connect to. Defaults to B<127.0.0.1>.
 
 =item B<Port> I<Port>
 
-UDP-Port to connect to. Defaults to B<123>.
+TCP-Port to connect to. Defaults to B<411>.
 
 =back
 
@@ -316,6 +355,88 @@ option for what this plugin does.
 
 =back
 
+=head2 Plugin C<network>
+
+=over 4
+
+=item B<Listen> I<Host> [I<Port>]
+
+=item B<Server> I<Host> [I<Port>]
+
+The B<Server> statement sets the server to send datagrams B<to>.  The statement
+may occur multiple times to send each datagram to multiple destinations.
+
+The B<Listen> statement sets the interfaces to bind to. When multiple
+statements are found the daemon will bind to multiple interfaces.
+
+The argument I<Host> may be a hostname, an IPv4 address or an IPv6 address. If
+the argument is a multicast address the daemon will join that multicast group.
+
+If no B<Listen> statement is found the server tries join both, the default IPv6
+multicast group and the default IPv4 multicast group. If no B<Server> statement
+is found the client will try to send data to the IPv6 multicast group first. If
+that failes the client will try the IPv4 multicast group.
+
+The default IPv6 multicast group is C<ff18::efc0:4a42>. The default IPv4
+multicast group is C<239.192.74.66>.
+
+The optional I<Port> argument sets the port to use. It can either be given
+using a numeric port number or a service name. If the argument is omited the
+default port B<25826> is assumed.
+
+=item B<TimeToLive> I<1-255>
+
+Set the time-to-live of sent packets. This applies to all, unicast and
+multicast, and IPv4 and IPv6 packets. The default is to not change this value.
+That means that multicast packets will be sent with a TTL of C<1> (one) on most
+operating systems.
+
+=item B<Forward> I<true|false>
+
+If set to I<true>, write packets that were received via the network plugin to
+the sending sockets. This should only be activated when the B<Listen>- and
+B<Server>-statements differ. Otherwise packets may be send multiple times to
+the same multicast group. While this results in more network traffic than
+neccessary it's not a huge problem since the plugin has a duplicate detection,
+so the values will not loop.
+
+=item B<CacheFlush> I<Seconds>
+
+For each host/plugin/type combination the C<network plugin> caches the time of
+the last value being sent or received. Every I<Seconds> seconds the plugin
+searches and removes all entries that are older than I<Seconds> seconds, thus
+freeing the unused memory again. Since this process is somewhat expensive and
+normally doesn't do much, this value should not be too small. The default is
+1800 seconds, but setting this to 86400 seconds (one day) will not do much harm
+either.
+
+=back
+
+=head2 Plugin C<ntpd>
+
+=over 4
+
+=item B<Host> I<Hostname>
+
+Hostname of the host running B<ntpd>. Defaults to B<localhost>.
+
+=item B<Port> I<Port>
+
+UDP-Port to connect to. Defaults to B<123>.
+
+=back
+
+=head2 Plugin C<nut>
+
+=over 4
+
+=item B<UPS> I<upsname>B<@>I<hostname>[B<:>I<port>]
+
+Add a UPS to collect data from. The format is identical to the one accepted by
+L<upsc(8)>.
+
+=back
+
 =head2 Plugin C<ping>
 
 =over 4
@@ -331,86 +452,140 @@ Sets the Time-To-Live of generated ICMP packets.
 
 =back
 
+=head2 Plugin C<processes>
+
+=over 4
+
+=item B<Process> I<Name>
+
+Select more detailed statistics of processes matching this name. The statistics
+collected for these selected processes are size of the resident segment size
+(RSS), user- and system-time used, number of processes and number of threads,
+and minor and major pagefaults.
+
+=back
+
+=head2 Plugin C<rrdtool>
+
+You can use the settings B<StepSize>, B<HeartBeat>, B<RRARows>, and B<XFF> to
+finetune your RRD-files. Please read L<rrdcreate(1)> if you encounter problems
+using these settings. If you don't want to dive into the depths of RRDTool, you
+can savely ignore these settings.
+
+=over 4
+
+=item B<DataDir> I<Directory>
+
+Set the directory to store CSV-files under. Per default CSV-files are generated
+beneath the daemon's working directory, i.E<nbsp>e. the B<BaseDir>.
+
+=item B<StepSize> I<Seconds>
+
+Sets the stepsize of newly created RRD-files. Ideally (and per default) this
+setting is identical to the global B<Interval>-option and should not be
+smaller. If unsure, don't set this option.
+
+=item B<HeartBeat> I<Seconds>
+
+Sets the heartbeat of newly created RRD-files. Ideally this setting is bigger
+than the B<Interval>-setting, by default it's twice the B<Interval>-setting. If
+unsure, don't set this option.
+
+=item B<RRARows> I<NumRows>
+
+The C<rrdtool plugin> calculates the number of PDPs per CDP based on the
+B<StepSize>, this setting and a timespan. This plugin creates RRD-files with
+three times five RRAs, i. e. five RRAs with the CFs B<MIN>, B<AVERAGE>, and
+B<MAX>. The five RRAs are optimized for graphs covering one hour, one day, one
+week, one month, and one year.
+
+So for each timespan, it calculates how many PDPs need to be consolidated into
+one CDP by calculating:
+  number of PDPs = timespan / (stepsize * rrarows)
+
+Bottom line is, set this no smaller than the width of you graphs in pixels. The
+default is 1200.
+
+=item B<XFF> I<Factor>
+
+Set the "XFiles Factor". The default is 0.1. If unsure, don't set this option.
+
+=item B<CacheFlush> I<Seconds>
+
+When the C<rrdtool plugin> uses a cache (by setting B<CacheTimeout>, see below)
+it writes all values for a certain RRD-file if the oldest value is older than
+(or equal to) the number of seconds specified. If some RRD-file is not updated
+anymore for some reason (the computer was shut down, the network is broken,
+etc.) some values may still be in the cache. If B<CacheFlush> is set, then the
+entire cache is searched for entries older than B<CacheTimeout> seconds and
+written to disk every I<Seconds> seconds. Since this is kind of expensive and
+does nothing under normal circumstances, this value should not be too small.
+900 seconds might be a good value, though setting this to 7200 seconds doesn't
+normally do much harm either.
+
+=item B<CacheTimeout> I<Seconds>
+
+If this option is set to a value greater than zero, the C<rrdtool plugin> will
+save values in a cache, as described above. Writing multiple values at once
+reduces IO-operations and thus lessens the load produced by updating the files.
+The tradeoff is that the graphs kind of "drag behind" and that more memory is
+used.
+
+=back
+
 =head2 Plugin C<sensors>
 
 =over 4
 
-=item B<ExtendedSensorNaming> I<true>|I<false>
-
-If set to I<true> this option switches on the extended sensors and RRD-files
-naming. This option exists to preserve backwards compatibility. It is
-recommended that you set this option to I<true>. The default is I<false> to
-maintain compatibility only.
-
-Sensors get names like I<chip-bus-address/type-feature> (e.g.
-I<it8712-isa-0290/voltage-in1>) and RRD files are therefore stored in a
-standalone directory inside the B<DataDir> directory and get names like
-I<lm_sensors-chip-bus-address/type-feature.rrd> (e.g.
-I<lm_sensors-it8712-isa-0290/voltage-in1.rrd>).
-
-The B<ExtendedSensorNaming> option breaks the compatibility with previous
-sensors and RRD files naming and the place where RRDs are stored. If you turn
-it on, the plugin will create new RRD files in a standalone directory inside
-the B<DataDir> directory and without previous history. You can rename ``old''
-RRD-files to preserve already collected statistics, because the file layout
-hasn't changed. If you have two chips of the same type, you need to use
-B<ExtendedSensorNaming> in order to collect information from both chips.
-
-If not set or set to I<false>, the extended naming is not active. Sensors get
-names like I<chip-feature> (e.g. I<it8712-in1>) and RRD files are stored in the
-main B<DataDir> directory and get names like I<sensors-chip-feature.rrd> (e.g.
-I<sensors-it8712-in1.rrd>).  You simply continue using the plugin the old way
-and additionally also getting data for newly added sensors in this mode.
-
-=item B<Sensor> I<chip-feature> or B<Sensor> I<chip-bus-address/type-feature>
-
-Both option modes select the name of the sensor which you want to collect.
-The naming scheme is dependent on the state of the B<ExtendedSensorNaming>
-option (see previous option). Both option modes can also deselect the
-sensor according to the B<IgnoreSelected> option (see below).
-
-For example the option "B<Sensor> I<it8712-in1>" will cause the collectd
-to gather data for the voltage sensor I<in1> of the I<it8712> chip in case
-of the B<ExtendedSensorNaming> option is set to I<false>.
-
-And likewise the option "B<Sensor> I<it8712-isa-0290/voltage-in1>" will
-cause the collectd to gather data for the voltage sensor I<in1> of the I<it8712>
-on the isa bus at the address 0290 in case of the B<ExtendedSensorNaming>
-option set to I<true>.
+=item B<Sensor> I<chip-bus-address/type-feature>
+
+Selects the name of the sensor which you want to collect or ignore, depending
+on the B<IgnoreSelected> below. For example, the option "B<Sensor>
+I<it8712-isa-0290/voltage-in1>" will cause collectd to gather data for the
+voltage sensor I<in1> of the I<it8712> on the isa bus at the address 0290.
 
 =item B<IgnoreSelected> I<true>|I<false>
 
-If no configuration if given, the B<sensors>-plugin will collect data from
-all sensors. This may not be practical, especially for uninteresting sensors.
-Thus, you can use the B<Sensor>-option to pick the sensors you're
-interested in. Sometimes, however, it's easier/prefered to collect all
-sensors I<except> a few ones. This option enables you to
-do that: By setting B<IgnoreSelected> to I<true> the effect of
-B<Sensor> is inversed: All selected sensors are ignored and all
-other sensors are collected.
+If no configuration if given, the B<sensors>-plugin will collect data from all
+sensors. This may not be practical, especially for uninteresting sensors.
+Thus, you can use the B<Sensor>-option to pick the sensors you're interested
+in. Sometimes, however, it's easier/prefered to collect all sensors I<except> a
+few ones. This option enables you to do that: By setting B<IgnoreSelected> to
+I<true> the effect of B<Sensor> is inversed: All selected sensors are ignored
+and all other sensors are collected.
 
-back
+=back
+
+=head2 Plugin C<syslog>
+
+=over 4
+
+=item B<LogLevel> B<debug|info|notice|warning|err>
+
+Sets the log-level. If, for example, set to B<notice>, then all events with
+severity B<notice>, B<warning>, or B<err> will be submitted to the
+syslog-daemon.
 
 =back
 
-=head2 Plugin C<traffic>
+=head2 Plugin C<unixsock>
 
 =over 4
 
-=item B<Interface> I<Interface>
+=item B<SocketFile> I<Path>
 
-Select this interface. By default these interfaces will then be collected. For a more detailed description see B<IgnoreSelected> below.
+Sets the socket-file which is to be created.
 
-=item B<IgnoreSelected> I<true>|I<false>
+=item B<SocketGroup> I<Group>
 
-If no configuration if given, the B<traffic>-plugin will collect data from
-all interfaces. This may not be practical, especially for loopback- and
-similar interfaces. Thus, you can use the B<Interface>-option to pick the
-interfaces you're interested in. Sometimes, however, it's easier/prefered
-to collect all interfaces I<except> a few ones. This option enables you to
-do that: By setting B<IgnoreSelected> to I<true> the effect of
-B<Interface> is inversed: All selected interfaces are ignored and all
-other interfaces are collected.
+If running as root change the group of the UNIX-socket after it has been 
+created. Defaults to B<collectd>.
+
+=item B<SocketPerms> I<Permissions>
+
+Change the file permissions of the UNIX-socket after it has been created. The
+permissions must be given as a numeric, octal value as you would pass to
+L<chmod(1)>. Defaults to B<0770>.
 
 =back
 
index a5c8169..e1ce97c 100644 (file)
@@ -4,8 +4,7 @@
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -78,9 +77,6 @@
 #if HAVE_ERRNO_H
 # include <errno.h>
 #endif
-#if HAVE_SYSLOG_H
-# include <syslog.h>
-#endif
 #if HAVE_LIMITS_H
 # include <limits.h>
 #endif
 # define assert(...) /* nop */
 #endif
 
+#if NAN_STATIC_DEFAULT
+# include <math.h>
+/* #endif NAN_STATIC_DEFAULT*/
+#elif NAN_STATIC_ISOC
+# ifndef __USE_ISOC99
+#  define DISABLE_ISOC99 1
+#  define __USE_ISOC99 1
+# endif /* !defined(__USE_ISOC99) */
+# include <math.h>
+# if DISABLE_ISOC99
+#  undef DISABLE_ISOC99
+#  undef __USE_ISOC99
+# endif /* DISABLE_ISOC99 */
+/* #endif NAN_STATIC_ISOC */
+#elif NAN_ZERO_ZERO
+# include <math.h>
+# define NAN (0.0 / 0.0)
+# ifndef isnan
+#  define isnan(f) ((f) != (f))
+# endif /* !defined(isnan) */
+#endif /* NAN_ZERO_ZERO */
+
 #if HAVE_DIRENT_H
 # include <dirent.h>
 # define NAMLEN(dirent) strlen((dirent)->d_name)
 # include <sys/param.h>
 #endif
 
-#if !HAVE_SYSLOG
-# define syslog(...) /**/
-# define openlog(...) /**/
-# define closelog(...) /**/
-#endif
-
 #if HAVE_KSTAT_H
 # include <kstat.h>
 #endif
 #define PIDFILE PREFIX "/var/run/" PACKAGE_NAME ".pid"
 #endif
 
-#ifndef LOGFILE
-#define LOGFILE PREFIX"/var/log/"PACKAGE_NAME"/"PACKAGE_NAME".log"
-#endif
-
 #ifndef PLUGINDIR
 #define PLUGINDIR PREFIX "/lib/" PACKAGE_NAME
 #endif
 # define COLLECTD_GRP_NAME "collectd"
 #endif
 
-#ifndef COLLECTD_STEP
-#  define COLLECTD_STEP "10"
-#endif
-
-#ifndef COLLECTD_HEARTBEAT
-#  define COLLECTD_HEARTBEAT "25"
-#endif
-
-#ifndef COLLECTD_ROWS
-#  define COLLECTD_ROWS "1200"
-#endif
-
-#ifndef COLLECTD_XFF
-#  define COLLECTD_XFF 0.1
-#endif
-
-extern time_t curtime;
-
-#ifdef HAVE_LIBRRD
-extern int operating_mode;
-#endif
+#define STATIC_ARRAY_LEN(array) (sizeof (array) / sizeof ((array)[0]))
 
-/* int main (int argc, char **argv); */
+extern char hostname_g[];
+extern int  interval_g;
 
 #endif /* COLLECTD_H */
index 96c3fcd..bc65f57 100644 (file)
@@ -219,6 +219,39 @@ Successful spam checks (e.g. "BAYES_99", "SUBJECT_DRUG_GAP_C", ...):
 Each line is limited to 256 characters (including the newline character). 
 Longer lines will be ignored.
 
+=head2 exec
+
+The C<exec> plugin forks of an executable and reads back values that it writes
+to C<STDOUT>. The executable is forked kind of as L<init> does: It is forked
+once and not again until it exits. If it exited, it will be forked again after
+at most I<Interval> seconds. It is perfectly legal for the executable to run
+for a long time and continuously write values to C<STDOUT>.
+
+The forked executable is expected to print values to C<STDOUT>. The expected
+format is as follows:
+
+=over 4
+
+=item
+
+Each line beginning with a C<#> (hash mark) is ignored.
+
+=item
+
+Any other line must be of the form C<I<type>,I<type-instance>,I<value>>, where
+I<type> is either B<counter> or B<gauge>, I<type-instance> may not contain
+C<,> (comma), C</> (slash) and C<\0> (null byte) and I<value> is either an
+integer (if I<type> is B<counter>) or a floating-point number (if I<type> is
+B<gauge>).
+
+=back
+
+The values are always considered to be "fresh", i.E<nbsp>e. the time is set to
+"now".
+
+When collectd exits it sends a B<SIGTERM> to all still running
+child-processes upon which they have to quit.
+
 =head2 mysql
 
 Requires B<mysqlclient> to be installed. It connects to the database when
index 5487b32..6521a58 100644 (file)
@@ -1,21 +1,19 @@
 /**
  * collectd - src/common.c
- * Copyright (C) 2005,2006  Florian octo Forster
+ * Copyright (C) 2005-2007  Florian octo Forster
  *
- * This program is free software; you can redistribute it and/
- * or modify it under the terms of the GNU General Public Li-
- * cence as published by the Free Software Foundation; either
- * version 2 of the Licence, or any later version.
+ * 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; only version 2 of the License is applicable.
  *
- * This program is distributed in the hope that it will be use-
- * ful, but WITHOUT ANY WARRANTY; without even the implied war-
- * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public Licence for more details.
+ * 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
- * Licence along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
  *   Florian octo Forster <octo at verplant.org>
 **/
 
 #include "common.h"
-#include "utils_debug.h"
+#include "plugin.h"
 
 #ifdef HAVE_MATH_H
 #  include <math.h>
 #endif
 
-extern int operating_mode;
+/* for ntohl and htonl */
+#if HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
 
 #ifdef HAVE_LIBKSTAT
 extern kstat_ctl_t *kc;
 #endif
 
-#ifdef HAVE_LIBRRD
-#if 0
-static char *rra_def[] =
-{
-               "RRA:AVERAGE:0.0:1:1500",
-               "RRA:AVERAGE:0.2:6:1500",
-               "RRA:AVERAGE:0.1:180:1680",
-               "RRA:AVERAGE:0.1:2160:1520",
-               "RRA:MIN:0.0:1:1500",
-               "RRA:MIN:0.2:6:1500",
-               "RRA:MIN:0.1:180:1680",
-               "RRA:MIN:0.1:2160:1520",
-               "RRA:MAX:0.0:1:1500",
-               "RRA:MAX:0.2:6:1500",
-               "RRA:MAX:0.1:180:1680",
-               "RRA:MAX:0.1:2160:1520",
-               NULL
-};
-static int rra_num = 12;
-#endif
-
-static int rra_timespans[] =
-{
-       3600,
-       86400,
-       604800,
-       2678400,
-       31622400,
-       0
-};
-static int rra_timespans_num = 5;
-
-static char *rra_types[] =
-{
-       "AVERAGE",
-       "MIN",
-       "MAX",
-       NULL
-};
-static int rra_types_num = 3;
-#endif /* HAVE_LIBRRD */
-
 void sstrncpy (char *d, const char *s, int len)
 {
        strncpy (d, s, len);
@@ -92,20 +51,29 @@ char *sstrdup (const char *s)
 
        if((r = strdup (s)) == NULL)
        {
-               DBG ("Not enough memory.");
+               DEBUG ("Not enough memory.");
                exit(3);
        }
 
        return (r);
 }
 
+/* Don't use the return value of `strerror_r', because the GNU-people got
+ * inventive there.. -octo */
+char *sstrerror (int errnum, char *buf, size_t buflen)
+{
+       buf[0] = '\0';
+       strerror_r (errnum, buf, buflen);
+       return (buf);
+} /* char *sstrerror */
+
 void *smalloc (size_t size)
 {
        void *r;
 
        if ((r = malloc (size)) == NULL)
        {
-               DBG("Not enough memory.");
+               DEBUG("Not enough memory.");
                exit(3);
        }
 
@@ -146,7 +114,7 @@ ssize_t sread (int fd, void *buf, size_t count)
 
                if (status == 0)
                {
-                       DBG ("Received EOF from fd %i. "
+                       DEBUG ("Received EOF from fd %i. "
                                        "Closing fd and returning error.",
                                        fd);
                        close (fd);
@@ -193,10 +161,12 @@ int strsplit (char *string, char **fields, size_t size)
 {
        size_t i;
        char *ptr;
+       char *saveptr;
 
        i = 0;
        ptr = string;
-       while ((fields[i] = strtok (ptr, " \t")) != NULL)
+       saveptr = NULL;
+       while ((fields[i] = strtok_r (ptr, " \t", &saveptr)) != NULL)
        {
                ptr = NULL;
                i++;
@@ -320,7 +290,7 @@ int timeval_sub_timespec (struct timeval *tv0, struct timeval *tv1, struct times
        return (0);
 }
 
-static int check_create_dir (const char *file_orig)
+int check_create_dir (const char *file_orig)
 {
        struct stat statbuf;
 
@@ -330,7 +300,9 @@ static int check_create_dir (const char *file_orig)
        char *fields[16];
        int   fields_num;
        char *ptr;
+       char *saveptr;
        int   last_is_file = 1;
+       int   path_is_absolute = 0;
        int   len;
        int   i;
 
@@ -351,9 +323,11 @@ static int check_create_dir (const char *file_orig)
         */
        if (file_orig[len - 1] == '/')
                last_is_file = 0;
+       if (file_orig[0] == '/')
+               path_is_absolute = 1;
 
        /*
-        * Create a copy for `strtok' to destroy
+        * Create a copy for `strtok_r' to destroy
         */
        strncpy (file_copy, file_orig, 512);
        file_copy[511] = '\0';
@@ -363,8 +337,9 @@ static int check_create_dir (const char *file_orig)
         * remove leading and trailing slashes..
         */
        ptr = file_copy;
+       saveptr = NULL;
        fields_num = 0;
-       while ((fields[fields_num] = strtok (ptr, "/")) != NULL)
+       while ((fields[fields_num] = strtok_r (ptr, "/", &saveptr)) != NULL)
        {
                ptr = NULL;
                fields_num++;
@@ -385,16 +360,18 @@ static int check_create_dir (const char *file_orig)
                 */
                if (fields[i][0] == '.')
                {
-                       syslog (LOG_ERR, "Cowardly refusing to create a directory that begins with a `.' (dot): `%s'", file_orig);
+                       ERROR ("Cowardly refusing to create a directory that begins with a `.' (dot): `%s'", file_orig);
                        return (-2);
                }
 
                /*
                 * Join the components together again
                 */
-               if (strjoin (dir, dir_len, fields, i + 1, "/") < 0)
+               dir[0] = '/';
+               if (strjoin (dir + path_is_absolute, dir_len - path_is_absolute,
+                                       fields, i + 1, "/") < 0)
                {
-                       syslog (LOG_ERR, "strjoin failed: `%s', component #%i", file_orig, i);
+                       ERROR ("strjoin failed: `%s', component #%i", file_orig, i);
                        return (-1);
                }
 
@@ -404,19 +381,25 @@ static int check_create_dir (const char *file_orig)
                        {
                                if (mkdir (dir, 0755) == -1)
                                {
-                                       syslog (LOG_ERR, "mkdir (%s): %s", dir, strerror (errno));
+                                       char errbuf[1024];
+                                       ERROR ("mkdir (%s): %s", dir,
+                                                       sstrerror (errno,
+                                                               errbuf, sizeof (errbuf)));
                                        return (-1);
                                }
                        }
                        else
                        {
-                               syslog (LOG_ERR, "stat (%s): %s", dir, strerror (errno));
+                               char errbuf[1024];
+                               ERROR ("stat (%s): %s", dir,
+                                               sstrerror (errno, errbuf,
+                                                       sizeof (errbuf)));
                                return (-1);
                        }
                }
                else if (!S_ISDIR (statbuf.st_mode))
                {
-                       syslog (LOG_ERR, "stat (%s): Not a directory!", dir);
+                       ERROR ("stat (%s): Not a directory!", dir);
                        return (-1);
                }
        }
@@ -424,338 +407,6 @@ static int check_create_dir (const char *file_orig)
        return (0);
 }
 
-/* * * * *
- * Magic *
- * * * * */
-#if HAVE_LIBRRD
-static int rra_get (char ***ret)
-{
-       static char **rra_def = NULL;
-       static int rra_num = 0;
-
-       int rra_max = rra_timespans_num * rra_types_num;
-
-       int step;
-       int rows;
-       int span;
-
-       int cdp_num;
-       int cdp_len;
-       int i, j;
-
-       char buffer[64];
-
-       if ((rra_num != 0) && (rra_def != NULL))
-       {
-               *ret = rra_def;
-               return (rra_num);
-       }
-
-       if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
-               return (-1);
-       memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
-
-       step = atoi (COLLECTD_STEP);
-       rows = atoi (COLLECTD_ROWS);
-
-       if ((step <= 0) || (rows <= 0))
-       {
-               *ret = NULL;
-               return (-1);
-       }
-
-       cdp_len = 0;
-       for (i = 0; i < rra_timespans_num; i++)
-       {
-               span = rra_timespans[i];
-
-               if ((span / step) < rows)
-                       continue;
-
-               if (cdp_len == 0)
-                       cdp_len = 1;
-               else
-                       cdp_len = (int) floor (((double) span) / ((double) (rows * step)));
-
-               cdp_num = (int) ceil (((double) span) / ((double) (cdp_len * step)));
-
-               for (j = 0; j < rra_types_num; j++)
-               {
-                       if (rra_num >= rra_max)
-                               break;
-
-                       if (snprintf (buffer, sizeof(buffer), "RRA:%s:%3.1f:%u:%u",
-                                               rra_types[j], COLLECTD_XFF,
-                                               cdp_len, cdp_num) >= sizeof (buffer))
-                       {
-                               syslog (LOG_ERR, "rra_get: Buffer would have been truncated.");
-                               continue;
-                       }
-
-                       rra_def[rra_num++] = sstrdup (buffer);
-               }
-       }
-
-#if COLLECT_DEBUG
-       DBG ("rra_num = %i", rra_num);
-       for (i = 0; i < rra_num; i++)
-               DBG ("  %s", rra_def[i]);
-#endif
-
-       *ret = rra_def;
-       return (rra_num);
-}
-#endif /* HAVE_LIBRRD */
-
-static int log_create_file (char *filename, char **ds_def, int ds_num)
-{
-       FILE *log;
-       int i;
-
-       if (check_create_dir (filename))
-               return (-1);
-
-       log = fopen (filename, "w");
-       if (log == NULL)
-       {
-               syslog (LOG_WARNING, "Failed to create %s: %s", filename,
-                               strerror(errno));
-               return (-1);
-       }
-
-       fprintf (log, "epoch");
-       for (i = 0; i < ds_num; i++)
-       {
-               char *name;
-               char *tmp;
-
-               name = strchr (ds_def[i], ':');
-               if (name == NULL)
-               {
-                       syslog (LOG_WARNING, "Invalid DS definition '%s' for %s",
-                                       ds_def[i], filename);
-                       fclose(log);
-                       remove(filename);
-                       return (-1);
-               }
-
-               name += 1;
-               tmp = strchr (name, ':');
-               if (tmp == NULL)
-               {
-                       syslog (LOG_WARNING, "Invalid DS definition '%s' for %s",
-                                       ds_def[i], filename);
-                       fclose(log);
-                       remove(filename);
-                       return (-1);
-               }
-
-               /* The `%.*s' is needed because there is no null-byte behind
-                * the name. */
-               fprintf(log, ",%.*s", (int) (tmp - name), name);
-       }
-       fprintf(log, "\n");
-       fclose(log);
-
-       return 0;
-}
-
-static int log_update_file (char *host, char *file, char *values,
-               char **ds_def, int ds_num)
-{
-       char *tmp;
-       FILE *fp;
-       struct stat statbuf;
-       char full_file[1024];
-
-       /* Cook the values a bit: Substitute colons with commas */
-       strsubstitute (values, ':', ',');
-
-       /* host == NULL => local mode */
-       if (host != NULL)
-       {
-               if (snprintf (full_file, 1024, "%s/%s", host, file) >= 1024)
-                       return (-1);
-       }
-       else
-       {
-               if (snprintf (full_file, 1024, "%s", file) >= 1024)
-                       return (-1);
-       }
-
-       strncpy (full_file, file, 1024);
-
-       tmp = full_file + strlen (full_file) - 4;
-       assert ((tmp != NULL) && (tmp > full_file));
-
-       /* Change the filename for logfiles. */
-       if (strncmp (tmp, ".rrd", 4) == 0)
-       {
-               time_t now;
-               struct tm *tm;
-
-               /* TODO: Find a way to minimize the calls to `localtime', since
-                * they are pretty expensive.. */
-               now = time (NULL);
-               tm = localtime (&now);
-
-               strftime (tmp, 1024 - (tmp - full_file), "-%Y-%m-%d", tm);
-
-               /* `localtime(3)' returns a pointer to static data,
-                * therefore the pointer may not be free'd. */
-       }
-       else
-               DBG ("The filename ends with `%s' which is unexpected.", tmp);
-
-       if (stat (full_file, &statbuf) == -1)
-       {
-               if (errno == ENOENT)
-               {
-                       if (log_create_file (full_file, ds_def, ds_num))
-                               return (-1);
-               }
-               else
-               {
-                       syslog (LOG_ERR, "stat %s: %s", full_file, strerror (errno));
-                       return (-1);
-               }
-       }
-       else if (!S_ISREG (statbuf.st_mode))
-       {
-               syslog (LOG_ERR, "stat %s: Not a regular file!", full_file);
-               return (-1);
-       }
-
-
-       fp = fopen (full_file, "a");
-       if (fp == NULL)
-       {
-               syslog (LOG_WARNING, "Failed to append to %s: %s", full_file,
-                               strerror(errno));
-               return (-1);
-       }
-       fprintf(fp, "%s\n", values);
-       fclose(fp);
-
-       return (0);
-} /* int log_update_file */
-
-#if HAVE_LIBRRD
-static int rrd_create_file (char *filename, char **ds_def, int ds_num)
-{
-       char **argv;
-       int argc;
-       char **rra_def;
-       int rra_num;
-       int i, j;
-       int status = 0;
-
-       if (check_create_dir (filename))
-               return (-1);
-
-       if ((rra_num = rra_get (&rra_def)) < 1)
-       {
-               syslog (LOG_ERR, "rra_create failed: Could not calculate RRAs");
-               return (-1);
-       }
-
-       argc = ds_num + rra_num + 4;
-
-       if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
-       {
-               syslog (LOG_ERR, "rrd_create failed: %s", strerror (errno));
-               return (-1);
-       }
-
-       argv[0] = "create";
-       argv[1] = filename;
-       argv[2] = "-s";
-       argv[3] = COLLECTD_STEP;
-
-       j = 4;
-       for (i = 0; i < ds_num; i++)
-               argv[j++] = ds_def[i];
-       for (i = 0; i < rra_num; i++)
-               argv[j++] = rra_def[i];
-       argv[j] = NULL;
-
-       optind = 0; /* bug in librrd? */
-       rrd_clear_error ();
-       if (rrd_create (argc, argv) == -1)
-       {
-               syslog (LOG_ERR, "rrd_create failed: %s: %s", filename, rrd_get_error ());
-               status = -1;
-       }
-
-       free (argv);
-
-       return (status);
-}
-#endif /* HAVE_LIBRRD */
-
-int rrd_update_file (char *host, char *file, char *values,
-               char **ds_def, int ds_num)
-{
-#if HAVE_LIBRRD
-       struct stat statbuf;
-       char full_file[1024];
-       char *argv[4] = { "update", full_file, values, NULL };
-#endif /* HAVE_LIBRRD */
-
-       /* I'd rather have a function `common_update_file' to make this
-        * decission, but for that we'd need to touch all plugins.. */
-       if (operating_mode == MODE_LOG)
-               return (log_update_file (host, file, values,
-                                       ds_def, ds_num));
-
-#if HAVE_LIBRRD
-       /* host == NULL => local mode */
-       if (host != NULL)
-       {
-               if (snprintf (full_file, 1024, "%s/%s", host, file) >= 1024)
-                       return (-1);
-       }
-       else
-       {
-               if (snprintf (full_file, 1024, "%s", file) >= 1024)
-                       return (-1);
-       }
-
-       if (stat (full_file, &statbuf) == -1)
-       {
-               if (errno == ENOENT)
-               {
-                       if (rrd_create_file (full_file, ds_def, ds_num))
-                               return (-1);
-               }
-               else
-               {
-                       syslog (LOG_ERR, "stat %s: %s", full_file, strerror (errno));
-                       return (-1);
-               }
-       }
-       else if (!S_ISREG (statbuf.st_mode))
-       {
-               syslog (LOG_ERR, "stat %s: Not a regular file!", full_file);
-               return (-1);
-       }
-
-       optind = 0; /* bug in librrd? */
-       rrd_clear_error ();
-       if (rrd_update (3, argv) == -1)
-       {
-               syslog (LOG_WARNING, "rrd_update failed: %s: %s", full_file, rrd_get_error ());
-               return (-1);
-       }
-       return (0);
-/* #endif HAVE_LIBRRD */
-
-#else
-       syslog (LOG_ERR, "`rrd_update_file' was called, but collectd isn't linked against librrd!");
-       return (-1);
-#endif
-}
-
 #ifdef HAVE_LIBKSTAT
 int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
 {
@@ -771,13 +422,13 @@ int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
        {
                if ((*ksp_ptr = kstat_lookup (kc, module, instance, name)) == NULL)
                {
-                       syslog (LOG_ERR, "Cound not find kstat %s", ident);
+                       ERROR ("Cound not find kstat %s", ident);
                        return (-1);
                }
 
                if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
                {
-                       syslog (LOG_WARNING, "kstat %s has wrong type", ident);
+                       WARNING ("kstat %s has wrong type", ident);
                        *ksp_ptr = NULL;
                        return (-1);
                }
@@ -790,13 +441,13 @@ int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
 
        if (kstat_read (kc, *ksp_ptr, NULL) == -1)
        {
-               syslog (LOG_WARNING, "kstat %s could not be read", ident);
+               WARNING ("kstat %s could not be read", ident);
                return (-1);
        }
 
        if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
        {
-               syslog (LOG_WARNING, "kstat %s has wrong type", ident);
+               WARNING ("kstat %s has wrong type", ident);
                return (-1);
        }
 
@@ -836,8 +487,63 @@ long long get_kstat_value (kstat_t *ksp, char *name)
        else if (kn->data_type == KSTAT_DATA_UINT64)
                retval = (long long) kn->value.ui64; /* XXX: Might overflow! */
        else
-               syslog (LOG_WARNING, "get_kstat_value: Not a numeric value: %s", name);
+               WARNING ("get_kstat_value: Not a numeric value: %s", name);
                 
        return (retval);
 }
 #endif /* HAVE_LIBKSTAT */
+
+unsigned long long ntohll (unsigned long long n)
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+       return (n);
+#else
+       return (((unsigned long long) ntohl (n)) << 32) + ntohl (n >> 32);
+#endif
+} /* unsigned long long ntohll */
+
+unsigned long long htonll (unsigned long long n)
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+       return (n);
+#else
+       return (((unsigned long long) htonl (n)) << 32) + htonl (n >> 32);
+#endif
+} /* unsigned long long htonll */
+
+int format_name (char *ret, int ret_len,
+               const char *hostname,
+               const char *plugin, const char *plugin_instance,
+               const char *type, const char *type_instance)
+{
+       int  status;
+
+       assert (plugin != NULL);
+       assert (type != NULL);
+
+       if ((plugin_instance == NULL) || (strlen (plugin_instance) == 0))
+       {
+               if ((type_instance == NULL) || (strlen (type_instance) == 0))
+                       status = snprintf (ret, ret_len, "%s/%s/%s",
+                                       hostname, plugin, type);
+               else
+                       status = snprintf (ret, ret_len, "%s/%s/%s-%s",
+                                       hostname, plugin, type,
+                                       type_instance);
+       }
+       else
+       {
+               if ((type_instance == NULL) || (strlen (type_instance) == 0))
+                       status = snprintf (ret, ret_len, "%s/%s-%s/%s",
+                                       hostname, plugin, plugin_instance,
+                                       type);
+               else
+                       status = snprintf (ret, ret_len, "%s/%s-%s/%s-%s",
+                                       hostname, plugin, plugin_instance,
+                                       type, type_instance);
+       }
+
+       if ((status < 1) || (status >= ret_len))
+               return (-1);
+       return (0);
+} /* int format_name */
index 2be2ff5..6c097f6 100644 (file)
@@ -1,21 +1,19 @@
 /**
  * collectd - src/common.h
- * Copyright (C) 2005,2006  Florian octo Forster
+ * Copyright (C) 2005-2007  Florian octo Forster
  *
- * This program is free software; you can redistribute it and/
- * or modify it under the terms of the GNU General Public Li-
- * cence as published by the Free Software Foundation; either
- * version 2 of the Licence, or any later version.
+ * 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; only version 2 of the License is applicable.
  *
- * This program is distributed in the hope that it will be use-
- * ful, but WITHOUT ANY WARRANTY; without even the implied war-
- * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public Licence for more details.
+ * 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
- * Licence along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
  *   Florian octo Forster <octo at verplant.org>
        } \
        (ptr) = NULL
 
+#define STATIC_ARRAY_SIZE(a) (sizeof (a) / sizeof (*(a)))
+
 void sstrncpy(char *d, const char *s, int len);
 char *sstrdup(const char *s);
 void *smalloc(size_t size);
+char *sstrerror (int errnum, char *buf, size_t buflen);
 
 /*
  * NAME
@@ -145,12 +146,22 @@ int escape_slashes (char *buf, int buf_len);
 /* FIXME: `timeval_sub_timespec' needs a description */
 int timeval_sub_timespec (struct timeval *tv0, struct timeval *tv1, struct timespec *ret);
 
-int rrd_update_file (char *host, char *file, char *values,
-               char **ds_def, int ds_num);
+int check_create_dir (const char *file_orig);
 
 #ifdef HAVE_LIBKSTAT
 int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name);
 long long get_kstat_value (kstat_t *ksp, char *name);
 #endif
 
+unsigned long long ntohll (unsigned long long n);
+unsigned long long htonll (unsigned long long n);
+
+int format_name (char *ret, int ret_len,
+               const char *hostname,
+               const char *plugin, const char *plugin_instance,
+               const char *type, const char *type_instance);
+#define FORMAT_VL(ret, ret_len, vl, ds) \
+       format_name (ret, ret_len, (vl)->host, (vl)->plugin, (vl)->plugin_instance, \
+                       (ds)->type, (vl)->type_instance)
+
 #endif /* COMMON_H */
index 40b46fa..311ebb3 100644 (file)
 
 #include "collectd.h"
 
-#include "libconfig/libconfig.h"
+#include "liboconfig/oconfig.h"
 
 #include "common.h"
 #include "plugin.h"
 #include "configfile.h"
 #include "network.h"
-#include "utils_debug.h"
-
-#define SHORTOPT_NONE 0
-
-#define ERR_NOT_NESTED "Sections cannot be nested.\n"
-#define ERR_SECTION_ONLY "`%s' can only be used as section.\n"
-#define ERR_NEEDS_ARG "Section `%s' needs an argument.\n"
-#define ERR_NEEDS_SECTION "`%s' can only be used within a section.\n"
 
 #define ESCAPE_NULL(str) ((str) == NULL ? "(null)" : (str))
 
-#define DEBUG_CALLBACK(shortvar, var, arguments, value) \
-       DBG("shortvar = %s, var = %s, arguments = %s, value = %s, ...", \
-                       ESCAPE_NULL(shortvar), \
-                       ESCAPE_NULL(var), \
-                       ESCAPE_NULL(arguments), \
-                       ESCAPE_NULL(value))
-
-extern int operating_mode;
-
+/*
+ * Private types
+ */
 typedef struct cf_callback
 {
-       char  *type;
-       int  (*callback) (char *, char *);
-       char **keys;
+       const char  *type;
+       int  (*callback) (const char *, const char *);
+       const char **keys;
        int    keys_num;
        struct cf_callback *next;
 } cf_callback_t;
 
-static cf_callback_t *first_callback = NULL;
+typedef struct cf_value_map_s
+{
+       char *key;
+       int (*func) (const oconfig_item_t *);
+} cf_value_map_t;
 
-typedef struct cf_mode_item
+typedef struct cf_global_option_s
 {
        char *key;
        char *value;
-       int   mode;
-} cf_mode_item_t;
+       char *def;
+} cf_global_option_t;
+
+/*
+ * Prototypes of callback functions
+ */
+static int dispatch_value_plugindir (const oconfig_item_t *ci);
+static int dispatch_value_loadds (const oconfig_item_t *ci);
+static int dispatch_value_loadplugin (const oconfig_item_t *ci);
 
-/* TODO
- * - LogFile
+/*
+ * Private variables
  */
-static cf_mode_item_t cf_mode_list[] =
+static cf_callback_t *first_callback = NULL;
+
+static cf_value_map_t cf_value_map[] =
 {
-       {"TimeToLive",  NULL, MODE_CLIENT                           },
-       {"PIDFile",     NULL, MODE_CLIENT | MODE_SERVER | MODE_LOCAL | MODE_LOG },
-       {"DataDir",     NULL, MODE_CLIENT | MODE_SERVER | MODE_LOCAL | MODE_LOG },
-       {"LogFile",     NULL, MODE_CLIENT | MODE_SERVER | MODE_LOCAL | MODE_LOG }
+       {"PluginDir",  dispatch_value_plugindir},
+       {"LoadPlugin", dispatch_value_loadplugin},
+       {"LoadDS", dispatch_value_loadds}
 };
-static int cf_mode_num = 4;
+static int cf_value_map_num = STATIC_ARRAY_LEN (cf_value_map);
 
-static int nesting_depth = 0;
-static char *current_module = NULL;
-
-/* `cf_register' needs this prototype */
-static int cf_callback_plugin_dispatch (const char *, const char *,
-               const char *, const char *, lc_flags_t, void *);
+static cf_global_option_t cf_global_options[] =
+{
+       {"BaseDir",   NULL, PKGLOCALSTATEDIR},
+       {"PIDFile",   NULL, PIDFILE},
+       {"Hostname",  NULL, NULL},
+       {"Interval",  NULL, "10"},
+       {"ReadThreads", NULL, "5"}
+};
+static int cf_global_options_num = STATIC_ARRAY_LEN (cf_global_options);
 
 /*
  * Functions to handle register/unregister, search, and other plugin related
  * stuff
  */
-static cf_callback_t *cf_search (char *type)
+static cf_callback_t *cf_search (const char *type)
 {
        cf_callback_t *cf_cb;
 
@@ -103,7 +104,8 @@ static cf_callback_t *cf_search (char *type)
        return (cf_cb);
 }
 
-static int cf_dispatch (char *type, const char *orig_key, const char *orig_value)
+static int cf_dispatch (const char *type, const char *orig_key,
+               const char *orig_value)
 {
        cf_callback_t *cf_cb;
        char *key;
@@ -111,14 +113,14 @@ static int cf_dispatch (char *type, const char *orig_key, const char *orig_value
        int ret;
        int i;
 
-       DBG ("type = %s, key = %s, value = %s",
+       DEBUG ("type = %s, key = %s, value = %s",
                        ESCAPE_NULL(type),
                        ESCAPE_NULL(orig_key),
                        ESCAPE_NULL(orig_value));
 
        if ((cf_cb = cf_search (type)) == NULL)
        {
-               syslog (LOG_WARNING, "Plugin `%s' did not register a callback.", type);
+               WARNING ("Plugin `%s' did not register a callback.", type);
                return (-1);
        }
 
@@ -142,423 +144,264 @@ static int cf_dispatch (char *type, const char *orig_key, const char *orig_value
        }
 
        if (i >= cf_cb->keys_num)
-               syslog (LOG_WARNING, "Plugin `%s' did not register for value `%s'.", type, key);
+               WARNING ("Plugin `%s' did not register for value `%s'.", type, key);
 
        free (key);
        free (value);
 
-       DBG ("return (%i)", ret);
+       DEBUG ("return (%i)", ret);
 
        return (ret);
-}
-
-void cf_unregister (char *type)
-{
-       cf_callback_t *this, *prev;
-
-       for (prev = NULL, this = first_callback;
-                       this != NULL;
-                       prev = this, this = this->next)
-               if (strcasecmp (this->type, type) == 0)
-               {
-                       if (prev == NULL)
-                               first_callback = this->next;
-                       else
-                               prev->next = this->next;
+} /* int cf_dispatch */
 
-                       free (this);
-                       break;
-               }
-}
-
-void cf_register (char *type,
-               int (*callback) (char *, char *),
-               char **keys, int keys_num)
+static int dispatch_global_option (const oconfig_item_t *ci)
 {
-       cf_callback_t *cf_cb;
-       char buf[64];
-       int i;
-
-       /* Remove this module from the list, if it already exists */
-       cf_unregister (type);
-
-       /* This pointer will be free'd in `cf_unregister' */
-       if ((cf_cb = (cf_callback_t *) malloc (sizeof (cf_callback_t))) == NULL)
-               return;
-
-       cf_cb->type     = type;
-       cf_cb->callback = callback;
-       cf_cb->keys     = keys;
-       cf_cb->keys_num = keys_num;
-
-       cf_cb->next = first_callback;
-       first_callback = cf_cb;
-
-       for (i = 0; i < keys_num; i++)
-       {
-               if (snprintf (buf, 64, "Plugin.%s", keys[i]) < 64)
-               {
-                       /* This may be called multiple times for the same
-                        * `key', but apparently `lc_register_*' can handle
-                        * it.. */
-                       lc_register_callback (buf, SHORTOPT_NONE,
-                                       LC_VAR_STRING, cf_callback_plugin_dispatch,
-                                       NULL);
-               }
-               else
-               {
-                       DBG ("Key was truncated: `%s'", ESCAPE_NULL(keys[i]));
-               }
-       }
-}
-
-/*
- * Other query functions
- */
-char *cf_get_option (const char *key, char *def)
-{
-       int i;
-
-       for (i = 0; i < cf_mode_num; i++)
+       if (ci->values_num != 1)
+               return (-1);
+       if (ci->values[0].type == OCONFIG_TYPE_STRING)
+               return (global_option_set (ci->key, ci->values[0].value.string));
+       else if (ci->values[0].type == OCONFIG_TYPE_NUMBER)
        {
-               if ((cf_mode_list[i].mode & operating_mode) == 0)
-                       continue;
-
-               if (strcasecmp (cf_mode_list[i].key, key) != 0)
-                       continue;
-
-               if (cf_mode_list[i].value != NULL)
-                       return (cf_mode_list[i].value);
-               return (def);
+               char tmp[128];
+               snprintf (tmp, sizeof (tmp), "%lf", ci->values[0].value.number);
+               tmp[127] = '\0';
+               return (global_option_set (ci->key, tmp));
        }
 
-       return (NULL);
-}
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Functions for the actual parsing                                    *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+       return (-1);
+} /* int dispatch_global_option */
 
-/*
- * `cf_callback_mode'
- *   Chose the `operating_mode'
- *
- * Mode `value'
- */
-static int cf_callback_mode (const char *shortvar, const char *var,
-               const char *arguments, const char *value, lc_flags_t flags,
-               void *extra)
+static int dispatch_value_plugindir (const oconfig_item_t *ci)
 {
-       DEBUG_CALLBACK (shortvar, var, arguments, value);
-
-       if (strcasecmp (value, "Client") == 0)
-               operating_mode = MODE_CLIENT;
-#if HAVE_LIBRRD
-       else if (strcasecmp (value, "Server") == 0)
-               operating_mode = MODE_SERVER;
-       else if (strcasecmp (value, "Local") == 0)
-               operating_mode = MODE_LOCAL;
-#else /* !HAVE_LIBRRD */
-       else if (strcasecmp (value, "Server") == 0)
-       {
-               fprintf (stderr, "Invalid mode `Server': "
-                               "You need to link against librrd for this "
-                               "mode to be available.\n");
-               syslog (LOG_ERR, "Invalid mode `Server': "
-                               "You need to link against librrd for this "
-                               "mode to be available.");
-               return (LC_CBRET_ERROR);
-       }
-       else if (strcasecmp (value, "Local") == 0)
-       {
-               fprintf (stderr, "Invalid mode `Local': "
-                               "You need to link against librrd for this "
-                               "mode to be available.\n");
-               syslog (LOG_ERR, "Invalid mode `Local': "
-                               "You need to link against librrd for this "
-                               "mode to be available.");
-               return (LC_CBRET_ERROR);
-       }
-#endif
-       else if (strcasecmp (value, "Log") == 0)
-               operating_mode = MODE_LOG;
-       else
-       {
-               syslog (LOG_ERR, "Invalid value for config option `Mode': `%s'", value);
-               return (LC_CBRET_ERROR);
-       }
+       assert (strcasecmp (ci->key, "PluginDir") == 0);
+       
+       if (ci->values_num != 1)
+               return (-1);
+       if (ci->values[0].type != OCONFIG_TYPE_STRING)
+               return (-1);
 
-       return (LC_CBRET_OKAY);
+       plugin_set_dir (ci->values[0].value.string);
+       return (0);
 }
 
-/*
- * `cf_callback_mode_plugindir'
- *   Change the plugin directory
- *
- * <Mode xxx>
- *   PluginDir `value'
- * </Mode>
- */
-static int cf_callback_mode_plugindir (const char *shortvar, const char *var,
-               const char *arguments, const char *value, lc_flags_t flags,
-               void *extra)
+static int dispatch_value_loadds (const oconfig_item_t *ci)
 {
-       DEBUG_CALLBACK (shortvar, var, arguments, value);
+       assert (strcasecmp (ci->key, "LoadDS") == 0);
 
-       plugin_set_dir (value);
+       if (ci->values_num != 1)
+               return (-1);
+       if (ci->values[0].type != OCONFIG_TYPE_STRING)
+               return (-1);
 
-       return (LC_CBRET_OKAY);
-}
+       return (plugin_load (ci->values[0].value.string, MR_DATASETS));
+} /* int dispatch_value_loadds */
 
-static int cf_callback_mode_option (const char *shortvar, const char *var,
-               const char *arguments, const char *value, lc_flags_t flags,
-               void *extra)
+static int dispatch_value_loadplugin (const oconfig_item_t *ci)
 {
-       cf_mode_item_t *item;
-
-       DEBUG_CALLBACK (shortvar, var, arguments, value);
-
-       if (extra == NULL)
-       {
-               fprintf (stderr, "No extra..?\n");
-               return (LC_CBRET_ERROR);
-       }
+       assert (strcasecmp (ci->key, "LoadPlugin") == 0);
 
-       item = (cf_mode_item_t *) extra;
+       if (ci->values_num != 1)
+               return (-1);
+       if (ci->values[0].type != OCONFIG_TYPE_STRING)
+               return (-1);
 
-       if (strcasecmp (item->key, shortvar))
-       {
-               fprintf (stderr, "Wrong extra..\n");
-               return (LC_CBRET_ERROR);
-       }
+       return (plugin_load (ci->values[0].value.string, MR_EVERYTHING));
+} /* int dispatch_value_loadplugin */
 
-       if ((operating_mode & item->mode) == 0)
-       {
-               fprintf (stderr, "Option `%s' is not valid in this mode!\n", shortvar);
-               return (LC_CBRET_ERROR);
-       }
+static int dispatch_value_plugin (const char *plugin, oconfig_item_t *ci)
+{
+       char  buffer[4096];
+       char *buffer_ptr;
+       int   buffer_free;
+       int i;
 
-       if (item->value != NULL)
-       {
-               free (item->value);
-               item->value = NULL;
-       }
+       buffer_ptr = buffer;
+       buffer_free = sizeof (buffer);
 
-       if ((item->value = strdup (value)) == NULL)
+       for (i = 0; i < ci->values_num; i++)
        {
-               perror ("strdup");
-               return (LC_CBRET_ERROR);
+               int status = -1;
+
+               if (ci->values[i].type == OCONFIG_TYPE_STRING)
+                       status = snprintf (buffer_ptr, buffer_free, " %s",
+                                       ci->values[i].value.string);
+               else if (ci->values[i].type == OCONFIG_TYPE_NUMBER)
+                       status = snprintf (buffer_ptr, buffer_free, " %lf",
+                                       ci->values[i].value.number);
+               else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN)
+                       status = snprintf (buffer_ptr, buffer_free, " %s",
+                                       ci->values[i].value.boolean
+                                       ? "true" : "false");
+
+               if ((status < 0) || (status >= buffer_free))
+                       return (-1);
+               buffer_free -= status;
+               buffer_ptr  += status;
        }
+       /* skip the initial space */
+       buffer_ptr = buffer + 1;
 
-       return (LC_CBRET_OKAY);
-}
+       return (cf_dispatch (plugin, ci->key, buffer_ptr));
+} /* int plugin_conf_dispatch */
 
-/*
- * `cf_callback_mode_loadmodule':
- *   Load a plugin.
- *
- * <Mode xxx>
- *   LoadPlugin `value'
- * </Mode>
- */
-static int cf_callback_mode_loadmodule (const char *shortvar, const char *var,
-               const char *arguments, const char *value, lc_flags_t flags,
-               void *extra)
+static int dispatch_value (const oconfig_item_t *ci)
 {
-       DEBUG_CALLBACK (shortvar, var, arguments, value);
-
-       if (plugin_load (value))
-               syslog (LOG_ERR, "plugin_load (%s): failed to load plugin", value);
-
-       /* Return `okay' even if there was an error, because it's not a syntax
-        * problem.. */
-       return (LC_CBRET_OKAY);
-}
+       int ret = -2;
+       int i;
 
-static int cf_callback_socket (const char *shortvar, const char *var,
-               const char *arguments, const char *value, lc_flags_t flags,
-               void *extra)
-{
-       char *buffer;
+       for (i = 0; i < cf_value_map_num; i++)
+               if (strcasecmp (cf_value_map[i].key, ci->key) == 0)
+               {
+                       ret = cf_value_map[i].func (ci);
+                       break;
+               }
 
-       char *fields[3];
-       int   numfields;
+       for (i = 0; i < cf_global_options_num; i++)
+               if (strcasecmp (cf_global_options[i].key, ci->key) == 0)
+               {
+                       ret = dispatch_global_option (ci);
+                       break;
+               }
 
-       char *node;
-       char *service = NET_DEFAULT_PORT;
+       return (ret);
+} /* int dispatch_value */
 
-       DEBUG_CALLBACK (shortvar, var, arguments, value);
+static int dispatch_block_plugin (oconfig_item_t *ci)
+{
+       int i;
+       char *name;
 
-       buffer = strdup (value);
-       if (buffer == NULL)
-               return (LC_CBRET_ERROR);
+       if (strcasecmp (ci->key, "Plugin") != 0)
+               return (-1);
+       if (ci->values_num != 1)
+               return (-1);
+       if (ci->values[0].type != OCONFIG_TYPE_STRING)
+               return (-1);
 
-       numfields = strsplit (buffer, fields, 3);
+       name = ci->values[0].value.string;
 
-       if ((numfields != 1) && (numfields != 2))
+       for (i = 0; i < ci->children_num; i++)
        {
-               syslog (LOG_ERR, "Invalid number of arguments to `%s'",
-                               shortvar);
-               free (buffer);
-               return (LC_CBRET_ERROR);
+               if (ci->children[i].children == NULL)
+                       dispatch_value_plugin (name, ci->children + i);
+               else
+                       {DEBUG ("No nested config blocks allow for plugins. Yet.");}
        }
 
-       node = fields[0];
-       if (numfields == 2)
-               service = fields[1];
+       return (0);
+}
 
-       /* Still return `LC_CBRET_OKAY' because this is not an syntax error */
-       if (network_create_socket (node, service) < 1)
-               syslog (LOG_ERR, "network_create_socket (%s, %s) failed",
-                               node, service);
 
-       free (buffer);
+static int dispatch_block (oconfig_item_t *ci)
+{
+       if (strcasecmp (ci->key, "Plugin") == 0)
+               return (dispatch_block_plugin (ci));
 
-       return (LC_CBRET_OKAY);
+       return (0);
 }
 
-/*
- * `cf_callback_plugin'
- *   Start/end section `plugin'
- *
- * <Plugin `arguments'>
- *   ...
- * </Plugin>
+/* 
+ * Public functions
  */
-static int cf_callback_plugin (const char *shortvar, const char *var,
-               const char *arguments, const char *value, lc_flags_t flags,
-               void *extra)
+int global_option_set (const char *option, const char *value)
 {
-       DEBUG_CALLBACK (shortvar, var, arguments, value);
-
-       if (flags == LC_FLAGS_SECTIONSTART)
-       {
-               if (nesting_depth != 0)
-               {
-                       fprintf (stderr, ERR_NOT_NESTED);
-                       return (LC_CBRET_ERROR);
-               }
-
-               if (arguments == NULL)
-               {
-                       fprintf (stderr, ERR_NEEDS_ARG, shortvar);
-                       return (LC_CBRET_ERROR);
-               }
+       int i;
 
-               if ((current_module = strdup (arguments)) == NULL)
-               {
-                       perror ("strdup");
-                       return (LC_CBRET_ERROR);
-               }
+       DEBUG ("option = %s; value = %s;", option, value);
 
-               nesting_depth++;
+       for (i = 0; i < cf_global_options_num; i++)
+               if (strcasecmp (cf_global_options[i].key, option) == 0)
+                       break;
 
-               if (cf_search (current_module) != NULL)
-                       return (LC_CBRET_OKAY);
-               else
-                       return (LC_CBRET_IGNORESECTION);
-       }
-       else if (flags == LC_FLAGS_SECTIONEND)
-       {
-               if (current_module != NULL)
-               {
-                       free (current_module);
-                       current_module = NULL;
-               }
+       if (i >= cf_global_options_num)
+               return (-1);
 
-               nesting_depth--;
+       sfree (cf_global_options[i].value);
 
-               return (LC_CBRET_OKAY);
-       }
+       if (value != NULL)
+               cf_global_options[i].value = strdup (value);
        else
-       {
-               fprintf (stderr, ERR_SECTION_ONLY, shortvar);
-               return (LC_CBRET_ERROR);
-       }
+               cf_global_options[i].value = NULL;
+
+       return (0);
 }
 
-/*
- * `cf_callback_plugin_dispatch'
- *   Send options within `plugin' sections to the plugin that requests it.
- *
- * <Plugin `current_module'>
- *   `var' `value'
- * </Plugin>
- */
-static int cf_callback_plugin_dispatch (const char *shortvar, const char *var,
-               const char *arguments, const char *value, lc_flags_t flags,
-               void *extra)
+const char *global_option_get (const char *option)
 {
-       DEBUG_CALLBACK (shortvar, var, arguments, value);
-
-       if ((nesting_depth == 0) || (current_module == NULL))
-       {
-               fprintf (stderr, ERR_NEEDS_SECTION, shortvar);
-               return (LC_CBRET_ERROR);
-       }
+       int i;
 
-       /* Send the data to the plugin */
-       if (cf_dispatch (current_module, shortvar, value) < 0)
-               return (LC_CBRET_ERROR);
+       for (i = 0; i < cf_global_options_num; i++)
+               if (strcasecmp (cf_global_options[i].key, option) == 0)
+                       break;
 
-       return (LC_CBRET_OKAY);
-}
+       if (i >= cf_global_options_num)
+               return (NULL);
+       
+       return ((cf_global_options[i].value != NULL)
+                       ? cf_global_options[i].value
+                       : cf_global_options[i].def);
+} /* char *global_option_get */
 
-static void cf_init (void)
+void cf_unregister (const char *type)
 {
-       static int run_once = 0;
-       int i;
+       cf_callback_t *this, *prev;
 
-       if (run_once != 0)
-               return;
-       run_once = 1;
+       for (prev = NULL, this = first_callback;
+                       this != NULL;
+                       prev = this, this = this->next)
+               if (strcasecmp (this->type, type) == 0)
+               {
+                       if (prev == NULL)
+                               first_callback = this->next;
+                       else
+                               prev->next = this->next;
 
-       lc_register_callback ("Mode", SHORTOPT_NONE, LC_VAR_STRING,
-                       cf_callback_mode, NULL);
-       lc_register_callback ("Plugin", SHORTOPT_NONE, LC_VAR_SECTION,
-                       cf_callback_plugin, NULL);
+                       free (this);
+                       break;
+               }
+} /* void cf_unregister */
 
-       lc_register_callback ("PluginDir", SHORTOPT_NONE,
-                       LC_VAR_STRING, cf_callback_mode_plugindir, NULL);
-       lc_register_callback ("LoadPlugin", SHORTOPT_NONE,
-                       LC_VAR_STRING, cf_callback_mode_loadmodule, NULL);
+void cf_register (const char *type,
+               int (*callback) (const char *, const char *),
+               const char **keys, int keys_num)
+{
+       cf_callback_t *cf_cb;
 
-       lc_register_callback ("Listen", SHORTOPT_NONE,
-                       LC_VAR_STRING, cf_callback_socket, NULL);
-       lc_register_callback ("Server", SHORTOPT_NONE,
-                       LC_VAR_STRING, cf_callback_socket, NULL);
+       /* Remove this module from the list, if it already exists */
+       cf_unregister (type);
 
-       for (i = 0; i < cf_mode_num; i++)
-       {
-               cf_mode_item_t *item;
+       /* This pointer will be free'd in `cf_unregister' */
+       if ((cf_cb = (cf_callback_t *) malloc (sizeof (cf_callback_t))) == NULL)
+               return;
 
-               item = &cf_mode_list[i];
+       cf_cb->type     = type;
+       cf_cb->callback = callback;
+       cf_cb->keys     = keys;
+       cf_cb->keys_num = keys_num;
 
-               lc_register_callback (item->key, SHORTOPT_NONE, LC_VAR_STRING,
-                               cf_callback_mode_option, (void *) item);
-       }
-}
+       cf_cb->next = first_callback;
+       first_callback = cf_cb;
+} /* void cf_register */
 
 int cf_read (char *filename)
 {
-       cf_init ();
-
-       if (filename == NULL)
-               filename = CONFIGFILE;
-
-       DBG ("Starting to parse file `%s'", filename);
+       oconfig_item_t *conf;
+       int i;
 
-       /* int lc_process_file(const char *appname, const char *pathname, lc_conf_type_t type); */
-       if (lc_process_file ("collectd", filename, LC_CONF_APACHE))
+       conf = oconfig_parse_file (filename);
+       if (conf == NULL)
        {
-               syslog (LOG_ERR, "lc_process_file (%s): %s", filename, lc_geterrstr ());
+               ERROR ("Unable to read config file %s.", filename);
                return (-1);
        }
 
-       DBG ("Done parsing file `%s'", filename);
-
-       /* free memory and stuff */
-       lc_cleanup ();
+       for (i = 0; i < conf->children_num; i++)
+       {
+               if (conf->children[i].children == NULL)
+                       dispatch_value (conf->children + i);
+               else
+                       dispatch_block (conf->children + i);
+       }
 
        return (0);
-}
+} /* int cf_read */
index 0bb11b2..0ee8f33 100644 (file)
@@ -31,7 +31,7 @@
  *  `type'      Name of the plugin (must be the same as passed to
  *              `plugin_register'
  */
-void cf_unregister (char *type);
+void cf_unregister (const char *type);
 
 /*
  * DESCRIPTION
@@ -57,24 +57,9 @@ void cf_unregister (char *type);
  *  exists for each `type' at any time. This means that `cf_register' may be
  *  called multiple times, but only the last call will have an effect.
  */
-void cf_register (char *type,
-               int (*callback) (char *, char *),
-               char **keys, int keys_num);
-
-/*
- * DESCRIPTION
- *  `cf_get_option' returns various general options.
- *
- * PARAMETERS
- *  `key'       Name of the option to query.
- *  `def'       Pointer to return as default value.
- *
- * RETURN VALUE
- *  The pointer returned is part of an internal structure and may not be
- *  changed. If the option is not found for whatever reason (wrong key, option
- *  not allowed for currently selected mode, ...) `NULL' is returned.
- */
-char *cf_get_option (const char *key, char *def);
+void cf_register (const char *type,
+               int (*callback) (const char *, const char *),
+               const char **keys, int keys_num);
 
 /*
  * DESCRIPTION
@@ -93,4 +78,7 @@ char *cf_get_option (const char *key, char *def);
  */
 int cf_read (char *filename);
 
+int global_option_set (const char *option, const char *value);
+const char *global_option_get (const char *option);
+
 #endif /* defined(CONFIGFILE_H) */
index b087d66..1dc7865 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -1,11 +1,10 @@
 /**
  * collectd - src/cpu.c
- * Copyright (C) 2005,2006  Florian octo Forster
+ * Copyright (C) 2005-2007  Florian octo Forster
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -23,9 +22,6 @@
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
-#include "utils_debug.h"
-
-#define MODULE_NAME "cpu"
 
 #ifdef HAVE_MACH_KERN_RETURN_H
 # include <mach/kern_return.h>
 # define CPU_HAVE_READ 0
 #endif
 
+static data_source_t dsrc[1] =
+{
+       {"value", DS_TYPE_COUNTER, 0, 4294967295.0}
+};
+
+static data_set_t ds =
+{
+       "cpu", 1, dsrc
+};
+
+#if CPU_HAVE_READ
 #ifdef PROCESSOR_CPU_LOAD_INFO
 static mach_port_t port_host;
 static processor_port_array_t cpu_list;
@@ -106,20 +113,7 @@ static int numcpu;
 static int numcpu;
 #endif /* HAVE_SYSCTLBYNAME */
 
-static char *cpu_filename = "cpu-%s.rrd";
-
-static char *ds_def[] =
-{
-       "DS:user:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:nice:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:syst:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:idle:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:wait:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       NULL
-};
-static int ds_num = 5;
-
-static void cpu_init (void)
+static int init (void)
 {
 #if PROCESSOR_CPU_LOAD_INFO || PROCESSOR_TEMPERATURE
        kern_return_t status;
@@ -130,13 +124,13 @@ static void cpu_init (void)
        /* FIXME: Free `cpu_list' if it's not NULL */
        if ((status = host_processors (port_host, &cpu_list, &cpu_list_len)) != KERN_SUCCESS)
        {
-               syslog (LOG_ERR, "cpu-plugin: host_processors returned %i\n", (int) status);
+               ERROR ("cpu plugin: host_processors returned %i", (int) status);
                cpu_list_len = 0;
-               return;
+               return (-1);
        }
 
-       DBG ("host_processors returned %i %s", (int) cpu_list_len, cpu_list_len == 1 ? "processor" : "processors");
-       syslog (LOG_INFO, "cpu-plugin: Found %i processor%s.", (int) cpu_list_len, cpu_list_len == 1 ? "" : "s");
+       DEBUG ("host_processors returned %i %s", (int) cpu_list_len, cpu_list_len == 1 ? "processor" : "processors");
+       INFO ("cpu plugin: Found %i processor%s.", (int) cpu_list_len, cpu_list_len == 1 ? "" : "s");
 
        collectd_step = atoi (COLLECTD_STEP);
        if ((collectd_step > 0) && (collectd_step <= 86400))
@@ -150,7 +144,7 @@ static void cpu_init (void)
        numcpu = 0;
 
        if (kc == NULL)
-               return;
+               return (-1);
 
        /* Solaris doesn't count linear.. *sigh* */
        for (numcpu = 0, ksp_chain = kc->kc_chain;
@@ -167,50 +161,40 @@ static void cpu_init (void)
 
        if (sysctlbyname ("hw.ncpu", &numcpu, &numcpu_size, NULL, 0) < 0)
        {
-               syslog (LOG_WARNING, "cpu: sysctlbyname: %s", strerror (errno));
-               return;
+               char errbuf[1024];
+               WARNING ("cpu plugin: sysctlbyname: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
        }
 
        if (numcpu != 1)
-               syslog (LOG_NOTICE, "cpu: Only one processor supported when using `sysctlbyname' (found %i)", numcpu);
+               NOTICE ("cpu: Only one processor supported when using `sysctlbyname' (found %i)", numcpu);
 #endif
 
-       return;
-}
-
-static void cpu_write (char *host, char *inst, char *val)
-{
-       char file[512];
-       int status;
-
-       status = snprintf (file, 512, cpu_filename, inst);
-       if (status < 1)
-               return;
-       else if (status >= 512)
-               return;
+       return (0);
+} /* int init */
 
-       rrd_update_file (host, file, val, ds_def, ds_num);
-}
-
-#if CPU_HAVE_READ
-#define BUFSIZE 512
-static void cpu_submit (int cpu_num, unsigned long long user,
-               unsigned long long nice, unsigned long long syst,
-               unsigned long long idle, unsigned long long wait)
+static void submit (int cpu_num, const char *type_instance, counter_t value)
 {
-       char buf[BUFSIZE];
-       char cpu[16];
-
-       if (snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu", (unsigned int) curtime,
-                               user, nice, syst, idle, wait) >= BUFSIZE)
-               return;
-       snprintf (cpu, 16, "%i", cpu_num);
-
-       plugin_submit (MODULE_NAME, cpu, buf);
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
+
+       values[0].counter = value;
+
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "cpu");
+       snprintf (vl.plugin_instance, sizeof (vl.type_instance),
+                       "%i", cpu_num);
+       vl.plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
+       strcpy (vl.type_instance, type_instance);
+
+       plugin_dispatch_values ("cpu", &vl);
 }
-#undef BUFSIZE
 
-static void cpu_read (void)
+static int cpu_read (void)
 {
 #if PROCESSOR_CPU_LOAD_INFO || PROCESSOR_TEMPERATURE
        int cpu;
@@ -238,21 +222,20 @@ static void cpu_read (void)
                                                PROCESSOR_CPU_LOAD_INFO, &cpu_host,
                                                (processor_info_t) &cpu_info, &cpu_info_len)) != KERN_SUCCESS)
                {
-                       syslog (LOG_ERR, "cpu-plugin: processor_info failed with status %i\n", (int) status);
+                       ERROR ("cpu plugin: processor_info failed with status %i", (int) status);
                        continue;
                }
 
                if (cpu_info_len < CPU_STATE_MAX)
                {
-                       syslog (LOG_ERR, "cpu-plugin: processor_info returned only %i elements..\n", cpu_info_len);
+                       ERROR ("cpu plugin: processor_info returned only %i elements..", cpu_info_len);
                        continue;
                }
 
-               cpu_submit (cpu, cpu_info.cpu_ticks[CPU_STATE_USER],
-                               cpu_info.cpu_ticks[CPU_STATE_NICE],
-                               cpu_info.cpu_ticks[CPU_STATE_SYSTEM],
-                               cpu_info.cpu_ticks[CPU_STATE_IDLE],
-                               0ULL);
+               submit (cpu, "user", (counter_t) cpu_info.cpu_ticks[CPU_STATE_USER]);
+               submit (cpu, "nice", (counter_t) cpu_info.cpu_ticks[CPU_STATE_USER]);
+               submit (cpu, "system", (counter_t) cpu_info.cpu_ticks[CPU_STATE_USER]);
+               submit (cpu, "idle", (counter_t) cpu_info.cpu_ticks[CPU_STATE_USER]);
 #endif /* PROCESSOR_CPU_LOAD_INFO */
 #if PROCESSOR_TEMPERATURE
                /*
@@ -275,7 +258,7 @@ static void cpu_read (void)
                                cpu_temp, &cpu_temp_len);
                if (status != KERN_SUCCESS)
                {
-                       syslog (LOG_ERR, "cpu-plugin: processor_info failed: %s",
+                       ERROR ("cpu plugin: processor_info failed: %s",
                                        mach_error_string (status));
 
                        cpu_temp_retry_counter = cpu_temp_retry_step;
@@ -288,7 +271,7 @@ static void cpu_read (void)
 
                if (cpu_temp_len != 1)
                {
-                       DBG ("processor_info (PROCESSOR_TEMPERATURE) returned %i elements..?",
+                       DEBUG ("processor_info (PROCESSOR_TEMPERATURE) returned %i elements..?",
                                        (int) cpu_temp_len);
                        continue;
                }
@@ -296,18 +279,17 @@ static void cpu_read (void)
                cpu_temp_retry_counter = 0;
                cpu_temp_retry_step    = 1;
 
-               DBG ("cpu_temp = %i", (int) cpu_temp);
+               DEBUG ("cpu_temp = %i", (int) cpu_temp);
 #endif /* PROCESSOR_TEMPERATURE */
        }
 /* #endif PROCESSOR_CPU_LOAD_INFO */
 
 #elif defined(KERNEL_LINUX)
-# define BUFSIZE 1024
        int cpu;
-       unsigned long long user, nice, syst, idle;
-       unsigned long long wait, intr, sitr; /* sitr == soft interrupt */
+       counter_t user, nice, syst, idle;
+       counter_t wait, intr, sitr; /* sitr == soft interrupt */
        FILE *fh;
-       char buf[BUFSIZE];
+       char buf[1024];
 
        char *fields[9];
        int numfields;
@@ -316,16 +298,17 @@ static void cpu_read (void)
 
        if ((fh = fopen ("/proc/stat", "r")) == NULL)
        {
+               char errbuf[1024];
                plugin_complain (LOG_ERR, &complain_obj, "cpu plugin: "
                                "fopen (/proc/stat) failed: %s",
-                               strerror (errno));
-               return;
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
        }
 
        plugin_relief (LOG_NOTICE, &complain_obj, "cpu plugin: "
                        "fopen (/proc/stat) succeeded.");
 
-       while (fgets (buf, BUFSIZE, fh) != NULL)
+       while (fgets (buf, 1024, fh) != NULL)
        {
                if (strncmp (buf, "cpu", 3))
                        continue;
@@ -342,31 +325,29 @@ static void cpu_read (void)
                syst = atoll (fields[3]);
                idle = atoll (fields[4]);
 
+               submit (cpu, "user", user);
+               submit (cpu, "nice", nice);
+               submit (cpu, "system", syst);
+               submit (cpu, "idle", idle);
+
                if (numfields >= 8)
                {
                        wait = atoll (fields[5]);
                        intr = atoll (fields[6]);
                        sitr = atoll (fields[7]);
 
-                       /* I doubt anyone cares about the time spent in
-                        * interrupt handlers.. */
-                       syst += intr + sitr;
+                       submit (cpu, "wait", wait);
+                       submit (cpu, "interrupt", intr);
+                       submit (cpu, "softirq", sitr);
                }
-               else
-               {
-                       wait = 0LL;
-               }
-
-               cpu_submit (cpu, user, nice, syst, idle, wait);
        }
 
        fclose (fh);
-#undef BUFSIZE
 /* #endif defined(KERNEL_LINUX) */
 
 #elif defined(HAVE_LIBKSTAT)
        int cpu;
-       unsigned long long user, syst, idle, wait;
+       counter_t user, syst, idle, wait;
        static cpu_stat_t cs;
 
        if (kc == NULL)
@@ -377,13 +358,15 @@ static void cpu_read (void)
                if (kstat_read (kc, ksp[cpu], &cs) == -1)
                        continue; /* error message? */
 
-               idle = (unsigned long long) cs.cpu_sysinfo.cpu[CPU_IDLE];
-               user = (unsigned long long) cs.cpu_sysinfo.cpu[CPU_USER];
-               syst = (unsigned long long) cs.cpu_sysinfo.cpu[CPU_KERNEL];
-               wait = (unsigned long long) cs.cpu_sysinfo.cpu[CPU_WAIT];
+               idle = (counter_t) cs.cpu_sysinfo.cpu[CPU_IDLE];
+               user = (counter_t) cs.cpu_sysinfo.cpu[CPU_USER];
+               syst = (counter_t) cs.cpu_sysinfo.cpu[CPU_KERNEL];
+               wait = (counter_t) cs.cpu_sysinfo.cpu[CPU_WAIT];
 
-               cpu_submit (ksp[cpu]->ks_instance,
-                               user, 0LL, syst, idle, wait);
+               submit (ksp[cpu]->ks_instance, "user", user);
+               submit (ksp[cpu]->ks_instance, "system", syst);
+               submit (ksp[cpu]->ks_instance, "idle", idle);
+               submit (ksp[cpu]->ks_instance, "wait", wait);
        }
 /* #endif defined(HAVE_LIBKSTAT) */
 
@@ -397,9 +380,10 @@ static void cpu_read (void)
 
        if (sysctlbyname("kern.cp_time", &cpuinfo, &cpuinfo_size, NULL, 0) < 0)
        {
+               char errbuf[1024];
                plugin_complain (LOG_ERR, &complain_obj, "cpu plugin: "
                                "sysctlbyname failed: %s.",
-                               strerror (errno));
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                return;
        }
 
@@ -408,19 +392,26 @@ static void cpu_read (void)
 
        cpuinfo[CP_SYS] += cpuinfo[CP_INTR];
 
-       /* FIXME: Instance is always `0' */
-       cpu_submit (0, cpuinfo[CP_USER], cpuinfo[CP_NICE], cpuinfo[CP_SYS], cpuinfo[CP_IDLE], 0LL);
+       submit (0, "user", cpuinfo[CP_USER]);
+       submit (0, "nice", cpuinfo[CP_NICE]);
+       submit (0, "system", cpuinfo[CP_SYS]);
+       submit (0, "idle", cpuinfo[CP_IDLE]);
 #endif
 
-       return;
+       return (0);
 }
-#else
-# define cpu_read NULL
 #endif /* CPU_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, cpu_init, cpu_read, cpu_write);
-}
+       if (load & MR_DATASETS)
+               plugin_register_data_set (&ds);
 
-#undef MODULE_NAME
+#if CPU_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_init ("cpu", init);
+               plugin_register_read ("cpu", cpu_read);
+       }
+#endif /* CPU_HAVE_READ */
+} /* void module_register */
index ba0149a..e4caf5f 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/cpufreq.c
- * Copyright (C) 2005,2006  Peter Holik
+ * Copyright (C) 2005-2007  Peter Holik
  *
  * 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
 # define CPUFREQ_HAVE_READ 0
 #endif
 
-static char *cpufreq_file = "cpufreq-%s.rrd";
+static data_source_t data_source[1] =
+{
+       {"value", DS_TYPE_GAUGE, 0, NAN}
+};
 
-static char *ds_def[] =
+static data_set_t data_set =
 {
-       "DS:value:GAUGE:"COLLECTD_HEARTBEAT":0:U",
-       NULL
+       "cpufreq", 1, data_source
 };
-static int ds_num = 1;
 
+#if CPUFREQ_HAVE_READ
 #ifdef KERNEL_LINUX
 static int num_cpu = 0;
 #endif
 
-#define BUFSIZE 256
-
-static void cpufreq_init (void)
+static int cpufreq_init (void)
 {
 #ifdef KERNEL_LINUX
         int status;
-       char filename[BUFSIZE];
+       char filename[256];
 
        num_cpu = 0;
 
        while (1)
        {
-               status = snprintf (filename, BUFSIZE, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", num_cpu);
-               if (status < 1 || status >= BUFSIZE)
+               status = snprintf (filename, sizeof (filename),
+                               "/sys/devices/system/cpu/cpu%d/cpufreq/"
+                               "scaling_cur_freq", num_cpu);
+               if (status < 1 || status >= sizeof (filename))
                        break;
 
-               if (access(filename, R_OK))
+               if (access (filename, R_OK))
                        break;
 
                num_cpu++;
        }
 
-       syslog (LOG_INFO, MODULE_NAME" found %d cpu(s)", num_cpu);
+       INFO ("cpufreq plugin: Found %d CPU%s", num_cpu,
+                       (num_cpu == 1) ? "" : "s");
+
+       if (num_cpu == 0)
+               plugin_unregister_read ("cpufreq");
 #endif /* defined(KERNEL_LINUX) */
 
-       return;
-}
+       return (0);
+} /* int cpufreq_init */
 
-static void cpufreq_write (char *host, char *inst, char *val)
+static void cpufreq_submit (int cpu_num, double value)
 {
-        int status;
-        char file[BUFSIZE];
-
-        status = snprintf (file, BUFSIZE, cpufreq_file, inst);
-        if (status < 1 || status >= BUFSIZE)
-                return;
-
-       rrd_update_file (host, file, val, ds_def, ds_num);
-}
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-#if CPUFREQ_HAVE_READ
-static void cpufreq_submit (int cpu_num, unsigned long long val)
-{
-       char buf[BUFSIZE];
-       char cpu[16];
+       values[0].gauge = value;
 
-       if (snprintf (buf, BUFSIZE, "%u:%llu", (unsigned int) curtime, val) >= BUFSIZE)
-               return;
-        snprintf (cpu, 16, "%i", cpu_num);
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "cpufreq");
+       snprintf (vl.type_instance, sizeof (vl.type_instance),
+                       "%i", cpu_num);
 
-       plugin_submit (MODULE_NAME, cpu, buf);
+       plugin_dispatch_values ("cpufreq", &vl);
 }
 
-static void cpufreq_read (void)
+static int cpufreq_read (void)
 {
 #ifdef KERNEL_LINUX
         int status;
        unsigned long long val;
        int i = 0;
        FILE *fp;
-       char filename[BUFSIZE];
+       char filename[256];
        char buffer[16];
 
        for (i = 0; i < num_cpu; i++)
        {
-               status = snprintf (filename, BUFSIZE, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", i);
-               if (status < 1 || status >= BUFSIZE)
-                       return;
+               status = snprintf (filename, sizeof (filename),
+                               "/sys/devices/system/cpu/cpu%d/cpufreq/"
+                               "scaling_cur_freq", i);
+               if (status < 1 || status >= sizeof (filename))
+                       return (-1);
 
                if ((fp = fopen (filename, "r")) == NULL)
                {
-                       syslog (LOG_WARNING, "cpufreq: fopen: %s", strerror (errno));
-                       return;
+                       char errbuf[1024];
+                       WARNING ("cpufreq: fopen (%s): %s", filename,
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
+                       return (-1);
                }
 
                if (fgets (buffer, 16, fp) == NULL)
                {
-                       syslog (LOG_WARNING, "cpufreq: fgets: %s", strerror (errno));
+                       char errbuf[1024];
+                       WARNING ("cpufreq: fgets: %s",
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        fclose (fp);
-                       return;
+                       return (-1);
                }
 
                if (fclose (fp))
-                       syslog (LOG_WARNING, "cpufreq: fclose: %s", strerror (errno));
+               {
+                       char errbuf[1024];
+                       WARNING ("cpufreq: fclose: %s",
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
+               }
+
 
                /* You're seeing correctly: The file is reporting kHz values.. */
                val = atoll (buffer) * 1000;
@@ -137,16 +150,21 @@ static void cpufreq_read (void)
        }
 #endif /* defined(KERNEL_LINUX) */
 
-       return;
-}
-#else
-#define cpufreq_read NULL
-#endif
+       return (0);
+} /* int cpufreq_read */
+#endif /* CPUFREQ_HAVE_READ */
 #undef BUFSIZE
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, cpufreq_init, cpufreq_read, cpufreq_write);
-}
+       if (load & MR_DATASETS)
+               plugin_register_data_set (&data_set);
 
-#undef MODULE_NAME
+#if CPUFREQ_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_init ("cpufreq", cpufreq_init);
+               plugin_register_read ("cpufreq", cpufreq_read);
+       }
+#endif /* CPUFREQ_HAVE_READ */
+}
diff --git a/src/csv.c b/src/csv.c
new file mode 100644 (file)
index 0000000..5d64fb8
--- /dev/null
+++ b/src/csv.c
@@ -0,0 +1,276 @@
+/**
+ * collectd - src/csv.c
+ * Copyright (C) 2007  Florian octo Forster
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+
+/*
+ * Private variables
+ */
+static const char *config_keys[] =
+{
+       "DataDir"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static char *datadir   = NULL;
+
+static int value_list_to_string (char *buffer, int buffer_len,
+               const data_set_t *ds, const value_list_t *vl)
+{
+       int offset;
+       int status;
+       int i;
+
+       memset (buffer, '\0', sizeof (buffer_len));
+
+       status = snprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+       if ((status < 1) || (status >= buffer_len))
+               return (-1);
+       offset = status;
+
+       for (i = 0; i < ds->ds_num; i++)
+       {
+               if ((ds->ds[i].type != DS_TYPE_COUNTER)
+                               && (ds->ds[i].type != DS_TYPE_GAUGE))
+                       return (-1);
+
+               if (ds->ds[i].type == DS_TYPE_COUNTER)
+                       status = snprintf (buffer + offset, buffer_len - offset,
+                                       ",%llu", vl->values[i].counter);
+               else
+                       status = snprintf (buffer + offset, buffer_len - offset,
+                                       ",%lf", vl->values[i].gauge);
+
+               if ((status < 1) || (status >= (buffer_len - offset)))
+                       return (-1);
+
+               offset += status;
+       } /* for ds->ds_num */
+
+       return (0);
+} /* int value_list_to_string */
+
+static int value_list_to_filename (char *buffer, int buffer_len,
+               const data_set_t *ds, const value_list_t *vl)
+{
+       int offset = 0;
+       int status;
+
+       if (datadir != NULL)
+       {
+               status = snprintf (buffer + offset, buffer_len - offset,
+                               "%s/", datadir);
+               if ((status < 1) || (status >= buffer_len - offset))
+                       return (-1);
+               offset += status;
+       }
+
+       status = snprintf (buffer + offset, buffer_len - offset,
+                       "%s/", vl->host);
+       if ((status < 1) || (status >= buffer_len - offset))
+               return (-1);
+       offset += status;
+
+       if (strlen (vl->plugin_instance) > 0)
+               status = snprintf (buffer + offset, buffer_len - offset,
+                               "%s-%s/", vl->plugin, vl->plugin_instance);
+       else
+               status = snprintf (buffer + offset, buffer_len - offset,
+                               "%s/", vl->plugin);
+       if ((status < 1) || (status >= buffer_len - offset))
+               return (-1);
+       offset += status;
+
+       if (strlen (vl->type_instance) > 0)
+               status = snprintf (buffer + offset, buffer_len - offset,
+                               "%s-%s", ds->type, vl->type_instance);
+       else
+               status = snprintf (buffer + offset, buffer_len - offset,
+                               "%s", ds->type);
+       if ((status < 1) || (status >= buffer_len - offset))
+               return (-1);
+       offset += status;
+
+       {
+               time_t now;
+               struct tm stm;
+
+               /* TODO: Find a way to minimize the calls to `localtime_r',
+                * since they are pretty expensive.. */
+               now = time (NULL);
+               if (localtime_r (&now, &stm) == NULL)
+               {
+                       ERROR ("csv plugin: localtime_r failed");
+                       return (1);
+               }
+
+               strftime (buffer + offset, buffer_len - offset,
+                               "-%Y-%m-%d", &stm);
+       }
+
+       return (0);
+} /* int value_list_to_filename */
+
+static int csv_create_file (const char *filename, const data_set_t *ds)
+{
+       FILE *csv;
+       int i;
+
+       if (check_create_dir (filename))
+               return (-1);
+
+       csv = fopen (filename, "w");
+       if (csv == NULL)
+       {
+               char errbuf[1024];
+               ERROR ("csv plugin: fopen (%s) failed: %s",
+                               filename,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
+
+       fprintf (csv, "epoch");
+       for (i = 0; i < ds->ds_num; i++)
+               fprintf (csv, ",%s", ds->ds[i].name);
+
+       fprintf (csv, "\n");
+       fclose (csv);
+
+       return 0;
+} /* int csv_create_file */
+
+static int csv_config (const char *key, const char *value)
+{
+       if (strcasecmp ("DataDir", key) == 0)
+       {
+               if (datadir != NULL)
+                       free (datadir);
+               datadir = strdup (value);
+               if (datadir != NULL)
+               {
+                       int len = strlen (datadir);
+                       while ((len > 0) && (datadir[len - 1] == '/'))
+                       {
+                               len--;
+                               datadir[len] = '\0';
+                       }
+                       if (len <= 0)
+                       {
+                               free (datadir);
+                               datadir = NULL;
+                       }
+               }
+       }
+       else
+       {
+               return (-1);
+       }
+       return (0);
+} /* int csv_config */
+
+static int csv_write (const data_set_t *ds, const value_list_t *vl)
+{
+       struct stat  statbuf;
+       char         filename[512];
+       char         values[512];
+       FILE        *csv;
+       int          csv_fd;
+       struct flock fl;
+       int          status;
+
+       if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
+               return (-1);
+
+       DEBUG ("csv plugin: csv_write: filename = %s;", filename);
+
+       if (value_list_to_string (values, sizeof (values), ds, vl) != 0)
+               return (-1);
+
+       if (stat (filename, &statbuf) == -1)
+       {
+               if (errno == ENOENT)
+               {
+                       if (csv_create_file (filename, ds))
+                               return (-1);
+               }
+               else
+               {
+                       char errbuf[1024];
+                       ERROR ("stat(%s) failed: %s", filename,
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
+                       return (-1);
+               }
+       }
+       else if (!S_ISREG (statbuf.st_mode))
+       {
+               ERROR ("stat(%s): Not a regular file!",
+                               filename);
+               return (-1);
+       }
+
+       csv = fopen (filename, "a");
+       if (csv == NULL)
+       {
+               char errbuf[1024];
+               ERROR ("csv plugin: fopen (%s) failed: %s", filename,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
+       csv_fd = fileno (csv);
+
+       memset (&fl, '\0', sizeof (fl));
+       fl.l_start  = 0;
+       fl.l_len    = 0; /* till end of file */
+       fl.l_pid    = getpid ();
+       fl.l_type   = F_WRLCK;
+       fl.l_whence = SEEK_SET;
+
+       status = fcntl (csv_fd, F_SETLK, &fl);
+       if (status != 0)
+       {
+               char errbuf[1024];
+               ERROR ("csv plugin: flock (%s) failed: %s", filename,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               fclose (csv);
+               return (-1);
+       }
+
+       fprintf (csv, "%s\n", values);
+
+       /* The lock is implicitely released. I we don't release it explicitely
+        * because the `FILE *' may need to flush a cache first */
+       fclose (csv);
+
+       return (0);
+} /* int csv_write */
+
+void module_register (modreg_e load)
+{
+       if (load & MR_WRITE)
+       {
+               plugin_register_config ("csv", csv_config,
+                               config_keys, config_keys_num);
+               plugin_register_write ("csv", csv_write);
+       }
+} /* void module_register */
index d327164..afd3e0b 100644 (file)
--- a/src/df.c
+++ b/src/df.c
@@ -1,11 +1,10 @@
 /**
  * collectd - src/df.c
- * Copyright (C) 2005,2006  Florian octo Forster
+ * Copyright (C) 2005-2007  Florian octo Forster
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -27,8 +26,6 @@
 #include "utils_mount.h"
 #include "utils_ignorelist.h"
 
-#define MODULE_NAME "df"
-
 #if HAVE_STATFS || HAVE_STATVFS
 # define DF_HAVE_READ 1
 #else
 # define BLOCKSIZE(s) (s).f_bsize
 #endif
 
-static char *filename_template = "df-%s.rrd";
+/* 2^50 - 1 == 1125899906842623 = 1 Petabyte */
+static data_source_t dsrc[2] =
+{
+       {"free", DS_TYPE_GAUGE, 0, 1125899906842623.0},
+       {"used", DS_TYPE_GAUGE, 0, 1125899906842623.0}
+};
 
-static char *ds_def[] =
+static data_set_t ds =
 {
-       "DS:used:GAUGE:"COLLECTD_HEARTBEAT":0:U",
-       "DS:free:GAUGE:"COLLECTD_HEARTBEAT":0:U",
-       NULL
+       "df", 2, dsrc
 };
-static int ds_num = 2;
 
-static char *config_keys[] =
+#if DF_HAVE_READ
+static const char *config_keys[] =
 {
        "Device",
        "MountPoint",
@@ -73,9 +73,7 @@ static ignorelist_t *il_device = NULL;
 static ignorelist_t *il_mountpoint = NULL;
 static ignorelist_t *il_fstype = NULL;
 
-#define BUFSIZE 512
-
-static void df_init (void)
+static int df_init (void)
 {
        if (il_device == NULL)
                il_device = ignorelist_create (1);
@@ -84,10 +82,10 @@ static void df_init (void)
        if (il_fstype == NULL)
                il_fstype = ignorelist_create (1);
 
-       return;
+       return (0);
 }
 
-static int df_config (char *key, char *value)
+static int df_config (const char *key, const char *value)
 {
        df_init ();
 
@@ -131,35 +129,28 @@ static int df_config (char *key, char *value)
        return (-1);
 }
 
-static void df_write (char *host, char *inst, char *val)
-{
-       char file[BUFSIZE];
-       int status;
-
-       status = snprintf (file, BUFSIZE, filename_template, inst);
-       if (status < 1)
-               return;
-       else if (status >= BUFSIZE)
-               return;
-
-       rrd_update_file (host, file, val, ds_def, ds_num);
-}
-
-#if DF_HAVE_READ
 static void df_submit (char *df_name,
-               unsigned long long df_used,
-               unsigned long long df_free)
+               gauge_t df_used,
+               gauge_t df_free)
 {
-       char buf[BUFSIZE];
+       value_t values[2];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       if (snprintf (buf, BUFSIZE, "%u:%llu:%llu", (unsigned int) curtime,
-                               df_used, df_free) >= BUFSIZE)
-               return;
+       values[0].gauge = df_used;
+       values[1].gauge = df_free;
 
-       plugin_submit (MODULE_NAME, df_name, buf);
-}
+       vl.values = values;
+       vl.values_len = 2;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "df");
+       strcpy (vl.plugin_instance, "");
+       strncpy (vl.type_instance, df_name, sizeof (vl.type_instance));
+
+       plugin_dispatch_values ("df", &vl);
+} /* void df_submit */
 
-static void df_read (void)
+static int df_read (void)
 {
 #if HAVE_STATVFS
        struct statvfs statbuf;
@@ -171,19 +162,22 @@ static void df_read (void)
        cu_mount_t *mnt_ptr;
 
        unsigned long long blocksize;
-       unsigned long long df_free;
-       unsigned long long df_used;
-       char mnt_name[BUFSIZE];
+       gauge_t df_free;
+       gauge_t df_used;
+       char mnt_name[256];
 
        mnt_list = NULL;
        if (cu_mount_getlist (&mnt_list) == NULL)
-               return;
+               return (-1);
 
        for (mnt_ptr = mnt_list; mnt_ptr != NULL; mnt_ptr = mnt_ptr->next)
        {
                if (STATANYFS (mnt_ptr->dir, &statbuf) < 0)
                {
-                       syslog (LOG_ERR, "statv?fs failed: %s", strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("statv?fs failed: %s",
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        continue;
                }
 
@@ -196,13 +190,13 @@ static void df_read (void)
 
                if (strcmp (mnt_ptr->dir, "/") == 0)
                {
-                       strncpy (mnt_name, "root", BUFSIZE);
+                       strncpy (mnt_name, "root", sizeof (mnt_name));
                }
                else
                {
                        int i, len;
 
-                       strncpy (mnt_name, mnt_ptr->dir + 1, BUFSIZE);
+                       strncpy (mnt_name, mnt_ptr->dir + 1, sizeof (mnt_name));
                        len = strlen (mnt_name);
 
                        for (i = 0; i < len; i++)
@@ -224,16 +218,23 @@ static void df_read (void)
        }
 
        cu_mount_freelist (mnt_list);
-} /* static void df_read (void) */
-#else
-# define df_read NULL
+
+       return (0);
+} /* int df_read */
 #endif /* DF_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, df_init, df_read, df_write);
-       cf_register (MODULE_NAME, df_config, config_keys, config_keys_num);
-}
+       if (load & MR_DATASETS)
+               plugin_register_data_set (&ds);
 
-#undef BUFSIZE
-#undef MODULE_NAME
+#if DF_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_config ("df", df_config,
+                               config_keys, config_keys_num);
+               plugin_register_init ("df", df_init);
+               plugin_register_read ("df", df_read);
+       }
+#endif
+} /* void module_register */
index c809fdb..c9d2f36 100644 (file)
@@ -1,11 +1,10 @@
 /**
  * collectd - src/disk.c
- * Copyright (C) 2005,2006  Florian octo Forster
+ * Copyright (C) 2005-2007  Florian octo Forster
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -23,9 +22,6 @@
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
-#include "utils_debug.h"
-
-#define MODULE_NAME "disk"
 
 #if HAVE_MACH_MACH_TYPES_H
 #  include <mach/mach_types.h>
 # define DISK_HAVE_READ 0
 #endif
 
-static char *disk_filename_template = "disk-%s.rrd";
-static char *part_filename_template = "partition-%s.rrd";
+/* 2^34 = 17179869184 = ~17.2GByte/s */
+static data_source_t octets_dsrc[2] =
+{
+       {"read",  DS_TYPE_COUNTER, 0, 17179869183.0},
+       {"write", DS_TYPE_COUNTER, 0, 17179869183.0}
+};
+
+static data_set_t octets_ds =
+{
+       "disk_octets", 2, octets_dsrc
+};
+
+static data_source_t operations_dsrc[2] =
+{
+       {"read",  DS_TYPE_COUNTER, 0, 4294967295.0},
+       {"write", DS_TYPE_COUNTER, 0, 4294967295.0}
+};
+
+static data_set_t operations_ds =
+{
+       "disk_ops", 2, operations_dsrc
+};
+
+static data_source_t merged_dsrc[2] =
+{
+       {"read",  DS_TYPE_COUNTER, 0, 4294967295.0},
+       {"write", DS_TYPE_COUNTER, 0, 4294967295.0}
+};
+
+static data_set_t merged_ds =
+{
+       "disk_merged", 2, merged_dsrc
+};
 
-/* 104857600 == 100 MB */
-static char *disk_ds_def[] =
+/* max is 1000000us per second. */
+static data_source_t time_dsrc[2] =
 {
-       "DS:rcount:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:rmerged:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:rbytes:COUNTER:"COLLECTD_HEARTBEAT":0:104857600",
-       "DS:rtime:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:wcount:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:wmerged:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:wbytes:COUNTER:"COLLECTD_HEARTBEAT":0:104857600",
-       "DS:wtime:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       NULL
+       {"read",  DS_TYPE_COUNTER, 0, 1000000.0},
+       {"write", DS_TYPE_COUNTER, 0, 1000000.0}
 };
-static int disk_ds_num = 8;
 
-static char *part_ds_def[] =
+static data_set_t time_ds =
 {
-       "DS:rcount:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:rbytes:COUNTER:"COLLECTD_HEARTBEAT":0:104857600",
-       "DS:wcount:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:wbytes:COUNTER:"COLLECTD_HEARTBEAT":0:104857600",
-       NULL
+       "disk_time", 2, time_dsrc
 };
-static int part_ds_num = 4;
 
+#if DISK_HAVE_READ
 #if HAVE_IOKIT_IOKITLIB_H
 static mach_port_t io_master_port = MACH_PORT_NULL;
 /* #endif HAVE_IOKIT_IOKITLIB_H */
@@ -101,17 +116,16 @@ typedef struct diskstats
        /* This overflows in roughly 1361 year */
        unsigned int poll_count;
 
-       unsigned long long read_sectors;
-       unsigned long long write_sectors;
+       counter_t read_sectors;
+       counter_t write_sectors;
 
-       unsigned long long read_bytes;
-       unsigned long long write_bytes;
+       counter_t read_bytes;
+       counter_t write_bytes;
 
        struct diskstats *next;
 } diskstats_t;
 
 static diskstats_t *disklist;
-static int min_poll_count;
 /* #endif KERNEL_LINUX */
 
 #elif HAVE_LIBKSTAT
@@ -121,7 +135,7 @@ static kstat_t *ksp[MAX_NUMDISK];
 static int numdisk = 0;
 #endif /* HAVE_LIBKSTAT */
 
-static void disk_init (void)
+static int disk_init (void)
 {
 #if HAVE_IOKIT_IOKITLIB_H
        kern_return_t status;
@@ -136,25 +150,15 @@ static void disk_init (void)
        status = IOMasterPort (MACH_PORT_NULL, &io_master_port);
        if (status != kIOReturnSuccess)
        {
-               syslog (LOG_ERR, "IOMasterPort failed: %s",
+               ERROR ("IOMasterPort failed: %s",
                                mach_error_string (status));
                io_master_port = MACH_PORT_NULL;
-               return;
+               return (-1);
        }
 /* #endif HAVE_IOKIT_IOKITLIB_H */
 
 #elif KERNEL_LINUX
-       int step;
-       int heartbeat;
-
-       step = atoi (COLLECTD_STEP);
-       heartbeat = atoi (COLLECTD_HEARTBEAT);
-
-       assert (step > 0);
-       assert (heartbeat >= step);
-
-       min_poll_count = 1 + (heartbeat / step);
-       DBG ("min_poll_count = %i;", min_poll_count);
+       /* do nothing */
 /* #endif KERNEL_LINUX */
 
 #elif HAVE_LIBKSTAT
@@ -163,7 +167,7 @@ static void disk_init (void)
        numdisk = 0;
 
        if (kc == NULL)
-               return;
+               return (-1);
 
        for (numdisk = 0, ksp_chain = kc->kc_chain;
                        (numdisk < MAX_NUMDISK) && (ksp_chain != NULL);
@@ -178,83 +182,29 @@ static void disk_init (void)
        }
 #endif /* HAVE_LIBKSTAT */
 
-       return;
-}
-
-static void disk_write (char *host, char *inst, char *val)
-{
-       char file[512];
-       int status;
-
-       status = snprintf (file, 512, disk_filename_template, inst);
-       if (status < 1)
-               return;
-       else if (status >= 512)
-               return;
-
-       rrd_update_file (host, file, val, disk_ds_def, disk_ds_num);
-}
-
-static void partition_write (char *host, char *inst, char *val)
-{
-       char file[512];
-       int status;
-
-       status = snprintf (file, 512, part_filename_template, inst);
-       if (status < 1)
-               return;
-       else if (status >= 512)
-               return;
-
-       rrd_update_file (host, file, val, part_ds_def, part_ds_num);
-}
+       return (0);
+} /* int disk_init */
 
-#if DISK_HAVE_READ
-#define BUFSIZE 512
-static void disk_submit (char *disk_name,
-               unsigned long long read_count,
-               unsigned long long read_merged,
-               unsigned long long read_bytes,
-               unsigned long long read_time,
-               unsigned long long write_count,
-               unsigned long long write_merged,
-               unsigned long long write_bytes,
-               unsigned long long write_time)
+static void disk_submit (const char *plugin_instance,
+               const char *type,
+               counter_t read, counter_t write)
 {
-       char buf[BUFSIZE];
+       value_t values[2];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       if (snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu",
-                               (unsigned int) curtime,
-                               read_count, read_merged, read_bytes, read_time,
-                               write_count, write_merged, write_bytes,
-                               write_time) >= BUFSIZE)
-               return;
+       values[0].counter = read;
+       values[1].counter = write;
 
-       DBG ("disk_name = %s; buf = %s;",
-                       disk_name, buf);
-
-       plugin_submit (MODULE_NAME, disk_name, buf);
-}
-
-#if KERNEL_LINUX || HAVE_LIBKSTAT
-static void partition_submit (char *part_name,
-               unsigned long long read_count,
-               unsigned long long read_bytes,
-               unsigned long long write_count,
-               unsigned long long write_bytes)
-{
-       char buf[BUFSIZE];
+       vl.values = values;
+       vl.values_len = 2;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "disk");
+       strncpy (vl.plugin_instance, plugin_instance,
+                       sizeof (vl.plugin_instance));
 
-       if (snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu",
-                               (unsigned int) curtime,
-                               read_count, read_bytes, write_count,
-                               write_bytes) >= BUFSIZE)
-               return;
-
-       plugin_submit ("partition", part_name, buf);
-}
-#endif /* KERNEL_LINUX || HAVE_LIBKSTAT */
-#undef BUFSIZE
+       plugin_dispatch_values (type, &vl);
+} /* void disk_submit */
 
 #if HAVE_IOKIT_IOKITLIB_H
 static signed long long dict_get_value (CFDictionaryRef dict, const char *key)
@@ -268,7 +218,7 @@ static signed long long dict_get_value (CFDictionaryRef dict, const char *key)
                        kCFStringEncodingASCII);
        if (key_obj == NULL)
        {
-               DBG ("CFStringCreateWithCString (%s) failed.", key);
+               DEBUG ("CFStringCreateWithCString (%s) failed.", key);
                return (-1LL);
        }
        
@@ -279,13 +229,13 @@ static signed long long dict_get_value (CFDictionaryRef dict, const char *key)
 
        if (val_obj == NULL)
        {
-               DBG ("CFDictionaryGetValue (%s) failed.", key);
+               DEBUG ("CFDictionaryGetValue (%s) failed.", key);
                return (-1LL);
        }
 
        if (!CFNumberGetValue (val_obj, kCFNumberSInt64Type, &val_int))
        {
-               DBG ("CFNumberGetValue (%s) failed.", key);
+               DEBUG ("CFNumberGetValue (%s) failed.", key);
                return (-1LL);
        }
 
@@ -293,7 +243,7 @@ static signed long long dict_get_value (CFDictionaryRef dict, const char *key)
 }
 #endif /* HAVE_IOKIT_IOKITLIB_H */
 
-static void disk_read (void)
+static int disk_read (void)
 {
 #if HAVE_IOKIT_IOKITLIB_H
        io_registry_entry_t     disk;
@@ -324,7 +274,7 @@ static void disk_read (void)
        {
                plugin_complain (LOG_ERR, &complain_obj, "disk plugin: "
                                "IOServiceGetMatchingServices failed.");
-               return;
+               return (-1);
        }
        else if (complain_obj.interval != 0)
        {
@@ -343,7 +293,7 @@ static void disk_read (void)
                                != kIOReturnSuccess)
                {
                        /* This fails for example for DVD/CD drives.. */
-                       DBG ("IORegistryEntryGetChildEntry (disk) failed: 0x%08x", status);
+                       DEBUG ("IORegistryEntryGetChildEntry (disk) failed: 0x%08x", status);
                        IOObjectRelease (disk);
                        continue;
                }
@@ -355,7 +305,7 @@ static void disk_read (void)
                                        kNilOptions)
                                != kIOReturnSuccess)
                {
-                       syslog (LOG_ERR, "disk-plugin: IORegistryEntryCreateCFProperties failed.");
+                       ERROR ("disk-plugin: IORegistryEntryCreateCFProperties failed.");
                        IOObjectRelease (disk_child);
                        IOObjectRelease (disk);
                        continue;
@@ -363,7 +313,7 @@ static void disk_read (void)
 
                if (props_dict == NULL)
                {
-                       DBG ("IORegistryEntryCreateCFProperties (disk) failed.");
+                       DEBUG ("IORegistryEntryCreateCFProperties (disk) failed.");
                        IOObjectRelease (disk_child);
                        IOObjectRelease (disk);
                        continue;
@@ -374,7 +324,7 @@ static void disk_read (void)
 
                if (stats_dict == NULL)
                {
-                       DBG ("CFDictionaryGetValue (%s) failed.",
+                       DEBUG ("CFDictionaryGetValue (%s) failed.",
                                        kIOBlockStorageDriverStatisticsKey);
                        CFRelease (props_dict);
                        IOObjectRelease (disk_child);
@@ -388,13 +338,14 @@ static void disk_read (void)
                                        kNilOptions)
                                != kIOReturnSuccess)
                {
-                       DBG ("IORegistryEntryCreateCFProperties (disk_child) failed.");
+                       DEBUG ("IORegistryEntryCreateCFProperties (disk_child) failed.");
                        IOObjectRelease (disk_child);
                        CFRelease (props_dict);
                        IOObjectRelease (disk);
                        continue;
                }
 
+               /* kIOBSDNameKey */
                disk_major = (int) dict_get_value (child_dict,
                                kIOBSDMajorKey);
                disk_minor = (int) dict_get_value (child_dict,
@@ -409,29 +360,33 @@ static void disk_read (void)
                                kIOBlockStorageDriverStatisticsWritesKey);
                write_byt = dict_get_value (stats_dict,
                                kIOBlockStorageDriverStatisticsBytesWrittenKey);
+               /* This property describes the number of nanoseconds spent
+                * performing writes since the block storage driver was
+                * instantiated. It is one of the statistic entries listed
+                * under the top-level kIOBlockStorageDriverStatisticsKey
+                * property table. It has an OSNumber value. */
                write_tme = dict_get_value (stats_dict,
                                kIOBlockStorageDriverStatisticsTotalWriteTimeKey);
 
                if (snprintf (disk_name, 64, "%i-%i", disk_major, disk_minor) >= 64)
                {
-                       DBG ("snprintf (major, minor) failed.");
+                       DEBUG ("snprintf (major, minor) failed.");
                        CFRelease (child_dict);
                        IOObjectRelease (disk_child);
                        CFRelease (props_dict);
                        IOObjectRelease (disk);
                        continue;
                }
-               DBG ("disk_name = %s", disk_name);
-
-               if ((read_ops != -1LL)
-                               || (read_byt != -1LL)
-                               || (read_tme != -1LL)
-                               || (write_ops != -1LL)
-                               || (write_byt != -1LL)
-                               || (write_tme != -1LL))
-                       disk_submit (disk_name,
-                                       read_ops, 0ULL, read_byt, read_tme,
-                                       write_ops, 0ULL, write_byt, write_tme);
+               DEBUG ("disk_name = %s", disk_name);
+
+               if ((read_byt != -1LL) || (write_byt != -1LL))
+                       disk_submit (disk_name, "disk_octets", read_byt, write_byt);
+               if ((read_ops != -1LL) || (write_ops != -1LL))
+                       disk_submit (disk_name, "disk_ops", read_ops, write_ops);
+               if ((read_tme != -1LL) || (write_tme != -1LL))
+                       disk_submit (disk_name, "disk_time",
+                                       read_tme / 1000,
+                                       write_tme / 1000);
 
                CFRelease (child_dict);
                IOObjectRelease (disk_child);
@@ -444,7 +399,6 @@ static void disk_read (void)
 #elif KERNEL_LINUX
        FILE *fh;
        char buffer[1024];
-       char disk_name[128];
        
        char *fields[32];
        int numfields;
@@ -453,17 +407,17 @@ static void disk_read (void)
        int major = 0;
        int minor = 0;
 
-       unsigned long long read_sectors  = 0ULL;
-       unsigned long long write_sectors = 0ULL;
-
-       unsigned long long read_count    = 0ULL;
-       unsigned long long read_merged   = 0ULL;
-       unsigned long long read_bytes    = 0ULL;
-       unsigned long long read_time     = 0ULL;
-       unsigned long long write_count   = 0ULL;
-       unsigned long long write_merged  = 0ULL;
-       unsigned long long write_bytes   = 0ULL;
-       unsigned long long write_time    = 0ULL;
+       counter_t read_sectors  = 0;
+       counter_t write_sectors = 0;
+
+       counter_t read_count    = 0;
+       counter_t read_merged   = 0;
+       counter_t read_bytes    = 0;
+       counter_t read_time     = 0;
+       counter_t write_count   = 0;
+       counter_t write_merged  = 0;
+       counter_t write_bytes   = 0;
+       counter_t write_time    = 0;
        int is_disk = 0;
 
        diskstats_t *ds, *pre_ds;
@@ -474,18 +428,23 @@ static void disk_read (void)
        {
                if ((fh = fopen ("/proc/partitions", "r")) == NULL)
                {
-                       plugin_complain (LOG_ERR, &complain_obj, "disk plugin: Failed to open /proc/{diskstats,partitions}.");
-                       return;
+                       plugin_complain (LOG_ERR, &complain_obj,
+                                       "disk plugin: Failed to open /proc/"
+                                       "{diskstats,partitions}.");
+                       return (-1);
                }
 
                /* Kernel is 2.4.* */
                fieldshift = 1;
        }
 
-       plugin_relief (LOG_NOTICE, &complain_obj, "disk plugin: Succeeded to open /proc/{diskstats,partitions}.");
+       plugin_relief (LOG_NOTICE, &complain_obj, "disk plugin: "
+                       "Succeeded to open /proc/{diskstats,partitions}.");
 
-       while (fgets (buffer, 1024, fh) != NULL)
+       while (fgets (buffer, sizeof (buffer), fh) != NULL)
        {
+               char *disk_name;
+
                numfields = strsplit (buffer, fields, 32);
 
                if ((numfields != (14 + fieldshift)) && (numfields != 7))
@@ -494,9 +453,7 @@ static void disk_read (void)
                major = atoll (fields[0]);
                minor = atoll (fields[1]);
 
-               if (snprintf (disk_name, 128, "%i-%i", major, minor) < 1)
-                       continue;
-               disk_name[127] = '\0';
+               disk_name = fields[2];
 
                for (ds = disklist, pre_ds = disklist; ds != NULL; pre_ds = ds, ds = ds->next)
                        if (strcmp (disk_name, ds->name) == 0)
@@ -547,7 +504,7 @@ static void disk_read (void)
                }
                else
                {
-                       DBG ("numfields = %i; => unknown file format.", numfields);
+                       DEBUG ("numfields = %i; => unknown file format.", numfields);
                        continue;
                }
 
@@ -569,25 +526,34 @@ static void disk_read (void)
 
                /* Don't write to the RRDs if we've just started.. */
                ds->poll_count++;
-               if (ds->poll_count <= min_poll_count)
+               if (ds->poll_count <= 2)
                {
-                       DBG ("(ds->poll_count = %i) <= (min_poll_count = %i); => Not writing.",
-                                       ds->poll_count, min_poll_count);
+                       DEBUG ("(ds->poll_count = %i) <= (min_poll_count = 2); => Not writing.",
+                                       ds->poll_count);
                        continue;
                }
 
                if ((read_count == 0) && (write_count == 0))
                {
-                       DBG ("((read_count == 0) && (write_count == 0)); => Not writing.");
+                       DEBUG ("((read_count == 0) && (write_count == 0)); => Not writing.");
                        continue;
                }
 
+               if ((read_bytes != -1LL) || (write_bytes != -1LL))
+                       disk_submit (disk_name, "disk_octets", read_bytes, write_bytes);
+               if ((read_count != -1LL) || (write_count != -1LL))
+                       disk_submit (disk_name, "disk_ops", read_count, write_count);
                if (is_disk)
-                       disk_submit (disk_name, read_count, read_merged, read_bytes, read_time,
-                                       write_count, write_merged, write_bytes, write_time);
-               else
-                       partition_submit (disk_name, read_count, read_bytes, write_count, write_bytes);
-       }
+               {
+                       if ((read_merged != -1LL) || (write_merged != -1LL))
+                               disk_submit (disk_name, "disk_merged",
+                                               read_merged, write_merged);
+                       if ((read_time != -1LL) || (write_time != -1LL))
+                               disk_submit (disk_name, "disk_time",
+                                               read_time * 1000,
+                                               write_time * 1000);
+               }
+       } /* while (fgets (buffer, sizeof (buffer), fh) != NULL) */
 
        fclose (fh);
 /* #endif defined(KERNEL_LINUX) */
@@ -597,7 +563,7 @@ static void disk_read (void)
        int i;
 
        if (kc == NULL)
-               return;
+               return (-1);
 
        for (i = 0; i < numdisk; i++)
        {
@@ -605,24 +571,39 @@ static void disk_read (void)
                        continue;
 
                if (strncmp (ksp[i]->ks_class, "disk", 4) == 0)
-                       disk_submit (ksp[i]->ks_name,
-                                       kio.reads,  0LL, kio.nread,    kio.rtime,
-                                       kio.writes, 0LL, kio.nwritten, kio.wtime);
+               {
+                       disk_submit (ksp[i]->ks_name, "disk_octets", kio.reads, kio.writes);
+                       disk_submit (ksp[i]->ks_name, "disk_ops", kio.nreads, kio.nwrites);
+                       /* FIXME: Convert this to microseconds if necessary */
+                       disk_submit (ksp[i]->ks_name, "disk_time", kio.rtime, kio.wtime);
+               }
                else if (strncmp (ksp[i]->ks_class, "partition", 9) == 0)
-                       partition_submit (ksp[i]->ks_name,
-                                       kio.reads, kio.nread,
-                                       kio.writes,kio.nwritten);
+               {
+                       disk_submit (ksp[i]->ks_name, "disk_octets", kio.reads, kio.writes);
+                       disk_submit (ksp[i]->ks_name, "disk_ops", kio.nreads, kio.nwrites);
+               }
        }
 #endif /* defined(HAVE_LIBKSTAT) */
-} /* static void disk_read (void) */
-#else
-# define disk_read NULL
+
+       return (0);
+} /* int disk_read */
 #endif /* DISK_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register ("partition", NULL, NULL, partition_write);
-       plugin_register (MODULE_NAME, disk_init, disk_read, disk_write);
-}
+       if (load & MR_DATASETS)
+       {
+               plugin_register_data_set (&octets_ds);
+               plugin_register_data_set (&operations_ds);
+               plugin_register_data_set (&merged_ds);
+               plugin_register_data_set (&time_ds);
+       }
 
-#undef MODULE_NAME
+#if DISK_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_init ("disk", disk_init);
+               plugin_register_read ("disk", disk_read);
+       }
+#endif /* DISK_HAVE_READ */
+} /* void module_register */
index cd73a7e..c9beb16 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
@@ -1,11 +1,10 @@
 /**
  * collectd - src/dns.c
- * Copyright (C) 2006  Florian octo Forster
+ * Copyright (C) 2006,2007  Florian octo Forster
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
 #include "common.h"
 #include "plugin.h"
 #include "configfile.h"
-#include "utils_debug.h"
-
-#define MODULE_NAME "dns"
 
 #if HAVE_LIBPCAP && HAVE_LIBPTHREAD
 # include "utils_dns.h"
 # include <pthread.h>
 # include <pcap.h>
-# include <sys/poll.h>
+# include <poll.h>
 # define DNS_HAVE_READ 1
 #else
 # define DNS_HAVE_READ 0
@@ -54,43 +50,39 @@ typedef struct counter_list_s counter_list_t;
 /*
  * Private variables
  */
-static char *traffic_file   = "dns/dns_traffic.rrd";
-static char *qtype_file   = "dns/qtype-%s.rrd";
-static char *opcode_file  = "dns/opcode-%s.rrd";
-static char *rcode_file   = "dns/rcode-%s.rrd";
+static data_source_t octets_dsrc[2] =
+{
+       {"queries",   DS_TYPE_COUNTER, 0, 125000000.0},
+       {"responses", DS_TYPE_COUNTER, 0, 125000000.0}
+};
 
-static char *traffic_ds_def[] =
+static data_set_t octets_ds =
 {
-       /* Limit to 1GBit/s */
-       "DS:queries:COUNTER:"COLLECTD_HEARTBEAT":0:125000000",
-       "DS:responses:COUNTER:"COLLECTD_HEARTBEAT":0:125000000",
-       NULL
+       "dns_octets", 2, octets_dsrc
 };
-static int traffic_ds_num = 2;
 
-static char *qtype_ds_def[] =
+static data_source_t counter_dsrc[1] =
 {
-       "DS:value:COUNTER:"COLLECTD_HEARTBEAT":0:65535",
-       NULL
+       {"value", DS_TYPE_COUNTER, 0, 65535.0}
 };
-static int qtype_ds_num = 1;
 
-static char *opcode_ds_def[] =
+static data_set_t qtype_ds =
 {
-       "DS:value:COUNTER:"COLLECTD_HEARTBEAT":0:65535",
-       NULL
+       "dns_qtype", 1, counter_dsrc
 };
-static int opcode_ds_num = 1;
 
-static char *rcode_ds_def[] =
+static data_set_t opcode_ds =
 {
-       "DS:value:COUNTER:"COLLECTD_HEARTBEAT":0:65535",
-       NULL
+       "dns_opcode", 1, counter_dsrc
+};
+
+static data_set_t rcode_ds =
+{
+       "dns_rcode", 1, counter_dsrc
 };
-static int rcode_ds_num = 1;
 
 #if DNS_HAVE_READ
-static char *config_keys[] =
+static const char *config_keys[] =
 {
        "Interface",
        "IgnoreSource",
@@ -101,8 +93,8 @@ static int config_keys_num = 2;
 #define PCAP_SNAPLEN 1460
 static char   *pcap_device = NULL;
 
-static unsigned int    tr_queries;
-static unsigned int    tr_responses;
+static counter_t       tr_queries;
+static counter_t       tr_responses;
 static counter_list_t *qtype_list;
 static counter_list_t *opcode_list;
 static counter_list_t *rcode_list;
@@ -124,14 +116,14 @@ static counter_list_t *counter_list_search (counter_list_t **list, unsigned int
 {
        counter_list_t *entry;
 
-       DBG ("counter_list_search (list = %p, key = %u)",
+       DEBUG ("counter_list_search (list = %p, key = %u)",
                        (void *) *list, key);
 
        for (entry = *list; entry != NULL; entry = entry->next)
                if (entry->key == key)
                        break;
 
-       DBG ("return (%p)", (void *) entry);
+       DEBUG ("return (%p)", (void *) entry);
        return (entry);
 }
 
@@ -140,7 +132,7 @@ static counter_list_t *counter_list_create (counter_list_t **list,
 {
        counter_list_t *entry;
 
-       DBG ("counter_list_create (list = %p, key = %u, value = %u)",
+       DEBUG ("counter_list_create (list = %p, key = %u, value = %u)",
                        (void *) *list, key, value);
 
        entry = (counter_list_t *) malloc (sizeof (counter_list_t));
@@ -166,7 +158,7 @@ static counter_list_t *counter_list_create (counter_list_t **list,
                last->next = entry;
        }
 
-       DBG ("return (%p)", (void *) entry);
+       DEBUG ("return (%p)", (void *) entry);
        return (entry);
 }
 
@@ -175,7 +167,7 @@ static void counter_list_add (counter_list_t **list,
 {
        counter_list_t *entry;
 
-       DBG ("counter_list_add (list = %p, key = %u, increment = %u)",
+       DEBUG ("counter_list_add (list = %p, key = %u, increment = %u)",
                        (void *) *list, key, increment);
 
        entry = counter_list_search (list, key);
@@ -188,10 +180,10 @@ static void counter_list_add (counter_list_t **list,
        {
                counter_list_create (list, key, increment);
        }
-       DBG ("return ()");
+       DEBUG ("return ()");
 }
 
-static int dns_config (char *key, char *value)
+static int dns_config (const char *key, const char *value)
 {
        if (strcasecmp (key, "Interface") == 0)
        {
@@ -260,15 +252,15 @@ static void *dns_child_loop (void *dummy)
        }
 
        /* Passing `pcap_device == NULL' is okay and the same as passign "any" */
-       DBG ("Creating PCAP object..");
+       DEBUG ("Creating PCAP object..");
        pcap_obj = pcap_open_live (pcap_device,
                        PCAP_SNAPLEN,
                        0 /* Not promiscuous */,
-                       atoi (COLLECTD_STEP),
+                       interval_g,
                        pcap_error);
        if (pcap_obj == NULL)
        {
-               syslog (LOG_ERR, "dns plugin: Opening interface `%s' "
+               ERROR ("dns plugin: Opening interface `%s' "
                                "failed: %s",
                                (pcap_device != NULL) ? pcap_device : "any",
                                pcap_error);
@@ -278,18 +270,18 @@ static void *dns_child_loop (void *dummy)
        memset (&fp, 0, sizeof (fp));
        if (pcap_compile (pcap_obj, &fp, "udp port 53", 1, 0) < 0)
        {
-               DBG ("pcap_compile failed");
-               syslog (LOG_ERR, "dns plugin: pcap_compile failed");
+               DEBUG ("pcap_compile failed");
+               ERROR ("dns plugin: pcap_compile failed");
                return (NULL);
        }
        if (pcap_setfilter (pcap_obj, &fp) < 0)
        {
-               DBG ("pcap_setfilter failed");
-               syslog (LOG_ERR, "dns plugin: pcap_setfilter failed");
+               DEBUG ("pcap_setfilter failed");
+               ERROR ("dns plugin: pcap_setfilter failed");
                return (NULL);
        }
 
-       DBG ("PCAP object created.");
+       DEBUG ("PCAP object created.");
 
        dnstop_set_pcap_obj (pcap_obj);
        dnstop_set_callback (dns_child_callback);
@@ -299,10 +291,10 @@ static void *dns_child_loop (void *dummy)
                        handle_pcap /* callback */,
                        NULL /* Whatever this means.. */);
        if (status < 0)
-               syslog (LOG_ERR, "dns plugin: Listener thread is exiting "
+               ERROR ("dns plugin: Listener thread is exiting "
                                "abnormally: %s", pcap_geterr (pcap_obj));
 
-       DBG ("child is exiting");
+       DEBUG ("child is exiting");
 
        pcap_close (pcap_obj);
        listen_thread_init = 0;
@@ -310,11 +302,9 @@ static void *dns_child_loop (void *dummy)
 
        return (NULL);
 } /* static void dns_child_loop (void) */
-#endif /* DNS_HAVE_READ */
 
-static void dns_init (void)
+static int dns_init (void)
 {
-#if DNS_HAVE_READ
        /* clean up an old thread */
        int status;
 
@@ -324,131 +314,59 @@ static void dns_init (void)
        pthread_mutex_unlock (&traffic_mutex);
 
        if (listen_thread_init != 0)
-               return;
+               return (-1);
 
        status = pthread_create (&listen_thread, NULL, dns_child_loop,
                        (void *) 0);
        if (status != 0)
        {
-               syslog (LOG_ERR, "dns plugin: pthread_create failed: %s",
-                               strerror (status));
-               return;
+               char errbuf[1024];
+               ERROR ("dns plugin: pthread_create failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
        }
 
        listen_thread_init = 1;
-#endif /* DNS_HAVE_READ */
-}
-
-static void traffic_write (char *host, char *inst, char *val)
-{
-       rrd_update_file (host, traffic_file, val,
-                       traffic_ds_def, traffic_ds_num);
-}
-
-static void qtype_write (char *host, char *inst, char *val)
-{
-       char file[512];
-       int status;
-
-       status = snprintf (file, 512, qtype_file, inst);
-       if (status < 1)
-               return;
-       else if (status >= 512)
-               return;
-
-       rrd_update_file (host, file, val, qtype_ds_def, qtype_ds_num);
-}
-
-static void rcode_write (char *host, char *inst, char *val)
-{
-       char file[512];
-       int status;
-
-       status = snprintf (file, 512, rcode_file, inst);
-       if (status < 1)
-               return;
-       else if (status >= 512)
-               return;
-
-       rrd_update_file (host, file, val, rcode_ds_def, rcode_ds_num);
-}
 
-static void opcode_write (char *host, char *inst, char *val)
-{
-       char file[512];
-       int status;
-
-       status = snprintf (file, 512, opcode_file, inst);
-       if (status < 1)
-               return;
-       else if (status >= 512)
-               return;
-
-       rrd_update_file (host, file, val, opcode_ds_def, opcode_ds_num);
-}
-
-#if DNS_HAVE_READ
-static void traffic_submit (unsigned int queries, unsigned int replies)
-{
-       char buffer[64];
-       int  status;
-
-       status = snprintf (buffer, 64, "N:%u:%u", queries, replies);
-       if ((status < 1) || (status >= 64))
-               return;
-
-       plugin_submit ("dns_traffic", "-", buffer);
-}
-
-static void qtype_submit (int qtype, unsigned int counter)
-{
-       char inst[32];
-       char buffer[32];
-       int  status;
-
-       strncpy (inst, qtype_str (qtype), 32);
-       inst[31] = '\0';
-
-       status = snprintf (buffer, 32, "N:%u", counter);
-       if ((status < 1) || (status >= 32))
-               return;
-
-       plugin_submit ("dns_qtype", inst, buffer);
-}
+       return (0);
+} /* int dns_init */
 
-static void rcode_submit (int rcode, unsigned int counter)
+static void submit_counter (const char *type, const char *type_instance,
+               counter_t value)
 {
-       char inst[32];
-       char buffer[32];
-       int  status;
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       strncpy (inst, rcode_str (rcode), 32);
-       inst[31] = '\0';
+       values[0].counter = value;
 
-       status = snprintf (buffer, 32, "N:%u", counter);
-       if ((status < 1) || (status >= 32))
-               return;
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "dns");
+       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       plugin_submit ("dns_rcode", inst, buffer);
-}
+       plugin_dispatch_values (type, &vl);
+} /* void submit_counter */
 
-static void opcode_submit (int opcode, unsigned int counter)
+static void submit_octets (counter_t queries, counter_t responses)
 {
-       char inst[32];
-       char buffer[32];
-       int  status;
+       value_t values[2];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       strncpy (inst, opcode_str (opcode), 32);
-       inst[31] = '\0';
+       values[0].counter = queries;
+       values[1].counter = responses;
 
-       status = snprintf (buffer, 32, "N:%u", counter);
-       if ((status < 1) || (status >= 32))
-               return;
+       vl.values = values;
+       vl.values_len = 2;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "dns");
 
-       plugin_submit ("dns_opcode", inst, buffer);
-}
+       plugin_dispatch_values ("dns_octets", &vl);
+} /* void submit_counter */
 
-static void dns_read (void)
+static int dns_read (void)
 {
        unsigned int keys[T_MAX];
        unsigned int values[T_MAX];
@@ -461,7 +379,7 @@ static void dns_read (void)
        values[0] = tr_queries;
        values[1] = tr_responses;
        pthread_mutex_unlock (&traffic_mutex);
-       traffic_submit (values[0], values[1]);
+       submit_octets (values[0], values[1]);
 
        pthread_mutex_lock (&qtype_mutex);
        for (ptr = qtype_list, len = 0;
@@ -475,8 +393,8 @@ static void dns_read (void)
 
        for (i = 0; i < len; i++)
        {
-               DBG ("qtype = %u; counter = %u;", keys[i], values[i]);
-               qtype_submit (keys[i], values[i]);
+               DEBUG ("qtype = %u; counter = %u;", keys[i], values[i]);
+               submit_counter ("dns_qtype", qtype_str (keys[i]), values[i]);
        }
 
        pthread_mutex_lock (&opcode_mutex);
@@ -491,8 +409,8 @@ static void dns_read (void)
 
        for (i = 0; i < len; i++)
        {
-               DBG ("opcode = %u; counter = %u;", keys[i], values[i]);
-               opcode_submit (keys[i], values[i]);
+               DEBUG ("opcode = %u; counter = %u;", keys[i], values[i]);
+               submit_counter ("dns_opcode", opcode_str (keys[i]), values[i]);
        }
 
        pthread_mutex_lock (&rcode_mutex);
@@ -507,24 +425,30 @@ static void dns_read (void)
 
        for (i = 0; i < len; i++)
        {
-               DBG ("rcode = %u; counter = %u;", keys[i], values[i]);
-               rcode_submit (keys[i], values[i]);
+               DEBUG ("rcode = %u; counter = %u;", keys[i], values[i]);
+               submit_counter ("dns_rcode", rcode_str (keys[i]), values[i]);
        }
-}
-#else /* if !DNS_HAVE_READ */
-# define dns_read NULL
+
+       return (0);
+} /* int dns_read */
 #endif
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, dns_init, dns_read, NULL);
-       plugin_register ("dns_traffic", NULL, NULL, traffic_write);
-       plugin_register ("dns_qtype", NULL, NULL, qtype_write);
-       plugin_register ("dns_rcode", NULL, NULL, rcode_write);
-       plugin_register ("dns_opcode", NULL, NULL, opcode_write);
+       if (load & MR_DATASETS)
+       {
+               plugin_register_data_set (&octets_ds);
+               plugin_register_data_set (&qtype_ds);
+               plugin_register_data_set (&opcode_ds);
+               plugin_register_data_set (&rcode_ds);
+       }
+
 #if DNS_HAVE_READ
-       cf_register (MODULE_NAME, dns_config, config_keys, config_keys_num);
+       if (load & MR_READ)
+       {
+               plugin_register_config ("dns", dns_config, config_keys, config_keys_num);
+               plugin_register_init ("dns", dns_init);
+               plugin_register_read ("dns", dns_read);
+       }
 #endif
-}
-
-#undef MODULE_NAME
+} /* void module_register */
index bbee9bb..ed58819 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/email.c
- * Copyright (C) 2006  Sebastian Harl
+ * Copyright (C) 2006,2007  Sebastian Harl
  *
  * 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
@@ -42,9 +42,6 @@
 
 #if HAVE_LIBPTHREAD
 # include <pthread.h>
-# define EMAIL_HAVE_READ 1
-#else
-# define EMAIL_HAVE_READ 0
 #endif
 
 #if HAVE_SYS_SELECT_H
 #define MAX_CONNS 5
 #define MAX_CONNS_LIMIT 16384
 
-#define log_err(...) syslog (LOG_ERR, MODULE_NAME": "__VA_ARGS__)
-#define log_warn(...) syslog (LOG_WARNING, MODULE_NAME": "__VA_ARGS__)
+#define log_err(...) ERROR (MODULE_NAME": "__VA_ARGS__)
+#define log_warn(...) WARNING (MODULE_NAME": "__VA_ARGS__)
 
 /*
  * Private data structures
  */
-#if EMAIL_HAVE_READ
 /* linked list of email and check types */
 typedef struct type {
        char        *name;
@@ -128,21 +124,48 @@ typedef struct {
        conn_t *head;
        conn_t *tail;
 } conn_list_t;
-#endif /* EMAIL_HAVE_READ */
 
 /*
  * Private variables
  */
-#if EMAIL_HAVE_READ
 /* valid configuration file keys */
-static char *config_keys[] =
+static const char *config_keys[] =
 {
        "SocketGroup",
        "SocketPerms",
-       "MaxConns",
-       NULL
+       "MaxConns"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static data_source_t gauge_dsrc[1] =
+{
+       {"value", DS_TYPE_GAUGE, 0.0, NAN}
+};
+
+static data_set_t email_count_ds =
+{
+       "email_count", 1, gauge_dsrc
+};
+
+static data_set_t email_size_ds =
+{
+       "email_size", 1, gauge_dsrc
+};
+
+static data_set_t spam_check_ds =
+{
+       "spam_check", 1, gauge_dsrc
+};
+
+static data_source_t spam_score_dsrc[1] =
+{
+       {"score", DS_TYPE_GAUGE, NAN, NAN}
+};
+
+static data_set_t spam_score_ds =
+{
+       "spam_score", 1, spam_score_dsrc
 };
-static int config_keys_num = 3;
 
 /* socket configuration */
 static char *sock_group = COLLECTD_GRP_NAME;
@@ -184,42 +207,11 @@ static int score_count;
 
 static pthread_mutex_t check_mutex = PTHREAD_MUTEX_INITIALIZER;
 static type_list_t check;
-#endif /* EMAIL_HAVE_READ */
-
-#define COUNT_FILE "email/email-%s.rrd"
-static char *count_ds_def[] =
-{
-       "DS:count:GAUGE:"COLLECTD_HEARTBEAT":0:U",
-       NULL
-};
-static int count_ds_num = 1;
-
-#define SIZE_FILE  "email/email_size-%s.rrd"
-static char *size_ds_def[] =
-{
-       "DS:size:GAUGE:"COLLECTD_HEARTBEAT":0:U",
-       NULL
-};
-static int size_ds_num = 1;
 
-#define SCORE_FILE "email/spam_score.rrd"
-static char *score_ds_def[] =
-{
-       "DS:score:GAUGE:"COLLECTD_HEARTBEAT":U:U",
-       NULL
-};
-static int score_ds_num = 1;
-
-#define CHECK_FILE "email/spam_check-%s.rrd"
-static char *check_ds_def[] =
-{
-       "DS:hits:GAUGE:"COLLECTD_HEARTBEAT":0:U",
-       NULL
-};
-static int check_ds_num = 1;
-
-#if EMAIL_HAVE_READ
-static int email_config (char *key, char *value)
+/*
+ * Private functions
+ */
+static int email_config (const char *key, const char *value)
 {
        if (0 == strcasecmp (key, "SocketGroup")) {
                sock_group = sstrdup (value);
@@ -300,7 +292,9 @@ static char read_char (conn_t *src)
        FD_SET (src->socket, &fdset);
 
        if (-1 == select (src->socket + 1, &fdset, NULL, NULL, NULL)) {
-               log_err ("select() failed: %s", strerror (errno));
+               char errbuf[1024];
+               log_err ("select() failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                return '\0';
        }
 
@@ -312,7 +306,9 @@ static char read_char (conn_t *src)
                errno = 0;
                if (0 > (len = read (src->socket, (void *)&ret, 1))) {
                        if (EINTR != errno) {
-                               log_err ("read() failed: %s", strerror (errno));
+                               char errbuf[1024];
+                               log_err ("read() failed: %s",
+                                               sstrerror (errno, errbuf, sizeof (errbuf)));
                                return '\0';
                        }
                }
@@ -361,7 +357,9 @@ static char *read_line (conn_t *src)
                FD_SET (src->socket, &fdset);
 
                if (-1 == select (src->socket + 1, &fdset, NULL, NULL, NULL)) {
-                       log_err ("select() failed: %s", strerror (errno));
+                       char errbuf[1024];
+                       log_err ("select() failed: %s",
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
                        return NULL;
                }
 
@@ -373,7 +371,9 @@ static char *read_line (conn_t *src)
                                                        (void *)(src->buffer + src->idx),
                                                        BUFSIZE - src->idx))) {
                                if (EINTR != errno) {
-                                       log_err ("read() failed: %s", strerror (errno));
+                                       char errbuf[1024];
+                                       log_err ("read() failed: %s",
+                                                       sstrerror (errno, errbuf, sizeof (errbuf)));
                                        return NULL;
                                }
                        }
@@ -445,13 +445,17 @@ static void *collect (void *arg)
 
                        errno = 0;
                        if (-1 == fcntl (connection->socket, F_GETFL, &flags)) {
-                               log_err ("fcntl() failed: %s", strerror (errno));
+                               char errbuf[1024];
+                               log_err ("fcntl() failed: %s",
+                                               sstrerror (errno, errbuf, sizeof (errbuf)));
                                loop = 0;
                        }
 
                        errno = 0;
                        if (-1 == fcntl (connection->socket, F_SETFL, flags | O_NONBLOCK)) {
-                               log_err ("fcntl() failed: %s", strerror (errno));
+                               char errbuf[1024];
+                               log_err ("fcntl() failed: %s",
+                                               sstrerror (errno, errbuf, sizeof (errbuf)));
                                loop = 0;
                        }
                }
@@ -536,8 +540,10 @@ static void *open_connection (void *arg)
        /* create UNIX socket */
        errno = 0;
        if (-1 == (connector_socket = socket (PF_UNIX, SOCK_STREAM, 0))) {
+               char errbuf[1024];
                disabled = 1;
-               log_err ("socket() failed: %s", strerror (errno));
+               log_err ("socket() failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                pthread_exit ((void *)1);
        }
 
@@ -551,39 +557,63 @@ static void *open_connection (void *arg)
        if (-1 == bind (connector_socket, (struct sockaddr *)&addr,
                                offsetof (struct sockaddr_un, sun_path)
                                        + strlen(addr.sun_path))) {
+               char errbuf[1024];
                disabled = 1;
-               log_err ("bind() failed: %s", strerror (errno));
+               log_err ("bind() failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                pthread_exit ((void *)1);
        }
 
        errno = 0;
        if (-1 == listen (connector_socket, 5)) {
+               char errbuf[1024];
                disabled = 1;
-               log_err ("listen() failed: %s", strerror (errno));
+               log_err ("listen() failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                pthread_exit ((void *)1);
        }
 
-       if ((uid_t)0 == geteuid ()) {
+       if ((uid_t) 0 == geteuid ())
+       {
+               struct group sg;
                struct group *grp;
-
-               errno = 0;
-               if (NULL != (grp = getgrnam (sock_group))) {
-                       errno = 0;
-                       if (0 != chown (SOCK_PATH, (uid_t)-1, grp->gr_gid)) {
-                               log_warn ("chown() failed: %s", strerror (errno));
-                       }
+               char grbuf[2048];
+               int status;
+
+               grp = NULL;
+               status = getgrnam_r (sock_group, &sg, grbuf, sizeof (grbuf), &grp);
+               if (status != 0)
+               {
+                       char errbuf[1024];
+                       log_warn ("getgrnam_r (%s) failed: %s", sock_group,
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
                }
-               else {
-                       log_warn ("getgrnam() failed: %s", strerror (errno));
+               else if (grp == NULL)
+               {
+                       log_warn ("No such group: `%s'", sock_group);
+               }
+               else
+               {
+                       status = chown (SOCK_PATH, (uid_t) -1, grp->gr_gid);
+                       if (status != 0)
+                       {
+                               char errbuf[1024];
+                               log_warn ("chown (%s, -1, %i) failed: %s",
+                                               SOCK_PATH, (int) grp->gr_gid,
+                                               sstrerror (errno, errbuf, sizeof (errbuf)));
+                       }
                }
        }
-       else {
+       else /* geteuid != 0 */
+       {
                log_warn ("not running as root");
        }
 
        errno = 0;
        if (0 != chmod (SOCK_PATH, sock_perms)) {
-               log_warn ("chmod() failed: %s", strerror (errno));
+               char errbuf[1024];
+               log_warn ("chmod() failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
        }
 
        { /* initialize collector threads */
@@ -609,7 +639,9 @@ static void *open_connection (void *arg)
 
                        if (0 != (err = pthread_create (&collectors[i]->thread, &ptattr,
                                                        collect, collectors[i]))) {
-                               log_err ("pthread_create() failed: %s", strerror (err));
+                               char errbuf[1024];
+                               log_err ("pthread_create() failed: %s",
+                                               sstrerror (errno, errbuf, sizeof (errbuf)));
                        }
                }
 
@@ -635,8 +667,10 @@ static void *open_connection (void *arg)
                        errno = 0;
                        if (-1 == (remote = accept (connector_socket, NULL, NULL))) {
                                if (EINTR != errno) {
+                                       char errbuf[1024];
                                        disabled = 1;
-                                       log_err ("accept() failed: %s", strerror (errno));
+                                       log_err ("accept() failed: %s",
+                                                       sstrerror (errno, errbuf, sizeof (errbuf)));
                                        pthread_exit ((void *)1);
                                }
                        }
@@ -664,30 +698,29 @@ static void *open_connection (void *arg)
        }
        pthread_exit ((void *)0);
 } /* static void *open_connection (void *) */
-#endif /* EMAIL_HAVE_READ */
 
-static void email_init (void)
+static int email_init (void)
 {
-#if EMAIL_HAVE_READ
        int err = 0;
 
        if (0 != (err = pthread_create (&connector, NULL,
                                open_connection, NULL))) {
+               char errbuf[1024];
                disabled = 1;
-               log_err ("pthread_create() failed: %s", strerror (err));
-               return;
+               log_err ("pthread_create() failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
        }
-#endif /* EMAIL_HAVE_READ */
-       return;
-} /* static void email_init (void) */
 
-#if EMAIL_HAVE_READ
-static void email_shutdown (void)
+       return (0);
+} /* int email_init */
+
+static int email_shutdown (void)
 {
        int i = 0;
 
        if (disabled)
-               return;
+               return (0);
 
        pthread_kill (connector, SIGTERM);
        close (connector_socket);
@@ -703,81 +736,26 @@ static void email_shutdown (void)
        pthread_mutex_unlock (&conns_mutex);
 
        unlink (SOCK_PATH);
-       return;
-} /* static void email_shutdown (void) */
-#endif /* EMAIL_HAVE_READ */
-
-static void count_write (char *host, char *inst, char *val)
-{
-       char file[BUFSIZE] = "";
-       int  len           = 0;
-
-       len = snprintf (file, BUFSIZE, COUNT_FILE, inst);
-       if ((len < 0) || (len >= BUFSIZE))
-               return;
-
-       rrd_update_file (host, file, val, count_ds_def, count_ds_num);
-       return;
-} /* static void email_write (char *host, char *inst, char *val) */
-
-static void size_write (char *host, char *inst, char *val)
-{
-       char file[BUFSIZE] = "";
-       int  len           = 0;
-
-       len = snprintf (file, BUFSIZE, SIZE_FILE, inst);
-       if ((len < 0) || (len >= BUFSIZE))
-               return;
-
-       rrd_update_file (host, file, val, size_ds_def, size_ds_num);
-       return;
-} /* static void size_write (char *host, char *inst, char *val) */
-
-static void score_write (char *host, char *inst, char *val)
-{
-       rrd_update_file (host, SCORE_FILE, val, score_ds_def, score_ds_num);
-       return;
-} /* static void score_write (char *host, char *inst, char *val) */
 
-static void check_write (char *host, char *inst, char *val)
-{
-       char file[BUFSIZE] = "";
-       int  len           = 0;
-
-       len = snprintf (file, BUFSIZE, CHECK_FILE, inst);
-       if ((len < 0) || (len >= BUFSIZE))
-               return;
-
-       rrd_update_file (host, file, val, check_ds_def, check_ds_num);
-       return;
-} /* static void check_write (char *host, char *inst, char *val) */
+       return (0);
+} /* static void email_shutdown (void) */
 
-#if EMAIL_HAVE_READ
-static void type_submit (char *plugin, char *inst, int value)
+static void email_submit (const char *type, const char *type_instance, gauge_t value)
 {
-       char buf[BUFSIZE] = "";
-       int  len          = 0;
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       len = snprintf (buf, BUFSIZE, "%u:%i", (unsigned int)curtime, value);
-       if ((len < 0) || (len >= BUFSIZE))
-               return;
+       values[0].gauge = value;
 
-       plugin_submit (plugin, inst, buf);
-       return;
-} /* static void type_submit (char *, char *, int) */
-
-static void score_submit (double value)
-{
-       char buf[BUFSIZE] = "";
-       int  len          = 0;
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "email");
+       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       len = snprintf (buf, BUFSIZE, "%u:%.2f", (unsigned int)curtime, value);
-       if ((len < 0) || (len >= BUFSIZE))
-               return;
-
-       plugin_submit ("email_spam_score", "-", buf);
-       return;
-} /* static void score_submit (double) */
+       plugin_dispatch_values (type, &vl);
+} /* void email_submit */
 
 /* Copy list l1 to list l2. l2 may partly exist already, but it is assumed
  * that neither the order nor the name of any element of either list is
@@ -817,7 +795,7 @@ static void copy_type_list (type_list_t *l1, type_list_t *l2)
        return;
 }
 
-static void email_read (void)
+static int email_read (void)
 {
        type_t *ptr;
 
@@ -828,7 +806,7 @@ static void email_read (void)
        static type_list_t *chk;
 
        if (disabled)
-               return;
+               return (-1);
 
        if (NULL == cnt) {
                cnt = (type_list_t *)smalloc (sizeof (type_list_t));
@@ -853,7 +831,7 @@ static void email_read (void)
        pthread_mutex_unlock (&count_mutex);
 
        for (ptr = cnt->head; NULL != ptr; ptr = ptr->next) {
-               type_submit ("email_count", ptr->name, ptr->value);
+               email_submit ("email_count", ptr->name, ptr->value);
        }
 
        /* email size */
@@ -864,7 +842,7 @@ static void email_read (void)
        pthread_mutex_unlock (&size_mutex);
 
        for (ptr = sz->head; NULL != ptr; ptr = ptr->next) {
-               type_submit ("email_size", ptr->name, ptr->value);
+               email_submit ("email_size", ptr->name, ptr->value);
        }
 
        /* spam score */
@@ -876,7 +854,7 @@ static void email_read (void)
 
        pthread_mutex_unlock (&score_mutex);
 
-       score_submit (sc);
+       email_submit ("spam_score", "", sc);
 
        /* spam checks */
        pthread_mutex_lock (&check_mutex);
@@ -885,28 +863,29 @@ static void email_read (void)
 
        pthread_mutex_unlock (&check_mutex);
 
-       for (ptr = chk->head; NULL != ptr; ptr = ptr->next) {
-               type_submit ("email_spam_check", ptr->name, ptr->value);
-       }
-       return;
-} /* static void read (void) */
-#else /* if !EMAIL_HAVE_READ */
-# define email_read NULL
-#endif
+       for (ptr = chk->head; NULL != ptr; ptr = ptr->next)
+               email_submit ("spam_check", ptr->name, ptr->value);
 
-void module_register (void)
+       return (0);
+} /* int email_read */
+
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, email_init, email_read, NULL);
-       plugin_register ("email_count", NULL, NULL, count_write);
-       plugin_register ("email_size", NULL, NULL, size_write);
-       plugin_register ("email_spam_score", NULL, NULL, score_write);
-       plugin_register ("email_spam_check", NULL, NULL, check_write);
-#if EMAIL_HAVE_READ
-       plugin_register_shutdown (MODULE_NAME, email_shutdown);
-       cf_register (MODULE_NAME, email_config, config_keys, config_keys_num);
-#endif /* EMAIL_HAVE_READ */
-       return;
-} /* void module_register (void) */
+       if (load & MR_DATASETS)
+       {
+               plugin_register_data_set (&email_count_ds);
+               plugin_register_data_set (&email_size_ds);
+               plugin_register_data_set (&spam_check_ds);
+               plugin_register_data_set (&spam_score_ds);
+       }
 
-/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
+       if (load & MR_READ)
+       {
+               plugin_register_config ("email", email_config, config_keys, config_keys_num);
+               plugin_register_init ("email", email_init);
+               plugin_register_read ("email", email_read);
+       }
+       plugin_register_shutdown ("email", email_shutdown);
+} /* void module_register */
 
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
diff --git a/src/entropy.c b/src/entropy.c
new file mode 100644 (file)
index 0000000..fd48c74
--- /dev/null
@@ -0,0 +1,100 @@
+/**
+ * collectd - src/entropy.c
+ * Copyright (C) 2005,2006  Florian octo Forster
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#if KERNEL_LINUX
+# define ENTROPY_HAVE_READ 1
+#else
+# define ENTROPY_HAVE_READ 0
+#endif
+
+#define ENTROPY_FILE "/proc/sys/kernel/random/entropy_avail"
+
+static data_source_t dsrc[1] =
+{
+       {"entropy",  DS_TYPE_GAUGE, 0.0, 4294967295.0}
+};
+
+static data_set_t ds =
+{
+       "entropy", 1, dsrc
+};
+
+#if ENTROPY_HAVE_READ
+static void entropy_submit (double entropy)
+{
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
+
+       values[0].gauge = entropy;
+
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "entropy");
+       strcpy (vl.plugin_instance, "");
+       strcpy (vl.type_instance, "");
+
+       plugin_dispatch_values ("entropy", &vl);
+}
+
+static int entropy_read (void)
+{
+#if KERNEL_LINUX
+       double entropy;
+       FILE *fh;
+       char buffer[64];
+
+       fh = fopen (ENTROPY_FILE, "r");
+       if (fh == NULL)
+               return (-1);
+
+       if (fgets (buffer, sizeof (buffer), fh) == NULL)
+       {
+               fclose (fh);
+               return (-1);
+       }
+       fclose (fh);
+
+       entropy = atof (buffer);
+       
+       if (entropy > 0.0)
+               entropy_submit (entropy);
+#endif /* KERNEL_LINUX */
+
+       return (0);
+}
+#endif /* ENTROPY_HAVE_READ */
+
+void module_register (modreg_e load)
+{
+       if (load & MR_DATASETS)
+               plugin_register_data_set (&ds);
+
+#if ENTROPY_HAVE_READ
+       if (load & MR_READ)
+               plugin_register_read ("entropy", entropy_read);
+#endif
+} /* void module_register */
diff --git a/src/exec.c b/src/exec.c
new file mode 100644 (file)
index 0000000..5bddfc5
--- /dev/null
@@ -0,0 +1,405 @@
+/**
+ * collectd - src/exec.c
+ * Copyright (C) 2007  Florian octo Forster
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <signal.h>
+
+#include <pthread.h>
+
+/*
+ * Private data types
+ */
+struct program_list_s;
+typedef struct program_list_s program_list_t;
+struct program_list_s
+{
+  char           *user;
+  char           *exec;
+  int             pid;
+  program_list_t *next;
+};
+
+/*
+ * Private variables
+ */
+static data_source_t dsrc_counter[1] =
+{
+  {"value", DS_TYPE_COUNTER, NAN, NAN}
+};
+
+static data_set_t ds_counter =
+{
+  "counter", STATIC_ARRAY_SIZE (dsrc_counter), dsrc_counter
+};
+
+static data_source_t dsrc_gauge[1] =
+{
+  {"value", DS_TYPE_GAUGE, NAN, NAN}
+};
+
+static data_set_t ds_gauge =
+{
+  "gauge", STATIC_ARRAY_SIZE (dsrc_gauge), dsrc_gauge
+};
+
+static const char *config_keys[] =
+{
+  "Exec"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static program_list_t *pl_head = NULL;
+
+/*
+ * Functions
+ */
+static int exec_config (const char *key, const char *value)
+{
+  if (strcasecmp ("Exec", key) == 0)
+  {
+    program_list_t *pl;
+    pl = (program_list_t *) malloc (sizeof (program_list_t));
+    if (pl == NULL)
+      return (1);
+    memset (pl, '\0', sizeof (program_list_t));
+
+    pl->user = strdup (value);
+    if (pl->user == NULL)
+    {
+      sfree (pl);
+      return (1);
+    }
+
+    pl->exec = strchr (pl->user, ' ');
+    if (pl->exec == NULL)
+    {
+      sfree (pl->user);
+      sfree (pl);
+      return (1);
+    }
+    while (*pl->exec == ' ')
+    {
+      *pl->exec = '\0';
+      pl->exec++;
+    }
+
+    if (*pl->exec == '\0')
+    {
+      sfree (pl->user);
+      sfree (pl);
+      return (1);
+    }
+
+    pl->next = pl_head;
+    pl_head = pl;
+  }
+  else
+  {
+    return (-1);
+  }
+
+  return (0);
+} /* int exec_config */
+
+static void submit_counter (const char *type_instance, counter_t value)
+{
+  value_t values[1];
+  value_list_t vl = VALUE_LIST_INIT;
+
+  DEBUG ("type_instance = %s; value = %llu;", type_instance, value);
+
+  values[0].counter = value;
+
+  vl.values = values;
+  vl.values_len = 1;
+  vl.time = time (NULL);
+  strcpy (vl.host, hostname_g);
+  strcpy (vl.plugin, "exec");
+  strcpy (vl.plugin_instance, "");
+  strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+  plugin_dispatch_values ("counter", &vl);
+} /* void submit_counter */
+
+static void submit_gauge (const char *type_instance, gauge_t value)
+{
+  value_t values[1];
+  value_list_t vl = VALUE_LIST_INIT;
+
+  DEBUG ("type_instance = %s; value = %lf;", type_instance, value);
+
+  values[0].gauge = value;
+
+  vl.values = values;
+  vl.values_len = 1;
+  vl.time = time (NULL);
+  strcpy (vl.host, hostname_g);
+  strcpy (vl.plugin, "exec");
+  strcpy (vl.plugin_instance, "");
+  strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+  plugin_dispatch_values ("gauge", &vl);
+} /* void submit_counter */
+
+static void exec_child (program_list_t *pl)
+{
+  int status;
+  int uid;
+  char *arg0;
+
+  struct passwd *sp_ptr;
+  struct passwd sp;
+  char pwnambuf[2048];
+  char errbuf[1024];
+
+  sp_ptr = NULL;
+  status = getpwnam_r (pl->user, &sp, pwnambuf, sizeof (pwnambuf), &sp_ptr);
+  if (status != 0)
+  {
+    ERROR ("exec plugin: getpwnam_r failed: %s",
+       sstrerror (errno, errbuf, sizeof (errbuf)));
+    exit (-1);
+  }
+  if (sp_ptr == NULL)
+  {
+    ERROR ("exec plugin: No such user: `%s'", pl->user);
+    exit (-1);
+  }
+
+  uid = sp.pw_uid;
+  if (uid == 0)
+  {
+    ERROR ("exec plugin: Cowardly refusing to exec program as root.");
+    exit (-1);
+  }
+
+  status = setuid (uid);
+  if (status != 0)
+  {
+    ERROR ("exec plugin: setuid failed: %s",
+       sstrerror (errno, errbuf, sizeof (errbuf)));
+    exit (-1);
+  }
+
+  arg0 = strrchr (pl->exec, '/');
+  if (arg0 != NULL)
+    arg0++;
+  if ((arg0 == NULL) || (*arg0 == '\0'))
+    arg0 = pl->exec;
+
+  status = execlp (pl->exec, arg0, (char *) 0);
+
+  ERROR ("exec plugin: exec failed: %s",
+      sstrerror (errno, errbuf, sizeof (errbuf)));
+  exit (-1);
+} /* void exec_child */
+
+static int fork_child (program_list_t *pl)
+{
+  int fd_pipe[2];
+  int status;
+
+  if (pl->pid != 0)
+    return (-1);
+
+  status = pipe (fd_pipe);
+  if (status != 0)
+  {
+    char errbuf[1024];
+    ERROR ("exec plugin: pipe failed: %s",
+       sstrerror (errno, errbuf, sizeof (errbuf)));
+    return (-1);
+  }
+
+  pl->pid = fork ();
+  if (pl->pid < 0)
+  {
+    char errbuf[1024];
+    ERROR ("exec plugin: fork failed: %s",
+       sstrerror (errno, errbuf, sizeof (errbuf)));
+    return (-1);
+  }
+  else if (pl->pid == 0)
+  {
+    close (fd_pipe[0]);
+
+    /* Connect the pipe to STDOUT and STDERR */
+    if (fd_pipe[1] != STDOUT_FILENO)
+      dup2 (fd_pipe[1], STDOUT_FILENO);
+    if (fd_pipe[1] != STDERR_FILENO)
+      dup2 (fd_pipe[1], STDERR_FILENO);
+    if ((fd_pipe[1] != STDOUT_FILENO) && (fd_pipe[1] != STDERR_FILENO))
+      close (fd_pipe[1]);
+
+    exec_child (pl);
+    /* does not return */
+  }
+
+  close (fd_pipe[1]);
+  return (fd_pipe[0]);
+} /* int fork_child */
+
+static void *exec_read_one (void *arg)
+{
+  program_list_t *pl = (program_list_t *) arg;
+  int fd;
+  FILE *fh;
+  char buffer[1024];
+
+  fd = fork_child (pl);
+  if (fd < 0)
+    pthread_exit ((void *) 1);
+
+  assert (pl->pid != 0);
+
+  fh = fdopen (fd, "r");
+  if (fh == NULL)
+  {
+    char errbuf[1024];
+    ERROR ("exec plugin: fdopen (%i) failed: %s", fd,
+       sstrerror (errno, errbuf, sizeof (errbuf)));
+    kill (pl->pid, SIGTERM);
+    close (fd);
+    pthread_exit ((void *) 1);
+  }
+
+  while (fgets (buffer, sizeof (buffer), fh) != NULL)
+  {
+    int len;
+    char *type;
+    char *type_instance;
+    char *value;
+
+    DEBUG ("buffer = %s", buffer);
+
+    len = strlen (buffer);
+    if (len < 5)
+      continue;
+
+    if (buffer[0] == '#')
+      continue;
+
+    type = buffer;
+
+    type_instance = strchr (type, ',');
+    if (type_instance == NULL)
+      continue;
+    *type_instance = '\0';
+    type_instance++;
+
+    if ((strcasecmp ("counter", type) != 0)
+       && (strcasecmp ("gauge", type) != 0))
+    {
+      WARNING ("exec plugin: Received invalid type: %s", type);
+      continue;
+    }
+
+    value = strchr (type_instance, ',');
+    if (value == NULL)
+      continue;
+    *value = '\0';
+    value++;
+
+    DEBUG ("value = %s", value);
+
+    if (strcasecmp ("counter", type) == 0)
+      submit_counter (type_instance, atoll (value));
+    else
+      submit_gauge (type_instance, atof (value));
+  } /* while (fgets) */
+
+  fclose (fh);
+  pl->pid = 0;
+
+  pthread_exit ((void *) 0);
+  return (NULL);
+} /* void *exec_read_one */
+
+static int exec_read (void)
+{
+  program_list_t *pl;
+
+  for (pl = pl_head; pl != NULL; pl = pl->next)
+  {
+    pthread_t t;
+    pthread_attr_t attr;
+
+    if (pl->pid != 0)
+      continue;
+
+    pthread_attr_init (&attr);
+    pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+    pthread_create (&t, &attr, exec_read_one, (void *) pl);
+  } /* for (pl) */
+
+  return (0);
+} /* int exec_read */
+
+static int exec_shutdown (void)
+{
+  program_list_t *pl;
+  program_list_t *next;
+
+  pl = pl_head;
+  while (pl != NULL)
+  {
+    next = pl->next;
+
+    if (pl->pid > 0)
+    {
+      kill (pl->pid, SIGTERM);
+      INFO ("exec plugin: Sent SIGTERM to %hu", (unsigned short int) pl->pid);
+    }
+
+    sfree (pl->user);
+    sfree (pl);
+
+    pl = next;
+  } /* while (pl) */
+  pl_head = NULL;
+
+  return (0);
+} /* int exec_shutdown */
+
+void module_register (modreg_e load)
+{
+  if (load & MR_DATASETS)
+  {
+    plugin_register_data_set (&ds_counter);
+    plugin_register_data_set (&ds_gauge);
+  }
+
+  if (load & MR_READ)
+  {
+    plugin_register_config ("exec", exec_config, config_keys, config_keys_num);
+    plugin_register_read ("exec", exec_read);
+    plugin_register_shutdown ("exec", exec_shutdown);
+  }
+} /* void module_register */
+
+/*
+ * vim:shiftwidth=2:softtabstop=2:tabstop=8
+ */
index 80b3419..505d10f 100644 (file)
 #include "common.h"
 #include "plugin.h"
 #include "configfile.h"
-#include "utils_debug.h"
 
-#define MODULE_NAME "hddtemp"
-
-#include <netdb.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <libgen.h> /* for basename */
+#if HAVE_NETDB_H && HAVE_SYS_SOCKET_H && HAVE_NETINET_IN_H \
+       && HAVE_NETINET_TCP_H && HAVE_LIBGEN_H
+# include <netdb.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <netinet/tcp.h>
+# include <libgen.h> /* for basename */
+# define HDDTEMP_HAVE_READ 1
+#else
+# define HDDTEMP_HAVE_READ 0
+#endif
 
 #if HAVE_LINUX_MAJOR_H
 # include <linux/major.h>
 #define HDDTEMP_DEF_HOST "127.0.0.1"
 #define HDDTEMP_DEF_PORT "7634"
 
-/* BUFFER_SIZE
-   Size of the buffer we use to receive from the hddtemp daemon. */
-#define BUFFER_SIZE 1024
-
-static char *filename_format = "hddtemp-%s.rrd";
+static data_source_t data_source_temperature[1] =
+{
+       {"value", DS_TYPE_GAUGE, -273.15, NAN}
+};
 
-static char *ds_def[] =
+static data_set_t temperature_ds =
 {
-       "DS:value:GAUGE:"COLLECTD_HEARTBEAT":U:U",
-       NULL
+       "temperature", 1, data_source_temperature
 };
-static int ds_num = 1;
 
-static char *config_keys[] =
+#if HDDTEMP_HAVE_READ
+static const char *config_keys[] =
 {
        "Host",
        "Port",
@@ -132,9 +133,12 @@ static int hddtemp_query_daemon (char *buffer, int buffer_size)
 
        if ((ai_return = getaddrinfo (host, port, &ai_hints, &ai_list)) != 0)
        {
-               syslog (LOG_ERR, "hddtemp: getaddrinfo (%s, %s): %s",
+               char errbuf[1024];
+               ERROR ("hddtemp: getaddrinfo (%s, %s): %s",
                                host, port,
-                               ai_return == EAI_SYSTEM ? strerror (errno) : gai_strerror (ai_return));
+                               (ai_return == EAI_SYSTEM)
+                               ? sstrerror (errno, errbuf, sizeof (errbuf))
+                               : gai_strerror (ai_return));
                return (-1);
        }
 
@@ -144,16 +148,18 @@ static int hddtemp_query_daemon (char *buffer, int buffer_size)
                /* create our socket descriptor */
                if ((fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol)) < 0)
                {
-                       syslog (LOG_ERR, "hddtemp: socket: %s",
-                                       strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("hddtemp: socket: %s",
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
                        continue;
                }
 
                /* connect to the hddtemp daemon */
                if (connect (fd, (struct sockaddr *) ai_ptr->ai_addr, ai_ptr->ai_addrlen))
                {
-                       DBG ("hddtemp: connect (%s, %s): %s", host, port,
-                                       strerror (errno));
+                       char errbuf[1024];
+                       DEBUG ("hddtemp: connect (%s, %s): %s", host, port,
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
                        close (fd);
                        fd = -1;
                        continue;
@@ -168,7 +174,7 @@ static int hddtemp_query_daemon (char *buffer, int buffer_size)
 
        if (fd < 0)
        {
-               syslog (LOG_ERR, "hddtemp: Could not connect to daemon.");
+               ERROR ("hddtemp: Could not connect to daemon.");
                return (-1);
        }
 
@@ -180,11 +186,13 @@ static int hddtemp_query_daemon (char *buffer, int buffer_size)
        {
                if (status == -1)
                {
+                       char errbuf[1024];
+
                        if ((errno == EAGAIN) || (errno == EINTR))
                                continue;
 
-                       syslog (LOG_ERR, "hddtemp: Error reading from socket: %s",
-                                               strerror (errno));
+                       ERROR ("hddtemp: Error reading from socket: %s",
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
                        close (fd);
                        return (-1);
                }
@@ -197,11 +205,11 @@ static int hddtemp_query_daemon (char *buffer, int buffer_size)
        if (buffer_fill >= buffer_size)
        {
                buffer[buffer_size - 1] = '\0';
-               syslog (LOG_WARNING, "hddtemp: Message from hddtemp has been truncated.");
+               WARNING ("hddtemp: Message from hddtemp has been truncated.");
        }
        else if (buffer_fill == 0)
        {
-               syslog (LOG_WARNING, "hddtemp: Peer has unexpectedly shut down the socket. "
+               WARNING ("hddtemp: Peer has unexpectedly shut down the socket. "
                                "Buffer: `%s'", buffer);
                close (fd);
                return (-1);
@@ -211,7 +219,7 @@ static int hddtemp_query_daemon (char *buffer, int buffer_size)
        return (0);
 }
 
-static int hddtemp_config (char *key, char *value)
+static int hddtemp_config (const char *key, const char *value)
 {
        if (strcasecmp (key, "host") == 0)
        {
@@ -236,11 +244,11 @@ static int hddtemp_config (char *key, char *value)
 /* In the init-function we initialize the `hddname_t' list used to translate
  * disk-names. Under Linux that's done using `/proc/partitions'. Under other
  * operating-systems, it's not done at all. */
-static void hddtemp_init (void)
+static int hddtemp_init (void)
 {
 #if KERNEL_LINUX
        FILE *fh;
-       char buf[BUFFER_SIZE];
+       char buf[1024];
        int buflen;
 
        char *fields[16];
@@ -265,9 +273,9 @@ static void hddtemp_init (void)
 
        if ((fh = fopen ("/proc/partitions", "r")) != NULL)
        {
-               DBG ("Looking at /proc/partitions...");
+               DEBUG ("Looking at /proc/partitions...");
 
-               while (fgets (buf, BUFFER_SIZE, fh) != NULL)
+               while (fgets (buf, sizeof (buf), fh) != NULL)
                {
                        /* Delete trailing newlines */
                        buflen = strlen (buf);
@@ -339,25 +347,25 @@ static void hddtemp_init (void)
 
                                /* Skip all other majors. */
                                default:
-                                       DBG ("Skipping unknown major %i", major);
+                                       DEBUG ("Skipping unknown major %i", major);
                                        continue;
                        } /* switch (major) */
 
                        if ((name = strdup (fields[3])) == NULL)
                        {
-                               syslog (LOG_ERR, "hddtemp: strdup(%s) == NULL", fields[3]);
+                               ERROR ("hddtemp: strdup(%s) == NULL", fields[3]);
                                continue;
                        }
 
                        if ((entry = (hddname_t *) malloc (sizeof (hddname_t))) == NULL)
                        {
-                               syslog (LOG_ERR, "hddtemp: malloc (%u) == NULL",
+                               ERROR ("hddtemp: malloc (%u) == NULL",
                                                (unsigned int) sizeof (hddname_t));
                                free (name);
                                continue;
                        }
 
-                       DBG ("Found disk: %s (%u:%u).", name, major, minor);
+                       DEBUG ("Found disk: %s (%u:%u).", name, major, minor);
 
                        entry->major = major;
                        entry->minor = minor;
@@ -376,26 +384,18 @@ static void hddtemp_init (void)
                }
                fclose (fh);
        }
+#if COLLECT_DEBUG
        else
-               DBG ("Could not open /proc/partitions: %s",
-                               strerror (errno));
+       {
+               char errbuf[1024];
+               DEBUG ("Could not open /proc/partitions: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+       }
+#endif /* COLLECT_DEBUG */
 #endif /* KERNEL_LINUX */
-}
-
-static void hddtemp_write (char *host, char *inst, char *val)
-{
-       char filename[BUFFER_SIZE];
-       int status;
-
-       /* construct filename */
-       status = snprintf (filename, BUFFER_SIZE, filename_format, inst);
-       if (status < 1)
-               return;
-       else if (status >= BUFFER_SIZE)
-               return;
 
-       rrd_update_file (host, filename, val, ds_def, ds_num);
-}
+       return (0);
+} /* int hddtemp_init */
 
 /*
  * hddtemp_get_name
@@ -416,7 +416,7 @@ static char *hddtemp_get_name (char *drive)
 
        if (list == NULL)
        {
-               DBG ("Don't know %s, keeping name as-is.", drive);
+               DEBUG ("Don't know %s, keeping name as-is.", drive);
                return (strdup (drive));
        }
 
@@ -432,60 +432,42 @@ static char *hddtemp_get_name (char *drive)
        return (ret);
 }
 
-static void hddtemp_submit (char *inst, double temperature)
+static void hddtemp_submit (char *type_instance, double value)
 {
-       char buf[BUFFER_SIZE];
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       if (snprintf (buf, BUFFER_SIZE, "%u:%.3f", (unsigned int) curtime, temperature)
-            >= BUFFER_SIZE)
-               return;
+       values[0].gauge = value;
 
-       plugin_submit (MODULE_NAME, inst, buf);
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "hddtemp");
+       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+       plugin_dispatch_values ("temperature", &vl);
 }
 
-static void hddtemp_read (void)
+static int hddtemp_read (void)
 {
-       char buf[BUFFER_SIZE];
+       char buf[1024];
        char *fields[128];
        char *ptr;
+       char *saveptr;
        int num_fields;
        int num_disks;
        int i;
 
-       static int wait_time = 1;
-       static int wait_left = 0;
-
-       if (wait_left >= 10)
-       {
-               wait_left -= 10;
-               return;
-       }
-
        /* get data from daemon */
-       if (hddtemp_query_daemon (buf, BUFFER_SIZE) < 0)
-       {
-               /* This limit is reached in log2(86400) =~ 17 steps. Since
-                * there is a 2^n seconds wait between each step it will need
-                * roughly one day to reach this limit. -octo */
-               
-               wait_time *= 2;
-               if (wait_time > 86400)
-                       wait_time = 86400;
-
-               wait_left = wait_time;
-
-               return;
-       }
-       else
-       {
-               wait_time = 1;
-               wait_left = 0;
-       }
+       if (hddtemp_query_daemon (buf, sizeof (buf)) < 0)
+               return (-1);
 
-       /* NB: strtok will eat up "||" and leading "|"'s */
+       /* NB: strtok_r will eat up "||" and leading "|"'s */
        num_fields = 0;
        ptr = buf;
-       while ((fields[num_fields] = strtok (ptr, "|")) != NULL)
+       saveptr = NULL;
+       while ((fields[num_fields] = strtok_r (ptr, "|", &saveptr)) != NULL)
        {
                ptr = NULL;
                num_fields++;
@@ -525,14 +507,25 @@ static void hddtemp_read (void)
                        hddtemp_submit (name, temperature);
                }
        }
-}
+       
+       return (0);
+} /* int hddtemp_read */
+#endif /* HDDTEMP_HAVE_READ */
 
 /* module_register
    Register collectd plugin. */
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, hddtemp_init, hddtemp_read, hddtemp_write);
-       cf_register (MODULE_NAME, hddtemp_config, config_keys, config_keys_num);
+       if (load & MR_DATASETS)
+               plugin_register_data_set (&temperature_ds);
+       
+#if HDDTEMP_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_config ("hddtemp", hddtemp_config,
+                               config_keys, config_keys_num);
+               plugin_register_init ("hddtemp", hddtemp_init);
+               plugin_register_read ("hddtemp", hddtemp_read);
+       }
+#endif /* HDDTEMP_HAVE_READ */
 }
-
-#undef MODULE_NAME
diff --git a/src/interface.c b/src/interface.c
new file mode 100644 (file)
index 0000000..960cc62
--- /dev/null
@@ -0,0 +1,413 @@
+/**
+ * collectd - src/interface.c
+ * Copyright (C) 2005-2007  Florian octo Forster
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at verplant.org>
+ *   Sune Marcher <sm at flork.dk>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+
+#if HAVE_SYS_TYPES_H
+#  include <sys/types.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#  include <sys/socket.h>
+#endif
+
+/* One cannot include both. This sucks. */
+#if HAVE_LINUX_IF_H
+#  include <linux/if.h>
+#elif HAVE_NET_IF_H
+#  include <net/if.h>
+#endif
+
+#if HAVE_LINUX_NETDEVICE_H
+#  include <linux/netdevice.h>
+#endif
+#if HAVE_IFADDRS_H
+#  include <ifaddrs.h>
+#endif
+
+/*
+ * Various people have reported problems with `getifaddrs' and varying versions
+ * of `glibc'. That's why it's disabled by default. Since more statistics are
+ * available this way one may enable it using the `--enable-getifaddrs' option
+ * of the configure script. -octo
+ */
+#if KERNEL_LINUX
+# if !COLLECT_GETIFADDRS
+#  undef HAVE_GETIFADDRS
+# endif /* !COLLECT_GETIFADDRS */
+#endif /* KERNEL_LINUX */
+
+#if HAVE_GETIFADDRS || KERNEL_LINUX || HAVE_LIBKSTAT || HAVE_LIBSTATGRAB
+# define INTERFACE_HAVE_READ 1
+#else
+# define INTERFACE_HAVE_READ 0
+#endif
+
+/*
+ * (Module-)Global variables
+ */
+/* 2^32 = 4294967296 = ~4.2GByte/s = ~34GBit/s */
+static data_source_t octets_dsrc[2] =
+{
+       {"rx", DS_TYPE_COUNTER, 0, 4294967295.0},
+       {"tx", DS_TYPE_COUNTER, 0, 4294967295.0}
+};
+
+static data_set_t octets_ds =
+{
+       "if_octets", 2, octets_dsrc
+};
+
+static data_source_t packets_dsrc[2] =
+{
+       {"rx", DS_TYPE_COUNTER, 0, 4294967295.0},
+       {"tx", DS_TYPE_COUNTER, 0, 4294967295.0}
+};
+
+static data_set_t packets_ds =
+{
+       "if_packets", 2, packets_dsrc
+};
+
+static data_source_t errors_dsrc[2] =
+{
+       {"rx", DS_TYPE_COUNTER, 0, 4294967295.0},
+       {"tx", DS_TYPE_COUNTER, 0, 4294967295.0}
+};
+
+static data_set_t errors_ds =
+{
+       "if_errors", 2, errors_dsrc
+};
+
+static const char *config_keys[] =
+{
+       "Interface",
+       "IgnoreSelected",
+       NULL
+};
+static int config_keys_num = 2;
+
+static char **if_list = NULL;
+static int    if_list_num = 0;
+/* 
+ * if_list_action:
+ * 0 => default is to collect selected interface
+ * 1 => ignore selcted interfaces
+ */
+static int    if_list_action = 0;
+
+#ifdef HAVE_LIBKSTAT
+#define MAX_NUMIF 256
+extern kstat_ctl_t *kc;
+static kstat_t *ksp[MAX_NUMIF];
+static int numif = 0;
+#endif /* HAVE_LIBKSTAT */
+
+static int interface_config (const char *key, const char *value)
+{
+       char **temp;
+
+       if (strcasecmp (key, "Interface") == 0)
+       {
+               temp = (char **) realloc (if_list, (if_list_num + 1) * sizeof (char *));
+               if (temp == NULL)
+               {
+                       ERROR ("Cannot allocate more memory.");
+                       return (1);
+               }
+               if_list = temp;
+
+               if ((if_list[if_list_num] = strdup (value)) == NULL)
+               {
+                       ERROR ("Cannot allocate memory.");
+                       return (1);
+               }
+               if_list_num++;
+       }
+       else if (strcasecmp (key, "IgnoreSelected") == 0)
+       {
+               if ((strcasecmp (value, "True") == 0)
+                               || (strcasecmp (value, "Yes") == 0)
+                               || (strcasecmp (value, "On") == 0))
+                       if_list_action = 1;
+               else
+                       if_list_action = 0;
+       }
+       else
+       {
+               return (-1);
+       }
+
+       return (0);
+}
+
+#if HAVE_LIBKSTAT
+static int interface_init (void)
+{
+#if HAVE_LIBKSTAT
+       kstat_t *ksp_chain;
+       unsigned long long val;
+
+       numif = 0;
+
+       if (kc == NULL)
+               return (-1);
+
+       for (numif = 0, ksp_chain = kc->kc_chain;
+                       (numif < MAX_NUMIF) && (ksp_chain != NULL);
+                       ksp_chain = ksp_chain->ks_next)
+       {
+               if (strncmp (ksp_chain->ks_class, "net", 3))
+                       continue;
+               if (ksp_chain->ks_type != KSTAT_TYPE_NAMED)
+                       continue;
+               if (kstat_read (kc, ksp_chain, NULL) == -1)
+                       continue;
+               if ((val = get_kstat_value (ksp_chain, "obytes")) == -1LL)
+                       continue;
+               ksp[numif++] = ksp_chain;
+       }
+#endif /* HAVE_LIBKSTAT */
+
+       return (0);
+} /* int interface_init */
+#endif /* HAVE_LIBKSTAT */
+
+/*
+ * Check if this interface/instance should be ignored. This is called from
+ * both, `submit' and `write' to give client and server the ability to
+ * ignore certain stuff..
+ */
+static int check_ignore_if (const char *interface)
+{
+       int i;
+
+       /* If no interfaces are given collect all interfaces. Mostly to be
+        * backwards compatible, but also because this is much easier. */
+       if (if_list_num < 1)
+               return (0);
+
+       for (i = 0; i < if_list_num; i++)
+               if (strcasecmp (interface, if_list[i]) == 0)
+                       return (if_list_action);
+       return (1 - if_list_action);
+} /* int check_ignore_if */
+
+#if INTERFACE_HAVE_READ
+static void if_submit (const char *dev, const char *type,
+               unsigned long long rx,
+               unsigned long long tx)
+{
+       value_t values[2];
+       value_list_t vl = VALUE_LIST_INIT;
+
+       if (check_ignore_if (dev))
+               return;
+
+       values[0].counter = rx;
+       values[1].counter = tx;
+
+       vl.values = values;
+       vl.values_len = 2;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "interface");
+       strncpy (vl.type_instance, dev, sizeof (vl.type_instance));
+
+       plugin_dispatch_values (type, &vl);
+} /* void if_submit */
+
+static int interface_read (void)
+{
+#if HAVE_GETIFADDRS
+       struct ifaddrs *if_list;
+       struct ifaddrs *if_ptr;
+
+/* Darin/Mac OS X and possible other *BSDs */
+#if HAVE_STRUCT_IF_DATA
+#  define IFA_DATA if_data
+#  define IFA_RX_BYTES ifi_ibytes
+#  define IFA_TX_BYTES ifi_obytes
+#  define IFA_RX_PACKT ifi_ipackets
+#  define IFA_TX_PACKT ifi_opackets
+#  define IFA_RX_ERROR ifi_ierrors
+#  define IFA_TX_ERROR ifi_oerrors
+/* #endif HAVE_STRUCT_IF_DATA */
+
+#elif HAVE_STRUCT_NET_DEVICE_STATS
+#  define IFA_DATA net_device_stats
+#  define IFA_RX_BYTES rx_bytes
+#  define IFA_TX_BYTES tx_bytes
+#  define IFA_RX_PACKT rx_packets
+#  define IFA_TX_PACKT tx_packets
+#  define IFA_RX_ERROR rx_errors
+#  define IFA_TX_ERROR tx_errors
+#else
+#  error "No suitable type for `struct ifaddrs->ifa_data' found."
+#endif
+
+       struct IFA_DATA *if_data;
+
+       if (getifaddrs (&if_list) != 0)
+               return (-1);
+
+       for (if_ptr = if_list; if_ptr != NULL; if_ptr = if_ptr->ifa_next)
+       {
+               if ((if_data = (struct IFA_DATA *) if_ptr->ifa_data) == NULL)
+                       continue;
+
+               if_submit (if_ptr->ifa_name, "if_octets",
+                               if_data->IFA_RX_BYTES,
+                               if_data->IFA_TX_BYTES);
+               if_submit (if_ptr->ifa_name, "if_packets",
+                               if_data->IFA_RX_PACKT,
+                               if_data->IFA_TX_PACKT);
+               if_submit (if_ptr->ifa_name, "if_errors",
+                               if_data->IFA_RX_ERROR,
+                               if_data->IFA_TX_ERROR);
+       }
+
+       freeifaddrs (if_list);
+/* #endif HAVE_GETIFADDRS */
+
+#elif KERNEL_LINUX
+       FILE *fh;
+       char buffer[1024];
+       unsigned long long incoming, outgoing;
+       char *device;
+       
+       char *dummy;
+       char *fields[16];
+       int numfields;
+
+       if ((fh = fopen ("/proc/net/dev", "r")) == NULL)
+       {
+               char errbuf[1024];
+               WARNING ("interface plugin: fopen: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
+
+       while (fgets (buffer, 1024, fh) != NULL)
+       {
+               if (!(dummy = strchr(buffer, ':')))
+                       continue;
+               dummy[0] = '\0';
+               dummy++;
+
+               device = buffer;
+               while (device[0] == ' ')
+                       device++;
+
+               if (device[0] == '\0')
+                       continue;
+               
+               numfields = strsplit (dummy, fields, 16);
+
+               if (numfields < 11)
+                       continue;
+
+               incoming = atoll (fields[0]);
+               outgoing = atoll (fields[8]);
+               if_submit (device, "if_octets", incoming, outgoing);
+
+               incoming = atoll (fields[1]);
+               outgoing = atoll (fields[9]);
+               if_submit (device, "if_packets", incoming, outgoing);
+
+               incoming = atoll (fields[2]);
+               outgoing = atoll (fields[10]);
+               if_submit (device, "if_errors", incoming, outgoing);
+       }
+
+       fclose (fh);
+/* #endif KERNEL_LINUX */
+
+#elif HAVE_LIBKSTAT
+       int i;
+       unsigned long long rx;
+       unsigned long long tx;
+
+       if (kc == NULL)
+               return;
+
+       for (i = 0; i < numif; i++)
+       {
+               if (kstat_read (kc, ksp[i], NULL) == -1)
+                       continue;
+
+               rx = get_kstat_value (ksp[i], "rbytes");
+               tx = get_kstat_value (ksp[i], "obytes");
+               if ((rx != -1LL) || (tx != -1LL))
+                       if_submit (ksp[i]->ks_name, "if_octets", rx, tx);
+
+               rx = get_kstat_value (ksp[i], "ipackets");
+               tx = get_kstat_value (ksp[i], "opackets");
+               if ((rx != -1LL) || (tx != -1LL))
+                       if_submit (ksp[i]->ks_name, "if_packets", rx, tx);
+
+               rx = get_kstat_value (ksp[i], "ierrors");
+               tx = get_kstat_value (ksp[i], "oerrors");
+               if ((rx != -1LL) || (tx != -1LL))
+                       if_submit (ksp[i]->ks_name, "if_errors", rx, tx);
+       }
+/* #endif HAVE_LIBKSTAT */
+
+#elif defined(HAVE_LIBSTATGRAB)
+       sg_network_io_stats *ios;
+       int i, num;
+
+       ios = sg_get_network_io_stats (&num);
+
+       for (i = 0; i < num; i++)
+               if_submit (ios[i].interface_name, "if_octets", ios[i].rx, ios[i].tx);
+#endif /* HAVE_LIBSTATGRAB */
+
+       return (0);
+} /* int interface_read */
+#endif /* INTERFACE_HAVE_READ */
+
+void module_register (modreg_e load)
+{
+       if (load & MR_DATASETS)
+       {
+               plugin_register_data_set (&octets_ds);
+               plugin_register_data_set (&packets_ds);
+               plugin_register_data_set (&errors_ds);
+       }
+
+       plugin_register_config ("interface", interface_config,
+                       config_keys, config_keys_num);
+
+       if (load & MR_READ)
+       {
+#if HAVE_LIBKSTAT
+               plugin_register_init ("interface", interface_init);
+#endif
+#if INTERFACE_HAVE_READ
+               plugin_register_read ("interface", interface_read);
+#endif
+       }
+} /* void module_register */
index 84878fd..1df35fa 100644 (file)
@@ -24,7 +24,6 @@
 #include "common.h"
 #include "plugin.h"
 #include "configfile.h"
-#include "utils_debug.h"
 
 #if HAVE_LIBIPTC_LIBIPTC_H
 # include <libiptc/libiptc.h>
  * eitherway for what to log
  */
 /* Limit to ~125MByte/s (~1GBit/s) */
-static char *ds_def[] =
+static data_source_t dsrc[1] =
 {
-       "DS:value:COUNTER:"COLLECTD_HEARTBEAT":0:134217728",
-       NULL
+       {"value",  DS_TYPE_COUNTER, 0.0, 134217728.0}
+};
+
+static data_set_t ipt_bytes_ds =
+{
+       "ipt_bytes", 1, dsrc
+};
+
+static data_set_t ipt_packets_ds =
+{
+       "ipt_packets", 1, dsrc
 };
-static int ds_num = 1;
 
 #if IPTABLES_HAVE_READ
 /*
  * Config format should be `Chain table chainname',
  * e. g. `Chain mangle incoming'
  */
-static char *config_keys[] =
+static const char *config_keys[] =
 {
        "Chain",
        NULL
@@ -93,7 +100,7 @@ typedef struct {
 static ip_chain_t **chain_list = NULL;
 static int chain_num = 0;
 
-static int iptables_config (char *key, char *value)
+static int iptables_config (const char *key, const char *value)
 {
        if (strcasecmp (key, "Chain") == 0)
        {
@@ -112,7 +119,9 @@ static int iptables_config (char *key, char *value)
                value_copy = strdup (value);
                if (value_copy == NULL)
                {
-                   syslog (LOG_ERR, "strdup failed: %s", strerror (errno));
+                   char errbuf[1024];
+                   ERROR ("strdup failed: %s",
+                           sstrerror (errno, errbuf, sizeof (errbuf)));
                    return (1);
                }
 
@@ -130,7 +139,7 @@ static int iptables_config (char *key, char *value)
                table_len = strlen (table);
                if (table_len >= sizeof(temp.table))
                {
-                       syslog (LOG_ERR, "Table `%s' too long.", table);
+                       ERROR ("Table `%s' too long.", table);
                        free (value_copy);
                        return (1);
                }
@@ -140,7 +149,7 @@ static int iptables_config (char *key, char *value)
                chain_len = strlen (chain);
                if (chain_len >= sizeof(temp.chain))
                {
-                       syslog (LOG_ERR, "Chain `%s' too long.", chain);
+                       ERROR ("Chain `%s' too long.", chain);
                        free (value_copy);
                        return (1);
                }
@@ -180,22 +189,26 @@ static int iptables_config (char *key, char *value)
                list = (ip_chain_t **) realloc (chain_list, (chain_num + 1) * sizeof (ip_chain_t *));
                if (list == NULL)
                {
-                       syslog (LOG_ERR, "realloc failed: %s", strerror (errno));
-                       return (1);
+                   char errbuf[1024];
+                   ERROR ("realloc failed: %s",
+                           sstrerror (errno, errbuf, sizeof (errbuf)));
+                   return (1);
                }
 
                chain_list = list;
                final = (ip_chain_t *) malloc( sizeof(temp) );
                if (final == NULL) 
                {
-                       syslog (LOG_ERR, "malloc failed: %s", strerror (errno));
-                       return (1);
+                   char errbuf[1024];
+                   ERROR ("malloc failed: %s",
+                           sstrerror (errno, errbuf, sizeof (errbuf)));
+                   return (1);
                }
                memcpy (final, &temp, sizeof (temp));
                chain_list[chain_num] = final;
                chain_num++;
 
-               DBG ("Chain #%i: table = %s; chain = %s;", chain_num, final->table, final->chain);
+               DEBUG ("Chain #%i: table = %s; chain = %s;", chain_num, final->table, final->chain);
        }
        else 
        {
@@ -203,65 +216,21 @@ static int iptables_config (char *key, char *value)
        }
 
        return (0);
-}
+} /* int iptables_config */
 #endif /* IPTABLES_HAVE_READ */
 
-static void iptables_write (char *host, char *orig_inst, char *val, char *type) 
-{
-    char *table;
-    char *inst;
-    char file[256];
-    int status;
-
-    table = strdup (orig_inst);
-    if (table == NULL)
-       return;
-    inst = strchr (table, ',');
-    if (inst == NULL)
-    {
-       free (table);
-       return;
-    }
-
-    *inst = '\0';
-    inst++;
-    if (*inst == '\0')
-    {
-       free (table);
-       return;
-    }
-
-    status = snprintf (file, sizeof (file), "iptables-%s/%s-%s.rrd",
-           table, type, inst);
-    free (table);
-    if ((status >= sizeof (file)) || (status < 1))
-       return;
-
-    rrd_update_file (host, file, val, ds_def, ds_num);
-} /* void iptables_write */
-
-static void iptables_write_bytes (char *host, char *inst, char *val)
-{
-    iptables_write (host, inst, val, "ipt_bytes");
-}
-
-static void iptables_write_packets (char *host, char *inst, char *val)
-{
-    iptables_write (host, inst, val, "ipt_packets");
-}
-
 #if IPTABLES_HAVE_READ
+/* This needs to return `int' for IPT_MATCH_ITERATE to work. */
 static int submit_match (const struct ipt_entry_match *match,
                const struct ipt_entry *entry,
                const ip_chain_t *chain,
                int rule_num) 
 {
-    char inst[64];
-    char value[64];
     int status;
+    value_t values[1];
+    value_list_t vl = VALUE_LIST_INIT;
 
-    /* Only log rules that have a comment, although could probably also do
-     * numerical targets sometime */
+    /* Select the rules to collect */
     if (chain->rule_type == RTYPE_NUM)
     {
        if (chain->rule.num != rule_num)
@@ -270,46 +239,46 @@ static int submit_match (const struct ipt_entry_match *match,
     else
     {
        if (strcmp (match->u.user.name, "comment") != 0)
-           return 0;
+           return (0);
        if ((chain->rule_type == RTYPE_COMMENT)
                && (strcmp (chain->rule.comment, (char *) match->data) != 0))
            return (0);
     }
 
+    vl.values = values;
+    vl.values_len = 1;
+    vl.time = time (NULL);
+    strcpy (vl.host, hostname_g);
+    strcpy (vl.plugin, "iptables");
+
+    status = snprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
+           "%s-%s", chain->table, chain->chain);
+    if ((status >= sizeof (vl.plugin_instance)) || (status < 1))
+       return (0);
+
     if (chain->name[0] != '\0')
     {
-       status = snprintf (inst, sizeof (inst), "%s-%s,%s",
-               chain->table, chain->chain, chain->name);
+       strncpy (vl.type_instance, chain->name, sizeof (vl.type_instance));
     }
     else
     {
        if (chain->rule_type == RTYPE_NUM)
-           status = snprintf (inst, sizeof (inst), "%s-%s,%i",
-               chain->table, chain->chain, chain->rule.num);
+           snprintf (vl.type_instance, sizeof (vl.type_instance),
+                   "%i", chain->rule.num);
        else
-           status = snprintf (inst, sizeof (inst), "%s-%s,%s",
-               chain->table, chain->chain, match->data);
-
-       if ((status >= sizeof (inst)) || (status < 1))
-           return (0);
+           strncpy (vl.type_instance, (char *) match->data,
+                   sizeof (vl.type_instance));
     }
+    vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
 
-    status = snprintf (value, sizeof (value), "%u:%lld",
-           (unsigned int) curtime,
-           entry->counters.bcnt);
-    if ((status >= sizeof (value)) || (status < 1))
-       return 0;
-    plugin_submit ("ipt_bytes", inst, value);
+    values[0].counter = (counter_t) entry->counters.bcnt;
+    plugin_dispatch_values ("ipt_bytes", &vl);
 
-    status = snprintf (value, sizeof (value), "%u:%lld",
-           (unsigned int) curtime,
-           entry->counters.pcnt);
-    if ((status >= sizeof (value)) || (status < 1))
-       return 0;
-    plugin_submit ("ipt_packets", inst, value);
+    values[0].counter = (counter_t) entry->counters.pcnt;
+    plugin_dispatch_values ("ipt_packets", &vl);
 
-    return 0;
-} /* int submit_match */
+    return (0);
+} /* void submit_match */
 
 static void submit_chain( iptc_handle_t *handle, ip_chain_t *chain ) {
     const struct ipt_entry *entry;
@@ -319,7 +288,7 @@ static void submit_chain( iptc_handle_t *handle, ip_chain_t *chain ) {
     entry = iptc_first_rule( chain->chain, handle );
     if (entry == NULL)
     {
-       DBG ("iptc_first_rule failed: %s", iptc_strerror (errno));
+       DEBUG ("iptc_first_rule failed: %s", iptc_strerror (errno));
        return;
     }
 
@@ -341,7 +310,7 @@ static void submit_chain( iptc_handle_t *handle, ip_chain_t *chain ) {
 }
 
 
-static void iptables_read (void)
+static int iptables_read (void)
 {
     int i;
     static complain_t complaint;
@@ -355,14 +324,14 @@ static void iptables_read (void)
        chain = chain_list[i];
        if (!chain)
        {
-           DBG ("chain == NULL");
+           DEBUG ("chain == NULL");
            continue;
        }
 
        handle = iptc_init( chain->table );
        if (!handle)
        {
-           DBG ("iptc_init (%s) failed: %s", chain->table, iptc_strerror (errno));
+           DEBUG ("iptc_init (%s) failed: %s", chain->table, iptc_strerror (errno));
            plugin_complain (LOG_ERR, &complaint, "iptc_init (%s) failed: %s",
                    chain->table, iptc_strerror (errno));
            continue;
@@ -373,20 +342,40 @@ static void iptables_read (void)
        submit_chain (&handle, chain);
        iptc_free (&handle);
     }
-}
-#else /* !IPTABLES_HAVE_READ */
-# define iptables_read NULL
-#endif
 
-void module_register (void)
+    return (0);
+} /* int iptables_read */
+
+static int iptables_shutdown (void)
 {
-    plugin_register ("ipt_bytes", NULL, NULL, iptables_write_bytes);
-    plugin_register ("ipt_packets", NULL, NULL, iptables_write_packets);
+    int i;
+
+    for (i = 0; i < chain_num; i++)
+       sfree (chain_list[i]);
+    sfree (chain_list);
+
+    return (0);
+} /* int iptables_shutdown */
+#endif /* IPTABLES_HAVE_READ */
+
+void module_register (modreg_e load)
+{
+    if (load & MR_DATASETS)
+    {
+       plugin_register_data_set (&ipt_bytes_ds);
+       plugin_register_data_set (&ipt_packets_ds);
+    }
+
 #if IPTABLES_HAVE_READ
-    plugin_register (MODULE_NAME, NULL, iptables_read, NULL);
-    cf_register (MODULE_NAME, iptables_config, config_keys, config_keys_num);
+    if (load & MR_READ)
+    {
+       plugin_register_config ("iptables", iptables_config,
+               config_keys, config_keys_num);
+       plugin_register_read ("iptables", iptables_read);
+       plugin_register_shutdown ("iptables", iptables_shutdown);
+    }
 #endif
-}
+} /* void module_register */
 
 #undef BUFSIZE
 #undef MODULE_NAME
index 69a3196..3df9d86 100644 (file)
--- a/src/irq.c
+++ b/src/irq.c
@@ -25,8 +25,6 @@
 #include "plugin.h"
 #include "configfile.h"
 
-#define MODULE_NAME "irq"
-
 #if KERNEL_LINUX
 # define IRQ_HAVE_READ 1
 #else
 /*
  * (Module-)Global variables
  */
-static char *irq_file   = "irq/irq-%s.rrd";
+static data_source_t dsrc_irq[1] =
+{
+       {"value", DS_TYPE_COUNTER, 0, 65535.0}
+};
 
-static char *config_keys[] =
+static data_set_t ds_irq =
 {
-       "Irq",
-       "IgnoreSelected",
-       NULL
+       "irq", 1, dsrc_irq
 };
-static int config_keys_num = 2;
 
-static char *ds_def[] =
+#if IRQ_HAVE_READ
+static const char *config_keys[] =
 {
-       "DS:value:COUNTER:"COLLECTD_HEARTBEAT":0:65535",
-       NULL
+       "Irq",
+       "IgnoreSelected"
 };
-static int ds_num = 1;
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
 static unsigned int *irq_list;
 static unsigned int irq_list_num;
@@ -65,7 +64,7 @@ static unsigned int irq_list_num;
  */
 static int irq_list_action;
 
-static int irq_config (char *key, char *value)
+static int irq_config (const char *key, const char *value)
 {
        if (strcasecmp (key, "Irq") == 0)
        {
@@ -77,7 +76,7 @@ static int irq_config (char *key, char *value)
                if (temp == NULL)
                {
                        fprintf (stderr, "irq plugin: Cannot allocate more memory.\n");
-                       syslog (LOG_ERR, "irq plugin: Cannot allocate more memory.");
+                       ERROR ("irq plugin: Cannot allocate more memory.");
                        return (1);
                }
                irq_list = temp;
@@ -90,7 +89,7 @@ static int irq_config (char *key, char *value)
                {
                        fprintf (stderr, "irq plugin: Irq value is not a "
                                        "number: `%s'\n", value);
-                       syslog (LOG_ERR, "irq plugin: Irq value is not a "
+                       ERROR ("irq plugin: Irq value is not a "
                                        "number: `%s'", value);
                        return (1);
                }
@@ -132,46 +131,32 @@ static int check_ignore_irq (const unsigned int irq)
        return (1 - irq_list_action);
 }
 
-static void irq_write (char *host, char *inst, char *value)
+static void irq_submit (unsigned int irq, counter_t value)
 {
-       char file[BUFSIZE];
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
        int status;
 
-       if (check_ignore_irq (atoi(inst)))
-               return;
-
-       status = snprintf (file, BUFSIZE, irq_file, inst);
-       if (status < 1)
-               return;
-       else if (status >= BUFSIZE)
-               return;
-
-       rrd_update_file (host, file, value, ds_def, ds_num);
-}
-
-#if IRQ_HAVE_READ
-static void irq_submit (unsigned int irq, unsigned int value)
-{
-       char value_str[32];
-       char type_str[16];
-       int  status;
-
        if (check_ignore_irq (irq))
                return;
 
-       status = snprintf (value_str, 32, "%u:%u",
-                               (unsigned int) curtime, value);
-       if ((status >= 32) || (status < 1))
-               return;
+       values[0].counter = value;
 
-       status = snprintf (type_str, 16, "%u", irq);
-       if ((status >= 16) || (status < 1))
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "irq");
+
+       status = snprintf (vl.type_instance, sizeof (vl.type_instance),
+                       "%u", irq);
+       if ((status < 1) || (status >= sizeof (vl.type_instance)))
                return;
 
-       plugin_submit (MODULE_NAME, type_str, value_str);
+       plugin_dispatch_values ("irq", &vl);
 } /* void irq_submit */
 
-static void irq_read (void)
+static int irq_read (void)
 {
 #if KERNEL_LINUX
 
@@ -191,9 +176,10 @@ static void irq_read (void)
 
        if ((fh = fopen ("/proc/interrupts", "r")) == NULL)
        {
-               syslog (LOG_WARNING, "irq plugin: fopen (/proc/interrupts): %s",
-                               strerror (errno));
-               return;
+               char errbuf[1024];
+               WARNING ("irq plugin: fopen (/proc/interrupts): %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
        }
        while (fgets (buffer, BUFSIZE, fh) != NULL)
        {
@@ -223,16 +209,24 @@ static void irq_read (void)
        }
        fclose (fh);
 #endif /* KERNEL_LINUX */
-} /* void irq_read */
-#else
-#define irq_read NULL
+
+       return (0);
+} /* int irq_read */
 #endif /* IRQ_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, NULL, irq_read, irq_write);
-       cf_register (MODULE_NAME, irq_config, config_keys, config_keys_num);
-}
+       if (load & MR_DATASETS)
+               plugin_register_data_set (&ds_irq);
+
+#if IRQ_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_config ("irq", irq_config,
+                               config_keys, config_keys_num);
+               plugin_register_read ("irq", irq_read);
+       }
+#endif /* IRQ_HAVE_READ */
+} /* void module_register */
 
 #undef BUFSIZE
-#undef MODULE_NAME
diff --git a/src/libconfig/AUTHORS b/src/libconfig/AUTHORS
deleted file mode 100644 (file)
index 53f27bf..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-                                libconfig 0.1.21
-
-Release information:
-  pkg:  libconfig version 0.1.21
-  url:  http://www.rkeene.org/files/oss/libconfig/devel/libconfig-0.1.21.tar.gz
-  web:  http://www.rkeene.org/oss/libconfig/
-  date: Tue Oct 18 16:03:55 CDT 2005
-  mail: libconfig@rkeene.org
---------------------------------------------------------------------------
-
-Primary Authors:
-  * Roy Keene <libconfig@rkeene.org>
-    Primary maintainer.
-
-People who have submitted patches:
-  * Mirko Buffoni <mirko.buffoni@synthesys.it>
-    Fixed installation issues and corrected mistakes in RPM spec file.
diff --git a/src/libconfig/LICENSE b/src/libconfig/LICENSE
deleted file mode 100644 (file)
index 4af06fb..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2004  Roy Keene, Keene Enterprises
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/src/libconfig/Makefile.am b/src/libconfig/Makefile.am
deleted file mode 100644 (file)
index b5a558a..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-AUTOMAKE_OPTIONS = foreign no-dependencies
-
-EXTRA_DIST = AUTHORS LICENSE README TODO
-
-noinst_LTLIBRARIES = libconfig.la
-
-libconfig_la_CFLAGS =
-libconfig_la_LDFLAGS = -avoid-version
-libconfig_la_SOURCES = \
-       libconfig.c libconfig.h \
-       conf_apache.c conf_apache.h \
-       conf_colon.c conf_colon.h \
-       conf_equal.c conf_equal.h \
-       conf_section.c conf_section.h \
-       conf_space.c conf_space.h \
-       conf_xml.c conf_xml.h \
-       compat.h libconfig_private.h
diff --git a/src/libconfig/README b/src/libconfig/README
deleted file mode 100644 (file)
index 7274223..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-                                libconfig 0.1.21
-
-Release information:
-  pkg:  libconfig version 0.1.21
-  url:  http://www.rkeene.org/files/oss/libconfig/devel/libconfig-0.1.21.tar.gz
-  web:  http://www.rkeene.org/oss/libconfig/
-  date: Tue Oct 18 16:03:55 CDT 2005
-  mail: libconfig@rkeene.org
---------------------------------------------------------------------------
-
-Tested platforms:
-  Mac OS X 10.1
-  HP-UX 11.11
-  NetBSD 1.6.1
-  FreeBSD 4.8
-  OpenBSD 3.4
-  SunOS 5.9
-  Linux (Slackware, RedHat, Fedora Core, Debian)
-  IRIX 6.5
diff --git a/src/libconfig/TODO b/src/libconfig/TODO
deleted file mode 100644 (file)
index 6ba4ed3..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-                                libconfig 0.1.21
-
-Release information:
-  pkg:  libconfig version 0.1.21
-  url:  http://www.rkeene.org/files/oss/libconfig/devel/libconfig-0.1.21.tar.gz
-  web:  http://www.rkeene.org/oss/libconfig/
-  date: Tue Oct 18 16:03:55 CDT 2005
-  mail: libconfig@rkeene.org
---------------------------------------------------------------------------
-
-  More manual pages.
diff --git a/src/libconfig/compat.h b/src/libconfig/compat.h
deleted file mode 100644 (file)
index 48d0b07..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-#ifndef RSK_COMPAT_H
-#define RSK_COMPAT_H
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#ifdef __WIN32__
-#include "win32.h"
-#endif
-
-#ifndef LC_LINEBUF_LEN
-#define LC_LINEBUF_LEN 1024
-#endif
-
-#ifdef HAVE_INTTYPES_H
-#include <inttypes.h>
-#endif
-#ifdef HAVE_MEMORY_H
-#include <memory.h>
-#endif
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_STDARG_H
-#include <stdarg.h>
-#endif
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef TIME_WITH_SYS_TIME
-#include <sys/time.h>
-#include <time.h>
-#else
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#else
-#include <time.h>
-#endif
-#endif
-
-#ifdef HAVE_OPENNET_H
-#include <opennet.h>
-#endif
-#ifdef HAVE_LIBOPENNET
-#define lc_fopen(path, mode) fopen_net(path, mode)
-#define lc_fgets(buf, size, stream) fgets_net(buf, size, stream)
-#define lc_feof(stream) feof_net(stream)
-#define lc_fclose(stream) fclose_net(stream)
-#define LC_FILE NETFILE
-#else
-#define lc_fopen(path, mode) fopen(path, mode)
-#define lc_fgets(buf, size, stream) fgets(buf, size, stream)
-#define lc_feof(stream) feof(stream)
-#define lc_fclose(stream) fclose(stream)
-#define LC_FILE FILE
-#endif
-
-#endif
diff --git a/src/libconfig/conf_apache.c b/src/libconfig/conf_apache.c
deleted file mode 100644 (file)
index 1497d1e..0000000
+++ /dev/null
@@ -1,371 +0,0 @@
-#include "compat.h"
-#include "libconfig.h"
-#include "libconfig_private.h"
-#include "conf_apache.h"
-
-#ifdef HAVE_CTYPE_H
-#include <ctype.h>
-#endif
-
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef HAVE_DIRENT_H
-#include <dirent.h>
-#endif
-
-static int lc_process_conf_apache_file(const char *configfile, const char *pathprefix);
-
-static int lc_process_conf_apache_include(const char *pathname, const char *pathprefix) {
-       struct stat pathinfo;
-       struct dirent *dinfo = NULL;
-       char includepath[LC_LINEBUF_LEN] = {0};
-       DIR *dh = NULL;
-       int statret = -1, lcpcafret = -1;
-       int retval = 0;
-
-       statret = stat(pathname, &pathinfo);
-       if (statret < 0) {
-               return(-1);
-       }
-
-       if (S_ISDIR(pathinfo.st_mode)) {
-               dh = opendir(pathname);
-               if (dh == NULL) {
-                       return(-1);
-               }
-
-               while (1) {
-                       dinfo = readdir(dh);
-                       if (dinfo == NULL) {
-                               break;
-                       }
-
-                       /* Skip files that begin with a dot ('.') */
-                       if (dinfo->d_name[0] == '.') continue;
-
-                       snprintf(includepath, sizeof(includepath) - 1, "%s/%s", pathname, dinfo->d_name);
-                       lcpcafret = lc_process_conf_apache_include(includepath, pathprefix);
-                       if (lcpcafret < 0) {
-                               retval = -1;
-                               /* XXX: should we break here (abort further including of files from a directory if one fails ?) */
-                       }
-               }
-
-               closedir(dh);
-       } else {
-               lcpcafret = lc_process_conf_apache_file(pathname, pathprefix);
-               if (lcpcafret < 0) {
-                       retval = -1;
-               }
-       }
-
-       return(retval);
-}
-
-static int lc_process_conf_apache_file(const char *configfile, const char *pathprefix) {
-       LC_FILE *configfp = NULL;
-       const char *local_lc_errfile;
-       char linebuf[LC_LINEBUF_LEN] = {0}, *linebuf_ptr = NULL, *tmp_ptr = NULL;
-       char *lastsection = NULL;
-       char qualifbuf[LC_LINEBUF_LEN] = {0};
-       char *cmd = NULL, *value = NULL, *sep = NULL, *cmdend = NULL;
-       char *fgetsret = NULL;
-       int lcpvret = -1, lpcafret = -1;
-       int invalid_section = 0, ignore_section = 0;
-       int local_lc_errline;
-       int retval = 0;
-       lc_err_t save_lc_errno = LC_ERR_NONE;
-
-       if (pathprefix != NULL) {
-               /* Copy the prefix, if specified. */
-               strncpy(qualifbuf, pathprefix, sizeof(qualifbuf) - 1);
-       }
-
-       local_lc_errfile = configfile;
-       local_lc_errline = 0;
-
-       if (configfile == NULL) {
-               lc_errfile = local_lc_errfile;
-               lc_errline = local_lc_errline;
-               lc_errno = LC_ERR_INVDATA;
-               return(-1);
-       }
-
-       configfp = lc_fopen(configfile, "r");
-
-       if (configfp == NULL) {
-               lc_errfile = local_lc_errfile;
-               lc_errline = local_lc_errline;
-               lc_errno = LC_ERR_CANTOPEN;
-               return(-1);
-       }
-
-       while (1) {
-               fgetsret = lc_fgets(linebuf, sizeof(linebuf) - 1, configfp);
-               if (fgetsret == NULL) {
-                       break;
-               }
-               if (lc_feof(configfp)) {
-                       break;
-               }
-
-               local_lc_errline++;
-
-               /* Remove trailing crap (but not spaces). */
-               linebuf_ptr = &linebuf[strlen(linebuf) - 1];
-               while (*linebuf_ptr < ' ' && linebuf_ptr >= linebuf) {
-                       *linebuf_ptr = '\0';
-                       linebuf_ptr--;
-               }
-
-               /* Remove leading spaces. */
-               linebuf_ptr = &linebuf[0];
-               while (*linebuf_ptr == ' ' || *linebuf_ptr == '\t') {
-                       linebuf_ptr++;
-               }
-
-               /* Handle section header. */
-               if (linebuf_ptr[0] == '<' && linebuf_ptr[strlen(linebuf_ptr) - 1] == '>') {
-                       /* Remove < and > from around the data. */
-                       linebuf_ptr[strlen(linebuf_ptr) - 1] = '\0';
-                       linebuf_ptr++;
-
-                       /* Lowercase the command part of the section. */
-                       tmp_ptr = linebuf_ptr;
-                       while (*tmp_ptr != '\0' && *tmp_ptr != ' ') {
-                               *tmp_ptr = tolower(*tmp_ptr);
-                               tmp_ptr++;
-                       }
-
-                       /* If this is a close section command, handle it */
-                       if (linebuf_ptr[0] == '/') {
-                               linebuf_ptr++;
-                               cmd = linebuf_ptr; 
-
-                               /* Find the last section closed. */
-                               tmp_ptr = strrchr(qualifbuf, '.');
-                               if (tmp_ptr == NULL) {
-                                       lastsection = qualifbuf;
-                                       tmp_ptr = qualifbuf;
-                               } else {
-                                       lastsection = tmp_ptr + 1;
-                               }
-
-                               if (strcmp(cmd, lastsection) != 0) {
-#ifdef DEBUG
-                                       fprintf(stderr, "Section closing does not match last opened section.\n");
-                                       fprintf(stderr, "Last opened = \"%s\", Closing = \"%s\"\n", lastsection, cmd);
-#endif
-                                       retval = -1;
-                                       lc_errfile = local_lc_errfile;
-                                       lc_errline = local_lc_errline;
-                                       lc_errno = LC_ERR_BADFORMAT;
-
-                                       /* For this error, we abort immediately. */
-                                       break;
-                               }
-
-                               lcpvret = lc_process_var(qualifbuf, NULL, NULL, LC_FLAGS_SECTIONEND);
-                               if (lcpvret < 0) {
-#ifdef DEBUG
-                                       fprintf(stderr, "Invalid section terminating: \"%s\"\n", qualifbuf);
-#endif
-                               }
-
-                               /* Remove the "lastsection" part.. */
-                               *tmp_ptr = '\0';
-
-                               /* We just sucessfully closed the last section opened,
-                                  we must be in a valid section now since we only open
-                                  sections from within valid sections. */
-                               invalid_section = 0;
-                               ignore_section = 0;
-
-                               continue;
-                       }
-                       /* Otherwise, open a new section. */
-
-                       /* Don't open a section from an invalid section. */
-                       if (invalid_section == 1 || ignore_section == 1) {
-                               continue;
-                       }
-
-                       /* Parse out any argument passed. */
-                       sep = strpbrk(linebuf_ptr, " \t");
-
-                       if (sep != NULL) {
-                               cmdend = sep;
-                               /* Delete space at the end of the command. */
-                               cmdend--; /* It currently derefs to the seperator.. */
-                               while (*cmdend <= ' ') {
-                                       *cmdend = '\0';
-                                       cmdend--;
-                               }
-
-                               /* Delete the seperator char and any leading space. */
-                               *sep = '\0';
-                               sep++;
-                               while (*sep == ' ' || *sep == '\t') {
-                                       sep++;
-                               }
-                               value = sep;
-                       } else {
-                               /* XXX: should this be "" or NULL ? */
-                               value = "";
-                       }
-
-                       cmd = linebuf_ptr;
-
-                       if (qualifbuf[0] != '\0') {
-                               strncat(qualifbuf, ".", sizeof(qualifbuf) - strlen(qualifbuf) - 1);
-                       }
-                       strncat(qualifbuf, cmd, sizeof(qualifbuf) - strlen(qualifbuf) - 1);
-
-                       lcpvret = lc_process_var(qualifbuf, value, NULL, LC_FLAGS_SECTIONSTART);
-                       if (lcpvret < 0) {
-#ifdef DEBUG
-                               fprintf(stderr, "Invalid section: \"%s\"\n", qualifbuf);
-#endif
-                               invalid_section = 1;
-                               lc_errfile = local_lc_errfile;
-                               lc_errline = local_lc_errline;
-                               lc_errno = LC_ERR_INVSECTION;
-                               retval = -1;
-                       }
-                       if (lcpvret == LC_CBRET_IGNORESECTION) {
-                               ignore_section = 1;
-                       }
-                       continue;
-               }
-
-               /* Drop comments and blank lines. */
-               if (*linebuf_ptr == '#' || *linebuf_ptr == '\0') {
-                       continue;
-               }
-
-               /* Don't handle things for a section that doesn't exist. */
-               if (invalid_section == 1) {
-#ifdef DEBUG
-                       fprintf(stderr, "Ignoring line (because invalid section): %s\n", linebuf);
-#endif
-                       continue;
-               }
-               if (ignore_section == 1) {
-#ifdef DEBUG
-                       fprintf(stderr, "Ignoring line (because ignored section): %s\n", linebuf);
-#endif
-                       continue;
-               }
-
-               /* Find the command and the data in the line. */
-               sep = strpbrk(linebuf_ptr, " \t");
-               if (sep != NULL) {
-                       cmdend = sep;
-
-                       /* Delete space at the end of the command. */
-                       cmdend--; /* It currently derefs to the seperator.. */
-                       while (*cmdend <= ' ') {
-                               *cmdend = '\0';
-                               cmdend--;
-                       }
-
-                       /* Delete the seperator char and any leading space. */
-                       *sep = '\0';
-                       sep++;
-                       while (*sep == ' ' || *sep == '\t') {
-                               sep++;
-                       }
-                       value = sep;
-               } else {
-                       value = NULL;
-               }
-
-               cmd = linebuf_ptr;
-
-               /* Handle special commands. */
-               if (strcasecmp(cmd, "include") == 0) {
-                       if (value == NULL) {
-                               lc_errfile = local_lc_errfile;
-                               lc_errline = local_lc_errline;
-                               lc_errno = LC_ERR_BADFORMAT;
-                               retval = -1;
-#ifdef DEBUG
-                               fprintf(stderr, "Invalid include command.\n");
-#endif
-                               continue;
-                       }
-
-                       lpcafret = lc_process_conf_apache_include(value, qualifbuf);
-                       if (lpcafret < 0) {
-#ifdef DEBUG
-                               fprintf(stderr, "Error in included file.\n");
-#endif
-                               retval = -1;
-                       }
-                       continue;
-               }
-
-               /* Create the fully qualified variable name. */
-               if (qualifbuf[0] != '\0') {
-                       strncat(qualifbuf, ".", sizeof(qualifbuf) - strlen(qualifbuf) - 1);
-               }
-               strncat(qualifbuf, cmd, sizeof(qualifbuf) - strlen(qualifbuf) - 1);
-
-               /* Call the parent and tell them we have data. */
-               save_lc_errno = lc_errno;
-               lc_errno = LC_ERR_NONE;
-               lcpvret = lc_process_var(qualifbuf, NULL, value, LC_FLAGS_VAR);
-               if (lcpvret < 0) {
-                       if (lc_errno == LC_ERR_NONE) {
-#ifdef DEBUG
-                               fprintf(stderr, "Invalid command: \"%s\"\n", cmd);
-#endif
-                               lc_errfile = local_lc_errfile;
-                               lc_errline = local_lc_errline;
-                               lc_errno = LC_ERR_INVCMD;
-                       } else {
-#ifdef DEBUG
-                               fprintf(stderr, "Error processing command (command was valid, but an error occured, errno was set)\n");
-#endif
-                       }
-                       lc_errfile = local_lc_errfile;
-                       lc_errline = local_lc_errline;
-                       retval = -1;
-               } else {
-                       lc_errno = save_lc_errno;
-               }
-
-               /* Remove the "cmd" part of the buffer. */
-               tmp_ptr = strrchr(qualifbuf, '.');
-               if (tmp_ptr == NULL) {
-                       tmp_ptr = qualifbuf;
-               }
-               *tmp_ptr = '\0';
-       }
-
-       lc_fclose(configfp);
-
-       return(retval);
-}
-
-int lc_process_conf_apache(const char *appname, const char *configfile) {
-       return(lc_process_conf_apache_file(configfile, NULL));
-}
diff --git a/src/libconfig/conf_apache.h b/src/libconfig/conf_apache.h
deleted file mode 100644 (file)
index 36c556e..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef LC_CONF_APACHE_H
-#define LC_CONF_APACHE_H
-#include "libconfig.h"
-#include "libconfig_private.h"
-
-int lc_process_conf_apache(const char *appname, const char *configfile);
-
-#endif
diff --git a/src/libconfig/conf_colon.c b/src/libconfig/conf_colon.c
deleted file mode 100644 (file)
index f184309..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "libconfig.h"
-#include "libconfig_private.h"
-#include "conf_colon.h"
-
-int lc_process_conf_colon(const char *appname, const char *configfile) {
-       return(-1);
-}
diff --git a/src/libconfig/conf_colon.h b/src/libconfig/conf_colon.h
deleted file mode 100644 (file)
index 7d2323c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef LC_CONF_COLON_H
-#define LC_CONF_COLON_H
-#include "libconfig.h"
-#include "libconfig_private.h"
-
-int lc_process_conf_colon(const char *appname, const char *configfile);
-
-#endif
diff --git a/src/libconfig/conf_equal.c b/src/libconfig/conf_equal.c
deleted file mode 100644 (file)
index a214330..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "libconfig.h"
-#include "libconfig_private.h"
-#include "conf_equal.h"
-
-int lc_process_conf_equal(const char *appname, const char *configfile) {
-       return(-1);
-}
diff --git a/src/libconfig/conf_equal.h b/src/libconfig/conf_equal.h
deleted file mode 100644 (file)
index 82e0f04..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef LC_CONF_EQUAL_H
-#define LC_CONF_EQUAL_H
-#include "libconfig.h"
-#include "libconfig_private.h"
-
-int lc_process_conf_equal(const char *appname, const char *configfile);
-
-#endif
diff --git a/src/libconfig/conf_section.c b/src/libconfig/conf_section.c
deleted file mode 100644 (file)
index fb948c1..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-#include "compat.h"
-#include "libconfig.h"
-#include "libconfig_private.h"
-#include "conf_section.h"
-
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-int lc_process_conf_section(const char *appname, const char *configfile) {
-       LC_FILE *configfp = NULL;
-       const char *local_lc_errfile;
-       char linebuf[LC_LINEBUF_LEN] = {0}, *linebuf_ptr = NULL;
-       char qualifbuf[LC_LINEBUF_LEN] = {0};
-       char *cmd = NULL, *value = NULL, *sep = NULL, *cmdend = NULL;
-       char *currsection = NULL;
-       char *fgetsret = NULL;
-       int lcpvret = -1;
-       int invalid_section = 1, ignore_section = 0;
-       int local_lc_errline;
-       int retval = 0;
-       lc_err_t save_lc_errno = LC_ERR_NONE;
-
-       local_lc_errfile = configfile;
-       local_lc_errline = 0;
-
-       if (appname == NULL || configfile == NULL) {
-               lc_errfile = local_lc_errfile;
-               lc_errline = local_lc_errline;
-               lc_errno = LC_ERR_INVDATA;
-               return(-1);
-       }
-
-       configfp = lc_fopen(configfile, "r");
-
-       if (configfp == NULL) {
-               lc_errfile = local_lc_errfile;
-               lc_errline = local_lc_errline;
-               lc_errno = LC_ERR_CANTOPEN;
-               return(-1);
-       }
-
-       while (1) {
-               fgetsret = lc_fgets(linebuf, sizeof(linebuf) - 1, configfp);
-               if (fgetsret == NULL) {
-                       break;
-               }
-               if (lc_feof(configfp)) {
-                       break;
-               }
-
-               local_lc_errline++;
-
-               /* Remove trailing crap (but not spaces). */
-               linebuf_ptr = &linebuf[strlen(linebuf) - 1];
-               while (*linebuf_ptr < ' ' && linebuf_ptr >= linebuf) {
-                       *linebuf_ptr = '\0';
-                       linebuf_ptr--;
-               }
-
-               /* Handle section header. */
-               if (linebuf[0] == '[' && linebuf[strlen(linebuf) - 1] == ']') {
-                       linebuf[strlen(linebuf) - 1] = '\0';
-                       linebuf_ptr = &linebuf[1];
-
-                       /* If a section was open, close it. */
-                       if (currsection != NULL) {
-                               lcpvret = lc_process_var(currsection, NULL, NULL, LC_FLAGS_SECTIONEND);
-                               if (lcpvret < 0) {
-#ifdef DEBUG
-                                       fprintf(stderr, "Invalid section terminating: \"%s\"\n", currsection);
-#endif
-                               }
-                               free(currsection);
-                       }
-
-                       /* Open new section. */
-                       currsection = strdup(linebuf_ptr);
-                       lcpvret = lc_process_var(currsection, NULL, NULL, LC_FLAGS_SECTIONSTART);
-                       if (lcpvret < 0) {
-#ifdef DEBUG
-                               fprintf(stderr, "Invalid section: \"%s\"\n", currsection);
-#endif
-                               invalid_section = 1;
-                               lc_errfile = local_lc_errfile;
-                               lc_errline = local_lc_errline;
-                               lc_errno = LC_ERR_INVSECTION;
-                               retval = -1;
-                       } else {
-                               invalid_section = 0;
-                               ignore_section = 0;
-                       }
-
-                       if (lcpvret == LC_CBRET_IGNORESECTION) {
-                               ignore_section = 1;
-                       }
-                       continue;
-               }
-
-               /* Remove leading spaces. */
-               linebuf_ptr = &linebuf[0];
-               while (*linebuf_ptr == ' ') {
-                       linebuf_ptr++;
-               }
-
-               /* Drop comments and blank lines. */
-               if (*linebuf_ptr == ';' || *linebuf_ptr == '\0') {
-                       continue;
-               }
-
-               /* Don't handle things for a section that doesn't exist. */
-               if (invalid_section == 1) {
-#ifdef DEBUG
-                       fprintf(stderr, "Ignoring line (because invalid section): %s\n", linebuf);
-#endif
-                       continue;
-               }
-
-               /* Don't process commands if this section is specifically ignored. */
-               if (ignore_section == 1) {
-#ifdef DEBUG
-                       fprintf(stderr, "Ignoring line (because ignored section): %s\n", linebuf);
-#endif
-                       continue;
-               }
-
-               /* Find the command and the data in the line. */
-               cmdend = sep = strpbrk(linebuf_ptr, "=");
-               if (sep == NULL) {
-#ifdef DEBUG
-                       fprintf(stderr, "Invalid line: \"%s\"\n", linebuf);
-#endif
-                       continue;
-               }
-
-               /* Delete space at the end of the command. */
-               cmdend--; /* It currently derefs to the seperator.. */
-               while (*cmdend <= ' ') {
-                       *cmdend = '\0';
-                       cmdend--;
-               }
-
-               cmd = linebuf_ptr;
-
-               /* Delete the seperator char and any leading space. */
-               *sep = '\0';
-               sep++;
-               while (*sep == ' ' || *sep == '\t') {
-                       sep++;
-               }
-               value = sep;
-
-               /* Create the fully qualified variable name. */
-               if (currsection == NULL) {
-                       strncpy(qualifbuf, cmd, sizeof(qualifbuf) - 1);
-               } else {
-                       snprintf(qualifbuf, sizeof(qualifbuf) - 1, "%s.%s", currsection, cmd);
-               }
-
-               /* Call the parent and tell them we have data. */
-               save_lc_errno = lc_errno;
-               lc_errno = LC_ERR_NONE;
-               lcpvret = lc_process_var(qualifbuf, NULL, value, LC_FLAGS_VAR);
-               if (lcpvret < 0) {
-                       if (lc_errno == LC_ERR_NONE) {
-#ifdef DEBUG
-                               fprintf(stderr, "Invalid command: \"%s\"\n", cmd);
-#endif
-                               lc_errno = LC_ERR_INVCMD;
-                       } else {
-#ifdef DEBUG
-                               fprintf(stderr, "Error processing command (command was valid, but an error occured, errno was set)\n");
-#endif
-                       }
-                       lc_errfile = local_lc_errfile;
-                       lc_errline = local_lc_errline;
-                       retval = -1;
-               } else {
-                       lc_errno = save_lc_errno;
-               }
-       }
-
-       /* Close any open section, and clean-up. */
-       if (currsection != NULL) {
-               lcpvret = lc_process_var(currsection, NULL, NULL, LC_FLAGS_SECTIONEND);
-               if (lcpvret < 0) {
-#ifdef DEBUG
-                       fprintf(stderr, "Invalid section terminating: \"%s\"\n", currsection);
-#endif
-               }
-               free(currsection);
-       }
-
-       lc_fclose(configfp);
-
-       return(retval);
-}
diff --git a/src/libconfig/conf_section.h b/src/libconfig/conf_section.h
deleted file mode 100644 (file)
index 1d1a94c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef LC_CONF_SECTION_H
-#define LC_CONF_SECTION_H
-#include "libconfig.h"
-#include "libconfig_private.h"
-
-int lc_process_conf_section(const char *appname, const char *configfile);
-
-#endif
diff --git a/src/libconfig/conf_space.c b/src/libconfig/conf_space.c
deleted file mode 100644 (file)
index 50a9b23..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-#include "compat.h"
-#include "libconfig.h"
-#include "libconfig_private.h"
-#include "conf_space.h"
-
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-int lc_process_conf_space(const char *appname, const char *configfile) {
-       LC_FILE *configfp = NULL;
-       const char *local_lc_errfile;
-       char linebuf[LC_LINEBUF_LEN] = {0}, *linebuf_ptr = NULL;
-       char *cmd = NULL, *value = NULL, *sep = NULL;
-       char *fgetsret = NULL;
-       int local_lc_errline;
-       int lcpvret = -1;
-       int retval = 0;
-       lc_err_t save_lc_errno = LC_ERR_NONE;
-
-       local_lc_errfile = configfile;
-       local_lc_errline = 0;
-
-       if (appname == NULL || configfile == NULL) {
-               lc_errfile = local_lc_errfile;
-               lc_errline = local_lc_errline;
-               lc_errno = LC_ERR_INVDATA;
-               return(-1);
-       }
-
-       configfp = lc_fopen(configfile, "r");
-
-       if (configfp == NULL) {
-               lc_errfile = local_lc_errfile;
-               lc_errline = local_lc_errline;
-               lc_errno = LC_ERR_CANTOPEN;
-               return(-1);
-       }
-
-       while (1) {
-               fgetsret = lc_fgets(linebuf, sizeof(linebuf) - 1, configfp);
-               if (fgetsret == NULL) {
-                       break;
-               }
-               if (lc_feof(configfp)) {
-                       break;
-               }
-
-               local_lc_errline++;
-
-               linebuf_ptr = &linebuf[strlen(linebuf) - 1];
-               while (*linebuf_ptr < ' ' && linebuf_ptr >= linebuf) {
-                       *linebuf_ptr = '\0';
-                       linebuf_ptr--;
-               }
-
-               linebuf_ptr = &linebuf[0];
-               while (*linebuf_ptr == ' ') {
-                       linebuf_ptr++;
-               }
-
-               if (*linebuf_ptr == '#' || *linebuf_ptr == '\0') {
-                       continue;
-               }
-
-
-               sep = strpbrk(linebuf_ptr, " \t");
-               cmd = linebuf_ptr;
-               if (sep != NULL) {
-                       *sep = '\0';
-                       sep++;
-                       while (*sep == ' ' || *sep == '\t') {
-                               sep++;
-                       }
-                       value = sep;
-               } else {
-                       value = NULL;
-               }
-
-               save_lc_errno = lc_errno;
-               lc_errno = LC_ERR_NONE;
-               lcpvret = lc_process_var(cmd, NULL, value, LC_FLAGS_VAR);
-               if (lcpvret < 0) {
-                       if (lc_errno == LC_ERR_NONE) {
-#ifdef DEBUG
-                               fprintf(stderr, "Invalid command: \"%s\"\n", cmd);
-#endif
-                               lc_errno = LC_ERR_INVCMD;
-                       } else {
-#ifdef DEBUG
-                               fprintf(stderr, "Error processing command (command was valid, but an error occured, errno was set)\n");
-#endif
-                       }
-                       lc_errfile = local_lc_errfile;
-                       lc_errline = local_lc_errline;
-                       retval = -1;
-               } else {
-                       lc_errno = save_lc_errno;
-               }
-       }
-
-       lc_fclose(configfp);
-
-       return(retval);
-}
diff --git a/src/libconfig/conf_space.h b/src/libconfig/conf_space.h
deleted file mode 100644 (file)
index 6cf0462..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef LC_CONF_SPACE_H
-#define LC_CONF_SPACE_H
-#include "libconfig.h"
-#include "libconfig_private.h"
-
-int lc_process_conf_space(const char *appname, const char *configfile);
-
-#endif
diff --git a/src/libconfig/conf_xml.c b/src/libconfig/conf_xml.c
deleted file mode 100644 (file)
index 85edd51..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "libconfig.h"
-#include "libconfig_private.h"
-#include "conf_xml.h"
-
-int lc_process_conf_xml(const char *appname, const char *configfile) {
-       return(-1);
-}
diff --git a/src/libconfig/conf_xml.h b/src/libconfig/conf_xml.h
deleted file mode 100644 (file)
index f0deffb..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef LC_CONF_XML_H
-#define LC_CONF_XML_H
-#include "libconfig.h"
-#include "libconfig_private.h"
-
-int lc_process_conf_xml(const char *appname, const char *configfile);
-
-#endif
diff --git a/src/libconfig/libconfig.c b/src/libconfig/libconfig.c
deleted file mode 100644 (file)
index 9f80a76..0000000
+++ /dev/null
@@ -1,1073 +0,0 @@
-#include "compat.h"
-#include "libconfig.h"
-#include "libconfig_private.h"
-#include "conf_section.h"
-#include "conf_apache.h"
-#include "conf_colon.h"
-#include "conf_equal.h"
-#include "conf_space.h"
-#include "conf_xml.h"
-
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifdef HAVE_CTYPE_H
-#include <ctype.h>
-#endif
-
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#ifdef HAVE_PWD_H
-#include <pwd.h>
-#endif
-
-struct lc_varhandler_st *varhandlers = NULL;
-lc_err_t lc_errno = LC_ERR_NONE;
-const char *lc_errfile = NULL;
-int lc_optind = 0;
-int lc_errline = 0;
-
-extern char **environ;
-
-static int lc_process_var_string(void *data, const char *value, const char **endptr) {
-       char **dataval;
-
-       dataval = data;
-       *dataval = strdup(value);
-
-       *endptr = NULL;
-
-       return(0);
-}
-
-static int lc_process_var_cidr(void *data, const char *value, const char **endptr) {
-       return(-1);
-}
-
-static int lc_process_var_hostname6(void *data, const char *value, const char **endptr) {
-       return(-1);
-}
-
-static int lc_process_var_hostname4(void *data, const char *value, const char **endptr) {
-       return(-1);
-}
-
-static int lc_process_var_ip6(void *data, const char *value, const char **endptr) {
-       return(-1);
-}
-
-static int lc_process_var_ip4(void *data, const char *value, const char **endptr) {
-       uint32_t *dataval, retval = 0;
-       const char *dotptr = NULL;
-       int tmpval = -1;
-//     int dotcount
-
-       dataval = data;
-
-       dotptr = value;
-
-       while (1) {
-               tmpval = atoi(dotptr);
-               if (tmpval < 0) {
-                       break;
-               }
-
-               retval <<= 8;
-               retval |= tmpval;
-
-               dotptr = strpbrk(dotptr, "./ \t");
-               if (dotptr == NULL) {
-                       break;
-               }
-               if (*dotptr != '.') {
-                       break;
-               }
-               dotptr++;
-       }
-
-       *dataval = retval;
-
-       *endptr = (char *) dotptr;
-
-       return(0);
-}
-
-static int lc_process_var_longlong(void *data, const char *value, const char **endptr) {
-       long long *dataval;
-
-       dataval = data;
-       *dataval = strtoll(value, (char **) endptr, 10);
-
-       return(0);
-}
-
-static int lc_process_var_long(void *data, const char *value, const char **endptr) {
-       long *dataval;
-
-       dataval = data;
-       *dataval = strtoll(value, (char **) endptr, 10);
-
-       return(0);
-}
-
-static int lc_process_var_int(void *data, const char *value, const char **endptr) {
-       int *dataval;
-
-       dataval = data;
-       *dataval = strtoll(value, (char **) endptr, 10);
-
-       return(0);
-}
-
-static int lc_process_var_short(void *data, const char *value, const char **endptr) {
-       short *dataval;
-
-       dataval = data;
-       *dataval = strtoll(value, (char **) endptr, 10);
-
-       return(0);
-}
-
-static int lc_process_var_bool_byexistance(void *data, const char *value, const char **endptr) {
-       int *dataval;
-
-       dataval = data;
-
-       *dataval = 1;
-
-       *endptr = NULL;
-
-       return(0);
-}
-
-static int lc_process_var_bool(void *data, const char *value, const char **endptr) {
-       char *trueval[] = {"enable", "true", "yes", "on", "y", "1"};
-       char *falseval[] = {"disable", "false", "no", "off", "n", "0"};
-       size_t chkvallen, vallen;
-       int *dataval;
-       int i;
-
-       dataval = data;
-
-       *dataval = -1;
-
-       vallen = strlen(value);
-
-       for (i = 0; i < (sizeof(trueval) / sizeof(*trueval)); i++) {
-               chkvallen = strlen(trueval[i]);
-
-               /*
-                * Skip if there's no way we could find a match here.
-                */
-               if (chkvallen > vallen) {
-                       continue;
-               }
-
-               /*
-                * Skip if there is no partial match.
-                */
-               if (strncasecmp(value, trueval[i], chkvallen) != 0) {
-                       continue;
-               }
-
-               if (value[chkvallen] == '\0' || value[chkvallen] == ',' || \
-                   value[chkvallen] == ' ') {
-                       /* Declare a winner and set the next token. */
-                       *endptr = value + chkvallen;
-                       *dataval = 1;
-                       return(0);
-               }
-       }
-
-       for (i = 0; i < (sizeof(falseval) / sizeof(*falseval)); i++) {
-               chkvallen = strlen(falseval[i]);
-
-               /*
-                * Skip if there's no way we could find a match here.
-                */
-               if (chkvallen > vallen) {
-                       continue;
-               }
-
-               /*
-                * Skip if there is no partial match.
-                */
-               if (strncasecmp(value, falseval[i], chkvallen) != 0) {
-                       continue;
-               }
-
-               if (value[chkvallen] == '\0' || value[chkvallen] == ',' || \
-                   value[chkvallen] == ' ') {
-                       /* Declare a winner and set the next token. */
-                       *endptr = value + chkvallen;
-                       *dataval = 0;
-                       return(0);
-               }
-       }
-
-       lc_errno = LC_ERR_BADFORMAT;
-       return(-1);
-}
-
-static unsigned long long lc_process_size(const char *value, const char **endptr) {
-       unsigned long long retval = 0;
-       char *mult = NULL;
-
-       retval = strtoll(value, &mult, 10);
-       if (mult != NULL) {
-               switch (tolower(mult[0])) {
-                       case 'p':
-                               retval *= 1125899906842624LLU;
-                               break;
-                       case 't':
-                               retval *= 1958505086976LLU;
-                               break;
-                       case 'g':
-                               retval *= 1073741824;
-                               break;
-                       case 'm':
-                               retval *= 1048576;
-                               break;
-                       case 'k':
-                               retval *= 1024;
-                               break;
-                       default:
-                               break;
-               }
-       }
-
-       return(retval);
-}
-
-static int lc_process_var_sizelonglong(void *data, const char *value, const char **endptr) {
-       long long *dataval;
-
-       dataval = data;
-       *dataval = lc_process_size(value, endptr);
-
-       return(0);
-}
-
-static int lc_process_var_sizelong(void *data, const char *value, const char **endptr) {
-       long *dataval;
-
-       dataval = data;
-       *dataval = lc_process_size(value, endptr);
-
-       return(0);
-}
-
-static int lc_process_var_sizeint(void *data, const char *value, const char **endptr) {
-       int *dataval;
-
-       dataval = data;
-       *dataval = lc_process_size(value, endptr);
-
-       return(0);
-}
-
-static int lc_process_var_sizeshort(void *data, const char *value, const char **endptr) {
-       short *dataval;
-
-       dataval = data;
-       *dataval = lc_process_size(value, endptr);
-
-       return(0);
-}
-
-static int lc_process_var_sizesizet(void *data, const char *value, const char **endptr) {
-       size_t *dataval;
-
-       dataval = data;
-       *dataval = lc_process_size(value, endptr);
-
-       return(0);
-}
-
-
-static int lc_handle_type(lc_var_type_t type, const char *value, void *data) {
-       const char *next;
-       int is_list;
-
-       is_list = type & LC_VAR_LIST;
-
-       if (is_list == LC_VAR_LIST) {
-       }
-
-       switch (type) {
-               case LC_VAR_STRING:
-                       return(lc_process_var_string(data, value, &next));
-                       break;
-               case LC_VAR_LONG_LONG:
-                       return(lc_process_var_longlong(data, value, &next));
-                       break;
-               case LC_VAR_LONG:
-                       return(lc_process_var_long(data, value, &next));
-                       break;
-               case LC_VAR_INT:
-                       return(lc_process_var_int(data, value, &next));
-                       break;
-               case LC_VAR_SHORT:
-                       return(lc_process_var_short(data, value, &next));
-                       break;
-               case LC_VAR_BOOL:
-                       return(lc_process_var_bool(data, value, &next));
-                       break;
-               case LC_VAR_SIZE_LONG_LONG:
-                       return(lc_process_var_sizelonglong(data, value, &next));
-                       break;
-               case LC_VAR_SIZE_LONG:
-                       return(lc_process_var_sizelong(data, value, &next));
-                       break;
-               case LC_VAR_SIZE_INT:
-                       return(lc_process_var_sizeint(data, value, &next));
-                       break;
-               case LC_VAR_SIZE_SHORT:
-                       return(lc_process_var_sizeshort(data, value, &next));
-                       break;
-               case LC_VAR_BOOL_BY_EXISTANCE:
-                       return(lc_process_var_bool_byexistance(data, value, &next));
-                       break;
-               case LC_VAR_SIZE_SIZE_T:
-                       return(lc_process_var_sizesizet(data, value, &next));
-                       break;
-               case LC_VAR_IP:
-               case LC_VAR_IP4:
-                       return(lc_process_var_ip4(data, value, &next));
-                       break;
-               case LC_VAR_IP6:
-                       return(lc_process_var_ip6(data, value, &next));
-                       break;
-               case LC_VAR_HOSTNAME4:
-                       return(lc_process_var_hostname4(data, value, &next));
-                       break;
-               case LC_VAR_HOSTNAME6:
-                       return(lc_process_var_hostname6(data, value, &next));
-                       break;
-               case LC_VAR_CIDR:
-                       return(lc_process_var_cidr(data, value, &next));
-                       break;
-               case LC_VAR_TIME:
-               case LC_VAR_DATE:
-               case LC_VAR_FILENAME:
-               case LC_VAR_DIRECTORY:
-#ifdef DEBUG
-                       fprintf(stderr, "Not implemented yet!\n");
-#endif
-                       return(-1);
-               case LC_VAR_NONE:
-               case LC_VAR_UNKNOWN:
-               case LC_VAR_SECTION:
-               case LC_VAR_SECTIONSTART:
-               case LC_VAR_SECTIONEND:
-                       return(0);
-                       break;
-       }
-
-       return(-1);
-}
-
-static int lc_handle(struct lc_varhandler_st *handler, const char *var, const char *varargs, const char *value, lc_flags_t flags) {
-       const char *localvar = NULL;
-       int retval;
-
-       if (var != NULL) {
-               localvar = strrchr(var, '.');
-               if (localvar == NULL) {
-                       localvar = var;
-               } else {
-                       localvar++;
-               }
-       } else {
-               localvar = NULL;
-       }
-
-       switch (handler->mode) {
-               case LC_MODE_CALLBACK:
-                       if (handler->callback != NULL) {
-                               retval = handler->callback(localvar, var, varargs, value, flags, handler->extra);
-                               if (retval < 0) {
-                                       lc_errno = LC_ERR_CALLBACK;
-                               }
-                               return(retval);
-                       }
-                       break;
-               case LC_MODE_VAR:
-                       return(lc_handle_type(handler->type, value, handler->data));
-                       break;
-       }
-
-       return(-1);
-}
-
-static int lc_process_environment(const char *appname) {
-#ifndef ENABLE_SMALL
-       struct lc_varhandler_st *handler = NULL;
-       size_t appnamelen = 0;
-       char varnamebuf[128] = {0};
-       char **currvar;
-       char *sep = NULL, *value = NULL, *cmd = NULL;
-       char *ucase_appname = NULL, *ucase_appname_itr = NULL;
-       char *lastcomponent_handler = NULL;
-       int varnamelen = 0;
-       char *local_lc_errfile;
-       int local_lc_errline;
-
-       /* Make sure we have an environment to screw with, if not,
-          no arguments were found to be in error */
-       if (environ == NULL || appname == NULL) {
-               return(0);
-       }
-
-       local_lc_errfile = "<environment>";
-       local_lc_errline = 0;
-
-       /* Allocate and create our uppercase appname. */
-       ucase_appname = strdup(appname);
-       if (ucase_appname == NULL) {
-               lc_errfile = local_lc_errfile;
-               lc_errline = local_lc_errline;
-               lc_errno = LC_ERR_ENOMEM;
-               return(-1);
-       }
-       for (ucase_appname_itr = ucase_appname; *ucase_appname_itr != '\0'; ucase_appname_itr++) {
-               *ucase_appname_itr = toupper(*ucase_appname_itr);
-       }
-
-       appnamelen = strlen(ucase_appname);
-
-       for (currvar = environ; *currvar != NULL; currvar++) {
-               /* If it doesn't begin with our appname ignore it completely. */
-               if (strncmp(*currvar, ucase_appname, appnamelen) != 0) {
-                       continue;
-               }
-
-               /* Find our seperator. */
-               sep = strchr(*currvar, '=');
-               if (sep == NULL) {
-                       continue;
-               }
-
-               varnamelen = sep - *currvar;
-
-               /* Skip variables that would overflow our buffer. */
-               if (varnamelen >= sizeof(varnamebuf)) {
-                       continue;
-               }
-
-               strncpy(varnamebuf, *currvar, varnamelen);
-
-               varnamebuf[varnamelen] = '\0';
-               value = sep + 1;
-
-               /* We ignore APPNAME by itself. */
-               if (strlen(varnamebuf) <= appnamelen) {
-                       continue;
-               }
-
-               /* Further it must be <APPNAME>_ */
-               if (varnamebuf[appnamelen] != '_') {
-                       continue;
-               }
-
-               cmd = varnamebuf + appnamelen + 1;
-
-               /* We don't allow section specifiers, for reasons see notes in
-                  the cmdline processor (below). */
-               if (strchr(cmd, '.') != NULL) {
-                       continue;
-               }
-
-               for (handler = varhandlers; handler != NULL; handler = handler->_next) {
-                       if (handler->var == NULL) {
-                               continue;
-                       }
-
-                       /* Skip handlers which don't agree with being
-                          processed outside a config file */
-                       if (handler->type == LC_VAR_SECTION ||
-                           handler->type == LC_VAR_SECTIONSTART ||
-                           handler->type == LC_VAR_SECTIONEND ||
-                           handler->type == LC_VAR_UNKNOWN) {
-                               continue;
-                       }
-
-                       /* Find the last part of the variable and compare it with 
-                          the option being processed, if a wildcard is given. */
-                       if (handler->var[0] == '*' && handler->var[1] == '.') {
-                               lastcomponent_handler = strrchr(handler->var, '.');
-                               if (lastcomponent_handler == NULL) {
-                                       lastcomponent_handler = handler->var;
-                               } else {
-                                       lastcomponent_handler++;
-                               }
-                       } else {
-                               lastcomponent_handler = handler->var;
-                       }
-
-                       /* Ignore this handler if they don't match. */
-                       if (strcasecmp(lastcomponent_handler, cmd) != 0) {
-                               continue;
-                       }
-
-                       if (handler->type == LC_VAR_NONE || handler->type == LC_VAR_BOOL_BY_EXISTANCE) {
-                               value = NULL;
-                       }
-
-                       /* We ignore errors from the environment variables,
-                          they're mostly insignificant. */
-                       lc_handle(handler, cmd, NULL, value, LC_FLAGS_ENVIRON);
-
-                       break;
-               }
-       }
-
-       free(ucase_appname);
-
-#endif
-       return(0);
-}
-
-static int lc_process_cmdline(int argc, char **argv) {
-       struct lc_varhandler_st *handler = NULL;
-       char *cmdarg = NULL, *cmdoptarg = NULL;
-       char *lastcomponent_handler = NULL;
-       char **newargv = NULL;
-       char *usedargv = NULL;
-       int cmdargidx = 0;
-       int newargvidx = 0;
-       int retval = 0, chkretval = 0;
-       int ch = 0;
-       char *local_lc_errfile;
-       int local_lc_errline;
-
-       local_lc_errfile = "<cmdline>";
-       local_lc_errline = 0;
-
-       /* Allocate "argc + 1" (+1 for the NULL terminator) elements. */
-       newargv = malloc((argc + 1) * sizeof(*newargv));
-       if (newargv == NULL) {
-               lc_errfile = local_lc_errfile;
-               lc_errline = local_lc_errline;
-               lc_errno = LC_ERR_ENOMEM;
-               return(-1);
-       }
-       newargv[newargvidx++] = argv[0];
-       newargv[argc] = NULL;
-
-       /* Allocate space to indicate which arguments have been used. */
-       usedargv = malloc(argc * sizeof(*usedargv));
-       if (usedargv == NULL) {
-               lc_errfile = local_lc_errfile;
-               lc_errline = local_lc_errline;
-               lc_errno = LC_ERR_ENOMEM;
-               free(newargv);
-               return(-1);
-       }
-       for (cmdargidx = 0; cmdargidx < argc; cmdargidx++) {
-               usedargv[cmdargidx] = 0;
-       }
-
-       for (cmdargidx = 1; cmdargidx < argc; cmdargidx++) {
-               cmdarg = argv[cmdargidx];
-
-               /* Make sure we have an argument here. */
-               if (cmdarg == NULL) {
-                       break;
-               }
-
-               /* If the argument isn't an option, skip. */
-               if (cmdarg[0] != '-') {
-                       continue;
-               }
-
-               /* Setup a pointer in the new array for the actual argument. */
-               newargv[newargvidx++] = cmdarg;
-               usedargv[cmdargidx] = 1;
-
-               /* Then shift the argument past the '-' so we can ignore it. */
-               cmdarg++;
-
-               /* Handle long options. */
-               if (cmdarg[0] == '-') {
-                       cmdarg++;
-
-                       /* Don't process arguments after the '--' option. */
-                       if (cmdarg[0] == '\0') {
-                               break;
-                       }
-
-                       /* Look for a variable name that matches */
-                       for (handler = varhandlers; handler != NULL; handler = handler->_next) {
-                               /* Skip handlers with no variable name. */
-                               if (handler->var == NULL) {
-                                       continue;
-                               }
-                               /* Skip handlers which don't agree with being
-                                  processed on the command line. */
-                               if (handler->type == LC_VAR_SECTION ||
-                                   handler->type == LC_VAR_SECTIONSTART ||
-                                   handler->type == LC_VAR_SECTIONEND ||
-                                   handler->type == LC_VAR_UNKNOWN) {
-                                       continue;
-                               }
-
-                               /* Find the last part of the variable and compare it with 
-                                  the option being processed, if a wildcard is given. */
-                               if (handler->var[0] == '*' && handler->var[1] == '.') {
-                                       lastcomponent_handler = strrchr(handler->var, '.');
-                                       if (lastcomponent_handler == NULL) {
-                                               lastcomponent_handler = handler->var;
-                                       } else {
-                                               lastcomponent_handler++;
-                                       }
-                               } else {
-                                       /* Disallow use of the fully qualified name
-                                          since there was no sectionstart portion
-                                          we cannot allow it to handle children of it. */
-                                       if (strchr(cmdarg, '.') != NULL) {
-                                               continue;
-                                       }
-                                       lastcomponent_handler = handler->var;
-                               }
-
-                               /* Ignore this handler if they don't match. */
-                               if (strcasecmp(lastcomponent_handler, cmdarg) != 0) {
-                                       continue;
-                               }
-
-                               if (handler->type == LC_VAR_NONE || handler->type == LC_VAR_BOOL_BY_EXISTANCE) {
-                                       cmdoptarg = NULL;
-                               } else {
-                                       cmdargidx++;
-                                       if (cmdargidx >= argc) {
-                                               fprintf(stderr, "Argument required.\n");
-                                               lc_errfile = local_lc_errfile;
-                                               lc_errline = local_lc_errline;
-                                               lc_errno = LC_ERR_BADFORMAT;
-                                               free(usedargv);
-                                               free(newargv);
-                                               return(-1);
-                                       }
-                                       cmdoptarg = argv[cmdargidx];
-                                       newargv[newargvidx++] = cmdoptarg;
-                                       usedargv[cmdargidx] = 1;
-                               }
-
-                               chkretval = lc_handle(handler, handler->var, NULL, cmdoptarg, LC_FLAGS_CMDLINE);
-                               if (chkretval < 0) {
-                                       retval = -1;
-                               }
-
-                               break;
-                       }
-
-                       if (handler == NULL) {
-                               fprintf(stderr, "Unknown option: --%s\n", cmdarg);
-                               lc_errfile = local_lc_errfile;
-                               lc_errline = local_lc_errline;
-                               lc_errno = LC_ERR_INVCMD;
-                               free(usedargv);
-                               free(newargv);
-                               return(-1);
-                       }
-               } else {
-                       for (; *cmdarg != '\0'; cmdarg++) {
-                               ch = *cmdarg;
-
-                               for (handler = varhandlers; handler != NULL; handler = handler->_next) {
-                                       if (handler->opt != ch || handler->opt == '\0') {
-                                               continue;
-                                       }
-                                       /* Skip handlers which don't agree with being
-                                          processed on the command line. */
-                                       if (handler->type == LC_VAR_SECTION ||
-                                           handler->type == LC_VAR_SECTIONSTART ||
-                                           handler->type == LC_VAR_SECTIONEND ||
-                                           handler->type == LC_VAR_UNKNOWN) {
-                                               continue;
-                                       }
-
-                                       if (handler->type == LC_VAR_NONE || handler->type == LC_VAR_BOOL_BY_EXISTANCE) {
-                                               cmdoptarg = NULL;
-                                       } else {
-                                               cmdargidx++;
-                                               if (cmdargidx >= argc) {
-                                                       fprintf(stderr, "Argument required.\n");
-                                                       lc_errfile = local_lc_errfile;
-                                                       lc_errline = local_lc_errline;
-                                                       lc_errno = LC_ERR_BADFORMAT;
-                                                       free(usedargv);
-                                                       free(newargv);
-                                                       return(-1);
-                                               }
-                                               cmdoptarg = argv[cmdargidx];
-                                               newargv[newargvidx++] = cmdoptarg;
-                                               usedargv[cmdargidx] = 1;
-                                       }
-
-                                       chkretval = lc_handle(handler, handler->var, NULL, cmdoptarg, LC_FLAGS_CMDLINE);
-                                       if (chkretval < 0) {
-                                               lc_errfile = local_lc_errfile;
-                                               lc_errline = local_lc_errline;
-                                               retval = -1;
-                                       }
-
-                                       break;
-                               }
-
-                               if (handler == NULL) {
-                                       fprintf(stderr, "Unknown option: -%c\n", ch);
-                                       lc_errfile = local_lc_errfile;
-                                       lc_errline = local_lc_errline;
-                                       lc_errno = LC_ERR_INVCMD;
-                                       free(usedargv);
-                                       free(newargv);
-                                       return(-1);
-                               }
-                       }
-               }
-       }
-
-       if (retval >= 0) {
-               lc_optind = newargvidx;
-               for (cmdargidx = 1; cmdargidx < argc; cmdargidx++) {
-                       if (usedargv[cmdargidx] != 0) {
-                               continue;
-                       }
-                       
-                       cmdarg = argv[cmdargidx];
-
-                       newargv[newargvidx++] = cmdarg;
-               }
-               for (cmdargidx = 1; cmdargidx < argc; cmdargidx++) {
-                       argv[cmdargidx] = newargv[cmdargidx];
-               }
-       }
-
-       free(usedargv);
-       free(newargv);
-
-       return(retval);
-}
-
-
-int lc_process_var(const char *var, const char *varargs, const char *value, lc_flags_t flags) {
-       struct lc_varhandler_st *handler = NULL;
-       const char *lastcomponent_handler = NULL, *lastcomponent_var = NULL;
-
-       lastcomponent_var = strrchr(var, '.');
-       if (lastcomponent_var == NULL) {
-               lastcomponent_var = var;
-       } else {
-               lastcomponent_var++;
-       }
-
-       for (handler = varhandlers; handler != NULL; handler = handler->_next) {
-               /* If either handler->var or var is NULL, skip, unless both are NULL. */
-               if (handler->var != var && (handler->var == NULL || var == NULL)) {
-                       continue;
-               }
-
-               /* If both are not-NULL, compare them. */
-               if (handler->var != NULL) {
-                       /* Wild-card-ish match. */
-                       if (handler->var[0] == '*' && handler->var[1] == '.') {
-                               /* Only compare the last components */
-
-                               lastcomponent_handler = strrchr(handler->var, '.') + 1; /* strrchr() won't return NULL, because we already checked it. */
-
-                               if (strcasecmp(lastcomponent_handler, lastcomponent_var) != 0) {
-                                       continue;
-                               }
-                       } else if (strcasecmp(handler->var, var) != 0) {
-                               /* Exact (case-insensitive comparison) failed. */
-                               continue;
-                       }
-               }
-
-               if (value == NULL &&
-                   handler->type != LC_VAR_NONE &&
-                   handler->type != LC_VAR_BOOL_BY_EXISTANCE &&
-                   handler->type != LC_VAR_SECTION &&
-                   handler->type != LC_VAR_SECTIONSTART &&
-                   handler->type != LC_VAR_SECTIONEND) {
-                       lc_errno = LC_ERR_BADFORMAT;
-                       break;
-               }
-
-               return(lc_handle(handler, var, varargs, value, flags));
-       }
-
-       return(-1);
-}
-
-int lc_register_callback(const char *var, char opt, lc_var_type_t type, int (*callback)(const char *, const char *, const char *, const char *, lc_flags_t, void *), void *extra) {
-       struct lc_varhandler_st *newhandler = NULL;
-
-       newhandler = malloc(sizeof(*newhandler));
-
-       if (newhandler == NULL) {
-               return(-1);
-       }
-
-       if (var == NULL) {
-               newhandler->var = NULL;
-       } else {
-               newhandler->var = strdup(var);
-       }
-       newhandler->mode = LC_MODE_CALLBACK;
-       newhandler->type = type;
-       newhandler->callback = callback;
-       newhandler->opt = opt;
-       newhandler->extra = extra;
-       newhandler->_next = varhandlers;
-
-       varhandlers = newhandler;
-
-       return(0);
-}
-
-int lc_register_var(const char *var, lc_var_type_t type, void *data, char opt) {
-       struct lc_varhandler_st *newhandler = NULL;
-
-       newhandler = malloc(sizeof(*newhandler));
-
-       if (newhandler == NULL) {
-               return(-1);
-       }
-
-       if (var == NULL) {
-               newhandler->var = NULL;
-       } else {
-               newhandler->var = strdup(var);
-       }
-       newhandler->mode = LC_MODE_VAR;
-       newhandler->type = type;
-       newhandler->data = data;
-       newhandler->opt = opt;
-       newhandler->extra = NULL;
-       newhandler->_next = varhandlers;
-
-       varhandlers = newhandler;
-
-       return(0);
-}
-
-int lc_process_file(const char *appname, const char *pathname, lc_conf_type_t type) {
-       int chkretval = 0;
-
-       switch (type) {
-               case LC_CONF_SECTION:
-                       chkretval = lc_process_conf_section(appname, pathname);
-                       break;
-               case LC_CONF_APACHE:
-                       chkretval = lc_process_conf_apache(appname, pathname);
-                       break;
-               case LC_CONF_COLON:
-                       chkretval = lc_process_conf_colon(appname, pathname);
-                       break;
-               case LC_CONF_EQUAL:
-                       chkretval = lc_process_conf_equal(appname, pathname);
-                       break;
-               case LC_CONF_SPACE:
-                       chkretval = lc_process_conf_space(appname, pathname);
-                       break;
-               case LC_CONF_XML:
-                       chkretval = lc_process_conf_xml(appname, pathname);
-                       break;
-               default:
-                       chkretval = -1;
-                       lc_errno = LC_ERR_INVDATA;
-                       break;
-       }
-
-       return(chkretval);
-}
-
-static int lc_process_files(const char *appname, lc_conf_type_t type, const char *extraconfig) {
-#ifdef HAVE_GETPWUID
-       struct passwd *pwinfo = NULL;
-#endif
-       char configfiles[3][13][512] = {{{0}}};
-       char *configfile = NULL;
-       char *homedir = NULL;
-       int configsetidx = 0, configidx = 0;
-       int chkretval = 0, retval = 0;
-
-       if (extraconfig != NULL) {
-               snprintf(configfiles[0][0], sizeof(**configfiles) - 1, "%s", extraconfig);
-       }
-       snprintf(configfiles[1][0], sizeof(**configfiles) - 1, "/etc/%s.cfg", appname);
-       snprintf(configfiles[1][1], sizeof(**configfiles) - 1, "/etc/%s.conf", appname);
-       snprintf(configfiles[1][2], sizeof(**configfiles) - 1, "/etc/%s/%s.cfg", appname, appname);
-       snprintf(configfiles[1][3], sizeof(**configfiles) - 1, "/etc/%s/%s.conf", appname, appname);
-       snprintf(configfiles[1][4], sizeof(**configfiles) - 1, "/usr/etc/%s.cfg", appname);
-       snprintf(configfiles[1][5], sizeof(**configfiles) - 1, "/usr/etc/%s.conf", appname);
-       snprintf(configfiles[1][6], sizeof(**configfiles) - 1, "/usr/etc/%s/%s.cfg", appname, appname);
-       snprintf(configfiles[1][7], sizeof(**configfiles) - 1, "/usr/etc/%s/%s.conf", appname, appname);
-       snprintf(configfiles[1][8], sizeof(**configfiles) - 1, "/usr/local/etc/%s.cfg", appname);
-       snprintf(configfiles[1][9], sizeof(**configfiles) - 1, "/usr/local/etc/%s.conf", appname);
-       snprintf(configfiles[1][10], sizeof(**configfiles) - 1, "/usr/local/etc/%s/%s.cfg", appname, appname);
-       snprintf(configfiles[1][11], sizeof(**configfiles) - 1, "/usr/local/etc/%s/%s.conf", appname, appname);
-       if (getuid() != 0) {
-               homedir = getenv("HOME");
-#ifdef HAVE_GETPWUID
-               if (homedir == NULL) {
-                       pwinfo = getpwuid(getuid());
-                       if (pwinfo != NULL) {
-                               homedir = pwinfo->pw_dir;
-                       }
-               }
-#endif
-               if (homedir != NULL) {
-                       if (strcmp(homedir, "/") != 0 && access(homedir, R_OK|W_OK|X_OK) == 0) {
-                               snprintf(configfiles[2][0], sizeof(**configfiles) - 1, "%s/.%src", homedir, appname);
-                               snprintf(configfiles[2][1], sizeof(**configfiles) - 1, "%s/.%s.cfg", homedir, appname);
-                               snprintf(configfiles[2][2], sizeof(**configfiles) - 1, "%s/.%s.conf", homedir, appname);
-                               snprintf(configfiles[2][3], sizeof(**configfiles) - 1, "%s/.%s/%s.cfg", homedir, appname, appname);
-                               snprintf(configfiles[2][4], sizeof(**configfiles) - 1, "%s/.%s/%s.conf", homedir, appname, appname);
-                               snprintf(configfiles[2][5], sizeof(**configfiles) - 1, "%s/.%s/config", homedir, appname);
-                       }
-               }
-       }
-
-       for (configsetidx = 0; configsetidx < 3; configsetidx++) {
-               for (configidx = 0; configidx < 13; configidx++) {
-                       configfile = configfiles[configsetidx][configidx];
-                       if (configfile[0] == '\0') {
-                               break;
-                       }
-                       if (access(configfile, R_OK) == 0) {
-                               chkretval = lc_process_file(appname, configfile, type);
-                               if (chkretval < 0) {
-                                       retval = -1;
-                               }
-                               break;
-                       }
-               }
-       }
-
-       return(retval);
-}
-
-void lc_cleanup(void) {
-       struct lc_varhandler_st *handler = NULL, *next = NULL;
-
-       handler = varhandlers;
-       while (handler != NULL) {
-               if (handler->var != NULL) {
-                       free(handler->var);
-               }
-
-               next = handler->_next;
-
-               free(handler);
-
-               handler = next;
-       }
-
-       varhandlers = NULL;
-
-       return;
-}
-
-int lc_process(int argc, char **argv, const char *appname, lc_conf_type_t type, const char *extra) {
-       int retval = 0, chkretval = 0;
-
-       /* Handle config files. */
-       chkretval = lc_process_files(appname, type, extra);
-       if (chkretval < 0) {
-               retval = -1;
-       }
-
-       /* Handle environment variables.*/
-       chkretval = lc_process_environment(appname);
-       if (chkretval < 0) {
-               retval = -1;
-       }
-
-       /* Handle command line arguments */
-       chkretval = lc_process_cmdline(argc, argv);
-       if (chkretval < 0) {
-               retval = -1;
-       }
-
-       return(retval);
-}
-
-
-lc_err_t lc_geterrno(void) {
-       lc_err_t retval;
-
-       retval = lc_errno;
-
-       lc_errno = LC_ERR_NONE;
-
-       return(retval);
-}
-
-char *lc_geterrstr(void) {
-       static char retval[512];
-       char *errmsg = NULL;
-
-       switch (lc_errno) {
-               case LC_ERR_NONE:
-                       errmsg = "Success";
-                       break;
-               case LC_ERR_INVCMD:
-                       errmsg = "Invalid command or option";
-                       break;
-               case LC_ERR_INVSECTION:
-                       errmsg = "Invalid section";
-                       break;
-               case LC_ERR_INVDATA:
-                       errmsg = "Invalid application data (internal error)";
-                       break;
-               case LC_ERR_BADFORMAT:
-                       errmsg = "Bad data specified or incorrect format.";
-                       break;
-               case LC_ERR_CANTOPEN:
-                       errmsg = "Can't open file.";
-                       break;
-               case LC_ERR_CALLBACK:
-                       errmsg = "Error return from application handler.";
-                       break;
-               case LC_ERR_ENOMEM:
-                       errmsg = "Insuffcient memory.";
-                       break;
-       }
-
-       /*
-        * This is not part of the switch statement so we will get warnings
-        * about unhandled enum values.
-        */
-       if (errmsg == NULL) {
-               errmsg = "Unknown error";
-       }
-
-       if (lc_errfile == NULL) {
-               snprintf(retval, sizeof(retval), "%s:%i: %s", "<no file>", lc_errline, errmsg);
-       } else {
-               snprintf(retval, sizeof(retval), "%s:%i: %s", lc_errfile, lc_errline, errmsg);
-       }
-
-       retval[sizeof(retval) - 1] = '\0';
-
-       return(retval);
-}
diff --git a/src/libconfig/libconfig.h b/src/libconfig/libconfig.h
deleted file mode 100644 (file)
index 8c2f361..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#  ifndef _RSK_LIBCONFIG_H
-#  define _RSK_LIBCONFIG_H
-#  ifdef __cplusplus
-extern "C" {
-#  endif
-
-#  define LC_VAR_LIST 0x80
-
-typedef enum {
-        LC_CONF_SECTION,
-        LC_CONF_APACHE,
-        LC_CONF_COLON,
-        LC_CONF_EQUAL,
-        LC_CONF_SPACE,
-        LC_CONF_XML
-} lc_conf_type_t;
-
-typedef enum {
-        LC_VAR_UNKNOWN,
-        LC_VAR_NONE,
-        LC_VAR_STRING,
-        LC_VAR_LONG_LONG,
-        LC_VAR_LONG,
-        LC_VAR_INT,
-        LC_VAR_SHORT,
-        LC_VAR_BOOL,
-        LC_VAR_FILENAME,
-        LC_VAR_DIRECTORY,
-        LC_VAR_SIZE_LONG_LONG,
-        LC_VAR_SIZE_LONG,
-        LC_VAR_SIZE_INT,
-        LC_VAR_SIZE_SHORT,
-        LC_VAR_TIME,
-        LC_VAR_DATE,
-        LC_VAR_SECTION,
-        LC_VAR_SECTIONSTART,
-        LC_VAR_SECTIONEND,
-        LC_VAR_BOOL_BY_EXISTANCE,
-        LC_VAR_SIZE_SIZE_T,
-        LC_VAR_CIDR,
-        LC_VAR_IP,
-        LC_VAR_IP4,
-        LC_VAR_IP6,
-        LC_VAR_HOSTNAME4,
-        LC_VAR_HOSTNAME6,
-} lc_var_type_t;
-
-typedef enum {
-        LC_FLAGS_VAR,
-        LC_FLAGS_CMDLINE,
-        LC_FLAGS_ENVIRON,
-        LC_FLAGS_SECTIONSTART,
-        LC_FLAGS_SECTIONEND
-} lc_flags_t;
-
-typedef enum {
-        LC_ERR_NONE,
-        LC_ERR_INVCMD,
-        LC_ERR_INVSECTION,
-        LC_ERR_INVDATA,
-        LC_ERR_BADFORMAT,
-        LC_ERR_CANTOPEN,
-        LC_ERR_CALLBACK,
-        LC_ERR_ENOMEM
-} lc_err_t;
-
-int lc_process(int argc, char **argv, const char *appname, lc_conf_type_t type, const char *extra);
-int lc_register_callback(const char *var, char opt, lc_var_type_t type, int (*callback)(const char *, const char *, const char *, const char *, lc_flags_t, void *), void *extra);
-int lc_register_var(const char *var, lc_var_type_t type, void *data, char opt);
-lc_err_t lc_geterrno(void);
-char *lc_geterrstr(void);
-int lc_process_file(const char *appname, const char *pathname, lc_conf_type_t type);
-void lc_cleanup(void);
-
-#  define LC_CBRET_IGNORESECTION (255)
-#  define LC_CBRET_OKAY (0)
-#  define LC_CBRET_ERROR (-1)
-
-extern int lc_optind;
-
-#  ifdef __cplusplus
-}
-#  endif
-#  endif
diff --git a/src/libconfig/libconfig_private.h b/src/libconfig/libconfig_private.h
deleted file mode 100644 (file)
index 8310a85..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef _RSK_LIBCONFIG_PRIVATE_H
-#define _RSK_LIBCONFIG_PRIVATE_H
-
-#include "libconfig.h"
-
-extern lc_err_t lc_errno;
-extern int lc_errline;
-extern const char *lc_errfile;
-
-int lc_process_var(const char *var, const char *varargs, const char *value, lc_flags_t flags);
-
-struct lc_varhandler_st;
-
-struct lc_varhandler_st {
-       struct lc_varhandler_st *_next;
-       char *var;
-       char opt;
-       lc_var_type_t type;
-       enum {
-               LC_MODE_CALLBACK,
-               LC_MODE_VAR
-       } mode;
-       int (*callback)();
-       void *data;
-       void *extra;
-};
-
-#endif
diff --git a/src/libconfig/test-lc.c b/src/libconfig/test-lc.c
deleted file mode 100644 (file)
index ed492d8..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-#include "compat.h"
-#include "libconfig.h"
-
-int help_cmd(const char *partarg, const char *arg, const char *argarg, const char *val, lc_flags_t flags, void *extra) {
-       printf("Usage info goes here\n");
-       printf("\n");
-
-       exit(EXIT_FAILURE);
-}
-int sally_cmd(const char *partarg, const char *arg, const char *argarg, const char *val, lc_flags_t flags, void *extra) {
-       fprintf(stderr, "%s sets value: \"%s\" (flags=%i)\n", arg, val, flags);
-       return(0);
-}
-
-int cmd_ifmodule(const char *partarg, const char *arg, const char *argarg, const char *val, lc_flags_t flags, void *extra) {
-       if (flags == LC_FLAGS_SECTIONEND) {
-               return(LC_CBRET_OKAY);
-       }
-       if (flags != LC_FLAGS_SECTIONSTART) {
-               fprintf(stderr, "IfModule can only be used as a section.\n");
-               return(LC_CBRET_ERROR);
-       }
-       if (argarg == NULL) {
-               fprintf(stderr, "You must specify an argument to IfModule.\n");
-               return(LC_CBRET_ERROR);
-       }
-
-       fprintf(stderr, "IfModule (%s)\n", argarg);
-       return(LC_CBRET_IGNORESECTION);
-}
-
-int main(int argc, char **argv) {
-       char *joeval = NULL;
-       size_t xval = -1;
-       int onoff = -1;
-       int lcpret = -1;
-       int i = 0;
-       int onoff2 = 0;
-       uint32_t ipaddr = 0;
-
-       lc_register_var("Section", LC_VAR_SECTION, NULL, 0);
-       lc_register_var("Somesection", LC_VAR_SECTION, NULL, 0);
-       lc_register_var("Section.Test", LC_VAR_STRING, &joeval, 'j');
-       lc_register_var("bob", LC_VAR_SIZE_SIZE_T, &xval, 's');
-       lc_register_var("Somesection.Free", LC_VAR_BOOL, &onoff, 0);
-       lc_register_var("long", LC_VAR_BOOL_BY_EXISTANCE, &onoff2, 'l');
-       lc_register_var("ipaddr", LC_VAR_IP, &ipaddr, 'i');
-       lc_register_callback("sally", 0, LC_VAR_STRING, sally_cmd, NULL);
-       lc_register_callback("HELP", 'h', LC_VAR_NONE, help_cmd, NULL);
-       lc_register_callback("*.ifmodule", 0, LC_VAR_NONE, cmd_ifmodule, NULL);
-       lcpret = lc_process_file("testapp", "build/test.conf", LC_CONF_APACHE);
-       if (lcpret < 0) {
-               fprintf(stderr, "Error processing config file: %s\n", lc_geterrstr());
-               return(EXIT_FAILURE);
-       }
-
-       lcpret = lc_process(argc, argv, "testapp", LC_CONF_APACHE, "test.cfg");
-       if (lcpret < 0) {
-               fprintf(stderr, "Error processing config file: %s\n", lc_geterrstr());
-               return(EXIT_FAILURE);
-       }
-
-       lc_cleanup();
-
-       if (joeval != NULL) {
-               fprintf(stderr, "joeval = \"%s\"\n", joeval);
-       } else {
-               fprintf(stderr, "joeval = \"(null)\"\n");
-       }
-       fprintf(stderr, "xval = %llu\n", (unsigned long long) xval);
-       fprintf(stderr, "onoff = %i\n", onoff);
-       fprintf(stderr, "long = %i\n", onoff2);
-       fprintf(stderr, "ip = %08lx\n", (unsigned long) ipaddr);
-       for (i = lc_optind; i < argc; i++) {
-               fprintf(stderr, "argv[%i] = \"%s\"\n", i, argv[i]);
-       }
-
-       return(0);
-}
diff --git a/src/libconfig/win32.h b/src/libconfig/win32.h
deleted file mode 100644 (file)
index 06f3a0d..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#if !defined(_LOCAL_WIN32_H) && defined(__WIN32__) && !defined(__CYGWIN__)
-#define _LOCAL_WIN32_H
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef __MINGW32__
-     /* MingW32 specific stuff here. */
-#  if defined(HAVE_WINSOCK2_H) && defined(HAVE_LIBWSOCK32)
-     /* We have to override the detected configuration
-        because it can't detect the network libraries. */
-#    define HAVE_GETHOSTBYNAME 1
-#    define HAVE_INET_ADDR 1
-#    define HAVE_SOCKET 1
-#  endif
-#  define sleep(x) Sleep((x) * 1000)
-#else
-   /* MSVC++ configuration follows */
-#  undef HAVE_UNISTD_H
-#  define HAVE_STDLIB_H 1
-#  define HAVE_WINDOWS_H 1
-#  define HAVE_STDARG_H 1
-#  define HAVE_WINSVC_H 1
-#  define HAVE_WINSOCK2_H 1
-#  define HAVE_WINDOWSX_H 1
-#endif /* __MINGW32__ */
-
-#ifdef HAVE_WINDOWS_H
-#  include <windows.h>
-#endif
-#ifdef HAVE_WINDOWSX_H
-#  include <windowsx.h>
-#endif
-#ifdef HAVE_WINSOCK2_H
-#  include <winsock2.h>
-#endif
-#ifdef HAVE_WINSVC_H
-#  include <winsvc.h>
-#endif
-
-#define _USE_WIN32_ 1
-
-#endif /* _LOCAL_WIN32_H */
diff --git a/src/liboconfig/AUTHORS b/src/liboconfig/AUTHORS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/liboconfig/COPYING b/src/liboconfig/COPYING
new file mode 100644 (file)
index 0000000..623b625
--- /dev/null
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/src/liboconfig/ChangeLog b/src/liboconfig/ChangeLog
new file mode 100644 (file)
index 0000000..390c507
--- /dev/null
@@ -0,0 +1,5 @@
+2007-02-15, Version 0.1.1
+       * src/parser.y: Fixes a memory leak.
+
+2007-02-11, Version 0.1.0
+       * Initial release.
diff --git a/src/liboconfig/Makefile.am b/src/liboconfig/Makefile.am
new file mode 100644 (file)
index 0000000..4e8d086
--- /dev/null
@@ -0,0 +1,11 @@
+AUTOMAKE_OPTIONS = foreign no-dependencies
+
+BUILT_SOURCES = parser.h
+CLEANFILES = parser.[ch] scanner.c
+AM_YFLAGS = -d
+
+include_HEADERS = oconfig.h
+lib_LTLIBRARIES = liboconfig.la
+
+liboconfig_la_LDFLAGS = -version-info 0:0:0 $(LEXLIB)
+liboconfig_la_SOURCES = oconfig.c oconfig.h scanner.l parser.y
diff --git a/src/liboconfig/aux_types.h b/src/liboconfig/aux_types.h
new file mode 100644 (file)
index 0000000..25b81ab
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef AUX_TYPES_H
+#define AUX_TYPES_H 1
+
+struct statement_list_s
+{
+       oconfig_item_t *statement;
+       int             statement_num;
+};
+typedef struct statement_list_s statement_list_t;
+
+struct argument_list_s
+{
+       oconfig_value_t *argument;
+       int              argument_num;
+};
+typedef struct argument_list_s argument_list_t;
+
+#endif /* AUX_TYPES_H */
diff --git a/src/liboconfig/oconfig.c b/src/liboconfig/oconfig.c
new file mode 100644 (file)
index 0000000..f8d1849
--- /dev/null
@@ -0,0 +1,84 @@
+/**
+ * oconfig - src/oconfig.c
+ * Copyright (C) 2006,2007  Florian octo Forster <octo at verplant.org>
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "oconfig.h"
+
+/* Functions provided by the scanner */
+void yyset_in  (FILE *);
+
+oconfig_item_t *ci_root;
+
+oconfig_item_t *oconfig_parse_fh (FILE *fh)
+{
+  int status;
+  oconfig_item_t *ret;
+
+  yyset_in (fh);
+
+  status = yyparse ();
+  if (status != 0)
+  {
+    fprintf (stderr, "yyparse returned error #%i\n", status);
+    return (NULL);
+  }
+
+  ret = ci_root;
+  ci_root = NULL;
+  yyset_in ((FILE *) 0);
+
+  return (ret);
+} /* oconfig_item_t *oconfig_parse_fh */
+
+oconfig_item_t *oconfig_parse_file (const char *file)
+{
+  FILE *fh;
+  oconfig_item_t *ret;
+
+  fh = fopen (file, "r");
+  if (fh == NULL)
+  {
+    fprintf (stderr, "fopen (%s) failed: %s\n", file, strerror (errno));
+    return (NULL);
+  }
+
+  ret = oconfig_parse_fh (fh);
+  fclose (fh);
+
+  return (ret);
+} /* oconfig_item_t *oconfig_parse_file */
+
+void oconfig_free (oconfig_item_t *ci)
+{
+  int i;
+
+  if (ci->values != NULL)
+    free (ci->values);
+
+  for (i = 0; i < ci->children_num; i++)
+    oconfig_free (ci->children + i);
+}
+
+/*
+ * vim:shiftwidth=2:tabstop=8:softtabstop=2
+ */
diff --git a/src/liboconfig/oconfig.h b/src/liboconfig/oconfig.h
new file mode 100644 (file)
index 0000000..e6e53e2
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef OCONFIG_H
+#define OCONFIG_H 1
+
+#include <stdio.h>
+
+/**
+ * oconfig - src/oconfig.h
+ * Copyright (C) 2006,2007  Florian octo Forster <octo at verplant.org>
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Types
+ */
+#define OCONFIG_TYPE_STRING  0
+#define OCONFIG_TYPE_NUMBER  1
+#define OCONFIG_TYPE_BOOLEAN 2
+
+struct oconfig_value_s
+{
+  union
+  {
+    char  *string;
+    double number;
+    int    boolean;
+  } value;
+  int type;
+};
+typedef struct oconfig_value_s oconfig_value_t;
+
+struct oconfig_item_s;
+typedef struct oconfig_item_s oconfig_item_t;
+struct oconfig_item_s
+{
+  char            *key;
+  oconfig_value_t *values;
+  int              values_num;
+
+  oconfig_item_t  *parent;
+  oconfig_item_t  *children;
+  int              children_num;
+};
+
+/*
+ * Functions
+ */
+oconfig_item_t *oconfig_parse_fh (FILE *fh);
+oconfig_item_t *oconfig_parse_file (const char *file);
+
+void oconfig_free (oconfig_item_t *ci);
+
+/*
+ * vim: shiftwidth=2:tabstop=8:softtabstop=2
+ */
+#endif /* OCONFIG_H */
diff --git a/src/liboconfig/parser.y b/src/liboconfig/parser.y
new file mode 100644 (file)
index 0000000..ea6ed0a
--- /dev/null
@@ -0,0 +1,221 @@
+/**
+ * oconfig - src/parser.y
+ * Copyright (C) 2007  Florian octo Forster <octo at verplant.org>
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+%{
+#include <stdlib.h>
+#include <string.h>
+#include "oconfig.h"
+#include "aux_types.h"
+
+static char *unquote (const char *orig);
+static int yyerror (const char *s);
+
+/* Lexer variables */
+extern int yylineno;
+extern char *yytext;
+
+extern oconfig_item_t *ci_root;
+%}
+
+%start entire_file
+
+%union {
+       double  number;
+       int     boolean;
+       char   *string;
+       oconfig_value_t  cv;
+       oconfig_item_t   ci;
+       argument_list_t  al;
+       statement_list_t sl;
+}
+
+%token <number> NUMBER
+%token <boolean> TRUE FALSE
+%token <string> QUOTED_STRING UNQUOTED_STRING
+%token SLASH OPENBRAC CLOSEBRAC EOL
+
+%type <string> string
+%type <string> identifier
+/* arguments */
+%type <cv> argument
+%type <al> argument_list
+/* blocks */
+%type <ci> block_begin
+%type <ci> block
+%type <string> block_end
+/* statements */
+%type <ci> option
+%type <ci> statement
+%type <sl> statement_list
+%type <ci> entire_file
+
+%%
+string:
+       QUOTED_STRING           {$$ = unquote ($1);}
+       | UNQUOTED_STRING       {$$ = strdup ($1);}
+       ;
+
+argument:
+       NUMBER                  {$$.value.number = $1; $$.type = OCONFIG_TYPE_NUMBER;}
+       | TRUE                  {$$.value.boolean = 1; $$.type = OCONFIG_TYPE_BOOLEAN;}
+       | FALSE                 {$$.value.boolean = 0; $$.type = OCONFIG_TYPE_BOOLEAN;}
+       | string                {$$.value.string = $1; $$.type = OCONFIG_TYPE_STRING;}
+       ;
+
+argument_list:
+       argument_list argument
+       {
+        $$ = $1;
+        $$.argument_num++;
+        $$.argument = realloc ($$.argument, $$.argument_num * sizeof (oconfig_value_t));
+        $$.argument[$$.argument_num-1] = $2;
+       }
+       | argument
+       {
+        $$.argument = malloc (sizeof (oconfig_value_t));
+        $$.argument[0] = $1;
+        $$.argument_num = 1;
+       }
+       ;
+
+identifier:
+       UNQUOTED_STRING                 {$$ = strdup ($1);}
+       ;
+
+option:
+       identifier argument_list EOL
+       {
+        memset (&$$, '\0', sizeof ($$));
+        $$.key = $1;
+        $$.values = $2.argument;
+        $$.values_num = $2.argument_num;
+       }
+       ;
+
+block_begin:
+       OPENBRAC identifier argument_list CLOSEBRAC EOL
+       {
+        memset (&$$, '\0', sizeof ($$));
+        $$.key = $2;
+        $$.values = $3.argument;
+        $$.values_num = $3.argument_num;
+       }
+       ;
+
+block_end:
+       OPENBRAC SLASH identifier CLOSEBRAC EOL
+       {
+        $$ = $3;
+       }
+       ;
+
+block:
+       block_begin statement_list block_end
+       {
+        if (strcmp ($1.key, $3) != 0)
+        {
+               printf ("block_begin = %s; block_end = %s;\n", $1.key, $3);
+               yyerror ("Block not closed..\n");
+               exit (1);
+        }
+        free ($3); $3 = NULL;
+        $$ = $1;
+        $$.children = $2.statement;
+        $$.children_num = $2.statement_num;
+       }
+       ;
+
+statement:
+       option          {$$ = $1;}
+       | block         {$$ = $1;}
+       | EOL           {$$.values_num = 0;}
+       ;
+
+statement_list:
+       statement_list statement
+       {
+        $$ = $1;
+        if ($2.values_num > 0)
+        {
+                $$.statement_num++;
+                $$.statement = realloc ($$.statement, $$.statement_num * sizeof (oconfig_item_t));
+                $$.statement[$$.statement_num-1] = $2;
+        }
+       }
+       | statement
+       {
+        if ($1.values_num > 0)
+        {
+                $$.statement = malloc (sizeof (oconfig_item_t));
+                $$.statement[0] = $1;
+                $$.statement_num = 1;
+        }
+        else
+        {
+               $$.statement = NULL;
+               $$.statement_num = 0;
+        }
+       }
+       ;
+
+entire_file:
+       statement_list
+       {
+        ci_root = malloc (sizeof (oconfig_item_t));
+        memset (ci_root, '\0', sizeof (oconfig_item_t));
+        ci_root->children = $1.statement;
+        ci_root->children_num = $1.statement_num;
+       }
+       ;
+
+%%
+static int yyerror (const char *s)
+{
+       fprintf (stderr, "Error in line %i near `%s': %s\n", yylineno, yytext, s);
+       return (-1);
+} /* int yyerror */
+
+static char *unquote (const char *orig)
+{
+       char *ret = strdup (orig);
+       int len;
+       int i;
+
+       if (ret == NULL)
+               return (NULL);
+
+       len = strlen (ret);
+
+       if ((len < 2) || (ret[0] != '"') || (ret[len - 1] != '"'))
+               return (ret);
+
+       ret++;
+       len -= 2;
+       ret[len] = '\0';
+
+       for (i = 0; i < len; i++)
+       {
+               if (ret[i] == '\\')
+               {
+                       memmove (ret + i, ret + (i + 1), len - i);
+                       len--;
+               }
+       }
+
+       return (ret);
+} /* char *unquote */
diff --git a/src/liboconfig/scanner.l b/src/liboconfig/scanner.l
new file mode 100644 (file)
index 0000000..aa111a2
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * oconfig - src/scanner.l
+ * Copyright (C) 2007  Florian octo Forster <octo at verplant.org>
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+%{
+#include <stdlib.h>
+#include "oconfig.h"
+#include "aux_types.h"
+#include "parser.h"
+%}
+WHITE_SPACE [\ \t\b]
+QUOTED_STRING \"([^\\"]+|\\.)*\"
+UNQUOTED_STRING [0-9A-Za-z_]+
+HEX_NUMBER 0[xX][0-9a-fA-F]+
+OCT_NUMBER 0[0-7]+
+DEC_NUMBER [\+\-]?[0-9]+
+FLOAT_NUMBER [\+\-]?[0-9]*\.[0-9]+([eE][\+\-][0-9]+)?
+NUMBER ({FLOAT_NUMBER}|{HEX_NUMBER}|{OCT_NUMBER}|{DEC_NUMBER})
+BOOL_TRUE (true|yes|on)
+BOOL_FALSE (false|no|off)
+COMMENT #.*
+PORT (6(5(5(3[0-5]|[0-2][0-9])|[0-4][0-9][0-9])|[0-4][0-9][0-9][0-9])|[1-5][0-9][0-9][0-9][0-9]|[1-9][0-9]?[0-9]?[0-9]?)
+IP_BYTE (2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])
+IPV4_ADDR {IP_BYTE}\.{IP_BYTE}\.{IP_BYTE}\.{IP_BYTE}(:{PORT})?
+
+%%
+{WHITE_SPACE}          |
+{COMMENT}              {/* ignore */}
+
+\n                     {return (EOL);}
+"/"                    {return (SLASH);}
+"<"                    {return (OPENBRAC);}
+">"                    {return (CLOSEBRAC);}
+{BOOL_TRUE}            {yylval.boolean = 1; return (TRUE);}
+{BOOL_FALSE}           {yylval.boolean = 0; return (FALSE);}
+
+{IPV4_ADDR}            {yylval.string = yytext; return (UNQUOTED_STRING);}
+
+{NUMBER}               {yylval.number = strtod (yytext, NULL); return (NUMBER);}
+
+{QUOTED_STRING}                {yylval.string = yytext; return (QUOTED_STRING);}
+{UNQUOTED_STRING}      {yylval.string = yytext; return (UNQUOTED_STRING);}
+%%
index 019f952..7be594d 100644 (file)
@@ -4,8 +4,7 @@
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -24,8 +23,6 @@
 #include "common.h"
 #include "plugin.h"
 
-#define MODULE_NAME "load"
-
 #if defined(HAVE_GETLOADAVG) || defined(KERNEL_LINUX) || defined(HAVE_LIBSTATGRAB)
 # define LOAD_HAVE_READ 1
 #else
 #endif
 #endif /* defined(HAVE_GETLOADAVG) */
 
-static char *load_file = "load.rrd";
-
-static char *ds_def[] =
+static data_source_t dsrc[3] =
 {
-       "DS:shortterm:GAUGE:"COLLECTD_HEARTBEAT":0:100",
-       "DS:midterm:GAUGE:"COLLECTD_HEARTBEAT":0:100",
-       "DS:longterm:GAUGE:"COLLECTD_HEARTBEAT":0:100",
-       NULL
+       {"shortterm", DS_TYPE_GAUGE, 0.0, 100.0},
+       {"midterm",   DS_TYPE_GAUGE, 0.0, 100.0},
+       {"longterm",  DS_TYPE_GAUGE, 0.0, 100.0}
 };
-static int ds_num = 3;
-
-static void load_init (void)
-{
-       return;
-}
 
-static void load_write (char *host, char *inst, char *val)
+static data_set_t ds =
 {
-       rrd_update_file (host, load_file, val, ds_def, ds_num);
-}
+       "load", 3, dsrc
+};
 
 #if LOAD_HAVE_READ
-#define BUFSIZE 256
-static void load_submit (double snum, double mnum, double lnum)
+static void load_submit (gauge_t snum, gauge_t mnum, gauge_t lnum)
 {
-       char buf[BUFSIZE];
+       value_t values[3];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       if (snprintf (buf, BUFSIZE, "%u:%.2f:%.2f:%.2f", (unsigned int) curtime,
-                               snum, mnum, lnum) >= BUFSIZE)
-               return;
+       values[0].gauge = snum;
+       values[1].gauge = mnum;
+       values[2].gauge = lnum;
+
+       vl.values = values;
+       vl.values_len = STATIC_ARRAY_SIZE (values);
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "load");
 
-       plugin_submit (MODULE_NAME, "-", buf);
+       plugin_dispatch_values ("load", &vl);
 }
-#undef BUFSIZE
 
-static void load_read (void)
+static int load_read (void)
 {
 #if defined(HAVE_GETLOADAVG)
        double load[3];
@@ -87,11 +80,15 @@ static void load_read (void)
        if (getloadavg (load, 3) == 3)
                load_submit (load[LOADAVG_1MIN], load[LOADAVG_5MIN], load[LOADAVG_15MIN]);
        else
-               syslog (LOG_WARNING, "load: getloadavg failed: %s", strerror (errno));
+       {
+               char errbuf[1024];
+               WARNING ("load: getloadavg failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+       }
 /* #endif HAVE_GETLOADAVG */
 
 #elif defined(KERNEL_LINUX)
-       double snum, mnum, lnum;
+       gauge_t snum, mnum, lnum;
        FILE *loadavg;
        char buffer[16];
 
@@ -100,19 +97,27 @@ static void load_read (void)
        
        if ((loadavg = fopen ("/proc/loadavg", "r")) == NULL)
        {
-               syslog (LOG_WARNING, "load: fopen: %s", strerror (errno));
+               char errbuf[1024];
+               WARNING ("load: fopen: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                return;
        }
 
        if (fgets (buffer, 16, loadavg) == NULL)
        {
-               syslog (LOG_WARNING, "load: fgets: %s", strerror (errno));
+               char errbuf[1024];
+               WARNING ("load: fgets: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                fclose (loadavg);
                return;
        }
 
        if (fclose (loadavg))
-               syslog (LOG_WARNING, "load: fclose: %s", strerror (errno));
+       {
+               char errbuf[1024];
+               WARNING ("load: fclose: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+       }
 
        numfields = strsplit (buffer, fields, 8);
 
@@ -127,7 +132,7 @@ static void load_read (void)
 /* #endif KERNEL_LINUX */
 
 #elif defined(HAVE_LIBSTATGRAB)
-       double snum, mnum, lnum;
+       gauge_t snum, mnum, lnum;
        sg_load_stats *ls;
 
        if ((ls = sg_get_load_stats ()) == NULL)
@@ -139,14 +144,18 @@ static void load_read (void)
 
        load_submit (snum, mnum, lnum);
 #endif /* HAVE_LIBSTATGRAB */
+
+       return (0);
 }
-#else
-# define load_read NULL
 #endif /* LOAD_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, load_init, load_read, load_write);
-}
+       if (load & MR_DATASETS)
+               plugin_register_data_set (&ds);
 
-#undef MODULE_NAME
+#if LOAD_HAVE_READ
+       if (load & MR_READ)
+               plugin_register_read ("load", load_read);
+#endif
+} /* void module_register */
diff --git a/src/logfile.c b/src/logfile.c
new file mode 100644 (file)
index 0000000..5cb4091
--- /dev/null
@@ -0,0 +1,124 @@
+/**
+ * collectd - src/logfile.c
+ * Copyright (C) 2007  Sebastian Harl
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Sebastian Harl <sh at tokkee.org>
+ *   Florian Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#include <pthread.h>
+
+#if COLLECT_DEBUG
+static int log_level = LOG_DEBUG;
+#else
+static int log_level = LOG_INFO;
+#endif /* COLLECT_DEBUG */
+
+static pthread_mutex_t file_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static char *log_file = NULL;
+
+static const char *config_keys[] =
+{
+       "LogLevel",
+       "File"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static int logfile_config (const char *key, const char *value)
+{
+       if (0 == strcasecmp (key, "LogLevel")) {
+               if ((0 == strcasecmp (value, "emerg"))
+                               || (0 == strcasecmp (value, "alert"))
+                               || (0 == strcasecmp (value, "crit"))
+                               || (0 == strcasecmp (value, "err")))
+                       log_level = LOG_ERR;
+               else if (0 == strcasecmp (value, "warning"))
+                       log_level = LOG_WARNING;
+               else if (0 == strcasecmp (value, "notice"))
+                       log_level = LOG_NOTICE;
+               else if (0 == strcasecmp (value, "info"))
+                       log_level = LOG_INFO;
+#if COLLECT_DEBUG
+               else if (0 == strcasecmp (value, "debug"))
+                       log_level = LOG_DEBUG;
+#endif /* COLLECT_DEBUG */
+               else
+                       return 1;
+       }
+       else if (0 == strcasecmp (key, "File")) {
+               sfree (log_file);
+               log_file = strdup (value);
+       }
+       else {
+               return -1;
+       }
+       return 0;
+} /* int logfile_config (const char *, const char *) */
+
+static void logfile_log (int severity, const char *msg)
+{
+       FILE *fh;
+       int do_close = 0;
+
+       if (severity > log_level)
+               return;
+
+       pthread_mutex_lock (&file_lock);
+
+       if ((log_file == NULL) || (strcasecmp (log_file, "stderr") == 0))
+               fh = stderr;
+       else if (strcasecmp (log_file, "stdout") == 0)
+               fh = stdout;
+       else
+       {
+               fh = fopen (log_file, "a");
+               do_close = 1;
+       }
+
+       if (fh == NULL)
+       {
+                       char errbuf[1024];
+                       fprintf (stderr, "logfile plugin: fopen (%s) failed: %s\n",
+                                       (log_file == NULL) ? "<null>" : log_file,
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+       }
+       else
+       {
+               fprintf (fh, "%s\n", msg);
+               if (do_close != 0)
+                       fclose (fh);
+       }
+
+       pthread_mutex_unlock (&file_lock);
+
+       return;
+} /* void logfile_log (int, const char *) */
+
+void module_register (modreg_e load)
+{
+       plugin_register_config ("logfile", logfile_config,
+                       config_keys, config_keys_num);
+       plugin_register_log ("logfile", logfile_log);
+} /* void module_register (void) */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
+
index a9bf100..08c49fe 100644 (file)
 #include "common.h"
 #include "plugin.h"
 #include "configfile.h"
-#include "utils_debug.h"
 
-#define MODULE_NAME "mbmon"
-
-#include <netdb.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
+#if HAVE_NETDB_H && HAVE_SYS_SOCKET_H && HAVE_NETINET_IN_H && HAVE_NETINET_TCP_H
+# include <netdb.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <netinet/tcp.h>
+# define MBMON_HAVE_READ 1
+#else
+# define MBMON_HAVE_READ 0
+#endif
 
 #define MBMON_DEF_HOST "127.0.0.1"
 #define MBMON_DEF_PORT "411" /* the default for Debian */
 
-/* BUFFER_SIZE
-   Size of the buffer we use to receive from the mbmon daemon. */
-#define BUFFER_SIZE 1024
+static data_source_t data_source_fanspeed[1] =
+{
+       {"value", DS_TYPE_GAUGE, 0, NAN}
+};
 
-static char *filename_temperature = "mbmon/temperature-%s.rrd";
-static char *filename_fanspeed = "mbmon/fanspeed-%s.rrd";
-static char *filename_voltage = "mbmon/voltage-%s.rrd";
+static data_set_t fanspeed_ds =
+{
+       "fanspeed", 1, data_source_fanspeed
+};
 
-/* temperature and fan sensors */
-static char *ds_def[] =
+static data_source_t data_source_temperature[1] =
 {
-       "DS:value:GAUGE:"COLLECTD_HEARTBEAT":U:U",
-       NULL
+       {"value", DS_TYPE_GAUGE, -273.15, NAN}
 };
-static int ds_num = 1;
 
-/* voltage sensors */
-static char *voltage_ds_def[] = 
+static data_set_t temperature_ds =
 {
-       "DS:voltage:GAUGE:"COLLECTD_HEARTBEAT":U:U",
-       NULL
+       "temperature", 1, data_source_temperature
+};
+
+static data_source_t data_source_voltage[1] =
+{
+       {"voltage", DS_TYPE_GAUGE, NAN, NAN}
+};
+
+static data_set_t voltage_ds =
+{
+       "voltage", 1, data_source_voltage
 };
-static int voltage_ds_num = 1;
 
-static char *config_keys[] =
+static const char *config_keys[] =
 {
        "Host",
        "Port",
@@ -69,6 +77,7 @@ static char *config_keys[] =
 };
 static int config_keys_num = 2;
 
+#if MBMON_HAVE_READ
 static char *mbmon_host = NULL;
 static char *mbmon_port = NULL;
 
@@ -130,9 +139,12 @@ static int mbmon_query_daemon (char *buffer, int buffer_size)
 
        if ((ai_return = getaddrinfo (host, port, &ai_hints, &ai_list)) != 0)
        {
-               syslog (LOG_ERR, "mbmon: getaddrinfo (%s, %s): %s",
+               char errbuf[1024];
+               ERROR ("mbmon: getaddrinfo (%s, %s): %s",
                                host, port,
-                               ai_return == EAI_SYSTEM ? strerror (errno) : gai_strerror (ai_return));
+                               (ai_return == EAI_SYSTEM)
+                               ? sstrerror (errno, errbuf, sizeof (errbuf))
+                               : gai_strerror (ai_return));
                return (-1);
        }
 
@@ -142,16 +154,20 @@ static int mbmon_query_daemon (char *buffer, int buffer_size)
                /* create our socket descriptor */
                if ((fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol)) < 0)
                {
-                       syslog (LOG_ERR, "mbmon: socket: %s",
-                                       strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("mbmon: socket: %s",
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        continue;
                }
 
                /* connect to the mbmon daemon */
                if (connect (fd, (struct sockaddr *) ai_ptr->ai_addr, ai_ptr->ai_addrlen))
                {
-                       DBG ("mbmon: connect (%s, %s): %s", host, port,
-                                       strerror (errno));
+                       char errbuf[1024];
+                       DEBUG ("mbmon: connect (%s, %s): %s", host, port,
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        close (fd);
                        fd = -1;
                        continue;
@@ -166,7 +182,7 @@ static int mbmon_query_daemon (char *buffer, int buffer_size)
 
        if (fd < 0)
        {
-               syslog (LOG_ERR, "mbmon: Could not connect to daemon.");
+               ERROR ("mbmon: Could not connect to daemon.");
                return (-1);
        }
 
@@ -178,11 +194,14 @@ static int mbmon_query_daemon (char *buffer, int buffer_size)
        {
                if (status == -1)
                {
+                       char errbuf[1024];
+
                        if ((errno == EAGAIN) || (errno == EINTR))
                                continue;
 
-                       syslog (LOG_ERR, "mbmon: Error reading from socket: %s",
-                                               strerror (errno));
+                       ERROR ("mbmon: Error reading from socket: %s",
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        close (fd);
                        return (-1);
                }
@@ -195,11 +214,11 @@ static int mbmon_query_daemon (char *buffer, int buffer_size)
        if (buffer_fill >= buffer_size)
        {
                buffer[buffer_size - 1] = '\0';
-               syslog (LOG_WARNING, "mbmon: Message from mbmon has been truncated.");
+               WARNING ("mbmon: Message from mbmon has been truncated.");
        }
        else if (buffer_fill == 0)
        {
-               syslog (LOG_WARNING, "mbmon: Peer has unexpectedly shut down the socket. "
+               WARNING ("mbmon: Peer has unexpectedly shut down the socket. "
                                "Buffer: `%s'", buffer);
                close (fd);
                return (-1);
@@ -209,7 +228,7 @@ static int mbmon_query_daemon (char *buffer, int buffer_size)
        return (0);
 }
 
-static int mbmon_config (char *key, char *value)
+static int mbmon_config (const char *key, const char *value)
 {
        if (strcasecmp (key, "host") == 0)
        {
@@ -231,60 +250,23 @@ static int mbmon_config (char *key, char *value)
        return (0);
 }
 
-static void mbmon_init (void)
-{
-       return;
-}
-
-static void mbmon_write_temperature (char *host, char *inst, char *val)
+static void mbmon_submit (const char *type, const char *type_instance,
+               double value)
 {
-       char filename[BUFFER_SIZE];
-       int status;
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       /* construct filename */
-       status = snprintf (filename, BUFFER_SIZE, filename_temperature, inst);
-       if ((status < 1) || (status >= BUFFER_SIZE))
-               return;
+       values[0].gauge = value;
 
-       rrd_update_file (host, filename, val, ds_def, ds_num);
-}
-
-static void mbmon_write_fanspeed (char *host, char *inst, char *val)
-{
-       char filename[BUFFER_SIZE];
-       int status;
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "mbmon");
+       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       /* construct filename */
-       status = snprintf (filename, BUFFER_SIZE, filename_fanspeed, inst);
-       if ((status < 1) || (status >= BUFFER_SIZE))
-               return;
-
-       rrd_update_file (host, filename, val, ds_def, ds_num);
-}
-
-static void mbmon_write_voltage (char *host, char *inst, char *val)
-{
-       char filename[BUFFER_SIZE];
-       int status;
-
-       /* construct filename */
-       status = snprintf (filename, BUFFER_SIZE, filename_voltage, inst);
-       if ((status < 1) || (status >= BUFFER_SIZE))
-               return;
-
-       rrd_update_file (host, filename, val, voltage_ds_def, voltage_ds_num);
-}
-
-static void mbmon_submit (char *type, char *inst, double value)
-{
-       char buf[BUFFER_SIZE];
-
-       if (snprintf (buf, BUFFER_SIZE, "%u:%.3f", (unsigned int) curtime, value)
-            >= BUFFER_SIZE)
-               return;
-
-       plugin_submit (type, inst, buf);
-}
+       plugin_dispatch_values (type, &vl);
+} /* void mbmon_submit */
 
 /* Trim trailing whitespace from a string. */
 static void trim_spaces (char *s)
@@ -295,40 +277,14 @@ static void trim_spaces (char *s)
                s[l] = '\0';
 }
 
-static void mbmon_read (void)
+static int mbmon_read (void)
 {
-       char buf[BUFFER_SIZE];
+       char buf[1024];
        char *s, *t;
 
-       static int wait_time = 1;
-       static int wait_left = 0;
-
-       if (wait_left >= 10)
-       {
-               wait_left -= 10;
-               return;
-       }
-
        /* get data from daemon */
-       if (mbmon_query_daemon (buf, BUFFER_SIZE) < 0)
-       {
-               /* This limit is reached in log2(86400) =~ 17 steps. Since
-                * there is a 2^n seconds wait between each step it will need
-                * roughly one day to reach this limit. -octo */
-               
-               wait_time *= 2;
-               if (wait_time > 86400)
-                       wait_time = 86400;
-
-               wait_left = wait_time;
-
-               return;
-       }
-       else
-       {
-               wait_time = 1;
-               wait_left = 0;
-       }
+       if (mbmon_query_daemon (buf, sizeof (buf)) < 0)
+               return (-1);
 
        s = buf;
        while ((t = strchr (s, ':')) != NULL)
@@ -345,24 +301,24 @@ static void mbmon_read (void)
                value = strtod (t, &nextc);
                if ((*nextc != '\n') && (*nextc != '\0'))
                {
-                       syslog (LOG_ERR, "mbmon: value for `%s' contains invalid characters: `%s'", s, t);
+                       ERROR ("mbmon: value for `%s' contains invalid characters: `%s'", s, t);
                        break;
                }
 
                if (strncmp (s, "TEMP", 4) == 0)
                {
                        inst = s + 4;
-                       type = "mbmon_temperature";
+                       type = "temperature";
                }
                else if (strncmp (s, "FAN", 3) == 0)
                {
                        inst = s + 3;
-                       type = "mbmon_fanspeed";
+                       type = "fanspeed";
                }
                else if (strncmp (s, "V", 1) == 0)
                {
                        inst = s + 1;
-                       type = "mbmon_voltage";
+                       type = "voltage";
                }
                else
                {
@@ -376,17 +332,27 @@ static void mbmon_read (void)
 
                s = nextc + 1;
        }
+
+       return (0);
 } /* void mbmon_read */
+#endif /* MBMON_HAVE_READ */
 
 /* module_register
    Register collectd plugin. */
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, mbmon_init, mbmon_read, NULL);
-       plugin_register ("mbmon_temperature", NULL, NULL, mbmon_write_temperature);
-       plugin_register ("mbmon_fanspeed", NULL, NULL, mbmon_write_fanspeed);
-       plugin_register ("mbmon_voltage", NULL, NULL, mbmon_write_voltage);
-       cf_register (MODULE_NAME, mbmon_config, config_keys, config_keys_num);
-}
+       if (load & MR_DATASETS)
+       {
+               plugin_register_data_set (&fanspeed_ds);
+               plugin_register_data_set (&temperature_ds);
+               plugin_register_data_set (&voltage_ds);
+       }
 
-#undef MODULE_NAME
+#if MBMON_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_config ("mbmon", mbmon_config, config_keys, config_keys_num);
+               plugin_register_read ("mbmon", mbmon_read);
+       }
+#endif /* MBMON_HAVE_READ */
+} /* void module_register */
index b8b7229..2187720 100644 (file)
@@ -1,11 +1,10 @@
 /**
  * collectd - src/memory.c
- * Copyright (C) 2005,2006  Florian octo Forster
+ * Copyright (C) 2005-2007  Florian octo Forster
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -23,7 +22,6 @@
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
-#include "utils_debug.h"
 
 #ifdef HAVE_SYS_SYSCTL_H
 # include <sys/sysctl.h>
 # define MEMORY_HAVE_READ 0
 #endif
 
-#define MODULE_NAME "memory"
-
-static char *memory_file = "memory.rrd";
+/* 2^48 = 281474976710656 */
+static data_source_t dsrc[4] =
+{
+       {"used",    DS_TYPE_GAUGE, 0, 281474976710656.0},
+       {"free",    DS_TYPE_GAUGE, 0, 281474976710656.0},
+       {"buffers", DS_TYPE_GAUGE, 0, 281474976710656.0},
+       {"cached",  DS_TYPE_GAUGE, 0, 281474976710656.0}
+};
 
-/* 9223372036854775807 == LLONG_MAX */
-static char *ds_def[] =
+static data_set_t ds =
 {
-       "DS:used:GAUGE:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:free:GAUGE:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:buffers:GAUGE:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:cached:GAUGE:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       NULL
+       "memory", 4, dsrc
 };
-static int ds_num = 4;
 
 /* vm_statistics_data_t */
 #if defined(HOST_VM_INFO)
@@ -85,7 +82,8 @@ static int pagesize;
 static kstat_t *ksp;
 #endif /* HAVE_LIBKSTAT */
 
-static void memory_init (void)
+#if MEMORY_HAVE_READ
+static int memory_init (void)
 {
 #if defined(HOST_VM_INFO)
        port_host = mach_host_self ();
@@ -107,31 +105,30 @@ static void memory_init (void)
                ksp = NULL;
 #endif /* HAVE_LIBKSTAT */
 
-       return;
-}
-
-static void memory_write (char *host, char *inst, char *val)
-{
-       rrd_update_file (host, memory_file, val, ds_def, ds_num);
-}
+       return (0);
+} /* int memory_init */
 
-#if MEMORY_HAVE_READ
-#define BUFSIZE 512
 static void memory_submit (long long mem_used, long long mem_buffered,
                long long mem_cached, long long mem_free)
 {
-       char buf[BUFSIZE];
+       value_t values[4];
+       value_list_t vl = VALUE_LIST_INIT;
+
+       values[0].gauge = mem_used;
+       values[1].gauge = mem_free;
+       values[2].gauge = mem_buffered;
+       values[3].gauge = mem_cached;
 
-       if (snprintf (buf, BUFSIZE, "%u:%lli:%lli:%lli:%lli",
-                               (unsigned int) curtime, mem_used, mem_free,
-                               mem_buffered, mem_cached) >= BUFSIZE)
-               return;
+       vl.values = values;
+       vl.values_len = 4;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "memory");
 
-       plugin_submit (MODULE_NAME, "-", buf);
+       plugin_dispatch_values ("memory", &vl);
 }
-#undef BUFSIZE
 
-static void memory_read (void)
+static int memory_read (void)
 {
 #if defined(HOST_VM_INFO)
        kern_return_t status;
@@ -144,15 +141,15 @@ static void memory_read (void)
        long long free;
 
        if (!port_host || !pagesize)
-               return;
+               return (-1);
 
        vm_data_len = sizeof (vm_data) / sizeof (natural_t);
        if ((status = host_statistics (port_host, HOST_VM_INFO,
                                        (host_info_t) &vm_data,
                                        &vm_data_len)) != KERN_SUCCESS)
        {
-               syslog (LOG_ERR, "memory-plugin: host_statistics failed and returned the value %i", (int) status);
-               return;
+               ERROR ("memory-plugin: host_statistics failed and returned the value %i", (int) status);
+               return (-1);
        }
 
        /*
@@ -217,11 +214,14 @@ static void memory_read (void)
                                                (void *) &sysctl_vals[i], &len,
                                                NULL, 0)) < 0)
                {
-                       syslog (LOG_ERR, "memory plugin: sysctlbyname (%s): %s",
-                                       sysctl_keys[i], strerror (errno));
-                       return;
+                       char errbuf[1024];
+                       ERROR ("memory plugin: sysctlbyname (%s): %s",
+                                       sysctl_keys[i],
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
+                       return (-1);
                }
-               DBG ("%26s: %6i", sysctl_keys[i], sysctl_vals[i]);
+               DEBUG ("%26s: %6i", sysctl_keys[i], sysctl_vals[i]);
        } /* for i */
 
        /* multiply all all page counts with the pagesize */
@@ -248,8 +248,10 @@ static void memory_read (void)
 
        if ((fh = fopen ("/proc/meminfo", "r")) == NULL)
        {
-               syslog (LOG_WARNING, "memory: fopen: %s", strerror (errno));
-               return;
+               char errbuf[1024];
+               WARNING ("memory: fopen: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
        }
 
        while (fgets (buffer, 1024, fh) != NULL)
@@ -276,7 +278,11 @@ static void memory_read (void)
        }
 
        if (fclose (fh))
-               syslog (LOG_WARNING, "memory: fclose: %s", strerror (errno));
+       {
+               char errbuf[1024];
+               WARNING ("memory: fclose: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+       }
 
        if (mem_used >= (mem_free + mem_buffered + mem_cached))
        {
@@ -291,16 +297,16 @@ static void memory_read (void)
        long long mem_lock;
 
        if (ksp == NULL)
-               return;
+               return (-1);
 
        mem_used = get_kstat_value (ksp, "pagestotal");
        mem_free = get_kstat_value (ksp, "pagesfree");
        mem_lock = get_kstat_value (ksp, "pageslocked");
 
        if ((mem_used < 0LL) || (mem_free < 0LL) || (mem_lock < 0LL))
-               return;
+               return (-1);
        if (mem_used < (mem_free + mem_lock))
-               return;
+               return (-1);
 
        mem_used -= mem_free + mem_lock;
        mem_used *= pagesize; /* If this overflows you have some serious */
@@ -316,14 +322,21 @@ static void memory_read (void)
        if ((ios = sg_get_mem_stats ()) != NULL)
                memory_submit (ios->used, 0LL, ios->cache, ios->free);
 #endif /* HAVE_LIBSTATGRAB */
+
+       return (0);
 }
-#else
-# define memory_read NULL
 #endif /* MEMORY_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, memory_init, memory_read, memory_write);
-}
+       if (load & MR_DATASETS)
+               plugin_register_data_set (&ds);
 
-#undef MODULE_NAME
+#if MEMORY_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_init ("memory", memory_init);
+               plugin_register_read ("memory", memory_read);
+       }
+#endif /* MEMORY_HAVE_READ */
+} /* void module_register */
index 46438bf..02abfc8 100644 (file)
  *   Peter Holik <peter at holik.at>
  *
  * Used multimeter: Metex M-4650CR
- *
  **/
 
-#include <termios.h>
-#include <sys/ioctl.h>
-#include <math.h>
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
 
-#define MODULE_NAME "multimeter"
-
-static char *multimeter_file = "multimeter.rrd";
+#if HAVE_TERMIOS_H && HAVE_SYS_IOCTL_H && HAVE_MATH_H
+# include <termios.h>
+# include <sys/ioctl.h>
+# include <math.h>
+# define MULTIMETER_HAVE_READ 1
+#else
+# define MULTIMETER_HAVE_READ 0
+# error "multimeter cannot read!"
+#endif
+
+static data_source_t data_source[1] =
+{
+       {"value", DS_TYPE_GAUGE, NAN, NAN}
+};
 
-static char *ds_def[] =
+static data_set_t data_set =
 {
-       "DS:value:GAUGE:"COLLECTD_HEARTBEAT":U:U",
-       NULL
+       "multimeter", 1, data_source
 };
-static int ds_num = 1;
 
+#if MULTIMETER_HAVE_READ
 static int fd = -1;
 
 static int multimeter_timeval_sub (struct timeval *tv1, struct timeval *tv2,
@@ -75,8 +81,10 @@ static int multimeter_read_value(double *value)
 
                if (gettimeofday (&time_end, NULL) < 0)
                {
-                       syslog (LOG_ERR, MODULE_NAME": gettimeofday failed: %s",
-                                strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("multimeter plugin: gettimeofday failed: %s",
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        return (-1);
                }
                time_end.tv_sec++;      
@@ -97,8 +105,11 @@ static int multimeter_read_value(double *value)
 
                        if (gettimeofday (&time_now, NULL) < 0)
                        {
-                               syslog (LOG_ERR, MODULE_NAME": gettimeofday failed: %s",
-                                        strerror (errno));
+                               char errbuf[1024];
+                               ERROR ("multimeter plugin: "
+                                               "gettimeofday failed: %s",
+                                               sstrerror (errno, errbuf,
+                                                       sizeof (errbuf)));
                                return (-1);
                        }
                        if (multimeter_timeval_sub (&time_end, &time_now, &timeout) == -1)
@@ -150,17 +161,19 @@ static int multimeter_read_value(double *value)
                        }
                        else /* status == -1 */
                        {
-                               syslog (LOG_ERR, MODULE_NAME": select failed: %s",
-                                        strerror (errno));
+                               char errbuf[1024];
+                               ERROR ("multimeter plugin: "
+                                               "select failed: %s",
+                                               sstrerror (errno, errbuf, sizeof (errbuf)));
                                break;
                        }
                }
        } while (--retry);
 
        return (-2);  /* no value received */
-}
+} /* int multimeter_read_value */
 
-static void multimeter_init (void)
+static int multimeter_init (void)
 {
        int i;
        char device[] = "/dev/ttyS ";
@@ -186,49 +199,78 @@ static void multimeter_init (void)
                        tcsetattr(fd, TCSANOW, &tios);
                        ioctl(fd, TIOCMBIC, &rts);
                        
-                       if (multimeter_read_value(&value) < -1)
+                       if (multimeter_read_value (&value) < -1)
                        {
-                               close(fd);
+                               close (fd);
                                fd = -1;
                        }
                        else
                        {
-                               syslog (LOG_INFO, MODULE_NAME" found (%s)", device);
-                               return;
+                               INFO ("multimeter plugin: Device "
+                                               "found at %s", device);
+                               return (0);
                        }
                }
        }
-       syslog (LOG_ERR, MODULE_NAME" not found");
+
+       ERROR ("multimeter plugin: No device found");
+       return (-1);
 }
 #undef LINE_LENGTH
 
-static void multimeter_write (char *host, char *inst, char *val)
+static void multimeter_submit (double value)
 {
-       rrd_update_file (host, multimeter_file, val, ds_def, ds_num);
-}
-#define BUFSIZE 128
-static void multimeter_submit (double *value)
-{
-       char buf[BUFSIZE];
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
+
+       values[0].gauge = value;
 
-       if (snprintf (buf, BUFSIZE, "%u:%f", (unsigned int) curtime, *value) >= BUFSIZE)
-               return;
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "multimeter");
 
-       plugin_submit (MODULE_NAME, "-", buf);
+       plugin_dispatch_values ("multimeter", &vl);
 }
-#undef BUFSIZE
 
-static void multimeter_read (void)
+static int multimeter_read (void)
 {
        double value;
 
-       if (fd > -1 && !(multimeter_read_value(&value)))
-               multimeter_submit (&value);
-}
+       if (fd < 0)
+               return (-1);
+
+       if (multimeter_read_value (&value) != 0)
+               return (-1);
 
-void module_register (void)
+       multimeter_submit (value);
+       return (0);
+} /* int multimeter_read */
+
+static int multimeter_shutdown (void)
 {
-       plugin_register (MODULE_NAME, multimeter_init, multimeter_read, multimeter_write);
+       if (fd >= 0)
+       {
+               close (fd);
+               fd = -1;
+       }
+
+       return (0);
 }
+#endif /* MULTIMETER_HAVE_READ */
+
+void module_register (modreg_e load)
+{
+       if (load & MR_DATASETS)
+               plugin_register_data_set (&data_set);
 
-#undef MODULE_NAME
+#if MULTIMETER_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_init ("multimeter", multimeter_init);
+               plugin_register_read ("multimeter", multimeter_read);
+               plugin_register_shutdown ("multimeter", multimeter_shutdown);
+       }
+#endif /* MULTIMETER_HAVE_READ */
+} /* void module_register */
index caebdf3..5fbe5a6 100644 (file)
@@ -1,11 +1,10 @@
 /**
  * collectd - src/mysql.c
- * Copyright (C) 2006  Florian octo Forster
+ * Copyright (C) 2006,2007  Florian octo Forster
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
 #include <mysql/mysql.h>
 #endif
 
-#define MODULE_NAME "mysql"
-
 #if COLLECT_LIBMYSQL
 # define MYSQL_HAVE_READ 1
 #else
 # define MYSQL_HAVE_READ 0
 #endif
 
-#define BUFSIZE 512
+/* TODO: Understand `Select_*' and possibly do that stuff as well.. */
 
-static char *host = "localhost";
-static char *user;
-static char *pass;
-static char *db = NULL;
+static data_source_t data_source_counter[1] =
+{
+       {"value", DS_TYPE_COUNTER, 0, NAN}
+};
 
-/* TODO
- * understand `Select_*' and possibly do that stuff as well..
- */
+static data_set_t ds_commands =
+{
+       "mysql_commands", 1, data_source_counter
+};
 
-static char *commands_file = "mysql/mysql_commands-%s.rrd";
-static char *handler_file  = "mysql/mysql_handler-%s.rrd";
-static char *qcache_file   = "mysql/mysql_qcache.rrd";
-static char *threads_file  = "mysql/mysql_threads.rrd";
-static char *traffic_file  = "traffic-mysql.rrd";
+static data_set_t ds_handler =
+{
+       "mysql_handler", 1, data_source_counter
+};
 
-static char *commands_ds_def[] =
+static data_source_t data_source_qcache[5] =
 {
-       "DS:value:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       NULL
+       {"hits",             DS_TYPE_COUNTER, 0, NAN},
+       {"inserts",          DS_TYPE_COUNTER, 0, NAN},
+       {"not_cached",       DS_TYPE_COUNTER, 0, NAN},
+       {"lowmem_prunes",    DS_TYPE_COUNTER, 0, NAN},
+       {"queries_in_cache", DS_TYPE_GAUGE,   0, NAN}
 };
-static int commands_ds_num = 1;
 
-static char *handler_ds_def[] =
+static data_set_t ds_qcache =
 {
-       "DS:value:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       NULL
+       "mysql_qcache", 5, data_source_qcache
 };
-static int handler_ds_num = 1;
 
-static char *qcache_ds_def[] =
+static data_source_t data_source_threads[4] =
 {
-       "DS:hits:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:inserts:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:not_cached:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:lowmem_prunes:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:queries_in_cache:GAUGE:"COLLECTD_HEARTBEAT":0:U",
-       NULL
+       {"running",   DS_TYPE_GAUGE,   0, NAN},
+       {"connected", DS_TYPE_GAUGE,   0, NAN},
+       {"cached",    DS_TYPE_GAUGE,   0, NAN},
+       {"created",   DS_TYPE_COUNTER, 0, NAN}
 };
-static int qcache_ds_num = 5;
 
-static char *threads_ds_def[] =
+static data_set_t ds_threads =
 {
-       "DS:running:GAUGE:"COLLECTD_HEARTBEAT":0:U",
-       "DS:connected:GAUGE:"COLLECTD_HEARTBEAT":0:U",
-       "DS:cached:GAUGE:"COLLECTD_HEARTBEAT":0:U",
-       "DS:created:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       NULL
+       "mysql_threads", 4, data_source_threads
 };
-static int threads_ds_num = 4;
 
-static char *traffic_ds_def[] =
+static data_source_t data_source_octets[2] =
 {
-       "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       NULL
+       {"rx", DS_TYPE_COUNTER, 0, 4294967295.0},
+       {"tx", DS_TYPE_COUNTER, 0, 4294967295.0}
+};
+
+static data_set_t ds_octets =
+{
+       "mysql_octets", 2, data_source_octets
 };
-static int traffic_ds_num = 2;
 
-static char *config_keys[] =
+#if MYSQL_HAVE_READ
+static const char *config_keys[] =
 {
        "Host",
        "User",
@@ -107,7 +100,11 @@ static char *config_keys[] =
 };
 static int config_keys_num = 4;
 
-#if MYSQL_HAVE_READ
+static char *host = "localhost";
+static char *user;
+static char *pass;
+static char *db = NULL;
+
 static MYSQL *getconnection (void)
 {
        static MYSQL *con;
@@ -116,14 +113,12 @@ static MYSQL *getconnection (void)
        static int wait_for = 0;
        static int wait_increase = 60;
 
-       int step;
-
        if (state != 0)
        {
                int err;
                if ((err = mysql_ping (con)) != 0)
                {
-                       syslog (LOG_WARNING, "mysql_ping failed: %s", mysql_error (con));
+                       WARNING ("mysql_ping failed: %s", mysql_error (con));
                        state = 0;
                }
                else
@@ -133,11 +128,9 @@ static MYSQL *getconnection (void)
                }
        }
 
-       step = atoi (COLLECTD_STEP);
-
        if (wait_for > 0)
        {
-               wait_for -= step;
+               wait_for -= interval_g;
                return (NULL);
        }
 
@@ -148,14 +141,14 @@ static MYSQL *getconnection (void)
 
        if ((con = mysql_init (con)) == NULL)
        {
-               syslog (LOG_ERR, "mysql_init failed: %s", mysql_error (con));
+               ERROR ("mysql_init failed: %s", mysql_error (con));
                state = 0;
                return (NULL);
        }
 
        if (mysql_real_connect (con, host, user, pass, db, 0, NULL, 0) == NULL)
        {
-               syslog (LOG_ERR, "mysql_real_connect failed: %s", mysql_error (con));
+               ERROR ("mysql_real_connect failed: %s", mysql_error (con));
                state = 0;
                return (NULL);
        }
@@ -167,14 +160,8 @@ static MYSQL *getconnection (void)
                return (con);
        }
 } /* static MYSQL *getconnection (void) */
-#endif /* MYSQL_HAVE_READ */
-
-static void init (void)
-{
-       return;
-}
 
-static int config (char *key, char *value)
+static int config (const char *key, const char *value)
 {
        if (strcasecmp (key, "host") == 0)
                return ((host = strdup (value)) == NULL ? 1 : 0);
@@ -188,160 +175,84 @@ static int config (char *key, char *value)
                return (-1);
 }
 
-static void commands_write (char *host, char *inst, char *val)
-{
-       char buf[BUFSIZE];
-
-       if (snprintf (buf, BUFSIZE, commands_file, inst) >= BUFSIZE)
-               return;
-
-       rrd_update_file (host, buf, val, commands_ds_def, commands_ds_num);
-}
-
-static void handler_write (char *host, char *inst, char *val)
-{
-       char buf[BUFSIZE];
-
-       if (snprintf (buf, BUFSIZE, handler_file, inst) >= BUFSIZE)
-               return;
-
-       rrd_update_file (host, buf, val, handler_ds_def, handler_ds_num);
-}
-
-static void qcache_write (char *host, char *inst, char *val)
-{
-       rrd_update_file (host, qcache_file, val,
-                       qcache_ds_def, qcache_ds_num);
-}
-
-static void threads_write (char *host, char *inst, char *val)
-{
-       rrd_update_file (host, threads_file, val,
-                       threads_ds_def, threads_ds_num);
-}
-
-static void traffic_write (char *host, char *inst, char *val)
-{
-       rrd_update_file (host, traffic_file, val,
-                       traffic_ds_def, traffic_ds_num);
-}
-
-#if MYSQL_HAVE_READ
-static void commands_submit (char *inst, unsigned long long value)
+static void counter_submit (const char *type, const char *type_instance,
+               counter_t value)
 {
-       char buf[BUFSIZE];
-       int  status;
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       status = snprintf (buf, BUFSIZE, "%u:%llu", (unsigned int) curtime, value);
+       values[0].counter = value;
 
-       if (status < 0)
-       {
-               syslog (LOG_ERR, "snprintf failed");
-               return;
-       }
-       else if (status >= BUFSIZE)
-       {
-               syslog (LOG_WARNING, "snprintf was truncated");
-               return;
-       }
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "mysql");
+       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       plugin_submit ("mysql_commands", inst, buf);
-}
+       plugin_dispatch_values (type, &vl);
+} /* void counter_submit */
 
-static void handler_submit (char *inst, unsigned long long value)
+static void qcache_submit (counter_t hits, counter_t inserts,
+               counter_t not_cached, counter_t lowmem_prunes,
+               gauge_t queries_in_cache)
 {
-       char buf[BUFSIZE];
-       int  status;
-
-       status = snprintf (buf, BUFSIZE, "%u:%llu", (unsigned int) curtime, value);
-
-       if (status < 0)
-       {
-               syslog (LOG_ERR, "snprintf failed");
-               return;
-       }
-       else if (status >= BUFSIZE)
-       {
-               syslog (LOG_WARNING, "snprintf was truncated");
-               return;
-       }
-
-       plugin_submit ("mysql_handler", inst, buf);
-}
-
-static void qcache_submit (unsigned long long hits, unsigned long long inserts,
-               unsigned long long not_cached, unsigned long long lowmem_prunes,
-               int queries_in_cache)
+       value_t values[5];
+       value_list_t vl = VALUE_LIST_INIT;
+
+       values[0].counter = hits;
+       values[1].counter = inserts;
+       values[2].counter = not_cached;
+       values[3].counter = lowmem_prunes;
+       values[4].gauge   = queries_in_cache;
+
+       vl.values = values;
+       vl.values_len = 5;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "mysql");
+
+       plugin_dispatch_values ("mysql_qcache", &vl);
+} /* void qcache_submit */
+
+static void threads_submit (gauge_t running, gauge_t connected, gauge_t cached,
+               counter_t created)
 {
-       char buf[BUFSIZE];
-       int  status;
+       value_t values[4];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       status = snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%i",
-                       (unsigned int) curtime, hits, inserts, not_cached,
-                       lowmem_prunes, queries_in_cache);
+       values[0].gauge   = running;
+       values[1].gauge   = connected;
+       values[2].gauge   = cached;
+       values[3].counter = created;
 
-       if (status < 0)
-       {
-               syslog (LOG_ERR, "snprintf failed");
-               return;
-       }
-       else if (status >= BUFSIZE)
-       {
-               syslog (LOG_WARNING, "snprintf was truncated");
-               return;
-       }
+       vl.values = values;
+       vl.values_len = 4;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "mysql");
 
-       plugin_submit ("mysql_qcache", "-", buf);
-}
+       plugin_dispatch_values ("mysql_threads", &vl);
+} /* void threads_submit */
 
-static void threads_submit (int running, int connected, int cached,
-               unsigned long long created)
+static void traffic_submit (counter_t rx, counter_t tx)
 {
-       char buf[BUFSIZE];
-       int  status;
+       value_t values[2];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       status = snprintf (buf, BUFSIZE, "%u:%i:%i:%i:%llu",
-                       (unsigned int) curtime,
-                       running, connected, cached, created);
+       values[0].counter = rx;
+       values[1].counter = tx;
 
-       if (status < 0)
-       {
-               syslog (LOG_ERR, "snprintf failed");
-               return;
-       }
-       else if (status >= BUFSIZE)
-       {
-               syslog (LOG_WARNING, "snprintf was truncated");
-               return;
-       }
-
-       plugin_submit ("mysql_threads", "-", buf);
-}
-
-static void traffic_submit (unsigned long long incoming,
-               unsigned long long outgoing)
-{
-       char buf[BUFSIZE];
-       int  status;
-
-       status = snprintf (buf, BUFSIZE, "%u:%llu:%llu", (unsigned int) curtime,
-                       incoming, outgoing);
+       vl.values = values;
+       vl.values_len = 2;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "mysql");
 
-       if (status < 0)
-       {
-               syslog (LOG_ERR, "snprintf failed");
-               return;
-       }
-       else if (status >= BUFSIZE)
-       {
-               syslog (LOG_WARNING, "snprintf was truncated");
-               return;
-       }
-
-       plugin_submit ("mysql_traffic", "-", buf);
-}
+       plugin_dispatch_values ("mysql_octets", &vl);
+} /* void traffic_submit */
 
-static void mysql_read (void)
+static int mysql_read (void)
 {
        MYSQL     *con;
        MYSQL_RES *res;
@@ -366,7 +277,7 @@ static void mysql_read (void)
 
        /* An error message will have been printed in this case */
        if ((con = getconnection ()) == NULL)
-               return;
+               return (-1);
 
        query = "SHOW STATUS";
        if (mysql_get_server_version (con) >= 50002)
@@ -376,16 +287,16 @@ static void mysql_read (void)
 
        if (mysql_real_query (con, query, query_len))
        {
-               syslog (LOG_ERR, "mysql_real_query failed: %s\n",
+               ERROR ("mysql_real_query failed: %s\n",
                                mysql_error (con));
-               return;
+               return (-1);
        }
 
        if ((res = mysql_store_result (con)) == NULL)
        {
-               syslog (LOG_ERR, "mysql_store_result failed: %s\n",
+               ERROR ("mysql_store_result failed: %s\n",
                                mysql_error (con));
-               return;
+               return (-1);
        }
 
        field_num = mysql_num_fields (res);
@@ -404,14 +315,14 @@ static void mysql_read (void)
 
                        /* Ignore `prepared statements' */
                        if (strncmp (key, "Com_stmt_", 9) != 0)
-                               commands_submit (key + 4, val);
+                               counter_submit ("mysql_commands", key + 4, val);
                }
                else if (strncmp (key, "Handler_", 8) == 0)
                {
                        if (val == 0ULL)
                                continue;
 
-                       handler_submit (key + 8, val);
+                       counter_submit ("mysql_handler", key + 8, val);
                }
                else if (strncmp (key, "Qcache_", 7) == 0)
                {
@@ -462,22 +373,26 @@ static void mysql_read (void)
 
        /* mysql_close (con); */
 
-       return;
-}
-#else
-# define mysql_read NULL
+       return (0);
+} /* int mysql_read */
 #endif /* MYSQL_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, init, mysql_read, NULL);
-       plugin_register ("mysql_commands", NULL, NULL, commands_write);
-       plugin_register ("mysql_handler",  NULL, NULL, handler_write);
-       plugin_register ("mysql_qcache",   NULL, NULL, qcache_write);
-       plugin_register ("mysql_threads",  NULL, NULL, threads_write);
-       plugin_register ("mysql_traffic",  NULL, NULL, traffic_write);
-       cf_register (MODULE_NAME, config, config_keys, config_keys_num);
-}
+       if (load & MR_DATASETS)
+       {
+               plugin_register_data_set (&ds_commands);
+               plugin_register_data_set (&ds_handler);
+               plugin_register_data_set (&ds_qcache);
+               plugin_register_data_set (&ds_threads);
+               plugin_register_data_set (&ds_octets);
+       }
 
-#undef BUFSIZE
-#undef MODULE_NAME
+#if MYSQL_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_config ("mysql", config, config_keys, config_keys_num);
+               plugin_register_read ("mysql", mysql_read);
+       }
+#endif /* MYSQL_HAVE_READ */
+} /* void module_register */
index e9ba84b..4b50ce2 100644 (file)
@@ -1,11 +1,10 @@
 /**
  * collectd - src/network.c
- * Copyright (C) 2005,2006  Florian octo Forster
+ * Copyright (C) 2005-2007  Florian octo Forster
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  *   Florian octo Forster <octo at verplant.org>
  **/
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <syslog.h>
-#include <errno.h>
-
-#include "network.h"
+#include "collectd.h"
+#include "plugin.h"
 #include "common.h"
 #include "configfile.h"
-#include "utils_debug.h"
+#include "utils_avltree.h"
+
+#include "network.h"
+
+#if HAVE_PTHREAD_H
+# include <pthread.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#if HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+#if HAVE_POLL_H
+# include <poll.h>
+#endif
 
 /* 1500 - 40 - 8  =  Ethernet packet - IPv6 header - UDP header */
 /* #define BUFF_SIZE 1452 */
 # endif
 #endif /* !IP_ADD_MEMBERSHIP */
 
-#define BUFF_SIZE 4096
-
-extern int operating_mode;
+#define BUFF_SIZE 1024
 
+/*
+ * Private data types
+ */
 typedef struct sockent
 {
        int                      fd;
-       int                      mode;
        struct sockaddr_storage *addr;
        socklen_t                addrlen;
        struct sockent          *next;
 } sockent_t;
 
-static sockent_t *socklist_head = NULL;
+/*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-------+-----------------------+-------------------------------+
+ * ! Ver.  !                       ! Length                        !
+ * +-------+-----------------------+-------------------------------+
+ */
+struct part_header_s
+{
+       uint16_t type;
+       uint16_t length;
+};
+typedef struct part_header_s part_header_t;
+
+/*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-------------------------------+-------------------------------+
+ * ! Type                          ! Length                        !
+ * +-------------------------------+-------------------------------+
+ * : (Length - 4) Bytes                                            :
+ * +---------------------------------------------------------------+
+ */
+struct part_string_s
+{
+       part_header_t *head;
+       char *value;
+};
+typedef struct part_string_s part_string_t;
+
+/*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-------------------------------+-------------------------------+
+ * ! Type                          ! Length                        !
+ * +-------------------------------+-------------------------------+
+ * : (Length - 4 == 2 || 4 || 8) Bytes                             :
+ * +---------------------------------------------------------------+
+ */
+struct part_number_s
+{
+       part_header_t *head;
+       uint64_t *value;
+};
+typedef struct part_number_s part_number_t;
+
+/*                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-------------------------------+-------------------------------+
+ * ! Type                          ! Length                        !
+ * +-------------------------------+---------------+---------------+
+ * ! Num of values                 ! Type0         ! Type1         !
+ * +-------------------------------+---------------+---------------+
+ * ! Value0                                                        !
+ * !                                                               !
+ * +---------------------------------------------------------------+
+ * ! Value1                                                        !
+ * !                                                               !
+ * +---------------------------------------------------------------+
+ */
+struct part_values_s
+{
+       part_header_t *head;
+       uint16_t *num_values;
+       uint8_t  *values_types;
+       value_t  *values;
+};
+typedef struct part_values_s part_values_t;
+
+/*
+ * Private variables
+ */
+static const char *config_keys[] =
+{
+       "CacheFlush",
+       "Listen",
+       "Server",
+       "TimeToLive",
+       "Forward"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static int network_config_ttl = 0;
+static int network_config_forward = 0;
+
+static sockent_t *sending_sockets = NULL;
+
+static struct pollfd *listen_sockets = NULL;
+static int listen_sockets_num = 0;
+static pthread_t listen_thread = 0;
+static int listen_loop = 0;
+
+static char         send_buffer[BUFF_SIZE];
+static char        *send_buffer_ptr;
+static int          send_buffer_fill;
+static value_list_t send_buffer_vl = VALUE_LIST_INIT;
+static char         send_buffer_type[DATA_MAX_NAME_LEN];
+static pthread_mutex_t send_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static avl_tree_t      *cache_tree = NULL;
+static pthread_mutex_t  cache_lock = PTHREAD_MUTEX_INITIALIZER;
+static time_t           cache_flush_last;
+static int              cache_flush_interval = 1800;
+
+/*
+ * Private functions
+ */
+static int cache_flush (void)
+{
+       char **keys = NULL;
+       int    keys_num = 0;
+
+       char **tmp;
+       int    i;
 
-static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
+       char   *key;
+       time_t *value;
+       avl_iterator_t *iter;
+
+       time_t curtime = time (NULL);
+
+       iter = avl_get_iterator (cache_tree);
+       while (avl_iterator_next (iter, (void *) &key, (void *) &value) == 0)
+       {
+               if ((curtime - *value) <= cache_flush_interval)
+                       continue;
+               tmp = (char **) realloc (keys,
+                               (keys_num + 1) * sizeof (char *));
+               if (tmp == NULL)
+               {
+                       sfree (keys);
+                       avl_iterator_destroy (iter);
+                       ERROR ("network plugin: cache_flush: realloc"
+                                       " failed.");
+                       return (-1);
+               }
+               keys = tmp;
+               keys[keys_num] = key;
+               keys_num++;
+       } /* while (avl_iterator_next) */
+       avl_iterator_destroy (iter);
+
+       for (i = 0; i < keys_num; i++)
+       {
+               if (avl_remove (cache_tree, keys[i], (void *) &key,
+                                       (void *) &value) != 0)
+               {
+                       WARNING ("network plugin: cache_flush: avl_remove"
+                                       " (%s) failed.", keys[i]);
+                       continue;
+               }
+
+               sfree (key);
+               sfree (value);
+       }
+
+       sfree (keys);
+
+       DEBUG ("network plugin: cache_flush: Removed %i %s",
+                       keys_num, (keys_num == 1) ? "entry" : "entries");
+       cache_flush_last = curtime;
+       return (0);
+} /* int cache_flush */
+
+static int cache_check (const char *type, const value_list_t *vl)
+{
+       char key[1024];
+       time_t *value = NULL;
+       int retval = -1;
+
+       if (cache_tree == NULL)
+               return (-1);
+
+       if (format_name (key, sizeof (key), vl->host, vl->plugin,
+                               vl->plugin_instance, type, vl->type_instance))
+               return (-1);
+
+       pthread_mutex_lock (&cache_lock);
+
+       if (avl_get (cache_tree, key, (void *) &value) == 0)
+       {
+               if (*value < vl->time)
+               {
+                       *value = vl->time;
+                       retval = 0;
+               }
+               else
+               {
+                       DEBUG ("network plugin: cache_check: *value = %i >= vl->time = %i",
+                                       (int) *value, (int) vl->time);
+                       retval = 1;
+               }
+       }
+       else
+       {
+               char *key_copy = strdup (key);
+               value = malloc (sizeof (time_t));
+               if ((key_copy != NULL) && (value != NULL))
+               {
+                       *value = vl->time;
+                       avl_insert (cache_tree, key_copy, value);
+                       retval = 0;
+               }
+               else
+               {
+                       sfree (key_copy);
+                       sfree (value);
+               }
+       }
+
+       if ((time (NULL) - cache_flush_last) > cache_flush_interval)
+               cache_flush ();
+
+       pthread_mutex_unlock (&cache_lock);
+
+       DEBUG ("network plugin: cache_check: key = %s; time = %i; retval = %i",
+                       key, (int) vl->time, retval);
+
+       return (retval);
+} /* int cache_check */
+
+static int write_part_values (char **ret_buffer, int *ret_buffer_len,
+               const data_set_t *ds, const value_list_t *vl)
+{
+       part_values_t pv;
+       int i;
+
+       i = 6 + (9 * vl->values_len);
+       if (*ret_buffer_len < i)
+               return (-1);
+       *ret_buffer_len -= i;
+
+       pv.head = (part_header_t *) *ret_buffer;
+       pv.num_values = (uint16_t *) (pv.head + 1);
+       pv.values_types = (uint8_t *) (pv.num_values + 1);
+       pv.values = (value_t *) (pv.values_types + vl->values_len);
+       *ret_buffer = (void *) (pv.values + vl->values_len);
+
+       pv.head->type = htons (TYPE_VALUES);
+       pv.head->length = htons (6 + (9 * vl->values_len));
+       *pv.num_values = htons ((uint16_t) vl->values_len);
+       
+       for (i = 0; i < vl->values_len; i++)
+       {
+               if (ds->ds[i].type == DS_TYPE_COUNTER)
+               {
+                       pv.values_types[i] = DS_TYPE_COUNTER;
+                       pv.values[i].counter = htonll (vl->values[i].counter);
+               }
+               else
+               {
+                       pv.values_types[i] = DS_TYPE_GAUGE;
+                       pv.values[i].gauge = vl->values[i].gauge;
+               }
+       } /* for (values) */
+
+       return (0);
+} /* int write_part_values */
+
+static int write_part_number (char **ret_buffer, int *ret_buffer_len,
+               int type, uint64_t value)
+{
+       part_number_t pn;
+
+       if (*ret_buffer_len < 12)
+               return (-1);
+
+       pn.head = (part_header_t *) *ret_buffer;
+       pn.value = (uint64_t *) (pn.head + 1);
+
+       pn.head->type = htons (type);
+       pn.head->length = htons (12);
+       *pn.value = htonll (value);
+
+       *ret_buffer = (char *) (pn.value + 1);
+       *ret_buffer_len -= 12;
+
+       return (0);
+} /* int write_part_number */
+
+static int write_part_string (char **ret_buffer, int *ret_buffer_len,
+               int type, const char *str, int str_len)
 {
-       char *ttl_str;
-       int   ttl_int;
+       part_string_t ps;
+       int len;
 
-       ttl_str = cf_get_option ("TimeToLive", NULL);
-       if (ttl_str == NULL)
+       len = 4 + str_len + 1;
+       if (*ret_buffer_len < len)
                return (-1);
+       *ret_buffer_len -= len;
+
+       ps.head = (part_header_t *) *ret_buffer;
+       ps.value = (char *) (ps.head + 1);
+
+       ps.head->type = htons ((uint16_t) type);
+       ps.head->length = htons ((uint16_t) str_len + 5);
+       if (str_len > 0)
+               memcpy (ps.value, str, str_len);
+       ps.value[str_len] = '\0';
+       *ret_buffer = (void *) (ps.value + (str_len + 1));
+
+       return (0);
+} /* int write_part_string */
 
-       ttl_int = atoi (ttl_str);
-       if ((ttl_int < 1) || (ttl_int > 255))
+static int parse_part_values (void **ret_buffer, int *ret_buffer_len,
+               value_t **ret_values, int *ret_num_values)
+{
+       char *buffer = *ret_buffer;
+       int   buffer_len = *ret_buffer_len;
+       part_values_t pv;
+       int   i;
+
+       uint16_t h_length;
+       uint16_t h_type;
+       uint16_t h_num;
+
+       if (buffer_len < (15))
        {
-               syslog (LOG_WARNING, "A TTL value of %i is invalid.", ttl_int);
+               DEBUG ("packet is too short: buffer_len = %i", buffer_len);
                return (-1);
        }
 
-       DBG ("ttl = %i", ttl_int);
+       pv.head = (part_header_t *) buffer;
+       h_length = ntohs (pv.head->length);
+       h_type = ntohs (pv.head->type);
+
+       assert (h_type == TYPE_VALUES);
+
+       pv.num_values = (uint16_t *) (pv.head + 1);
+       h_num = ntohs (*pv.num_values);
+
+       if (h_num != ((h_length - 6) / 9))
+       {
+               DEBUG ("`length' and `num of values' don't match");
+               return (-1);
+       }
+
+       pv.values_types = (uint8_t *) (pv.num_values + 1);
+       pv.values = (value_t *) (pv.values_types + h_num);
+
+       for (i = 0; i < h_num; i++)
+               if (pv.values_types[i] == DS_TYPE_COUNTER)
+                       pv.values[i].counter = ntohll (pv.values[i].counter);
+
+       *ret_buffer     = (void *) (pv.values + h_num);
+       *ret_buffer_len = buffer_len - h_length;
+       *ret_num_values = h_num;
+       *ret_values     = pv.values;
+
+       return (0);
+} /* int parse_part_values */
+
+static int parse_part_number (void **ret_buffer, int *ret_buffer_len,
+               uint64_t *value)
+{
+       part_number_t pn;
+       uint16_t len;
+
+       pn.head = (part_header_t *) *ret_buffer;
+       pn.value = (uint64_t *) (pn.head + 1);
+
+       len = ntohs (pn.head->length);
+       if (len != 12)
+               return (-1);
+       if (len > *ret_buffer_len)
+               return (-1);
+       *value = ntohll (*pn.value);
+
+       *ret_buffer = (void *) (pn.value + 1);
+       *ret_buffer_len -= len;
+
+       return (0);
+} /* int parse_part_number */
+
+static int parse_part_string (void **ret_buffer, int *ret_buffer_len,
+               char *output, int output_len)
+{
+       char *buffer = *ret_buffer;
+       int   buffer_len = *ret_buffer_len;
+       part_string_t ps;
+
+       uint16_t h_length;
+       uint16_t h_type;
+
+       DEBUG ("network plugin: parse_part_string: ret_buffer = %p;"
+                       " ret_buffer_len = %i; output = %p; output_len = %i;",
+                       *ret_buffer, *ret_buffer_len,
+                       (void *) output, output_len);
+
+       ps.head = (part_header_t *) buffer;
+
+       h_length = ntohs (ps.head->length);
+       h_type = ntohs (ps.head->type);
+
+       DEBUG ("network plugin: parse_part_string: length = %hu; type = %hu;",
+                       h_length, h_type);
+
+       if (buffer_len < h_length)
+       {
+               DEBUG ("packet is too short");
+               return (-1);
+       }
+       assert ((h_type == TYPE_HOST)
+                       || (h_type == TYPE_PLUGIN)
+                       || (h_type == TYPE_PLUGIN_INSTANCE)
+                       || (h_type == TYPE_TYPE)
+                       || (h_type == TYPE_TYPE_INSTANCE));
+
+       ps.value = buffer + 4;
+       if (ps.value[h_length - 5] != '\0')
+       {
+               DEBUG ("String does not end with a nullbyte");
+               return (-1);
+       }
+
+       if (output_len < (h_length - 4))
+       {
+               DEBUG ("output buffer is too small");
+               return (-1);
+       }
+       strcpy (output, ps.value);
+
+       DEBUG ("network plugin: parse_part_string: output = %s", output);
+
+       *ret_buffer = (void *) (buffer + h_length);
+       *ret_buffer_len = buffer_len - h_length;
+
+       return (0);
+} /* int parse_part_string */
+
+static int parse_packet (void *buffer, int buffer_len)
+{
+       part_header_t *header;
+       int status;
+
+       value_list_t vl = VALUE_LIST_INIT;
+       char type[DATA_MAX_NAME_LEN];
+
+       DEBUG ("network plugin: parse_packet: buffer = %p; buffer_len = %i;",
+                       buffer, buffer_len);
+
+       memset (&vl, '\0', sizeof (vl));
+       memset (&type, '\0', sizeof (type));
+       status = 0;
+
+       while ((status == 0) && (buffer_len > sizeof (part_header_t)))
+       {
+               header = (part_header_t *) buffer;
+
+               if (ntohs (header->length) > buffer_len)
+                       break;
+               /* Assure that this loop terminates eventually */
+               if (ntohs (header->length) < 4)
+                       break;
+
+               if (ntohs (header->type) == TYPE_VALUES)
+               {
+                       status = parse_part_values (&buffer, &buffer_len,
+                                       &vl.values, &vl.values_len);
+
+                       if (status != 0)
+                       {
+                               DEBUG ("parse_part_values failed.");
+                               break;
+                       }
+
+                       if ((vl.time > 0)
+                                       && (strlen (vl.host) > 0)
+                                       && (strlen (vl.plugin) > 0)
+                                       && (strlen (type) > 0)
+                                       && (cache_check (type, &vl) == 0))
+                       {
+                               DEBUG ("network plugin: parse_packet:"
+                                               " dispatching values");
+                               plugin_dispatch_values (type, &vl);
+                       }
+                       else
+                       {
+                               DEBUG ("network plugin: parse_packet:"
+                                               " NOT dispatching values");
+                       }
+               }
+               else if (ntohs (header->type) == TYPE_TIME)
+               {
+                       uint64_t tmp = 0;
+                       status = parse_part_number (&buffer, &buffer_len, &tmp);
+                       if (status == 0)
+                               vl.time = (time_t) tmp;
+               }
+               else if (ntohs (header->type) == TYPE_HOST)
+               {
+                       status = parse_part_string (&buffer, &buffer_len,
+                                       vl.host, sizeof (vl.host));
+                       DEBUG ("network plugin: parse_packet: vl.host = %s", vl.host);
+               }
+               else if (ntohs (header->type) == TYPE_PLUGIN)
+               {
+                       status = parse_part_string (&buffer, &buffer_len,
+                                       vl.plugin, sizeof (vl.plugin));
+                       DEBUG ("network plugin: parse_packet: vl.plugin = %s", vl.plugin);
+               }
+               else if (ntohs (header->type) == TYPE_PLUGIN_INSTANCE)
+               {
+                       status = parse_part_string (&buffer, &buffer_len,
+                                       vl.plugin_instance, sizeof (vl.plugin_instance));
+                       DEBUG ("network plugin: parse_packet: vl.plugin_instance = %s", vl.plugin_instance);
+               }
+               else if (ntohs (header->type) == TYPE_TYPE)
+               {
+                       status = parse_part_string (&buffer, &buffer_len,
+                                       type, sizeof (type));
+                       DEBUG ("network plugin: parse_packet: type = %s", type);
+               }
+               else if (ntohs (header->type) == TYPE_TYPE_INSTANCE)
+               {
+                       status = parse_part_string (&buffer, &buffer_len,
+                                       vl.type_instance, sizeof (vl.type_instance));
+                       DEBUG ("network plugin: parse_packet: vl.type_instance = %s", vl.type_instance);
+               }
+               else
+               {
+                       DEBUG ("network plugin: parse_packet: Unknown part"
+                                       " type: 0x%0hx", ntohs (header->type));
+                       buffer = ((char *) buffer) + ntohs (header->length);
+               }
+       } /* while (buffer_len > sizeof (part_header_t)) */
+
+       return (0);
+} /* int parse_packet */
+
+static void free_sockent (sockent_t *se)
+{
+       sockent_t *next;
+       while (se != NULL)
+       {
+               next = se->next;
+               free (se->addr);
+               free (se);
+               se = next;
+       }
+} /* void free_sockent */
+
+/*
+ * int network_set_ttl
+ *
+ * Set the `IP_MULTICAST_TTL', `IP_TTL', `IPV6_MULTICAST_HOPS' or
+ * `IPV6_UNICAST_HOPS', depending on which option is applicable.
+ *
+ * The `struct addrinfo' is used to destinguish between unicast and multicast
+ * sockets.
+ */
+static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
+{
+       if ((network_config_ttl < 1) || (network_config_ttl > 255))
+               return (-1);
+
+       DEBUG ("ttl = %i", network_config_ttl);
 
        if (ai->ai_family == AF_INET)
        {
@@ -91,9 +636,12 @@ static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
                        optname = IP_TTL;
 
                if (setsockopt (se->fd, IPPROTO_IP, optname,
-                                       &ttl_int, sizeof (ttl_int)) == -1)
+                                       &network_config_ttl,
+                                       sizeof (network_config_ttl)) == -1)
                {
-                       syslog (LOG_ERR, "setsockopt: %s", strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("setsockopt: %s",
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
                        return (-1);
                }
        }
@@ -109,25 +657,31 @@ static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
                        optname = IPV6_UNICAST_HOPS;
 
                if (setsockopt (se->fd, IPPROTO_IPV6, optname,
-                                       &ttl_int, sizeof (ttl_int)) == -1)
+                                       &network_config_ttl,
+                                       sizeof (network_config_ttl)) == -1)
                {
-                       syslog (LOG_ERR, "setsockopt: %s", strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("setsockopt: %s",
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        return (-1);
                }
        }
 
        return (0);
-}
+} /* int network_set_ttl */
 
 static int network_bind_socket (const sockent_t *se, const struct addrinfo *ai)
 {
-       int loop = 1;
+       int loop = 0;
 
-       DBG ("fd = %i; calling `bind'", se->fd);
+       DEBUG ("fd = %i; calling `bind'", se->fd);
 
        if (bind (se->fd, ai->ai_addr, ai->ai_addrlen) == -1)
        {
-               syslog (LOG_ERR, "bind: %s", strerror (errno));
+               char errbuf[1024];
+               ERROR ("bind: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                return (-1);
        }
 
@@ -138,7 +692,7 @@ static int network_bind_socket (const sockent_t *se, const struct addrinfo *ai)
                {
                        struct ip_mreq mreq;
 
-                       DBG ("fd = %i; IPv4 multicast address found", se->fd);
+                       DEBUG ("fd = %i; IPv4 multicast address found", se->fd);
 
                        mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
                        mreq.imr_interface.s_addr = htonl (INADDR_ANY);
@@ -146,14 +700,20 @@ static int network_bind_socket (const sockent_t *se, const struct addrinfo *ai)
                        if (setsockopt (se->fd, IPPROTO_IP, IP_MULTICAST_LOOP,
                                                &loop, sizeof (loop)) == -1)
                        {
-                               syslog (LOG_ERR, "setsockopt: %s", strerror (errno));
+                               char errbuf[1024];
+                               ERROR ("setsockopt: %s",
+                                               sstrerror (errno, errbuf,
+                                                       sizeof (errbuf)));
                                return (-1);
                        }
 
                        if (setsockopt (se->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                                                &mreq, sizeof (mreq)) == -1)
                        {
-                               syslog (LOG_ERR, "setsockopt: %s", strerror (errno));
+                               char errbuf[1024];
+                               ERROR ("setsockopt: %s",
+                                               sstrerror (errno, errbuf,
+                                                       sizeof (errbuf)));
                                return (-1);
                        }
                }
@@ -166,7 +726,7 @@ static int network_bind_socket (const sockent_t *se, const struct addrinfo *ai)
                {
                        struct ipv6_mreq mreq;
 
-                       DBG ("fd = %i; IPv6 multicast address found", se->fd);
+                       DEBUG ("fd = %i; IPv6 multicast address found", se->fd);
 
                        memcpy (&mreq.ipv6mr_multiaddr,
                                        &addr->sin6_addr,
@@ -186,44 +746,40 @@ static int network_bind_socket (const sockent_t *se, const struct addrinfo *ai)
                        if (setsockopt (se->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
                                                &loop, sizeof (loop)) == -1)
                        {
-                               syslog (LOG_ERR, "setsockopt: %s", strerror (errno));
+                               char errbuf[1024];
+                               ERROR ("setsockopt: %s",
+                                               sstrerror (errno, errbuf,
+                                                       sizeof (errbuf)));
                                return (-1);
                        }
 
                        if (setsockopt (se->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
                                                &mreq, sizeof (mreq)) == -1)
                        {
-                               syslog (LOG_ERR, "setsockopt: %s", strerror (errno));
+                               char errbuf[1024];
+                               ERROR ("setsockopt: %s",
+                                               sstrerror (errno, errbuf,
+                                                       sizeof (errbuf)));
                                return (-1);
                        }
                }
        }
 
        return (0);
-}
+} /* int network_bind_socket */
 
-int network_create_socket (const char *node, const char *service)
+static sockent_t *network_create_socket (const char *node,
+               const char *service,
+               int listen)
 {
-       sockent_t *socklist_tail;
-
        struct addrinfo  ai_hints;
        struct addrinfo *ai_list, *ai_ptr;
        int              ai_return;
 
-       int num_added = 0;
+       sockent_t *se_head = NULL;
+       sockent_t *se_tail = NULL;
 
-       DBG ("node = %s, service = %s", node, service);
-
-       if (operating_mode == MODE_LOCAL || operating_mode == MODE_LOG)
-       {
-               syslog (LOG_WARNING, "network_create_socket: There is no point opening a socket when you are in mode `%s'.",
-                               operating_mode == MODE_LOCAL ? "Local" : "Log");
-               return (-1);
-       }
-
-       socklist_tail = socklist_head;
-       while ((socklist_tail != NULL) && (socklist_tail->next != NULL))
-               socklist_tail = socklist_tail->next;
+       DEBUG ("node = %s, service = %s", node, service);
 
        memset (&ai_hints, '\0', sizeof (ai_hints));
        ai_hints.ai_flags    = 0;
@@ -233,17 +789,21 @@ int network_create_socket (const char *node, const char *service)
 #ifdef AI_ADDRCONFIG
        ai_hints.ai_flags |= AI_ADDRCONFIG;
 #endif
-       ai_hints.ai_family   = PF_UNSPEC;
+       ai_hints.ai_family   = AF_UNSPEC;
        ai_hints.ai_socktype = SOCK_DGRAM;
        ai_hints.ai_protocol = IPPROTO_UDP;
 
-       if ((ai_return = getaddrinfo (node, service, &ai_hints, &ai_list)) != 0)
+       ai_return = getaddrinfo (node, service, &ai_hints, &ai_list);
+       if (ai_return != 0)
        {
-               syslog (LOG_ERR, "getaddrinfo (%s, %s): %s",
-                               node == NULL ? "(null)" : node,
-                               service == NULL ? "(null)" : service,
-                               ai_return == EAI_SYSTEM ? strerror (errno) : gai_strerror (ai_return));
-               return (-1);
+               char errbuf[1024];
+               ERROR ("getaddrinfo (%s, %s): %s",
+                               (node == NULL) ? "(null)" : node,
+                               (service == NULL) ? "(null)" : service,
+                               (ai_return == EAI_SYSTEM)
+                               ? sstrerror (errno, errbuf, sizeof (errbuf))
+                               : gai_strerror (ai_return));
+               return (NULL);
        }
 
        for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
@@ -252,13 +812,19 @@ int network_create_socket (const char *node, const char *service)
 
                if ((se = (sockent_t *) malloc (sizeof (sockent_t))) == NULL)
                {
-                       syslog (LOG_EMERG, "malloc: %s", strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("malloc: %s",
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        continue;
                }
 
                if ((se->addr = (struct sockaddr_storage *) malloc (sizeof (struct sockaddr_storage))) == NULL)
                {
-                       syslog (LOG_EMERG, "malloc: %s", strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("malloc: %s",
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        free (se);
                        continue;
                }
@@ -268,19 +834,23 @@ int network_create_socket (const char *node, const char *service)
                memcpy (se->addr, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
                se->addrlen = ai_ptr->ai_addrlen;
 
-               se->mode = operating_mode;
-               se->fd   = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
+               se->fd   = socket (ai_ptr->ai_family,
+                               ai_ptr->ai_socktype,
+                               ai_ptr->ai_protocol);
                se->next = NULL;
 
                if (se->fd == -1)
                {
-                       syslog (LOG_ERR, "socket: %s", strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("socket: %s",
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        free (se->addr);
                        free (se);
                        continue;
                }
 
-               if (operating_mode == MODE_SERVER)
+               if (listen != 0)
                {
                        if (network_bind_socket (se, ai_ptr) != 0)
                        {
@@ -290,260 +860,492 @@ int network_create_socket (const char *node, const char *service)
                                continue;
                        }
                }
-               else if (operating_mode == MODE_CLIENT)
+               else /* listen == 0 */
                {
                        network_set_ttl (se, ai_ptr);
                }
 
-               if (socklist_tail == NULL)
+               if (se_tail == NULL)
                {
-                       socklist_head = se;
-                       socklist_tail = se;
+                       se_head = se;
+                       se_tail = se;
                }
                else
                {
-                       socklist_tail->next = se;
-                       socklist_tail = se;
+                       se_tail->next = se;
+                       se_tail = se;
                }
 
-               num_added++;
-
                /* We don't open more than one write-socket per node/service pair.. */
-               if (operating_mode == MODE_CLIENT)
+               if (listen == 0)
                        break;
        }
 
        freeaddrinfo (ai_list);
 
-       return (num_added);
-}
+       return (se_head);
+} /* sockent_t *network_create_socket */
 
-static int network_connect_default (void)
+static sockent_t *network_create_default_socket (int listen)
 {
-       int ret;
+       sockent_t *se_ptr  = NULL;
+       sockent_t *se_head = NULL;
+       sockent_t *se_tail = NULL;
 
-       if (socklist_head != NULL)
-               return (0);
+       se_ptr = network_create_socket (NET_DEFAULT_V6_ADDR,
+                       NET_DEFAULT_PORT, listen);
 
-       DBG ("socklist_head is NULL");
+       /* Don't send to the same machine in IPv6 and IPv4 if both are available. */
+       if ((listen == 0) && (se_ptr != NULL))
+               return (se_ptr);
 
-       ret = 0;
+       if (se_ptr != NULL)
+       {
+               se_head = se_ptr;
+               se_tail = se_ptr;
+               while (se_tail->next != NULL)
+                       se_tail = se_tail->next;
+       }
 
-       if (network_create_socket (NET_DEFAULT_V6_ADDR, NET_DEFAULT_PORT) > 0)
-               ret++;
+       se_ptr = network_create_socket (NET_DEFAULT_V4_ADDR, NET_DEFAULT_PORT, listen);
 
-       /* Don't use IPv4 and IPv6 in parallel by default.. */
-       if ((operating_mode == MODE_CLIENT) && (ret != 0))
-               return (ret);
+       if (se_tail == NULL)
+               return (se_ptr);
 
-       if (network_create_socket (NET_DEFAULT_V4_ADDR, NET_DEFAULT_PORT) > 0)
-               ret++;
+       se_tail->next = se_ptr;
+       return (se_head);
+} /* sockent_t *network_create_default_socket */
 
-       if (ret == 0)
-               ret = -1;
+static int network_add_listen_socket (const char *node, const char *service)
+{
+       sockent_t *se;
+       sockent_t *se_ptr;
+       int se_num = 0;
 
-       return (ret);
-}
+       if (service == NULL)
+               service = NET_DEFAULT_PORT;
 
-static int network_get_listen_socket (void)
-{
-       int fd;
-       int max_fd;
-       int status;
+       if (node == NULL)
+               se = network_create_default_socket (1 /* listen == true */);
+       else
+               se = network_create_socket (node, service, 1 /* listen == true */);
 
-       fd_set readfds;
-       sockent_t *se;
+       if (se == NULL)
+               return (-1);
+
+       for (se_ptr = se; se_ptr != NULL; se_ptr = se_ptr->next)
+               se_num++;
 
-       if (socklist_head == NULL)
-               network_connect_default ();
+       listen_sockets = (struct pollfd *) realloc (listen_sockets,
+                       (listen_sockets_num + se_num)
+                       * sizeof (struct pollfd));
 
-       FD_ZERO (&readfds);
-       max_fd = -1;
-       for (se = socklist_head; se != NULL; se = se->next)
+       for (se_ptr = se; se_ptr != NULL; se_ptr = se_ptr->next)
        {
-               if (se->mode != operating_mode)
-                       continue;
+               listen_sockets[listen_sockets_num].fd = se_ptr->fd;
+               listen_sockets[listen_sockets_num].events = POLLIN | POLLPRI;
+               listen_sockets[listen_sockets_num].revents = 0;
+               listen_sockets_num++;
+       } /* for (se) */
 
-               FD_SET (se->fd, &readfds);
-               if (se->fd >= max_fd)
-                       max_fd = se->fd + 1;
-       }
+       free_sockent (se);
+       return (0);
+} /* int network_add_listen_socket */
 
-       if (max_fd == -1)
-       {
-               syslog (LOG_WARNING, "No listen sockets found!");
+static int network_add_sending_socket (const char *node, const char *service)
+{
+       sockent_t *se;
+       sockent_t *se_ptr;
+
+       if (service == NULL)
+               service = NET_DEFAULT_PORT;
+
+       if (node == NULL)
+               se = network_create_default_socket (0 /* listen == false */);
+       else
+               se = network_create_socket (node, service, 0 /* listen == false */);
+
+       if (se == NULL)
                return (-1);
+
+       if (sending_sockets == NULL)
+       {
+               sending_sockets = se;
+               return (0);
        }
 
-       status = select (max_fd, &readfds, NULL, NULL, NULL);
+       for (se_ptr = sending_sockets; se_ptr->next != NULL; se_ptr = se_ptr->next)
+               /* seek end */;
 
-       if (status == -1)
+       se_ptr->next = se;
+       return (0);
+} /* int network_get_listen_socket */
+
+int network_receive (void)
+{
+       char buffer[BUFF_SIZE];
+       int  buffer_len;
+
+       int i;
+       int status;
+
+       if (listen_sockets_num == 0)
+               network_add_listen_socket (NULL, NULL);
+
+       if (listen_sockets_num == 0)
        {
-               if (errno != EINTR)
-                       syslog (LOG_ERR, "select: %s", strerror (errno));
+               ERROR ("network: Failed to open a listening socket.");
                return (-1);
        }
 
-       fd = -1;
-       for (se = socklist_head; se != NULL; se = se->next)
+       while (listen_loop == 0)
        {
-               if (se->mode != operating_mode)
-                       continue;
+               status = poll (listen_sockets, listen_sockets_num, -1);
 
-               if (FD_ISSET (se->fd, &readfds))
+               if (status <= 0)
                {
-                       fd = se->fd;
-                       break;
+                       char errbuf[1024];
+                       if (errno == EINTR)
+                               continue;
+                       ERROR ("poll failed: %s",
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+                       return (-1);
                }
-       }
 
-       if (fd == -1)
-               syslog (LOG_WARNING, "No socket ready..?");
+               for (i = 0; (i < listen_sockets_num) && (status > 0); i++)
+               {
+                       if ((listen_sockets[i].revents & (POLLIN | POLLPRI)) == 0)
+                               continue;
+                       status--;
+
+                       buffer_len = recv (listen_sockets[i].fd,
+                                       buffer, sizeof (buffer),
+                                       0 /* no flags */);
+                       if (buffer_len < 0)
+                       {
+                               char errbuf[1024];
+                               ERROR ("recv failed: %s",
+                                               sstrerror (errno, errbuf,
+                                                       sizeof (errbuf)));
+                               return (-1);
+                       }
 
-       DBG ("fd = %i", fd);
-       return (fd);
+                       parse_packet (buffer, buffer_len);
+               } /* for (listen_sockets) */
+       } /* while (listen_loop == 0) */
+
+       return (0);
 }
 
-int network_receive (char **host, char **type, char **inst, char **value)
+static void *receive_thread (void *arg)
 {
-       int fd;
-       char buffer[BUFF_SIZE];
+       return (network_receive () ? (void *) 1 : (void *) 0);
+} /* void *receive_thread */
 
-       struct sockaddr_storage addr;
-       socklen_t               addrlen;
+static void network_send_buffer (const char *buffer, int buffer_len)
+{
+       sockent_t *se;
        int status;
 
-       char *fields[4];
+       DEBUG ("buffer_len = %i", buffer_len);
 
-       assert (operating_mode == MODE_SERVER);
+       for (se = sending_sockets; se != NULL; se = se->next)
+       {
+               while (42)
+               {
+                       status = sendto (se->fd, buffer, buffer_len, 0 /* no flags */,
+                                       (struct sockaddr *) se->addr, se->addrlen);
+                       if (status < 0)
+                       {
+                               char errbuf[1024];
+                               if (errno == EINTR)
+                                       continue;
+                               ERROR ("network plugin: sendto failed: %s",
+                                               sstrerror (errno, errbuf,
+                                                       sizeof (errbuf)));
+                               break;
+                       }
 
-       *host  = NULL;
-       *type  = NULL;
-       *inst  = NULL;
-       *value = NULL;
+                       break;
+               } /* while (42) */
+       } /* for (sending_sockets) */
+} /* void network_send_buffer */
 
-       if ((fd = network_get_listen_socket ()) < 0)
-               return (-1);
+static int add_to_buffer (char *buffer, int buffer_size,
+               value_list_t *vl_def, char *type_def,
+               const data_set_t *ds, const value_list_t *vl)
+{
+       char *buffer_orig = buffer;
 
-       addrlen = sizeof (addr);
-       if (recvfrom (fd, buffer, BUFF_SIZE, 0, (struct sockaddr *) &addr, &addrlen) == -1)
+       if (strcmp (vl_def->host, vl->host) != 0)
        {
-               syslog (LOG_ERR, "recvfrom: %s", strerror (errno));
-               return (-1);
+               if (write_part_string (&buffer, &buffer_size, TYPE_HOST,
+                                       vl->host, strlen (vl->host)) != 0)
+                       return (-1);
+               strcpy (vl_def->host, vl->host);
+               DEBUG ("network plugin: add_to_buffer: host = %s", vl->host);
        }
 
-       if ((*host = (char *) malloc (BUFF_SIZE)) == NULL)
+       if (vl_def->time != vl->time)
        {
-               syslog (LOG_EMERG, "malloc: %s", strerror (errno));
-               return (-1);
+               if (write_part_number (&buffer, &buffer_size, TYPE_TIME,
+                                       (uint64_t) vl->time))
+                       return (-1);
+               vl_def->time = vl->time;
+               DEBUG ("network plugin: add_to_buffer: time = %u",
+                               (unsigned int) vl->time);
        }
 
-       status = getnameinfo ((struct sockaddr *) &addr, addrlen,
-                       *host, BUFF_SIZE, NULL, 0, 0);
-       if (status != 0)
+       if (strcmp (vl_def->plugin, vl->plugin) != 0)
        {
-               free (*host); *host = NULL;
-               syslog (LOG_ERR, "getnameinfo: %s",
-                               status == EAI_SYSTEM ? strerror (errno) : gai_strerror (status));
-               return (-1);
+               if (write_part_string (&buffer, &buffer_size, TYPE_PLUGIN,
+                                       vl->plugin, strlen (vl->plugin)) != 0)
+                       return (-1);
+               strcpy (vl_def->plugin, vl->plugin);
+               DEBUG ("network plugin: add_to_buffer: plugin = %s",
+                               vl->plugin);
        }
 
-       if (strsplit (buffer, fields, 4) != 3)
+       if (strcmp (vl_def->plugin_instance, vl->plugin_instance) != 0)
        {
-               syslog (LOG_WARNING, "Invalid message from `%s'", *host);
-               free (*host); *host = NULL;
-               return (1);
+               if (write_part_string (&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
+                                       vl->plugin_instance,
+                                       strlen (vl->plugin_instance)) != 0)
+                       return (-1);
+               strcpy (vl_def->plugin_instance, vl->plugin_instance);
+               DEBUG ("network plugin: add_to_buffer: plugin_instance = %s",
+                               vl->plugin_instance);
        }
 
-       if ((*type = strdup (fields[0])) == NULL)
+       if (strcmp (type_def, ds->type) != 0)
        {
-               syslog (LOG_EMERG, "strdup: %s", strerror (errno));
-               free (*host); *host = NULL;
-               return (-1);
+               if (write_part_string (&buffer, &buffer_size, TYPE_TYPE,
+                                       ds->type, strlen (ds->type)) != 0)
+                       return (-1);
+               strcpy (type_def, ds->type);
+               DEBUG ("network plugin: add_to_buffer: type = %s", ds->type);
        }
 
-       if ((*inst = strdup (fields[1])) == NULL)
+       if (strcmp (vl_def->type_instance, vl->type_instance) != 0)
        {
-               syslog (LOG_EMERG, "strdup: %s", strerror (errno));
-               free (*host); *host = NULL;
-               free (*type); *type = NULL;
+               if (write_part_string (&buffer, &buffer_size, TYPE_TYPE_INSTANCE,
+                                       vl->type_instance,
+                                       strlen (vl->type_instance)) != 0)
+                       return (-1);
+               strcpy (vl_def->type_instance, vl->type_instance);
+               DEBUG ("network plugin: add_to_buffer: type_instance = %s",
+                               vl->type_instance);
+       }
+       
+       if (write_part_values (&buffer, &buffer_size, ds, vl) != 0)
                return (-1);
+
+       return (buffer - buffer_orig);
+} /* int add_to_buffer */
+
+static void flush_buffer (void)
+{
+       DEBUG ("network plugin: flush_buffer: send_buffer_fill = %i",
+                       send_buffer_fill);
+
+       network_send_buffer (send_buffer, send_buffer_fill);
+       send_buffer_ptr  = send_buffer;
+       send_buffer_fill = 0;
+       memset (&send_buffer_vl, '\0', sizeof (send_buffer_vl));
+       memset (send_buffer_type, '\0', sizeof (send_buffer_type));
+}
+
+static int network_write (const data_set_t *ds, const value_list_t *vl)
+{
+       int status;
+
+       /* If the value is already in the cache, we have received it via the
+        * network. We write it again if forwarding is activated. It's then in
+        * the cache and should we receive it again we will ignore it. */
+       status = cache_check (ds->type, vl);
+       if ((network_config_forward == 0)
+                       && (status != 0))
+               return (0);
+
+       pthread_mutex_lock (&send_buffer_lock);
+
+       status = add_to_buffer (send_buffer_ptr,
+                       sizeof (send_buffer) - send_buffer_fill,
+                       &send_buffer_vl, send_buffer_type,
+                       ds, vl);
+       if (status >= 0)
+       {
+               /* status == bytes added to the buffer */
+               send_buffer_fill += status;
+               send_buffer_ptr  += status;
+       }
+       else
+       {
+               flush_buffer ();
+
+               status = add_to_buffer (send_buffer_ptr,
+                               sizeof (send_buffer) - send_buffer_fill,
+                               &send_buffer_vl, send_buffer_type,
+                               ds, vl);
+
+               if (status >= 0)
+               {
+                       send_buffer_fill += status;
+                       send_buffer_ptr  += status;
+               }
        }
 
-       if ((*value = strdup (fields[2])) == NULL)
+       if (status < 0)
        {
-               syslog (LOG_EMERG, "strdup: %s", strerror (errno));
-               free (*host); *host = NULL;
-               free (*type); *type = NULL;
-               free (*inst); *inst = NULL;
-               return (-1);
+               ERROR ("network plugin: Unable to append to the "
+                               "buffer for some weird reason");
+       }
+       else if ((sizeof (send_buffer) - send_buffer_fill) < 15)
+       {
+               flush_buffer ();
        }
 
-       DBG ("host = %s, type = %s, inst = %s, value = %s",
-                       *host, *type, *inst, *value);
+       pthread_mutex_unlock (&send_buffer_lock);
 
-       return (0);
-}
+       return ((status < 0) ? -1 : 0);
+} /* int network_write */
 
-int network_send (char *type, char *inst, char *value)
+static int network_config (const char *key, const char *val)
 {
-       char buf[BUFF_SIZE];
-       int buflen;
+       char *node;
+       char *service;
 
-       sockent_t *se;
+       char *fields[3];
+       int   fields_num;
 
-       int ret;
-       int status;
+       if ((strcasecmp ("Listen", key) == 0)
+                       || (strcasecmp ("Server", key) == 0))
+       {
+               char *val_cpy = strdup (val);
+               if (val_cpy == NULL)
+                       return (1);
+
+               service = NET_DEFAULT_PORT;
+               fields_num = strsplit (val_cpy, fields, 3);
+               if ((fields_num != 1)
+                               && (fields_num != 2))
+                       return (1);
+               else if (fields_num == 2)
+                       service = fields[1];
+               node = fields[0];
+
+               if (strcasecmp ("Listen", key) == 0)
+                       network_add_listen_socket (node, service);
+               else
+                       network_add_sending_socket (node, service);
+       }
+       else if (strcasecmp ("TimeToLive", key) == 0)
+       {
+               int tmp = atoi (val);
+               if ((tmp > 0) && (tmp < 256))
+                       network_config_ttl = tmp;
+               else
+                       return (1);
+       }
+       else if (strcasecmp ("Forward", key) == 0)
+       {
+               if ((strcasecmp ("true", val) == 0)
+                               || (strcasecmp ("yes", val) == 0)
+                               || (strcasecmp ("on", val) == 0))
+                       network_config_forward = 1;
+               else
+                       network_config_forward = 0;
+       }
+       else if (strcasecmp ("CacheFlush", key) == 0)
+       {
+               int tmp = atoi (val);
+               if (tmp > 0)
+                       cache_flush_interval = tmp;
+               else return (1);
+       }
+       else
+       {
+               return (-1);
+       }
+       return (0);
+} /* int network_config */
 
-       DBG ("type = %s, inst = %s, value = %s", type, inst, value);
+static int network_shutdown (void)
+{
+       DEBUG ("Shutting down.");
 
-       assert (operating_mode == MODE_CLIENT);
+       listen_loop++;
 
-       buflen = snprintf (buf, BUFF_SIZE, "%s %s %s", type, inst, value);
-       if ((buflen >= BUFF_SIZE) || (buflen < 1))
+       if (listen_thread != (pthread_t) 0)
        {
-               syslog (LOG_WARNING, "network_send: snprintf failed..");
-               return (-1);
+               pthread_kill (listen_thread, SIGTERM);
+               pthread_join (listen_thread, NULL /* no return value */);
+               listen_thread = (pthread_t) 0;
        }
-       buf[buflen] = '\0';
-       buflen++;
 
-       if (socklist_head == NULL)
-               network_connect_default ();
+       listen_thread = 0;
 
-       ret = 0;
-       for (se = socklist_head; se != NULL; se = se->next)
+       if (cache_tree != NULL)
        {
-               if (se->mode != operating_mode)
-                       continue;
+               void *key;
+               void *value;
 
-               while (1)
+               while (avl_pick (cache_tree, &key, &value) == 0)
                {
-                       status = sendto (se->fd, buf, buflen, 0,
-                                       (struct sockaddr *) se->addr, se->addrlen);
-
-                       if (status == -1)
-                       {
-                               if (errno == EINTR)
-                               {
-                                       DBG ("sendto was interrupted");
-                                       continue;
-                               }
-                               else
-                               {
-                                       syslog (LOG_ERR, "sendto: %s", strerror (errno));
-                                       ret = -1;
-                                       break;
-                               }
-                       }
-                       else if (ret >= 0)
-                               ret++;
-                       break;
+                       sfree (key);
+                       sfree (value);
                }
+               avl_destroy (cache_tree);
+               cache_tree = NULL;
        }
 
-       if (ret == 0)
-               syslog (LOG_WARNING, "Message wasn't sent to anybody..");
+       /* TODO: Close `sending_sockets' */
 
-       return (ret);
-}
+       plugin_unregister_config ("network");
+       plugin_unregister_init ("network");
+       plugin_unregister_write ("network");
+       plugin_unregister_shutdown ("network");
+
+       return (0);
+} /* int network_shutdown */
+
+static int network_init (void)
+{
+       plugin_register_shutdown ("network", network_shutdown);
+
+       send_buffer_ptr  = send_buffer;
+       send_buffer_fill = 0;
+       memset (&send_buffer_vl, '\0', sizeof (send_buffer_vl));
+       memset (send_buffer_type, '\0', sizeof (send_buffer_type));
+
+       cache_tree = avl_create ((int (*) (const void *, const void *)) strcmp);
+       cache_flush_last = time (NULL);
+
+       /* setup socket(s) and so on */
+       if (sending_sockets != NULL)
+               plugin_register_write ("network", network_write);
+
+       if ((listen_sockets_num != 0) && (listen_thread == 0))
+       {
+               int status;
+
+               status = pthread_create (&listen_thread, NULL /* no attributes */,
+                               receive_thread, NULL /* no argument */);
+
+               if (status != 0)
+               {
+                       char errbuf[1024];
+                       ERROR ("network: pthread_create failed: %s",
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
+               }
+       }
+       return (0);
+} /* int network_init */
+
+void module_register (modreg_e load)
+{
+       plugin_register_config ("network", network_config,
+                       config_keys, config_keys_num);
+       plugin_register_init   ("network", network_init);
+} /* void module_register */
index 2df989b..b20fc75 100644 (file)
@@ -4,8 +4,7 @@
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
 #define NET_DEFAULT_V6_ADDR "ff18::efc0:4a42"
 #define NET_DEFAULT_PORT    "25826"
 
-int network_create_socket (const char *node, const char *service);
-int network_receive (char **host, char **type, char **instance, char **value);
-int network_send (char *type, char *instance, char *value);
+#define TYPE_HOST            0x0000
+#define TYPE_TIME            0x0001
+#define TYPE_PLUGIN          0x0002
+#define TYPE_PLUGIN_INSTANCE 0x0003
+#define TYPE_TYPE            0x0004
+#define TYPE_TYPE_INSTANCE   0x0005
+#define TYPE_VALUES          0x0006
 
 #endif /* NETWORK_H */
index d0f33c5..40e4110 100644 (file)
--- a/src/nfs.c
+++ b/src/nfs.c
@@ -4,8 +4,7 @@
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -25,8 +24,6 @@
 #include "common.h"
 #include "plugin.h"
 
-#define MODULE_NAME "nfs"
-
 /* #if defined(KERNEL_LINUX) || defined(HAVE_LIBKSTAT) */
 #if KERNEL_LINUX
 # define NFS_HAVE_READ 1
@@ -34,9 +31,6 @@
 # define NFS_HAVE_READ 0
 #endif
 
-static char *nfs2_procedures_file  = "nfs2_procedures-%s.rrd";
-static char *nfs3_procedures_file  = "nfs3_procedures-%s.rrd";
-
 /*
 see /proc/net/rpc/nfs
 see http://www.missioncriticallinux.com/orph/NFS-Statistics
@@ -82,57 +76,68 @@ Number      Procedures  Procedures
 21                      commit
 */
 
-static char *nfs2_procedures_ds_def[] =
+static data_source_t procedure_dsrc[1] =
 {
-       "DS:null:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:getattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:setattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:root:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:lookup:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:readlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:read:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:wrcache:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:write:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:create:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:remove:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:rename:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:link:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:symlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:mkdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:rmdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:readdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:fsstat:COUNTER:"COLLECTD_HEARTBEAT":0:U",
+       {"value", DS_TYPE_COUNTER, 0, 4294967295.0}
+};
+
+static data_set_t procedure_ds =
+{
+       "nfs_procedure", 1, procedure_dsrc
+};
+
+#if NFS_HAVE_READ
+static const char *nfs2_procedures_names[] =
+{
+       "null",
+       "getattr",
+       "setattr",
+       "root",
+       "lookup",
+       "readlink",
+       "read",
+       "wrcache",
+       "write",
+       "create",
+       "remove",
+       "rename",
+       "link",
+       "symlink",
+       "mkdir",
+       "rmdir",
+       "readdir",
+       "fsstat",
        NULL
 };
-static int nfs2_procedures_ds_num = 18;
+static int nfs2_procedures_names_num = 18;
 
-static char *nfs3_procedures_ds_def[] =
+static const char *nfs3_procedures_names[] =
 {
-       "DS:null:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:getattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:setattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:lookup:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:access:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:readlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:read:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:write:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:create:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:mkdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:symlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:mknod:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:remove:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:rmdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:rename:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:link:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:readdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:readdirplus:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:fsstat:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:fsinfo:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:pathconf:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:commit:COUNTER:"COLLECTD_HEARTBEAT":0:U",
+       "null",
+       "getattr",
+       "setattr",
+       "lookup",
+       "access",
+       "readlink",
+       "read",
+       "write",
+       "create",
+       "mkdir",
+       "symlink",
+       "mknod",
+       "remove",
+       "rmdir",
+       "rename",
+       "link",
+       "readdir",
+       "readdirplus",
+       "fsstat",
+       "fsinfo",
+       "pathconf",
+       "commit",
        NULL
 };
-static int nfs3_procedures_ds_num = 22;
+static int nfs3_procedures_names_num = 22;
 
 #if HAVE_LIBKSTAT && 0
 extern kstat_ctl_t *kc;
@@ -146,7 +151,8 @@ static kstat_t *nfs4_ksp_server;
 
 /* Possibly TODO: NFSv4 statistics */
 
-static void nfs_init (void)
+#if 0
+static int nfs_init (void)
 {
 #if HAVE_LIBKSTAT && 0
        kstat_t *ksp_chain;
@@ -181,89 +187,45 @@ static void nfs_init (void)
        }
 #endif
 
-       return;
-}
+       return (0);
+} /* int nfs_init */
+#endif
 
 #define BUFSIZE 1024
-static void nfs2_procedures_write (char *host, char *inst, char *val)
-{
-       char filename[BUFSIZE];
-
-       if (snprintf (filename, BUFSIZE, nfs2_procedures_file, inst) > BUFSIZE)
-               return;
-
-       rrd_update_file (host, filename, val, nfs2_procedures_ds_def,
-                       nfs2_procedures_ds_num);
-}
-
-static void nfs3_procedures_write (char *host, char *inst, char *val)
+static void nfs_procedures_submit (const char *plugin_instance,
+               unsigned long long *val, const char **names, int len)
 {
-       char filename[BUFSIZE];
-
-       if (snprintf (filename, BUFSIZE, nfs3_procedures_file, inst) > BUFSIZE)
-               return;
-
-       rrd_update_file (host, filename, val, nfs3_procedures_ds_def,
-                       nfs3_procedures_ds_num);
-}
-
-#if NFS_HAVE_READ
-static void nfs2_procedures_submit (unsigned long long *val, char *inst)
-{
-       char buf[BUFSIZE];
-       int retval = 0;
-
-       retval = snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
-                       "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
-                       "%llu:%llu:%llu", /* 18x %llu */
-                       (unsigned int) curtime,
-                       val[0], val[1], val[2], val[3], val[4], val[5], val[6],
-                       val[7], val[8], val[9], val[10], val[11], val[12],
-                       val[13], val[14], val[15], val[16], val[17]);
-
-
-       if (retval >= BUFSIZE)
-               return;
-       else if (retval < 0)
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
+       int i;
+
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "nfs");
+       strncpy (vl.plugin_instance, plugin_instance,
+                       sizeof (vl.plugin_instance));
+
+       for (i = 0; i < len; i++)
        {
-               syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
-               return;
+               values[0].counter = val[i];
+               strncpy (vl.type_instance, names[i],
+                               sizeof (vl.type_instance));
+               DEBUG ("%s-%s/nfs_procedure-%s = %llu",
+                               vl.plugin, vl.plugin_instance,
+                               vl.type_instance, val[i]);
+               plugin_dispatch_values ("nfs_procedure", &vl);
        }
-
-       plugin_submit ("nfs2_procedures", inst, buf);
-}
-
-static void nfs3_procedures_submit (unsigned long long *val, char *inst)
-{
-       char buf[BUFSIZE];
-       int retval = 0;
-
-       retval = snprintf(buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
-                       "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
-                       "%llu:%llu:%llu:%llu:%llu:%llu:%llu", /* 22x %llu */
-                       (unsigned int) curtime,
-                       val[0], val[1], val[2], val[3], val[4], val[5], val[6],
-                       val[7], val[8], val[9], val[10], val[11], val[12],
-                       val[13], val[14], val[15], val[16], val[17], val[18],
-                       val[19], val[20], val[21]);
-
-       if (retval >= BUFSIZE)
-               return;
-       else if (retval < 0)
-       {
-               syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
-               return;
-       }
-
-       plugin_submit("nfs3_procedures", inst, buf);
-}
-#endif /* NFS_HAVE_READ */
+} /* void nfs_procedures_submit */
 
 #if KERNEL_LINUX
 static void nfs_read_stats_file (FILE *fh, char *inst)
 {
        char buffer[BUFSIZE];
 
+       char plugin_instance[DATA_MAX_NAME_LEN];
+
        char *fields[48];
        int numfields = 0;
 
@@ -274,30 +236,45 @@ static void nfs_read_stats_file (FILE *fh, char *inst)
        {
                numfields = strsplit (buffer, fields, 48);
 
-               if (numfields < 2)
+               if (((numfields - 2) != nfs2_procedures_names_num)
+                               && ((numfields - 2)
+                                       != nfs3_procedures_names_num))
                        continue;
 
-               if (strncmp (fields[0], "proc2", 5) == 0)
+               if (strcmp (fields[0], "proc2") == 0)
                {
                        int i;
                        unsigned long long *values;
 
-                       if (numfields - 2 != nfs2_procedures_ds_num)
+                       if ((numfields - 2) != nfs2_procedures_names_num)
                        {
-                               syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS2 statistics.", numfields - 2);
+                               WARNING ("nfs plugin: Wrong "
+                                               "number of fields (= %i) "
+                                               "for NFSv2 statistics.",
+                                               numfields - 2);
                                continue;
                        }
 
-                       if ((values = (unsigned long long *) malloc (nfs2_procedures_ds_num * sizeof (unsigned long long))) == NULL)
+                       snprintf (plugin_instance, sizeof (plugin_instance),
+                                       "v2%s", inst);
+                       plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
+
+                       values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
+                       if (values == NULL)
                        {
-                               syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
+                               char errbuf[1024];
+                               ERROR ("nfs plugin: malloc "
+                                               "failed: %s",
+                                               sstrerror (errno, errbuf, sizeof (errbuf)));
                                continue;
                        }
 
-                       for (i = 0; i < nfs2_procedures_ds_num; i++)
+                       for (i = 0; i < nfs2_procedures_names_num; i++)
                                values[i] = atoll (fields[i + 2]);
 
-                       nfs2_procedures_submit (values, inst);
+                       nfs_procedures_submit (plugin_instance, values,
+                                       nfs2_procedures_names,
+                                       nfs2_procedures_names_num);
 
                        free (values);
                }
@@ -306,27 +283,40 @@ static void nfs_read_stats_file (FILE *fh, char *inst)
                        int i;
                        unsigned long long *values;
 
-                       if (numfields - 2 != nfs3_procedures_ds_num)
+                       if ((numfields - 2) != nfs3_procedures_names_num)
                        {
-                               syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS3 statistics.", numfields - 2);
+                               WARNING ("nfs plugin: Wrong "
+                                               "number of fields (= %i) "
+                                               "for NFSv3 statistics.",
+                                               numfields - 2);
                                continue;
                        }
 
-                       if ((values = (unsigned long long *) malloc (nfs3_procedures_ds_num * sizeof (unsigned long long))) == NULL)
+                       snprintf (plugin_instance, sizeof (plugin_instance),
+                                       "v3%s", inst);
+                       plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
+
+                       values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
+                       if (values == NULL)
                        {
-                               syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
+                               char errbuf[1024];
+                               ERROR ("nfs plugin: malloc "
+                                               "failed: %s",
+                                               sstrerror (errno, errbuf, sizeof (errbuf)));
                                continue;
                        }
 
-                       for (i = 0; i < nfs3_procedures_ds_num; i++)
+                       for (i = 0; i < nfs3_procedures_names_num; i++)
                                values[i] = atoll (fields[i + 2]);
 
-                       nfs3_procedures_submit (values, inst);
+                       nfs_procedures_submit (plugin_instance, values,
+                                       nfs3_procedures_names,
+                                       nfs3_procedures_names_num);
 
                        free (values);
                }
-       }
-}
+       } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
+} /* void nfs_read_stats_file */
 #endif /* defined(KERNEL_LINUX) */
 #undef BUFSIZE
 
@@ -358,8 +348,7 @@ static void nfs2_read_kstat (kstat_t *ksp, char *inst)
 }
 #endif
 
-#if NFS_HAVE_READ
-static void nfs_read (void)
+static int nfs_read (void)
 {
 #if KERNEL_LINUX
        FILE *fh;
@@ -384,16 +373,18 @@ static void nfs_read (void)
        if (nfs2_ksp_server != NULL)
                nfs2_read_kstat (nfs2_ksp_server, "server");
 #endif /* defined(HAVE_LIBKSTAT) */
+
+       return (0);
 }
-#else
-# define nfs_read NULL
 #endif /* NFS_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, nfs_init, nfs_read, NULL);
-       plugin_register ("nfs2_procedures", NULL, NULL, nfs2_procedures_write);
-       plugin_register ("nfs3_procedures", NULL, NULL, nfs3_procedures_write);
-}
+       if (load & MR_DATASETS)
+               plugin_register_data_set (&procedure_ds);
 
-#undef MODULE_NAME
+#if NFS_HAVE_READ
+       if (load & MR_READ)
+               plugin_register_read ("nfs", nfs_read);
+#endif
+} /* void module_register */
index b65a9e8..7f4d62a 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/ntpd.c
- * Copyright (C) 2006  Florian octo Forster
+ * Copyright (C) 2006-2007  Florian octo Forster
  *
  * 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
@@ -23,9 +23,6 @@
 #include "common.h"
 #include "plugin.h"
 #include "configfile.h"
-#include "utils_debug.h"
-
-#define MODULE_NAME "ntpd"
 
 #if HAVE_SYS_SOCKET_H
 # define NTPD_HAVE_READ 1
 #if HAVE_NETINET_TCP_H
 # include <netinet/tcp.h>
 #endif
-#if HAVE_SYS_POLL_H
-# include <sys/poll.h>
+#if HAVE_POLL_H
+# include <poll.h>
 #endif
 
-static char *config_keys[] =
+static data_source_t seconds_dsrc[1] =
 {
-       "Host",
-       "Port",
-       NULL
+       {"seconds", DS_TYPE_GAUGE, -1000000.0, 1000000.0}
 };
-static int config_keys_num = 2;
 
-/* drift */
-static char *time_offset_file     = "ntpd/time_offset-%s.rrd";
-static char *time_dispersion_file = "ntpd/time_dispersion-%s.rrd";
-static char *time_delay_file      = "ntpd/delay-%s.rrd";
+static data_set_t time_offset_ds =
+{
+       "time_offset", 1, seconds_dsrc
+};
 
-/* used for `time_offset', `time_dispersion', and `delay' */
-static char *sec_ds_def[] =
+static data_set_t time_dispersion_ds =
 {
-       "DS:seconds:GAUGE:"COLLECTD_HEARTBEAT":-1000000:1000000",
-       NULL
+       "time_dispersion", 1, seconds_dsrc
+};
+
+static data_set_t delay_ds =
+{
+       "delay", 1, seconds_dsrc
+};
+
+static data_source_t ppm_dsrc[1] =
+{
+       {"ppm", DS_TYPE_GAUGE, -1000000.0, 1000000.0}
+};
+
+static data_set_t frequency_offset_ds =
+{
+       "frequency_offset", 1, ppm_dsrc
 };
-static int sec_ds_num = 1;
 
-static char *frequency_offset_file = "ntpd/frequency_offset-%s.rrd";
-static char *frequency_offset_ds_def[] =
+static const char *config_keys[] =
 {
-       "DS:ppm:GAUGE:"COLLECTD_HEARTBEAT":-1000000:1000000",
+       "Host",
+       "Port",
        NULL
 };
-static int frequency_offset_ds_num = 1;
+static int config_keys_num = 2;
 
 #if NTPD_HAVE_READ
 # define NTPD_DEFAULT_HOST "localhost"
@@ -90,7 +96,6 @@ static int frequency_offset_ds_num = 1;
 static int   sock_descr = -1;
 static char *ntpd_host = NULL;
 static char *ntpd_port = NULL;
-#endif
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * The following definitions were copied from the NTPd distribution  *
@@ -286,7 +291,7 @@ static int refclock_names_num = 45;
  * End of the copied stuff..                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-static int ntpd_config (char *key, char *value)
+static int ntpd_config (const char *key, const char *value)
 {
        if (strcasecmp (key, "host") == 0)
        {
@@ -310,64 +315,22 @@ static int ntpd_config (char *key, char *value)
        return (0);
 }
 
-static void ntpd_init (void)
+static void ntpd_submit (char *type, char *type_inst, double value)
 {
-       return;
-}
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-static void ntpd_write_sec (char *host, char *inst, char *val, char *file)
-{
-       char buf[256];
-       int  status;
+       values[0].gauge = value;
 
-       status = snprintf (buf, 256, file, inst);
-       if ((status < 1) || (status >= 256))
-               return;
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "ntpd");
+       strcpy (vl.plugin_instance, "");
+       strncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
 
-       rrd_update_file (host, buf, val,
-                       sec_ds_def, sec_ds_num);
-}
-
-static void ntpd_write_time_offset (char *host, char *inst, char *val)
-{
-       ntpd_write_sec (host, inst, val, time_offset_file);
-}
-
-static void ntpd_write_time_dispersion (char *host, char *inst, char *val)
-{
-       ntpd_write_sec (host, inst, val, time_dispersion_file);
-}
-
-static void ntpd_write_delay (char *host, char *inst, char *val)
-{
-       ntpd_write_sec (host, inst, val, time_delay_file);
-}
-
-static void ntpd_write_frequency_offset (char *host, char *inst, char *val)
-{
-       char buf[256];
-       int  status;
-
-       status = snprintf (buf, 256, frequency_offset_file, inst);
-       if ((status < 1) || (status >= 256))
-               return;
-
-       rrd_update_file (host, buf, val,
-                       frequency_offset_ds_def, frequency_offset_ds_num);
-}
-
-#if NTPD_HAVE_READ
-static void ntpd_submit (char *type, char *inst, double value)
-{
-       char buf[256];
-
-       if (snprintf (buf, 256, "%u:%.8f", (unsigned int) curtime, value) >= 256)
-               return;
-
-       DBG ("type = %s; inst = %s; value = %s;",
-                       type, inst, buf);
-
-       plugin_submit (type, inst, buf);
+       plugin_dispatch_values (type, &vl);
 }
 
 /* returns `tv0 - tv1' in milliseconds or 0 if `tv1 > tv0' */
@@ -408,7 +371,7 @@ static int ntpd_connect (void)
        if (sock_descr >= 0)
                return (sock_descr);
 
-       DBG ("Opening a new socket");
+       DEBUG ("Opening a new socket");
 
        host = ntpd_host;
        if (host == NULL)
@@ -426,12 +389,12 @@ static int ntpd_connect (void)
 
        if ((status = getaddrinfo (host, port, &ai_hints, &ai_list)) != 0)
        {
-               DBG ("getaddrinfo (%s, %s): %s",
-                               host, port,
-                               status == EAI_SYSTEM ? strerror (errno) : gai_strerror (status));
-               syslog (LOG_ERR, "ntpd plugin: getaddrinfo (%s, %s): %s",
+               char errbuf[1024];
+               ERROR ("ntpd plugin: getaddrinfo (%s, %s): %s",
                                host, port,
-                               status == EAI_SYSTEM ? strerror (errno) : gai_strerror (status));
+                               (status == EAI_SYSTEM)
+                               ? sstrerror (errno, errbuf, sizeof (errbuf))
+                               : gai_strerror (status));
                return (-1);
        }
 
@@ -458,8 +421,8 @@ static int ntpd_connect (void)
 
        if (sock_descr < 0)
        {
-               DBG ("Unable to connect to server.");
-               syslog (LOG_ERR, "ntpd plugin: Unable to connect to server.");
+               DEBUG ("Unable to connect to server.");
+               ERROR ("ntpd plugin: Unable to connect to server.");
        }
 
        return (sock_descr);
@@ -507,8 +470,9 @@ static int ntpd_receive_response (int req_code, int *res_items, int *res_size,
 
        if (gettimeofday (&time_end, NULL) < 0)
        {
-               syslog (LOG_ERR, "ntpd plugin: gettimeofday failed: %s",
-                               strerror (errno));
+               char errbuf[1024];
+               ERROR ("ntpd plugin: gettimeofday failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                return (-1);
        }
        time_end.tv_sec++; /* wait for a most one second */
@@ -518,8 +482,9 @@ static int ntpd_receive_response (int req_code, int *res_items, int *res_size,
        {
                if (gettimeofday (&time_now, NULL) < 0)
                {
-                       syslog (LOG_ERR, "ntpd plugin: gettimeofday failed: %s",
-                                       strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("ntpd plugin: gettimeofday failed: %s",
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
                        return (-1);
                }
 
@@ -531,7 +496,7 @@ static int ntpd_receive_response (int req_code, int *res_items, int *res_size,
                poll_s.events  = POLLIN | POLLPRI;
                poll_s.revents = 0;
                
-               DBG ("Polling for %ims", timeout);
+               DEBUG ("Polling for %ims", timeout);
                status = poll (&poll_s, 1, timeout);
 
                if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
@@ -539,15 +504,15 @@ static int ntpd_receive_response (int req_code, int *res_items, int *res_size,
 
                if (status < 0)
                {
-                       DBG ("poll failed: %s", strerror (errno));
-                       syslog (LOG_ERR, "ntpd plugin: poll failed: %s",
-                                       strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("ntpd plugin: poll failed: %s",
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
                        return (-1);
                }
 
                if (status == 0) /* timeout */
                {
-                       DBG ("timeout reached.");
+                       DEBUG ("timeout reached.");
                        break;
                }
 
@@ -559,50 +524,52 @@ static int ntpd_receive_response (int req_code, int *res_items, int *res_size,
 
                if (status < 0)
                {
-                       DBG ("recv(2) failed: %s", strerror (errno));
-                       DBG ("Closing socket #%i", sd);
+                       char errbuf[1024];
+                       DEBUG ("recv(2) failed: %s",
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+                       DEBUG ("Closing socket #%i", sd);
                        close (sd);
                        sock_descr = sd = -1;
                        return (-1);
                }
 
-               DBG ("recv'd %i bytes", status);
+               DEBUG ("recv'd %i bytes", status);
 
                /* 
                 * Do some sanity checks first
                 */
                if (status < RESP_HEADER_SIZE)
                {
-                       syslog (LOG_WARNING, "ntpd plugin: Short (%i bytes) packet received",
+                       WARNING ("ntpd plugin: Short (%i bytes) packet received",
                                        (int) status);
                        continue;
                }
                if (INFO_MODE (res.rm_vn_mode) != MODE_PRIVATE)
                {
-                       syslog (LOG_NOTICE, "ntpd plugin: Packet received with mode %i",
+                       NOTICE ("ntpd plugin: Packet received with mode %i",
                                        INFO_MODE (res.rm_vn_mode));
                        continue;
                }
                if (INFO_IS_AUTH (res.auth_seq))
                {
-                       syslog (LOG_NOTICE, "ntpd plugin: Encrypted packet received");
+                       NOTICE ("ntpd plugin: Encrypted packet received");
                        continue;
                }
                if (!ISRESPONSE (res.rm_vn_mode))
                {
-                       syslog (LOG_NOTICE, "ntpd plugin: Received request packet, "
+                       NOTICE ("ntpd plugin: Received request packet, "
                                        "wanted response");
                        continue;
                }
                if (INFO_MBZ (res.mbz_itemsize))
                {
-                       syslog (LOG_WARNING, "ntpd plugin: Received packet with nonzero "
+                       WARNING ("ntpd plugin: Received packet with nonzero "
                                        "MBZ field!");
                        continue;
                }
                if (res.implementation != IMPL_XNTPD)
                {
-                       syslog (LOG_WARNING, "ntpd plugin: Asked for request of type %i, "
+                       WARNING ("ntpd plugin: Asked for request of type %i, "
                                        "got %i", (int) IMPL_XNTPD, (int) res.implementation);
                        continue;
                }
@@ -610,7 +577,7 @@ static int ntpd_receive_response (int req_code, int *res_items, int *res_size,
                /* Check for error code */
                if (INFO_ERR (res.err_nitems) != 0)
                {
-                       syslog (LOG_ERR, "ntpd plugin: Received error code %i",
+                       ERROR ("ntpd plugin: Received error code %i",
                                        (int) INFO_ERR(res.err_nitems));
                        return ((int) INFO_ERR (res.err_nitems));
                }
@@ -618,13 +585,13 @@ static int ntpd_receive_response (int req_code, int *res_items, int *res_size,
                /* extract number of items in this packet and the size of these items */
                pkt_item_num = INFO_NITEMS (res.err_nitems);
                pkt_item_len = INFO_ITEMSIZE (res.mbz_itemsize);
-               DBG ("pkt_item_num = %i; pkt_item_len = %i;",
+               DEBUG ("pkt_item_num = %i; pkt_item_len = %i;",
                                pkt_item_num, pkt_item_len);
 
                /* Check if the reported items fit in the packet */
                if ((pkt_item_num * pkt_item_len) > (status - RESP_HEADER_SIZE))
                {
-                       syslog (LOG_ERR, "ntpd plugin: %i items * %i bytes > "
+                       ERROR ("ntpd plugin: %i items * %i bytes > "
                                        "%i bytes - %i bytes header",
                                        (int) pkt_item_num, (int) pkt_item_len,
                                        (int) status, (int) RESP_HEADER_SIZE);
@@ -636,14 +603,14 @@ static int ntpd_receive_response (int req_code, int *res_items, int *res_size,
                 * items have the same size. Discard invalid packets. */
                if (items_num == 0) /* first packet */
                {
-                       DBG ("*res_size = %i", pkt_item_len);
+                       DEBUG ("*res_size = %i", pkt_item_len);
                        *res_size = pkt_item_len;
                }
                else if (*res_size != pkt_item_len)
                {
-                       DBG ("Error: *res_size = %i; pkt_item_len = %i;",
+                       DEBUG ("Error: *res_size = %i; pkt_item_len = %i;",
                                        *res_size, pkt_item_len);
-                       syslog (LOG_ERR, "Item sizes differ.");
+                       ERROR ("Item sizes differ.");
                        continue;
                }
 
@@ -651,14 +618,14 @@ static int ntpd_receive_response (int req_code, int *res_items, int *res_size,
                pkt_padding = 0;
                if (res_item_size > pkt_item_len)
                        pkt_padding = res_item_size - pkt_item_len;
-               DBG ("res_item_size = %i; pkt_padding = %i;",
+               DEBUG ("res_item_size = %i; pkt_padding = %i;",
                                res_item_size, pkt_padding);
 
                /* Extract the sequence number */
                pkt_sequence = INFO_SEQ (res.auth_seq);
                if ((pkt_sequence < 0) || (pkt_sequence > MAXSEQ))
                {
-                       syslog (LOG_ERR, "ntpd plugin: Received packet with sequence %i",
+                       ERROR ("ntpd plugin: Received packet with sequence %i",
                                        pkt_sequence);
                        continue;
                }
@@ -666,7 +633,7 @@ static int ntpd_receive_response (int req_code, int *res_items, int *res_size,
                /* Check if this sequence has been received before. If so, discard it. */
                if (pkt_recvd[pkt_sequence] != '\0')
                {
-                       syslog (LOG_NOTICE, "ntpd plugin: Sequence %i received twice",
+                       NOTICE ("ntpd plugin: Sequence %i received twice",
                                        pkt_sequence);
                        continue;
                }
@@ -677,20 +644,20 @@ static int ntpd_receive_response (int req_code, int *res_items, int *res_size,
                {
                        if (pkt_lastseq != -1)
                        {
-                               syslog (LOG_ERR, "ntpd plugin: Two packets which both "
+                               ERROR ("ntpd plugin: Two packets which both "
                                                "claim to be the last one in the "
                                                "sequence have been received.");
                                continue;
                        }
                        pkt_lastseq = pkt_sequence;
-                       DBG ("Last sequence = %i;", pkt_lastseq);
+                       DEBUG ("Last sequence = %i;", pkt_lastseq);
                }
 
                /*
                 * Enough with the checks. Copy the data now.
                 * We start by allocating some more memory.
                 */
-               DBG ("realloc (%p, %i)", (void *) *res_data,
+               DEBUG ("realloc (%p, %i)", (void *) *res_data,
                                (items_num + pkt_item_num) * res_item_size);
                items = realloc ((void *) *res_data,
                                (items_num + pkt_item_num) * res_item_size);
@@ -698,7 +665,7 @@ static int ntpd_receive_response (int req_code, int *res_items, int *res_size,
                if (items == NULL)
                {
                        items = *res_data;
-                       syslog (LOG_ERR, "ntpd plugin: realloc failed.");
+                       ERROR ("ntpd plugin: realloc failed.");
                        continue;
                }
                *res_data = items;
@@ -757,13 +724,13 @@ static int ntpd_send_request (int req_code, int req_items, int req_size, char *r
        if (req_data != NULL)
                memcpy ((void *) req.data, (const void *) req_data, req_data_len);
 
-       DBG ("req_items = %i; req_size = %i; req_data = %p;",
+       DEBUG ("req_items = %i; req_size = %i; req_data = %p;",
                        req_items, req_size, (void *) req_data);
 
        status = swrite (sd, (const char *) &req, REQ_LEN_NOMAC);
        if (status < 0)
        {
-               DBG ("`swrite' failed. Closing socket #%i", sd);
+               DEBUG ("`swrite' failed. Closing socket #%i", sd);
                close (sd);
                sock_descr = sd = -1;
                return (status);
@@ -810,7 +777,7 @@ static double ntpd_read_fp (int32_t val_int)
        return (val_double);
 }
 
-static void ntpd_read (void)
+static int ntpd_read (void)
 {
        struct info_kernel *ik;
        int                 ik_num;
@@ -834,19 +801,19 @@ static void ntpd_read (void)
 
        if (status != 0)
        {
-               DBG ("ntpd_do_query failed with status %i", status);
-               return;
+               DEBUG ("ntpd_do_query failed with status %i", status);
+               return (-1);
        }
        if ((ik == NULL) || (ik_num == 0) || (ik_size == 0))
        {
-               DBG ("ntpd_do_query returned: ik = %p; ik_num = %i; ik_size = %i;",
+               DEBUG ("ntpd_do_query returned: ik = %p; ik_num = %i; ik_size = %i;",
                                (void *) ik, ik_num, ik_size);
-               return;
+               return (-1);
        }
 
        /* kerninfo -> estimated error */
 
-       DBG ("info_kernel:\n"
+       DEBUG ("info_kernel:\n"
                        "  pll offset    = %.8f\n"
                        "  pll frequency = %.8f\n" /* drift compensation */
                        "  est error     = %.8f\n",
@@ -854,9 +821,9 @@ static void ntpd_read (void)
                        ntpd_read_fp (ik->freq),
                        ntpd_read_fp (ik->esterror));
 
-       ntpd_submit ("ntpd_frequency_offset", "loop",  ntpd_read_fp (ik->freq));
-       ntpd_submit ("ntpd_time_offset",      "loop",  ntpd_read_fp (ik->offset));
-       ntpd_submit ("ntpd_time_offset",      "error", ntpd_read_fp (ik->esterror));
+       ntpd_submit ("frequency_offset", "loop",  ntpd_read_fp (ik->freq));
+       ntpd_submit ("time_offset",      "loop",  ntpd_read_fp (ik->offset));
+       ntpd_submit ("time_offset",      "error", ntpd_read_fp (ik->esterror));
 
        free (ik);
        ik = NULL;
@@ -867,14 +834,14 @@ static void ntpd_read (void)
                        sizeof (struct info_peer_summary));
        if (status != 0)
        {
-               DBG ("ntpd_do_query failed with status %i", status);
-               return;
+               DEBUG ("ntpd_do_query failed with status %i", status);
+               return (-1);
        }
        if ((ps == NULL) || (ps_num == 0) || (ps_size == 0))
        {
-               DBG ("ntpd_do_query returned: ps = %p; ps_num = %i; ps_size = %i;",
+               DEBUG ("ntpd_do_query returned: ps = %p; ps_num = %i; ps_size = %i;",
                                (void *) ps, ps_num, ps_size);
-               return;
+               return (-1);
        }
 
        for (i = 0; i < ps_num; i++)
@@ -911,9 +878,10 @@ static void ntpd_read (void)
                                        NULL, 0, 0 /* no flags */);
                        if (status != 0)
                        {
-                               syslog (LOG_ERR, "ntpd plugin: getnameinfo failed: %s",
-                                               status == EAI_SYSTEM
-                                               ? strerror (errno)
+                               char errbuf[1024];
+                               ERROR ("ntpd plugin: getnameinfo failed: %s",
+                                               (status == EAI_SYSTEM)
+                                               ? sstrerror (errno, errbuf, sizeof (errbuf))
                                                : gai_strerror (status));
                                continue;
                        }
@@ -961,7 +929,7 @@ static void ntpd_read (void)
                        }
                }
 
-               DBG ("peer %i:\n"
+               DEBUG ("peer %i:\n"
                                "  peername   = %s\n"
                                "  srcadr     = 0x%08x\n"
                                "  delay      = %f\n"
@@ -979,29 +947,35 @@ static void ntpd_read (void)
                                ntpd_read_fp (ptr->dispersion));
 
                if (refclock_id != 1) /* not the system clock (offset will always be zero.. */
-                       ntpd_submit ("ntpd_time_offset", peername, offset);
-               ntpd_submit ("ntpd_time_dispersion", peername, ntpd_read_fp (ptr->dispersion));
+                       ntpd_submit ("time_offset", peername, offset);
+               ntpd_submit ("time_dispersion", peername, ntpd_read_fp (ptr->dispersion));
                if (refclock_id == 0) /* not a reference clock */
-                       ntpd_submit ("ntpd_delay", peername, ntpd_read_fp (ptr->delay));
+                       ntpd_submit ("delay", peername, ntpd_read_fp (ptr->delay));
        }
 
        free (ps);
        ps = NULL;
 
-       return;
-}
-#else
-# define ntpd_read NULL
+       return (0);
+} /* int ntpd_read */
 #endif /* NTPD_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, ntpd_init, ntpd_read, NULL);
-       plugin_register ("ntpd_time_offset", NULL, NULL, ntpd_write_time_offset);
-       plugin_register ("ntpd_time_dispersion", NULL, NULL, ntpd_write_time_dispersion);
-       plugin_register ("ntpd_delay", NULL, NULL, ntpd_write_delay);
-       plugin_register ("ntpd_frequency_offset", NULL, NULL, ntpd_write_frequency_offset);
-       cf_register (MODULE_NAME, ntpd_config, config_keys, config_keys_num);
-}
+       if (load & MR_DATASETS)
+       {
+               plugin_register_data_set (&time_offset_ds);
+               plugin_register_data_set (&time_dispersion_ds);
+               plugin_register_data_set (&delay_ds);
+               plugin_register_data_set (&frequency_offset_ds);
+       }
 
-#undef MODULE_NAME
+#if NTPD_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_config ("ntpd", ntpd_config,
+                               config_keys, config_keys_num);
+               plugin_register_read ("ntpd", ntpd_read);
+       }
+#endif /* NTPD_HAVE_READ */
+} /* void module_register */
diff --git a/src/nut.c b/src/nut.c
new file mode 100644 (file)
index 0000000..73a3318
--- /dev/null
+++ b/src/nut.c
@@ -0,0 +1,375 @@
+/**
+ * collectd - src/nut.c
+ * Copyright (C) 2007  Florian octo Forster
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#if HAVE_PTHREAD_H
+# include <pthread.h>
+#endif
+
+#if HAVE_UPSCLIENT_H
+# include <upsclient.h>
+# define NUT_HAVE_READ 1
+#else
+# define NUT_HAVE_READ 0
+#endif
+
+static data_source_t data_source_current[1] =
+{
+  {"value", DS_TYPE_GAUGE, NAN, NAN}
+};
+
+static data_set_t ds_current =
+{
+  "current", 1, data_source_current
+};
+
+static data_source_t data_source_humidity[1] =
+{
+  {"value", DS_TYPE_GAUGE, 0.0, 100.0}
+};
+
+static data_set_t ds_humidity =
+{
+  "humidity", 1, data_source_humidity
+};
+
+static data_source_t data_source_power[1] =
+{
+  {"value", DS_TYPE_GAUGE, 0.0, NAN}
+};
+
+static data_set_t ds_power =
+{
+  "power", 1, data_source_power
+};
+
+static data_source_t data_source_voltage[1] =
+{
+  {"value", DS_TYPE_GAUGE, NAN, NAN}
+};
+
+static data_set_t ds_voltage =
+{
+  "voltage", 1, data_source_voltage
+};
+
+static data_source_t data_source_percent[1] =
+{
+  {"percent", DS_TYPE_GAUGE, 0, 100.1}
+};
+
+static data_set_t ds_percent =
+{
+  "percent", 1, data_source_percent
+};
+
+static data_source_t data_source_timeleft[1] =
+{
+  {"timeleft", DS_TYPE_GAUGE, 0, 100.0}
+};
+
+static data_set_t ds_timeleft =
+{
+  "timeleft", 1, data_source_timeleft
+};
+
+static data_source_t data_source_temperature[1] =
+{
+  {"value", DS_TYPE_GAUGE, -273.15, NAN}
+};
+
+static data_set_t ds_temperature =
+{
+  "temperature", 1, data_source_temperature
+};
+
+static data_source_t data_source_frequency[1] =
+{
+  {"frequency", DS_TYPE_GAUGE, 0, NAN}
+};
+
+static data_set_t ds_frequency =
+{
+  "frequency", 1, data_source_frequency
+};
+
+#if NUT_HAVE_READ
+struct nut_ups_s;
+typedef struct nut_ups_s nut_ups_t;
+struct nut_ups_s
+{
+  UPSCONN    conn;
+  char      *upsname;
+  char      *hostname;
+  int        port;
+  nut_ups_t *next;
+};
+
+static nut_ups_t *upslist_head = NULL;
+
+static pthread_mutex_t read_lock = PTHREAD_MUTEX_INITIALIZER;
+static int read_busy = 0;
+
+static const char *config_keys[] =
+{
+  "UPS"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
+
+static void free_nut_ups_t (nut_ups_t *ups)
+{
+    upscli_disconnect (&ups->conn);
+    sfree (ups->hostname);
+    sfree (ups->upsname);
+    sfree (ups);
+} /* void free_nut_ups_t */
+
+static int nut_add_ups (const char *name)
+{
+  nut_ups_t *ups;
+  int status;
+
+  DEBUG ("nut plugin: nut_add_ups (name = %s);", name);
+
+  ups = (nut_ups_t *) malloc (sizeof (nut_ups_t));
+  if (ups == NULL)
+  {
+    ERROR ("nut plugin: nut_add_ups: malloc failed.");
+    return (1);
+  }
+  memset (ups, '\0', sizeof (nut_ups_t));
+
+  status = upscli_splitname (name, &ups->upsname, &ups->hostname,
+      &ups->port);
+  if (status != 0)
+  {
+    ERROR ("nut plugin: nut_add_ups: upscli_splitname (%s) failed.", name);
+    free_nut_ups_t (ups);
+    return (1);
+  }
+
+  status = upscli_connect (&ups->conn, ups->hostname, ups->port,
+      UPSCLI_CONN_TRYSSL);
+  if (status != 0)
+  {
+    ERROR ("nut plugin: nut_add_ups: upscli_connect (%s, %i) failed: %s",
+       ups->hostname, ups->port, upscli_strerror (&ups->conn));
+    free_nut_ups_t (ups);
+    return (1);
+  }
+
+  if (upslist_head == NULL)
+    upslist_head = ups;
+  else
+  {
+    nut_ups_t *last = upslist_head;
+    while (last->next != NULL)
+      last = last->next;
+    last->next = ups;
+  }
+
+  return (0);
+} /* int nut_add_ups */
+
+static int nut_config (const char *key, const char *value)
+{
+  if (strcasecmp (key, "UPS") == 0)
+    return (nut_add_ups (value));
+  else
+    return (-1);
+} /* int nut_config */
+
+static void nut_submit (nut_ups_t *ups, const char *type,
+    const char *type_instance, gauge_t value)
+{
+  value_t values[1];
+  value_list_t vl = VALUE_LIST_INIT;
+
+  values[0].gauge = value;
+
+  vl.values = values;
+  vl.values_len = STATIC_ARRAY_SIZE (values);
+  vl.time = time (NULL);
+  strncpy (vl.host,
+      (strcasecmp (ups->hostname, "localhost") == 0)
+      ? hostname_g
+      : ups->hostname,
+      sizeof (vl.host));
+  strcpy (vl.plugin, "nut");
+  strncpy (vl.plugin_instance, ups->upsname, sizeof (vl.plugin_instance));
+  strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+  vl.host[sizeof (vl.host) - 1] = '\0';
+  vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0';
+  vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+
+  plugin_dispatch_values (type, &vl);
+} /* void nut_submit */
+
+static int nut_read_one (nut_ups_t *ups)
+{
+  const char *query[3] = {"VAR", ups->upsname, NULL};
+  unsigned int query_num = 2;
+  char **answer;
+  unsigned int answer_num;
+  int status;
+
+  /* nut plugin: nut_read_one: upscli_list_start (adpos) failed: Protocol
+   * error */
+  status = upscli_list_start (&ups->conn, query_num, query);
+  if (status != 0)
+  {
+    ERROR ("nut plugin: nut_read_one: upscli_list_start (%s) failed: %s",
+       ups->upsname, upscli_strerror (&ups->conn));
+    return (-1);
+  }
+
+  while ((status = upscli_list_next (&ups->conn, query_num, query,
+         &answer_num, &answer)) == 1)
+  {
+    char  *key;
+    double value;
+
+    if (answer_num < 4)
+      continue;
+
+    key = answer[2];
+    value = atof (answer[3]);
+
+    if (strncmp ("ambient.", key, 8) == 0)
+    {
+      if (strcmp ("ambient.humidity", key) == 0)
+       nut_submit (ups, "humidity", "ambient", value);
+      else if (strcmp ("ambient.temperature", key) == 0)
+       nut_submit (ups, "temperature", "ambient", value);
+    }
+    else if (strncmp ("battery.", key, 8) == 0)
+    {
+      if (strcmp ("battery.charge", key) == 0)
+       nut_submit (ups, "percent", "charge", value);
+      else if (strcmp ("battery.current", key) == 0)
+       nut_submit (ups, "current", "battery", value);
+      else if (strcmp ("battery.runtime", key) == 0)
+       nut_submit (ups, "timeleft", "battery", value);
+      else if (strcmp ("battery.temperature", key) == 0)
+       nut_submit (ups, "temperature", "battery", value);
+      else if (strcmp ("battery.voltage", key) == 0)
+       nut_submit (ups, "voltage", "battery", value);
+    }
+    else if (strncmp ("input.", key, 6) == 0)
+    {
+      if (strcmp ("input.frequency", key) == 0)
+       nut_submit (ups, "frequency", "input", value);
+      else if (strcmp ("input.voltage", key) == 0)
+       nut_submit (ups, "voltage", "input", value);
+    }
+    else if (strncmp ("output.", key, 7) == 0)
+    {
+      if (strcmp ("output.current", key) == 0)
+       nut_submit (ups, "current", "output", value);
+      else if (strcmp ("output.frequency", key) == 0)
+       nut_submit (ups, "frequency", "output", value);
+      else if (strcmp ("output.voltage", key) == 0)
+       nut_submit (ups, "voltage", "output", value);
+    }
+    else if (strncmp ("ups.", key, 4) == 0)
+    {
+      if (strcmp ("ups.load", key) == 0)
+       nut_submit (ups, "percent", "load", value);
+      else if (strcmp ("ups.power", key) == 0)
+       nut_submit (ups, "power", "ups", value);
+      else if (strcmp ("ups.temperature", key) == 0)
+       nut_submit (ups, "temperature", "ups", value);
+    }
+  } /* while (upscli_list_next) */
+
+  return (0);
+} /* int nut_read_one */
+
+static int nut_read (void)
+{
+  nut_ups_t *ups;
+  int success = 0;
+
+  pthread_mutex_lock (&read_lock);
+  success = read_busy;
+  read_busy = 1;
+  pthread_mutex_unlock (&read_lock);
+
+  if (success != 0)
+    return (0);
+
+  for (ups = upslist_head; ups != NULL; ups = ups->next)
+    if (nut_read_one (ups) == 0)
+      success++;
+
+  pthread_mutex_lock (&read_lock);
+  read_busy = 0;
+  pthread_mutex_unlock (&read_lock);
+
+  return ((success != 0) ? 0 : -1);
+} /* int nut_read */
+#endif /* NUT_HAVE_READ */
+
+static int nut_shutdown (void)
+{
+  nut_ups_t *this;
+  nut_ups_t *next;
+
+  this = upslist_head;
+  while (this != NULL)
+  {
+    next = this->next;
+    free_nut_ups_t (this);
+    this = next;
+  }
+
+  return (0);
+} /* int nut_shutdown */
+
+void module_register (modreg_e load)
+{
+  if (load & MR_DATASETS)
+  {
+    plugin_register_data_set (&ds_current);
+    plugin_register_data_set (&ds_humidity);
+    plugin_register_data_set (&ds_power);
+    plugin_register_data_set (&ds_voltage);
+    plugin_register_data_set (&ds_percent);
+    plugin_register_data_set (&ds_timeleft);
+    plugin_register_data_set (&ds_temperature);
+    plugin_register_data_set (&ds_frequency);
+  }
+
+#if NUT_HAVE_READ
+  if (load & MR_READ)
+  {
+    plugin_register_config ("nut", nut_config, config_keys, config_keys_num);
+    plugin_register_read ("nut", nut_read);
+    plugin_register_shutdown ("nut", nut_shutdown);
+  }
+#endif
+} /* void module_register */
+
+/* vim: set sw=2 ts=8 sts=2 tw=78 : */
index 2a2f03e..6dcd9ec 100644 (file)
@@ -4,8 +4,7 @@
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
 #include "common.h"
 #include "plugin.h"
 #include "configfile.h"
-#include "utils_debug.h"
-
-#define MODULE_NAME "ping"
 
 #include <netinet/in.h>
 #include "liboping/oping.h"
 
+/*
+ * Private data types
+ */
 struct hostlist_s
 {
        char *host;
@@ -40,19 +39,23 @@ struct hostlist_s
 };
 typedef struct hostlist_s hostlist_t;
 
+/*
+ * Private variables
+ */
 static pingobj_t *pingobj = NULL;
 static hostlist_t *hosts = NULL;
 
-static char *file_template = "ping-%s.rrd";
+static data_source_t dsrc[1] =
+{
+       {"ping", DS_TYPE_GAUGE, 0, 65535.0},
+};
 
-static char *ds_def[] = 
+static data_set_t ds =
 {
-       "DS:ping:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
-       NULL
+       "ping", 1, dsrc
 };
-static int ds_num = 1;
 
-static char *config_keys[] =
+static const char *config_keys[] =
 {
        "Host",
        "TTL",
@@ -60,25 +63,26 @@ static char *config_keys[] =
 };
 static int config_keys_num = 2;
 
+/*
+ * Private functions
+ */
 static void add_hosts (void)
 {
        hostlist_t *hl_this;
        hostlist_t *hl_prev;
 
-       int step = atoi (COLLECTD_STEP);
-
        hl_this = hosts;
        hl_prev = NULL;
        while (hl_this != NULL)
        {
-               DBG ("host = %s, wait_left = %i, wait_time = %i, next = %p",
+               DEBUG ("host = %s, wait_left = %i, wait_time = %i, next = %p",
                                hl_this->host, hl_this->wait_left, hl_this->wait_time, (void *) hl_this->next);
 
                if (hl_this->wait_left <= 0)
                {
                        if (ping_host_add (pingobj, hl_this->host) == 0)
                        {
-                               DBG ("Successfully added host %s", hl_this->host);
+                               DEBUG ("Successfully added host %s", hl_this->host);
                                /* Remove the host from the linked list */
                                if (hl_prev != NULL)
                                        hl_prev->next = hl_this->next;
@@ -98,7 +102,7 @@ static void add_hosts (void)
                }
                else
                {
-                       hl_this->wait_left -= step;
+                       hl_this->wait_left -= interval_g;
                }
 
                if (hl_this != NULL)
@@ -109,19 +113,21 @@ static void add_hosts (void)
        }
 }
 
-static void ping_init (void)
+static int ping_init (void)
 {
        if (hosts != NULL)
                add_hosts ();
+
+       return (0);
 }
 
-static int ping_config (char *key, char *value)
+static int ping_config (const char *key, const char *value)
 {
        if (pingobj == NULL)
        {
                if ((pingobj = ping_construct ()) == NULL)
                {
-                       syslog (LOG_ERR, "ping: `ping_construct' failed: %s",
+                       ERROR ("ping: `ping_construct' failed: %s",
                                        ping_get_error (pingobj));
                        return (1);
                }
@@ -131,24 +137,27 @@ static int ping_config (char *key, char *value)
        {
                hostlist_t *hl;
                char *host;
-               int step = atoi (COLLECTD_STEP);
 
                if ((hl = (hostlist_t *) malloc (sizeof (hostlist_t))) == NULL)
                {
-                       syslog (LOG_ERR, "ping plugin: malloc failed: %s",
-                                       strerror (errno));
+                       char errbuf[1024];
+                       ERROR ("ping plugin: malloc failed: %s",
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        return (1);
                }
                if ((host = strdup (value)) == NULL)
                {
+                       char errbuf[1024];
                        free (hl);
-                       syslog (LOG_ERR, "ping plugin: strdup failed: %s",
-                                       strerror (errno));
+                       ERROR ("ping plugin: strdup failed: %s",
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
                        return (1);
                }
 
                hl->host = host;
-               hl->wait_time = 2 * step;
+               hl->wait_time = 2 * interval_g;
                hl->wait_left = 0;
                hl->next = hosts;
                hosts = hl;
@@ -158,7 +167,7 @@ static int ping_config (char *key, char *value)
                int ttl = atoi (value);
                if (ping_setopt (pingobj, PING_DEF_TIMEOUT, (void *) &ttl))
                {
-                       syslog (LOG_WARNING, "ping: liboping did not accept the TTL value %i", ttl);
+                       WARNING ("ping: liboping did not accept the TTL value %i", ttl);
                        return (1);
                }
        }
@@ -170,33 +179,25 @@ static int ping_config (char *key, char *value)
        return (0);
 }
 
-static void ping_write (char *host, char *inst, char *val)
-{
-       char file[512];
-       int status;
-
-       status = snprintf (file, 512, file_template, inst);
-       if (status < 1)
-               return;
-       else if (status >= 512)
-               return;
-
-       rrd_update_file (host, file, val, ds_def, ds_num);
-}
-
-#define BUFSIZE 256
 static void ping_submit (char *host, double latency)
 {
-       char buf[BUFSIZE];
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
+
+       values[0].gauge = latency;
 
-       if (snprintf (buf, BUFSIZE, "%u:%f", (unsigned int) curtime, latency) >= BUFSIZE)
-               return;
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "ping");
+       strcpy (vl.plugin_instance, "");
+       strncpy (vl.type_instance, host, sizeof (vl.type_instance));
 
-       plugin_submit (MODULE_NAME, host, buf);
+       plugin_dispatch_values ("ping", &vl);
 }
-#undef BUFSIZE
 
-static void ping_read (void)
+static int ping_read (void)
 {
        pingobj_iter_t *iter;
 
@@ -205,16 +206,16 @@ static void ping_read (void)
        size_t buf_len;
 
        if (pingobj == NULL)
-               return;
+               return (-1);
 
        if (hosts != NULL)
                add_hosts ();
 
        if (ping_send (pingobj) < 0)
        {
-               syslog (LOG_ERR, "ping: `ping_send' failed: %s",
+               ERROR ("ping: `ping_send' failed: %s",
                                ping_get_error (pingobj));
-               return;
+               return (-1);
        }
 
        for (iter = ping_iterator_get (pingobj);
@@ -231,15 +232,23 @@ static void ping_read (void)
                                        &latency, &buf_len))
                        continue;
 
-               DBG ("host = %s, latency = %f", host, latency);
+               DEBUG ("host = %s, latency = %f", host, latency);
                ping_submit (host, latency);
        }
-}
 
-void module_register (void)
+       return (0);
+} /* int ping_read */
+
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, ping_init, ping_read, ping_write);
-       cf_register (MODULE_NAME, ping_config, config_keys, config_keys_num);
-}
+       if (load & MR_DATASETS)
+               plugin_register_data_set (&ds);
 
-#undef MODULE_NAME
+       if (load & MR_READ)
+       {
+               plugin_register_config ("ping", ping_config,
+                               config_keys, config_keys_num);
+               plugin_register_init ("ping", ping_init);
+               plugin_register_read ("ping", ping_read);
+       }
+} /* void module_register */
index d708b6b..c6762de 100644 (file)
@@ -4,8 +4,7 @@
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
 
 #include <ltdl.h>
 
+#if HAVE_PTHREAD_H
+# include <pthread.h>
+#endif
+
+#include "common.h"
 #include "plugin.h"
-#include "network.h"
-#include "utils_debug.h"
+#include "configfile.h"
+#include "utils_llist.h"
 
-typedef struct plugin
+/*
+ * Private structures
+ */
+struct read_func_s
 {
-       char *type;
-       void (*init) (void);
-       void (*read) (void);
-       void (*write) (char *host, char *inst, char *val);
-       void (*shutdown) (void);
-       struct plugin *next;
-} plugin_t;
+       int wait_time;
+       int wait_left;
+       int (*callback) (void);
+       enum { DONE = 0, TODO = 1, ACTIVE = 2 } needs_read;
+};
+typedef struct read_func_s read_func_t;
 
-static plugin_t *first_plugin = NULL;
-
-extern int operating_mode;
+/*
+ * Private variables
+ */
+static llist_t *list_init;
+static llist_t *list_read;
+static llist_t *list_write;
+static llist_t *list_shutdown;
+static llist_t *list_data_set;
+static llist_t *list_log;
 
 static char *plugindir = NULL;
 
-char *plugin_get_dir (void)
+static int             read_loop = 1;
+static pthread_mutex_t read_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t  read_cond = PTHREAD_COND_INITIALIZER;
+static pthread_t      *read_threads = NULL;
+static int             read_threads_num = 0;
+
+/*
+ * Static functions
+ */
+static const char *plugin_get_dir (void)
 {
        if (plugindir == NULL)
                return (PLUGINDIR);
@@ -52,71 +73,57 @@ char *plugin_get_dir (void)
                return (plugindir);
 }
 
-void plugin_set_dir (const char *dir)
+static int register_callback (llist_t **list, const char *name, void *callback)
 {
-       if (plugindir != NULL)
-               free (plugindir);
+       llentry_t *le;
 
-       if (dir == NULL)
-               plugindir = NULL;
-       else if ((plugindir = strdup (dir)) == NULL)
-               syslog (LOG_ERR, "strdup: %s", strerror (errno));
-}
+       if ((*list == NULL)
+                       && ((*list = llist_create ()) == NULL))
+               return (-1);
 
-/*
- * Returns the number of plugins registered
- */
-int plugin_count (void)
-{
-       int i;
-       plugin_t *p;
+       le = llist_search (*list, name);
+       if (le == NULL)
+       {
+               le = llentry_create (name, callback);
+               if (le == NULL)
+                       return (-1);
 
-       for (i = 0, p = first_plugin; p != NULL; p = p->next)
-               i++;
+               llist_append (*list, le);
+       }
+       else
+       {
+               le->value = callback;
+       }
 
-       return (i);
-}
+       return (0);
+} /* int register_callback */
 
-/*
- * Returns the plugins with the type `type' or NULL if it's not found.
- */
-plugin_t *plugin_search (const char *type)
+static int plugin_unregister (llist_t *list, const char *name)
 {
-       plugin_t *ret;
+       llentry_t *e;
 
-       if (type == NULL)
-               return (NULL);
+       e = llist_search (list, name);
 
-       for (ret = first_plugin; ret != NULL; ret = ret->next)
-               if (strcmp (ret->type, type) == 0)
-                       break;
+       if (e == NULL)
+               return (-1);
 
-       return (ret);
-}
+       llist_remove (list, e);
+       llentry_destroy (e);
 
-/*
- * Returns true if the plugin is loaded (i.e. `exists') and false otherwise.
- * This is used in `configfile.c' to skip sections that are not needed..
- */
-int plugin_exists (char *type)
-{
-       if (plugin_search (type) == NULL)
-               return (0);
-       else
-               return (1);
-}
+       return (0);
+} /* int plugin_unregister */
 
 /*
  * (Try to) load the shared object `file'. Won't complain if it isn't a shared
  * object, but it will bitch about a shared object not having a
  * ``module_register'' symbol..
  */
-int plugin_load_file (char *file)
+static int plugin_load_file (char *file, modreg_e load)
 {
        lt_dlhandle dlh;
-       void (*reg_handle) (void);
+       void (*reg_handle) (modreg_e mr);
 
-       DBG ("file = %s", file);
+       DEBUG ("file = %s", file);
 
        lt_dlinit ();
        lt_dlerror (); /* clear errors */
@@ -125,29 +132,169 @@ int plugin_load_file (char *file)
        {
                const char *error = lt_dlerror ();
 
-               syslog (LOG_ERR, "lt_dlopen failed: %s", error);
-               DBG ("lt_dlopen failed: %s", error);
+               ERROR ("lt_dlopen failed: %s", error);
+               DEBUG ("lt_dlopen failed: %s", error);
                return (1);
        }
 
-       if ((reg_handle = (void (*) (void)) lt_dlsym (dlh, "module_register")) == NULL)
+       if ((reg_handle = (void (*) (modreg_e)) lt_dlsym (dlh, "module_register")) == NULL)
        {
-               syslog (LOG_WARNING, "Couldn't find symbol ``module_register'' in ``%s'': %s\n",
+               WARNING ("Couldn't find symbol ``module_register'' in ``%s'': %s\n",
                                file, lt_dlerror ());
                lt_dlclose (dlh);
                return (-1);
        }
 
-       (*reg_handle) ();
+       (*reg_handle) (load);
 
        return (0);
 }
 
+static void *plugin_read_thread (void *args)
+{
+       llentry_t   *le;
+       read_func_t *rf;
+       int          status;
+       int          done;
+
+       pthread_mutex_lock (&read_lock);
+
+       while (read_loop != 0)
+       {
+               le = llist_head (list_read);
+               done = 0;
+
+               while ((read_loop != 0) && (le != NULL))
+               {
+                       rf = (read_func_t *) le->value;
+
+                       if (rf->needs_read != TODO)
+                       {
+                               le = le->next;
+                               continue;
+                       }
+
+                       /* We will do this read function */
+                       rf->needs_read = ACTIVE;
+
+                       DEBUG ("[thread #%5lu] plugin: plugin_read_thread: Handling %s",
+                                       (unsigned long int) pthread_self (), le->key);
+                       pthread_mutex_unlock (&read_lock);
+
+                       status = rf->callback ();
+                       done++;
+
+                       if (status != 0)
+                       {
+                               rf->wait_left = rf->wait_time;
+                               rf->wait_time = rf->wait_time * 2;
+                               if (rf->wait_time > 86400)
+                                       rf->wait_time = 86400;
+
+                               NOTICE ("read-function of plugin `%s' "
+                                               "failed. Will syspend it for %i "
+                                               "seconds.", le->key, rf->wait_left);
+                       }
+                       else
+                       {
+                               rf->wait_left = 0;
+                               rf->wait_time = interval_g;
+                       }
+
+                       pthread_mutex_lock (&read_lock);
+
+                       rf->needs_read = DONE;
+                       le = le->next;
+               } /* while (le != NULL) */
+
+               if ((read_loop != 0) && (done == 0))
+               {
+                       DEBUG ("[thread #%5lu] plugin: plugin_read_thread: Waiting on read_cond.",
+                                       (unsigned long int) pthread_self ());
+                       pthread_cond_wait (&read_cond, &read_lock);
+               }
+       } /* while (read_loop) */
+
+       pthread_mutex_unlock (&read_lock);
+
+       pthread_exit (NULL);
+} /* void *plugin_read_thread */
+
+static void start_threads (int num)
+{
+       int i;
+
+       if (read_threads != NULL)
+               return;
+
+       read_threads = (pthread_t *) calloc (num, sizeof (pthread_t));
+       if (read_threads == NULL)
+       {
+               ERROR ("plugin: start_threads: calloc failed.");
+               return;
+       }
+
+       read_threads_num = 0;
+       for (i = 0; i < num; i++)
+       {
+               if (pthread_create (read_threads + read_threads_num, NULL,
+                                       plugin_read_thread, NULL) == 0)
+               {
+                       read_threads_num++;
+               }
+               else
+               {
+                       ERROR ("plugin: start_threads: pthread_create failed.");
+                       return;
+               }
+       } /* for (i) */
+} /* void start_threads */
+
+static void stop_threads (void)
+{
+       int i;
+
+       pthread_mutex_lock (&read_lock);
+       read_loop = 0;
+       DEBUG ("plugin: stop_threads: Signalling `read_cond'");
+       pthread_cond_broadcast (&read_cond);
+       pthread_mutex_unlock (&read_lock);
+
+       for (i = 0; i < read_threads_num; i++)
+       {
+               if (pthread_join (read_threads[i], NULL) != 0)
+               {
+                       ERROR ("plugin: stop_threads: pthread_join failed.");
+               }
+               read_threads[i] = -1;
+       }
+       sfree (read_threads);
+       read_threads_num = 0;
+} /* void stop_threads */
+
+/*
+ * Public functions
+ */
+void plugin_set_dir (const char *dir)
+{
+       if (plugindir != NULL)
+               free (plugindir);
+
+       if (dir == NULL)
+               plugindir = NULL;
+       else if ((plugindir = strdup (dir)) == NULL)
+       {
+               char errbuf[1024];
+               ERROR ("strdup failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+       }
+}
+
 #define BUFSIZE 512
-int plugin_load (const char *type)
+int plugin_load (const char *type, modreg_e mr)
 {
        DIR  *dh;
-       char *dir;
+       const char *dir;
        char  filename[BUFSIZE];
        char  typename[BUFSIZE];
        int   typename_len;
@@ -155,27 +302,25 @@ int plugin_load (const char *type)
        struct stat    statbuf;
        struct dirent *de;
 
-       DBG ("type = %s", type);
+       DEBUG ("type = %s", type);
 
        dir = plugin_get_dir ();
        ret = 1;
 
-       /* don't load twice */
-       if (plugin_search (type) != NULL)
-               return (0);
-
        /* `cpu' should not match `cpufreq'. To solve this we add `.so' to the
         * type when matching the filename */
        if (snprintf (typename, BUFSIZE, "%s.so", type) >= BUFSIZE)
        {
-               syslog (LOG_WARNING, "snprintf: truncated: `%s.so'", type);
+               WARNING ("snprintf: truncated: `%s.so'", type);
                return (-1);
        }
        typename_len = strlen (typename);
 
        if ((dh = opendir (dir)) == NULL)
        {
-               syslog (LOG_ERR, "opendir (%s): %s", dir, strerror (errno));
+               char errbuf[1024];
+               ERROR ("opendir (%s): %s", dir,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                return (-1);
        }
 
@@ -186,13 +331,15 @@ int plugin_load (const char *type)
 
                if (snprintf (filename, BUFSIZE, "%s/%s", dir, de->d_name) >= BUFSIZE)
                {
-                       syslog (LOG_WARNING, "snprintf: truncated: `%s/%s'", dir, de->d_name);
+                       WARNING ("snprintf: truncated: `%s/%s'", dir, de->d_name);
                        continue;
                }
 
                if (lstat (filename, &statbuf) == -1)
                {
-                       syslog (LOG_WARNING, "stat %s: %s", filename, strerror (errno));
+                       char errbuf[1024];
+                       WARNING ("stat %s: %s", filename,
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
                        continue;
                }
                else if (!S_ISREG (statbuf.st_mode))
@@ -201,7 +348,7 @@ int plugin_load (const char *type)
                        continue;
                }
 
-               if (plugin_load_file (filename) == 0)
+               if (plugin_load_file (filename, mr) == 0)
                {
                        /* success */
                        ret = 0;
@@ -215,189 +362,280 @@ int plugin_load (const char *type)
 }
 
 /*
- * (Try to) load all plugins in `dir'. Returns the number of loaded plugins..
+ * The `register_*' functions follow
  */
-int plugin_load_all (char *dir)
+int plugin_register_config (const char *name,
+               int (*callback) (const char *key, const char *val),
+               const char **keys, int keys_num)
 {
-       DIR *dh;
-       struct dirent *de;
-       char filename[BUFSIZE];
-       struct stat statbuf;
+       cf_register (name, callback, keys, keys_num);
+       return (0);
+} /* int plugin_register_config */
 
-       if (dir == NULL)
-               dir = plugin_get_dir ();
-       else
-               plugin_set_dir (dir);
+int plugin_register_init (const char *name,
+               int (*callback) (void))
+{
+       return (register_callback (&list_init, name, (void *) callback));
+} /* plugin_register_init */
 
-       if ((dh = opendir (dir)) == NULL)
+int plugin_register_read (const char *name,
+               int (*callback) (void))
+{
+       read_func_t *rf;
+
+       rf = (read_func_t *) malloc (sizeof (read_func_t));
+       if (rf == NULL)
        {
-               syslog (LOG_ERR, "opendir (%s): %s", dir, strerror (errno));
-               return (0);
+               char errbuf[1024];
+               ERROR ("plugin_register_read: malloc failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
        }
 
-       while ((de = readdir (dh)) != NULL)
-       {
-               if (snprintf (filename, BUFSIZE, "%s/%s", dir, de->d_name) >= BUFSIZE)
-               {
-                       syslog (LOG_WARNING, "snprintf: truncated: %s/%s", dir, de->d_name);
-                       continue;
-               }
+       memset (rf, '\0', sizeof (read_func_t));
+       rf->wait_time = interval_g;
+       rf->wait_left = 0;
+       rf->callback = callback;
+       rf->needs_read = DONE;
 
-               if (lstat (filename, &statbuf) == -1)
-               {
-                       syslog (LOG_WARNING, "stat %s: %s", filename, strerror (errno));
-                       continue;
-               }
-               else if (!S_ISREG (statbuf.st_mode))
-               {
-                       continue;
-               }
+       return (register_callback (&list_read, name, (void *) rf));
+} /* int plugin_register_read */
 
-               plugin_load_file (filename);
-       }
+int plugin_register_write (const char *name,
+               int (*callback) (const data_set_t *ds, const value_list_t *vl))
+{
+       return (register_callback (&list_write, name, (void *) callback));
+} /* int plugin_register_write */
 
-       closedir (dh);
+int plugin_register_shutdown (char *name,
+               int (*callback) (void))
+{
+       return (register_callback (&list_shutdown, name, (void *) callback));
+} /* int plugin_register_shutdown */
+
+int plugin_register_data_set (const data_set_t *ds)
+{
+       return (register_callback (&list_data_set, ds->type, (void *) ds));
+} /* int plugin_register_data_set */
+
+int plugin_register_log (char *name,
+               void (*callback) (int priority, const char *msg))
+{
+       return (register_callback (&list_log, name, (void *) callback));
+} /* int plugin_register_log */
 
-       return (plugin_count ());
+int plugin_unregister_config (const char *name)
+{
+       cf_unregister (name);
+       return (0);
+} /* int plugin_unregister_config */
+
+int plugin_unregister_init (const char *name)
+{
+       return (plugin_unregister (list_init, name));
 }
-#undef BUFSIZE
 
-/*
- * Call `init' on all plugins (if given)
- */
-void plugin_init_all (void)
+int plugin_unregister_read (const char *name)
 {
-       plugin_t *p;
+       return (plugin_unregister (list_read, name));
+       llentry_t *e;
 
-       for (p = first_plugin; p != NULL; p = p->next)
-               if (p->init != NULL)
-                       (*p->init) ();
+       e = llist_search (list_read, name);
+
+       if (e == NULL)
+               return (-1);
+
+       llist_remove (list_read, e);
+       free (e->value);
+       llentry_destroy (e);
+
+       return (0);
 }
 
-/*
- * Call `read' on all plugins (if given)
- */
-void plugin_read_all (const int *loop)
+int plugin_unregister_write (const char *name)
 {
-       plugin_t *p;
+       return (plugin_unregister (list_write, name));
+}
 
-       for (p = first_plugin; (*loop == 0) && (p != NULL); p = p->next)
-               if (p->read != NULL)
-                       (*p->read) ();
+int plugin_unregister_shutdown (const char *name)
+{
+       return (plugin_unregister (list_shutdown, name));
 }
 
-/*
- * Call `shutdown' on all plugins (if given)
- */
-void plugin_shutdown_all (void)
+int plugin_unregister_data_set (const char *name)
 {
-       plugin_t *p;
+       return (plugin_unregister (list_data_set, name));
+}
 
-       for (p = first_plugin; NULL != p; p = p->next)
-               if (NULL != p->shutdown)
-                       (*p->shutdown) ();
-       return;
+int plugin_unregister_log (const char *name)
+{
+       return (plugin_unregister (list_log, name));
 }
 
-/*
- * Add plugin to the linked list of registered plugins.
- */
-void plugin_register (char *type,
-               void (*init) (void),
-               void (*read) (void),
-               void (*write) (char *, char *, char *))
+void plugin_init_all (void)
 {
-       plugin_t *p;
+       int (*callback) (void);
+       llentry_t *le;
+       int status;
+
+       /* Start read-threads */
+       if (list_read != NULL)
+       {
+               const char *rt;
+               int num;
+               rt = global_option_get ("ReadThreads");
+               num = atoi (rt);
+               start_threads ((num > 0) ? num : 5);
+       }
 
-       if (plugin_search (type) != NULL)
+       if (list_init == NULL)
                return;
 
-#ifdef HAVE_LIBRRD
-       if (operating_mode != MODE_SERVER)
-#endif
-               if ((init != NULL) && (read == NULL))
-                       syslog (LOG_NOTICE, "Plugin `%s' doesn't provide a read function.", type);
+       le = llist_head (list_init);
+       while (le != NULL)
+       {
+               callback = le->value;
+               status = (*callback) ();
+
+               if (status != 0)
+               {
+                       ERROR ("Initialization of plugin `%s' "
+                                       "failed with status %i. "
+                                       "Plugin will be unloaded. TODO!",
+                                       le->key, status);
+                       plugin_unregister_read (le->key);
+               }
+
+               le = le->next;
+       }
+} /* void plugin_init_all */
 
-       if ((p = (plugin_t *) malloc (sizeof (plugin_t))) == NULL)
+void plugin_read_all (const int *loop)
+{
+       llentry_t   *le;
+       read_func_t *rf;
+
+       if (list_read == NULL)
                return;
 
-       if ((p->type = strdup (type)) == NULL)
+       pthread_mutex_lock (&read_lock);
+
+       le = llist_head (list_read);
+       while (le != NULL)
        {
-               free (p);
-               return;
+               rf = (read_func_t *) le->value;
+
+               if (rf->needs_read != DONE)
+                       continue;
+
+               if (rf->wait_left > 0)
+                       rf->wait_left -= interval_g;
+
+               if (rf->wait_left <= 0)
+               {
+                       rf->needs_read = TODO;
+               }
+
+               le = le->next;
        }
 
-       p->init  = init;
-       p->read  = read;
-       p->write = write;
+       DEBUG ("plugin: plugin_read_all: Signalling `read_cond'");
+       pthread_cond_broadcast (&read_cond);
+       pthread_mutex_unlock (&read_lock);
+} /* void plugin_read_all */
+
+void plugin_shutdown_all (void)
+{
+       int (*callback) (void);
+       llentry_t *le;
 
-       p->shutdown = NULL;
+       stop_threads ();
 
-       p->next = first_plugin;
-       first_plugin = p;
-}
+       if (list_shutdown == NULL)
+               return;
 
-/*
- * Register the shutdown function (optional).
- */
-int plugin_register_shutdown (char *type, void (*shutdown) (void))
+       le = llist_head (list_shutdown);
+       while (le != NULL)
+       {
+               callback = le->value;
+               (*callback) ();
+
+               le = le->next;
+       }
+} /* void plugin_shutdown_all */
+
+int plugin_dispatch_values (const char *name, const value_list_t *vl)
 {
-       plugin_t *p = plugin_search (type);
+       int (*callback) (const data_set_t *, const value_list_t *);
+       data_set_t *ds;
+       llentry_t *le;
+
+       if (list_write == NULL)
+               return (-1);
+
+       le = llist_search (list_data_set, name);
+       if (le == NULL)
+       {
+               DEBUG ("No such dataset registered: %s", name);
+               return (-1);
+       }
+
+       ds = (data_set_t *) le->value;
+
+       DEBUG ("plugin: plugin_dispatch_values: time = %u; host = %s; "
+                       "plugin = %s; plugin_instance = %s; type = %s; "
+                       "type_instance = %s;",
+                       (unsigned int) vl->time, vl->host,
+                       vl->plugin, vl->plugin_instance,
+                       ds->type, vl->type_instance);
 
-       if (NULL == p)
-               return -1;
+       le = llist_head (list_write);
+       while (le != NULL)
+       {
+               callback = le->value;
+               (*callback) (ds, vl);
+
+               le = le->next;
+       }
 
-       p->shutdown = shutdown;
-       return 0;
+       return (0);
 }
 
-/*
- * Send received data back to the plugin/module which will append DS
- * definitions and pass it on to ``rrd_update_file''.
- */
-void plugin_write (char *host, char *type, char *inst, char *val)
+void plugin_log (int level, const char *format, ...)
 {
-       plugin_t *p;
+       char msg[512];
+       va_list ap;
 
-       if ((p = plugin_search (type)) == NULL)
-               return;
+       void (*callback) (int, const char *);
+       llentry_t *le;
 
-       if (p->write == NULL)
+       if (list_log == NULL)
                return;
 
-       (*p->write) (host, inst, val);
-}
+#if !COLLECT_DEBUG
+       if (level >= LOG_DEBUG)
+               return;
+#endif
 
-/*
- * Receive data from the plugin/module and get it somehow to ``plugin_write'':
- * Either using ``network_send'' (when in network/client mode) or call it
- * directly (in local mode).
- */
-void plugin_submit (char *type, char *inst, char *val)
-{
-       if (inst == NULL)
-               inst = "-";
+       va_start (ap, format);
+       vsnprintf (msg, 512, format, ap);
+       msg[511] = '\0';
+       va_end (ap);
 
-       if ((type == NULL) || (val == NULL))
+       le = llist_head (list_log);
+       while (le != NULL)
        {
-               DBG ("Help! NULL-pointer! type = %s; inst = %s; val = %s;",
-                               (type == NULL) ? "(null)" : type,
-                               inst,
-                               (val == NULL) ? "(null)" : val);
-               return;
-       }
+               callback = le->value;
+               (*callback) (level, msg);
 
-        if (operating_mode == MODE_CLIENT)
-               network_send (type, inst, val);
-       else
-               plugin_write (NULL, type, inst, val);
-}
+               le = le->next;
+       }
+} /* void plugin_log */
 
 void plugin_complain (int level, complain_t *c, const char *format, ...)
 {
        char message[512];
        va_list ap;
-       int step;
 
        if (c->delay > 0)
        {
@@ -405,25 +643,22 @@ void plugin_complain (int level, complain_t *c, const char *format, ...)
                return;
        }
 
-       step = atoi (COLLECTD_STEP);
-       assert (step > 0);
-
-       if (c->interval < step)
-               c->interval = step;
+       if (c->interval < interval_g)
+               c->interval = interval_g;
        else
                c->interval *= 2;
 
        if (c->interval > 86400)
                c->interval = 86400;
 
-       c->delay = c->interval / step;
+       c->delay = c->interval / interval_g;
 
        va_start (ap, format);
        vsnprintf (message, 512, format, ap);
        message[511] = '\0';
        va_end (ap);
 
-       syslog (level, message);
+       plugin_log (level, message);
 }
 
 void plugin_relief (int level, complain_t *c, const char *format, ...)
@@ -441,5 +676,22 @@ void plugin_relief (int level, complain_t *c, const char *format, ...)
        message[511] = '\0';
        va_end (ap);
 
-       syslog (level, message);
+       plugin_log (level, message);
 }
+
+const data_set_t *plugin_get_ds (const char *name)
+{
+       data_set_t *ds;
+       llentry_t *le;
+
+       le = llist_search (list_data_set, name);
+       if (le == NULL)
+       {
+               DEBUG ("No such dataset registered: %s", name);
+               return (NULL);
+       }
+
+       ds = (data_set_t *) le->value;
+
+       return (ds);
+} /* data_set_t *plugin_get_ds */
index 45e9b49..0164e9c 100644 (file)
@@ -7,8 +7,7 @@
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  *   Florian octo Forster <octo at verplant.org>
  **/
 
+#define DATA_MAX_NAME_LEN 64
+
+#define DS_TYPE_COUNTER 0
+#define DS_TYPE_GAUGE   1
+
+#ifndef LOG_ERR
+# define LOG_ERR 3
+#endif
+#ifndef LOG_WARNING
+# define LOG_WARNING 4
+#endif
+#ifndef LOG_NOTICE
+# define LOG_NOTICE 5
+#endif
+#ifndef LOG_INFO
+# define LOG_INFO 6
+#endif
+#ifndef LOG_DEBUG
+# define LOG_DEBUG 7
+#endif
+
 /*
- *
+ * Public data types
  */
+enum modreg
+{
+       MR_EVERYTHING = 7,
+       MR_DATASETS   = 1,
+       MR_READ       = 2,
+       MR_WRITE      = 4
+};
+typedef enum modreg modreg_e;
+
+typedef unsigned long long counter_t;
+typedef double gauge_t;
+
+union value_u
+{
+       counter_t counter;
+       gauge_t   gauge;
+};
+typedef union value_u value_t;
+
+struct value_list_s
+{
+       value_t *values;
+       int      values_len;
+       time_t   time;
+       char     host[DATA_MAX_NAME_LEN];
+       char     plugin[DATA_MAX_NAME_LEN];
+       char     plugin_instance[DATA_MAX_NAME_LEN];
+       char     type_instance[DATA_MAX_NAME_LEN];
+};
+typedef struct value_list_s value_list_t;
+
+#define VALUE_LIST_INIT { NULL, 0, 0, "localhost", "", "", "" }
+
+struct data_source_s
+{
+       char   name[DATA_MAX_NAME_LEN];
+       int    type;
+       double min;
+       double max;
+};
+typedef struct data_source_s data_source_t;
+
+struct data_set_s
+{
+       char           type[DATA_MAX_NAME_LEN];
+       int            ds_num;
+       data_source_t *ds;
+};
+typedef struct data_set_s data_set_t;
+
 typedef struct complain_s
 {
        unsigned int interval; /* how long we wait for reporting this error again */
@@ -49,34 +119,6 @@ void plugin_set_dir (const char *dir);
 
 /*
  * NAME
- *  plugin_count
- *
- * DESCRIPTION
- *  trivial
- *
- * RETURN VALUE
- *  The number of currently loaded plugins
- */
-int plugin_count (void);
-
-/*
- * NAME
- *  plugin_exists
- *
- * DESCRIPTION
- *  trivial
- *
- * ARGUMENTS
- *  `type'      Name of the plugin.
- *
- * RETURN VALUE
- *  Returns non-zero if a plugin with the name $type is found and zero
- *  otherwise.
- */
-int plugin_exists (char *type);
-
-/*
- * NAME
  *  plugin_load
  *
  * DESCRIPTION
@@ -86,7 +128,8 @@ int plugin_exists (char *type);
  *  functions.
  *
  * ARGUMENTS
- *  `type'      Name of the plugin to load.
+ *  `name'      Name of the plugin to load.
+ *  `mr'        Types of functions to request from the plugin.
  *
  * RETURN VALUE
  *  Returns zero upon success, a value greater than zero if no plugin was found
@@ -95,43 +138,68 @@ int plugin_exists (char *type);
  * NOTES
  *  No attempt is made to re-load an already loaded module.
  */
-int  plugin_load (const char *type);
+int plugin_load (const char *name, modreg_e mr);
 
-int  plugin_load_all (char *dir);
 void plugin_init_all (void);
 void plugin_read_all (const int *loop);
-
 void plugin_shutdown_all (void);
 
-void plugin_register (char *type,
-               void (*init) (void),
-               void (*read) (void),
-               void (*write) (char *, char *, char *));
+/*
+ * The `plugin_register_*' functions are used to make `config', `init',
+ * `read', `write' and `shutdown' functions known to the plugin
+ * infrastructure. Also, the data-formats are made public like this.
+ */
+int plugin_register_config (const char *name,
+               int (*callback) (const char *key, const char *val),
+               const char **keys, int keys_num);
+int plugin_register_init (const char *name,
+               int (*callback) (void));
+int plugin_register_read (const char *name,
+               int (*callback) (void));
+int plugin_register_write (const char *name,
+               int (*callback) (const data_set_t *ds, const value_list_t *vl));
+int plugin_register_shutdown (char *name,
+               int (*callback) (void));
+int plugin_register_data_set (const data_set_t *ds);
+int plugin_register_log (char *name,
+               void (*callback) (int, const char *));
 
-int plugin_register_shutdown (char *, void (*) (void));
+int plugin_unregister_config (const char *name);
+int plugin_unregister_init (const char *name);
+int plugin_unregister_read (const char *name);
+int plugin_unregister_write (const char *name);
+int plugin_unregister_shutdown (const char *name);
+int plugin_unregister_data_set (const char *name);
+int plugin_unregister_log (const char *name);
 
 /*
  * NAME
- *  plugin_write
+ *  plugin_dispatch_values
  *
  * DESCRIPTION
- *  Searches the plugin for `type' in the plugin-list. If found, and a `write'
- *  function is registered, it's called. If either the plugin is not found or
- *  the plugin doesn't provide a `write' function this function will return
- *  without further notice.
+ *  This function is called by reading processes with the values they've
+ *  aquired. The function fetches the data-set definition (that has been
+ *  registered using `plugin_register_data_set') and calls _all_ registered
+ *  write-functions.
  *
  * ARGUMENTS
- *  `host'      Host(name) from which the data originates.
- *  `type'      Name of the plugin.
- *  `inst'      Instance (passed to the plugin's `write' function.
- *  `val'       Values for the RRD files. Also passed to the plugin.
+ *  `name'      Name/type of the data-set that describe the values in `vl'.
+ *  `vl'        Value list of the values that have been read by a `read'
+ *              function.
  */
-void plugin_write    (char *host, char *type, char *inst, char *val);
-
-void plugin_submit   (char *type, char *inst, char *val);
+int plugin_dispatch_values (const char *name, const value_list_t *vl);
 
+void plugin_log (int level, const char *format, ...);
+#define ERROR(...)   plugin_log (LOG_ERR,     __VA_ARGS__)
+#define WARNING(...) plugin_log (LOG_WARNING, __VA_ARGS__)
+#define NOTICE(...)  plugin_log (LOG_NOTICE,  __VA_ARGS__)
+#define INFO(...)    plugin_log (LOG_INFO,    __VA_ARGS__)
+#define DEBUG(...)   plugin_log (LOG_DEBUG,   __VA_ARGS__)
 
+/* TODO: Move plugin_{complain,relief} into `utils_complain.[ch]'. -octo */
 void plugin_complain (int level, complain_t *c, const char *format, ...);
 void plugin_relief (int level, complain_t *c, const char *format, ...);
 
+const data_set_t *plugin_get_ds (const char *name);
+
 #endif /* PLUGIN_H */
index 6898445..f57f2d3 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * collectd - src/processes.c
  * Copyright (C) 2005  Lyonel Vincent
- * Copyright (C) 2006  Florian Forster (Mach code)
+ * Copyright (C) 2006-2007  Florian Forster (Mach code)
  *
  * 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
@@ -25,7 +25,6 @@
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
-#include "utils_debug.h"
 #include "configfile.h"
 
 /* Include header files for the mach system, if they exist.. */
 
 #define BUFSIZE 256
 
-static char *processes_file = "processes.rrd";
-static char *processes_ds_def[] =
+static data_source_t state_dsrc[1] =
 {
-       "DS:running:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
-       "DS:sleeping:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
-       "DS:zombies:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
-       "DS:stopped:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
-       "DS:paging:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
-       "DS:blocked:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
-       NULL
+       {"value", DS_TYPE_GAUGE, 0.0, 65535.0}
 };
-static int processes_ds_num = 6;
 
-static char *ps_rss_file = "processes/ps_rss-%s.rrd";
-static char *ps_rss_ds_def[] =
+static data_set_t state_ds =
+{
+       "ps_state", 1, state_dsrc
+};
+
+static data_source_t rss_dsrc[1] =
 {
        /* max = 2^63 - 1 */
-       "DS:byte:GAUGE:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       NULL
+       {"value", DS_TYPE_GAUGE, 0.0, 9223372036854775807.0}
 };
-static int ps_rss_ds_num = 1;
 
-static char *ps_cputime_file = "processes/ps_cputime-%s.rrd";
-static char *ps_cputime_ds_def[] =
+static data_set_t rss_ds =
+{
+       "ps_rss", 1, rss_dsrc
+};
+
+static data_source_t time_dsrc[2] =
 {
        /* 1 second in user-mode per second ought to be enough.. */
-       "DS:user:COUNTER:"COLLECTD_HEARTBEAT":0:1000000",
-       "DS:syst:COUNTER:"COLLECTD_HEARTBEAT":0:1000000",
-       NULL
+       {"user", DS_TYPE_COUNTER, 0.0, 1000000.0},
+       {"syst", DS_TYPE_COUNTER, 0.0, 1000000.0}
 };
-static int ps_cputime_ds_num = 2;
 
-static char *ps_count_file = "processes/ps_count-%s.rrd";
-static char *ps_count_ds_def[] =
+static data_set_t time_ds =
 {
-       "DS:processes:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
-       "DS:threads:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
-       NULL
+       "ps_cputime", 2, time_dsrc
 };
-static int ps_count_ds_num = 2;
 
-static char *ps_pagefaults_file = "processes/ps_pagefaults-%s.rrd";
-static char *ps_pagefaults_ds_def[] =
+static data_source_t count_dsrc[2] =
+{
+       /* 1 second in user-mode per second ought to be enough.. */
+       {"processes", DS_TYPE_GAUGE, 0.0, 1000000.0},
+       {"threads",   DS_TYPE_GAUGE, 0.0, 1000000.0}
+};
+
+static data_set_t count_ds =
+{
+       "ps_count", 2, count_dsrc
+};
+
+static data_source_t pagefaults_dsrc[2] =
 {
        /* max = 2^63 - 1 */
-       "DS:minflt:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:majflt:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       NULL
+       {"minflt", DS_TYPE_COUNTER, 0.0, 9223372036854775807.0},
+       {"majflt", DS_TYPE_COUNTER, 0.0, 9223372036854775807.0}
 };
-static int ps_pagefaults_ds_num = 2;
 
+static data_set_t pagefaults_ds =
+{
+       "ps_pagefaults", 2, pagefaults_dsrc
+};
+
+#if PROCESSES_HAVE_READ
 #if HAVE_THREAD_INFO | KERNEL_LINUX
-static char *config_keys[] =
+static const char *config_keys[] =
 {
        "Process",
        NULL
@@ -381,7 +387,7 @@ static void ps_list_reset (void)
                {
                        if (pse->age > 10)
                        {
-                               DBG ("Removing this procstat entry cause it's too old: "
+                               DEBUG ("Removing this procstat entry cause it's too old: "
                                                "id = %lu; name = %s;",
                                                pse->id, ps->name);
 
@@ -408,7 +414,7 @@ static void ps_list_reset (void)
        } /* for (ps = list_head_g; ps != NULL; ps = ps->next) */
 }
 
-static int ps_config (char *key, char *value)
+static int ps_config (const char *key, const char *value)
 {
        if (strcasecmp (key, "Process") == 0)
        {
@@ -423,7 +429,7 @@ static int ps_config (char *key, char *value)
 }
 #endif /* HAVE_THREAD_INFO | KERNEL_LINUX */
 
-static void ps_init (void)
+static int ps_init (void)
 {
 #if HAVE_THREAD_INFO
        kern_return_t status;
@@ -444,149 +450,79 @@ static void ps_init (void)
                                        &pset_list,
                                        &pset_list_len)) != KERN_SUCCESS)
        {
-               syslog (LOG_ERR, "host_processor_sets failed: %s\n",
+               ERROR ("host_processor_sets failed: %s\n",
                                mach_error_string (status));
                pset_list = NULL;
                pset_list_len = 0;
-               return;
+               return (-1);
        }
 /* #endif HAVE_THREAD_INFO */
 
 #elif KERNEL_LINUX
        pagesize_g = sysconf(_SC_PAGESIZE);
-       DBG ("pagesize_g = %li; CONFIG_HZ = %i;",
+       DEBUG ("pagesize_g = %li; CONFIG_HZ = %i;",
                        pagesize_g, CONFIG_HZ);
 #endif /* KERNEL_LINUX */
 
-       return;
-}
-
-static void ps_write (char *host, char *inst, char *val)
-{
-       rrd_update_file (host, processes_file, val,
-                       processes_ds_def, processes_ds_num);
-}
-
-static void ps_rss_write (char *host, char *inst, char *val)
-{
-       char filename[256];
-       int status;
-
-       status = snprintf (filename, 256, ps_rss_file, inst);
-       if ((status < 1) || (status >= 256))
-               return;
-
-       rrd_update_file (host, filename, val, ps_rss_ds_def, ps_rss_ds_num);
-}
-
-static void ps_cputime_write (char *host, char *inst, char *val)
-{
-       char filename[256];
-       int status;
-
-       status = snprintf (filename, 256, ps_cputime_file, inst);
-       if ((status < 1) || (status >= 256))
-               return;
-
-       DBG ("host = %s; filename = %s; val = %s;",
-                       host, filename, val);
-       rrd_update_file (host, filename, val,
-                       ps_cputime_ds_def, ps_cputime_ds_num);
-}
-
-static void ps_count_write (char *host, char *inst, char *val)
-{
-       char filename[256];
-       int status;
-
-       status = snprintf (filename, 256, ps_count_file, inst);
-       if ((status < 1) || (status >= 256))
-               return;
-
-       DBG ("host = %s; filename = %s; val = %s;",
-                       host, filename, val);
-       rrd_update_file (host, filename, val,
-                       ps_count_ds_def, ps_count_ds_num);
-}
-
-static void ps_pagefaults_write (char *host, char *inst, char *val)
-{
-       char filename[256];
-       int status;
-
-       status = snprintf (filename, 256, ps_pagefaults_file, inst);
-       if ((status < 1) || (status >= 256))
-               return;
-
-       DBG ("host = %s; filename = %s; val = %s;",
-                       host, filename, val);
-       rrd_update_file (host, filename, val,
-                       ps_pagefaults_ds_def, ps_pagefaults_ds_num);
-}
+       return (0);
+} /* int ps_init */
 
-#if PROCESSES_HAVE_READ
-static void ps_submit (int running,
-               int sleeping,
-               int zombies,
-               int stopped,
-               int paging,
-               int blocked)
+static void ps_submit_state (const char *state, double value)
 {
-       char buf[BUFSIZE];
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       if (snprintf (buf, BUFSIZE, "%u:%i:%i:%i:%i:%i:%i",
-                               (unsigned int) curtime,
-                               running, sleeping, zombies, stopped, paging,
-                               blocked) >= BUFSIZE)
-               return;
+       values[0].gauge = value;
 
-       DBG ("running = %i; sleeping = %i; zombies = %i; stopped = %i; paging = %i; blocked = %i;",
-                       running, sleeping, zombies, stopped, paging, blocked);
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "processes");
+       strcpy (vl.plugin_instance, "");
+       strncpy (vl.type_instance, state, sizeof (vl.type_instance));
 
-       plugin_submit (MODULE_NAME, "-", buf);
+       plugin_dispatch_values ("ps_state", &vl);
 }
 
 static void ps_submit_proc_list (procstat_t *ps)
 {
-       char buffer[64];
-
-       if (ps == NULL)
-               return;
-
-       snprintf (buffer, 64, "%u:%lu",
-                       (unsigned int) curtime,
-                       ps->vmem_rss);
-       buffer[63] = '\0';
-       plugin_submit ("ps_rss", ps->name, buffer);
-
-       snprintf (buffer, 64, "%u:%u:%u",
-                       (unsigned int) curtime,
-                       /* Make the counter overflow */
-                       (unsigned int) (ps->cpu_user_counter   & 0xFFFFFFFF),
-                       (unsigned int) (ps->cpu_system_counter & 0xFFFFFFFF));
-       buffer[63] = '\0';
-       plugin_submit ("ps_cputime", ps->name, buffer);
-
-       snprintf (buffer, 64, "%u:%lu:%lu",
-                       (unsigned int) curtime,
-                       ps->num_proc, ps->num_lwp);
-       buffer[63] = '\0';
-       plugin_submit ("ps_count", ps->name, buffer);
-
-       snprintf (buffer, 64, "%u:%lu:%lu",
-                       (unsigned int) curtime,
-                       ps->vmem_minflt_counter, ps->vmem_majflt_counter);
-       buffer[63] = '\0';
-       plugin_submit ("ps_pagefaults", ps->name, buffer);
-
-       DBG ("name = %s; num_proc = %lu; num_lwp = %lu; vmem_rss = %lu; "
+       value_t values[2];
+       value_list_t vl = VALUE_LIST_INIT;
+
+       vl.values = values;
+       vl.values_len = 2;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "processes");
+       strncpy (vl.plugin_instance, ps->name, sizeof (vl.plugin_instance));
+
+       vl.values[0].gauge = ps->vmem_rss;
+       vl.values_len = 1;
+       plugin_dispatch_values ("ps_rss", &vl);
+
+       vl.values[0].counter = ps->cpu_user_counter;
+       vl.values[1].counter = ps->cpu_system_counter;
+       vl.values_len = 2;
+       plugin_dispatch_values ("ps_cputime", &vl);
+
+       vl.values[0].gauge = ps->num_proc;
+       vl.values[1].gauge = ps->num_lwp;
+       vl.values_len = 2;
+       plugin_dispatch_values ("ps_count", &vl);
+
+       vl.values[0].counter = ps->vmem_minflt_counter;
+       vl.values[1].counter = ps->vmem_majflt_counter;
+       vl.values_len = 2;
+       plugin_dispatch_values ("ps_pagefaults", &vl);
+
+       DEBUG ("name = %s; num_proc = %lu; num_lwp = %lu; vmem_rss = %lu; "
                        "vmem_minflt_counter = %lu; vmem_majflt_counter = %lu; "
                        "cpu_user_counter = %lu; cpu_system_counter = %lu;",
                        ps->name, ps->num_proc, ps->num_lwp, ps->vmem_rss,
-                       ps->vmem_minflt_counter, ps->vmem_majflt_counter, ps->cpu_user_counter,
-                       ps->cpu_system_counter);
-
-}
+                       ps->vmem_minflt_counter, ps->vmem_majflt_counter,
+                       ps->cpu_user_counter, ps->cpu_system_counter);
+} /* void ps_submit_proc_list */
 
 #if KERNEL_LINUX
 static int *ps_read_tasks (int pid)
@@ -604,7 +540,7 @@ static int *ps_read_tasks (int pid)
 
        if ((dh = opendir (dirname)) == NULL)
        {
-               DBG ("Failed to open directory `%s'", dirname);
+               DEBUG ("Failed to open directory `%s'", dirname);
                return (NULL);
        }
 
@@ -624,7 +560,7 @@ static int *ps_read_tasks (int pid)
                        {
                                if (list != NULL)
                                        free (list);
-                               syslog (LOG_ERR, "processes plugin: "
+                               ERROR ("processes plugin: "
                                                "Failed to allocate more memory.");
                                return (NULL);
                        }
@@ -686,20 +622,17 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
        fields_len = strsplit (buffer, fields, 64);
        if (fields_len < 24)
        {
-               DBG ("`%s' has only %i fields..",
-                               filename, fields_len);
+               DEBUG ("processes plugin: ps_read_process (pid = %i):"
+                               " `%s' has only %i fields..",
+                               (int) pid, filename, fields_len);
                return (-1);
        }
-       else if (fields_len != 41)
-       {
-               DBG ("WARNING: (fields_len = %i) != 41", fields_len);
-       }
 
        /* copy the name, strip brackets in the process */
        name_len = strlen (fields[1]) - 2;
        if ((fields[1][0] != '(') || (fields[1][name_len + 1] != ')'))
        {
-               DBG ("No brackets found in process name: `%s'", fields[1]);
+               DEBUG ("No brackets found in process name: `%s'", fields[1]);
                return (-1);
        }
        fields[1] = fields[1] + 1;
@@ -711,7 +644,7 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
        if ((tasks = ps_read_tasks (pid)) == NULL)
        {
                /* This happends for zombied, e.g. */
-               DBG ("ps_read_tasks (%i) failed.", pid);
+               DEBUG ("ps_read_tasks (%i) failed.", pid);
                *state = 'Z';
                ps->num_lwp  = 0;
                ps->num_proc = 0;
@@ -731,7 +664,7 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
        /* Leave the rest at zero if this is only an LWP */
        if (ps->num_proc == 0)
        {
-               DBG ("This is only an LWP: pid = %i; name = %s;",
+               DEBUG ("This is only an LWP: pid = %i; name = %s;",
                                pid, ps->name);
                return (0);
        }
@@ -784,7 +717,7 @@ static int mach_get_task_name (task_t t, int *pid, char *name, size_t name_max_l
        strncpy (name, kp.kp_proc.p_comm, name_max_len - 1);
        name[name_max_len - 1] = '\0';
 
-       DBG ("pid = %i; name = %s;", *pid, name);
+       DEBUG ("pid = %i; name = %s;", *pid, name);
 
        /* We don't do the special handling for `p_comm == "LaunchCFMApp"' as
         * `top' does it, because it is a lot of work and only used when
@@ -794,7 +727,7 @@ static int mach_get_task_name (task_t t, int *pid, char *name, size_t name_max_l
 }
 #endif /* HAVE_THREAD_INFO */
 
-static void ps_read (void)
+static int ps_read (void)
 {
 #if HAVE_THREAD_INFO
        kern_return_t            status;
@@ -840,7 +773,7 @@ static void ps_read (void)
                                                pset_list[pset],
                                                &port_pset_priv)) != KERN_SUCCESS)
                {
-                       syslog (LOG_ERR, "host_processor_set_priv failed: %s\n",
+                       ERROR ("host_processor_set_priv failed: %s\n",
                                        mach_error_string (status));
                        continue;
                }
@@ -849,7 +782,7 @@ static void ps_read (void)
                                                &task_list,
                                                &task_list_len)) != KERN_SUCCESS)
                {
-                       syslog (LOG_ERR, "processor_set_tasks failed: %s\n",
+                       ERROR ("processor_set_tasks failed: %s\n",
                                        mach_error_string (status));
                        mach_port_deallocate (port_task_self, port_pset_priv);
                        continue;
@@ -883,7 +816,7 @@ static void ps_read (void)
                                                &task_basic_info_len);
                                if (status != KERN_SUCCESS)
                                {
-                                       syslog (LOG_ERR, "task_info failed: %s",
+                                       ERROR ("task_info failed: %s",
                                                        mach_error_string (status));
                                        continue; /* with next thread_list */
                                }
@@ -895,7 +828,7 @@ static void ps_read (void)
                                                &task_events_info_len);
                                if (status != KERN_SUCCESS)
                                {
-                                       syslog (LOG_ERR, "task_info failed: %s",
+                                       ERROR ("task_info failed: %s",
                                                        mach_error_string (status));
                                        continue; /* with next thread_list */
                                }
@@ -907,7 +840,7 @@ static void ps_read (void)
                                                &task_absolutetime_info_len);
                                if (status != KERN_SUCCESS)
                                {
-                                       syslog (LOG_ERR, "task_info failed: %s",
+                                       ERROR ("task_info failed: %s",
                                                        mach_error_string (status));
                                        continue; /* with next thread_list */
                                }
@@ -931,7 +864,7 @@ static void ps_read (void)
                                 * thread is nonsense, since the task/process
                                 * is dead. */
                                zombies++;
-                               DBG ("task_threads failed: %s",
+                               DEBUG ("task_threads failed: %s",
                                                mach_error_string (status));
                                if (task_list[task] != port_task_self)
                                        mach_port_deallocate (port_task_self,
@@ -948,7 +881,7 @@ static void ps_read (void)
                                                &thread_data_len);
                                if (status != KERN_SUCCESS)
                                {
-                                       syslog (LOG_ERR, "thread_info failed: %s",
+                                       ERROR ("thread_info failed: %s",
                                                        mach_error_string (status));
                                        if (task_list[task] != port_task_self)
                                                mach_port_deallocate (port_task_self,
@@ -980,8 +913,7 @@ static void ps_read (void)
                                         * There's only zombie tasks, which are
                                         * handled above. */
                                        default:
-                                               syslog (LOG_WARNING,
-                                                               "Unknown thread status: %s",
+                                               WARNING ("Unknown thread status: %s",
                                                                thread_data.run_state);
                                                break;
                                } /* switch (thread_data.run_state) */
@@ -991,7 +923,7 @@ static void ps_read (void)
                                        status = mach_port_deallocate (port_task_self,
                                                        thread_list[thread]);
                                        if (status != KERN_SUCCESS)
-                                               syslog (LOG_ERR, "mach_port_deallocate failed: %s",
+                                               ERROR ("mach_port_deallocate failed: %s",
                                                                mach_error_string (status));
                                }
                        } /* for (thread_list) */
@@ -1001,7 +933,7 @@ static void ps_read (void)
                                                        thread_list_len * sizeof (thread_act_t)))
                                        != KERN_SUCCESS)
                        {
-                               syslog (LOG_ERR, "vm_deallocate failed: %s",
+                               ERROR ("vm_deallocate failed: %s",
                                                mach_error_string (status));
                        }
                        thread_list = NULL;
@@ -1015,7 +947,7 @@ static void ps_read (void)
                                status = mach_port_deallocate (port_task_self,
                                                task_list[task]);
                                if (status != KERN_SUCCESS)
-                                       syslog (LOG_ERR, "mach_port_deallocate failed: %s",
+                                       ERROR ("mach_port_deallocate failed: %s",
                                                        mach_error_string (status));
                        }
 
@@ -1027,7 +959,7 @@ static void ps_read (void)
                                (vm_address_t) task_list,
                                task_list_len * sizeof (task_t))) != KERN_SUCCESS)
                {
-                       syslog (LOG_ERR, "vm_deallocate failed: %s",
+                       ERROR ("vm_deallocate failed: %s",
                                        mach_error_string (status));
                }
                task_list = NULL;
@@ -1036,12 +968,16 @@ static void ps_read (void)
                if ((status = mach_port_deallocate (port_task_self, port_pset_priv))
                                != KERN_SUCCESS)
                {
-                       syslog (LOG_ERR, "mach_port_deallocate failed: %s",
+                       ERROR ("mach_port_deallocate failed: %s",
                                        mach_error_string (status));
                }
        } /* for (pset_list) */
 
-       ps_submit (running, sleeping, zombies, stopped, -1, blocked);
+       ps_submit_state ("running", running);
+       ps_submit_state ("sleeping", sleeping);
+       ps_submit_state ("zombies", zombies);
+       ps_submit_state ("stopped", stopped);
+       ps_submit_state ("blocked", blocked);
 
        for (ps = list_head_g; ps != NULL; ps = ps->next)
                ps_submit_proc_list (ps);
@@ -1071,8 +1007,10 @@ static void ps_read (void)
 
        if ((proc = opendir ("/proc")) == NULL)
        {
-               syslog (LOG_ERR, "Cannot open `/proc': %s", strerror (errno));
-               return;
+               char errbuf[1024];
+               ERROR ("Cannot open `/proc': %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
        }
 
        while ((ent = readdir (proc)) != NULL)
@@ -1086,7 +1024,7 @@ static void ps_read (void)
                status = ps_read_process (pid, &ps, &state);
                if (status != 0)
                {
-                       DBG ("ps_read_process failed: %i", status);
+                       DEBUG ("ps_read_process failed: %i", status);
                        continue;
                }
 
@@ -1122,27 +1060,41 @@ static void ps_read (void)
 
        closedir (proc);
 
-       ps_submit (running, sleeping, zombies, stopped, paging, blocked);
+       ps_submit_state ("running",  running);
+       ps_submit_state ("sleeping", sleeping);
+       ps_submit_state ("zombies",  zombies);
+       ps_submit_state ("stopped",  stopped);
+       ps_submit_state ("paging",   paging);
+       ps_submit_state ("blocked",  blocked);
 
        for (ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
                ps_submit_proc_list (ps_ptr);
 #endif /* KERNEL_LINUX */
-}
-#else
-# define ps_read NULL
+
+       return (0);
+} /* int ps_read */
 #endif /* PROCESSES_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, ps_init, ps_read, ps_write);
-       plugin_register ("ps_rss", NULL, NULL, ps_rss_write);
-       plugin_register ("ps_cputime", NULL, NULL, ps_cputime_write);
-       plugin_register ("ps_count", NULL, NULL, ps_count_write);
-       plugin_register ("ps_pagefaults", NULL, NULL, ps_pagefaults_write);
+       if (load & MR_DATASETS)
+       {
+               plugin_register_data_set (&state_ds);
+               plugin_register_data_set (&rss_ds);
+               plugin_register_data_set (&time_ds);
+               plugin_register_data_set (&count_ds);
+               plugin_register_data_set (&pagefaults_ds);
+       }
+
+#if PROCESSES_HAVE_READ
+       if (load & MR_READ)
+       {
 #if HAVE_THREAD_INFO | KERNEL_LINUX
-       cf_register (MODULE_NAME, ps_config, config_keys, config_keys_num);
+               plugin_register_config ("processes", ps_config,
+                               config_keys, config_keys_num);
 #endif
-}
-
-#undef BUFSIZE
-#undef MODULE_NAME
+               plugin_register_init ("processes", ps_init);
+               plugin_register_read ("processes", ps_read);
+       }
+#endif /* PROCESSES_HAVE_READ */
+} /* void module_register */
diff --git a/src/rrdtool.c b/src/rrdtool.c
new file mode 100644 (file)
index 0000000..b221341
--- /dev/null
@@ -0,0 +1,826 @@
+/**
+ * collectd - src/rrdtool.c
+ * Copyright (C) 2006  Florian octo Forster
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+#include "utils_avltree.h"
+
+#if HAVE_PTHREAD_H
+# include <pthread.h>
+#endif
+
+/*
+ * Private types
+ */
+struct rrd_cache_s
+{
+       int    values_num;
+       char **values;
+       time_t first_value;
+};
+typedef struct rrd_cache_s rrd_cache_t;
+
+/*
+ * Private variables
+ */
+static int rra_timespans[] =
+{
+       3600,
+       86400,
+       604800,
+       2678400,
+       31622400
+};
+static int rra_timespans_num = STATIC_ARRAY_SIZE (rra_timespans);
+
+static char *rra_types[] =
+{
+       "AVERAGE",
+       "MIN",
+       "MAX"
+};
+static int rra_types_num = STATIC_ARRAY_SIZE (rra_types);
+
+static const char *config_keys[] =
+{
+       "CacheTimeout",
+       "CacheFlush",
+       "DataDir",
+       "StepSize",
+       "HeartBeat",
+       "RRARows",
+       "XFF"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static char   *datadir   = NULL;
+static int     stepsize  = 0;
+static int     heartbeat = 0;
+static int     rrarows   = 1200;
+static double  xff       = 0.1;
+
+static int         cache_timeout = 0;
+static int         cache_flush_timeout = 0;
+static time_t      cache_flush_last;
+static avl_tree_t *cache = NULL;
+static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* * * * * * * * * *
+ * WARNING:  Magic *
+ * * * * * * * * * */
+static int rra_get (char ***ret)
+{
+       static char **rra_def = NULL;
+       static int rra_num = 0;
+
+       int rra_max = rra_timespans_num * rra_types_num;
+
+       int span;
+
+       int cdp_num;
+       int cdp_len;
+       int i, j;
+
+       char buffer[64];
+
+       if ((rra_num != 0) && (rra_def != NULL))
+       {
+               *ret = rra_def;
+               return (rra_num);
+       }
+
+       if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
+               return (-1);
+       memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
+
+       if ((stepsize <= 0) || (rrarows <= 0))
+       {
+               *ret = NULL;
+               return (-1);
+       }
+
+       cdp_len = 0;
+       for (i = 0; i < rra_timespans_num; i++)
+       {
+               span = rra_timespans[i];
+
+               if ((span / stepsize) < rrarows)
+                       continue;
+
+               if (cdp_len == 0)
+                       cdp_len = 1;
+               else
+                       cdp_len = (int) floor (((double) span)
+                                       / ((double) (rrarows * stepsize)));
+
+               cdp_num = (int) ceil (((double) span)
+                               / ((double) (cdp_len * stepsize)));
+
+               for (j = 0; j < rra_types_num; j++)
+               {
+                       if (rra_num >= rra_max)
+                               break;
+
+                       if (snprintf (buffer, sizeof (buffer), "RRA:%s:%3.1f:%u:%u",
+                                               rra_types[j], xff,
+                                               cdp_len, cdp_num) >= sizeof (buffer))
+                       {
+                               ERROR ("rra_get: Buffer would have been truncated.");
+                               continue;
+                       }
+
+                       rra_def[rra_num++] = sstrdup (buffer);
+               }
+       }
+
+#if COLLECT_DEBUG
+       DEBUG ("rra_num = %i", rra_num);
+       for (i = 0; i < rra_num; i++)
+               DEBUG ("  %s", rra_def[i]);
+#endif
+
+       *ret = rra_def;
+       return (rra_num);
+}
+
+static void ds_free (int ds_num, char **ds_def)
+{
+       int i;
+
+       for (i = 0; i < ds_num; i++)
+               if (ds_def[i] != NULL)
+                       free (ds_def[i]);
+       free (ds_def);
+}
+
+static int ds_get (char ***ret, const data_set_t *ds)
+{
+       char **ds_def;
+       int ds_num;
+
+       char min[32];
+       char max[32];
+       char buffer[128];
+
+       DEBUG ("ds->ds_num = %i", ds->ds_num);
+
+       ds_def = (char **) malloc (ds->ds_num * sizeof (char *));
+       if (ds_def == NULL)
+       {
+               char errbuf[1024];
+               ERROR ("rrdtool plugin: malloc failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
+       memset (ds_def, '\0', ds->ds_num * sizeof (char *));
+
+       for (ds_num = 0; ds_num < ds->ds_num; ds_num++)
+       {
+               data_source_t *d = ds->ds + ds_num;
+               char *type;
+               int status;
+
+               ds_def[ds_num] = NULL;
+
+               if (d->type == DS_TYPE_COUNTER)
+                       type = "COUNTER";
+               else if (d->type == DS_TYPE_GAUGE)
+                       type = "GAUGE";
+               else
+               {
+                       ERROR ("rrdtool plugin: Unknown DS type: %i",
+                                       d->type);
+                       break;
+               }
+
+               if (isnan (d->min))
+               {
+                       strcpy (min, "U");
+               }
+               else
+               {
+                       snprintf (min, sizeof (min), "%lf", d->min);
+                       min[sizeof (min) - 1] = '\0';
+               }
+
+               if (isnan (d->max))
+               {
+                       strcpy (max, "U");
+               }
+               else
+               {
+                       snprintf (max, sizeof (max), "%lf", d->max);
+                       max[sizeof (max) - 1] = '\0';
+               }
+
+               status = snprintf (buffer, sizeof (buffer),
+                               "DS:%s:%s:%i:%s:%s",
+                               d->name, type, heartbeat,
+                               min, max);
+               if ((status < 1) || (status >= sizeof (buffer)))
+                       break;
+
+               ds_def[ds_num] = sstrdup (buffer);
+       } /* for ds_num = 0 .. ds->ds_num */
+
+#if COLLECT_DEBUG
+{
+       int i;
+       DEBUG ("ds_num = %i", ds_num);
+       for (i = 0; i < ds_num; i++)
+               DEBUG ("  %s", ds_def[i]);
+}
+#endif
+
+       if (ds_num != ds->ds_num)
+       {
+               ds_free (ds_num, ds_def);
+               return (-1);
+       }
+
+       *ret = ds_def;
+       return (ds_num);
+}
+
+static int rrd_create_file (char *filename, const data_set_t *ds)
+{
+       char **argv;
+       int argc;
+       char **rra_def;
+       int rra_num;
+       char **ds_def;
+       int ds_num;
+       int i, j;
+       char stepsize_str[16];
+       int status = 0;
+
+       if (check_create_dir (filename))
+               return (-1);
+
+       if ((rra_num = rra_get (&rra_def)) < 1)
+       {
+               ERROR ("rrd_create_file failed: Could not calculate RRAs");
+               return (-1);
+       }
+
+       if ((ds_num = ds_get (&ds_def, ds)) < 1)
+       {
+               ERROR ("rrd_create_file failed: Could not calculate DSes");
+               return (-1);
+       }
+
+       argc = ds_num + rra_num + 4;
+
+       if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
+       {
+               char errbuf[1024];
+               ERROR ("rrd_create failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
+
+       status = snprintf (stepsize_str, sizeof (stepsize_str),
+                       "%i", stepsize);
+       if ((status < 1) || (status >= sizeof (stepsize_str)))
+       {
+               ERROR ("rrdtool plugin: snprintf failed.");
+               return (-1);
+       }
+
+       argv[0] = "create";
+       argv[1] = filename;
+       argv[2] = "-s";
+       argv[3] = stepsize_str;
+
+       j = 4;
+       for (i = 0; i < ds_num; i++)
+               argv[j++] = ds_def[i];
+       for (i = 0; i < rra_num; i++)
+               argv[j++] = rra_def[i];
+       argv[j] = NULL;
+
+       optind = 0; /* bug in librrd? */
+       rrd_clear_error ();
+       if (rrd_create (argc, argv) == -1)
+       {
+               ERROR ("rrd_create failed: %s: %s", filename, rrd_get_error ());
+               status = -1;
+       }
+
+       free (argv);
+       ds_free (ds_num, ds_def);
+
+       return (status);
+}
+
+static int value_list_to_string (char *buffer, int buffer_len,
+               const data_set_t *ds, const value_list_t *vl)
+{
+       int offset;
+       int status;
+       int i;
+
+       memset (buffer, '\0', sizeof (buffer_len));
+
+       status = snprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+       if ((status < 1) || (status >= buffer_len))
+               return (-1);
+       offset = status;
+
+       for (i = 0; i < ds->ds_num; i++)
+       {
+               if ((ds->ds[i].type != DS_TYPE_COUNTER)
+                               && (ds->ds[i].type != DS_TYPE_GAUGE))
+                       return (-1);
+
+               if (ds->ds[i].type == DS_TYPE_COUNTER)
+                       status = snprintf (buffer + offset, buffer_len - offset,
+                                       ":%llu", vl->values[i].counter);
+               else
+                       status = snprintf (buffer + offset, buffer_len - offset,
+                                       ":%lf", vl->values[i].gauge);
+
+               if ((status < 1) || (status >= (buffer_len - offset)))
+                       return (-1);
+
+               offset += status;
+       } /* for ds->ds_num */
+
+       return (0);
+} /* int value_list_to_string */
+
+static int value_list_to_filename (char *buffer, int buffer_len,
+               const data_set_t *ds, const value_list_t *vl)
+{
+       int offset = 0;
+       int status;
+
+       if (datadir != NULL)
+       {
+               status = snprintf (buffer + offset, buffer_len - offset,
+                               "%s/", datadir);
+               if ((status < 1) || (status >= buffer_len - offset))
+                       return (-1);
+               offset += status;
+       }
+
+       status = snprintf (buffer + offset, buffer_len - offset,
+                       "%s/", vl->host);
+       if ((status < 1) || (status >= buffer_len - offset))
+               return (-1);
+       offset += status;
+
+       if (strlen (vl->plugin_instance) > 0)
+               status = snprintf (buffer + offset, buffer_len - offset,
+                               "%s-%s/", vl->plugin, vl->plugin_instance);
+       else
+               status = snprintf (buffer + offset, buffer_len - offset,
+                               "%s/", vl->plugin);
+       if ((status < 1) || (status >= buffer_len - offset))
+               return (-1);
+       offset += status;
+
+       if (strlen (vl->type_instance) > 0)
+               status = snprintf (buffer + offset, buffer_len - offset,
+                               "%s-%s.rrd", ds->type, vl->type_instance);
+       else
+               status = snprintf (buffer + offset, buffer_len - offset,
+                               "%s.rrd", ds->type);
+       if ((status < 1) || (status >= buffer_len - offset))
+               return (-1);
+       offset += status;
+
+       return (0);
+} /* int value_list_to_filename */
+
+static rrd_cache_t *rrd_cache_insert (const char *filename,
+               const char *value)
+{
+       rrd_cache_t *rc = NULL;
+       int new_rc = 0;
+
+       if (cache != NULL)
+               avl_get (cache, filename, (void *) &rc);
+
+       if (rc == NULL)
+       {
+               rc = (rrd_cache_t *) malloc (sizeof (rrd_cache_t));
+               if (rc == NULL)
+                       return (NULL);
+               rc->values_num = 0;
+               rc->values = NULL;
+               rc->first_value = 0;
+               new_rc = 1;
+       }
+
+       rc->values = (char **) realloc ((void *) rc->values,
+                       (rc->values_num + 1) * sizeof (char *));
+       if (rc->values == NULL)
+       {
+               char errbuf[1024];
+               ERROR ("rrdtool plugin: realloc failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               if (cache != NULL)
+               {
+                       void *cache_key = NULL;
+                       avl_remove (cache, filename, &cache_key, NULL);
+                       sfree (cache_key);
+               }
+               free (rc);
+               return (NULL);
+       }
+
+       rc->values[rc->values_num] = strdup (value);
+       if (rc->values[rc->values_num] != NULL)
+               rc->values_num++;
+
+       if (rc->values_num == 1)
+               rc->first_value = time (NULL);
+
+       /* Insert if this is the first value */
+       if ((cache != NULL) && (new_rc == 1))
+       {
+               void *cache_key = strdup (filename);
+
+               if (cache_key == NULL)
+               {
+                       char errbuf[1024];
+                       ERROR ("rrdtool plugin: strdup failed: %s",
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+                       sfree (rc->values[0]);
+                       sfree (rc->values);
+                       sfree (rc);
+                       return (NULL);
+               }
+
+               avl_insert (cache, cache_key, rc);
+       }
+
+       DEBUG ("rrd_cache_insert (%s, %s) = %p", filename, value, (void *) rc);
+
+       return (rc);
+} /* rrd_cache_t *rrd_cache_insert */
+
+static int rrd_write_cache_entry (const char *filename, rrd_cache_t *rc)
+{
+       char **argv;
+       int    argc;
+
+       char *fn;
+       int status;
+
+       int i;
+
+       if (rc->values_num < 1)
+               return (0);
+
+       argc = rc->values_num + 2;
+       argv = (char **) malloc ((argc + 1) * sizeof (char *));
+       if (argv == NULL)
+               return (-1);
+
+       fn = strdup (filename);
+       if (fn == NULL)
+       {
+               free (argv);
+               return (-1);
+       }
+
+       argv[0] = "update";
+       argv[1] = fn;
+       memcpy (argv + 2, rc->values, rc->values_num * sizeof (char *));
+       argv[argc] = NULL;
+
+       DEBUG ("rrd_update (argc = %i, argv = %p)", argc, (void *) argv);
+
+       optind = 0; /* bug in librrd? */
+       rrd_clear_error ();
+       status = rrd_update (argc, argv);
+       if (status != 0)
+       {
+               WARNING ("rrd_update failed: %s: %s",
+                               filename, rrd_get_error ());
+               status = -1;
+       }
+
+       free (argv);
+       free (fn);
+       /* Free the value list of `rc' */
+       for (i = 0; i < rc->values_num; i++)
+               free (rc->values[i]);
+       free (rc->values);
+       rc->values = NULL;
+       rc->values_num = 0;
+
+       return (status);
+} /* int rrd_write_cache_entry */
+
+static void rrd_cache_flush (int timeout)
+{
+       rrd_cache_t *rc;
+       time_t       now;
+
+       char **keys = NULL;
+       int    keys_num = 0;
+
+       char *key;
+       avl_iterator_t *iter;
+       int i;
+
+       if (cache == NULL)
+               return;
+
+       DEBUG ("Flushing cache, timeout = %i", timeout);
+
+       now = time (NULL);
+
+       /* Build a list of entries to be flushed */
+       iter = avl_get_iterator (cache);
+       while (avl_iterator_next (iter, (void *) &key, (void *) &rc) == 0)
+       {
+               DEBUG ("key = %s; age = %i;", key, now - rc->first_value);
+               if ((now - rc->first_value) >= timeout)
+               {
+                       keys = (char **) realloc ((void *) keys,
+                                       (keys_num + 1) * sizeof (char *));
+                       if (keys == NULL)
+                       {
+                               char errbuf[1024];
+                               ERROR ("rrdtool plugin: "
+                                               "realloc failed: %s",
+                                               sstrerror (errno, errbuf,
+                                                       sizeof (errbuf)));
+                               avl_iterator_destroy (iter);
+                               return;
+                       }
+                       keys[keys_num] = key;
+                       keys_num++;
+               }
+       } /* while (avl_iterator_next) */
+       avl_iterator_destroy (iter);
+       
+       for (i = 0; i < keys_num; i++)
+       {
+               if (avl_remove (cache, keys[i], (void *) &key, (void *) &rc) != 0)
+               {
+                       DEBUG ("avl_remove (%s) failed.", keys[i]);
+                       continue;
+               }
+
+               rrd_write_cache_entry (keys[i], rc);
+               /* rc's value-list is free's by `rrd_write_cache_entry' */
+               sfree (rc);
+               sfree (key);
+               keys[i] = NULL;
+       } /* for (i = 0..keys_num) */
+
+       free (keys);
+       DEBUG ("Flushed %i value(s)", keys_num);
+
+       cache_flush_last = now;
+} /* void rrd_cache_flush */
+
+static int rrd_write (const data_set_t *ds, const value_list_t *vl)
+{
+       struct stat  statbuf;
+       char         filename[512];
+       char         values[512];
+       rrd_cache_t *rc;
+       time_t       now;
+
+       if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
+               return (-1);
+
+       if (value_list_to_string (values, sizeof (values), ds, vl) != 0)
+               return (-1);
+
+       if (stat (filename, &statbuf) == -1)
+       {
+               if (errno == ENOENT)
+               {
+                       if (rrd_create_file (filename, ds))
+                               return (-1);
+               }
+               else
+               {
+                       char errbuf[1024];
+                       ERROR ("stat(%s) failed: %s", filename,
+                                       sstrerror (errno, errbuf,
+                                               sizeof (errbuf)));
+                       return (-1);
+               }
+       }
+       else if (!S_ISREG (statbuf.st_mode))
+       {
+               ERROR ("stat(%s): Not a regular file!",
+                               filename);
+               return (-1);
+       }
+
+       pthread_mutex_lock (&cache_lock);
+       rc = rrd_cache_insert (filename, values);
+       if (rc == NULL)
+       {
+               pthread_mutex_unlock (&cache_lock);
+               return (-1);
+       }
+
+       if (cache == NULL)
+       {
+               rrd_write_cache_entry (filename, rc);
+               /* rc's value-list is free's by `rrd_write_cache_entry' */
+               sfree (rc);
+               pthread_mutex_unlock (&cache_lock);
+               return (0);
+       }
+
+       now = time (NULL);
+
+       DEBUG ("age (%s) = %i", filename, now - rc->first_value);
+
+       /* `rc' is not free'd here, because we'll likely reuse it. If not, then
+        * the next flush will remove this entry.  */
+       if ((now - rc->first_value) >= cache_timeout)
+               rrd_write_cache_entry (filename, rc);
+
+       if ((now - cache_flush_last) >= cache_flush_timeout)
+               rrd_cache_flush (cache_flush_timeout);
+
+       pthread_mutex_unlock (&cache_lock);
+       return (0);
+} /* int rrd_write */
+
+static int rrd_config (const char *key, const char *value)
+{
+       if (strcasecmp ("CacheTimeout", key) == 0)
+       {
+               int tmp = atoi (value);
+               if (tmp < 0)
+               {
+                       fprintf (stderr, "rrdtool: `CacheTimeout' must "
+                                       "be greater than 0.\n");
+                       return (1);
+               }
+               cache_timeout = tmp;
+       }
+       else if (strcasecmp ("CacheFlush", key) == 0)
+       {
+               int tmp = atoi (value);
+               if (tmp < 0)
+               {
+                       fprintf (stderr, "rrdtool: `CacheFlush' must "
+                                       "be greater than 0.\n");
+                       return (1);
+               }
+               cache_flush_timeout = tmp;
+       }
+       else if (strcasecmp ("DataDir", key) == 0)
+       {
+               if (datadir != NULL)
+                       free (datadir);
+               datadir = strdup (value);
+               if (datadir != NULL)
+               {
+                       int len = strlen (datadir);
+                       while ((len > 0) && (datadir[len - 1] == '/'))
+                       {
+                               len--;
+                               datadir[len] = '\0';
+                       }
+                       if (len <= 0)
+                       {
+                               free (datadir);
+                               datadir = NULL;
+                       }
+               }
+       }
+       else if (strcasecmp ("StepSize", key) == 0)
+       {
+               int tmp = atoi (value);
+               if (tmp <= 0)
+               {
+                       fprintf (stderr, "rrdtool: `StepSize' must "
+                                       "be greater than 0.\n");
+                       return (1);
+               }
+               stepsize = tmp;
+       }
+       else if (strcasecmp ("HeartBeat", key) == 0)
+       {
+               int tmp = atoi (value);
+               if (tmp <= 0)
+               {
+                       fprintf (stderr, "rrdtool: `HeartBeat' must "
+                                       "be greater than 0.\n");
+                       return (1);
+               }
+               heartbeat = tmp;
+       }
+       else if (strcasecmp ("RRARows", key) == 0)
+       {
+               int tmp = atoi (value);
+               if (tmp <= 0)
+               {
+                       fprintf (stderr, "rrdtool: `RRARows' must "
+                                       "be greater than 0.\n");
+                       return (1);
+               }
+               rrarows = tmp;
+       }
+       else if (strcasecmp ("XFF", key) == 0)
+       {
+               double tmp = atof (value);
+               if ((tmp < 0.0) || (tmp >= 1.0))
+               {
+                       fprintf (stderr, "rrdtool: `XFF' must "
+                                       "be in the range 0 to 1 (exclusive).");
+                       return (1);
+               }
+               xff = tmp;
+       }
+       else
+       {
+               return (-1);
+       }
+       return (0);
+} /* int rrd_config */
+
+static int rrd_shutdown (void)
+{
+       pthread_mutex_lock (&cache_lock);
+       rrd_cache_flush (-1);
+       if (cache != NULL)
+               avl_destroy (cache);
+       cache = NULL;
+       pthread_mutex_unlock (&cache_lock);
+
+       return (0);
+} /* int rrd_shutdown */
+
+static int rrd_init (void)
+{
+       if (stepsize <= 0)
+               stepsize = interval_g;
+       if (heartbeat <= 0)
+               heartbeat = 2 * interval_g;
+
+       if (heartbeat < interval_g)
+               WARNING ("rrdtool plugin: Your `heartbeat' is "
+                               "smaller than your `interval'. This will "
+                               "likely cause problems.");
+       else if (stepsize < interval_g)
+               WARNING ("rrdtool plugin: Your `stepsize' is "
+                               "smaller than your `interval'. This will "
+                               "create needlessly big RRD-files.");
+
+       pthread_mutex_lock (&cache_lock);
+       if (cache_timeout < 2)
+       {
+               cache_timeout = 0;
+               cache_flush_timeout = 0;
+       }
+       else
+       {
+               if (cache_flush_timeout < cache_timeout)
+                       cache_flush_timeout = 10 * cache_timeout;
+
+               cache = avl_create ((int (*) (const void *, const void *)) strcmp);
+               cache_flush_last = time (NULL);
+               plugin_register_shutdown ("rrdtool", rrd_shutdown);
+       }
+       pthread_mutex_unlock (&cache_lock);
+
+       DEBUG ("rrdtool plugin: rrd_init: datadir = %s; stepsize = %i;"
+                       " heartbeat = %i; rrarows = %i; xff = %lf;",
+                       (datadir == NULL) ? "(null)" : datadir,
+                       stepsize, heartbeat, rrarows, xff);
+
+       return (0);
+} /* int rrd_init */
+
+void module_register (modreg_e load)
+{
+       plugin_register_config ("rrdtool", rrd_config,
+                       config_keys, config_keys_num);
+       plugin_register_init ("rrdtool", rrd_init);
+       plugin_register_write ("rrdtool", rrd_write);
+}
index 66cd5b2..551d267 100644 (file)
@@ -1,11 +1,10 @@
 /**
  * collectd - src/sensors.c
- * Copyright (C) 2005,2006  Florian octo Forster
+ * Copyright (C) 2005-2007  Florian octo Forster
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
 #include "plugin.h"
 #include "configfile.h"
 #include "utils_ignorelist.h"
-#include "utils_debug.h"
-
-#define MODULE_NAME "sensors"
-#define MODULE_NAME_VOLTAGE MODULE_NAME"_voltage"
 
 #if defined(HAVE_SENSORS_SENSORS_H)
 # include <sensors/sensors.h>
 # define SENSORS_HAVE_READ 0
 #endif
 
-#define BUFSIZE 512
+static data_source_t data_source_fanspeed[1] =
+{
+       {"value", DS_TYPE_GAUGE, 0, NAN}
+};
 
-/* temperature and fan sensors */
-static char *ds_def[] =
+static data_set_t fanspeed_ds =
 {
-       "DS:value:GAUGE:"COLLECTD_HEARTBEAT":U:U",
-       NULL
+       "fanspeed", 1, data_source_fanspeed
 };
-static int ds_num = 1;
 
-/* voltage sensors */
-static char *sensor_voltage_ds_def[] = 
+static data_source_t data_source_temperature[1] =
 {
-       "DS:voltage:GAUGE:"COLLECTD_HEARTBEAT":U:U",
-       NULL
+       {"value", DS_TYPE_GAUGE, -273.15, NAN}
 };
-static int sensor_voltage_ds_num = 1;
 
-/* old naming */
-static char *old_filename_format = "sensors-%s.rrd";
-/* end old naming */
+static data_set_t temperature_ds =
+{
+       "temperature", 1, data_source_temperature
+};
 
-/* new naming <chip-bus-address/type-feature */
-static char *extended_filename_format = "lm_sensors-%s.rrd";
+static data_source_t data_source_voltage[1] =
+{
+       {"value", DS_TYPE_GAUGE, NAN, NAN}
+};
 
-#define SENSOR_TYPE_UNKNOWN 0
-#define SENSOR_TYPE_VOLTAGE 1
-#define SENSOR_TYPE_FANSPEED 2
-#define SENSOR_TYPE_TEMPERATURE 3
+static data_set_t voltage_ds =
+{
+       "voltage", 1, data_source_voltage
+};
 
 #if SENSORS_HAVE_READ
-static char *sensor_type_prefix[] =
+#define SENSOR_TYPE_VOLTAGE     0
+#define SENSOR_TYPE_FANSPEED    1
+#define SENSOR_TYPE_TEMPERATURE 2
+#define SENSOR_TYPE_UNKNOWN     3
+
+static char *sensor_to_type[] =
 {
-       "unknown",
        "voltage",
        "fanspeed",
        "temperature",
        NULL
 };
-#endif
 
-typedef struct sensors_labeltypes {
+struct sensors_labeltypes_s
+{
        char *label;
        int type;
-} sensors_labeltypes;
+};
+typedef struct sensors_labeltypes_s sensors_labeltypes_t;
 
 /*
  * finite list of known labels extracted from lm_sensors
  */
-#if SENSORS_HAVE_READ
-static sensors_labeltypes known_features[] = 
+static sensors_labeltypes_t known_features[] = 
 {
        { "fan1", SENSOR_TYPE_FANSPEED },
        { "fan2", SENSOR_TYPE_FANSPEED },
@@ -154,34 +153,24 @@ static sensors_labeltypes known_features[] =
        { "3.3V", SENSOR_TYPE_VOLTAGE },
        { "2.5V", SENSOR_TYPE_VOLTAGE },
        { "2.0V", SENSOR_TYPE_VOLTAGE },
-       { "12V", SENSOR_TYPE_VOLTAGE },
-       { 0, -1 }
+       { "12V", SENSOR_TYPE_VOLTAGE }
 };
-#endif
+static int known_features_num = STATIC_ARRAY_SIZE (known_features);
 /* end new naming */
 
-static char *config_keys[] =
+static const char *config_keys[] =
 {
        "Sensor",
        "IgnoreSelected",
-       "ExtendedSensorNaming",
        NULL
 };
-static int config_keys_num = 3;
+static int config_keys_num = 2;
 
 static ignorelist_t *sensor_list;
 
-/* 
- * sensor_extended_naming:
- * 0 => default is to create chip-feature
- * 1 => use new naming scheme chip-bus-address/type-feature
- */
-static int sensor_extended_naming = 0;
-
-#if SENSORS_HAVE_READ
-#  ifndef SENSORS_CONF_PATH
-#    define SENSORS_CONF_PATH "/etc/sensors.conf"
-#  endif
+#ifndef SENSORS_CONF_PATH
+# define SENSORS_CONF_PATH "/etc/sensors.conf"
+#endif
 
 static const char *conffile = SENSORS_CONF_PATH;
 /* SENSORS_CONF_PATH */
@@ -200,9 +189,8 @@ typedef struct featurelist
 } featurelist_t;
 
 featurelist_t *first_feature = NULL;
-#endif /* if SENSORS_HAVE_READ */
 
-static int sensors_config (char *key, char *value)
+static int sensors_config (const char *key, const char *value)
 {
        if (sensor_list == NULL)
                sensor_list = ignorelist_create (1);
@@ -211,7 +199,8 @@ static int sensors_config (char *key, char *value)
        {
                if (ignorelist_add (sensor_list, value))
                {
-                       syslog (LOG_EMERG, MODULE_NAME": Cannot add value to ignorelist.");
+                       ERROR ("sensors plugin: "
+                                       "Cannot add value to ignorelist.");
                        return (1);
                }
        }
@@ -223,15 +212,6 @@ static int sensors_config (char *key, char *value)
                                || (strcasecmp (value, "On") == 0))
                        ignorelist_set_invert (sensor_list, 0);
        }
-       else if (strcasecmp (key, "ExtendedSensorNaming") == 0)
-       {
-               if ((strcasecmp (value, "True") == 0)
-                               || (strcasecmp (value, "Yes") == 0)
-                               || (strcasecmp (value, "On") == 0))
-                       sensor_extended_naming = 1;
-               else
-                       sensor_extended_naming = 0;
-       }
        else
        {
                return (-1);
@@ -240,7 +220,6 @@ static int sensors_config (char *key, char *value)
        return (0);
 }
 
-#if SENSORS_HAVE_READ
 void sensors_free_features (void)
 {
        featurelist_t *thisft;
@@ -277,8 +256,9 @@ static void sensors_load_conf (void)
        status = stat (conffile, &statbuf);
        if (status != 0)
        {
-               syslog (LOG_ERR, MODULE_NAME": stat(%s) failed: %s",
-                               conffile, strerror (errno));
+               char errbuf[1024];
+               ERROR ("sensors plugin: stat (%s) failed: %s", conffile,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                sensors_config_mtime = 0;
        }
 
@@ -288,7 +268,7 @@ static void sensors_load_conf (void)
 
        if (sensors_config_mtime != 0)
        {
-               syslog (LOG_NOTICE, MODULE_NAME": Reloading config from %s",
+               NOTICE ("sensors plugin: Reloading config from %s",
                                conffile);
                sensors_free_features ();
                sensors_config_mtime = 0;
@@ -297,8 +277,9 @@ static void sensors_load_conf (void)
        fh = fopen (conffile, "r");
        if (fh == NULL)
        {
-               syslog (LOG_ERR, MODULE_NAME": fopen(%s) failed: %s",
-                               conffile, strerror(errno));
+               char errbuf[1024];
+               ERROR ("sensors plugin: fopen(%s) failed: %s", conffile,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                return;
        }
 
@@ -306,7 +287,7 @@ static void sensors_load_conf (void)
        fclose (fh);
        if (status != 0)
        {
-               syslog (LOG_ERR, MODULE_NAME": Cannot initialize sensors. "
+               ERROR ("sensors plugin: Cannot initialize sensors. "
                                "Data will not be collected.");
                return;
        }
@@ -329,7 +310,7 @@ static void sensors_load_conf (void)
                                continue;
 
                        /* Only known features */
-                       for (i = 0; known_features[i].type >= 0; i++)
+                       for (i = 0; i < known_features_num; i++)
                        {
                                if (strcmp (data->name, known_features[i].label) != 0)
                                        continue;
@@ -338,16 +319,16 @@ static void sensors_load_conf (void)
                                if (sensors_get_ignored (*chip, data->number) == 0)
                                        break;
 
-                               DBG ("Adding feature: %s-%s-%s",
+                               DEBUG ("Adding feature: %s-%s-%s",
                                                chip->prefix,
-                                               sensor_type_prefix[known_features[i].type],
+                                               sensor_to_type[known_features[i].type],
                                                data->name);
 
                                if ((new_feature = (featurelist_t *) malloc (sizeof (featurelist_t))) == NULL)
                                {
-                                       DBG ("malloc: %s", strerror (errno));
-                                       syslog (LOG_ERR, MODULE_NAME":  malloc: %s",
-                                                       strerror (errno));
+                                       char errbuf[1024];
+                                       ERROR ("sensors plugin: malloc: %s",
+                                                       sstrerror (errno, errbuf, sizeof (errbuf)));
                                        break;
                                }
 
@@ -376,107 +357,50 @@ static void sensors_load_conf (void)
        if (first_feature == NULL)
        {
                sensors_cleanup ();
-               syslog (LOG_INFO, MODULE_NAME": lm_sensors reports no features. "
-                       "Data will not be collected.");
+               INFO ("sensors plugin: lm_sensors reports no "
+                               "features. Data will not be collected.");
        }
 } /* void sensors_load_conf */
-#endif /* if SENSORS_HAVE_READ */
 
-static void collectd_sensors_init (void)
+static int sensors_shutdown (void)
 {
-       return;
-}
-
-static void sensors_shutdown (void)
-{
-#if SENSORS_HAVE_READ
        sensors_free_features ();
-#endif /* if SENSORS_HAVE_READ */
-
-       if (NULL != sensor_list)
-               ignorelist_free (sensor_list);
-}
-
-static void sensors_voltage_write (char *host, char *inst, char *val)
-{
-       char file[BUFSIZE];
-       int status;
-
-       /* skip ignored in our config */
-       if ((NULL != sensor_list) && ignorelist_match (sensor_list, inst))
-               return;
-
-       /* extended sensor naming */
-       if(sensor_extended_naming)
-               status = snprintf (file, BUFSIZE, extended_filename_format, inst);
-       else
-               status = snprintf (file, BUFSIZE, old_filename_format, inst);
-
-       if ((status < 1) || (status >= BUFSIZE))
-               return;
-
-       rrd_update_file (host, file, val, sensor_voltage_ds_def, sensor_voltage_ds_num);
-}
+       ignorelist_free (sensor_list);
 
-static void sensors_write (char *host, char *inst, char *val)
-{
-       char file[BUFSIZE];
-       int status;
-
-       /* skip ignored in our config */
-       if ((NULL != sensor_list) && ignorelist_match (sensor_list, inst))
-               return;
-
-       /* extended sensor naming */
-       if (sensor_extended_naming)
-               status = snprintf (file, BUFSIZE, extended_filename_format, inst);
-       else
-               status = snprintf (file, BUFSIZE, old_filename_format, inst);
-
-       if ((status < 1) || (status >= BUFSIZE))
-               return;
-
-       rrd_update_file (host, file, val, ds_def, ds_num);
-}
+       return (0);
+} /* int sensors_shutdown */
 
-#if SENSORS_HAVE_READ
-static void sensors_submit (const char *feat_name,
-               const char *chip_prefix, double value, int type)
+static void sensors_submit (const char *plugin_instance,
+               const char *type, const char *type_instance,
+               double val)
 {
-       char buf[BUFSIZE];
-       char inst[BUFSIZE];
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       if (snprintf (inst, BUFSIZE, "%s-%s", chip_prefix, feat_name)
-                       >= BUFSIZE)
+       if ((sensor_list != NULL)
+                       && (ignorelist_match (sensor_list, type_instance)))
                return;
 
-       /* skip ignored in our config */
-       if ((NULL != sensor_list) && ignorelist_match (sensor_list, inst))
-               return;
+       values[0].gauge = val;
 
-       if (snprintf (buf, BUFSIZE, "%u:%.3f", (unsigned int) curtime,
-                               value) >= BUFSIZE)
-               return;
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "sensors");
+       strcpy (vl.plugin_instance, plugin_instance);
+       strcpy (vl.type_instance, type_instance);
 
-       if (type == SENSOR_TYPE_VOLTAGE)
-       {
-               DBG ("%s: %s/%s, %s", MODULE_NAME_VOLTAGE,
-                               sensor_type_prefix[type], inst, buf);
-               plugin_submit (MODULE_NAME_VOLTAGE, inst, buf);
-       }
-       else
-       {
-               DBG ("%s: %s/%s, %s", MODULE_NAME,
-                               sensor_type_prefix[type], inst, buf);
-               plugin_submit (MODULE_NAME, inst, buf);
-       }
-}
+       plugin_dispatch_values (type, &vl);
+} /* void sensors_submit */
 
-static void sensors_read (void)
+static int sensors_read (void)
 {
        featurelist_t *feature;
        double value;
-       char chip_fullprefix[BUFSIZE];
+
+       char plugin_instance[DATA_MAX_NAME_LEN];
+       char type_instance[DATA_MAX_NAME_LEN];
 
        sensors_load_conf ();
 
@@ -485,62 +409,62 @@ static void sensors_read (void)
                if (sensors_get_feature (*feature->chip, feature->data->number, &value) < 0)
                        continue;
 
-               if (sensor_extended_naming)
+               /* full chip name logic borrowed from lm_sensors */
+               if (feature->chip->bus == SENSORS_CHIP_NAME_BUS_ISA)
                {
-                       /* full chip name logic borrowed from lm_sensors */
-                       if (feature->chip->bus == SENSORS_CHIP_NAME_BUS_ISA)
-                       {
-                               if (snprintf (chip_fullprefix, BUFSIZE, "%s-isa-%04x/%s",
-                                                       feature->chip->prefix,
-                                                       feature->chip->addr,
-                                                       sensor_type_prefix[feature->type])
-                                               >= BUFSIZE)
-                                       continue;
-                       }
-                       else if (feature->chip->bus == SENSORS_CHIP_NAME_BUS_DUMMY)
-                       {
-                               if (snprintf (chip_fullprefix, BUFSIZE, "%s-%s-%04x/%s",
-                                                       feature->chip->prefix,
-                                                       feature->chip->busname,
-                                                       feature->chip->addr,
-                                                       sensor_type_prefix[feature->type])
-                                               >= BUFSIZE)
-                                       continue;
-                       }
-                       else
-                       {
-                               if (snprintf (chip_fullprefix, BUFSIZE, "%s-i2c-%d-%02x/%s",
-                                                       feature->chip->prefix,
-                                                       feature->chip->bus,
-                                                       feature->chip->addr,
-                                                       sensor_type_prefix[feature->type])
-                                               >= BUFSIZE)
-                                       continue;
-                       }
-
-                       sensors_submit (feature->data->name,
-                                       chip_fullprefix,
-                                       value, feature->type);
+                       if (snprintf (plugin_instance, DATA_MAX_NAME_LEN, "%s-isa-%04x",
+                                               feature->chip->prefix,
+                                               feature->chip->addr)
+                                       >= 512)
+                               continue;
+               }
+               else if (feature->chip->bus == SENSORS_CHIP_NAME_BUS_DUMMY)
+               {
+                       if (snprintf (plugin_instance, 512, "%s-%s-%04x",
+                                               feature->chip->prefix,
+                                               feature->chip->busname,
+                                               feature->chip->addr)
+                                       >= 512)
+                               continue;
                }
                else
                {
-                       sensors_submit (feature->data->name,
-                                       feature->chip->prefix,
-                                       value, feature->type);
+                       if (snprintf (plugin_instance, 512, "%s-i2c-%d-%02x",
+                                               feature->chip->prefix,
+                                               feature->chip->bus,
+                                               feature->chip->addr)
+                                       >= 512)
+                               continue;
                }
+
+               strncpy (type_instance, feature->data->name, DATA_MAX_NAME_LEN);
+
+               sensors_submit (plugin_instance,
+                               sensor_to_type[feature->type],
+                               type_instance,
+                               value);
        } /* for feature = first_feature .. NULL */
-} /* void sensors_read */
-#else
-# define sensors_read NULL
+
+       return (0);
+} /* int sensors_read */
 #endif /* SENSORS_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, collectd_sensors_init, sensors_read, sensors_write);
-       plugin_register (MODULE_NAME_VOLTAGE, NULL, NULL, sensors_voltage_write);
-       plugin_register_shutdown (MODULE_NAME, sensors_shutdown);
-       cf_register (MODULE_NAME, sensors_config, config_keys, config_keys_num);
-}
+       if (load & MR_DATASETS)
+       {
+               plugin_register_data_set (&fanspeed_ds);
+               plugin_register_data_set (&temperature_ds);
+               plugin_register_data_set (&voltage_ds);
+       }
 
-#undef BUFSIZE
-#undef MODULE_NAME
+#if SENSORS_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_config ("sensors", sensors_config,
+                               config_keys, config_keys_num);
+               plugin_register_read ("sensors", sensors_read);
+               plugin_register_shutdown ("sensors", sensors_shutdown);
+       }
+#endif
+} /* void module_register */
index 0c6050d..c278672 100644 (file)
 #include "common.h"
 #include "plugin.h"
 
-#define MODULE_NAME "serial"
-
 #if defined(KERNEL_LINUX)
 # define SERIAL_HAVE_READ 1
 #else
 # define SERIAL_HAVE_READ 0
 #endif
 
-static char *serial_filename_template = "serial-%s.rrd";
-
-static char *ds_def[] =
+static data_source_t octets_dsrc[2] =
 {
-       "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       NULL
+       {"rx", DS_TYPE_COUNTER, 0, 4294967295.0},
+       {"tx", DS_TYPE_COUNTER, 0, 4294967295.0}
 };
-static int ds_num = 2;
 
-static void serial_init (void)
+static data_set_t octets_ds =
 {
-       return;
-}
+       "serial_octets", 2, octets_dsrc
+};
 
-static void serial_write (char *host, char *inst, char *val)
+#if SERIAL_HAVE_READ
+static void serial_submit (const char *type_instance,
+               counter_t rx, counter_t tx)
 {
-       char file[512];
-       int status;
+       value_t values[2];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       status = snprintf (file, 512, serial_filename_template, inst);
-       if (status < 1)
-               return;
-       else if (status >= 512)
-               return;
+       values[0].counter = rx;
+       values[1].counter = tx;
 
-       rrd_update_file (host, file, val, ds_def, ds_num);
-}
-
-#if SERIAL_HAVE_READ
-#define BUFSIZE 512
-static void serial_submit (char *device,
-               unsigned long long incoming,
-               unsigned long long outgoing)
-{
-       char buf[BUFSIZE];
-        
-       if (snprintf (buf, BUFSIZE, "%u:%llu:%llu", (unsigned int) curtime,
-                               incoming, outgoing) >= BUFSIZE)
-               return;
+       vl.values = values;
+       vl.values_len = 2;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "serial");
+       strncpy (vl.type_instance, type_instance,
+                       sizeof (vl.type_instance));
 
-       plugin_submit (MODULE_NAME, device, buf);
+       plugin_dispatch_values ("serial_octets", &vl);
 }
-#undef BUFSIZE
 
-static void serial_read (void)
+static int serial_read (void)
 {
 #ifdef KERNEL_LINUX
-
        FILE *fh;
        char buffer[1024];
-       unsigned long long incoming, outgoing;
+
+       counter_t rx = 0;
+       counter_t tx = 0;
        
        char *fields[16];
        int i, numfields;
@@ -94,21 +80,16 @@ static void serial_read (void)
        if ((fh = fopen ("/proc/tty/driver/serial", "r")) == NULL &&
                (fh = fopen ("/proc/tty/driver/ttyS", "r")) == NULL)
        {
-               syslog (LOG_WARNING, "serial: fopen: %s", strerror (errno));
-               return;
+               char errbuf[1024];
+               WARNING ("serial: fopen: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
        }
 
-       while (fgets (buffer, 1024, fh) != NULL)
+       while (fgets (buffer, sizeof (buffer), fh) != NULL)
        {
                int have_rx = 0, have_tx = 0;
 
-               /* stupid compiler:
-                * serial.c:87: warning: 'incoming' may be used uninitialized in this function
-                * serial.c:87: warning: 'outgoing' may be used uninitialized in this function
-                */
-               incoming = 0ULL;
-               outgoing = 0ULL;
-
                numfields = strsplit (buffer, fields, 16);
 
                if (numfields < 6)
@@ -133,12 +114,12 @@ static void serial_read (void)
 
                        if (strncmp (fields[i], "tx:", 3) == 0)
                        {
-                               outgoing = atoll (fields[i] + 3);
+                               tx = atoll (fields[i] + 3);
                                have_tx++;
                        }
                        else if (strncmp (fields[i], "rx:", 3) == 0)
                        {
-                               incoming = atoll (fields[i] + 3);
+                               rx = atoll (fields[i] + 3);
                                have_rx++;
                        }
                }
@@ -146,19 +127,22 @@ static void serial_read (void)
                if ((have_rx == 0) || (have_tx == 0))
                        continue;
 
-               serial_submit (fields[0], incoming, outgoing);
+               serial_submit (fields[0], rx, tx);
        }
 
        fclose (fh);
+       return (0);
 #endif /* KERNEL_LINUX */
-}
-#else
-# define serial_read NULL
+} /* int serial_read */
 #endif /* SERIAL_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-   plugin_register (MODULE_NAME, serial_init, serial_read, serial_write);
-}
+       if (load & MR_DATASETS)
+               plugin_register_data_set (&octets_ds);
 
-#undef MODULE_NAME
+#if SERIAL_HAVE_READ
+       if (load & MR_READ)
+               plugin_register_read ("serial", serial_read);
+#endif /* SERIAL_HAVE_READ */
+} /* void module_register */
index 43275fc..86bdc35 100644 (file)
@@ -1,11 +1,10 @@
 /**
  * collectd - src/swap.c
- * Copyright (C) 2005,2006  Florian octo Forster
+ * Copyright (C) 2005-2007  Florian octo Forster
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -37,8 +36,6 @@
 #  include <kvm.h>
 #endif
 
-#define MODULE_NAME "swap"
-
 #if KERNEL_LINUX || HAVE_LIBKSTAT || defined(VM_SWAPUSAGE) || HAVE_LIBKVM || HAVE_LIBSTATGRAB
 # define SWAP_HAVE_READ 1
 #else
 #undef  MAX
 #define MAX(x,y) ((x) > (y) ? (x) : (y))
 
-static char *swap_file = "swap.rrd";
+static data_source_t data_source[1] =
+{
+       {"value", DS_TYPE_GAUGE, 0, 1099511627776.0}
+};
 
-/* 1099511627776 == 1TB ought to be enough for anyone ;) */
-static char *ds_def[] =
+static data_set_t data_set =
 {
-       "DS:used:GAUGE:"COLLECTD_HEARTBEAT":0:1099511627776",
-       "DS:free:GAUGE:"COLLECTD_HEARTBEAT":0:1099511627776",
-       "DS:cached:GAUGE:"COLLECTD_HEARTBEAT":0:1099511627776",
-       "DS:resv:GAUGE:"COLLECTD_HEARTBEAT":0:1099511627776",
-       NULL
+       "swap", 1, data_source
 };
-static int ds_num = 4;
 
+#if SWAP_HAVE_READ
 #if KERNEL_LINUX
 /* No global variables */
 /* #endif KERNEL_LINUX */
@@ -83,7 +78,7 @@ int kvm_pagesize;
 /* No global variables */
 #endif /* HAVE_LIBSTATGRAB */
 
-static void swap_init (void)
+static int swap_init (void)
 {
 #if KERNEL_LINUX
        /* No init stuff */
@@ -116,8 +111,8 @@ static void swap_init (void)
                                        NULL)) /* errstr */
                        == NULL)
        {
-               syslog (LOG_ERR, "swap plugin: kvm_open failed.");
-               return;
+               ERROR ("swap plugin: kvm_open failed.");
+               return (-1);
        }
 /* #endif HAVE_LIBKVM */
 
@@ -125,30 +120,27 @@ static void swap_init (void)
        /* No init stuff */
 #endif /* HAVE_LIBSTATGRAB */
 
-       return;
+       return (0);
 }
 
-static void swap_write (char *host, char *inst, char *val)
+static void swap_submit (const char *type_instance, double value)
 {
-       rrd_update_file (host, swap_file, val, ds_def, ds_num);
-}
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-#if SWAP_HAVE_READ
-static void swap_submit (unsigned long long swap_used,
-               unsigned long long swap_free,
-               unsigned long long swap_cached,
-               unsigned long long swap_resv)
-{
-       char buffer[512];
+       values[0].gauge = value;
 
-       if (snprintf (buffer, 512, "%u:%llu:%llu:%llu:%llu", (unsigned int) curtime,
-                               swap_used, swap_free, swap_cached, swap_resv) >= 512)
-               return;
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "swap");
+       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       plugin_submit (MODULE_NAME, "-", buffer);
-}
+       plugin_dispatch_values ("swap", &vl);
+} /* void swap_submit */
 
-static void swap_read (void)
+static int swap_read (void)
 {
 #if KERNEL_LINUX
        FILE *fh;
@@ -164,8 +156,10 @@ static void swap_read (void)
 
        if ((fh = fopen ("/proc/meminfo", "r")) == NULL)
        {
-               syslog (LOG_WARNING, "memory: fopen: %s", strerror (errno));
-               return;
+               char errbuf[1024];
+               WARNING ("memory: fopen: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
        }
 
        while (fgets (buffer, 1024, fh) != NULL)
@@ -190,14 +184,20 @@ static void swap_read (void)
        }
 
        if (fclose (fh))
-               syslog (LOG_WARNING, "memory: fclose: %s", strerror (errno));
+       {
+               char errbuf[1024];
+               WARNING ("memory: fclose: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+       }
 
        if ((swap_total == 0LL) || ((swap_free + swap_cached) > swap_total))
-               return;
+               return (-1);
 
        swap_used = swap_total - (swap_free + swap_cached);
 
-       swap_submit (swap_used, swap_free, swap_cached, -1LL);
+       swap_submit ("used", swap_used);
+       swap_submit ("free", swap_free);
+       swap_submit ("cached", swap_cached);
 /* #endif KERNEL_LINUX */
 
 #elif HAVE_LIBKSTAT
@@ -209,9 +209,10 @@ static void swap_read (void)
 
        if (swapctl (SC_AINFO, &ai) == -1)
        {
-               syslog (LOG_ERR, "swap plugin: swapctl failed: %s",
-                               strerror (errno));
-               return;
+               char errbuf[1024];
+               ERROR ("swap plugin: swapctl failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
        }
 
        /*
@@ -242,7 +243,9 @@ static void swap_read (void)
        swap_avail  = ai.ani_max - ai.ani_resv;
        swap_avail *= pagesize;
 
-       swap_submit (swap_alloc, swap_avail, -1LL, swap_resv - swap_alloc);
+       swap_submit ("used", swap_alloc);
+       swap_submit ("free", swap_avail);
+       swap_submit ("reserved", swap_resv - swap_alloc);
 /* #endif HAVE_LIBKSTAT */
 
 #elif defined(VM_SWAPUSAGE)
@@ -258,10 +261,11 @@ static void swap_read (void)
        sw_usage_len = sizeof (struct xsw_usage);
 
        if (sysctl (mib, mib_len, &sw_usage, &sw_usage_len, NULL, 0) != 0)
-               return;
+               return (-1);
 
        /* The returned values are bytes. */
-       swap_submit (sw_usage.xsu_used, sw_usage.xsu_avail, -1LL, -1LL);
+       swap_submit ("used", sw_usage.xsu_used);
+       swap_submit ("free", sw_usage.xsu_avail);
 /* #endif VM_SWAPUSAGE */
 
 #elif HAVE_LIBKVM
@@ -273,12 +277,12 @@ static void swap_read (void)
        unsigned long long total;
 
        if (kvm_obj == NULL)
-               return;
+               return (-1);
 
        /* only one structure => only get the grand total, no details */
        status = kvm_getswapinfo (kvm_obj, &data_s, 1, 0);
        if (status == -1)
-               return;
+               return (-1);
 
        total = (unsigned long long) data_s.ksw_total;
        used  = (unsigned long long) data_s.ksw_used;
@@ -288,23 +292,36 @@ static void swap_read (void)
 
        free = total - used;
 
-       swap_submit (used, free, -1LL, -1LL);
+       swap_submit ("used", used);
+       swap_submit ("free", free);
 /* #endif HAVE_LIBKVM */
 
 #elif HAVE_LIBSTATGRAB
        sg_swap_stats *swap;
 
-       if ((swap = sg_get_swap_stats ()) != NULL)
-               swap_submit (swap->used, swap->free, -1LL, -1LL);
+       swap = sg_get_swap_stats ();
+
+       if (swap == NULL)
+               return (-1);
+
+       swap_submit ("used", swap->used);
+       swap_submit ("free", swap->free);
 #endif /* HAVE_LIBSTATGRAB */
-}
-#else
-# define swap_read NULL
+
+       return (0);
+} /* int swap_read */
 #endif /* SWAP_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, swap_init, swap_read, swap_write);
-}
+       if (load & MR_DATASETS)
+               plugin_register_data_set (&data_set);
 
-#undef MODULE_NAME
+#if SWAP_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_init ("swap", swap_init);
+               plugin_register_read ("swap", swap_read);
+       }
+#endif /* SWAP_HAVE_READ */
+} /* void module_register */
diff --git a/src/syslog.c b/src/syslog.c
new file mode 100644 (file)
index 0000000..d643e39
--- /dev/null
@@ -0,0 +1,95 @@
+/**
+ * collectd - src/syslog.c
+ * Copyright (C) 2007  Florian Forster
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#if HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+static int log_level = LOG_DEBUG;
+
+static const char *config_keys[] =
+{
+       "LogLevel"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
+
+static int sl_config (const char *key, const char *value)
+{
+       if (strcasecmp (key, "LogLevel") == 0)
+       {
+               if ((strcasecmp (value, "emerg") == 0)
+                               || (strcasecmp (value, "alert") == 0)
+                               || (strcasecmp (value, "crit") == 0)
+                               || (strcasecmp (value, "err") == 0))
+                       log_level = LOG_ERR;
+               else if (strcasecmp (value, "warning") == 0)
+                       log_level = LOG_WARNING;
+               else if (strcasecmp (value, "notice") == 0)
+                       log_level = LOG_NOTICE;
+               else if (strcasecmp (value, "info") == 0)
+                       log_level = LOG_INFO;
+#if COLLECT_DEBUG
+               else if (strcasecmp (value, "debug") == 0)
+                       log_level = LOG_DEBUG;
+#endif
+               else
+                       return (1);
+       }
+       else
+               return (-1);
+
+       return (0);
+} /* int sl_config */
+
+static int sl_init (void)
+{
+       openlog ("collectd", LOG_CONS | LOG_PID, LOG_DAEMON);
+
+       return (0);
+}
+
+static void sl_log (int severity, const char *msg)
+{
+       if (severity > log_level)
+               return;
+
+       syslog (severity, "%s", msg);
+} /* void sl_log */
+
+static int sl_shutdown (void)
+{
+       closelog ();
+
+       return (0);
+}
+
+void module_register (modreg_e load)
+{
+       plugin_register_config ("syslog", sl_config, config_keys, config_keys_num);
+       plugin_register_init ("syslog", sl_init);
+       plugin_register_log ("syslog", sl_log);
+       plugin_register_shutdown ("syslog", sl_shutdown);
+} /* void module_register(void) */
index b13cdbd..2345cb3 100644 (file)
 #include "common.h"
 #include "plugin.h"
 
-#define MODULE_NAME "tape"
-
 #if defined(HAVE_LIBKSTAT)
 # define TAPE_HAVE_READ 1
 #else
 # define TAPE_HAVE_READ 0
 #endif
 
-static char *tape_filename_template = "tape-%s.rrd";
+/* 2^34 = 17179869184 = ~17.2GByte/s */
+static data_source_t octets_dsrc[2] =
+{
+       {"read",  DS_TYPE_COUNTER, 0, 17179869183.0},
+       {"write", DS_TYPE_COUNTER, 0, 17179869183.0}
+};
+
+static data_set_t octets_ds =
+{
+       "tape_octets", 2, octets_dsrc
+};
+
+static data_source_t operations_dsrc[2] =
+{
+       {"read",  DS_TYPE_COUNTER, 0, 4294967295.0},
+       {"write", DS_TYPE_COUNTER, 0, 4294967295.0}
+};
+
+static data_set_t operations_ds =
+{
+       "tape_ops", 2, operations_dsrc
+};
+
+static data_source_t merged_dsrc[2] =
+{
+       {"read",  DS_TYPE_COUNTER, 0, 4294967295.0},
+       {"write", DS_TYPE_COUNTER, 0, 4294967295.0}
+};
+
+static data_set_t merged_ds =
+{
+       "tape_merged", 2, merged_dsrc
+};
+
+/* max is 1000000us per second. */
+static data_source_t time_dsrc[2] =
+{
+       {"read",  DS_TYPE_COUNTER, 0, 1000000.0},
+       {"write", DS_TYPE_COUNTER, 0, 1000000.0}
+};
 
-/* 104857600 == 100 MB */
-static char *tape_ds_def[] =
+static data_set_t time_ds =
 {
-       "DS:rcount:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:rmerged:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:rbytes:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:rtime:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:wcount:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:wmerged:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:wbytes:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:wtime:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       NULL
+       "tape_time", 2, time_dsrc
 };
-static int tape_ds_num = 8;
 
+#if TAPE_HAVE_READ
 #if defined(HAVE_LIBKSTAT)
 #define MAX_NUMTAPE 256
 extern kstat_ctl_t *kc;
@@ -56,7 +84,7 @@ static kstat_t *ksp[MAX_NUMTAPE];
 static int numtape = 0;
 #endif /* HAVE_LIBKSTAT */
 
-static void tape_init (void)
+static int tape_init (void)
 {
 #ifdef HAVE_LIBKSTAT
        kstat_t *ksp_chain;
@@ -64,7 +92,7 @@ static void tape_init (void)
        numtape = 0;
 
        if (kc == NULL)
-               return;
+               return (-1);
 
        for (numtape = 0, ksp_chain = kc->kc_chain;
                        (numtape < MAX_NUMTAPE) && (ksp_chain != NULL);
@@ -78,52 +106,31 @@ static void tape_init (void)
        }
 #endif
 
-       return;
+       return (0);
 }
 
-static void tape_write (char *host, char *inst, char *val)
+static void tape_submit (const char *plugin_instance,
+               const char *type,
+               counter_t read, counter_t write)
 {
-       char file[512];
-       int status;
-
-       status = snprintf (file, 512, tape_filename_template, inst);
-       if (status < 1)
-               return;
-       else if (status >= 512)
-               return;
+       value_t values[2];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       rrd_update_file (host, file, val, tape_ds_def, tape_ds_num);
-}
+       values[0].counter = read;
+       values[1].counter = write;
 
+       vl.values = values;
+       vl.values_len = 2;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "tape");
+       strncpy (vl.plugin_instance, plugin_instance,
+                       sizeof (vl.plugin_instance));
 
-#if TAPE_HAVE_READ
-#define BUFSIZE 512
-static void tape_submit (char *tape_name,
-               unsigned long long read_count,
-               unsigned long long read_merged,
-               unsigned long long read_bytes,
-               unsigned long long read_time,
-               unsigned long long write_count,
-               unsigned long long write_merged,
-               unsigned long long write_bytes,
-               unsigned long long write_time)
+       plugin_dispatch_values (type, &vl);
+} /* void tape_submit */
 
-{
-       char buf[BUFSIZE];
-
-       if (snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu",
-                               (unsigned int) curtime,
-                               read_count, read_merged, read_bytes, read_time,
-                               write_count, write_merged, write_bytes,
-                               write_time) >= BUFSIZE)
-               return;
-
-       plugin_submit (MODULE_NAME, tape_name, buf);
-}
-
-#undef BUFSIZE
-
-static void tape_read (void)
+static int tape_read (void)
 {
 
 #if defined(HAVE_LIBKSTAT)
@@ -131,7 +138,10 @@ static void tape_read (void)
        int i;
 
        if (kc == NULL)
-               return;
+               return (-1);
+
+       if (numtape <= 0)
+               return (-1);
 
        for (i = 0; i < numtape; i++)
        {
@@ -139,19 +149,34 @@ static void tape_read (void)
                        continue;
 
                if (strncmp (ksp[i]->ks_class, "tape", 4) == 0)
-                       tape_submit (ksp[i]->ks_name,
-                                       kio.reads,  0LL, kio.nread,    kio.rtime,
-                                       kio.writes, 0LL, kio.nwritten, kio.wtime);
+               {
+                       tape_submit (ksp[i]->ks_name, "tape_octets", kio.reads, kio.writes);
+                       tape_submit (ksp[i]->ks_name, "tape_ops", kio.nreads, kio.nwrites);
+                       /* FIXME: Convert this to microseconds if necessary */
+                       tape_submit (ksp[i]->ks_name, "tape_time", kio.rtime, kio.wtime);
+               }
        }
 #endif /* defined(HAVE_LIBKSTAT) */
+
+       return (0);
 }
-#else
-# define tape_read NULL
 #endif /* TAPE_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, tape_init, tape_read, tape_write);
-}
+       if (load & MR_DATASETS)
+       {
+               plugin_register_data_set (&octets_ds);
+               plugin_register_data_set (&operations_ds);
+               plugin_register_data_set (&merged_ds);
+               plugin_register_data_set (&time_ds);
+       }
 
-#undef MODULE_NAME
+#if TAPE_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_init ("tape", tape_init);
+               plugin_register_read ("tape", tape_read);
+       }
+#endif /* TAPE_HAVE_READ */
+}
diff --git a/src/traffic.c b/src/traffic.c
deleted file mode 100644 (file)
index 14b7dc3..0000000
+++ /dev/null
@@ -1,478 +0,0 @@
-/**
- * collectd - src/traffic.c
- * Copyright (C) 2005,2006  Florian octo Forster
- *
- * 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.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- *
- * Authors:
- *   Florian octo Forster <octo at verplant.org>
- *   Sune Marcher <sm at flork.dk>
- **/
-
-#include "collectd.h"
-#include "common.h"
-#include "plugin.h"
-#include "configfile.h"
-
-#if HAVE_SYS_TYPES_H
-#  include <sys/types.h>
-#endif
-#if HAVE_SYS_SOCKET_H
-#  include <sys/socket.h>
-#endif
-
-/* One cannot include both. This sucks. */
-#if HAVE_LINUX_IF_H
-#  include <linux/if.h>
-#elif HAVE_NET_IF_H
-#  include <net/if.h>
-#endif
-
-#if HAVE_LINUX_NETDEVICE_H
-#  include <linux/netdevice.h>
-#endif
-#if HAVE_IFADDRS_H
-#  include <ifaddrs.h>
-#endif
-
-#define MODULE_NAME "traffic"
-
-/*
- * Various people have reported problems with `getifaddrs' and varying versions
- * of `glibc'. That's why it's disabled by default. Since more statistics are
- * available this way one may enable it using the `--enable-getifaddrs' option
- * of the configure script. -octo
- */
-#if KERNEL_LINUX
-# if !COLLECT_GETIFADDRS
-#  undef HAVE_GETIFADDRS
-# endif /* !COLLECT_GETIFADDRS */
-#endif /* KERNEL_LINUX */
-
-#if HAVE_GETIFADDRS || KERNEL_LINUX || HAVE_LIBKSTAT || HAVE_LIBSTATGRAB
-# define TRAFFIC_HAVE_READ 1
-#else
-# define TRAFFIC_HAVE_READ 0
-#endif
-
-#define BUFSIZE 512
-
-/*
- * (Module-)Global variables
- */
-/* TODO: Move this to `interface-%s/<blah>.rrd' in version 4. */
-static char *bytes_file   = "traffic-%s.rrd";
-static char *packets_file = "interface-%s/if_packets.rrd";
-static char *errors_file  = "interface-%s/if_errors.rrd";
-/* TODO: Maybe implement multicast and broadcast counters */
-
-static char *config_keys[] =
-{
-       "Interface",
-       "IgnoreSelected",
-       NULL
-};
-static int config_keys_num = 2;
-
-static char *bytes_ds_def[] =
-{
-       "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       NULL
-};
-static int bytes_ds_num = 2;
-
-static char *packets_ds_def[] =
-{
-       "DS:rx:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:tx:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       NULL
-};
-static int packets_ds_num = 2;
-
-static char *errors_ds_def[] =
-{
-       "DS:rx:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:tx:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       NULL
-};
-static int errors_ds_num = 2;
-
-static char **if_list = NULL;
-static int    if_list_num = 0;
-/* 
- * if_list_action:
- * 0 => default is to collect selected interface
- * 1 => ignore selcted interfaces
- */
-static int    if_list_action = 0;
-
-#ifdef HAVE_LIBKSTAT
-#define MAX_NUMIF 256
-extern kstat_ctl_t *kc;
-static kstat_t *ksp[MAX_NUMIF];
-static int numif = 0;
-#endif /* HAVE_LIBKSTAT */
-
-static int traffic_config (char *key, char *value)
-{
-       char **temp;
-
-       if (strcasecmp (key, "Interface") == 0)
-       {
-               temp = (char **) realloc (if_list, (if_list_num + 1) * sizeof (char *));
-               if (temp == NULL)
-               {
-                       syslog (LOG_EMERG, "Cannot allocate more memory.");
-                       return (1);
-               }
-               if_list = temp;
-
-               if ((if_list[if_list_num] = strdup (value)) == NULL)
-               {
-                       syslog (LOG_EMERG, "Cannot allocate memory.");
-                       return (1);
-               }
-               if_list_num++;
-       }
-       else if (strcasecmp (key, "IgnoreSelected") == 0)
-       {
-               if ((strcasecmp (value, "True") == 0)
-                               || (strcasecmp (value, "Yes") == 0)
-                               || (strcasecmp (value, "On") == 0))
-                       if_list_action = 1;
-               else
-                       if_list_action = 0;
-       }
-       else
-       {
-               return (-1);
-       }
-
-       return (0);
-}
-
-static void traffic_init (void)
-{
-#if HAVE_GETIFADDRS
-       /* nothing */
-/* #endif HAVE_GETIFADDRS */
-
-#elif KERNEL_LINUX
-       /* nothing */
-/* #endif KERNEL_LINUX */
-
-#elif HAVE_LIBKSTAT
-       kstat_t *ksp_chain;
-       unsigned long long val;
-
-       numif = 0;
-
-       if (kc == NULL)
-               return;
-
-       for (numif = 0, ksp_chain = kc->kc_chain;
-                       (numif < MAX_NUMIF) && (ksp_chain != NULL);
-                       ksp_chain = ksp_chain->ks_next)
-       {
-               if (strncmp (ksp_chain->ks_class, "net", 3))
-                       continue;
-               if (ksp_chain->ks_type != KSTAT_TYPE_NAMED)
-                       continue;
-               if (kstat_read (kc, ksp_chain, NULL) == -1)
-                       continue;
-               if ((val = get_kstat_value (ksp_chain, "obytes")) == -1LL)
-                       continue;
-               ksp[numif++] = ksp_chain;
-       }
-/* #endif HAVE_LIBKSTAT */
-
-#elif HAVE_LIBSTATG
-       /* nothing */
-#endif /* HAVE_LIBSTATG */
-
-       return;
-}
-
-/*
- * Check if this interface/instance should be ignored. This is called from
- * both, `submit' and `write' to give client and server the ability to
- * ignore certain stuff..
- */
-static int check_ignore_if (const char *interface)
-{
-       int i;
-
-       /* If no interfaces are given collect all interfaces. Mostly to be
-        * backwards compatible, but also because this is much easier. */
-       if (if_list_num < 1)
-               return (0);
-
-       for (i = 0; i < if_list_num; i++)
-               if (strcasecmp (interface, if_list[i]) == 0)
-                       return (if_list_action);
-       return (1 - if_list_action);
-}
-
-static void generic_write (char *host, char *inst, char *val,
-               char *file_template,
-               char **ds_def, int ds_num)
-{
-       char file[512];
-       int status;
-
-       if (check_ignore_if (inst))
-               return;
-
-       status = snprintf (file, BUFSIZE, file_template, inst);
-       if (status < 1)
-               return;
-       else if (status >= 512)
-               return;
-
-       rrd_update_file (host, file, val, ds_def, ds_num);
-}
-
-static void bytes_write (char *host, char *inst, char *val)
-{
-       generic_write (host, inst, val, bytes_file, bytes_ds_def, bytes_ds_num);
-}
-
-static void packets_write (char *host, char *inst, char *val)
-{
-       generic_write (host, inst, val, packets_file, packets_ds_def, packets_ds_num);
-}
-
-static void errors_write (char *host, char *inst, char *val)
-{
-       generic_write (host, inst, val, errors_file, errors_ds_def, errors_ds_num);
-}
-
-#if TRAFFIC_HAVE_READ
-static void bytes_submit (char *dev,
-               unsigned long long rx,
-               unsigned long long tx)
-{
-       char buf[512];
-       int  status;
-
-       if (check_ignore_if (dev))
-               return;
-
-       status = snprintf (buf, 512, "%u:%lld:%lld",
-                               (unsigned int) curtime,
-                               rx, tx);
-       if ((status >= 512) || (status < 1))
-               return;
-
-       plugin_submit (MODULE_NAME, dev, buf);
-}
-
-#if HAVE_GETIFADDRS || KERNEL_LINUX || HAVE_LIBKSTAT
-static void packets_submit (char *dev,
-               unsigned long long rx,
-               unsigned long long tx)
-{
-       char buf[512];
-       int  status;
-
-       if (check_ignore_if (dev))
-               return;
-
-       status = snprintf (buf, 512, "%u:%lld:%lld",
-                       (unsigned int) curtime,
-                       rx, tx);
-       if ((status >= 512) || (status < 1))
-               return;
-       plugin_submit ("if_packets", dev, buf);
-}
-
-static void errors_submit (char *dev,
-               unsigned long long rx,
-               unsigned long long tx)
-{
-       char buf[512];
-       int  status;
-
-       if (check_ignore_if (dev))
-               return;
-
-       status = snprintf (buf, 512, "%u:%lld:%lld",
-                       (unsigned int) curtime,
-                       rx, tx);
-       if ((status >= 512) || (status < 1))
-               return;
-       plugin_submit ("if_errors", dev, buf);
-}
-#endif /* HAVE_GETIFADDRS || KERNEL_LINUX || HAVE_LIBKSTAT */
-
-static void traffic_read (void)
-{
-#if HAVE_GETIFADDRS
-       struct ifaddrs *if_list;
-       struct ifaddrs *if_ptr;
-
-/* Darin/Mac OS X and possible other *BSDs */
-#if HAVE_STRUCT_IF_DATA
-#  define IFA_DATA if_data
-#  define IFA_RX_BYTES ifi_ibytes
-#  define IFA_TX_BYTES ifi_obytes
-#  define IFA_RX_PACKT ifi_ipackets
-#  define IFA_TX_PACKT ifi_opackets
-#  define IFA_RX_ERROR ifi_ierrors
-#  define IFA_TX_ERROR ifi_oerrors
-/* #endif HAVE_STRUCT_IF_DATA */
-
-#elif HAVE_STRUCT_NET_DEVICE_STATS
-#  define IFA_DATA net_device_stats
-#  define IFA_RX_BYTES rx_bytes
-#  define IFA_TX_BYTES tx_bytes
-#  define IFA_RX_PACKT rx_packets
-#  define IFA_TX_PACKT tx_packets
-#  define IFA_RX_ERROR rx_errors
-#  define IFA_TX_ERROR tx_errors
-#else
-#  error "No suitable type for `struct ifaddrs->ifa_data' found."
-#endif
-
-       struct IFA_DATA *if_data;
-
-       if (getifaddrs (&if_list) != 0)
-               return;
-
-       for (if_ptr = if_list; if_ptr != NULL; if_ptr = if_ptr->ifa_next)
-       {
-               if ((if_data = (struct IFA_DATA *) if_ptr->ifa_data) == NULL)
-                       continue;
-
-               bytes_submit (if_ptr->ifa_name,
-                               if_data->IFA_RX_BYTES,
-                               if_data->IFA_TX_BYTES);
-               packets_submit (if_ptr->ifa_name,
-                               if_data->IFA_RX_PACKT,
-                               if_data->IFA_TX_PACKT);
-               errors_submit (if_ptr->ifa_name,
-                               if_data->IFA_RX_ERROR,
-                               if_data->IFA_TX_ERROR);
-       }
-
-       freeifaddrs (if_list);
-/* #endif HAVE_GETIFADDRS */
-
-#elif KERNEL_LINUX
-       FILE *fh;
-       char buffer[1024];
-       unsigned long long incoming, outgoing;
-       char *device;
-       
-       char *dummy;
-       char *fields[16];
-       int numfields;
-
-       if ((fh = fopen ("/proc/net/dev", "r")) == NULL)
-       {
-               syslog (LOG_WARNING, "traffic: fopen: %s", strerror (errno));
-               return;
-       }
-
-       while (fgets (buffer, 1024, fh) != NULL)
-       {
-               if (!(dummy = strchr(buffer, ':')))
-                       continue;
-               dummy[0] = '\0';
-               dummy++;
-
-               device = buffer;
-               while (device[0] == ' ')
-                       device++;
-
-               if (device[0] == '\0')
-                       continue;
-               
-               numfields = strsplit (dummy, fields, 16);
-
-               if (numfields < 11)
-                       continue;
-
-               incoming = atoll (fields[0]);
-               outgoing = atoll (fields[8]);
-               bytes_submit (device, incoming, outgoing);
-
-               incoming = atoll (fields[1]);
-               outgoing = atoll (fields[9]);
-               packets_submit (device, incoming, outgoing);
-
-               incoming = atoll (fields[2]);
-               outgoing = atoll (fields[10]);
-               errors_submit (device, incoming, outgoing);
-       }
-
-       fclose (fh);
-/* #endif KERNEL_LINUX */
-
-#elif HAVE_LIBKSTAT
-       int i;
-       unsigned long long rx;
-       unsigned long long tx;
-
-       if (kc == NULL)
-               return;
-
-       for (i = 0; i < numif; i++)
-       {
-               if (kstat_read (kc, ksp[i], NULL) == -1)
-                       continue;
-
-               rx = get_kstat_value (ksp[i], "rbytes");
-               tx = get_kstat_value (ksp[i], "obytes");
-               if ((rx != -1LL) || (tx != -1LL))
-                       bytes_submit (ksp[i]->ks_name, rx, tx);
-
-               rx = get_kstat_value (ksp[i], "ipackets");
-               tx = get_kstat_value (ksp[i], "opackets");
-               if ((rx != -1LL) || (tx != -1LL))
-                       packets_submit (ksp[i]->ks_name, rx, tx);
-
-               rx = get_kstat_value (ksp[i], "ierrors");
-               tx = get_kstat_value (ksp[i], "oerrors");
-               if ((rx != -1LL) || (tx != -1LL))
-                       errors_submit (ksp[i]->ks_name, rx, tx);
-       }
-/* #endif HAVE_LIBKSTAT */
-
-#elif defined(HAVE_LIBSTATGRAB)
-       sg_network_io_stats *ios;
-       int i, num;
-
-       ios = sg_get_network_io_stats (&num);
-
-       for (i = 0; i < num; i++)
-               bytes_submit (ios[i].interface_name, ios[i].rx, ios[i].tx);
-#endif /* HAVE_LIBSTATGRAB */
-}
-#else
-#define traffic_read NULL
-#endif /* TRAFFIC_HAVE_READ */
-
-void module_register (void)
-{
-       plugin_register (MODULE_NAME, traffic_init, traffic_read, bytes_write);
-       plugin_register ("if_packets", NULL, NULL, packets_write);
-       plugin_register ("if_errors",  NULL, NULL, errors_write);
-       cf_register (MODULE_NAME, traffic_config, config_keys, config_keys_num);
-}
-
-#undef BUFSIZE
-#undef MODULE_NAME
diff --git a/src/unixsock.c b/src/unixsock.c
new file mode 100644 (file)
index 0000000..8524bea
--- /dev/null
@@ -0,0 +1,857 @@
+/**
+ * collectd - src/unixsock.c
+ * Copyright (C) 2007  Florian octo Forster
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Author:
+ *   Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+
+/* Folks without pthread will need to disable this plugin. */
+#include <pthread.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/poll.h>
+
+#include <grp.h>
+
+#ifndef UNIX_PATH_MAX
+# define UNIX_PATH_MAX sizeof (((struct sockaddr_un *)0)->sun_path)
+#endif
+
+#define US_DEFAULT_PATH PREFIX"/var/run/"PACKAGE_NAME"-unixsock"
+
+/*
+ * Private data structures
+ */
+/* linked list of cached values */
+typedef struct value_cache_s
+{
+       char       name[4*DATA_MAX_NAME_LEN];
+       int        values_num;
+       gauge_t   *gauge;
+       counter_t *counter;
+       const data_set_t *ds;
+       time_t     time;
+       struct value_cache_s *next;
+} value_cache_t;
+
+/*
+ * Private variables
+ */
+/* valid configuration file keys */
+static const char *config_keys[] =
+{
+       "SocketFile",
+       "SocketGroup",
+       "SocketPerms",
+       NULL
+};
+static int config_keys_num = 3;
+
+static int loop = 0;
+
+/* socket configuration */
+static int   sock_fd    = -1;
+static char *sock_file  = NULL;
+static char *sock_group = NULL;
+static int   sock_perms = S_IRWXU | S_IRWXG;
+
+static pthread_t listen_thread = (pthread_t) 0;
+
+/* Linked list and auxilliary variables for saving values */
+static value_cache_t   *cache_head = NULL;
+static pthread_mutex_t  cache_lock = PTHREAD_MUTEX_INITIALIZER;
+static unsigned int     cache_oldest = UINT_MAX;
+
+/*
+ * Functions
+ */
+static int parse_identifier (char *str, char **ret_host,
+               char **ret_plugin, char **ret_plugin_instance,
+               char **ret_type, char **ret_type_instance)
+{
+       char *hostname = NULL;
+       char *plugin = NULL;
+       char *plugin_instance = NULL;
+       char *type = NULL;
+       char *type_instance = NULL;
+
+       hostname = str;
+       if (hostname == NULL)
+               return (-1);
+
+       plugin = strchr (hostname, '/');
+       if (plugin == NULL)
+               return (-1);
+       *plugin = '\0'; plugin++;
+
+       type = strchr (plugin, '/');
+       if (type == NULL)
+               return (-1);
+       *type = '\0'; type++;
+
+       plugin_instance = strchr (plugin, '-');
+       if (plugin_instance != NULL)
+       {
+               *plugin_instance = '\0';
+               plugin_instance++;
+       }
+
+       type_instance = strchr (type, '-');
+       if (type_instance != NULL)
+       {
+               *type_instance = '\0';
+               type_instance++;
+       }
+
+       *ret_host = hostname;
+       *ret_plugin = plugin;
+       *ret_plugin_instance = plugin_instance;
+       *ret_type = type;
+       *ret_type_instance = type_instance;
+       return (0);
+} /* int parse_identifier */
+
+static value_cache_t *cache_search (const char *name)
+{
+       value_cache_t *vc;
+
+       for (vc = cache_head; vc != NULL; vc = vc->next)
+       {
+               if (strcmp (vc->name, name) == 0)
+                       break;
+       } /* for vc = cache_head .. NULL */
+
+       return (vc);
+} /* value_cache_t *cache_search */
+
+static int cache_insert (const data_set_t *ds, const value_list_t *vl)
+{
+       /* We're called from `cache_update' so we don't need to lock the mutex */
+       value_cache_t *vc;
+       int i;
+
+       DEBUG ("unixsock plugin: cache_insert: ds->ds_num = %i;"
+                       " vl->values_len = %i;",
+                       ds->ds_num, vl->values_len);
+       assert (ds->ds_num == vl->values_len);
+
+       vc = (value_cache_t *) malloc (sizeof (value_cache_t));
+       if (vc == NULL)
+       {
+               char errbuf[1024];
+               pthread_mutex_unlock (&cache_lock);
+               ERROR ("unixsock plugin: malloc failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
+
+       vc->gauge = (gauge_t *) malloc (sizeof (gauge_t) * vl->values_len);
+       if (vc->gauge == NULL)
+       {
+               char errbuf[1024];
+               pthread_mutex_unlock (&cache_lock);
+               ERROR ("unixsock plugin: malloc failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               free (vc);
+               return (-1);
+       }
+
+       vc->counter = (counter_t *) malloc (sizeof (counter_t) * vl->values_len);
+       if (vc->counter == NULL)
+       {
+               char errbuf[1024];
+               pthread_mutex_unlock (&cache_lock);
+               ERROR ("unixsock plugin: malloc failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               free (vc->gauge);
+               free (vc);
+               return (-1);
+       }
+
+       if (FORMAT_VL (vc->name, sizeof (vc->name), vl, ds))
+       {
+               pthread_mutex_unlock (&cache_lock);
+               ERROR ("unixsock plugin: FORMAT_VL failed.");
+               free (vc->counter);
+               free (vc->gauge);
+               free (vc);
+               return (-1);
+       }
+
+       for (i = 0; i < ds->ds_num; i++)
+       {
+               if (ds->ds[i].type == DS_TYPE_COUNTER)
+               {
+                       vc->gauge[i] = 0.0;
+                       vc->counter[i] = vl->values[i].counter;
+               }
+               else if (ds->ds[i].type == DS_TYPE_GAUGE)
+               {
+                       vc->gauge[i] = vl->values[i].gauge;
+                       vc->counter[i] = 0;
+               }
+               else
+               {
+                       vc->gauge[i] = 0.0;
+                       vc->counter[i] = 0;
+               }
+       }
+       vc->values_num = ds->ds_num;
+       vc->ds = ds;
+
+       vc->next = cache_head;
+       cache_head = vc;
+
+       vc->time = vl->time;
+       if (vc->time < cache_oldest)
+               cache_oldest = vc->time;
+
+       pthread_mutex_unlock (&cache_lock);
+       return (0);
+} /* int cache_insert */
+
+static int cache_update (const data_set_t *ds, const value_list_t *vl)
+{
+       char name[4*DATA_MAX_NAME_LEN];;
+       value_cache_t *vc;
+       int i;
+
+       if (FORMAT_VL (name, sizeof (name), vl, ds) != 0)
+               return (-1);
+
+       pthread_mutex_lock (&cache_lock);
+
+       vc = cache_search (name);
+
+       if (vc == NULL)
+               return (cache_insert (ds, vl));
+
+       assert (vc->values_num == ds->ds_num);
+       assert (vc->values_num == vl->values_len);
+
+       /*
+        * Update the values. This is possibly a lot more that you'd expect
+        * because we honor min and max values and handle counter overflows here.
+        */
+       for (i = 0; i < ds->ds_num; i++)
+       {
+               if (ds->ds[i].type == DS_TYPE_COUNTER)
+               {
+                       if (vl->values[i].counter < vc->counter[i])
+                       {
+                               if (vl->values[i].counter <= 4294967295U)
+                               {
+                                       vc->gauge[i] = ((4294967295U - vl->values[i].counter)
+                                                       + vc->counter[i]) / (vl->time - vc->time);
+                               }
+                               else
+                               {
+                                       vc->gauge[i] = ((18446744073709551615ULL - vl->values[i].counter)
+                                               + vc->counter[i]) / (vl->time - vc->time);
+                               }
+                       }
+                       else
+                       {
+                               vc->gauge[i] = (vl->values[i].counter - vc->counter[i])
+                                       / (vl->time - vc->time);
+                       }
+
+                       vc->counter[i] = vl->values[i].counter;
+               }
+               else if (ds->ds[i].type == DS_TYPE_GAUGE)
+               {
+                       vc->gauge[i] = vl->values[i].gauge;
+                       vc->counter[i] = 0;
+               }
+               else
+               {
+                       vc->gauge[i] = NAN;
+                       vc->counter[i] = 0;
+               }
+
+               if (isnan (vc->gauge[i])
+                               || (!isnan (ds->ds[i].min) && (vc->gauge[i] < ds->ds[i].min))
+                               || (!isnan (ds->ds[i].max) && (vc->gauge[i] > ds->ds[i].max)))
+                       vc->gauge[i] = NAN;
+       } /* for i = 0 .. ds->ds_num */
+
+       vc->ds = ds;
+       vc->time = vl->time;
+
+       if (vc->time < cache_oldest)
+               cache_oldest = vc->time;
+
+       pthread_mutex_unlock (&cache_lock);
+       return (0);
+} /* int cache_update */
+
+static void cache_flush (int max_age)
+{
+       value_cache_t *this;
+       value_cache_t *prev;
+       time_t now;
+
+       pthread_mutex_lock (&cache_lock);
+
+       now = time (NULL);
+
+       if ((now - cache_oldest) <= max_age)
+       {
+               pthread_mutex_unlock (&cache_lock);
+               return;
+       }
+       
+       cache_oldest = now;
+
+       prev = NULL;
+       this = cache_head;
+
+       while (this != NULL)
+       {
+               if ((now - this->time) <= max_age)
+               {
+                       if (this->time < cache_oldest)
+                               cache_oldest = this->time;
+
+                       prev = this;
+                       this = this->next;
+                       continue;
+               }
+
+               if (prev == NULL)
+                       cache_head = this->next;
+               else
+                       prev->next = this->next;
+
+               free (this->gauge);
+               free (this->counter);
+               free (this);
+
+               if (prev == NULL)
+                       this = cache_head;
+               else
+                       this = prev->next;
+       } /* while (this != NULL) */
+
+       pthread_mutex_unlock (&cache_lock);
+} /* int cache_flush */
+
+static int us_open_socket (void)
+{
+       struct sockaddr_un sa;
+       int status;
+
+       sock_fd = socket (PF_UNIX, SOCK_STREAM, 0);
+       if (sock_fd < 0)
+       {
+               char errbuf[1024];
+               ERROR ("unixsock plugin: socket failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
+
+       memset (&sa, '\0', sizeof (sa));
+       sa.sun_family = AF_UNIX;
+       strncpy (sa.sun_path, (sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
+                       sizeof (sa.sun_path) - 1);
+       /* unlink (sa.sun_path); */
+
+       status = bind (sock_fd, (struct sockaddr *) &sa, sizeof (sa));
+       if (status != 0)
+       {
+               char errbuf[1024];
+               sstrerror (errno, errbuf, sizeof (errbuf));
+               DEBUG ("bind failed: %s; sa.sun_path = %s", errbuf, sa.sun_path);
+               ERROR ("unixsock plugin: bind failed: %s", errbuf);
+               close (sock_fd);
+               sock_fd = -1;
+               return (-1);
+       }
+
+       status = listen (sock_fd, 8);
+       if (status != 0)
+       {
+               char errbuf[1024];
+               ERROR ("unixsock plugin: listen failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               close (sock_fd);
+               sock_fd = -1;
+               return (-1);
+       }
+
+       do
+       {
+               char *grpname;
+               struct group *g;
+               struct group sg;
+               char grbuf[2048];
+
+               grpname = (sock_group != NULL) ? sock_group : COLLECTD_GRP_NAME;
+               g = NULL;
+
+               status = getgrnam_r (grpname, &sg, grbuf, sizeof (grbuf), &g);
+               if (status != 0)
+               {
+                       char errbuf[1024];
+                       WARNING ("unixsock plugin: getgrnam_r (%s) failed: %s", grpname,
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+                       break;
+               }
+               if (g == NULL)
+               {
+                       WARNING ("unixsock plugin: No such group: `%s'",
+                                       grpname);
+                       break;
+               }
+
+               if (chown ((sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
+                                       (uid_t) -1, g->gr_gid) != 0)
+               {
+                       char errbuf[1024];
+                       WARNING ("unixsock plugin: chown (%s, -1, %i) failed: %s",
+                                       (sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
+                                       (int) g->gr_gid,
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+               }
+       } while (0);
+
+       return (0);
+} /* int us_open_socket */
+
+static int us_handle_getval (FILE *fh, char **fields, int fields_num)
+{
+       char *hostname;
+       char *plugin;
+       char *plugin_instance;
+       char *type;
+       char *type_instance;
+       char  name[4*DATA_MAX_NAME_LEN];
+       value_cache_t *vc;
+       int   status;
+       int   i;
+
+       if (fields_num != 2)
+       {
+               DEBUG ("unixsock plugin: Wrong number of fields: %i", fields_num);
+               fprintf (fh, "-1 Wrong number of fields: Got %i, expected 2.\n",
+                               fields_num);
+               fflush (fh);
+               return (-1);
+       }
+       DEBUG ("unixsock plugin: Got query for `%s'", fields[1]);
+
+       status = parse_identifier (fields[1], &hostname,
+                       &plugin, &plugin_instance,
+                       &type, &type_instance);
+       if (status != 0)
+       {
+               DEBUG ("unixsock plugin: Cannot parse `%s'", fields[1]);
+               fprintf (fh, "-1 Cannot parse identifier.\n");
+               fflush (fh);
+               return (-1);
+       }
+
+       status = format_name (name, sizeof (name),
+                       hostname, plugin, plugin_instance, type, type_instance);
+       /* FIXME: Send some response */
+       if (status != 0)
+               return (-1);
+
+       pthread_mutex_lock (&cache_lock);
+
+       DEBUG ("vc = cache_search (%s)", name);
+       vc = cache_search (name);
+
+       if (vc == NULL)
+       {
+               DEBUG ("Did not find cache entry.");
+               fprintf (fh, "-1 No such value");
+       }
+       else
+       {
+               DEBUG ("Found cache entry.");
+               fprintf (fh, "%i", vc->values_num);
+               for (i = 0; i < vc->values_num; i++)
+               {
+                       fprintf (fh, " %s=", vc->ds->ds[i].name);
+                       if (isnan (vc->gauge[i]))
+                               fprintf (fh, "NaN");
+                       else
+                               fprintf (fh, "%12e", vc->gauge[i]);
+               }
+       }
+
+       /* Free the mutex as soon as possible and definitely before flushing */
+       pthread_mutex_unlock (&cache_lock);
+
+       fprintf (fh, "\n");
+       fflush (fh);
+
+       return (0);
+} /* int us_handle_getval */
+
+static int us_handle_putval (FILE *fh, char **fields, int fields_num)
+{
+       char *hostname;
+       char *plugin;
+       char *plugin_instance;
+       char *type;
+       char *type_instance;
+       int   status;
+       int   i;
+
+       const data_set_t *ds;
+       value_list_t vl = VALUE_LIST_INIT;
+
+       char **value_ptr;
+
+       if (fields_num != 3)
+       {
+               DEBUG ("unixsock plugin: Wrong number of fields: %i", fields_num);
+               fprintf (fh, "-1 Wrong number of fields: Got %i, expected 3.\n",
+                               fields_num);
+               fflush (fh);
+               return (-1);
+       }
+
+       status = parse_identifier (fields[1], &hostname,
+                       &plugin, &plugin_instance,
+                       &type, &type_instance);
+       if (status != 0)
+       {
+               DEBUG ("unixsock plugin: Cannot parse `%s'", fields[1]);
+               fprintf (fh, "-1 Cannot parse identifier.\n");
+               fflush (fh);
+               return (-1);
+       }
+
+       /* FIXME: Send some response */
+       if ((strlen (hostname) > sizeof (vl.host))
+                       || (strlen (plugin) > sizeof (vl.plugin))
+                       || ((plugin_instance != NULL)
+                               && (strlen (plugin_instance) > sizeof (vl.plugin_instance)))
+                       || ((type_instance != NULL)
+                               && (strlen (type_instance) > sizeof (vl.type_instance))))
+               return (-1);
+
+       strcpy (vl.host, hostname);
+       strcpy (vl.plugin, plugin);
+       if (plugin_instance != NULL)
+               strcpy (vl.plugin_instance, plugin_instance);
+       if (type_instance != NULL)
+               strcpy (vl.type_instance, type_instance);
+
+       { /* parse the time */
+               char *t = fields[2];
+               char *v = strchr (t, ':');
+               if (v == NULL)
+                       return (-1);
+               *v = '\0'; v++;
+
+               vl.time = (time_t) atoi (t);
+               if (vl.time == 0)
+                       vl.time = time (NULL);
+
+               fields[2] = v;
+       }
+
+       ds = plugin_get_ds (type);
+       if (ds == NULL)
+               return (-1);
+
+       value_ptr = (char **) calloc (ds->ds_num, sizeof (char *));
+       /* FIXME: Send some response */
+       if (value_ptr == NULL)
+               return (-1);
+
+
+       { /* parse the value-list. It's colon-separated. */
+               char *dummy;
+               char *ptr;
+               char *saveptr;
+
+               i = 0;
+               dummy = fields[2];
+               saveptr = NULL;
+               while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL)
+               {
+                       dummy = NULL;
+                       if (i >= ds->ds_num)
+                       {
+                               i = ds->ds_num + 1;
+                               break;
+                       }
+                       value_ptr[i] = ptr;
+                       i++;
+               }
+
+               if (i != ds->ds_num)
+               {
+                       sfree (value_ptr);
+                       /* FIXME: Send some response */
+                       return (-1);
+               }
+       } /* done parsing the value-list */
+
+       vl.values_len = ds->ds_num;
+       vl.values = (value_t *) malloc (vl.values_len * sizeof (value_t));
+       if (vl.values == NULL)
+       {
+               sfree (value_ptr);
+               return (-1);
+       }
+       DEBUG ("value_ptr = 0x%p; vl.values = 0x%p;", (void *) value_ptr, (void *) vl.values);
+
+       for (i = 0; i < ds->ds_num; i++)
+       {
+               if (strcmp (value_ptr[i], "U") == 0)
+                       vl.values[i].gauge = NAN;
+               else if (ds->ds[i].type == DS_TYPE_COUNTER)
+                       vl.values[i].counter = atoll (value_ptr[i]);
+               else if (ds->ds[i].type == DS_TYPE_GAUGE)
+                       vl.values[i].gauge = atof (value_ptr[i]);
+       } /* for (i = 2 .. fields_num) */
+
+       plugin_dispatch_values (type, &vl);
+
+       DEBUG ("value_ptr = 0x%p; vl.values = 0x%p;", (void *) value_ptr, (void *) vl.values);
+
+       sfree (value_ptr);
+       sfree (vl.values); 
+
+       fprintf (fh, "0 Success\n");
+       fflush (fh);
+
+       return (0);
+} /* int us_handle_putval */
+
+static void *us_handle_client (void *arg)
+{
+       int fd;
+       FILE *fh;
+       char buffer[1024];
+       char *fields[128];
+       int   fields_num;
+
+       fd = *((int *) arg);
+       free (arg);
+       arg = NULL;
+
+       DEBUG ("Reading from fd #%i", fd);
+
+       fh = fdopen (fd, "r+");
+       if (fh == NULL)
+       {
+               char errbuf[1024];
+               ERROR ("unixsock plugin: fdopen failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               close (fd);
+               pthread_exit ((void *) 1);
+       }
+
+       while (fgets (buffer, sizeof (buffer), fh) != NULL)
+       {
+               int len;
+
+               len = strlen (buffer);
+               while ((len > 0)
+                               && ((buffer[len - 1] == '\n') || (buffer[len - 1] == '\r')))
+                       buffer[--len] = '\0';
+
+               if (len == 0)
+                       continue;
+
+               DEBUG ("fgets -> buffer = %s; len = %i;", buffer, len);
+
+               fields_num = strsplit (buffer, fields,
+                               sizeof (fields) / sizeof (fields[0]));
+
+               if (fields_num < 1)
+               {
+                       close (fd);
+                       break;
+               }
+
+               if (strcasecmp (fields[0], "getval") == 0)
+               {
+                       us_handle_getval (fh, fields, fields_num);
+               }
+               else if (strcasecmp (fields[0], "putval") == 0)
+               {
+                       us_handle_putval (fh, fields, fields_num);
+               }
+               else
+               {
+                       fprintf (fh, "Unknown command: %s\n", fields[0]);
+                       fflush (fh);
+               }
+       } /* while (fgets) */
+
+       DEBUG ("Exiting..");
+       close (fd);
+
+       pthread_exit ((void *) 0);
+} /* void *us_handle_client */
+
+static void *us_server_thread (void *arg)
+{
+       int  status;
+       int *remote_fd;
+       pthread_t th;
+       pthread_attr_t th_attr;
+
+       if (us_open_socket () != 0)
+               pthread_exit ((void *) 1);
+
+       while (loop != 0)
+       {
+               DEBUG ("Calling accept..");
+               status = accept (sock_fd, NULL, NULL);
+               if (status < 0)
+               {
+                       char errbuf[1024];
+
+                       if (errno == EINTR)
+                               continue;
+
+                       ERROR ("unixsock plugin: accept failed: %s",
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+                       close (sock_fd);
+                       sock_fd = -1;
+                       pthread_exit ((void *) 1);
+               }
+
+               remote_fd = (int *) malloc (sizeof (int));
+               if (remote_fd == NULL)
+               {
+                       char errbuf[1024];
+                       WARNING ("unixsock plugin: malloc failed: %s",
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+                       close (status);
+                       continue;
+               }
+               *remote_fd = status;
+
+               DEBUG ("Spawning child to handle connection on fd #%i", *remote_fd);
+
+               pthread_attr_init (&th_attr);
+               pthread_attr_setdetachstate (&th_attr, PTHREAD_CREATE_DETACHED);
+
+               status = pthread_create (&th, &th_attr, us_handle_client, (void *) remote_fd);
+               if (status != 0)
+               {
+                       char errbuf[1024];
+                       WARNING ("unixsock plugin: pthread_create failed: %s",
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+                       close (*remote_fd);
+                       free (remote_fd);
+                       continue;
+               }
+       } /* while (loop) */
+
+       close (sock_fd);
+       sock_fd = -1;
+
+       return ((void *) 0);
+} /* void *us_server_thread */
+
+static int us_config (const char *key, const char *val)
+{
+       if (strcasecmp (key, "SocketFile") == 0)
+       {
+               sfree (sock_file);
+               sock_file = strdup (val);
+       }
+       else if (strcasecmp (key, "SocketGroup") == 0)
+       {
+               sfree (sock_group);
+               sock_group = strdup (val);
+       }
+       else if (strcasecmp (key, "SocketPerms") == 0)
+       {
+               sock_perms = (int) strtol (val, NULL, 8);
+       }
+       else
+       {
+               return (-1);
+       }
+
+       return (0);
+} /* int us_config */
+
+static int us_init (void)
+{
+       int status;
+
+       loop = 1;
+
+       status = pthread_create (&listen_thread, NULL, us_server_thread, NULL);
+       if (status != 0)
+       {
+               char errbuf[1024];
+               ERROR ("unixsock plugin: pthread_create failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
+
+       return (0);
+} /* int us_init */
+
+static int us_shutdown (void)
+{
+       void *ret;
+
+       loop = 0;
+
+       if (listen_thread != (pthread_t) 0)
+       {
+               pthread_kill (listen_thread, SIGTERM);
+               pthread_join (listen_thread, &ret);
+               listen_thread = (pthread_t) 0;
+       }
+
+       plugin_unregister_init ("unixsock");
+       plugin_unregister_write ("unixsock");
+       plugin_unregister_shutdown ("unixsock");
+
+       return (0);
+} /* int us_shutdown */
+
+static int us_write (const data_set_t *ds, const value_list_t *vl)
+{
+       cache_update (ds, vl);
+       cache_flush (2 * interval_g);
+
+       return (0);
+}
+
+void module_register (modreg_e load)
+{
+       plugin_register_config ("unixsock", us_config,
+                       config_keys, config_keys_num);
+       plugin_register_init ("unixsock", us_init);
+       plugin_register_write ("unixsock", us_write);
+       plugin_register_shutdown ("unixsock", us_shutdown);
+} /* void module_register (void) */
+
+/* vim: set sw=4 ts=4 sts=4 tw=78 : */
index 973fda0..e600aab 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/users.c
- * Copyright (C) 2005,2006  Sebastian Harl
+ * Copyright (C) 2005-2007  Sebastian Harl
  *
  * 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
 # define USERS_HAVE_READ 0
 #endif
 
-static char *rrd_file = "users.rrd";
-static char *ds_def[] =
+static data_source_t dsrc[1] =
 {
-       "DS:users:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
-       NULL
+       {"users",  DS_TYPE_GAUGE, 0.0, 65535.0}
 };
-static int ds_num = 1;
 
-static void users_init (void)
+static data_set_t ds =
 {
-       /* we have nothing to do here :-) */
-       return;
-} /* static void users_init(void) */
-
-static void users_write (char *host, char *inst, char *val)
-{
-       rrd_update_file(host, rrd_file, val, ds_def, ds_num);
-       return;
-} /* static void users_write(char *host, char *inst, char *val) */
+       "users", 1, dsrc
+};
 
 #if USERS_HAVE_READ
-/* I don't like this temporary macro definition - well it's used everywhere
-   else in the collectd-sources, so I will just stick with it...  */
-#define BUFSIZE 256
-static void users_submit (unsigned int users)
+static void users_submit (gauge_t value)
 {
-       char buf[BUFSIZE] = "";
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       if (snprintf(buf, BUFSIZE, "%u:%u", 
-               (unsigned int)curtime, users) >= BUFSIZE)
-       {
-               return;
-       }
+       values[0].gauge = value;
+
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "users");
 
-       plugin_submit(MODULE_NAME, "-", buf);
-       return;
-} /* static void users_submit(unsigned int users) */
-#undef BUFSIZE
+       plugin_dispatch_values ("users", &vl);
+} /* void users_submit */
 
-static void users_read (void)
+static int users_read (void)
 {
 #if HAVE_GETUTXENT
        unsigned int users = 0;
@@ -114,17 +102,20 @@ static void users_read (void)
        }
        endutent();
 
-       users_submit(users);
+       users_submit (users);
 #endif /* HAVE_GETUTENT */
 
-       return;
-} /* static void users_read(void) */
-#else
-# define users_read NULL
+       return (0);
+} /* int users_read */
 #endif /* USERS_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, users_init, users_read, users_write);
-       return;
+       if (load & MR_DATASETS)
+               plugin_register_data_set (&ds);
+
+#if USERS_HAVE_READ
+       if (load & MR_READ)
+               plugin_register_read ("users", users_read);
+#endif
 } /* void module_register(void) */
diff --git a/src/utils_avltree.c b/src/utils_avltree.c
new file mode 100644 (file)
index 0000000..786bc38
--- /dev/null
@@ -0,0 +1,708 @@
+/**
+ * collectd - src/utils_avltree.c
+ * Copyright (C) 2006,2007  Florian octo Forster
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at verplant.org>
+ **/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "utils_avltree.h"
+
+#define BALANCE(n) ((((n)->left == NULL) ? 0 : (n)->left->height) \
+               - (((n)->right == NULL) ? 0 : (n)->right->height))
+
+/*
+ * private data types
+ */
+struct avl_node_s
+{
+       void *key;
+       void *value;
+
+       int height;
+       struct avl_node_s *left;
+       struct avl_node_s *right;
+       struct avl_node_s *parent;
+};
+typedef struct avl_node_s avl_node_t;
+
+struct avl_tree_s
+{
+       avl_node_t *root;
+       int (*compare) (const void *, const void *);
+};
+
+struct avl_iterator_s
+{
+       avl_tree_t *tree;
+       avl_node_t *node;
+};
+
+/*
+ * private functions
+ */
+#if 0
+static void verify_tree (avl_node_t *n)
+{
+       if (n == NULL)
+               return;
+
+       verify_tree (n->left);
+       verify_tree (n->right);
+
+       assert ((BALANCE (n) >= -1) && (BALANCE (n) <= 1));
+       assert ((n->parent == NULL) || (n->parent->right == n) || (n->parent->left == n));
+} /* void verify_tree */
+#else
+# define verify_tree(n) /**/
+#endif
+
+static void free_node (avl_node_t *n)
+{
+       if (n == NULL)
+               return;
+
+       if (n->left != NULL)
+               free_node (n->left);
+       if (n->right != NULL)
+               free_node (n->right);
+
+       free (n);
+}
+
+static int calc_height (avl_node_t *n)
+{
+       int height_left;
+       int height_right;
+
+       if (n == NULL)
+               return (0);
+
+       height_left  = (n->left == NULL)  ? 0 : n->left->height;
+       height_right = (n->right == NULL) ? 0 : n->right->height;
+
+       return (((height_left > height_right)
+                               ? height_left
+                               : height_right) + 1);
+} /* int calc_height */
+
+static avl_node_t *search (avl_tree_t *t, const void *key)
+{
+       avl_node_t *n;
+       int cmp;
+
+       n = t->root;
+       while (n != NULL)
+       {
+               cmp = t->compare (key, n->key);
+               if (cmp == 0)
+                       return (n);
+               else if (cmp < 0)
+                       n = n->left;
+               else
+                       n = n->right;
+       }
+
+       return (NULL);
+}
+
+/*         (x)             (y)
+ *        /   \           /   \
+ *     (y)    /\         /\    (x)
+ *    /   \  /_c\  ==>  / a\  /   \
+ *   /\   /\           /____\/\   /\
+ *  / a\ /_b\               /_b\ /_c\
+ * /____\
+ */
+static avl_node_t *rotate_right (avl_tree_t *t, avl_node_t *x)
+{
+       avl_node_t *p;
+       avl_node_t *y;
+       avl_node_t *b;
+
+       p = x->parent;
+       y = x->left;
+       b = y->right;
+
+       x->left = b;
+       if (b != NULL)
+               b->parent = x;
+
+       x->parent = y;
+       y->right = x;
+
+       y->parent = p;
+       assert ((p == NULL) || (p->left == x) || (p->right == x));
+       if (p == NULL)
+               t->root = y;
+       else if (p->left == x)
+               p->left = y;
+       else
+               p->right = y;
+
+       x->height = calc_height (x);
+       y->height = calc_height (y);
+
+       return (y);
+} /* void rotate_left */
+
+/*
+ *    (x)                   (y)
+ *   /   \                 /   \
+ *  /\    (y)           (x)    /\
+ * /_a\  /   \   ==>   /   \  / c\
+ *      /\   /\       /\   /\/____\
+ *     /_b\ / c\     /_a\ /_b\
+ *         /____\
+ */
+static avl_node_t *rotate_left (avl_tree_t *t, avl_node_t *x)
+{
+       avl_node_t *p;
+       avl_node_t *y;
+       avl_node_t *b;
+
+       p = x->parent;
+       y = x->right;
+       b = y->left;
+
+       x->right = b;
+       if (b != NULL)
+               b->parent = x;
+
+       x->parent = y;
+       y->left = x;
+
+       y->parent = p;
+       assert ((p == NULL) || (p->left == x) || (p->right == x));
+       if (p == NULL)
+               t->root = y;
+       else if (p->left == x)
+               p->left = y;
+       else
+               p->right = y;
+
+       x->height = calc_height (x);
+       y->height = calc_height (y);
+
+       return (y);
+} /* void rotate_left */
+
+static avl_node_t *rotate_left_right (avl_tree_t *t, avl_node_t *x)
+{
+       rotate_left (t, x->left);
+       return (rotate_right (t, x));
+} /* void rotate_left_right */
+
+static avl_node_t *rotate_right_left (avl_tree_t *t, avl_node_t *x)
+{
+       rotate_right (t, x->right);
+       return (rotate_left (t, x));
+} /* void rotate_right_left */
+
+static void rebalance (avl_tree_t *t, avl_node_t *n)
+{
+       int b_top;
+       int b_bottom;
+
+       while (n != NULL)
+       {
+               b_top = BALANCE (n);
+               assert ((b_top >= -2) && (b_top <= 2));
+
+               if (b_top == -2)
+               {
+                       assert (n->right != NULL);
+                       b_bottom = BALANCE (n->right);
+                       assert ((b_bottom >= -1) || (b_bottom <= 1));
+                       if (b_bottom == 1)
+                               n = rotate_right_left (t, n);
+                       else
+                               n = rotate_left (t, n);
+               }
+               else if (b_top == 2)
+               {
+                       assert (n->left != NULL);
+                       b_bottom = BALANCE (n->left);
+                       assert ((b_bottom >= -1) || (b_bottom <= 1));
+                       if (b_bottom == -1)
+                               n = rotate_left_right (t, n);
+                       else
+                               n = rotate_right (t, n);
+               }
+               else
+               {
+                       int height = calc_height (n);
+                       if (height == n->height)
+                               break;
+                       n->height = height;
+               }
+
+               assert (n->height == calc_height (n));
+
+               n = n->parent;
+       } /* while (n != NULL) */
+} /* void rebalance */
+
+static avl_node_t *avl_node_next (avl_tree_t *t, avl_node_t *n)
+{
+       avl_node_t *r; /* return node */
+
+       if (n == NULL)
+       {
+               return (NULL);
+       }
+
+       /* If we can't descent any further, we have to backtrack to the first
+        * parent that's bigger than we, i. e. who's _left_ child we are. */
+       if (n->right == NULL)
+       {
+               r = n->parent;
+               while ((r != NULL) && (r->parent != NULL))
+               {
+                       if (r->left == n)
+                               break;
+                       n = r;
+                       r = n->parent;
+               }
+
+               /* n->right == NULL && r == NULL => t is root and has no next
+                * r->left != n => r->right = n => r->parent == NULL */
+               if ((r == NULL) || (r->left != n))
+               {
+                       assert ((r == NULL) || (r->parent == NULL));
+                       return (NULL);
+               }
+               else
+               {
+                       assert (r->left == n);
+                       return (r);
+               }
+       }
+       else
+       {
+               r = n->right;
+               while (r->left != NULL)
+                       r = r->left;
+       }
+
+       return (r);
+} /* avl_node_t *avl_node_next */
+
+static avl_node_t *avl_node_prev (avl_tree_t *t, avl_node_t *n)
+{
+       avl_node_t *r; /* return node */
+
+       if (n == NULL)
+       {
+               return (NULL);
+       }
+
+       /* If we can't descent any further, we have to backtrack to the first
+        * parent that's smaller than we, i. e. who's _right_ child we are. */
+       if (n->left == NULL)
+       {
+               r = n->parent;
+               while ((r != NULL) && (r->parent != NULL))
+               {
+                       if (r->right == n)
+                               break;
+                       n = r;
+                       r = n->parent;
+               }
+
+               /* n->left == NULL && r == NULL => t is root and has no next
+                * r->right != n => r->left = n => r->parent == NULL */
+               if ((r == NULL) || (r->right != n))
+               {
+                       assert ((r == NULL) || (r->parent == NULL));
+                       return (NULL);
+               }
+               else
+               {
+                       assert (r->right == n);
+                       return (r);
+               }
+       }
+       else
+       {
+               r = n->left;
+               while (r->right != NULL)
+                       r = r->right;
+       }
+
+       return (r);
+} /* avl_node_t *avl_node_prev */
+
+static int _remove (avl_tree_t *t, avl_node_t *n)
+{
+       assert ((t != NULL) && (n != NULL));
+
+       if ((n->left != NULL) && (n->right != NULL))
+       {
+               avl_node_t *r; /* replacement node */
+               if (BALANCE (n) > 0) /* left subtree is higher */
+               {
+                       assert (n->left != NULL);
+                       r = avl_node_prev (t, n);
+                       
+               }
+               else /* right subtree is higher */
+               {
+                       assert (n->right != NULL);
+                       r = avl_node_next (t, n);
+               }
+
+               assert ((r->left == NULL) || (r->right == NULL));
+
+               /* copy content */
+               n->key   = r->key;
+               n->value = r->value;
+
+               n = r;
+       }
+
+       assert ((n->left == NULL) || (n->right == NULL));
+
+       if ((n->left == NULL) && (n->right == NULL))
+       {
+               /* Deleting a leave is easy */
+               if (n->parent == NULL)
+               {
+                       assert (t->root == n);
+                       t->root = NULL;
+               }
+               else
+               {
+                       assert ((n->parent->left == n)
+                                       || (n->parent->right == n));
+                       if (n->parent->left == n)
+                               n->parent->left = NULL;
+                       else
+                               n->parent->right = NULL;
+
+                       rebalance (t, n->parent);
+               }
+
+               free_node (n);
+       }
+       else if (n->left == NULL)
+       {
+               assert (BALANCE (n) == -1);
+               assert ((n->parent == NULL) || (n->parent->left == n) || (n->parent->right == n));
+               if (n->parent == NULL)
+               {
+                       assert (t->root == n);
+                       t->root = n->right;
+               }
+               else if (n->parent->left == n)
+               {
+                       n->parent->left = n->right;
+               }
+               else
+               {
+                       n->parent->right = n->right;
+               }
+               n->right->parent = n->parent;
+
+               if (n->parent != NULL)
+                       rebalance (t, n->parent);
+
+               n->right = NULL;
+               free_node (n);
+       }
+       else if (n->right == NULL)
+       {
+               assert (BALANCE (n) == 1);
+               assert ((n->parent == NULL) || (n->parent->left == n) || (n->parent->right == n));
+               if (n->parent == NULL)
+               {
+                       assert (t->root == n);
+                       t->root = n->left;
+               }
+               else if (n->parent->left == n)
+               {
+                       n->parent->left = n->left;
+               }
+               else
+               {
+                       n->parent->right = n->left;
+               }
+               n->left->parent = n->parent;
+
+               if (n->parent != NULL)
+                       rebalance (t, n->parent);
+
+               n->left = NULL;
+               free_node (n);
+       }
+       else
+       {
+               assert (0);
+       }
+
+       return (0);
+} /* void *_remove */
+
+/*
+ * public functions
+ */
+avl_tree_t *avl_create (int (*compare) (const void *, const void *))
+{
+       avl_tree_t *t;
+
+       if (compare == NULL)
+               return (NULL);
+
+       if ((t = (avl_tree_t *) malloc (sizeof (avl_tree_t))) == NULL)
+               return (NULL);
+
+       t->root = NULL;
+       t->compare = compare;
+
+       return (t);
+}
+
+void avl_destroy (avl_tree_t *t)
+{
+       free_node (t->root);
+       free (t);
+}
+
+int avl_insert (avl_tree_t *t, void *key, void *value)
+{
+       avl_node_t *new;
+       avl_node_t *nptr;
+       int cmp;
+
+       if ((new = (avl_node_t *) malloc (sizeof (avl_node_t))) == NULL)
+               return (-1);
+
+       new->key = key;
+       new->value = value;
+       new->height = 1;
+       new->left = NULL;
+       new->right = NULL;
+
+       if (t->root == NULL)
+       {
+               new->parent = NULL;
+               t->root = new;
+               return (0);
+       }
+
+       nptr = t->root;
+       while (42)
+       {
+               cmp = t->compare (nptr->key, new->key);
+               if (cmp == 0)
+               {
+                       free_node (new);
+                       return (-1);
+               }
+               else if (cmp < 0)
+               {
+                       /* nptr < new */
+                       if (nptr->right == NULL)
+                       {
+                               nptr->right = new;
+                               new->parent = nptr;
+                               rebalance (t, nptr);
+                               break;
+                       }
+                       else
+                       {
+                               nptr = nptr->right;
+                       }
+               }
+               else /* if (cmp > 0) */
+               {
+                       /* nptr > new */
+                       if (nptr->left == NULL)
+                       {
+                               nptr->left = new;
+                               new->parent = nptr;
+                               rebalance (t, nptr);
+                               break;
+                       }
+                       else
+                       {
+                               nptr = nptr->left;
+                       }
+               }
+       } /* while (42) */
+
+       verify_tree (t->root);
+       return (0);
+} /* int avl_insert */
+
+int avl_remove (avl_tree_t *t, const void *key, void **rkey, void **rvalue)
+{
+       avl_node_t *n;
+       int status;
+
+       assert (t != NULL);
+
+       n = search (t, key);
+       if (n == NULL)
+               return (-1);
+
+       if (rkey != NULL)
+               *rkey = n->key;
+       if (rvalue != NULL)
+               *rvalue = n->value;
+
+       status = _remove (t, n);
+       verify_tree (t->root);
+       return (status);
+} /* void *avl_remove */
+
+int avl_get (avl_tree_t *t, const void *key, void **value)
+{
+       avl_node_t *n;
+
+       assert (value != NULL);
+
+       n = search (t, key);
+       if (n == NULL)
+               return (-1);
+
+       *value = n->value;
+
+       return (0);
+}
+
+int avl_pick (avl_tree_t *t, void **key, void **value)
+{
+       avl_node_t *n;
+       avl_node_t *p;
+
+       if ((key == NULL) || (value == NULL))
+               return (-1);
+       if (t->root == NULL)
+               return (-1);
+
+       n = t->root;
+       while ((n->left != NULL) || (n->right != NULL))
+       {
+               int height_left  = (n->left  == NULL) ? 0 : n->left->height;
+               int height_right = (n->right == NULL) ? 0 : n->right->height;
+
+               if (height_left > height_right)
+                       n = n->left;
+               else
+                       n = n->right;
+       }
+
+       p = n->parent;
+       if (p == NULL)
+               t->root = NULL;
+       else if (p->left == n)
+               p->left = NULL;
+       else
+               p->right = NULL;
+
+       *key   = n->key;
+       *value = n->value;
+
+       free_node (n);
+       rebalance (t, p);
+
+       return (0);
+} /* int avl_pick */
+
+avl_iterator_t *avl_get_iterator (avl_tree_t *t)
+{
+       avl_iterator_t *iter;
+
+       if (t == NULL)
+               return (NULL);
+
+       iter = (avl_iterator_t *) malloc (sizeof (avl_iterator_t));
+       if (iter == NULL)
+               return (NULL);
+       memset (iter, '\0', sizeof (avl_iterator_t));
+       iter->tree = t;
+
+       return (iter);
+} /* avl_iterator_t *avl_get_iterator */
+
+int avl_iterator_next (avl_iterator_t *iter, void **key, void **value)
+{
+       avl_node_t *n;
+
+       if ((iter == NULL) || (key == NULL) || (value == NULL))
+               return (-1);
+
+       if (iter->node == NULL)
+       {
+               for (n = iter->tree->root; n != NULL; n = n->left)
+                       if (n->left == NULL)
+                               break;
+               iter->node = n;
+       }
+       else
+       {
+               n = avl_node_next (iter->tree, iter->node);
+       }
+
+       if (n == NULL)
+               return (-1);
+
+       iter->node = n;
+       *key = n->key;
+       *value = n->value;
+
+       return (0);
+} /* int avl_iterator_next */
+
+int avl_iterator_prev (avl_iterator_t *iter, void **key, void **value)
+{
+       avl_node_t *n;
+
+       if ((iter == NULL) || (key == NULL) || (value == NULL))
+               return (-1);
+
+       if (iter->node == NULL)
+       {
+               for (n = iter->tree->root; n != NULL; n = n->left)
+                       if (n->right == NULL)
+                               break;
+               iter->node = n;
+       }
+       else
+       {
+               n = avl_node_prev (iter->tree, iter->node);
+       }
+
+       if (n == NULL)
+               return (-1);
+
+       iter->node = n;
+       *key = n->key;
+       *value = n->value;
+
+       return (0);
+} /* int avl_iterator_prev */
+
+void avl_iterator_destroy (avl_iterator_t *iter)
+{
+       free (iter);
+}
diff --git a/src/utils_avltree.h b/src/utils_avltree.h
new file mode 100644 (file)
index 0000000..0ac6087
--- /dev/null
@@ -0,0 +1,144 @@
+/**
+ * collectd - src/utils_avltree.h
+ * Copyright (C) 2006,2007  Florian octo Forster
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at verplant.org>
+ **/
+
+#ifndef UTILS_AVLTREE_H
+#define UTILS_AVLTREE_H 1
+
+struct avl_tree_s;
+typedef struct avl_tree_s avl_tree_t;
+
+struct avl_iterator_s;
+typedef struct avl_iterator_s avl_iterator_t;
+
+/*
+ * NAME
+ *   avl_create
+ *
+ * DESCRIPTION
+ *   Allocates a new AVL-tree.
+ *
+ * PARAMETERS
+ *   `compare'  The function-pointer `compare' is used to compare two keys. It
+ *              has to return less than zero if it's first argument is smaller
+ *              then the second argument, more than zero if the first argument
+ *              is bigger than the second argument and zero if they are equal.
+ *              If your keys are char-pointers, you can use the `strcmp'
+ *              function from the libc here.
+ *
+ * RETURN VALUE
+ *   A avl_tree_t-pointer upon success or NULL upon failure.
+ */
+avl_tree_t *avl_create (int (*compare) (const void *, const void *));
+
+
+/*
+ * NAME
+ *   avl_destroy
+ *
+ * DESCRIPTION
+ *   Deallocates an AVL-tree. Stored value- and key-pointer are lost, but of
+ *   course not freed.
+ */
+void avl_destroy (avl_tree_t *t);
+
+/*
+ * NAME
+ *   avl_insert
+ *
+ * DESCRIPTION
+ *   Stores the key-value-pair in the AVL-tree pointed to by `t'.
+ *
+ * PARAMETERS
+ *   `t'        AVL-tree to store the data in.
+ *   `key'      Key used to store the value under. This is used to get back to
+ *              the value again.
+ *   `value'    Value to be stored.
+ *
+ * RETURN VALUE
+ *   Zero upon success and non-zero upon failure and if the key is already
+ *   stored in the tree.
+ */
+int avl_insert (avl_tree_t *t, void *key, void *value);
+
+/*
+ * NAME
+ *   avl_remove
+ *
+ * DESCRIPTION
+ *   Removes a key-value-pair from the tree t. The stored key and value may be
+ *   returned in `rkey' and `rvalue'.
+ *
+ * PARAMETERS
+ *   `t'       AVL-tree to remove key-value-pair from.
+ *   `key'      Key to identify the entry.
+ *   `rkey'     Pointer to a pointer in which to store the key. May be NULL.
+ *   `rvalue'   Pointer to a pointer in which to store the value. May be NULL.
+ *
+ * RETURN VALUE
+ *   Zero upon success or non-zero if the key isn't found in the tree.
+ */
+int avl_remove (avl_tree_t *t, const void *key, void **rkey, void **rvalue);
+
+/*
+ * NAME
+ *   avl_get
+ *
+ * DESCRIPTION
+ *   Retrieve the `value' belonging to `key'.
+ *
+ * PARAMETERS
+ *   `t'       AVL-tree to get the value from.
+ *   `key'      Key to identify the entry.
+ *   `value'    Pointer to a pointer in which to store the value. May be NULL.
+ *
+ * RETURN VALUE
+ *   Zero upon success or non-zero if the key isn't found in the tree.
+ */
+int avl_get (avl_tree_t *t, const void *key, void **value);
+
+/*
+ * NAME
+ *   avl_pick
+ *
+ * DESCRIPTION
+ *   Remove a (pseudo-)random element from the tree and return it's `key' and
+ *   `value'. Entries are not returned in any particular order. This function
+ *   is intended for cache-flushes that don't care about the order but simply
+ *   want to remove all elements, one at a time.
+ *
+ * PARAMETERS
+ *   `t'       AVL-tree to get the value from.
+ *   `key'      Pointer to a pointer in which to store the key.
+ *   `value'    Pointer to a pointer in which to store the value.
+ *
+ * RETURN VALUE
+ *   Zero upon success or non-zero if the tree is empty or key or value is
+ *   NULL.
+ */
+int avl_pick (avl_tree_t *t, void **key, void **value);
+
+avl_iterator_t *avl_get_iterator (avl_tree_t *t);
+int avl_iterator_next (avl_iterator_t *iter, void **key, void **value);
+int avl_iterator_prev (avl_iterator_t *iter, void **key, void **value);
+void avl_iterator_destroy (avl_iterator_t *iter);
+
+#endif /* UTILS_AVLTREE_H */
diff --git a/src/utils_debug.c b/src/utils_debug.c
deleted file mode 100644 (file)
index 9fc9040..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/**
- * collectd - src/utils_debug.c
- * Copyright (C) 2005,2006  Niki W. Waibel
- *
- * 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.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- *
- * Authors:
- *   Niki W. Waibel <niki.waibel at gmx.net>
- **/
-
-#include "common.h"
-#include "utils_debug.h"
-
-#if COLLECT_DEBUG
-
-static void cu_vdebug(const char *file, int line, const char *func,
-       const char *format, va_list ap);
-
-/* if preemptive threads are used, these vars need some sort of locking! */
-/* pth is non-preemptive, so no locking is necessary */
-static FILE *cu_debug_file = NULL;
-static char *cu_debug_filename = NULL;
-
-static void
-cu_vdebug(const char *file, int line, const char *func,
-       const char *format, va_list ap)
-{ 
-       FILE *f;
-       if(cu_debug_file != NULL) {
-               f = cu_debug_file;
-       } else {
-               /* stderr might be redirected to /dev/null. in that case */
-               /* you'll not see anything... */
-               f = stderr;
-       }
-
-       fprintf(f, "%s:%d:%s(): ",
-               file, line, func);
-       vfprintf(f, format, ap);
-       fprintf(f, "\n");
-       fflush(f);
-} /* static void cu_vdebug(const char *file, int line, const char *func,
-       const char *format, va_list ap) */
-
-void
-cu_debug(const char *file, int line, const char *func,
-       const char *format, ...)
-{ 
-       va_list ap;
-
-       va_start(ap, format);
-       cu_vdebug(file, line, func, format, ap);
-       va_end(ap);
-} /* void cu_debug(const char *file, int line, const char *func,
-       const char *format, ...) */
-
-int
-cu_debug_startfile(const char *file, int line, const char *func,
-       const char *filename, const char *format, ...)
-{
-       va_list ap;
-
-       if(cu_debug_file != NULL) {
-               DBG("Don't call this function more then once without"
-                       " calling cu_debug_stopfile().");
-               return EXIT_FAILURE;
-       }
-
-       if(cu_debug_filename == NULL) {
-               cu_debug_filename = sstrdup(filename);
-       }
-
-       cu_debug_file = fopen(cu_debug_filename, "a");
-       if(cu_debug_file == NULL) {
-               DBG("Cannot open debug file %s: %s.\n",
-                       cu_debug_filename, strerror(errno));
-               return EXIT_FAILURE;
-       }
-
-       va_start(ap, format);
-       cu_vdebug(file, line, func, format, ap);
-       va_end(ap);
-
-       return EXIT_SUCCESS;
-} /* int cu_debug_start(const char *file, int line, const char *func,
-       const char *format, ...) */
-
-int
-cu_debug_stopfile(const char *file, int line, const char *func,
-       const char *format, ...)
-{
-       va_list ap;
-
-       va_start(ap, format);
-       cu_vdebug(file, line, func, format, ap);
-       va_end(ap);
-
-       if(cu_debug_file == NULL) {
-               DBG("Don't call this function more then once or without"
-                       " calling cu_debug_startfile().");
-               return EXIT_FAILURE;
-       }
-
-       if(fclose(cu_debug_file) != 0) {
-               DBG("Cannot close debug file %s: %s.\n",
-                       cu_debug_filename, strerror(errno));
-               return EXIT_FAILURE;
-       }
-       cu_debug_file = NULL;
-
-       sfree(cu_debug_filename);
-
-       return EXIT_SUCCESS;
-} /* int cu_debug_stop(const char *file, int line, const char *func,
-       const char *format, ...) */
-
-int
-cu_debug_resetfile(const char *file, int line, const char *func,
-       const char *filename)
-{
-       if(filename == NULL) {
-               DBG("You have to set filename when calling this function!\n");
-               return EXIT_FAILURE;
-       }
-       if(cu_debug_file != NULL) {
-               char *save_filename = NULL;
-
-               /* DBG_STARTFILE was called already */
-               /* reopen file */
-
-               DBG_STOPFILE("Closing %s and reopening %s.",
-                       cu_debug_filename, filename);
-               save_filename = smalloc(strlen(cu_debug_filename)+1);
-               sstrncpy(save_filename, cu_debug_filename,
-                       strlen(cu_debug_filename)+1);
-               cu_debug_filename = smalloc(strlen(filename)+1);
-               sstrncpy(cu_debug_filename, filename, strlen(filename)+1);
-               DBG_STARTFILE("Reopening %s after closing %s.",
-                       filename, save_filename);
-               sfree(save_filename);
-               return EXIT_SUCCESS;
-       }
-
-       /* DBG_STARTFILE was NOT called already */
-       /* setting filename only */
-
-       if(cu_debug_filename != NULL) {
-               sfree(cu_debug_filename);
-       }
-       cu_debug_filename = smalloc(strlen(filename)+1);
-       sstrncpy(cu_debug_filename, filename, strlen(filename)+1);
-
-       return EXIT_SUCCESS;
-} /* int cu_debug_resetfile(const char *file, int line, const char *func,
-        const char *filename) */
-
-#endif /* COLLECT_DEBUG */
-
diff --git a/src/utils_debug.h b/src/utils_debug.h
deleted file mode 100644 (file)
index 63567d3..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * collectd - src/utils_debug.h
- * Copyright (C) 2005,2006  Niki W. Waibel
- *
- * This program is free software; you can redistribute it and/
- * or modify it under the terms of the GNU General Public Li-
- * cence as published by the Free Software Foundation; either
- * version 2 of the Licence, or any later version.
- *
- * This program is distributed in the hope that it will be use-
- * ful, but WITHOUT ANY WARRANTY; without even the implied war-
- * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public Licence for more details.
- *
- * You should have received a copy of the GNU General Public
- * Licence along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- * Author:
- *   Niki W. Waibel <niki.waibel@gmx.net>
-**/
-
-/* BUG: at the moment you can use DBG_STARTFILE only ONCE in
-   your program. more then one logfile is not supported. */
-
-#if !COLLECTD_UTILS_DEBUG_H
-#define COLLECTD_UTILS_DEBUG_H 1
-
-#if COLLECT_DEBUG
-
-#define DBG(...) cu_debug(__FILE__, __LINE__, __func__, \
-       __VA_ARGS__)
-
-#define DBG_STARTFILE(file, ...) cu_debug_startfile(__FILE__, __LINE__, \
-       __func__, file, __VA_ARGS__)
-#define DBG_STOPFILE(...) cu_debug_stopfile(__FILE__, __LINE__, \
-       __func__, __VA_ARGS__)
-
-#define DBG_RESETFILE(file) cu_debug_resetfile(__FILE__, __LINE__, __func__, \
-       filename)
-
-void cu_debug(const char *file, int line, const char *func,
-       const char *format, ...);
-
-int cu_debug_startfile(const char *file, int line, const char *func,
-       const char *filename, const char *format, ...);
-int cu_debug_stopfile(const char *file, int line, const char *func,
-       const char *format, ...);
-
-int cu_debug_resetfile(const char *file, int line, const char *func,
-       const char *filename);
-
-#else /* !COLLECT_DEBUG */
-
-#define DBG(...)                   /* DBG(...) */
-#define DBG_STARTFILE(file, ...)   /* DBG_STARTFILE(file, ...) */
-#define DBG_STOPFILE(...)          /* DBG_STOPFILE(...) */
-#define DBG_RESETFILE(file)        /* DBG_RESETFILE(file) */
-
-#endif /* COLLECT_DEBUG */
-
-#endif /* !COLLECTD_UTILS_DEBUG_H */
-
index 532eb4b..f71ac1d 100644 (file)
@@ -48,7 +48,7 @@
  **/
 
 #include "common.h"
-#include "utils_debug.h"
+#include "plugin.h"
 #include "utils_ignorelist.h"
 
 /*
@@ -94,7 +94,7 @@ static int ignorelist_append_regex(ignorelist_t *il, const char *entry)
        /* create buffer */
        if ((regtemp = malloc(sizeof(regex_t))) == NULL)
        {
-               syslog (LOG_ERR, "cannot allocate new config entry");
+               ERROR ("cannot allocate new config entry");
                return (1);
        }
        memset (regtemp, '\0', sizeof(regex_t));
@@ -111,14 +111,14 @@ static int ignorelist_append_regex(ignorelist_t *il, const char *entry)
                {
                        fprintf (stderr, "Cannot compile regex %s: %i/%s",
                                        entry, rcompile, regerr);
-                       syslog (LOG_ERR, "Cannot compile regex %s: %i/%s",
+                       ERROR ("Cannot compile regex %s: %i/%s",
                                        entry, rcompile, regerr);
                }
                else
                {
                        fprintf (stderr, "Cannot compile regex %s: %i",
                                        entry, rcompile);
-                       syslog (LOG_ERR, "Cannot compile regex %s: %i",
+                       ERROR ("Cannot compile regex %s: %i",
                                        entry, rcompile);
                }
 
@@ -127,12 +127,12 @@ static int ignorelist_append_regex(ignorelist_t *il, const char *entry)
                regfree (regtemp);
                return (1);
        }
-       DBG("regex compiled: %s - %i", entry, rcompile);
+       DEBUG("regex compiled: %s - %i", entry, rcompile);
 
        /* create new entry */
        if ((new = malloc(sizeof(ignorelist_item_t))) == NULL)
        {
-               syslog (LOG_ERR, "cannot allocate new config entry");
+               ERROR ("cannot allocate new config entry");
                regfree (regtemp);
                return (1);
        }
@@ -153,7 +153,7 @@ static int ignorelist_append_string(ignorelist_t *il, const char *entry)
        /* create new entry */
        if ((new = malloc(sizeof(ignorelist_item_t))) == NULL )
        {
-               syslog (LOG_ERR, "cannot allocate new entry");
+               ERROR ("cannot allocate new entry");
                return (1);
        }
        memset (new, '\0', sizeof(ignorelist_item_t));
@@ -213,7 +213,7 @@ ignorelist_t *ignorelist_create (int invert)
 
        /* smalloc exits if it failes */
        il = (ignorelist_t *) smalloc (sizeof (ignorelist_t));
-       DBG("Ignorelist created 0x%p, default is %s",
+       DEBUG("Ignorelist created 0x%p, default is %s",
                        (void *) il,
                        invert ? "collect" : "ignore");
 
@@ -236,7 +236,7 @@ void ignorelist_free (ignorelist_t *il)
        ignorelist_item_t *this;
        ignorelist_item_t *next;
 
-       DBG ("(il = 0x%p)", (void *) il);
+       DEBUG ("(il = 0x%p)", (void *) il);
 
        if (il == NULL)
                return;
@@ -270,7 +270,7 @@ void ignorelist_set_invert (ignorelist_t *il, int invert)
 {
        if (il == NULL)
        {
-               DBG("ignore call with ignorelist_t == NULL");
+               DEBUG("ignore call with ignorelist_t == NULL");
                return;
        }
 
@@ -288,7 +288,7 @@ int ignorelist_add (ignorelist_t *il, const char *entry)
 
        if (il == NULL)
        {
-               DBG ("add called with ignorelist_t == NULL");
+               DEBUG ("add called with ignorelist_t == NULL");
                return (1);
        }
 
@@ -297,7 +297,7 @@ int ignorelist_add (ignorelist_t *il, const char *entry)
        /* append nothing */
        if (entry_len == 0)
        {
-               DBG("not appending: empty entry");
+               DEBUG("not appending: empty entry");
                return (1);
        }
 
@@ -312,14 +312,14 @@ int ignorelist_add (ignorelist_t *il, const char *entry)
                memset (entry_copy, '\0', entry_len);
                strncpy (entry_copy, entry + 1, entry_len - 2);
 
-               DBG("I'm about to add regex entry: %s", entry_copy);
+               DEBUG("I'm about to add regex entry: %s", entry_copy);
                ret = ignorelist_append_regex(il, entry_copy);
                sfree (entry_copy);
        }
        else
 #endif
        {
-               DBG("to add entry: %s", entry);
+               DEBUG("to add entry: %s", entry);
                ret = ignorelist_append_string(il, entry);
        }
 
diff --git a/src/utils_llist.c b/src/utils_llist.c
new file mode 100644 (file)
index 0000000..a815035
--- /dev/null
@@ -0,0 +1,148 @@
+/**
+ * collectd - src/utils_llist.c
+ * Copyright (C) 2006 Florian Forster <octo at verplant.org>
+ *
+ * This program is free software; you can redistribute it and/
+ * or modify it under the terms of the GNU General Public Li-
+ * cence as published by the Free Software Foundation; only
+ * version 2 of the Licence is applicable.
+ *
+ * This program is distributed in the hope that it will be use-
+ * ful, but WITHOUT ANY WARRANTY; without even the implied war-
+ * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * Licence along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ * Authors:
+ *   Florian Forster <octo at verplant.org>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils_llist.h"
+
+/*
+ * Private data types
+ */
+struct llist_s
+{
+       llentry_t *head;
+       llentry_t *tail;
+};
+
+/*
+ * Public functions
+ */
+llist_t *llist_create (void)
+{
+       llist_t *ret;
+
+       ret = (llist_t *) malloc (sizeof (llist_t));
+       if (ret == NULL)
+               return (NULL);
+
+       memset (ret, '\0', sizeof (llist_t));
+
+       return (ret);
+}
+
+void llist_destroy (llist_t *l)
+{
+       llentry_t *e_this;
+       llentry_t *e_next;
+
+       for (e_this = l->head; e_this != NULL; e_this = e_next)
+       {
+               e_next = e_this->next;
+               llentry_destroy (e_this);
+       }
+
+       free (l);
+}
+
+llentry_t *llentry_create (const char *key, void *value)
+{
+       llentry_t *e;
+
+       e = (llentry_t *) malloc (sizeof (llentry_t));
+       if (e == NULL)
+               return (NULL);
+
+       e->key   = strdup (key);
+       e->value = value;
+       e->next  = NULL;
+
+       if (e->key == NULL)
+       {
+               free (e);
+               return (NULL);
+       }
+
+       return (e);
+}
+
+void llentry_destroy (llentry_t *e)
+{
+       free (e->key);
+       free (e);
+}
+
+void llist_append (llist_t *l, llentry_t *e)
+{
+       e->next = NULL;
+
+       if (l->tail == NULL)
+               l->head = e;
+       else
+               l->tail->next = e;
+
+       l->tail = e;
+}
+
+void llist_prepend (llist_t *l, llentry_t *e)
+{
+       e->next = l->head;
+       l->head = e;
+}
+
+void llist_remove (llist_t *l, llentry_t *e)
+{
+       llentry_t *prev;
+
+       prev = l->head;
+       while ((prev != NULL) && (prev->next != e))
+               prev = prev->next;
+
+       if (prev != NULL)
+               prev->next = e->next;
+       if (l->head == e)
+               l->head = e->next;
+       if (l->tail == e)
+               l->tail = prev;
+}
+
+llentry_t *llist_search (llist_t *l, const char *key)
+{
+       llentry_t *e;
+
+       for (e = l->head; e != NULL; e = e->next)
+               if (strcmp (key, e->key) == 0)
+                       break;
+
+       return (e);
+}
+
+llentry_t *llist_head (llist_t *l)
+{
+       return (l->head);
+}
+
+llentry_t *llist_tail (llist_t *l)
+{
+       return (l->tail);
+}
diff --git a/src/utils_llist.h b/src/utils_llist.h
new file mode 100644 (file)
index 0000000..603fc87
--- /dev/null
@@ -0,0 +1,59 @@
+/**
+ * collectd - src/utils_llist.h
+ * Copyright (C) 2006 Florian Forster <octo at verplant.org>
+ *
+ * This program is free software; you can redistribute it and/
+ * or modify it under the terms of the GNU General Public Li-
+ * cence as published by the Free Software Foundation; only
+ * version 2 of the Licence is applicable.
+ *
+ * This program is distributed in the hope that it will be use-
+ * ful, but WITHOUT ANY WARRANTY; without even the implied war-
+ * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * Licence along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ * Authors:
+ *   Florian Forster <octo at verplant.org>
+ */
+
+#ifndef UTILS_LLIST_H
+#define UTILS_LLIST_H 1
+
+/*
+ * Data types
+ */
+struct llentry_s
+{
+       char *key;
+       void *value;
+       struct llentry_s *next;
+};
+typedef struct llentry_s llentry_t;
+
+struct llist_s;
+typedef struct llist_s llist_t;
+
+/*
+ * Functions
+ */
+llist_t *llist_create (void);
+void llist_destroy (llist_t *l);
+
+llentry_t *llentry_create (const char *key, void *value);
+void llentry_destroy (llentry_t *e);
+
+void llist_append (llist_t *l, llentry_t *e);
+void llist_prepend (llist_t *l, llentry_t *e);
+void llist_remove (llist_t *l, llentry_t *e);
+
+llentry_t *llist_search (llist_t *l, const char *key);
+
+llentry_t *llist_head (llist_t *l);
+llentry_t *llist_tail (llist_t *l);
+
+#endif /* UTILS_LLIST_H */
index 7748c61..eee2eb6 100644 (file)
@@ -30,7 +30,7 @@
 #define XFS_SUPER_MAGIC2_STR "BSFX"
 #endif
 
-#include "utils_debug.h"
+#include "plugin.h"
 #include "utils_mount.h"
 
 #if HAVE_GETVFSSTAT
@@ -332,7 +332,7 @@ get_spec_by_uuid(const char *s)
        return get_spec_by_x(UUID, uuid);
 
        bad_uuid:
-               DBG("Found an invalid UUID: %s", s);
+               DEBUG("Found an invalid UUID: %s", s);
        return NULL;
 }
 
@@ -351,12 +351,12 @@ static char *get_device_name(const char *optstr)
        }
        else if (strncmp (optstr, "UUID=", 5) == 0)
        {
-               DBG ("TODO: check UUID= code!");
+               DEBUG ("TODO: check UUID= code!");
                rc = get_spec_by_uuid (optstr + 5);
        }
        else if (strncmp (optstr, "LABEL=", 6) == 0)
        {
-               DBG ("TODO: check LABEL= code!");
+               DEBUG ("TODO: check LABEL= code!");
                rc = get_spec_by_volume_label (optstr + 6);
        }
        else
@@ -366,7 +366,7 @@ static char *get_device_name(const char *optstr)
 
        if(!rc)
        {
-               DBG ("Error checking device name: optstr = %s", optstr);
+               DEBUG ("Error checking device name: optstr = %s", optstr);
        }
        return rc;
 }
@@ -381,7 +381,9 @@ static cu_mount_t *cu_mount_listmntent (void)
 
        struct tabmntent *mntlist;
        if(listmntent(&mntlist, COLLECTD_MNTTAB, NULL, NULL) < 0) {
-               DBG("calling listmntent() failed: %s", strerror(errno));
+               char errbuf[1024];
+               DEBUG("calling listmntent() failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
        }
 
        for(p = mntlist; p; p = p->next) {
@@ -392,7 +394,7 @@ static cu_mount_t *cu_mount_listmntent (void)
                if(loop == NULL) {   /* no loop= mount */
                        device = get_device_name(mnt->mnt_fsname);
                        if(device == NULL) {
-                               DBG("can't get devicename for fs (%s) %s (%s)"
+                               DEBUG("can't get devicename for fs (%s) %s (%s)"
                                        ": ignored", mnt->mnt_type,
                                        mnt->mnt_dir, mnt->mnt_fsname);
                                continue;
@@ -450,7 +452,9 @@ static cu_mount_t *cu_mount_getfsstat (void)
        /* Get the number of mounted file systems */
        if ((bufsize = CMD_STATFS (NULL, 0, FLAGS_STATFS)) < 1)
        {
-               DBG ("getv?fsstat failed: %s", strerror (errno));
+               char errbuf[1024];
+               DEBUG ("getv?fsstat failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                return (NULL);
        }
 
@@ -463,7 +467,9 @@ static cu_mount_t *cu_mount_getfsstat (void)
         * manpage.. -octo */
        if ((num = CMD_STATFS (buf, bufsize * sizeof (STRUCT_STATFS), FLAGS_STATFS)) < 1)
        {
-               DBG ("getv?fsstat failed: %s", strerror (errno));
+               char errbuf[1024];
+               DEBUG ("getv?fsstat failed: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                free (buf);
                return (NULL);
        }
@@ -512,11 +518,13 @@ static cu_mount_t *cu_mount_gen_getmntent (void)
        cu_mount_t *last  = NULL;
        cu_mount_t *new   = NULL;
 
-       DBG ("(void); COLLECTD_MNTTAB = %s", COLLECTD_MNTTAB);
+       DEBUG ("(void); COLLECTD_MNTTAB = %s", COLLECTD_MNTTAB);
 
        if ((fp = fopen (COLLECTD_MNTTAB, "r")) == NULL)
        {
-               syslog (LOG_ERR, "fopen (%s): %s", COLLECTD_MNTTAB, strerror (errno));
+               char errbuf[1024];
+               ERROR ("fopen (%s): %s", COLLECTD_MNTTAB,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                return (NULL);
        }
 
@@ -567,11 +575,13 @@ static cu_mount_t *cu_mount_getmntent (void)
        cu_mount_t *last  = NULL;
        cu_mount_t *new   = NULL;
 
-       DBG ("(void); COLLECTD_MNTTAB = %s", COLLECTD_MNTTAB);
+       DEBUG ("(void); COLLECTD_MNTTAB = %s", COLLECTD_MNTTAB);
 
        if ((fp = setmntent (COLLECTD_MNTTAB, "r")) == NULL)
        {
-               syslog (LOG_ERR, "setmntent (%s): %s", COLLECTD_MNTTAB, strerror (errno));
+               char errbuf[1024];
+               ERROR ("setmntent (%s): %s", COLLECTD_MNTTAB,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
                return (NULL);
        }
 
@@ -589,7 +599,7 @@ static cu_mount_t *cu_mount_getmntent (void)
                new->device      = get_device_name (new->options);
                new->next        = NULL;
 
-               DBG ("new = {dir = %s, spec_device = %s, type = %s, options = %s, device = %s}",
+               DEBUG ("new = {dir = %s, spec_device = %s, type = %s, options = %s, device = %s}",
                                new->dir, new->spec_device, new->type, new->options, new->device);
 
                /* Append to list */
@@ -607,7 +617,7 @@ static cu_mount_t *cu_mount_getmntent (void)
 
        endmntent (fp);
 
-       DBG ("return (0x%p)", (void *) first);
+       DEBUG ("return (0x%p)", (void *) first);
 
        return (first);
 }
@@ -670,7 +680,7 @@ void cu_mount_freelist (cu_mount_t *list)
        cu_mount_t *this;
        cu_mount_t *next;
 
-       DBG ("(list = 0x%p)", (void *) list);
+       DEBUG ("(list = 0x%p)", (void *) list);
 
        for (this = list; this != NULL; this = next)
        {
index 3a77961..2e39060 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/vserver.c
- * Copyright (C) 2006  Sebastian Harl
+ * Copyright (C) 2006,2007  Sebastian Harl
  *
  * 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
 #include "plugin.h"
 
 #include <dirent.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <syslog.h>
 #include <sys/types.h>
-#include <unistd.h>
 
 #define BUFSIZE 512
 
 # define VSERVER_HAVE_READ 0
 #endif /* defined(KERNEL_LINUX) */
 
-static char *rrd_unix  = "vserver-%s/traffic-unix.rrd";
-static char *rrd_inet  = "vserver-%s/traffic-inet.rrd";
-static char *rrd_inet6 = "vserver-%s/traffic-inet6.rrd";
-static char *rrd_other = "vserver-%s/traffic-other.rrd";
-static char *rrd_unspec        = "vserver-%s/traffic-unspec.rrd";
-
-static char *rrd_thread        = "vserver-%s/vs_threads.rrd";
-
-static char *rrd_load  = "vserver-%s/load.rrd";
-
-static char *rrd_procs = "vserver-%s/vs_processes.rrd";
-static char *rrd_memory        = "vserver-%s/vs_memory.rrd";
+static data_source_t octets_dsrc[2] =
+{
+       {"rx", DS_TYPE_COUNTER, 0, 4294967295.0},
+       {"tx", DS_TYPE_COUNTER, 0, 4294967295.0}
+};
 
-/* 9223372036854775807 == LLONG_MAX */
-/* bytes transferred */
-static char *ds_def_unix[] =
+static data_set_t octets_ds =
 {
-       "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:failed:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       NULL
+       "if_octets", 2, octets_dsrc
 };
-static int ds_num_unix = 3;
 
-static char *ds_def_inet[] =
+static data_source_t load_dsrc[3] =
 {
-       "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:failed:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       NULL
+       {"shortterm", DS_TYPE_GAUGE, 0.0, 100.0},
+       {"midterm",   DS_TYPE_GAUGE, 0.0, 100.0},
+       {"longterm",  DS_TYPE_GAUGE, 0.0, 100.0}
 };
-static int ds_num_inet = 3;
 
-static char *ds_def_inet6[] =
+static data_set_t load_ds =
 {
-       "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:failed:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       NULL
+       "load", 3, load_dsrc
 };
-static int ds_num_inet6 = 3;
 
-static char *ds_def_other[] =
+static data_source_t threads_dsrc[1] =
 {
-       "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:failed:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       NULL
+       {"value", DS_TYPE_GAUGE, 0.0, 65535.0}
 };
-static int ds_num_other = 3;
 
-static char *ds_def_unspec[] =
+static data_set_t threads_ds =
 {
-       "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:failed:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       NULL
+       "vs_threads", 1, threads_dsrc
 };
-static int ds_num_unspec = 3;
 
-static char *ds_def_threads[] =
+static data_source_t processes_dsrc[1] =
 {
-       "DS:total:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
-       "DS:running:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
-       "DS:uninterruptible:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
-       "DS:onhold:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
-       NULL
+       {"value", DS_TYPE_GAUGE, 0.0, 65535.0}
 };
-static int ds_num_threads = 4;
 
-static char *ds_def_load[] =
+static data_set_t processes_ds =
 {
-       "DS:shortterm:GAUGE:"COLLECTD_HEARTBEAT":0:100",
-       "DS:midterm:GAUGE:"COLLECTD_HEARTBEAT":0:100",
-       "DS:longterm:GAUGE:"COLLECTD_HEARTBEAT":0:100",
-       NULL
+       "vs_processes", 1, processes_dsrc
 };
-static int ds_num_load = 3;
 
-static char *ds_def_procs[] =
+static data_source_t memory_dsrc[1] =
 {
-       "DS:total:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
-       NULL
+       {"value", DS_TYPE_GAUGE, 0.0, 9223372036854775807.0}
 };
-static int ds_num_procs = 1;
 
-/* 9223372036854775807 == LLONG_MAX */
-/* bytes */
-static char *ds_def_memory[] =
+static data_set_t memory_ds =
 {
-       "DS:vm:GAUGE:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:vml:GAUGE:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:rss:GAUGE:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       "DS:anon:GAUGE:"COLLECTD_HEARTBEAT":0:9223372036854775807",
-       NULL
+       "vs_memory", 1, memory_dsrc
 };
-static int ds_num_memory = 4;
 
+#if VSERVER_HAVE_READ
 static int pagesize = 0;
 
-static void vserver_init (void)
+static int vserver_init (void)
 {
        /* XXX Should we check for getpagesize () in configure?
         * What's the right thing to do, if there is no getpagesize ()? */
        pagesize = getpagesize ();
-       return;
-} /* static void vserver_init(void) */
-
-static void vserver_unix_write (char *host, char *inst, char *val)
-{
-       int  len;
-       char filename[BUFSIZE];
-
-       len = snprintf (filename, BUFSIZE, rrd_unix, inst);
-       if ((len > 0) && (len < BUFSIZE))
-               rrd_update_file (host, filename, val, ds_def_unix, ds_num_unix);
-       return;
-} /* static void vserver_unix_write(char *host, char *inst, char *val) */
-
-static void vserver_inet_write (char *host, char *inst, char *val)
-{
-       int  len;
-       char filename[BUFSIZE];
-
-       len = snprintf (filename, BUFSIZE, rrd_inet, inst);
-       if ((len > 0) && (len < BUFSIZE))
-               rrd_update_file (host, filename, val, ds_def_inet, ds_num_inet);
-       return;
-} /* static void vserver_inet_write(char *host, char *inst, char *val) */
-
-static void vserver_inet6_write (char *host, char *inst, char *val)
-{
-       int  len;
-       char filename[BUFSIZE];
-
-       len = snprintf (filename, BUFSIZE, rrd_inet6, inst);
-       if ((len > 0) && (len < BUFSIZE))
-               rrd_update_file (host, filename, val, ds_def_inet6, ds_num_inet6);
-       return;
-} /* static void vserver_inet6_write(char *host, char *inst, char *val) */
 
-static void vserver_other_write (char *host, char *inst, char *val)
-{
-       int  len;
-       char filename[BUFSIZE];
-
-       len = snprintf (filename, BUFSIZE, rrd_other, inst);
-       if ((len > 0) && (len < BUFSIZE))
-               rrd_update_file (host, filename, val, ds_def_other, ds_num_other);
-       return;
-} /* static void vserver_other_write(char *host, char *inst, char *val) */
+       return (0);
+} /* static void vserver_init(void) */
 
-static void vserver_unspec_write (char *host, char *inst, char *val)
+static void traffic_submit (const char *plugin_instance,
+               const char *type_instance, counter_t rx, counter_t tx)
 {
-       int  len;
-       char filename[BUFSIZE];
+       value_t values[2];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       len = snprintf (filename, BUFSIZE, rrd_unspec, inst);
-       if ((len > 0) && (len < BUFSIZE))
-               rrd_update_file (host, filename, val, ds_def_unspec, ds_num_unspec);
-       return;
-} /* static void vserver_unspec_write(char *host, char *inst, char *val) */
+       values[0].counter = rx;
+       values[1].counter = tx;
 
-static void vserver_threads_write (char *host, char *inst, char *val)
-{
-       int  len;
-       char filename[BUFSIZE];
+       vl.values = values;
+       vl.values_len = STATIC_ARRAY_SIZE (values);
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "vserver");
+       strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       len = snprintf (filename, BUFSIZE, rrd_thread, inst);
-       if ((len > 0) && (len < BUFSIZE))
-               rrd_update_file (host, filename, val, ds_def_threads, ds_num_threads);
-       return;
-} /* static void vserver_threads_write(char *host, char *inst, char *val) */
+       plugin_dispatch_values ("if_octets", &vl);
+} /* void traffic_submit */
 
-static void vserver_load_write (char *host, char *inst, char *val)
+static void load_submit (const char *plugin_instance,
+               gauge_t snum, gauge_t mnum, gauge_t lnum)
 {
-       int  len;
-       char filename[BUFSIZE];
+       value_t values[3];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       len = snprintf (filename, BUFSIZE, rrd_load, inst);
-       if ((len > 0) && (len < BUFSIZE))
-               rrd_update_file (host, filename, val, ds_def_load, ds_num_load);
-       return;
-} /* static void vserver_load_write(char *host, char *inst, char *val) */
-
-static void vserver_procs_write (char *host, char *inst, char *val)
-{
-       int  len;
-       char filename[BUFSIZE];
+       values[0].gauge = snum;
+       values[1].gauge = mnum;
+       values[2].gauge = lnum;
 
-       len = snprintf (filename, BUFSIZE, rrd_procs, inst);
-       if ((len > 0) && (len < BUFSIZE))
-               rrd_update_file (host, filename, val, ds_def_procs, ds_num_procs);
-       return;
-} /* static void vserver_procs_write(char *host, char *inst, char *val) */
+       vl.values = values;
+       vl.values_len = STATIC_ARRAY_SIZE (values);
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "vserver");
+       strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
 
-static void vserver_memory_write (char *host, char *inst, char *val)
-{
-       int  len;
-       char filename[BUFSIZE];
+       plugin_dispatch_values ("load", &vl);
+}
 
-       len = snprintf (filename, BUFSIZE, rrd_memory, inst);
-       if ((len > 0) && (len < BUFSIZE))
-               rrd_update_file (host, filename, val, ds_def_memory, ds_num_memory);
-       return;
-} /* static void vserver_memory_write(char *host, char *inst, char *val) */
+static void submit_gauge (const char *plugin_instance, const char *type,
+               const char *type_instance, gauge_t value)
 
-#if VSERVER_HAVE_READ
-static void vserver_submit (char *inst, long long unix_in, long long unix_out, 
-               long long unix_failed, long long inet_in, long long inet_out, 
-               long long inet_failed, long long inet6_in, long long inet6_out, 
-               long long inet6_failed, long long other_in, long long other_out,
-               long long other_failed, long long unspec_in, long long unspec_out, 
-               long long unspec_failed, int t_total, int t_running, 
-               int t_uninterruptible, int t_onhold, double avg1, double avg5, 
-               double avg15, int p_total, long long vm, long long vml, long long rss, 
-               long long anon)
 {
-       int  len;
-       char buffer[BUFSIZE];
-
-       len = snprintf (buffer, BUFSIZE, 
-                       "N:%lld:%lld:%lld", unix_in, unix_out, unix_failed);
-
-       if ((len > 0) && (len < BUFSIZE))
-               plugin_submit ("vserver_unix", inst, buffer);
-
-
-       len = snprintf (buffer, BUFSIZE, 
-                       "N:%lld:%lld:%lld", inet_in, inet_out, inet_failed);
-
-       if ((len > 0) && (len < BUFSIZE))
-               plugin_submit ("vserver_inet", inst, buffer);
-
-
-       len = snprintf (buffer, BUFSIZE, 
-                       "N:%lld:%lld:%lld", inet6_in, inet6_out, inet6_failed);
-
-       if ((len > 0) && (len < BUFSIZE))
-               plugin_submit ("vserver_inet6", inst, buffer);
-
-
-       len = snprintf (buffer, BUFSIZE, 
-                       "N:%lld:%lld:%lld", other_in, other_out, other_failed);
-
-       if ((len > 0) && (len < BUFSIZE))
-               plugin_submit ("vserver_other", inst, buffer);
-
-
-       len = snprintf (buffer, BUFSIZE, 
-                       "N:%lld:%lld:%lld", unspec_in, unspec_out, unspec_failed);
-
-       if ((len > 0) && (len < BUFSIZE))
-               plugin_submit ("vserver_unspec", inst, buffer);
-
-
-       len = snprintf (buffer, BUFSIZE, "N:%d:%d:%d:%d",
-                       t_total, t_running, t_uninterruptible, t_onhold);
-
-       if ((len > 0) && (len < BUFSIZE))
-               plugin_submit ("vserver_threads", inst, buffer);
-
-
-       len = snprintf (buffer, BUFSIZE, "N:%.2f:%.2f:%.2f",
-                       avg1, avg5, avg15);
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       if ((len > 0) && (len < BUFSIZE))
-               plugin_submit ("vserver_load", inst, buffer);
+       values[0].gauge = value;
 
+       vl.values = values;
+       vl.values_len = STATIC_ARRAY_SIZE (values);
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "vserver");
+       strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       len = snprintf (buffer, BUFSIZE, "N:%d",
-                       p_total);
-
-       if ((len > 0) && (len < BUFSIZE))
-               plugin_submit ("vserver_procs", inst, buffer);
-
-
-       len = snprintf (buffer, BUFSIZE, "N:%lld:%lld:%lld:%lld",
-                       vm, vml, rss, anon);
-
-       if ((len > 0) && (len < BUFSIZE))
-               plugin_submit ("vserver_memory", inst, buffer);
-       return;
-} /* static void vserver_submit() */
+       plugin_dispatch_values (type, &vl);
+} /* void submit_gauge */
 
 static inline long long __get_sock_bytes(const char *s)
 {
@@ -338,24 +173,22 @@ static inline long long __get_sock_bytes(const char *s)
        return atoll(s);
 }
 
-static void vserver_read (void)
+static int vserver_read (void)
 {
        DIR                     *proc;
        struct dirent   *dent; /* 42 */
 
-       static complain_t complain_obj;
-
        errno = 0;
        if (NULL == (proc = opendir (PROCDIR)))
        {
-               plugin_complain (LOG_ERR, &complain_obj, "vserver plugin: "
-                               "fopen (%s) failed: %s", PROCDIR, strerror (errno));
-               return;
+               char errbuf[1024];
+               ERROR ("vserver plugin: fopen (%s): %s", PROCDIR, 
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
        }
-       plugin_relief (LOG_NOTICE, &complain_obj, "vserver plugin: "
-                       "fopen (%s) succeeded.", PROCDIR);
 
-       while (NULL != (dent = readdir (proc))) {
+       while (NULL != (dent = readdir (proc)))
+       {
                int  len;
                char file[BUFSIZE];
 
@@ -364,24 +197,11 @@ static void vserver_read (void)
 
                char *cols[4];
 
-               long long       unix_s[3]       = {-1, -1, -1};
-               long long       inet[3]         = {-1, -1, -1};
-               long long       inet6[3]        = {-1, -1, -1};
-               long long       other[3]        = {-1, -1, -1};
-               long long       unspec[3]       = {-1, -1, -1};
-               int                     threads[4]      = {-1, -1, -1, -1};
-               double          load[3]         = {-1, -1, -1};
-               /* Just to be consistent ;-) */
-               int                     procs[1]        = {-1};
-               long long       memory[4]       = {-1, -1, -1, -1};
-
                if (dent->d_name[0] == '.')
                        continue;
 
-               /* XXX This check is just the result of a trial-and-error test.
-                * I did not find any documentation describing the d_type field. */
-               if (!(dent->d_type & 0x4))
-                       /* This is not a directory */
+               /* This is not a directory */
+               if (dent->d_type != DT_DIR)
                        continue;
 
                /* socket message accounting */
@@ -389,146 +209,177 @@ static void vserver_read (void)
                if ((len < 0) || (len >= BUFSIZE))
                        continue;
 
-               if (NULL == (fh = fopen (file, "r"))) {
-                       syslog (LOG_ERR, "Cannot open '%s': %s", file, strerror (errno));
-                       continue;
+               if (NULL == (fh = fopen (file, "r")))
+               {
+                       char errbuf[1024];
+                       ERROR ("Cannot open '%s': %s", file,
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
                }
 
-               while (NULL != fgets (buffer, BUFSIZE, fh)) {
+               while ((fh != NULL) && (NULL != fgets (buffer, BUFSIZE, fh)))
+               {
+                       counter_t rx;
+                       counter_t tx;
+                       char *type_instance;
+
                        if (strsplit (buffer, cols, 4) < 4)
                                continue;
 
-                       if (0 == strcmp (cols[0], "UNIX:")) {
-                               unix_s[0] = __get_sock_bytes (cols[1]);
-                               unix_s[1] = __get_sock_bytes (cols[2]);
-                               unix_s[2] = __get_sock_bytes (cols[3]);
-                       }
-                       else if (0 == strcmp (cols[0], "INET:")) {
-                               inet[0] = __get_sock_bytes (cols[1]);
-                               inet[1] = __get_sock_bytes (cols[2]);
-                               inet[2] = __get_sock_bytes (cols[3]);
-                       }
-                       else if (0 == strcmp (cols[0], "INET6:")) {
-                               inet6[0] = __get_sock_bytes (cols[1]);
-                               inet6[1] = __get_sock_bytes (cols[2]);
-                               inet6[2] = __get_sock_bytes (cols[3]);
-                       }
-                       else if (0 == strcmp (cols[0], "OTHER:")) {
-                               other[0] = __get_sock_bytes (cols[1]);
-                               other[1] = __get_sock_bytes (cols[2]);
-                               other[2] = __get_sock_bytes (cols[3]);
-                       }
-                       else if (0 == strcmp (cols[0], "UNSPEC:")) {
-                               unspec[0] = __get_sock_bytes (cols[1]);
-                               unspec[1] = __get_sock_bytes (cols[2]);
-                               unspec[2] = __get_sock_bytes (cols[3]);
-                       }
-               }
+                       if (0 == strcmp (cols[0], "UNIX:"))
+                               type_instance = "unix";
+                       else if (0 == strcmp (cols[0], "INET:"))
+                               type_instance = "inet";
+                       else if (0 == strcmp (cols[0], "INET6:"))
+                               type_instance = "inet6";
+                       else if (0 == strcmp (cols[0], "OTHER:"))
+                               type_instance = "other";
+                       else if (0 == strcmp (cols[0], "UNSPEC:"))
+                               type_instance = "unspec";
+                       else
+                               continue;
+
+                       rx = __get_sock_bytes (cols[1]);
+                       tx = __get_sock_bytes (cols[2]);
+                       /* cols[3] == errors */
 
-               fclose (fh);
+                       traffic_submit (dent->d_name, type_instance, rx, tx);
+               } /* while (fgets) */
+
+               if (fh != NULL)
+               {
+                       fclose (fh);
+                       fh = NULL;
+               }
 
                /* thread information and load */
                len = snprintf (file, BUFSIZE, PROCDIR "/%s/cvirt", dent->d_name);
                if ((len < 0) || (len >= BUFSIZE))
                        continue;
 
-               if (NULL == (fh = fopen (file, "r"))) {
-                       syslog (LOG_ERR, "Cannot open '%s': %s", file, strerror (errno));
-                       continue;
+               if (NULL == (fh = fopen (file, "r")))
+               {
+                       char errbuf[1024];
+                       ERROR ("Cannot open '%s': %s", file,
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
                }
 
-               while (NULL != fgets (buffer, BUFSIZE, fh)) {
+               while ((fh != NULL) && (NULL != fgets (buffer, BUFSIZE, fh)))
+               {
                        int n = strsplit (buffer, cols, 4);
 
-                       if (2 == n) {
-                               if (0 == strcmp (cols[0], "nr_threads:")) {
-                                       threads[0] = atoi (cols[1]);
-                               }
-                               else if (0 == strcmp (cols[0], "nr_running:")) {
-                                       threads[1] = atoi (cols[1]);
-                               }
-                               else if (0 == strcmp (cols[0], "nr_unintr:")) {
-                                       threads[2] = atoi (cols[1]);
-                               }
-                               else if (0 == strcmp (cols[0], "nr_onhold:")) {
-                                       threads[3] = atoi (cols[1]);
-                               }
+                       if (2 == n)
+                       {
+                               char   *type_instance;
+                               gauge_t value;
+
+                               if (0 == strcmp (cols[0], "nr_threads:"))
+                                       type_instance = "total";
+                               else if (0 == strcmp (cols[0], "nr_running:"))
+                                       type_instance = "running";
+                               else if (0 == strcmp (cols[0], "nr_unintr:"))
+                                       type_instance = "uninterruptable";
+                               else if (0 == strcmp (cols[0], "nr_onhold:"))
+                                       type_instance = "onhold";
+                               else
+                                       continue;
+
+                               value = atof (cols[1]);
+                               submit_gauge (dent->d_name, "vs_threads", type_instance, value);
                        }
                        else if (4 == n) {
-                               if (0 == strcmp (cols[0], "loadavg:")) {
-                                       load[0] = atof (cols[1]);
-                                       load[1] = atof (cols[2]);
-                                       load[2] = atof (cols[3]);
+                               if (0 == strcmp (cols[0], "loadavg:"))
+                               {
+                                       gauge_t snum = atof (cols[1]);
+                                       gauge_t mnum = atof (cols[2]);
+                                       gauge_t lnum = atof (cols[3]);
+                                       load_submit (dent->d_name, snum, mnum, lnum);
                                }
                        }
-               }
+               } /* while (fgets) */
 
-               fclose (fh);
+               if (fh != NULL)
+               {
+                       fclose (fh);
+                       fh = NULL;
+               }
 
                /* processes and memory usage */
                len = snprintf (file, BUFSIZE, PROCDIR "/%s/limit", dent->d_name);
                if ((len < 0) || (len >= BUFSIZE))
                        continue;
 
-               if (NULL == (fh = fopen (file, "r"))) {
-                       syslog (LOG_ERR, "Cannot open '%s': %s", file, strerror (errno));
-                       continue;
+               if (NULL == (fh = fopen (file, "r")))
+               {
+                       char errbuf[1024];
+                       ERROR ("Cannot open '%s': %s", file,
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
                }
 
-               while (NULL != fgets (buffer, BUFSIZE, fh)) {
+               while ((fh != NULL) && (NULL != fgets (buffer, BUFSIZE, fh)))
+               {
+                       char *type = "vs_memory";
+                       char *type_instance;
+                       gauge_t value;
+
                        if (strsplit (buffer, cols, 2) < 2)
                                continue;
 
-                       if (0 == strcmp (cols[0], "PROC:")) {
-                               procs[0] = atoi (cols[1]);
+                       if (0 == strcmp (cols[0], "PROC:"))
+                       {
+                               type = "vs_processes";
+                               type_instance = "";
+                               value = atof (cols[1]);
                        }
-                       else if (0 == strcmp (cols[0], "VM:")) {
-                               memory[0] = atoll (cols[1]) * pagesize;
+                       else
+                       {
+                               if (0 == strcmp (cols[0], "VM:"))
+                                       type_instance = "vm";
+                               else if (0 == strcmp (cols[0], "VML:"))
+                                       type_instance = "vml";
+                               else if (0 == strcmp (cols[0], "RSS:"))
+                                       type_instance = "rss";
+                               else if (0 == strcmp (cols[0], "ANON:"))
+                                       type_instance = "anon";
+                               else
+                                       continue;
+
+                               value = atof (cols[1]) * pagesize;
                        }
-                       else if (0 == strcmp (cols[0], "VML:")) {
-                               memory[1] = atoll (cols[1]) * pagesize;
-                       }
-                       else if (0 == strcmp (cols[0], "RSS:")) {
-                               memory[2] = atoll (cols[1]) * pagesize;
-                       }
-                       else if (0 == strcmp (cols[0], "ANON:")) {
-                               memory[3] = atoll (cols[1]) * pagesize;
-                       }
-               }
-
-               fclose (fh);
 
-               /* XXX What to do in case of an error (i.e. some value is
-                * still -1)? */
+                       submit_gauge (dent->d_name, type, type_instance, value);
+               } /* while (fgets) */
 
-               vserver_submit (dent->d_name, unix_s[0], unix_s[1], unix_s[2], 
-                               inet[0], inet[1], inet[2], inet6[0], inet6[1], inet6[2], 
-                               other[0], other[1], other[2], unspec[0], unspec[1], unspec[2],
-                               threads[0], threads[1], threads[2], threads[3], load[0], 
-                               load[1], load[2], procs[0], memory[0], memory[1], memory[2], 
-                               memory[3]);
-       }
+               if (fh != NULL)
+               {
+                       fclose (fh);
+                       fh = NULL;
+               }
+       } /* while (readdir) */
 
        closedir (proc);
-       return;
-} /* static void vserver_read(void) */
-#else
-# define vserver_read NULL
+
+       return (0);
+} /* int vserver_read */
 #endif /* VSERVER_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, vserver_init, vserver_read, NULL);
-       plugin_register ("vserver_unix", NULL, NULL, vserver_unix_write);
-       plugin_register ("vserver_inet", NULL, NULL, vserver_inet_write);
-       plugin_register ("vserver_inet6", NULL, NULL, vserver_inet6_write);
-       plugin_register ("vserver_other", NULL, NULL, vserver_other_write);
-       plugin_register ("vserver_unspec", NULL, NULL, vserver_unspec_write);
-       plugin_register ("vserver_threads", NULL, NULL, vserver_threads_write);
-       plugin_register ("vserver_load", NULL, NULL, vserver_load_write);
-       plugin_register ("vserver_procs", NULL, NULL, vserver_procs_write);
-       plugin_register ("vserver_memory", NULL, NULL, vserver_memory_write);
-       return;
+       if (load & MR_DATASETS)
+       {
+               plugin_register_data_set (&octets_ds);
+               plugin_register_data_set (&load_ds);
+               plugin_register_data_set (&threads_ds);
+               plugin_register_data_set (&processes_ds);
+               plugin_register_data_set (&memory_ds);
+       }
+
+#if VSERVER_HAVE_READ
+       if (load & MR_READ)
+       {
+               plugin_register_init ("vserver", vserver_init);
+               plugin_register_read ("vserver", vserver_read);
+       }
+#endif /* VSERVER_HAVE_READ */
 } /* void module_register(void) */
 
 /* vim: set ts=4 sw=4 noexpandtab : */
index f0b9b01..007272e 100644 (file)
@@ -1,11 +1,10 @@
 /**
  * collectd - src/wireless.c
- * Copyright (C) 2006  Florian octo Forster
+ * Copyright (C) 2006,2007  Florian octo Forster
  *
  * 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.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -24,9 +23,6 @@
 #include "common.h"
 #include "plugin.h"
 
-#define MODULE_NAME "wireless"
-#define BUFSIZE 1024
-
 #if defined(KERNEL_LINUX)
 # define WIRELESS_HAVE_READ 1
 #else
 
 #define WIRELESS_PROC_FILE "/proc/net/wireless"
 
-static char *filename_template = "wireless-%s.rrd";
-
-static char *ds_def[] =
+static data_source_t data_source_quality[1] =
 {
-       "DS:quality:GAUGE:"COLLECTD_HEARTBEAT":0:U",
-       "DS:power:GAUGE:"COLLECTD_HEARTBEAT":U:0",
-       "DS:noise:GAUGE:"COLLECTD_HEARTBEAT":U:0",
-       NULL
+       {"value", DS_TYPE_GAUGE, 0, NAN}
 };
-static int ds_num = 3;
-
-#if WIRELESS_HAVE_READ
-static int proc_file_found = 0;
-#endif
 
-static void wireless_init (void)
+static data_set_t quality_ds =
 {
-#if WIRELESS_HAVE_READ
-       if (access (WIRELESS_PROC_FILE, R_OK) == 0)
-               proc_file_found = 1;
-       else
-               proc_file_found = 0;
-#endif
-
-       return;
-}
+       "signal_quality", 1, data_source_quality
+};
 
-static void wireless_write (char *host, char *inst, char *val)
+static data_source_t data_source_signal[1] =
 {
-       char file[BUFSIZE];
-       int status;
+       {"value", DS_TYPE_GAUGE, NAN, 0}
+};
 
-       status = snprintf (file, BUFSIZE, filename_template, inst);
-       if (status < 1)
-               return;
-       else if (status >= BUFSIZE)
-               return;
+static data_set_t power_ds =
+{
+       "signal_power", 1, data_source_signal
+};
 
-       rrd_update_file (host, file, val, ds_def, ds_num);
-}
+static data_set_t noise_ds =
+{
+       "signal_noise", 1, data_source_signal
+};
 
 #if WIRELESS_HAVE_READ
 #if 0
@@ -93,27 +73,30 @@ static double wireless_dbm_to_watt (double dbm)
 }
 #endif
 
-static void wireless_submit (char *device,
-               double quality, double power, double noise)
+static void wireless_submit (const char *plugin_instance, const char *type,
+               double value)
 {
-       char buf[BUFSIZE];
-       int  status;
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
 
-       status = snprintf (buf, BUFSIZE, "%u:%f:%f:%f",
-                       (unsigned int) curtime,
-                       quality, power, noise);
-       if ((status < 1) || (status >= BUFSIZE))
-               return;
+       values[0].gauge = value;
 
-       plugin_submit (MODULE_NAME, device, buf);
-}
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "wireless");
+       strncpy (vl.plugin_instance, plugin_instance,
+                       sizeof (vl.plugin_instance));
 
-static void wireless_read (void)
+       plugin_dispatch_values (type, &vl);
+} /* void wireless_submit */
+
+static int wireless_read (void)
 {
 #ifdef KERNEL_LINUX
-
        FILE *fh;
-       char buffer[BUFSIZE];
+       char buffer[1024];
 
        char   *device;
        double  quality;
@@ -123,19 +106,20 @@ static void wireless_read (void)
        char *fields[8];
        int   numfields;
 
+       int devices_found;
        int len;
 
-       if (!proc_file_found)
-               return;
-
        /* there are a variety of names for the wireless device */
        if ((fh = fopen (WIRELESS_PROC_FILE, "r")) == NULL)
        {
-               syslog (LOG_WARNING, "wireless: fopen: %s", strerror (errno));
-               return;
+               char errbuf[1024];
+               WARNING ("wireless: fopen: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
        }
 
-       while (fgets (buffer, BUFSIZE, fh) != NULL)
+       devices_found = 0;
+       while (fgets (buffer, sizeof (buffer), fh) != NULL)
        {
                numfields = strsplit (buffer, fields, 8);
 
@@ -164,20 +148,36 @@ static void wireless_read (void)
                if (noise == 0.0)
                        noise = 1.0; /* noise <= 0 */
 
-               wireless_submit (device, quality, power, noise);
+               wireless_submit (device, "signal_quality", quality);
+               wireless_submit (device, "signal_power", power);
+               wireless_submit (device, "signal_noise", noise);
+
+               devices_found++;
        }
 
        fclose (fh);
+
+       /* If no wireless devices are present return an error, so the plugin
+        * code delays our read function. */
+       if (devices_found == 0)
+               return (-1);
 #endif /* KERNEL_LINUX */
-}
-#else
-# define wireless_read NULL
+
+       return (0);
+} /* int wireless_read */
 #endif /* WIRELESS_HAVE_READ */
 
-void module_register (void)
+void module_register (modreg_e load)
 {
-       plugin_register (MODULE_NAME, wireless_init, wireless_read, wireless_write);
-}
+       if (load & MR_DATASETS)
+       {
+               plugin_register_data_set (&quality_ds);
+               plugin_register_data_set (&power_ds);
+               plugin_register_data_set (&noise_ds);
+       }
 
-#undef BUFSIZE
-#undef MODULE_NAME
+#if WIRELESS_HAVE_READ
+       if (load & MR_READ)
+               plugin_register_read ("wireless", wireless_read);
+#endif /* WIRELESS_HAVE_READ */
+} /* void module_register */