Merge branch 'collectd-4.0' into collectd-4.1
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Fri, 12 Oct 2007 16:33:59 +0000 (18:33 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Fri, 12 Oct 2007 16:33:59 +0000 (18:33 +0200)
Conflicts:

src/rrdtool.c

67 files changed:
.gitignore
ChangeLog
README
configure.in
contrib/PerlLib/Collectd.pm
contrib/PerlLib/Collectd/Unixsock.pm
contrib/README
contrib/SpamAssassin/Collectd.pm
contrib/SpamAssassin/example.cf
contrib/collection.conf [new file with mode: 0644]
contrib/cussh.pl [new file with mode: 0755]
src/Makefile.am
src/apache.c
src/apcups.c
src/apple_sensors.c
src/battery.c
src/collectd-exec.pod
src/collectd-nagios.c
src/collectd-snmp.pod [new file with mode: 0644]
src/collectd-unixsock.pod
src/collectd.conf.in
src/collectd.conf.pod
src/collectd.h
src/collectd.pod
src/configfile.c
src/configfile.h
src/cpu.c
src/cpufreq.c
src/df.c
src/disk.c
src/dns.c
src/email.c
src/entropy.c
src/exec.c
src/hddtemp.c
src/interface.c
src/iptables.c
src/irq.c
src/load.c
src/mbmon.c
src/memory.c
src/multimeter.c
src/mysql.c
src/netlink.c [new file with mode: 0644]
src/network.c
src/network.h
src/nfs.c
src/ntpd.c
src/nut.c
src/plugin.c
src/plugin.h
src/processes.c
src/rrdtool.c
src/sensors.c
src/serial.c
src/snmp.c [new file with mode: 0644]
src/swap.c
src/tape.c
src/types.db
src/unixsock.c
src/users.c
src/utils_cmd_putval.c [new file with mode: 0644]
src/utils_cmd_putval.h [new file with mode: 0644]
src/vserver.c
src/wireless.c
src/xmms.c [new file with mode: 0644]
version-gen.sh [new file with mode: 0755]

index 5029e96..855e36b 100644 (file)
@@ -32,6 +32,7 @@ config.status
 libtool
 src/.deps
 src/Makefile
+src/collectd.conf
 src/config.h
 src/libconfig/Makefile
 src/liboping/Makefile
@@ -43,16 +44,22 @@ src/*.la
 src/*.lo
 src/*.o
 src/collectd
-src/collectd.1
-src/collectd.conf.5
+src/collectd*.1
+src/collectd*.5
 src/config.h.in~
-src/libconfig/.libs
-src/libconfig/*.la
-src/libconfig/*.lo
+src/liboconfig/.libs
+src/liboconfig/*.la
+src/liboconfig/*.lo
 src/liboping/.libs
 src/liboping/*.la
 src/liboping/*.lo
 
+# lex / yacc stuff:
+ylwrap
+src/liboconfig/parser.c
+src/liboconfig/parser.h
+src/liboconfig/scanner.c
+
 # make dist stuff:
 collectd-*.tar.gz
 collectd-*.tar.bz2
index 653227f..099a5ca 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,52 @@
+       * rrdtool plugin: Use the threadsafe RRD-library if available. Try to
+         be more threadsafe otherwise by locking calls to the library.
+
+2007-09-28, Version 4.1.2
+       * apcups plugin: Fix reporting of the `load percent' data.
+       * wireless plugin: Correct the handling of cards returning signal and
+         noise quality as percentage.
+       * perl plugin: Fix a possible buffer overflow in get_module_name().
+       * build system: Further improve the detection of libraries.
+       * netlink plugin: Build issues under some older versions of the Linux
+         includes (i. e. Debian Sarge) have been fixed.
+       * snmp plugin: Fix a potential segfault when a host times out. Add
+         support for the `timeticks' type. 
+
+2007-09-12, Version 4.1.1
+       * Build system: The detection of `libnetlink' has been improved.
+       * collectd: The documentation has been fixed in numerous places.
+       * exec plugin: Setting the group under which to run a program has been
+         fixed.
+       * collectd: The `sstrerror' function was improved to work correctly
+         with the broken GNU version of `strerror_r'.
+       * collectd: Write an error message to STDERR when loading of a plugin
+         fails.
+       * apcups plugin: Fix the `types' used to submit the values: They still
+         has an `apcups_' prefix which doesn't work anymore.
+       * rrdtool plugin: Create new RRD-files with the `begin' time set to
+         whatever the client thinks is `now'..
+
+2007-09-01, Version 4.1.0
+       * Build system: The build system has been changed to automatically
+         disable all plugins, which are missing dependencies. The dependency
+         checking has been removed from the plugins themselves to remove
+         redundancy.
+       * Flexible interval: The interval of collected data is now sent along
+         with the data itself over the network, so that the interval-settings
+         of server and clients no longer needs to match.
+       * netlink plugin: The new `netlink' plugin connects to the Linux
+         kernel using a netlink socket and uses it to query information about
+         interfaces, qdiscs and classes.
+       * rrdtool plugin: The cache is now dumped to disk in an extra thread
+         to not block data collection.
+       * snmp plugin: The new `snmp' plugin can read values from SNMP enabled
+         network devices, such as switches, routers, thermometers, rack
+         monitoring servers, etc. The collectd-snmp(5) manpage documents this
+         plugin.
+       * unixsock plugin: Added the `LISTVAL' command.
+       * xmms plugin: The new `xmms' plugin graphs the bitrate and frequency
+         of music played with xmms.
+
 2007-09-28, Version 4.0.9
        * apcups plugin: Fix reporting of the `load percent' data.
        * wireless plugin: Correct the handling of cards returning signal and
diff --git a/README b/README
index 6f59a7a..56dee29 100644 (file)
--- a/README
+++ b/README
@@ -91,6 +91,11 @@ Features
       MySQL server statistics: Commands issued, handlers triggered, thread
       usage, query cache utilization and traffic/octets sent and received.
 
+    - netlink
+      Very detailed Linux network interface and routing statistics. You can get
+      (detailed) information on interfaces, qdiscs, classes, and, if you can
+      make use of it, filters.
+
     - network
       Receive values that were collected by other hosts. Large setups will
       want to collect the data on one dedicated machine, and this is the
@@ -129,6 +134,11 @@ Features
     - serial
       RX and TX of serial interfaces. Linux only; needs root privileges.
 
+    - snmp
+      Read values from SNMP (Simple Network Management Protocol) enabled
+      network devices such as switches, routers, thermometers, rack monitoring
+      servers, etc. See collectd-snmp(5).
+
     - swap
       Pages swapped out onto harddisk or whatever is called `swap' by the OS..
 
@@ -145,6 +155,9 @@ Features
     - wireless
       Link quality of wireless cards. Linux only.
 
+    - xmms
+      Bitrate and frequency of music played with XMMS.
+
   * Output can be written or send to various destinations by the following
     plugins:
 
@@ -205,8 +218,8 @@ Operation
   * When the `csv' or `rrdtool' plugins are loaded they'll write the values to
     files. The usual place for these files is beneath `/var/lib/collectd'.
 
-  * When using some of the plugins, collectd needs to run as user root, since only
-    root can do certain things, such as craft ICMP packages needed to ping
+  * When using some of the plugins, collectd needs to run as user root, since
+    only root can do certain things, such as craft ICMP packages needed to ping
     other hosts. collectd should NOT be installed setuid root since it can be
     used to overwrite valuable files!
 
@@ -223,6 +236,17 @@ Operation
     the values and read the rrdtool(1) manpage thoroughly.
 
 
+collectd and chkrootkit
+-----------------------
+
+  If you are using the `dns' plugin chkrootkit(1) will report collectd as a
+  packet sniffer ("<iface>: PACKET SNIFFER(/usr/sbin/collectd[<pid>])"). The
+  plugin captures all UDP packets on port 53 to analyze the DNS traffic. In
+  this case, collectd is a legitimate sniffer and the report should be
+  considered to be a false positive. However, you might want to check that
+  this really is collectd and not some other, illegitimate sniffer.
+
+
 Prerequisites
 -------------
 
@@ -244,6 +268,10 @@ Prerequisites
 
   * libmysqlclient (optional)
 
+  * libnetlink (optional)
+
+  * libnetsnmp (optional)
+
   * liboping (optional, if not found a version shipped with this distribution
     can be used)
     Used by the `ping' plugin to send and receive ICMP packets.
@@ -268,6 +296,8 @@ Prerequisites
   * libupsclient/nut (optional)
     For the `nut' plugin which queries nut's `upsd'.
 
+  * libxmms (optional)
+
   * librt, libsocket, libkstat, libdevinfo
     Various standard Solaris libraries which provide system functions.
 
@@ -279,20 +309,20 @@ Prerequisites
 Crosscompiling
 --------------
 
-    To compile correctly collectd needs to be able to initialize static
-    variables to NAN (Not A Number). Some C libraries, especially the GNU
-    libc, have a problem with that.
+  To compile correctly collectd needs to be able to initialize static
+  variables to NAN (Not A Number). Some C libraries, especially the GNU
+  libc, have a problem with that.
 
-    Luckily, with GCC it's possible to work around that problem: One can define
-    NAN as being (0.0 / 0.0) and `isnan' as `f != f'. However, to test this
-    ``implementation'' the configure script needs to compile and run a short
-    test program. Obviously running a test program when doing a cross-
-    compilation is, well, challenging.
+  Luckily, with GCC it's possible to work around that problem: One can define
+  NAN as being (0.0 / 0.0) and `isnan' as `f != f'. However, to test this
+  ``implementation'' the configure script needs to compile and run a short
+  test program. Obviously running a test program when doing a cross-
+  compilation is, well, challenging.
 
-    If you run into this problem, you can use the `--with-nan-emulation'
-    configure option to force the use of this implementation. We can't promise
-    that the compiled binary actually behaves as it should, but since NANs
-    are likely never passed to the libm you have a good chance to be lucky.
+  If you run into this problem, you can use the `--with-nan-emulation'
+  configure option to force the use of this implementation. We can't promise
+  that the compiled binary actually behaves as it should, but since NANs
+  are likely never passed to the libm you have a good chance to be lucky.
 
 
 Contact
index 40016fd..78a807a 100644 (file)
@@ -1,5 +1,5 @@
 dnl Process this file with autoconf to produce a configure script.
-AC_INIT(collectd, 4.0.9)
+AC_INIT(collectd, m4_esyscmd(./version-gen.sh))
 AC_CONFIG_SRCDIR(src/collectd.c)
 AC_CONFIG_HEADERS(src/config.h)
 AM_INIT_AUTOMAKE(dist-bzip2)
@@ -30,29 +30,32 @@ AC_PROG_LEX
 AC_PROG_YACC
 AC_CONFIG_SUBDIRS(libltdl)
 
+AC_MSG_CHECKING([for kernel type ($host_os)])
+case $host_os in
+       *linux*)
+       AC_DEFINE([KERNEL_LINUX], 1, [True if program is to be compiled for a Linux kernel])
+       ac_system="Linux"
+       ;;
+       *solaris*)
+       AC_DEFINE([KERNEL_SOLARIS], 1, [True if program is to be compiled for a Solaris kernel])
+       ac_system="Solaris"
+       ;;
+       *darwin*)
+       ac_system="Darwin"
+       ;;
+       *)
+       ac_system="unknown"
+esac
+AC_MSG_RESULT([$ac_system])
+
 #
 # Checks for header files.
 #
 AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
 AC_HEADER_DIRENT
-AC_CHECK_HEADERS(stdint.h)
-AC_CHECK_HEADERS(stdio.h)
-AC_CHECK_HEADERS(errno.h)
-AC_CHECK_HEADERS(math.h)
-AC_CHECK_HEADERS(syslog.h)
-AC_CHECK_HEADERS(fcntl.h)
-AC_CHECK_HEADERS(signal.h)
-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(poll.h)
-AC_CHECK_HEADERS(netdb.h)
-AC_CHECK_HEADERS(arpa/inet.h)
-AC_CHECK_HEADERS(sys/resource.h)
-AC_CHECK_HEADERS(sys/param.h)
-AC_CHECK_HEADERS(kstat.h)
+
+AC_CHECK_HEADERS(stdint.h stdio.h errno.h math.h stdarg.h syslog.h fcntl.h signal.h assert.h sys/types.h sys/socket.h sys/select.h poll.h netdb.h arpa/inet.h sys/resource.h sys/param.h kstat.h regex.h sys/ioctl.h)
 
 # For ping library
 AC_CHECK_HEADERS(netinet/in_systm.h, [], [],
@@ -189,6 +192,12 @@ AC_CHECK_HEADERS(netinet/udp.h, [], [],
 ])
 
 # For cpu modules
+AC_CHECK_HEADERS(sys/dkstat.h)
+if test "x$ac_system" = "xDarwin"
+then
+       AC_CHECK_HEADERS(mach/mach_init.h mach/host_priv.h mach/mach_error.h mach/mach_host.h mach/mach_port.h mach/mach_types.h mach/message.h mach/processor_set.h mach/processor.h mach/processor_info.h mach/task.h mach/thread_act.h mach/vm_region.h mach/vm_map.h mach/vm_prot.h mach/vm_statistics.h mach/kern_return.h)
+       AC_CHECK_HEADERS(CoreFoundation/CoreFoundation.h IOKit/IOKitLib.h IOKit/IOTypes.h IOKit/ps/IOPSKeys.h IOKit/IOBSD.h IOKit/storage/IOBlockStorageDriver.h)
+fi
 AC_CHECK_HEADERS(sys/sysctl.h, [], [],
 [
 #if HAVE_SYS_TYPES_H
@@ -198,33 +207,9 @@ AC_CHECK_HEADERS(sys/sysctl.h, [], [],
 # include <sys/param.h>
 #endif
 ])
-AC_CHECK_HEADERS(sys/dkstat.h)
-AC_CHECK_HEADERS(mach/mach_init.h)
-AC_CHECK_HEADERS(mach/host_priv.h)
-AC_CHECK_HEADERS(mach/mach_error.h)
-AC_CHECK_HEADERS(mach/mach_host.h)
-AC_CHECK_HEADERS(mach/mach_port.h)
-AC_CHECK_HEADERS(mach/mach_types.h)
-AC_CHECK_HEADERS(mach/message.h)
-AC_CHECK_HEADERS(mach/processor_set.h)
-AC_CHECK_HEADERS(mach/processor.h)
-AC_CHECK_HEADERS(mach/processor_info.h)
-AC_CHECK_HEADERS(mach/task.h)
-AC_CHECK_HEADERS(mach/thread_act.h)
-AC_CHECK_HEADERS(mach/vm_region.h)
-AC_CHECK_HEADERS(mach/vm_map.h)
-AC_CHECK_HEADERS(mach/vm_prot.h)
-AC_CHECK_HEADERS(mach/vm_statistics.h)
-AC_CHECK_HEADERS(mach/kern_return.h)
 
 # For hddtemp module
-AC_CHECK_HEADERS(linux/major.h)
-AC_CHECK_HEADERS(libgen.h)
-
-# For the apple_sensors module
-AC_CHECK_HEADERS(CoreFoundation/CoreFoundation.h)
-AC_CHECK_HEADERS(IOKit/IOKitLib.h)
-AC_CHECK_HEADERS(IOKit/IOTypes.h)
+AC_CHECK_HEADERS(linux/major.h libgen.h)
 
 # For the battery plugin
 AC_CHECK_HEADERS(IOKit/ps/IOPowerSources.h, [], [],
@@ -236,17 +221,6 @@ AC_CHECK_HEADERS(IOKit/ps/IOPowerSources.h, [], [],
 #  include <IOKit/IOTypes.h>
 #endif
 ])
-AC_CHECK_HEADERS(IOKit/ps/IOPSKeys.h)
-
-# For the `disk' plugin
-AC_CHECK_HEADERS(IOKit/IOBSD.h)
-AC_CHECK_HEADERS(IOKit/storage/IOBlockStorageDriver.h)
-
-# For load module
-AC_CHECK_HEADERS(sys/loadavg.h)
-
-# For the processes plugin
-AC_CHECK_HEADERS(linux/config.h)
 
 # For the swap module
 AC_CHECK_HEADERS(sys/swap.h, [], [],
@@ -259,9 +233,10 @@ AC_CHECK_HEADERS(sys/swap.h, [], [],
 #endif
 ])
 
+# For load module
+# For the processes plugin
 # For users module
-AC_CHECK_HEADERS(utmp.h)
-AC_CHECK_HEADERS(utmpx.h)
+AC_CHECK_HEADERS(sys/loadavg.h linux/config.h utmp.h utmpx.h)
 
 # For interface plugin
 AC_CHECK_HEADERS(ifaddrs.h)
@@ -296,11 +271,7 @@ AC_CHECK_HEADERS(linux/netdevice.h, [], [],
 #endif
 ])
 
-# For apache plugin
-AC_CHECK_HEADERS(curl/curl.h)
-
 # For quota module
-AC_CHECK_HEADERS(pwd.h)
 AC_CHECK_HEADERS(sys/ucred.h, [], [],
 [
 #if HAVE_SYS_TYPES_H
@@ -310,21 +281,8 @@ AC_CHECK_HEADERS(sys/ucred.h, [], [],
 # include <sys/param.h>
 #endif
 ])
-AC_CHECK_HEADERS(ctype.h)
-AC_CHECK_HEADERS(limits.h)
-AC_CHECK_HEADERS(sys/quota.h)
-AC_CHECK_HEADERS(xfs/xqm.h)
 
 # For mount interface
-AC_CHECK_HEADERS(fs_info.h)
-AC_CHECK_HEADERS(fshelp.h)
-AC_CHECK_HEADERS(paths.h)
-AC_CHECK_HEADERS(mntent.h)
-AC_CHECK_HEADERS(mnttab.h)
-AC_CHECK_HEADERS(sys/fstyp.h)
-AC_CHECK_HEADERS(sys/fs_types.h)
-AC_CHECK_HEADERS(sys/mntent.h)
-AC_CHECK_HEADERS(sys/mnttab.h)
 AC_CHECK_HEADERS(sys/mount.h, [], [],
 [
 #if HAVE_SYS_TYPES_H
@@ -334,13 +292,6 @@ AC_CHECK_HEADERS(sys/mount.h, [], [],
 # include <sys/param.h>
 #endif
 ])
-AC_CHECK_HEADERS(sys/statfs.h)
-AC_CHECK_HEADERS(sys/statvfs.h)
-AC_CHECK_HEADERS(sys/vfs.h)
-AC_CHECK_HEADERS(sys/vfstab.h)
-
-# For the swap plugin, FreeBSD
-AC_CHECK_HEADERS(kvm.h)
 
 # For the email plugin
 AC_CHECK_HEADERS(linux/un.h, [], [],
@@ -349,14 +300,8 @@ AC_CHECK_HEADERS(linux/un.h, [], [],
 #      include <sys/socket.h>
 #endif
 ])
-AC_CHECK_HEADERS(sys/un.h)
-AC_CHECK_HEADERS(grp.h)
 
-# For debugging interface (variable number of arguments)
-AC_CHECK_HEADERS(stdarg.h)
-
-# Regular expressions for the ignorelist.
-AC_CHECK_HEADERS(regex.h)
+AC_CHECK_HEADERS(pwd.h grp.h sys/un.h ctype.h limits.h sys/quota.h xfs/xqm.h fs_info.h fshelp.h paths.h mntent.h mnttab.h sys/fstyp.h sys/fs_types.h sys/mntent.h sys/mnttab.h sys/statfs.h sys/statvfs.h sys/vfs.h sys/vfstab.h kvm.h)
 
 # For the dns plugin
 AC_CHECK_HEADERS(arpa/nameser.h)
@@ -397,8 +342,8 @@ AC_CHECK_HEADERS(netinet/if_ether.h, [], [],
 ])
 
 # For the multimeter plugin
-AC_CHECK_HEADERS(termios.h)
-AC_CHECK_HEADERS(sys/ioctl.h)
+have_termios_h="no"
+AC_CHECK_HEADERS(termios.h, [have_termios_h="yes"])
 
 #
 # Checking for libraries
@@ -418,11 +363,7 @@ AC_HEADER_TIME
 # Checks for library functions.
 #
 AC_PROG_GCC_TRADITIONAL
-AC_CHECK_FUNCS(gettimeofday select strdup strtol)
-AC_CHECK_FUNCS(getaddrinfo getnameinfo)
-AC_CHECK_FUNCS(strchr memcpy strstr strcmp strncmp strncpy strlen)
-AC_CHECK_FUNCS(strncasecmp strcasecmp)
-AC_CHECK_FUNCS(openlog syslog closelog)
+AC_CHECK_FUNCS(gettimeofday select strdup strtol getaddrinfo getnameinfo strchr memcpy strstr strcmp strncmp strncpy strlen strncasecmp strcasecmp openlog closelog)
 
 AC_FUNC_STRERROR_R
 
@@ -437,27 +378,22 @@ nanosleep_needs_rt="no"
 AC_CHECK_FUNCS(nanosleep, [], AC_CHECK_LIB(rt, nanosleep, [nanosleep_needs_rt="yes"], AC_MSG_ERROR(cannot find nanosleep)))
 AM_CONDITIONAL(BUILD_WITH_LIBRT, test "x$nanosleep_needs_rt" = "xyes")
 
-# Regular expressions for the ignorelist.
 AC_CHECK_FUNCS(regcomp regerror regexec regfree)
 
-# For cpu module
 AC_CHECK_FUNCS(sysctlbyname, [have_sysctlbyname="yes"], [have_sysctlbyname="no"])
-
-# For df module
-AC_CHECK_FUNCS(statfs statvfs)
+AC_CHECK_FUNCS(host_statistics, [have_host_statistics="yes"], [have_host_statistics="no"])
+AC_CHECK_FUNCS(processor_info, [have_processor_info="yes"], [have_processor_info="no"])
+AC_CHECK_FUNCS(thread_info, [have_thread_info="yes"], [have_thread_info="no"])
+AC_CHECK_FUNCS(statfs, [have_statfs="yes"], [have_statfs="no"])
+AC_CHECK_FUNCS(statvfs, [have_statvfs="yes"], [have_statvfs="no"])
+AC_CHECK_FUNCS(getifaddrs, [have_getifaddrs="yes"], [have_getifaddrs="no"])
+AC_CHECK_FUNCS(syslog, [have_syslog="yes"], [have_syslog="no"])
+AC_CHECK_FUNCS(getutent, [have_getutent="yes"], [have_getutent="no"])
+AC_CHECK_FUNCS(getutxent, [have_getutxent="yes"], [have_getutxent="no"])
 
 # For load module
 AC_CHECK_FUNCS(getloadavg, [have_getloadavg="yes"], [have_getloadavg="no"])
 
-# For the `processes' plugin
-AC_CHECK_FUNCS(thread_info)
-
-# For users module
-AC_CHECK_FUNCS(getutent getutxent)
-
-# For interface module
-AC_CHECK_FUNCS(getifaddrs)
-
 # Check for NAN
 AC_ARG_WITH(nan-emulation, [AS_HELP_STRING([--with-nan-emulation], [use emulated NAN. For crosscompiling only.])],
 [
@@ -721,21 +657,6 @@ AC_CHECK_MEMBERS([kstat_io_t.nwritten, kstat_io_t.writes, kstat_io_t.nwrites, ks
 #endif
        ])
 
-AC_MSG_CHECKING([for kernel type ($host_os)])
-case $host_os in
-       *linux*)
-       AC_DEFINE([KERNEL_LINUX], 1, [True if program is to be compiled for a Linux kernel])
-       ac_system="Linux"
-       ;;
-       *solaris*)
-       AC_DEFINE([KERNEL_SOLARIS], 1, [True if program is to be compiled for a Solaris kernel])
-       ac_system="Solaris"
-       ;;
-       *)
-       ac_system="unknown"
-esac
-AC_MSG_RESULT([$ac_system])
-
 with_libresolv="yes"
 AC_CHECK_LIB(resolv, res_search,
 [
@@ -749,35 +670,57 @@ m4_divert_once([HELP_WITH], [
 collectd additional packages:])
 
 # AC_ARG_WITH (package, help-string, [action-if-given], [action-if-not-given])
+librrd_cflags=""
+librrd_ldflags=""
+librrd_threadsafe="yes"
 AC_ARG_WITH(rrdtool, [AS_HELP_STRING([--with-rrdtool@<:@=PREFIX@:>@], [Path to rrdtool.])],
 [      if test "x$withval" != "xno" && test "x$withval" != "xyes"
        then
-               LDFLAGS="$LDFLAGS -L$withval/lib"
-               CPPFLAGS="$CPPFLAGS -I$withval/include"
+               librrd_cflags="-I$withval/include"
+               librrd_ldflags="-L$withval/lib"
                with_rrdtool="yes"
        fi
 ], [with_rrdtool="yes"])
 if test "x$with_rrdtool" = "xyes"
 then
-       AC_CHECK_LIB(rrd, rrd_update,
-       [
-               AC_DEFINE(HAVE_LIBRRD, 1, [Define to 1 if you have the rrd library (-lrrd).])
-       ],
-       [with_rrdtool="no (librrd not found)"], [-lm])
+       SAVE_CFLAGS="$CFLAGS"
+       SAVE_LDFLAGS="$LDFLAGS"
+
+       CFLAGS="$CFLAGS $librrd_cflags"
+       LDFLAGS="$LDFLAGS $librrd_ldflags"
+
+       AC_CHECK_HEADERS(rrd.h,, [with_rrdtool="no (rrd.h not found)"])
+
+       CFLAGS="$SAVE_CFLAGS"
+       LDFLAGS="$SAVE_LDFLAGS"
 fi
 if test "x$with_rrdtool" = "xyes"
 then
-       AC_CHECK_HEADERS(rrd.h,, [with_rrdtool="no (rrd.h not found)"])
+       AC_CHECK_LIB(rrd_th, rrd_update_r,
+       [with_rrdtool="yes"
+        librrd_ldflags="$librrd_ldflags -lrrd_th -lm"
+       ],
+       [librrd_threadsafe="no"
+        AC_CHECK_LIB(rrd, rrd_update,
+        [with_rrdtool="yes"
+         librrd_ldflags="$librrd_ldflags -lrrd -lm"
+        ],
+        [with_rrdtool="no (symbol 'rrd_update' not found)"],
+        [-lm])
+       ]
+       [-lm])
 fi
 if test "x$with_rrdtool" = "xyes"
 then
-       collect_rrdtool=1
-else
-       collect_rrdtool=0
+       BUILD_WITH_LIBRRD_CFLAGS="$librrd_cflags"
+       BUILD_WITH_LIBRRD_LDFLAGS="$librrd_ldflags"
+       AC_SUBST(BUILD_WITH_LIBRRD_CFLAGS)
+       AC_SUBST(BUILD_WITH_LIBRRD_LDFLAGS)
+fi
+if test "x$librrd_threadsafe" = "xyes"
+then
+       AC_DEFINE(HAVE_THREADSAFE_LIBRRD, 1, [Define to 1 if you have the threadsafe rrd library (-lrrd_th).])
 fi
-AC_DEFINE_UNQUOTED(COLLECT_RRDTOOL, [$collect_rrdtool],
-       [Wether or not to use rrdtool library])
-AM_CONDITIONAL(BUILD_WITH_RRDTOOL, test "x$with_rrdtool" = "xyes")
 
 AC_ARG_WITH(libpthread, [AS_HELP_STRING([--with-libpthread=@<:@=PREFIX@:>@], [Path to libpthread.])],
 [      if test "x$withval" != "xno" -a "x$withval" != "xyes"
@@ -810,7 +753,7 @@ AC_DEFINE_UNQUOTED(HAVE_LIBPTHREAD, [$collect_pthread],
        [Wether or not to use pthread (POSIX threads) library])
 AM_CONDITIONAL(BUILD_WITH_LIBPTHREAD, test "x$with_libpthread" = "xyes")
 
-if test "$ac_system" = "Solaris"
+if test "x$ac_system" = "xSolaris"
 then
        with_kstat="yes"
        with_devinfo="yes"
@@ -849,13 +792,16 @@ AC_ARG_WITH(libcurl, [AS_HELP_STRING([--with-libcurl@<:@=PREFIX@:>@], [Path to l
        then
                with_libcurl="yes"
        else
-               if test -x "$withval"
+               if test -f "$withval" && test -x "$withval"
                then
                        with_curl_config="$withval"
+                       with_libcurl="yes"
                else if test -x "$withval/bin/curl-config"
                then
                        with_curl_config="$withval/bin/curl-config"
+                       with_libcurl="yes"
                fi; fi
+               with_libcurl="yes"
        fi; fi
 ],
 [
@@ -868,7 +814,7 @@ then
 
        if test $curl_config_status -ne 0
        then
-               with_libcurl="no"
+               with_libcurl="no ($with_curl_config failed)"
        else
                SAVE_CFLAGS=$CFLAGS
                CFLAGS="$CFLAGS $with_curl_cflags"
@@ -885,15 +831,10 @@ then
 
        if test $curl_config_status -ne 0
        then
-               with_libcurl="no"
+               with_libcurl="no ($with_curl_config failed)"
        else
                AC_CHECK_LIB(curl, curl_easy_init,
-                [
-                 # We need to do this to have `HAVE_LIBCURL' defined but
-                 # `-lcurl' NOT added to the default LDFLAGS.
-                       AC_DEFINE(HAVE_LIBCURL, 1,
-                                 [Define to 1 if you have the curl library.])
-                ],
+                [with_libcurl="yes"],
                 [with_libcurl="no (symbol 'curl_easy_init' not found)"],
                 [$with_curl_libs])
        fi
@@ -985,7 +926,7 @@ AC_ARG_WITH(lm-sensors, [AS_HELP_STRING([--with-lm-sensors@<:@=PREFIX@:>@], [Pat
        then
                with_lm_sensors="yes"
        else
-               with_lm_sensors="no"
+               with_lm_sensors="no (Linux only library)"
        fi
 ])
 if test "x$with_lm_sensors" = "xyes"
@@ -1026,13 +967,14 @@ AC_ARG_WITH(libmysql, [AS_HELP_STRING([--with-libmysql@<:@=PREFIX@:>@], [Path to
        then
                with_libmysql="yes"
        else
-               if test -x "$withval";
+               if test -f "$withval" && test -x "$withval";
                then
                        with_mysql_config="$withval"
                else if test -x "$withval/bin/mysql_config"
                then
                        with_mysql_config="$withval/bin/mysql_config"
                fi; fi
+               with_libmysql="yes"
        fi; fi
 ],
 [
@@ -1065,13 +1007,8 @@ then
                with_libmysql="no"
        else
                AC_CHECK_LIB(mysqlclient, mysql_init,
-                [
-                 # We need to do this to have `HAVE_LIBMYSQLCLIENT' defined
-                 # but `-lmysqlclient' NOT added to the default LDFLAGS.
-                       AC_DEFINE(HAVE_LIBMYSQLCLIENT, 1,
-                                 [Define to 1 if you have the mysqlclient library.])
-                ],
-                [with_libmysql="no (libmysql not found)"],
+                [with_libmysql="yes"],
+                [with_libmysql="no (symbol 'mysql_init' not found)"],
                 [$with_mysql_libs])
        fi
 fi
@@ -1179,10 +1116,6 @@ then
 fi
 AM_CONDITIONAL(BUILD_WITH_LIBOPING, test "x$with_liboping" = "xyes")
 AM_CONDITIONAL(BUILD_WITH_OWN_LIBOPING, test "x$with_own_liboping" = "xyes")
-if test "x$with_liboping" = "xyes" -a "x$with_own_liboping" = "xyes"
-then
-       with_liboping="yes (shipped version)"
-fi
 
 AC_ARG_WITH(libpcap, [AS_HELP_STRING([--with-libpcap@<:@=PREFIX@:>@], [Path to libpcap.])],
 [
@@ -1316,13 +1249,88 @@ else
 fi
 AM_CONDITIONAL(BUILD_WITH_LIBIPTC, test "x$with_libiptc" = "xyes")
 
-# TODO: Use `libupsclient-config' here.
+with_snmp_config="net-snmp-config"
+with_snmp_cflags=""
+with_snmp_libs=""
+AC_ARG_WITH(libnetsnmp, [AS_HELP_STRING([--with-libnetsnmp@<:@=PREFIX@:>@], [Path to the Net-SNMPD library.])],
+[
+       if test "x$withval" = "xno"
+       then
+               with_libnetsnmp="no"
+       else if "x$withval" = "xyes"
+       then
+               with_libnetsnmp="yes"
+       else
+               if test -x "$withval"
+               then
+                       with_snmp_config="$withval"
+                       with_libnetsnmp="yes"
+               else
+                       with_snmp_config="$withval/bin/net-snmp-config"
+                       with_libnetsnmp="yes"
+               fi
+       fi; fi
+],
+[with_libnetsnmp="yes"])
+if test "x$with_libnetsnmp" = "xyes"
+then
+       with_snmp_cflags=`$with_snmp_config --cflags 2>/dev/null`
+       snmp_config_status=$?
+
+       if test $snmp_config_status -ne 0
+       then
+               with_libnetsnmp="no ($with_snmp_config failed)"
+       else
+               SAVE_CFLAGS=$CFLAGS
+               CFLAGS="$CFLAGS $with_snmp_cflags"
+               
+               AC_CHECK_HEADERS(net-snmp/net-snmp-config.h, [], [with_libnetsnmp="no (net-snmp/net-snmp-config.h not found)"])
+
+               CFLAGS="$SAVE_CFLAGS"
+       fi
+fi
+if test "x$with_libnetsnmp" = "xyes"
+then
+       with_snmp_libs=`$with_snmp_config --libs 2>/dev/null`
+       snmp_config_status=$?
+
+       if test $snmp_config_status -ne 0
+       then
+               with_libnetsnmp="no ($with_snmp_config failed)"
+       else
+               AC_CHECK_LIB(netsnmp, init_snmp,
+               [with_libnetsnmp="yes"],
+               [with_libnetsnmp="no (libnetsnmp not found)"],
+               [$with_snmp_libs])
+       fi
+fi
+if test "x$with_libnetsnmp" = "xyes"
+then
+       BUILD_WITH_LIBSNMP_CFLAGS="$with_snmp_cflags"
+       BUILD_WITH_LIBSNMP_LIBS="$with_snmp_libs"
+       AC_SUBST(BUILD_WITH_LIBSNMP_CFLAGS)
+       AC_SUBST(BUILD_WITH_LIBSNMP_LIBS)
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBNETSNMP, test "x$with_libnetsnmp" = "xyes")
+
+with_upsclient_config="libupsclient-config"
+with_upsclient_cflags=""
+with_upsclient_libs=""
 AC_ARG_WITH(libupsclient, [AS_HELP_STRING([--with-libupsclient@<:@=PREFIX@:>@], [Path to libupsclient.])],
 [
-       if test "x$withval" != "xno" && test "x$withval" != "xyes"
+       if test "x$withval" = "xno"
        then
-               LDFLAGS="$LDFLAGS -L$withval/lib"
-               CPPFLAGS="$CPPFLAGS -I$withval/include"
+               with_libupsclient="no"
+       else
+               if test "x$withval" != "xyes"
+               then
+                       if test -f "$withval" && test -x "$withval";
+                       then
+                               with_upsclient_config="$withval"
+                       else
+                               with_upsclient_config="$withval/bin/libupsclient-config"
+                       fi
+               fi
                with_libupsclient="yes"
        fi
 ],
@@ -1331,17 +1339,45 @@ AC_ARG_WITH(libupsclient, [AS_HELP_STRING([--with-libupsclient@<:@=PREFIX@:>@],
 ])
 if test "x$with_libupsclient" = "xyes"
 then
-       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)"])
+       with_upsclient_cflags=`$with_upsclient_config --cflags 2>/dev/null`
+       upsclient_config_status=$?
+
+       if test $upsclient_config_status -ne 0
+       then
+               with_libupsclient="no ($with_upsclient_config failed)"
+       fi
+fi
+if test "x$with_libupsclient" = "xyes"
+then
+       SAVE_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS $with_upsclient_cflags"
+
+       AC_CHECK_HEADERS(upsclient.h, [], [with_libupsclient="no (upsclient.h not found)"])
+
+       CFLAGS="$SAVE_CFLAGS"
+fi
+if test "x$with_libupsclient" = "xyes"
+then
+       with_upsclient_libs=`$with_upsclient_config --libs 2>/dev/null`
+       upsclient_config_status=$?
+
+       if test $upsclient_config_status -ne 0
+       then
+               with_libupsclient="no ($with_upsclient_config failed)"
+       fi
 fi
 if test "x$with_libupsclient" = "xyes"
 then
-       AC_CHECK_HEADERS(upsclient.h,
+       AC_CHECK_LIB(upsclient, upscli_connect,
        [
-               AC_DEFINE(HAVE_UPSCLIENT_H, 1, [Define to 1 if you have the <upsclient.h> header file.])
-       ], [with_libupsclient="no (upsclient.h not found)"])
+               BUILD_WITH_LIBUPSCLIENT_CFLAGS="$with_upsclient_cflags"
+               BUILD_WITH_LIBUPSCLIENT_LIBS="$with_upsclient_libs"
+               AC_SUBST(BUILD_WITH_LIBUPSCLIENT_CFLAGS)
+               AC_SUBST(BUILD_WITH_LIBUPSCLIENT_LIBS)
+       ],
+       [
+               with_libupsclient="no (symbol 'upscli_connect' not found)"
+       ], [$with_upsclient_libs])
 fi
 if test "x$with_libupsclient" = "xyes"
 then
@@ -1352,6 +1388,179 @@ then
 fi
 AM_CONDITIONAL(BUILD_WITH_LIBUPSCLIENT, test "x$with_libupsclient" = "xyes")
 
+### BEGIN of check for libxmms ###
+with_xmms_config="xmms-config"
+with_xmms_cflags=""
+with_xmms_libs=""
+AC_ARG_WITH(libxmms, [AS_HELP_STRING([--with-libxmms@<:@=PREFIX@:>@], [Path to libxmms.])],
+[
+       if test "x$withval" != "xno" -a "x$withval" != "xyes"
+       then
+               if test -f "$withval" && test -x "$withval";
+               then
+                       with_xmms_config="$withval"
+               else if test -x "$withval/bin/xmms-config"
+               then
+                       with_xmms_config="$withval/bin/xmms-config"
+               fi; fi
+               with_libxmms="yes"
+       else if test "x$withval" = "xno"
+       then
+               with_libxmms="no"
+       else
+               with_libxmms="yes"
+       fi; fi
+],
+[
+       with_libxmms="yes"
+])
+if test "x$with_libxmms" = "xyes"
+then
+       with_xmms_cflags=`$with_xmms_config --cflags 2>/dev/null`
+       xmms_config_status=$?
+
+       if test $xmms_config_status -ne 0
+       then
+               with_libxmms="no"
+       fi
+fi
+if test "x$with_libxmms" = "xyes"
+then
+       with_xmms_libs=`$with_xmms_config --libs 2>/dev/null`
+       xmms_config_status=$?
+
+       if test $xmms_config_status -ne 0
+       then
+               with_libxmms="no"
+       fi
+fi
+if test "x$with_libxmms" = "xyes"
+then
+       AC_CHECK_LIB(xmms, xmms_remote_get_info,
+       [
+               BUILD_WITH_LIBXMMS_CFLAGS="$with_xmms_cflags"
+               BUILD_WITH_LIBXMMS_LIBS="$with_xmms_libs"
+               AC_SUBST(BUILD_WITH_LIBXMMS_CFLAGS)
+               AC_SUBST(BUILD_WITH_LIBXMMS_LIBS)
+       ],
+       [
+               with_libxmms="no"
+       ],
+       [$with_xmms_libs])
+fi
+with_libxmms_numeric=0
+if test "x$with_libxmms" = "xyes"
+then
+       with_libxmms_numeric=1
+fi
+AC_DEFINE_UNQUOTED(HAVE_LIBXMMS, [$with_libxmms_numeric], [Define to 1 if you have the 'xmms' library (-lxmms).])
+AM_CONDITIONAL(BUILD_WITH_LIBXMMS, test "x$with_libxmms" = "xyes")
+### END of check for libxmms ###
+
+with_libnetlink_cflags=""
+with_libnetlink_libs="-lnetlink"
+AC_ARG_WITH(libnetlink, [AS_HELP_STRING([--with-libnetlink@<:@=PREFIX@:>@], [Path to libnetlink.])],
+[
+ echo "libnetlink: withval = $withval"
+ if test "x$withval" = "xyes"
+ then
+        with_libnetlink="yes"
+ else if test "x$withval" = "xno"
+ then
+        with_libnetlink="no"
+ else
+        if test -d "$withval/include"
+        then
+                with_libnetlink_cflags="-I$withval/include"
+                with_libnetlink_libs="-L$withval/lib -lnetlink"
+                with_libnetlink="yes"
+        else
+                AC_MSG_ERROR("no such directory: $withval/include")
+        fi
+ fi; fi
+],
+[
+ if test "x$ac_system" = "xLinux"
+ then
+        with_libnetlink="yes"
+ else
+        with_libnetlink="no (Linux only library)"
+ fi
+])
+if test "x$with_libnetlink" = "xyes"
+then
+       SAVE_CFLAGS=$CFLAGS
+       CFLAGS="$CFLAGS $with_libnetlink_cflags"
+
+       with_libnetlink="no (libnetlink.h not found)"
+
+       AC_CHECK_HEADERS(libnetlink.h iproute/libnetlink.h linux/libnetlink.h,
+       [
+        with_libnetlink="yes"
+        break
+       ], [],
+[#include <stdio.h>
+#include <sys/types.h>
+#include <asm/types.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>])
+       AC_CHECK_HEADERS(linux/gen_stats.h linux/pkt_sched.h, [], [],
+[#include <stdio.h>
+#include <sys/types.h>
+#include <asm/types.h>
+#include <sys/socket.h>])
+
+       AC_COMPILE_IFELSE(
+[#include <stdio.h>
+#include <sys/types.h>
+#include <asm/types.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+int main (void)
+{
+       int retval = TCA_STATS2;
+       return (retval);
+}],
+       [AC_DEFINE([HAVE_TCA_STATS2], 1, [True if the enum-member TCA_STATS2 exists])]
+       []);
+
+       AC_COMPILE_IFELSE(
+[#include <stdio.h>
+#include <sys/types.h>
+#include <asm/types.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+int main (void)
+{
+       int retval = TCA_STATS;
+       return (retval);
+}],
+       [AC_DEFINE([HAVE_TCA_STATS], 1, [True if the enum-member TCA_STATS exists])]
+       []);
+
+       CFLAGS="$SAVE_CFLAGS"
+fi
+if test "x$with_libnetlink" = "xyes"
+then
+       AC_CHECK_LIB(netlink, rtnl_open,
+                    [with_libnetlink="yes"],
+                    [with_libnetlink="no (symbol 'rtnl_open' not found)"],
+                    [$with_libnetlink_libs])
+fi
+if test "x$with_libnetlink" = "xyes"
+then
+       BUILD_WITH_LIBNETLINK_CFLAGS="$with_libnetlink_cflags"
+       BUILD_WITH_LIBNETLINK_LIBS="$with_libnetlink_libs"
+       AC_SUBST(BUILD_WITH_LIBNETLINK_CFLAGS)
+       AC_SUBST(BUILD_WITH_LIBNETLINK_LIBS)
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBNETLINK, test "x$with_libnetlink" = "xyes")
+
 # Check for enabled/disabled features
 #
 
        ]dnl
 )# AC_COLLECTD(name, enable/disable, info-text, feature/module)
 
+# AC_PLUGIN(name, default, info)
+# ------------------------------------------------------------
+dnl
+AC_DEFUN(
+  [AC_PLUGIN],
+  [
+    enable_plugin="no"
+    AC_ARG_ENABLE([$1], AC_HELP_STRING([--enable-$1], [$3]),
+    [
+     if test "x$enableval" = "xyes"
+     then
+            enable_plugin="yes"
+     else
+            enable_plugin="no"
+     fi
+    ],
+    [
+     if test "x$2" = "xyes"
+     then
+            enable_plugin="yes"
+     else
+            enable_plugin="no"
+     fi
+    ])
+    if test "x$enable_plugin" = "xyes"
+    then
+           AC_DEFINE([HAVE_PLUGIN_]my_toupper([$1]), 1, [Define to 1 if the $1 plugin is enabled.])
+    fi
+    AM_CONDITIONAL([BUILD_PLUGIN_]my_toupper([$1]), test "x$enable_plugin" = "xyes")
+    enable_$1="$enable_plugin"
+  ]
+)# AC_PLUGIN(name, default, info)
+
 m4_divert_once([HELP_ENABLE], [
 collectd features:])
+# FIXME: Remove these calls to `AC_COLLECTD' and then remove that macro.
 AC_COLLECTD([debug],     [enable],  [feature], [debugging])
 AC_COLLECTD([daemon],    [disable], [feature], [daemon mode])
 AC_COLLECTD([getifaddrs],[enable],  [feature], [getifaddrs under Linux])
 
+plugin_battery="no"
+plugin_cpu="no"
+plugin_cpufreq="no"
+plugin_df="no"
+plugin_disk="no"
+plugin_entropy="no"
+plugin_interface="no"
+plugin_irq="no"
+plugin_load="no"
+plugin_memory="no"
+plugin_multimeter="no"
+plugin_nfs="no"
+plugin_processes="no"
+plugin_serial="no"
+plugin_swap="no"
+plugin_tape="no"
+plugin_users="no"
+plugin_vserver="no"
+plugin_wireless="no"
+
+# Linux
+if test "x$ac_system" = "xLinux"
+then
+       plugin_battery="yes"
+       plugin_cpu="yes"
+       plugin_cpufreq="yes"
+       plugin_disk="yes"
+       plugin_entropy="yes"
+       plugin_interface="yes"
+       plugin_irq="yes"
+       plugin_load="yes"
+       plugin_memory="yes"
+       plugin_nfs="yes"
+       plugin_processes="yes"
+       plugin_serial="yes"
+       plugin_swap="yes"
+       plugin_vserver="yes"
+       plugin_wireless="yes"
+fi
+
+# Mac OS X devices
+if test "x$with_libiokit" = "xyes"
+then
+       plugin_battery="yes"
+       plugin_disk="yes"
+fi
+
+# Solaris
+if test "x$with_devinfo$with_kstat" = "xyesyes"
+then
+       plugin_cpu="yes"
+       plugin_disk="yes"
+       plugin_interface="yes"
+       plugin_memory="yes"
+       plugin_swap="yes"
+       plugin_tape="yes"
+fi
+
+# libstatgrab
+if test "x$with_libstatgrab" = "xyes"
+then
+       plugin_interface="yes"
+       plugin_load="yes"
+       plugin_memory="yes"
+       plugin_swap="yes"
+fi
+
+if test "x$have_processor_info" = "xyes"
+then
+       plugin_cpu="yes"
+fi
+if test "x$have_sysctlbyname" = "xyes"
+then
+       plugin_cpu="yes"
+       plugin_memory="yes"
+fi
+
+if test "x$have_statfs" = "xyes"
+then
+       plugin_df="yes"
+fi
+if test "x$have_statvfs" = "xyes"
+then
+       plugin_df="yes"
+fi
+
+if test "x$have_getifaddrs" = "xyes"
+then
+       plugin_interface="yes"
+fi
+
+if test "x$have_getloadavg" = "xyes"
+then
+       plugin_load="yes"
+fi
+
+# Mac OS X memory interface
+if test "x$have_host_statistics" = "xyes"
+then
+       plugin_memory="yes"
+fi
+
+if test "x$have_termios_h" = "xyes"
+then
+       plugin_multimeter="yes"
+fi
+
+if test "x$have_thread_info" = "xyes"
+then
+       plugin_processes="yes"
+fi
+
+if test "x$with_libkvm" = "xyes"
+then
+       plugin_swap="yes"
+fi
+
+if test "x$have_getutent" = "xyes"
+then
+       plugin_users="yes"
+fi
+if test "x$have_getutxent" = "xyes"
+then
+       plugin_users="yes"
+fi
+
+# FIXME: sysctl for swap plugin
+
 m4_divert_once([HELP_ENABLE], [
-collectd modules:])
-AC_COLLECTD([apache],    [disable], [module], [Apache httpd statistics])
-AC_COLLECTD([apcups],    [disable], [module], [Statistics of UPSes by APC])
-AC_COLLECTD([apple_sensors], [disable], [module], [Apple's hardware sensors])
-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([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])
-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([perl],      [disable], [module], [embedded perl interpreter])
-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([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])
+collectd plugins:])
+
+AC_PLUGIN([apache],      [$with_libcurl],      [Apache httpd statistics])
+AC_PLUGIN([apcups],      [yes],                [Statistics of UPSes by APC])
+AC_PLUGIN([apple_sensors], [$with_libiokit],   [Apple's hardware sensors])
+AC_PLUGIN([battery],     [$plugin_battery],    [Battery statistics])
+AC_PLUGIN([cpu],         [$plugin_cpu],        [CPU usage statistics])
+AC_PLUGIN([cpufreq],     [$plugin_cpufreq],    [CPU frequency statistics])
+AC_PLUGIN([csv],         [yes],                [CSV output plugin])
+AC_PLUGIN([df],          [$plugin_df],         [Filesystem usage statistics])
+AC_PLUGIN([disk],        [$plugin_disk],       [Disk usage statistics])
+AC_PLUGIN([dns],         [$with_libpcap],      [DNS traffic analysis])
+AC_PLUGIN([email],       [yes],                [EMail statistics])
+AC_PLUGIN([entropy],     [$plugin_entropy],    [Entropy statistics])
+AC_PLUGIN([exec],        [yes],                [Execution of external programs])
+AC_PLUGIN([hddtemp],     [yes],                [Query hddtempd])
+AC_PLUGIN([interface],   [$plugin_interface],  [Interface traffic statistics])
+AC_PLUGIN([iptables],    [$with_libiptc],      [IPTables rule counters])
+AC_PLUGIN([irq],         [$plugin_irq],        [IRQ statistics])
+AC_PLUGIN([load],        [$plugin_load],       [System load])
+AC_PLUGIN([logfile],     [yes],                [File logging plugin])
+AC_PLUGIN([mbmon],       [yes],                [Query mbmond])
+AC_PLUGIN([memory],      [$plugin_memory],     [Memory usage])
+AC_PLUGIN([multimeter],  [$plugin_multimeter], [Read multimeter values])
+AC_PLUGIN([mysql],       [$with_libmysql],     [MySQL statistics])
+AC_PLUGIN([netlink],     [$with_libnetlink],   [Enhanced Linux network statistics])
+AC_PLUGIN([network],     [yes],                [Network communication plugin])
+AC_PLUGIN([nfs],         [$plugin_nfs],        [NFS statistics])
+AC_PLUGIN([ntpd],        [yes],                [NTPd statistics])
+AC_PLUGIN([nut],         [$with_libupsclient], [Network UPS tools statistics])
+AC_PLUGIN([perl],        [$with_libperl],      [Embed a Perl interpreter])
+AC_PLUGIN([ping],        [$with_liboping],     [Network latency statistics])
+AC_PLUGIN([processes],   [$plugin_processes],  [Process statistics])
+AC_PLUGIN([rrdtool],     [$with_rrdtool],      [RRDTool output plugin])
+AC_PLUGIN([sensors],     [$with_lm_sensors],   [lm_sensors statistics])
+AC_PLUGIN([serial],      [$plugin_serial],     [serial port traffic])
+AC_PLUGIN([snmp],        [$with_libnetsnmp],   [SNMP querying plugin])
+AC_PLUGIN([swap],        [$plugin_swap],       [Swap usage statistics])
+AC_PLUGIN([syslog],      [$have_syslog],       [Syslog logging plugin])
+AC_PLUGIN([tape],        [$plugin_tape],       [Tape drive statistics])
+AC_PLUGIN([unixsock],    [yes],                [Unixsock communication plugin])
+AC_PLUGIN([users],       [$plugin_users],      [User statistics])
+AC_PLUGIN([vserver],     [$plugin_vserver],    [Linux VServer statistics])
+AC_PLUGIN([wireless],    [$plugin_wireless],   [Wireless statistics])
+AC_PLUGIN([xmms],        [$with_libxmms],      [XMMS statistics])
 
 AC_OUTPUT(Makefile src/Makefile src/collectd.conf src/liboconfig/Makefile src/liboping/Makefile)
 
+if test "x$with_liboping" = "xyes" -a "x$with_own_liboping" = "xyes"
+then
+       with_liboping="yes (shipped version)"
+fi
+
 if test "x$with_libperl" = "xyes"
 then
        with_libperl="yes (version `perl -MConfig -e 'print $Config{version};'`)"
@@ -1480,7 +1861,10 @@ Configuration:
     libiokit  . . . . . $with_libiokit
     libiptc . . . . . . $with_libiptc
     libkstat  . . . . . $with_kstat
+    libkvm  . . . . . . $with_libkvm
     libmysql  . . . . . $with_libmysql
+    libnetlink  . . . . $with_libnetlink
+    libnetsnmp  . . . . $with_libnetsnmp
     liboconfig  . . . . $with_liboconfig
     liboping  . . . . . $with_liboping
     libpcap . . . . . . $with_libpcap
@@ -1490,6 +1874,7 @@ Configuration:
     libsensors  . . . . $with_lm_sensors
     libstatgrab . . . . $with_libstatgrab
     libupsclient  . . . $with_libupsclient
+    libxmms . . . . . . $with_libxmms
 
   Features:
     daemon mode . . . . $enable_daemon
@@ -1519,6 +1904,7 @@ Configuration:
     memory  . . . . . . $enable_memory
     multimeter  . . . . $enable_multimeter
     mysql . . . . . . . $enable_mysql
+    netlink . . . . . . $enable_netlink
     network . . . . . . $enable_network
     nfs . . . . . . . . $enable_nfs
     ntpd  . . . . . . . $enable_ntpd
@@ -1528,6 +1914,7 @@ Configuration:
     processes . . . . . $enable_processes
     sensors . . . . . . $enable_sensors
     serial  . . . . . . $enable_serial
+    snmp  . . . . . . . $enable_snmp
     swap  . . . . . . . $enable_swap
     syslog  . . . . . . $enable_syslog
     tape  . . . . . . . $enable_tape
@@ -1535,5 +1922,6 @@ Configuration:
     users . . . . . . . $enable_users
     vserver . . . . . . $enable_vserver
     wireless  . . . . . $enable_wireless
+    xmms  . . . . . . . $enable_xmms
 
 EOF
index 61dd1b5..0c6c6c8 100644 (file)
@@ -44,7 +44,7 @@ our %EXPORT_TAGS = (
 
 Exporter::export_ok_tags('all');
 
-bootstrap Collectd "4.0.9";
+bootstrap Collectd "4.1.2";
 
 1;
 
index 92e8772..3b8a91c 100644 (file)
@@ -83,6 +83,33 @@ sub _create_identifier
        return ("$host/$plugin/$type");
 } # _create_identifier
 
+sub _parse_identifier
+{
+       my $string = shift;
+       my $host;
+       my $plugin;
+       my $plugin_instance;
+       my $type;
+       my $type_instance;
+       my $ident;
+
+       ($host, $plugin, $type) = split ('/', $string);
+
+       ($plugin, $plugin_instance) = split ('-', $plugin, 2);
+       ($type, $type_instance) = split ('-', $type, 2);
+
+       $ident =
+       {
+               host => $host,
+               plugin => $plugin,
+               type => $type
+       };
+       $ident->{'plugin_instance'} = $plugin_instance if (defined ($plugin_instance));
+       $ident->{'type_instance'} = $type_instance if (defined ($type_instance));
+
+       return ($ident);
+} # _parse_identifier
+
 =head1 PUBLIC METHODS
 
 =over 4
@@ -217,6 +244,52 @@ sub putval
        return;
 } # putval
 
+=item I<$res> = I<$obj>-E<gt>B<listval> ()
+
+Queries a list of values from the daemon. The list is returned as an array of
+hash references, where each hash reference is a valid identifier. The C<time>
+member of each hash holds the epoch value of the last update of that value.
+
+=cut
+
+sub listval
+{
+       my $obj = shift;
+       my $msg;
+       my @ret = ();
+       my $status;
+       my $fh = $obj->{'sock'} or confess;
+
+       $msg = "LISTVAL\n";
+       send ($fh, $msg, 0) or confess ("send: $!");
+
+       $msg = <$fh>;
+       ($status, $msg) = split (' ', $msg, 2);
+       if ($status < 0)
+       {
+               $obj->{'error'} = $msg;
+               return;
+       }
+
+       for (my $i = 0; $i < $status; $i++)
+       {
+               my $time;
+               my $ident;
+
+               $msg = <$fh>;
+               chomp ($msg);
+
+               ($time, $ident) = split (' ', $msg, 2);
+
+               $ident = _parse_identifier ($ident);
+               $ident->{'time'} = int ($time);
+
+               push (@ret, $ident);
+       } # for (i = 0 .. $status)
+
+       return (@ret);
+} # listval
+
 =item I<$obj>-E<gt>destroy ();
 
 Closes the socket before the object is destroyed. This function is also
index 467ecb3..685903b 100644 (file)
@@ -24,8 +24,19 @@ several PNG files which are graphs of the RRD files found.
 
 collection.cgi
 --------------
-  Sample CGI script that creates graphs on the fly. The Perl module `RRDs' is
-needed (Debian package `librrds-perl').
+  Sample CGI script that creates graphs on the fly. The Perl modules `RRDs'
+(Debian package `librrds-perl'), `URI:Escape' (package liburi-perl),
+`HTML::Entities' (package libhtml-parser-perl) and a CGI capable web server
+(e.g. apache2 or boa) are needed. Simply install the script to a place where
+the webserver will treat it as a CGI script (/usr/lib/cgi-bin/ by default) and
+visit that page in a browser (http://localhost/cgi-bin/collection.cgi by
+default). Please refer to your webserver's documentation for more details.
+
+  Starting with version 4, collection.cgi requires a small config file, which
+should look something like this:
+
+  datadir: "/var/lib/collectd/rrd/"
+  libdir: "/usr/lib/collectd/"
 
 extractDS.px
 ------------
index c76c44d..1edcfc6 100644 (file)
@@ -18,7 +18,7 @@ add a loadplugin call into your init.pre file.
 
 =over 4
 
-=item collectd_socket [ socket path ]      (default: /tmp/.collectd-email)
+=item collectd_socket [ socket path ]      (default: /var/run/collectd-email)
 
 Where the collectd socket is
 
@@ -116,7 +116,7 @@ sub set_config {
 
     push (@cmds, {
            setting => 'collectd_socket', 
-           default => '/tmp/.collectd-email',
+           default => '/var/run/collectd-email',
            type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING,
     });
 
index 0abfb49..7ffd708 100644 (file)
@@ -1,5 +1,5 @@
 collectd_buffersize 256
-collectd_socket /tmp/.collectd-email
+collectd_socket /var/run/collectd-email
 collectd_timeout 2
 collectd_retries 3 
 
diff --git a/contrib/collection.conf b/contrib/collection.conf
new file mode 100644 (file)
index 0000000..e8444f5
--- /dev/null
@@ -0,0 +1,3 @@
+datadir: "/opt/collectd/var/lib/collectd/rrd/"
+libdir: "/opt/collectd/lib/collectd/"
+
diff --git a/contrib/cussh.pl b/contrib/cussh.pl
new file mode 100755 (executable)
index 0000000..65c634e
--- /dev/null
@@ -0,0 +1,185 @@
+#!/usr/bin/perl
+#
+# collectd - contrib/cussh.pl
+# 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
+#
+# Author:
+#   Sebastian Harl <sh at tokkee.org>
+#
+
+=head1 NAME
+
+cussh - collectd UNIX socket shell
+
+=head1 SYNOPSIS
+
+B<cussh> [I<E<lt>pathE<gt>>]
+
+=head1 DESCRIPTION
+
+B<collectd>'s unixsock plugin allows external programs to access the values it
+has collected or received and to submit own values. This is a little
+interactive frontend for this plugin.
+
+=head1 OPTIONS
+
+=over 4
+
+=item I<E<lt>pathE<gt>>
+
+The path to the UNIX socket provided by collectd's unixsock plugin. (Default:
+F</var/run/collectd-unixsock>)
+
+=back
+
+=cut
+
+use strict;
+use warnings;
+
+use Collectd::Unixsock();
+
+{ # main
+       my $path = $ARGV[0] || "/var/run/collectd-unixsock";
+       my $sock = Collectd::Unixsock->new($path);
+
+       if (! $sock) {
+               print STDERR "Unable to connect to $path!\n";
+               exit 1;
+       }
+
+       print "cussh version 0.1, Copyright (C) 2007 Sebastian Harl\n"
+               . "cussh comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
+               . "and you are welcome to redistribute it under certain conditions.\n"
+               . "See the GNU General Public License 2 for more details.\n\n";
+
+       while (1) {
+               print "cussh> ";
+               my $line = <STDIN>;
+
+               last if ((! $line) || ($line =~ m/^quit$/i));
+
+               my ($cmd) = $line =~ m/^(\w+)\s+/;
+               $line = $';
+
+               next if (! $cmd);
+               $cmd = uc $cmd;
+
+               my $f = undef;
+               if ($cmd eq "PUTVAL") {
+                       $f = \&putval;
+               }
+               elsif ($cmd eq "GETVAL") {
+                       $f = \&getval;
+               }
+               else {
+                       print STDERR "ERROR: Unknown command $cmd!\n";
+                       next;
+               }
+
+               if (! $f->($sock, $line)) {
+                       print STDERR "ERROR: Command failed!\n";
+                       next;
+               }
+       }
+
+       $sock->destroy();
+       exit 0;
+}
+
+sub getid {
+       my $string = shift || return;
+
+       print $$string . $/;
+       my ($h, $p, $pi, $t, $ti) =
+               $$string =~ m/^(\w+)\/(\w+)(?:-(\w+))?\/(\w+)(?:-(\w+))?\s+/;
+       $$string = $';
+
+       return if ((! $h) || (! $p) || (! $t));
+
+       my %id = ();
+
+       ($id{'host'}, $id{'plugin'}, $id{'type'}) = ($h, $p, $t);
+
+       $id{'plugin_instance'} = $pi if ($pi);
+       $id{'type_instance'} = $ti if ($ti);
+       return \%id;
+}
+
+=head1 COMMANDS
+
+=over 4
+
+=item B<GETVAL> I<Identifier>
+
+=item B<PUTVAL> I<Identifier> I<Valuelist>
+
+These commands follow the exact same syntax as described in
+L<collectd-unixsock(5)>.
+
+=cut
+
+sub putval {
+       my $sock = shift || return;
+       my $line = shift || return;
+
+       my $id = getid(\$line);
+
+       return if (! $id);
+
+       my ($time, @values) = split m/:/, $line;
+       return $sock->putval(%$id, $time, \@values);
+}
+
+sub getval {
+       my $sock = shift || return;
+       my $line = shift || return;
+
+       my $id = getid(\$line);
+
+       return if (! $id);
+
+       my $vals = $sock->getval(%$id);
+
+       return if (! $vals);
+
+       foreach my $key (keys %$vals) {
+               print "\t$key: $vals->{$key}\n";
+       }
+       return 1;
+}
+
+=head1 SEE ALSO
+
+L<collectd(1)>, L<collectd-unisock(5)>
+
+=head1 AUTHOR
+
+Written by Sebastian Harl E<lt>sh@tokkee.orgE<gt>.
+
+B<collectd> has been written by Florian Forster and others.
+
+=head1 COPYRIGHT
+
+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.
+
+=cut
+
+# vim: set sw=4 ts=4 tw=78 noexpandtab :
index ab4d46a..9818580 100644 (file)
@@ -25,6 +25,7 @@ collectd_SOURCES = collectd.c collectd.h \
 collectd_CPPFLAGS = $(LTDLINCL)
 collectd_CPPFLAGS += -DPREFIX='"${prefix}"'
 collectd_CPPFLAGS += -DCONFIGFILE='"${sysconfdir}/${PACKAGE_NAME}.conf"'
+collectd_CPPFLAGS += -DLOCALSTATEDIR='"${localstatedir}"'
 collectd_CPPFLAGS += -DPKGLOCALSTATEDIR='"${localstatedir}/lib/${PACKAGE_NAME}"'
 if BUILD_FEATURE_DAEMON
 collectd_CPPFLAGS += -DPIDFILE='"${localstatedir}/run/${PACKAGE_NAME}.pid"'
@@ -80,7 +81,7 @@ endif
 
 pkglib_LTLIBRARIES = 
 
-if BUILD_MODULE_APACHE
+if BUILD_PLUGIN_APACHE
 pkglib_LTLIBRARIES += apache.la
 apache_la_SOURCES = apache.c
 apache_la_LDFLAGS = -module -avoid-version
@@ -94,7 +95,7 @@ endif
 collectd_DEPENDENCIES += apache.la
 endif
 
-if BUILD_MODULE_APCUPS
+if BUILD_PLUGIN_APCUPS
 pkglib_LTLIBRARIES += apcups.la
 apcups_la_SOURCES = apcups.c
 apcups_la_LDFLAGS = -module -avoid-version
@@ -105,18 +106,15 @@ collectd_LDADD += "-dlopen" apcups.la
 collectd_DEPENDENCIES += apcups.la
 endif
 
-if BUILD_MODULE_APPLE_SENSORS
+if BUILD_PLUGIN_APPLE_SENSORS
 pkglib_LTLIBRARIES += apple_sensors.la
 apple_sensors_la_SOURCES = apple_sensors.c
-apple_sensors_la_LDFLAGS = -module -avoid-version
-if BUILD_WITH_LIBIOKIT
-apple_sensors_la_LDFLAGS += -lIOKit
-endif
+apple_sensors_la_LDFLAGS = -module -avoid-version -lIOKit
 collectd_LDADD += "-dlopen" apple_sensors.la
 collectd_DEPENDENCIES += apple_sensors.la
 endif
 
-if BUILD_MODULE_BATTERY
+if BUILD_PLUGIN_BATTERY
 pkglib_LTLIBRARIES += battery.la
 battery_la_SOURCES = battery.c
 battery_la_LDFLAGS = -module -avoid-version
@@ -127,7 +125,7 @@ collectd_LDADD += "-dlopen" battery.la
 collectd_DEPENDENCIES += battery.la
 endif
 
-if BUILD_MODULE_CPU
+if BUILD_PLUGIN_CPU
 pkglib_LTLIBRARIES += cpu.la
 cpu_la_SOURCES = cpu.c
 cpu_la_LDFLAGS = -module -avoid-version
@@ -141,7 +139,7 @@ collectd_LDADD += "-dlopen" cpu.la
 collectd_DEPENDENCIES += cpu.la
 endif
 
-if BUILD_MODULE_CPUFREQ
+if BUILD_PLUGIN_CPUFREQ
 pkglib_LTLIBRARIES += cpufreq.la
 cpufreq_la_SOURCES = cpufreq.c
 cpufreq_la_LDFLAGS = -module -avoid-version
@@ -149,7 +147,7 @@ collectd_LDADD += "-dlopen" cpufreq.la
 collectd_DEPENDENCIES += cpufreq.la
 endif
 
-if BUILD_MODULE_CSV
+if BUILD_PLUGIN_CSV
 pkglib_LTLIBRARIES += csv.la
 csv_la_SOURCES = csv.c
 csv_la_LDFLAGS = -module -avoid-version
@@ -157,7 +155,7 @@ collectd_LDADD += "-dlopen" csv.la
 collectd_DEPENDENCIES += csv.la
 endif
 
-if BUILD_MODULE_DF
+if BUILD_PLUGIN_DF
 pkglib_LTLIBRARIES += df.la
 df_la_SOURCES = df.c
 df_la_LDFLAGS = -module -avoid-version
@@ -165,7 +163,7 @@ collectd_LDADD += "-dlopen" df.la
 collectd_DEPENDENCIES += df.la
 endif
 
-if BUILD_MODULE_DISK
+if BUILD_PLUGIN_DISK
 pkglib_LTLIBRARIES += disk.la
 disk_la_SOURCES = disk.c
 disk_la_LDFLAGS = -module -avoid-version
@@ -182,26 +180,15 @@ collectd_LDADD += "-dlopen" disk.la
 collectd_DEPENDENCIES += disk.la
 endif
 
-if BUILD_MODULE_DNS
+if BUILD_PLUGIN_DNS
 pkglib_LTLIBRARIES += dns.la
-dns_la_SOURCES = dns.c
-if BUILD_WITH_LIBPCAP
-if BUILD_WITH_LIBPTHREAD
-dns_la_SOURCES += utils_dns.c utils_dns.h
-endif
-endif
-dns_la_LDFLAGS = -module -avoid-version
-if BUILD_WITH_LIBPCAP
-dns_la_LDFLAGS += -lpcap
-endif
-if BUILD_WITH_LIBPTHREAD
-dns_la_LDFLAGS += -lpthread
-endif
+dns_la_SOURCES = dns.c utils_dns.c utils_dns.h
+dns_la_LDFLAGS = -module -avoid-version -lpcap -lpthread
 collectd_LDADD += "-dlopen" dns.la
 collectd_DEPENDENCIES += dns.la
 endif
 
-if BUILD_MODULE_EMAIL
+if BUILD_PLUGIN_EMAIL
 pkglib_LTLIBRARIES += email.la
 email_la_SOURCES = email.c
 email_la_LDFLAGS = -module -avoid-version
@@ -212,7 +199,7 @@ collectd_LDADD += "-dlopen" email.la
 collectd_DEPENDENCIES += email.la
 endif
 
-if BUILD_MODULE_ENTROPY
+if BUILD_PLUGIN_ENTROPY
 pkglib_LTLIBRARIES += entropy.la
 entropy_la_SOURCES = entropy.c
 entropy_la_LDFLAGS = -module -avoid-version
@@ -220,9 +207,9 @@ collectd_LDADD += "-dlopen" entropy.la
 collectd_DEPENDENCIES += entropy.la
 endif
 
-if BUILD_MODULE_EXEC
+if BUILD_PLUGIN_EXEC
 pkglib_LTLIBRARIES += exec.la
-exec_la_SOURCES = exec.c
+exec_la_SOURCES = exec.c utils_cmd_putval.c utils_cmd_putval.h
 exec_la_LDFLAGS = -module -avoid-version
 if BUILD_WITH_LIBPTHREAD
 exec_la_LDFLAGS += -lpthread
@@ -231,7 +218,7 @@ collectd_LDADD += "-dlopen" exec.la
 collectd_DEPENDENCIES += exec.la
 endif
 
-if BUILD_MODULE_HDDTEMP
+if BUILD_PLUGIN_HDDTEMP
 pkglib_LTLIBRARIES += hddtemp.la
 hddtemp_la_SOURCES = hddtemp.c
 hddtemp_la_LDFLAGS = -module -avoid-version
@@ -242,7 +229,7 @@ collectd_LDADD += "-dlopen" hddtemp.la
 collectd_DEPENDENCIES += hddtemp.la
 endif
 
-if BUILD_MODULE_INTERFACE
+if BUILD_PLUGIN_INTERFACE
 pkglib_LTLIBRARIES += interface.la
 interface_la_SOURCES = interface.c
 interface_la_LDFLAGS = -module -avoid-version
@@ -265,18 +252,15 @@ interface_la_LDFLAGS += -lstatgrab
 endif
 endif
 
-if BUILD_MODULE_IPTABLES
+if BUILD_PLUGIN_IPTABLES
 pkglib_LTLIBRARIES += iptables.la
 iptables_la_SOURCES = iptables.c
-iptables_la_LDFLAGS = -module -avoid-version
-if BUILD_WITH_LIBIPTC
-iptables_la_LDFLAGS += -liptc
-endif
+iptables_la_LDFLAGS = -module -avoid-version -liptc
 collectd_LDADD += "-dlopen" iptables.la
 collectd_DEPENDENCIES += iptables.la
 endif
 
-if BUILD_MODULE_IRQ
+if BUILD_PLUGIN_IRQ
 pkglib_LTLIBRARIES += irq.la
 irq_la_SOURCES = irq.c
 irq_la_LDFLAGS = -module -avoid-version
@@ -284,7 +268,7 @@ collectd_LDADD += "-dlopen" irq.la
 collectd_DEPENDENCIES += irq.la
 endif
 
-if BUILD_MODULE_LOAD
+if BUILD_PLUGIN_LOAD
 pkglib_LTLIBRARIES += load.la
 load_la_SOURCES = load.c
 load_la_LDFLAGS = -module -avoid-version
@@ -301,7 +285,7 @@ load_la_LDFLAGS += -lstatgrab
 endif
 endif
 
-if BUILD_MODULE_LOGFILE
+if BUILD_PLUGIN_LOGFILE
 pkglib_LTLIBRARIES += logfile.la
 logfile_la_SOURCES = logfile.c
 logfile_la_LDFLAGS = -module -avoid-version
@@ -309,7 +293,7 @@ collectd_LDADD += "-dlopen" logfile.la
 collectd_DEPENDENCIES += logfile.la
 endif
 
-if BUILD_MODULE_MBMON
+if BUILD_PLUGIN_MBMON
 pkglib_LTLIBRARIES += mbmon.la
 mbmon_la_SOURCES = mbmon.c
 mbmon_la_LDFLAGS = -module -avoid-version
@@ -320,7 +304,7 @@ collectd_LDADD += "-dlopen" mbmon.la
 collectd_DEPENDENCIES += mbmon.la
 endif
 
-if BUILD_MODULE_MEMORY
+if BUILD_PLUGIN_MEMORY
 pkglib_LTLIBRARIES += memory.la
 memory_la_SOURCES = memory.c
 memory_la_LDFLAGS = -module -avoid-version
@@ -343,7 +327,7 @@ memory_la_LDFLAGS += -lstatgrab
 endif
 endif
 
-if BUILD_MODULE_MULTIMETER
+if BUILD_PLUGIN_MULTIMETER
 pkglib_LTLIBRARIES += multimeter.la
 multimeter_la_SOURCES = multimeter.c
 multimeter_la_LDFLAGS = -module -avoid-version
@@ -351,7 +335,7 @@ collectd_LDADD += "-dlopen" multimeter.la
 collectd_DEPENDENCIES += multimeter.la
 endif
 
-if BUILD_MODULE_MYSQL
+if BUILD_PLUGIN_MYSQL
 pkglib_LTLIBRARIES += mysql.la
 mysql_la_SOURCES = mysql.c
 mysql_la_LDFLAGS = -module -avoid-version
@@ -365,7 +349,17 @@ endif
 collectd_DEPENDENCIES += mysql.la
 endif
 
-if BUILD_MODULE_NETWORK
+if BUILD_PLUGIN_NETLINK
+pkglib_LTLIBRARIES += netlink.la
+netlink_la_SOURCES = netlink.c
+netlink_la_LDFLAGS = -module -avoid-version
+netlink_la_CFLAGS = $(BUILD_WITH_LIBNETLINK_CFLAGS)
+netlink_la_LIBADD = $(BUILD_WITH_LIBNETLINK_LIBS)
+collectd_LDADD += "-dlopen" netlink.la
+collectd_DEPENDENCIES += netlink.la
+endif
+
+if BUILD_PLUGIN_NETWORK
 pkglib_LTLIBRARIES += network.la
 network_la_SOURCES = network.c network.h
 network_la_LDFLAGS = -module -avoid-version
@@ -379,7 +373,7 @@ collectd_LDADD += "-dlopen" network.la
 collectd_DEPENDENCIES += network.la
 endif
 
-if BUILD_MODULE_NFS
+if BUILD_PLUGIN_NFS
 pkglib_LTLIBRARIES += nfs.la
 nfs_la_SOURCES = nfs.c
 nfs_la_LDFLAGS = -module -avoid-version
@@ -387,7 +381,7 @@ collectd_LDADD += "-dlopen" nfs.la
 collectd_DEPENDENCIES += nfs.la
 endif
 
-if BUILD_MODULE_NTPD
+if BUILD_PLUGIN_NTPD
 pkglib_LTLIBRARIES += ntpd.la
 ntpd_la_SOURCES = ntpd.c
 ntpd_la_LDFLAGS = -module -avoid-version
@@ -398,22 +392,16 @@ collectd_LDADD += "-dlopen" ntpd.la
 collectd_DEPENDENCIES += ntpd.la
 endif
 
-if BUILD_MODULE_NUT
+if BUILD_PLUGIN_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
+nut_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBUPSCLIENT_CFLAGS)
+nut_la_LDFLAGS = -module -avoid-version -lpthread $(BUILD_WITH_LIBUPSCLIENT_LIBS)
 collectd_LDADD += "-dlopen" nut.la
 collectd_DEPENDENCIES += nut.la
 endif
 
-if BUILD_WITH_LIBPERL
-if BUILD_MODULE_PERL
+if BUILD_PLUGIN_PERL
 pkglib_LTLIBRARIES += perl.la
 perl_la_SOURCES = perl.c
 perl_la_CFLAGS  = $(AM_CFLAGS) \
@@ -424,25 +412,22 @@ perl_la_LDFLAGS = -module -avoid-version \
 collectd_LDADD += "-dlopen" perl.la
 collectd_DEPENDENCIES += perl.la
 endif
-endif
 
-if BUILD_MODULE_PING
+if BUILD_PLUGIN_PING
 pkglib_LTLIBRARIES += ping.la
 ping_la_SOURCES = ping.c
 ping_la_LDFLAGS = -module -avoid-version
-if BUILD_WITH_LIBOPING
 if BUILD_WITH_OWN_LIBOPING
 ping_la_LIBADD  = liboping/liboping.la
 ping_la_DEPENDENCIES = liboping/liboping.la
 else
 ping_la_LDFLAGS += -loping
 endif
-endif
 collectd_LDADD += "-dlopen" ping.la
 collectd_DEPENDENCIES += ping.la
 endif
 
-if BUILD_MODULE_PROCESSES
+if BUILD_PLUGIN_PROCESSES
 pkglib_LTLIBRARIES += processes.la
 processes_la_SOURCES = processes.c
 processes_la_LDFLAGS = -module -avoid-version
@@ -450,15 +435,17 @@ collectd_LDADD += "-dlopen" processes.la
 collectd_DEPENDENCIES += processes.la
 endif
 
-if BUILD_WITH_RRDTOOL
+if BUILD_PLUGIN_RRDTOOL
 pkglib_LTLIBRARIES += rrdtool.la
 rrdtool_la_SOURCES = rrdtool.c
-rrdtool_la_LDFLAGS = -module -avoid-version -lrrd
+rrdtool_la_LDFLAGS = -module -avoid-version
+rrdtool_la_CFLAGS = $(BUILD_WITH_LIBRRD_CFLAGS)
+rrdtool_la_LIBADD = $(BUILD_WITH_LIBRRD_LDFLAGS)
 collectd_LDADD += "-dlopen" rrdtool.la
 collectd_DEPENDENCIES += rrdtool.la
 endif
 
-if BUILD_MODULE_SENSORS
+if BUILD_PLUGIN_SENSORS
 pkglib_LTLIBRARIES += sensors.la
 sensors_la_SOURCES = sensors.c
 sensors_la_LDFLAGS = -module -avoid-version
@@ -469,7 +456,7 @@ collectd_LDADD += "-dlopen" sensors.la
 collectd_DEPENDENCIES += sensors.la
 endif
 
-if BUILD_MODULE_SERIAL
+if BUILD_PLUGIN_SERIAL
 pkglib_LTLIBRARIES += serial.la
 serial_la_SOURCES = serial.c
 serial_la_LDFLAGS = -module -avoid-version
@@ -477,7 +464,24 @@ collectd_LDADD += "-dlopen" serial.la
 collectd_DEPENDENCIES += serial.la
 endif
 
-if BUILD_MODULE_SWAP
+if BUILD_PLUGIN_SNMP
+pkglib_LTLIBRARIES += snmp.la
+snmp_la_SOURCES = snmp.c
+snmp_la_LDFLAGS = -module -avoid-version
+snmp_la_CFLAGS =
+snmp_la_LIBADD =
+if BUILD_WITH_LIBNETSNMP
+snmp_la_CFLAGS += $(BUILD_WITH_LIBSNMP_CFLAGS)
+snmp_la_LIBADD += $(BUILD_WITH_LIBSNMP_LIBS)
+endif
+if BUILD_WITH_LIBPTHREAD
+snmp_la_LIBADD += -lpthread
+endif
+collectd_LDADD += "-dlopen" snmp.la
+collectd_DEPENDENCIES += snmp.la
+endif
+
+if BUILD_PLUGIN_SWAP
 pkglib_LTLIBRARIES += swap.la
 swap_la_SOURCES = swap.c
 swap_la_LDFLAGS = -module -avoid-version
@@ -500,7 +504,7 @@ swap_la_LDFLAGS += -lstatgrab
 endif
 endif
 
-if BUILD_MODULE_SYSLOG
+if BUILD_PLUGIN_SYSLOG
 pkglib_LTLIBRARIES += syslog.la
 syslog_la_SOURCES = syslog.c
 syslog_la_LDFLAGS = -module -avoid-version
@@ -508,30 +512,24 @@ collectd_LDADD += "-dlopen" syslog.la
 collectd_DEPENDENCIES += syslog.la
 endif
 
-if BUILD_MODULE_TAPE
+if BUILD_PLUGIN_TAPE
 pkglib_LTLIBRARIES += tape.la
 tape_la_SOURCES = tape.c
-tape_la_LDFLAGS = -module -avoid-version
-if BUILD_WITH_LIBKSTAT
-tape_la_LDFLAGS += -lkstat
-endif
-if BUILD_WITH_LIBDEVINFO
-tape_la_LDFLAGS += -ldevinfo
-endif
+tape_la_LDFLAGS = -module -avoid-version -lkstat -ldevinfo
 collectd_LDADD += "-dlopen" tape.la
 collectd_DEPENDENCIES += tape.la
 endif
 
-if BUILD_MODULE_UNIXSOCK
+if BUILD_PLUGIN_UNIXSOCK
 pkglib_LTLIBRARIES += unixsock.la
-unixsock_la_SOURCES = unixsock.c
-unixsock_la_CPPFLAGS = -DPREFIX='"${prefix}"'
+unixsock_la_SOURCES = unixsock.c utils_cmd_putval.h utils_cmd_putval.c
+unixsock_la_CPPFLAGS = -DLOCALSTATEDIR='"${localstatedir}"'
 unixsock_la_LDFLAGS = -module -avoid-version -lpthread
 collectd_LDADD += "-dlopen" unixsock.la
 collectd_DEPENDENCIES += unixsock.la
 endif
 
-if BUILD_MODULE_USERS
+if BUILD_PLUGIN_USERS
 pkglib_LTLIBRARIES += users.la
 users_la_SOURCES = users.c
 users_la_LDFLAGS = -module -avoid-version
@@ -539,7 +537,7 @@ collectd_LDADD += "-dlopen" users.la
 collectd_DEPENDENCIES += users.la
 endif
 
-if BUILD_MODULE_VSERVER
+if BUILD_PLUGIN_VSERVER
 pkglib_LTLIBRARIES += vserver.la
 vserver_la_SOURCES = vserver.c
 vserver_la_LDFLAGS = -module -avoid-version
@@ -547,7 +545,7 @@ collectd_LDADD += "-dlopen" vserver.la
 collectd_DEPENDENCIES += vserver.la
 endif
 
-if BUILD_MODULE_WIRELESS
+if BUILD_PLUGIN_WIRELESS
 pkglib_LTLIBRARIES += wireless.la
 wireless_la_SOURCES = wireless.c
 wireless_la_LDFLAGS = -module -avoid-version
@@ -555,9 +553,19 @@ collectd_LDADD += "-dlopen" wireless.la
 collectd_DEPENDENCIES += wireless.la
 endif
 
+if BUILD_PLUGIN_XMMS
+pkglib_LTLIBRARIES += xmms.la
+xmms_la_SOURCES = xmms.c
+xmms_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBXMMS_CFLAGS)
+xmms_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBXMMS_LIBS)
+collectd_LDADD += "-dlopen" xmms.la
+collectd_DEPENDENCIES += xmms.la
+endif
+
+
 dist_man_MANS = collectd.1 collectd-nagios.1 collectd.conf.5 \
                collectd-email.5 collectd-exec.5 collectd-perl.5 \
-               collectd-unixsock.5
+               collectd-snmp.5 collectd-unixsock.5
 
 #collectd_1_SOURCES = collectd.pod
 
index 573a116..2365d1f 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/apache.c
- * Copyright (C) 2006  Florian octo Forster
+ * Copyright (C) 2006,2007  Florian octo Forster
  * Copyright (C) 2007  Florent EppO Monbillard
  *
  * This program is free software; you can redistribute it and/or modify it
 #include "plugin.h"
 #include "configfile.h"
 
-#if HAVE_LIBCURL && HAVE_CURL_CURL_H
-#  define APACHE_HAVE_READ 1
-#  include <curl/curl.h>
-#else
-#  define APACHE_HAVE_READ 0
-#endif
+#include <curl/curl.h>
 
-#if APACHE_HAVE_READ
 static char *url    = NULL;
 static char *user   = NULL;
 static char *pass   = NULL;
@@ -309,14 +303,11 @@ static int apache_read (void)
 
        return (0);
 } /* int apache_read */
-#endif /* APACHE_HAVE_READ */
 
 void module_register (void)
 {
-#if APACHE_HAVE_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 6391eb0..4f0bdfa 100644 (file)
@@ -1,9 +1,11 @@
 /*
  * collectd - src/apcups.c
+ * Copyright (C) 2007 Florian octo Forster
  * Copyright (C) 2006 Anthony Gialluca <tonyabg at charter.net>
  * Copyright (C) 2000-2004 Kern Sibbald
  * Copyright (C) 1996-99 Andre M. Hedrick <andre at suse.com>
  *
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General
  * Public License as published by the Free Software Foundation.
index e13bdc8..2726ad2 100644 (file)
 #  include <IOKit/IOTypes.h>
 #endif
 
-#if HAVE_IOKIT_IOKITLIB_H
-# define IOKIT_HAVE_READ 1
-#else
-# define IOKIT_HAVE_READ 0
-#endif
-
-#if HAVE_IOKIT_IOKITLIB_H
 static mach_port_t io_master_port = MACH_PORT_NULL;
-#endif
 
-#if IOKIT_HAVE_READ
 static int as_init (void)
 {
        kern_return_t status;
@@ -240,12 +231,9 @@ static int as_read (void)
 
        return (0);
 } /* int as_read */
-#endif /* IOKIT_HAVE_READ */
 
 void module_register (void)
 {
-#if IOKIT_HAVE_READ
        plugin_register_init ("apple_sensors", as_init);
        plugin_register_read ("apple_sensors", as_read);
-#endif /* IOKIT_HAVE_READ */
 } /* void module_register */
index 952c56c..2e27e60 100644 (file)
 #  include <IOKit/ps/IOPSKeys.h>
 #endif
 
-#if HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H || KERNEL_LINUX
-# define BATTERY_HAVE_READ 1
-#else
-# define BATTERY_HAVE_READ 0
+#if !HAVE_IOKIT_IOKITLIB_H && !HAVE_IOKIT_PS_IOPOWERSOURCES_H && !KERNEL_LINUX
+# error "No applicable input method."
 #endif
 
 #define INVALID_VALUE 47841.29
 
-#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 */
@@ -523,12 +520,9 @@ static int battery_read (void)
 
        return (0);
 }
-#endif /* BATTERY_HAVE_READ */
 
 void module_register (void)
 {
-#if BATTERY_HAVE_READ
        plugin_register_init ("battery", battery_init);
        plugin_register_read ("battery", battery_read);
-#endif /* BATTERY_HAVE_READ */
 } /* void module_register */
index 0baf2eb..27d0eed 100644 (file)
@@ -8,8 +8,8 @@ collectd-exec - Documentation of collectd's C<exec plugin>
   LoadPlugin exec
   # ...
   <Plugin exec>
-    Exec myuser myprog
-    Exec otheruser /path/to/another/binary
+    Exec "myuser:mygroup" "myprog"
+    Exec "otheruser" "/path/to/another/binary"
   </Plugin>
 
 =head1 DESCRIPTION
@@ -36,25 +36,48 @@ Each line beginning with a C<#> (hash mark) is ignored.
 
 =item
 
-Other lines must consist of an I<Identifier> and a I<Value-List>, separated by
-a space. A description of these two parts follows:
+Other lines must consist of an I<Identifier>, an optional I<Option-List> and a
+I<Value-List>, separated by a spaces. A description of these two parts follows:
 
 An I<Identifier> is of the form
 C<I<host>B</>I<plugin>B<->I<instance>B</>I<type>B<->I<instance>> with both
 I<instance>-parts being optional. If they're omitted the hyphen must be
 omitted, too.
 
-A I<Value-List> is a colon-separated list of values, prepended by the time
-stamp in epoch, i.E<nbsp>e. the same format RRDTool uses, see L<rrdupdate(1)>.
-As with the argument passed to RRDTool you can use B<N> as the current time and
-B<U> for undefined values. However, undefined values can only passed for
-B<GAUGE> values. When setting B<U> for a B<COUNTER> data source the behavior is
-undefined.
+The I<OptionList> is an optional list of I<Options>, where each option if a
+key-value-pair. A list of currently understood options can be found below, all
+other options will be ignored.
+
+I<Valuelist> is a colon-seperated list of the time and the values, each either
+an integer if the data-source is a counter, of a double if the data-source if
+of type "gauge". You can submit an undefined gauge-value by using B<U>. When
+submitting B<U> to a counter the behavior is undefined. The time is given as
+epoch (i.E<nbsp>e. standard UNIX time).
+
+You can mix options and values, but the order is important: Options only
+effect following values, so specifying an option as last field is allowed, but
+useless. Also, an option applies to B<all> following values, so you don't need
+to re-set an option over and over again.
+
+The currently defined B<Options> are:
+
+=over 4
+
+=item B<interval=>I<seconds>
+
+Gives the interval in which the data identified by I<Identifier> is being
+collected.
+
+=back
+
+Please note that this is the same format as used in the B<unixsock plugin>, see
+L<collectd-unixsock(5)>. There's also a bit more information on identifiers in
+case you're confused.
 
 Since examples usually let one understand a lot better, here are some:
 
   leeloo/cpu-0/cpu-idle N:2299366
-  alice/interface/if_octets-eth0 1180647081:421465:479194
+  alice/interface/if_octets-eth0 interval=10 1180647081:421465:479194
 
 =back
 
index fca9f18..63effd5 100644 (file)
@@ -294,25 +294,22 @@ int do_check_con_none (int values_num, double *values, char **values_names)
                        num_okay++;
        }
 
-       if ((num_critical != 0) || (values_num == 0))
+       printf ("%i critical, %i warning, %i okay",
+                       num_critical, num_warning, num_okay);
+       if (values_num > 0)
        {
-               printf ("CRITICAL: %i critical, %i warning, %i okay\n",
-                               num_critical, num_warning, num_okay);
-               return (RET_CRITICAL);
+               printf (" |");
+               for (i = 0; i < values_num; i++)
+                       printf (" %s=%lf;;;;", values_names[i], values[i]);
        }
+       printf ("\n");
+
+       if ((num_critical != 0) || (values_num == 0))
+               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);
+       return (RET_OKAY);
 } /* int do_check_con_none */
 
 int do_check_con_average (int values_num, double *values, char **values_names)
@@ -320,6 +317,7 @@ int do_check_con_average (int values_num, double *values, char **values_names)
        int i;
        double total;
        int total_num;
+       double average;
 
        total = 0.0;
        total_num = 0;
@@ -333,31 +331,23 @@ int do_check_con_average (int values_num, double *values, char **values_names)
        }
 
        if (total_num == 0)
-       {
-               printf ("WARNING: No defined values found\n");
+               average = NAN;
+       else
+               average = total / total_num;
+       printf ("%lf average |", average);
+       for (i = 0; i < values_num; i++)
+               printf (" %s=%lf;;;;", values_names[i], values[i]);
+
+       if (total_num == 0)
                return (RET_WARNING);
-       }
 
-       if (match_range (&range_critical_g, total / total_num) != 0)
-       {
-               printf ("CRITICAL: Average = %lf\n",
-                               (double) (total / total_num));
+       if (isnan (average)
+                       || match_range (&range_critical_g, average))
                return (RET_CRITICAL);
-       }
-       else if (match_range (&range_warning_g, total / total_num) != 0)
-       {
-               printf ("WARNING: Average = %lf\n",
-                               (double) (total / total_num));
+       else if (match_range (&range_warning_g, average) != 0)
                return (RET_WARNING);
-       }
-       else
-       {
-               printf ("OKAY: Average = %lf\n",
-                               (double) (total / total_num));
-               return (RET_OKAY);
-       }
 
-       return (RET_UNKNOWN);
+       return (RET_OKAY);
 } /* int do_check_con_average */
 
 int do_check_con_sum (int values_num, double *values, char **values_names)
@@ -422,7 +412,7 @@ int do_check (void)
                return (do_check_con_sum (values_num, values, values_names));
 
        free (values);
-       free (values_names);
+       free (values_names); /* FIXME? */
 
        return (RET_UNKNOWN);
 }
diff --git a/src/collectd-snmp.pod b/src/collectd-snmp.pod
new file mode 100644 (file)
index 0000000..e351081
--- /dev/null
@@ -0,0 +1,214 @@
+=head1 NAME
+
+collectd-snmp - Documentation of collectd's C<snmp plugin>
+
+=head1 SYNOPSIS
+
+  LoadPlugin snmp
+  # ...
+  <Plugin snmp>
+    <Data "powerplus_voltge_input">
+      Type "voltage"
+      Table false
+      Instance "input_line1"
+      Values "SNMPv2-SMI::enterprises.6050.5.4.1.1.2.1"
+    </Data>
+    <Data "hr_users">
+      Type "users"
+      Table false
+      Instance ""
+      Values "HOST-RESOURCES-MIB::hrSystemNumUsers.0"
+    </Data>
+    <Data "std_traffic">
+      Type "if_octets"
+      Table true
+      Instance "IF-MIB::ifDescr"
+      Values "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets"
+    </Data>
+
+    <Host "some.switch.mydomain.org">
+      Address "192.168.0.2"
+      Version 1
+      Community "community_string"
+      Collect "std_traffic"
+      Inverval 120
+    </Host>
+    <Host "some.server.mydomain.org">
+      Address "192.168.0.42"
+      Version 2
+      Community "another_string"
+      Collect "std_traffic" "hr_users"
+    </Host>
+    <Host "some.ups.mydomain.org">
+      Address "192.168.0.3"
+      Version 1
+      Community "more_communities"
+      Collect "powerplus_voltge_input"
+      Interval 300
+    </Host>
+  </Plugin>
+
+=head1 DESCRIPTION
+
+The C<snmp plugin> queries other hosts using SNMP, the simple network
+management protocol, and translates the value it receives to collectd's
+internal format and dispatches them. Depending on the write plugins you have
+loaded they may be written to disk or submitted to another instance or
+whatever you configured.
+
+Because querying a host via SNMP may produce a timeout multiple threads are
+used to query hosts in parallel. Depending on the number of hosts between one
+and ten threads are used.
+
+=head1 CONFIGURATION
+
+Since the aim of the C<snmp plugin> is to provide a generic interface to SNMP,
+it's configuration is not trivial and may take some time.
+
+Since the C<Net-SNMP> library is used you cann use all the environment
+variables that are interpreted by that package. See L<snmpcmd(1)> for more
+details.
+
+There are two types of blocks that can be contained in the
+C<E<lt>PluginE<nbsp>snmpE<gt>> block: B<Data> and B<Host>:
+
+=head2 The B<Data> block
+
+The B<Data> block defines a list of values or a table of values that are to be
+queried. The following options can be set:
+
+=over 4
+
+=item B<Type> I<type>
+
+collectd's type that is to be used, e.E<nbsp>g. "if_octets" for interface
+traffic or "users" for a user count. The types are read from the B<TypesDB>
+(see L<collectd.conf(5)>), so you may want to check for which types are
+defined.
+
+=item B<Table> I<true|false>
+
+Define if this is a single list of values or a table of values. The difference
+is the following:
+
+When B<Table> is set to B<false>, the OIDs given to B<Values> (see below) are
+queried using the C<GET> SNMP command (see L<snmpget(1)>) and transmitted to
+collectd. B<One> value list is dispatched and, eventually, one file will be
+written.
+
+When B<Table> is set to B<true>, the OIDs given to B<Values> (see below) are
+queried using the C<GETNEXT> SNMP command until the subtree is left. After all
+the lists (think: all columns of the table) have been read B<several> values
+sets will be dispatches and, eventually, several files will be written. If you
+configure a B<Type> (see above) which needs more than one data source (for
+example C<if_octets> which needs C<rx> and C<tx>) you will need to specify more
+than one (two, in the example case) OIDs with the B<Values> option. This has
+nothing to do with the B<Table> setting.
+
+For example, if you want to query the number of users on a system, you can use
+C<HOST-RESOURCES-MIB::hrSystemNumUsers.0>. This is one value and belongs to one
+value list, therefore B<Table> must be set to B<false>. Please note that, in
+this case, you have to include the sequence number (zero in this case) in the
+OID.
+
+Counter example: If you want to query the interface table provided by the
+C<IF-MIB>, e.E<nbsp>g. the bytes transmitted. There are potentially many
+interfaces, so you will want to set B<Table> to B<true>. Because the
+C<if_octets> type needs two values, received and transmitted bytes, you need to
+specify two OIDs in the B<Values> setting, in this case likely
+C<IF-MIB::ifHCInOctets> and C<IF-MIB::ifHCOutOctets>. But, this is because of
+the B<Type> setting, not the B<Table> setting.
+
+Since the semantic of B<Instance> and B<Values> depends on this setting you
+need to set it before setting them. Doing vice verse will result in undefined
+behavior.
+
+=item B<Instance> I<Instance>
+
+Sets the type-instance of the values that are dispatched. The meaning of this
+setting depends on whether B<Table> is set to I<true> or I<false>:
+
+If B<Table> is set to I<true>, I<Instance> is interpreted as an SNMP-prefix
+that will return a list of strings. Those strings are then used as the actual
+type-instance. An example would be the C<IF-MIB::ifDescr> subtree.
+L<variables(5)> from the SNMP distribution describes the format of OIDs.
+
+If B<Table> is set to I<false> the actual string configured for I<Instance> is
+copied into the value-list. In this case I<Instance> may be empty, i.E<nbsp>e.
+"".
+
+=item B<Values> I<OID> [I<OID> ...]
+
+Configures the values to be queried from the SNMP host. The meaning slightly
+changes with the B<Table> setting. L<variables(5)> from the SNMP distribution
+describes the format of OIDs.
+
+If B<Table> is set to I<true>, each I<OID> must be the prefix of all the
+values to query, e.E<nbsp>g. C<IF-MIB::ifInOctets> for all the counters of
+incoming traffic. This subtree is walked (using C<GETNEXT>) until a value from
+outside the subtree is returned.
+
+If B<Table> is set to I<false>, each I<OID> must be the OID of exactly one
+value, e.E<nbsp>g. C<IF-MIB::ifInOctets.3> for the third counter of incoming
+traffic.
+
+=back
+
+=head2 The Host block
+
+The B<Host> block defines which hosts to query, which SNMP community and
+version to use and which of the defined B<Data> to query.
+
+The argument passed to the B<Host> block is used as the hostname in the data
+stored by collectd.
+
+=over 4
+
+=item B<Address> I<IP-Address>|I<Hostname>
+
+Set the address to connect to.
+
+=item B<Version> B<1>|B<2>
+
+Set the SNMP version to use. When giving B<2> version 2c is actually used.
+Version 3 is not supported by this plugin.
+
+=item B<Community> I<Community>
+
+Pass I<Community> to the host.
+
+=item B<Collect> I<Data> [I<Data> ...]
+
+Defines which values to collect. I<Data> refers to one of the B<Data> block
+above. Since the config file is read top-down you need to define the data
+before using it here.
+
+=item B<Interval> I<Seconds>
+
+Collect data from this host every I<Seconds> seconds. This value needs to be a
+multiple of the global B<Interval> setting and, if it is not, will be rounded
+B<down> to one and a warning is logged in this case. So if your global
+B<Interval> is set to I<10> and you configure I<25> here, it's rounded down to
+I<20>. By default the global B<Interval> setting will be used.
+
+This option is meant for devices with not much CPU power, e.E<nbsp>g. network
+equipment such as switches, embedded devices, rack monitoring systems and so
+on. Since the B<Step> of generated RRD files depends on this setting it's
+wise to select a reasonable value once and never change it.
+
+=back
+
+=head1 SEE ALSO
+
+L<collectd(1)>,
+L<collectd.conf(5)>,
+L<snmpget(1)>,
+L<snmpgetnext(1)>,
+L<variables(5)>,
+L<unix(7)>
+
+=head1 AUTHOR
+
+Florian Forster E<lt>octo@verplant.orgE<gt>
+
+=cut
index 9a142f2..1be0654 100644 (file)
@@ -50,18 +50,66 @@ Example:
   -> | GETVAL myhost/cpu-0/cpu-user
   <- | 1 value=1.260000e+00
 
-=item B<PUTVAL> I<Identifier> I<Valuelist>
+=item B<LISTVAL>
 
-Submits a value (identified by I<Identifier>, see below) to the daemon which
-will dispatch it to all it's write-plugins. The I<Valuelist> is a
-colon-separated list of the time and the values, each either an integer if the
-data-source is a counter, of a double if the data-source if of type "gauge".
-You can submit an undefined gauge-value by using B<U>. When submitting B<U> to
-a counter the behavior is undefined. The time is given as epoch (i.E<nbsp>e.
-standard UNIX time).
+Returnes a list of the values available in the value cache together with the
+time of the last update, so that querying applications can issue a B<GETVAL>
+command for the values that have changed.
+
+The first line's status number is the number of identifiers returned or less
+than zero if an error occured. Each of the following lines containes the
+update time as an epoch value and the identifier, seperated by a space.
+
+Example:
+  -> | LISTVAL
+  <- | 69 Values found
+  <- | 1182204284 leeloo/cpu-0/cpu-idle
+  <- | 1182204284 leeloo/cpu-0/cpu-nice
+  <- | 1182204284 leeloo/cpu-0/cpu-system
+  <- | 1182204284 leeloo/cpu-0/cpu-user
+  ...
+
+=item B<PUTVAL> I<Identifier> [I<OptionList>] I<Valuelist>
+
+Submits one or more values (identified by I<Identifier>, see below) to the
+daemon which will dispatch it to all it's write-plugins.
+
+An I<Identifier> is of the form
+C<I<host>B</>I<plugin>B<->I<instance>B</>I<type>B<->I<instance>> with both
+I<instance>-parts being optional. If they're omitted the hyphen must be
+omitted, too.
+
+The I<OptionList> is an optional list of I<Options>, where each option if a
+key-value-pair. A list of currently understood options can be found below, all
+other options will be ignored.
+
+I<Valuelist> is a colon-seperated list of the time and the values, each either
+an integer if the data-source is a counter, of a double if the data-source if
+of type "gauge". You can submit an undefined gauge-value by using B<U>. When
+submitting B<U> to a counter the behavior is undefined. The time is given as
+epoch (i.E<nbsp>e. standard UNIX time).
+
+You can mix options and values, but the order is important: Options only
+effect following values, so specifying an option as last field is allowed, but
+useless. Also, an option applies to B<all> following values, so you don't need
+to re-set an option over and over again.
+
+The currently defined B<Options> are:
+
+=over 4
+
+=item B<interval=>I<seconds>
+
+Gives the interval in which the data identified by I<Identifier> is being
+collected.
+
+=back
+
+Please note that this is the same format as used in the B<exec plugin>, see
+L<collectd-exec(5)>.
 
 Example:
-  -> | PUTVAL testhost/interface/if_octets-test0 1179574444:123:456
+  -> | PUTVAL testhost/interface/if_octets-test0 interval=10 1179574444:123:456
   <- | 0 Success
 
 =back
index b7f3298..5bb1fc7 100644 (file)
 #Interval     10
 #ReadThreads  5
 
-@BUILD_MODULE_APACHE_TRUE@LoadPlugin apache
-@BUILD_MODULE_APCUPS_TRUE@LoadPlugin apcups
-@BUILD_MODULE_APPLE_SENSORS_TRUE@LoadPlugin apple_sensors
-@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_PERL_TRUE@LoadPlugin perl
-@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_UNIXSOCK_TRUE@LoadPlugin unixsock
-@BUILD_MODULE_USERS_TRUE@LoadPlugin users
-@BUILD_MODULE_VSERVER_TRUE@LoadPlugin vserver
-@BUILD_MODULE_WIRELESS_TRUE@LoadPlugin wireless
+@BUILD_PLUGIN_APACHE_TRUE@LoadPlugin apache
+@BUILD_PLUGIN_APCUPS_TRUE@LoadPlugin apcups
+@BUILD_PLUGIN_APPLE_SENSORS_TRUE@LoadPlugin apple_sensors
+@BUILD_PLUGIN_BATTERY_TRUE@LoadPlugin battery
+@BUILD_PLUGIN_CPU_TRUE@LoadPlugin cpu
+@BUILD_PLUGIN_CPUFREQ_TRUE@LoadPlugin cpufreq
+@BUILD_PLUGIN_CSV_TRUE@LoadPlugin csv
+@BUILD_PLUGIN_DF_TRUE@LoadPlugin df
+@BUILD_PLUGIN_DISK_TRUE@LoadPlugin disk
+@BUILD_PLUGIN_DNS_TRUE@LoadPlugin dns
+@BUILD_PLUGIN_EMAIL_TRUE@LoadPlugin email
+@BUILD_PLUGIN_ENTROPY_TRUE@LoadPlugin entropy
+@BUILD_PLUGIN_EXEC_TRUE@LoadPlugin exec
+@BUILD_PLUGIN_HDDTEMP_TRUE@LoadPlugin hddtemp
+@BUILD_PLUGIN_INTERFACE_TRUE@LoadPlugin interface
+@BUILD_PLUGIN_IPTABLES_TRUE@LoadPlugin iptables
+@BUILD_PLUGIN_IRQ_TRUE@LoadPlugin irq
+@BUILD_PLUGIN_LOAD_TRUE@LoadPlugin load
+@BUILD_PLUGIN_LOGFILE_TRUE@LoadPlugin logfile
+@BUILD_PLUGIN_MBMON_TRUE@LoadPlugin mbmon
+@BUILD_PLUGIN_MEMORY_TRUE@LoadPlugin memory
+@BUILD_PLUGIN_MULTIMETER_TRUE@LoadPlugin multimeter
+@BUILD_PLUGIN_MYSQL_TRUE@LoadPlugin mysql
+@BUILD_PLUGIN_NETLINK_TRUE@LoadPlugin netlink
+@BUILD_PLUGIN_NETWORK_TRUE@LoadPlugin network
+@BUILD_PLUGIN_NFS_TRUE@LoadPlugin nfs
+@BUILD_PLUGIN_NTPD_TRUE@LoadPlugin ntpd
+@BUILD_PLUGIN_NUT_TRUE@LoadPlugin nut
+@BUILD_PLUGIN_PERL_TRUE@LoadPlugin perl
+@BUILD_PLUGIN_PING_TRUE@LoadPlugin ping
+@BUILD_PLUGIN_PROCESSES_TRUE@LoadPlugin processes
+@BUILD_PLUGIN_RRDTOOL_TRUE@LoadPlugin rrdtool
+@BUILD_PLUGIN_SENSORS_TRUE@LoadPlugin sensors
+@BUILD_PLUGIN_SERIAL_TRUE@LoadPlugin serial
+@BUILD_PLUGIN_SNMP_TRUE@LoadPlugin snmp
+@BUILD_PLUGIN_SWAP_TRUE@LoadPlugin swap
+@BUILD_PLUGIN_SYSLOG_TRUE@LoadPlugin syslog
+@BUILD_PLUGIN_TAPE_TRUE@LoadPlugin tape
+@BUILD_PLUGIN_UNIXSOCK_TRUE@LoadPlugin unixsock
+@BUILD_PLUGIN_USERS_TRUE@LoadPlugin users
+@BUILD_PLUGIN_VSERVER_TRUE@LoadPlugin vserver
+@BUILD_PLUGIN_WIRELESS_TRUE@LoadPlugin wireless
+@BUILD_PLUGIN_XMMS_TRUE@LoadPlugin xmms
 
 #<Plugin apache>
 #      URL "http://localhost/status?auto"
@@ -90,7 +93,7 @@
 #</Plugin>
 
 #<Plugin exec>
-#      Exec user "/path/to/exec"
+#      Exec "user:group" "/path/to/exec"
 #</Plugin>
 
 #<Plugin hddtemp>
 #      Database "db_name"
 #</Plugin>
 
+#<Plugin netlink>
+#      Interface "All"
+#      VerboseInterface "All"
+#      QDisc "eth0" "pfifo_fast-1:0"
+#      Class "ppp0" "htb-1:10"
+#      Filter "ppp0" "u32-1:0"
+#</Plugin>
+
 #<Plugin network>
 #      Server "ff18::efc0:4a42" "25826"
 #      Server "239.192.74.66" "25826"
 
 #<Plugin rrdtool>
 #      DataDir "@prefix@/var/lib/@PACKAGE_NAME@/rrd"
-#      StepSize      10
-#      HeartBeat     20
-#      RRARows     1200
-#      XFF            0.1
 #      CacheTimeout 120
 #      CacheFlush   900
 #</Plugin>
 #      IgnoreSelected false
 #</Plugin>
 
+#<Plugin snmp>
+#   <Data "powerplus_voltge_input">
+#       Type "voltage"
+#       Table false
+#       Instance "input_line1"
+#       Values "SNMPv2-SMI::enterprises.6050.5.4.1.1.2.1"
+#   </Data>
+#   <Data "hr_users">
+#       Type "users"
+#       Table false
+#       Instance ""
+#       Values "HOST-RESOURCES-MIB::hrSystemNumUsers.0"
+#   </Data>
+#   <Data "std_traffic">
+#       Type "if_octets"
+#       Table true
+#       Instance "IF-MIB::ifDescr"
+#       Values "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets"
+#   </Data>
+#   
+#   <Host "some.switch.mydomain.org">
+#       Address "192.168.0.2"
+#       Version 1
+#       Community "community_string"
+#       Collect "std_traffic"
+#       Inverval 120
+#   </Host>
+#   <Host "some.server.mydomain.org">
+#       Address "192.168.0.42"
+#       Version 2
+#       Community "another_string"
+#       Collect "std_traffic" "hr_users"
+#   </Host>
+#   <Host "some.ups.mydomain.org">
+#       Address "192.168.0.3"
+#       Version 1
+#       Community "more_communities"
+#       Collect "powerplus_voltge_input"
+#       Interval 300
+#   </Host>
+#</Plugin>
+
 #<Plugin syslog>
 #      LogLevel info
 #</Plugin>
index 2b82b75..db87f9c 100644 (file)
@@ -50,8 +50,8 @@ will be mostly useless.
 =item B<PIDFile> I<File>
 
 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.
+and deleted when the program is stopped. Some init-scripts might override this
+setting using the B<-P> command-line option.
 
 =item B<PluginDir> I<Directory>
 
@@ -78,7 +78,7 @@ a value higher than the number of plugins you've loaded is totally useless.
 
 =head1 PLUGIN OPTIONS
 
-Some Plugins may register own options. These options must be enclosed in a
+Some plugins may register own options. These options must be enclosed in a
 C<Plugin>-Section. Which options exist depends on the plugin used. Some plugins
 require external configuration, too. The C<apache plugin>, for example,
 required C<mod_status> to be configured in the webserver you're going to
@@ -214,6 +214,10 @@ Ignore packets that originate from this address.
 
 =over 4
 
+=item B<SocketFile> I<Path>
+
+Sets the socket-file which is to be created.
+
 =item B<SocketGroup> I<Group>
 
 If running as root change the group of the UNIX-socket after it has been 
@@ -242,9 +246,18 @@ output that is expected from it.
 
 =over 4
 
-=item B<Exec> I<User> I<Executable>
+=item B<Exec> I<User>[:[I<Group>]] I<Executable>
+
+Execute the executable I<Executable> as user I<User>. If the user name is
+followed by a colon and a group name, the effective group is set to that group.
+The real group and saved-set group will be set to the default group of that
+user. If no group is given the effective group ID will be the same as the real
+group ID.
 
-Execute the executable I<Executable> as user I<User>.
+Please note that in order to change the user and/or group the daemon needs
+superuser privileges. If the daemon is run as an unprivileged user you must
+specify the same user/group here. If the daemon is run with superuser
+privileges, you must supply a non-root user here.
 
 =back
 
@@ -413,6 +426,83 @@ option for what this plugin does.
 
 =back
 
+=head2 Plugin C<netlink>
+
+The C<netlink> plugin uses a netlink socket to query the Linux kernel about
+statistics of various interface and routing aspects.
+
+=over 4
+
+=item B<Interface> I<Interface>
+
+=item B<VerboseInterface> I<Interface>
+
+Instruct the plugin to collect interface statistics. This is basically the same
+as the statistics provided by the C<interface> plugin (see above) but
+potentially much more detailed.
+
+When configuring with B<Interface> only the basic statistics will be collected,
+namely octets, packets, and errors. These statistics are collected by
+the C<interface> plugin, too, so using both at the same time is no benefit.
+
+When configured with B<VerboseInterface> all counters B<except> the basic ones,
+so that no data needs to be collected twice if you use the C<interface> plugin.
+This includes dropped packets, received multicast packets, collisions and a
+whole zoo of differentiated RX and TX errors. You can try the following command
+to get an idea of what awaits you:
+
+  ip -s -s link list
+
+If I<Interface> is B<All>, all interfaces will be selected.
+
+=item B<QDisc> I<Interface> [I<QDisc>]
+
+=item B<Class> I<Interface> [I<Class>]
+
+=item B<Filter> I<Interface> [I<Filter>]
+
+Collect the octets and packets that pass a certain qdisc, class or filter.
+
+QDiscs and classes are identified by their type and handle (or classid).
+Filters don't necessarily have a handle, therefore the parent's handle is used.
+The notation used in collectd differs from that used in tc(1) in that it
+doesn't skip the major or minor number if it's zero and doesn't print special
+ids by their name.  So, for example, a qdisc may be identified by
+C<pfifo_fast-1:0> even though the minor number of B<all> qdiscs is zero and
+thus not displayed by tc(1).
+
+If B<QDisc>, B<Class>, or B<Filter> is given without the second argument,
+i.E<nbsp>.e. without an identifier, all qdiscs, classes, or filters that are
+associated with that interface will be collected.
+
+Since a filter itself doesn't necessarily have a handle, the parent's handle is
+used. This may lead to problems when more than one filter is attached to a
+qdisc or class. This isn't nice, but we don't know how this could be done any
+better. If you have a idea, please don't hesitate to tell us.
+
+As with the B<Interface> option you can specify B<All> as the interface,
+meaning all interfaces.
+
+Here are some examples to help you understand the above text more easily:
+
+  <Plugin netlink>
+    VerboseInterface "All"
+    QDisc "eth0" "pfifo_fast-1:0"
+    QDisc "ppp0"
+    Class "ppp0" "htb-1:10"
+    Filter "ppp0" "u32-1:0"
+  </Plugin>
+
+=item B<IgnoreSelected>
+
+The behaviour is the same as with all other similar plugins: If nothing is
+selected at all, everything is collected. If some things are selected using the
+options described above, only these statistics are collected. If you set
+B<IgnoreSelected> to B<true>, this behavior is inversed, i.E<nbsp>e. the
+specified statistics will not be collected.
+
+=back
+
 =head2 Plugin C<network>
 
 =over 4
@@ -547,7 +637,7 @@ and minor and major pagefaults.
 =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
+fine-tune 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 safely ignore these settings.
 
@@ -560,15 +650,18 @@ 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.
+B<Force> the stepsize of newly created RRD-files. Ideally (and per default)
+this setting is unset and the stepsize is set to the interval in which the data
+is collected. Do not use this option unless you absolutely have to for some
+reason. Setting this option may cause problems with the C<snmp plugin>, the
+C<exec plugin> or when the daemon is set up to receive data from other hosts.
 
 =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.
+B<Force> the heartbeat of newly created RRD-files. This setting should be unset
+in which case the heartbeat is set to twice the B<StepSize> which should equal
+the interval in which data is collected. Do not set this option unless you have
+a very good reason to do so.
 
 =item B<RRARows> I<NumRows>
 
@@ -615,7 +708,7 @@ normally do much harm either.
 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
+The trade off is that the graphs kind of "drag behind" and that more memory is
 used.
 
 =back
@@ -651,6 +744,12 @@ and all other sensors are collected.
 
 =back
 
+=head2 Plugin C<snmp>
+
+Since the configuration of the C<snmp plugin> is a little more complicated than
+other plugins, its documentation has been moved to an own manpage,
+L<collectd-snmp(5)>. Please see there for details.
+
 =head2 Plugin C<syslog>
 
 =over 4
index ac75516..282e632 100644 (file)
 #define CONFIGFILE SYSCONFDIR"/collectd.conf"
 #endif
 
+#ifndef LOCALSTATEDIR
+#define LOCALSTATEDIR PREFIX "/var"
+#endif
+
 #ifndef PKGLOCALSTATEDIR
 #define PKGLOCALSTATEDIR PREFIX "/var/lib/" PACKAGE_NAME
 #endif
index 5a9f420..e09fd84 100644 (file)
@@ -92,7 +92,7 @@ Several loglevels let you suppress uninteresting messages.
 Please note that some plugins, that provide other means of communicating with
 the daemon, have manpages of their own to describe their functionality in more
 detail. In particular those are L<collectd-email(5)>, L<collectd-exec(5)>,
-L<collectd-perl(5)>, and L<collectd-unixsock(5)>
+L<collectd-perl(5)>, L<collectd-snmp(5)>, and L<collectd-unixsock(5)>
 
 =head1 SEE ALSO
 
@@ -100,6 +100,7 @@ L<collectd.conf(5)>,
 L<collectd-email(5)>,
 L<collectd-exec(5)>,
 L<collectd-perl(5)>,
+L<collectd-snmp(5)>,
 L<collectd-unixsock(5)>,
 L<http://collectd.org/>
 
index 4b6803e..f4e9c60 100644 (file)
@@ -42,6 +42,13 @@ typedef struct cf_callback
        struct cf_callback *next;
 } cf_callback_t;
 
+typedef struct cf_complex_callback_s
+{
+       char *type;
+       int (*callback) (oconfig_item_t *);
+       struct cf_complex_callback_s *next;
+} cf_complex_callback_t;
+
 typedef struct cf_value_map_s
 {
        char *key;
@@ -65,6 +72,7 @@ static int dispatch_value_loadplugin (const oconfig_item_t *ci);
  * Private variables
  */
 static cf_callback_t *first_callback = NULL;
+static cf_complex_callback_t *complex_callback_head = NULL;
 
 static cf_value_map_t cf_value_map[] =
 {
@@ -257,21 +265,29 @@ static int dispatch_block_plugin (oconfig_item_t *ci)
        int i;
        char *name;
 
+       cf_complex_callback_t *cb;
+
        if (strcasecmp (ci->key, "Plugin") != 0)
                return (-1);
-       if (ci->values_num != 1)
+       if (ci->values_num < 1)
                return (-1);
        if (ci->values[0].type != OCONFIG_TYPE_STRING)
                return (-1);
 
        name = ci->values[0].value.string;
 
+       /* Check for a complex callback first */
+       for (cb = complex_callback_head; cb != NULL; cb = cb->next)
+               if (strcasecmp (name, cb->type) == 0)
+                       return (cb->callback (ci));
+
+       /* Hm, no complex plugin found. Dispatch the values one by one */
        for (i = 0; i < ci->children_num; i++)
        {
                if (ci->children[i].children == NULL)
                        dispatch_value_plugin (name, ci->children + i);
                else
-                       {DEBUG ("No nested config blocks allow for plugins. Yet.");}
+                       {DEBUG ("No nested config blocks allow for this plugin.");}
        }
 
        return (0);
@@ -347,6 +363,26 @@ void cf_unregister (const char *type)
                }
 } /* void cf_unregister */
 
+void cf_unregister_complex (const char *type)
+{
+       cf_complex_callback_t *this, *prev;
+
+       for (prev = NULL, this = complex_callback_head;
+                       this != NULL;
+                       prev = this, this = this->next)
+               if (strcasecmp (this->type, type) == 0)
+               {
+                       if (prev == NULL)
+                               complex_callback_head = this->next;
+                       else
+                               prev->next = this->next;
+
+                       sfree (this->type);
+                       sfree (this);
+                       break;
+               }
+} /* void cf_unregister */
+
 void cf_register (const char *type,
                int (*callback) (const char *, const char *),
                const char **keys, int keys_num)
@@ -369,6 +405,39 @@ void cf_register (const char *type,
        first_callback = cf_cb;
 } /* void cf_register */
 
+int cf_register_complex (const char *type, int (*callback) (oconfig_item_t *))
+{
+       cf_complex_callback_t *new;
+
+       new = (cf_complex_callback_t *) malloc (sizeof (cf_complex_callback_t));
+       if (new == NULL)
+               return (-1);
+
+       new->type = strdup (type);
+       if (new->type == NULL)
+       {
+               sfree (new);
+               return (-1);
+       }
+
+       new->callback = callback;
+       new->next = NULL;
+
+       if (complex_callback_head == NULL)
+       {
+               complex_callback_head = new;
+       }
+       else
+       {
+               cf_complex_callback_t *last = complex_callback_head;
+               while (last->next != NULL)
+                       last = last->next;
+               last->next = new;
+       }
+
+       return (0);
+} /* int cf_register_complex */
+
 int cf_read (char *filename)
 {
        oconfig_item_t *conf;
index 0ee8f33..3952c18 100644 (file)
@@ -1,3 +1,5 @@
+#ifndef CONFIGFILE_H
+#define CONFIGFILE_H
 /**
  * collectd - src/configfile.h
  * Copyright (C) 2005,2006  Florian octo Forster
@@ -20,8 +22,8 @@
  *   Florian octo Forster <octo at verplant.org>
  **/
 
-#ifndef CONFIGFILE_H
-#define CONFIGFILE_H
+#include "collectd.h"
+#include "liboconfig/oconfig.h"
 
 /*
  * DESCRIPTION
@@ -32,6 +34,7 @@
  *              `plugin_register'
  */
 void cf_unregister (const char *type);
+void cf_unregister_complex (const char *type);
 
 /*
  * DESCRIPTION
@@ -61,6 +64,8 @@ void cf_register (const char *type,
                int (*callback) (const char *, const char *),
                const char **keys, int keys_num);
 
+int cf_register_complex (const char *type, int (*callback) (oconfig_item_t *));
+
 /*
  * DESCRIPTION
  *  `cf_read' reads the config file `filename' and dispatches the read
index cbdde1e..ba0c1b1 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
 # endif
 #endif /* HAVE_SYSCTLBYNAME */
 
-#if defined(PROCESSOR_CPU_LOAD_INFO) || defined(KERNEL_LINUX) || defined(HAVE_LIBKSTAT) || defined(HAVE_SYSCTLBYNAME)
-# define CPU_HAVE_READ 1
-#else
-# define CPU_HAVE_READ 0
+#if !PROCESSOR_CPU_LOAD_INFO && !KERNEL_LINUX && !HAVE_LIBKSTAT && !HAVE_SYSCTLBYNAME
+# error "No applicable input method."
 #endif
 
-#if CPU_HAVE_READ
 #ifdef PROCESSOR_CPU_LOAD_INFO
 static mach_port_t port_host;
 static processor_port_array_t cpu_list;
@@ -389,12 +386,9 @@ static int cpu_read (void)
 
        return (0);
 }
-#endif /* CPU_HAVE_READ */
 
 void module_register (void)
 {
-#if CPU_HAVE_READ
        plugin_register_init ("cpu", init);
        plugin_register_read ("cpu", cpu_read);
-#endif /* CPU_HAVE_READ */
 } /* void module_register */
index 7a5c8fd..b1037c3 100644 (file)
 
 #define MODULE_NAME "cpufreq"
 
-#if defined(KERNEL_LINUX)
-# define CPUFREQ_HAVE_READ 1
-#else
-# define CPUFREQ_HAVE_READ 0
-#endif
-
-#if CPUFREQ_HAVE_READ
-#ifdef KERNEL_LINUX
 static int num_cpu = 0;
-#endif
 
 static int cpufreq_init (void)
 {
-#ifdef KERNEL_LINUX
         int status;
        char filename[256];
 
@@ -64,7 +54,6 @@ static int cpufreq_init (void)
 
        if (num_cpu == 0)
                plugin_unregister_read ("cpufreq");
-#endif /* defined(KERNEL_LINUX) */
 
        return (0);
 } /* int cpufreq_init */
@@ -89,7 +78,6 @@ static void cpufreq_submit (int cpu_num, double value)
 
 static int cpufreq_read (void)
 {
-#ifdef KERNEL_LINUX
         int status;
        unsigned long long val;
        int i = 0;
@@ -138,17 +126,12 @@ static int cpufreq_read (void)
 
                cpufreq_submit (i, val);
        }
-#endif /* defined(KERNEL_LINUX) */
 
        return (0);
 } /* int cpufreq_read */
-#endif /* CPUFREQ_HAVE_READ */
-#undef BUFSIZE
 
 void module_register (void)
 {
-#if CPUFREQ_HAVE_READ
        plugin_register_init ("cpufreq", cpufreq_init);
        plugin_register_read ("cpufreq", cpufreq_read);
-#endif /* CPUFREQ_HAVE_READ */
 }
index 433f4e2..0f357d8 100644 (file)
--- a/src/df.c
+++ b/src/df.c
 #include "utils_mount.h"
 #include "utils_ignorelist.h"
 
-#if HAVE_STATFS || HAVE_STATVFS
-# define DF_HAVE_READ 1
-#else
-# define DF_HAVE_READ 0
-#endif
-
 #if HAVE_STATVFS
 # if HAVE_SYS_STATVFS_H
 #  include <sys/statvfs.h>
 # endif
 # define STATANYFS statfs
 # define BLOCKSIZE(s) (s).f_bsize
+#else
+# error "No applicable input method."
 #endif
 
-#if DF_HAVE_READ
 static const char *config_keys[] =
 {
        "Device",
@@ -209,14 +204,11 @@ static int df_read (void)
 
        return (0);
 } /* int df_read */
-#endif /* DF_HAVE_READ */
 
 void module_register (void)
 {
-#if DF_HAVE_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 38c161f..490da07 100644 (file)
 #  define UINT_MAX 4294967295U
 #endif
 
-#if HAVE_IOKIT_IOKITLIB_H || KERNEL_LINUX || HAVE_LIBKSTAT
-# define DISK_HAVE_READ 1
-#else
-# define DISK_HAVE_READ 0
-#endif
-
-#if DISK_HAVE_READ
 #if HAVE_IOKIT_IOKITLIB_H
 static mach_port_t io_master_port = MACH_PORT_NULL;
 /* #endif HAVE_IOKIT_IOKITLIB_H */
@@ -102,7 +95,11 @@ static diskstats_t *disklist;
 extern kstat_ctl_t *kc;
 static kstat_t *ksp[MAX_NUMDISK];
 static int numdisk = 0;
-#endif /* HAVE_LIBKSTAT */
+/* #endif HAVE_LIBKSTAT */
+
+#else
+# error "No applicable input method."
+#endif
 
 static int disk_init (void)
 {
@@ -639,12 +636,9 @@ static int disk_read (void)
 
        return (0);
 } /* int disk_read */
-#endif /* DISK_HAVE_READ */
 
 void module_register (void)
 {
-#if DISK_HAVE_READ
        plugin_register_init ("disk", disk_init);
        plugin_register_read ("disk", disk_read);
-#endif /* DISK_HAVE_READ */
 } /* void module_register */
index 0801fe7..e9996b9 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
 #include "plugin.h"
 #include "configfile.h"
 
-#if HAVE_LIBPCAP && HAVE_LIBPTHREAD
-# include "utils_dns.h"
-# include <pthread.h>
-# include <pcap.h>
-# include <poll.h>
-# define DNS_HAVE_READ 1
-#else
-# define DNS_HAVE_READ 0
-#endif
+#include "utils_dns.h"
+#include <pthread.h>
+#include <pcap.h>
+#include <poll.h>
 
 /*
  * Private data types
  */
-#if DNS_HAVE_READ
 struct counter_list_s
 {
        unsigned int key;
@@ -45,12 +39,10 @@ struct counter_list_s
        struct counter_list_s *next;
 };
 typedef struct counter_list_s counter_list_t;
-#endif
 
 /*
  * Private variables
  */
-#if DNS_HAVE_READ
 static const char *config_keys[] =
 {
        "Interface",
@@ -75,12 +67,10 @@ static pthread_mutex_t traffic_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t qtype_mutex   = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t opcode_mutex  = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t rcode_mutex   = PTHREAD_MUTEX_INITIALIZER;
-#endif /* DNS_HAVE_READ */
 
 /*
  * Private functions
  */
-#if DNS_HAVE_READ
 static counter_list_t *counter_list_search (counter_list_t **list, unsigned int key)
 {
        counter_list_t *entry;
@@ -400,13 +390,10 @@ static int dns_read (void)
 
        return (0);
 } /* int dns_read */
-#endif
 
 void module_register (void)
 {
-#if DNS_HAVE_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
 } /* void module_register */
index 594ef96..f5a544a 100644 (file)
 /* 256 bytes ought to be enough for anybody ;-) */
 #define BUFSIZE 256
 
-#ifndef COLLECTD_SOCKET_PREFIX
-# define COLLECTD_SOCKET_PREFIX "/tmp/.collectd-"
-#endif /* COLLECTD_SOCKET_PREFIX */
-
-#define SOCK_PATH COLLECTD_SOCKET_PREFIX"email"
+#define SOCK_PATH LOCALSTATEDIR"/run/"PACKAGE_NAME"-email"
 #define MAX_CONNS 5
 #define MAX_CONNS_LIMIT 16384
 
@@ -119,6 +115,7 @@ typedef struct {
 /* valid configuration file keys */
 static const char *config_keys[] =
 {
+       "SocketFile",
        "SocketGroup",
        "SocketPerms",
        "MaxConns"
@@ -126,6 +123,7 @@ static const char *config_keys[] =
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
 /* socket configuration */
+static char *sock_file  = SOCK_PATH;
 static char *sock_group = COLLECTD_GRP_NAME;
 static int  sock_perms  = S_IRWXU | S_IRWXG;
 static int  max_conns   = MAX_CONNS;
@@ -171,7 +169,10 @@ static type_list_t check;
  */
 static int email_config (const char *key, const char *value)
 {
-       if (0 == strcasecmp (key, "SocketGroup")) {
+       if (0 == strcasecmp (key, "SocketFile")) {
+               sock_file = sstrdup (value);
+       }
+       else if (0 == strcasecmp (key, "SocketGroup")) {
                sock_group = sstrdup (value);
        }
        else if (0 == strcasecmp (key, "SocketPerms")) {
@@ -508,7 +509,7 @@ static void *open_connection (void *arg)
 
        addr.sun_family = AF_UNIX;
 
-       strncpy (addr.sun_path, SOCK_PATH, (size_t)(UNIX_PATH_MAX - 1));
+       strncpy (addr.sun_path, sock_file, (size_t)(UNIX_PATH_MAX - 1));
        addr.sun_path[UNIX_PATH_MAX - 1] = '\0';
        unlink (addr.sun_path);
 
@@ -555,12 +556,12 @@ static void *open_connection (void *arg)
                }
                else
                {
-                       status = chown (SOCK_PATH, (uid_t) -1, grp->gr_gid);
+                       status = chown (sock_file, (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,
+                                               sock_file, (int) grp->gr_gid,
                                                sstrerror (errno, errbuf, sizeof (errbuf)));
                        }
                }
@@ -571,7 +572,7 @@ static void *open_connection (void *arg)
        }
 
        errno = 0;
-       if (0 != chmod (SOCK_PATH, sock_perms)) {
+       if (0 != chmod (sock_file, sock_perms)) {
                char errbuf[1024];
                log_warn ("chmod() failed: %s",
                                sstrerror (errno, errbuf, sizeof (errbuf)));
@@ -714,7 +715,7 @@ static int email_shutdown (void)
 
        pthread_mutex_unlock (&conns_mutex);
 
-       unlink (SOCK_PATH);
+       unlink (sock_file);
        errno = 0;
 
        return (0);
index 7e90395..5f9eb53 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/entropy.c
- * Copyright (C) 2005,2006  Florian octo Forster
+ * 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
 #include "common.h"
 #include "plugin.h"
 
-#if KERNEL_LINUX
-# define ENTROPY_HAVE_READ 1
-#else
-# define ENTROPY_HAVE_READ 0
+#if !KERNEL_LINUX
+# error "No applicable input method."
 #endif
 
 #define ENTROPY_FILE "/proc/sys/kernel/random/entropy_avail"
 
-#if ENTROPY_HAVE_READ
 static void entropy_submit (double entropy)
 {
        value_t values[1];
@@ -52,7 +49,6 @@ static void entropy_submit (double entropy)
 
 static int entropy_read (void)
 {
-#if KERNEL_LINUX
        double entropy;
        FILE *fh;
        char buffer[64];
@@ -72,15 +68,11 @@ static int entropy_read (void)
        
        if (entropy > 0.0)
                entropy_submit (entropy);
-#endif /* KERNEL_LINUX */
 
        return (0);
 }
-#endif /* ENTROPY_HAVE_READ */
 
 void module_register (void)
 {
-#if ENTROPY_HAVE_READ
        plugin_register_read ("entropy", entropy_read);
-#endif
 } /* void module_register */
index d726f70..d9f2d8c 100644 (file)
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
+#include "utils_cmd_putval.h"
 
 #include <sys/types.h>
 #include <pwd.h>
+#include <grp.h>
 #include <signal.h>
 
 #include <pthread.h>
@@ -37,6 +39,7 @@ typedef struct program_list_s program_list_t;
 struct program_list_s
 {
   char           *user;
+  char           *group;
   char           *exec;
   int             pid;
   program_list_t *next;
@@ -95,6 +98,12 @@ static int exec_config (const char *key, const char *value)
 
     pl->next = pl_head;
     pl_head = pl;
+
+    pl->group = strchr (pl->user, ':');
+    if (NULL != pl->group) {
+      *pl->group = '\0';
+      pl->group++;
+    }
   }
   else
   {
@@ -108,15 +117,17 @@ static void exec_child (program_list_t *pl)
 {
   int status;
   int uid;
+  int gid;
+  int egid;
   char *arg0;
 
   struct passwd *sp_ptr;
   struct passwd sp;
-  char pwnambuf[2048];
+  char nambuf[2048];
   char errbuf[1024];
 
   sp_ptr = NULL;
-  status = getpwnam_r (pl->user, &sp, pwnambuf, sizeof (pwnambuf), &sp_ptr);
+  status = getpwnam_r (pl->user, &sp, nambuf, sizeof (nambuf), &sp_ptr);
   if (status != 0)
   {
     ERROR ("exec plugin: getpwnam_r failed: %s",
@@ -130,17 +141,67 @@ static void exec_child (program_list_t *pl)
   }
 
   uid = sp.pw_uid;
+  gid = sp.pw_gid;
   if (uid == 0)
   {
     ERROR ("exec plugin: Cowardly refusing to exec program as root.");
     exit (-1);
   }
 
+  /* The group configured in the configfile is set as effective group, because
+   * this way the forked process can (re-)gain the user's primary group. */
+  egid = -1;
+  if (NULL != pl->group)
+  {
+    if ('\0' != *pl->group) {
+      struct group *gr_ptr = NULL;
+      struct group gr;
+
+      status = getgrnam_r (pl->group, &gr, nambuf, sizeof (nambuf), &gr_ptr);
+      if (0 != status)
+      {
+       ERROR ("exec plugin: getgrnam_r failed: %s",
+           sstrerror (errno, errbuf, sizeof (errbuf)));
+       exit (-1);
+      }
+      if (NULL == gr_ptr)
+      {
+       ERROR ("exec plugin: No such group: `%s'", pl->group);
+       exit (-1);
+      }
+
+      egid = gr.gr_gid;
+    }
+    else
+    {
+      egid = gid;
+    }
+  } /* if (pl->group == NULL) */
+
+  status = setgid (gid);
+  if (status != 0)
+  {
+    ERROR ("exec plugin: setgid (%i) failed: %s",
+       gid, sstrerror (errno, errbuf, sizeof (errbuf)));
+    exit (-1);
+  }
+
+  if (egid != -1)
+  {
+    status = setegid (egid);
+    if (status != 0)
+    {
+      ERROR ("exec plugin: setegid (%i) failed: %s",
+         egid, sstrerror (errno, errbuf, sizeof (errbuf)));
+      exit (-1);
+    }
+  }
+
   status = setuid (uid);
   if (status != 0)
   {
-    ERROR ("exec plugin: setuid failed: %s",
-       sstrerror (errno, errbuf, sizeof (errbuf)));
+    ERROR ("exec plugin: setuid (%i) failed: %s",
+       uid, sstrerror (errno, errbuf, sizeof (errbuf)));
     exit (-1);
   }
 
@@ -204,79 +265,13 @@ static int fork_child (program_list_t *pl)
 
 static int parse_line (char *buffer)
 {
-  char *fields[4];
+  char *fields[256];
   int fields_num;
 
-  char *hostname;
-  char *plugin;
-  char *plugin_instance;
-  char *type;
-  char *type_instance;
-
-  const data_set_t *ds;
-  value_list_t vl = VALUE_LIST_INIT;
-
-  int status;
-
-  fields_num = strsplit (buffer, fields, 4);
-  if (fields_num != 2)
-  {
-    WARNING ("exec plugin: Number of fields is not 2.");
-    return (-1);
-  }
-
-  status = parse_identifier (fields[0], &hostname,
-      &plugin, &plugin_instance,
-      &type, &type_instance);
-  if (status != 0)
-  {
-    WARNING ("exec plugin: Cannot parse `%s'", fields[0]);
-    return (-1);
-  }
-
-  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))))
-  {
-    WARNING ("exec plugin: An identifier is too long.");
-    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);
-
-  ds = plugin_get_ds (type);
-  if (ds == NULL)
-  {
-    WARNING ("exec plugin: No such type: `%s'", type);
-    return (-1);
-  }
-
-  vl.values_len = ds->ds_num;
-  vl.values = (value_t *) malloc (sizeof (value_t) * vl.values_len);
-  if (vl.values == NULL)
-    return (-1);
-
-  /* Sets vl.values and vl.time */
-  status = parse_values (fields[1], &vl, ds);
-  if (status != 0)
-  {
-    WARNING ("exec plugin: Cannot parse `%s'", fields[1]);
-    sfree (vl.values);
-    return (-1);
-  }
-
-  plugin_dispatch_values (type, &vl);
+  fields[0] = "PUTVAL";
+  fields_num = strsplit (buffer, &fields[1], STATIC_ARRAY_SIZE(fields) - 1);
 
-  sfree (vl.values);
-  
+  handle_putval (stdout, fields, fields_num + 1);
   return (0);
 } /* int parse_line */
 
index c777465..0432de7 100644 (file)
 #include "plugin.h"
 #include "configfile.h"
 
-#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>
@@ -50,7 +44,6 @@
 #define HDDTEMP_DEF_HOST "127.0.0.1"
 #define HDDTEMP_DEF_PORT "7634"
 
-#if HDDTEMP_HAVE_READ
 static const char *config_keys[] =
 {
        "Host",
@@ -507,16 +500,13 @@ static int hddtemp_read (void)
        
        return (0);
 } /* int hddtemp_read */
-#endif /* HDDTEMP_HAVE_READ */
 
 /* module_register
    Register collectd plugin. */
 void module_register (void)
 {
-#if HDDTEMP_HAVE_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 */
 }
index 52b2ddf..741ff76 100644 (file)
 # 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
+#if !HAVE_GETIFADDRS && !KERNEL_LINUX && !HAVE_LIBKSTAT && !HAVE_LIBSTATGRAB
+# error "No applicable input method."
 #endif
 
 /*
@@ -132,7 +130,6 @@ static int interface_config (const char *key, const char *value)
 #if HAVE_LIBKSTAT
 static int interface_init (void)
 {
-#if HAVE_LIBKSTAT
        kstat_t *ksp_chain;
        unsigned long long val;
 
@@ -155,7 +152,6 @@ static int interface_init (void)
                        continue;
                ksp[numif++] = ksp_chain;
        }
-#endif /* HAVE_LIBKSTAT */
 
        return (0);
 } /* int interface_init */
@@ -181,7 +177,6 @@ static int check_ignore_if (const char *interface)
        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)
@@ -353,7 +348,6 @@ static int interface_read (void)
 
        return (0);
 } /* int interface_read */
-#endif /* INTERFACE_HAVE_READ */
 
 void module_register (void)
 {
@@ -362,7 +356,5 @@ void module_register (void)
 #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 8dc5710..5fa1f40 100644 (file)
 # include <libiptc/libiptc.h>
 #endif
 
-#if HAVE_LIBIPTC_LIBIPTC_H
-# define IPTABLES_HAVE_READ 1
-#else
-# define IPTABLES_HAVE_READ 0
-#endif
-
-#define MODULE_NAME "iptables"
-#define BUFSIZE 512
-
 /*
  * (Module-)Global variables
  */
 
 /*
- * Removed packet count for now, should have config option if you want to save
- * them Although other collectd models don't seem to care much for options
- * eitherway for what to log
- */
-#if IPTABLES_HAVE_READ
-/*
  * Config format should be `Chain table chainname',
  * e. g. `Chain mangle incoming'
  */
@@ -205,9 +190,7 @@ static int iptables_config (const char *key, const char *value)
 
        return (0);
 } /* int iptables_config */
-#endif /* IPTABLES_HAVE_READ */
 
-#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,
@@ -350,21 +333,15 @@ static int iptables_shutdown (void)
 
     return (0);
 } /* int iptables_shutdown */
-#endif /* IPTABLES_HAVE_READ */
 
 void module_register (void)
 {
-#if IPTABLES_HAVE_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
-
 /*
  * vim:shiftwidth=4:softtabstop=4:tabstop=8
  */
index 1c7b5ae..b6b8c4c 100644 (file)
--- a/src/irq.c
+++ b/src/irq.c
 #include "plugin.h"
 #include "configfile.h"
 
-#if KERNEL_LINUX
-# define IRQ_HAVE_READ 1
-#else
-# define IRQ_HAVE_READ 0
+#if !KERNEL_LINUX
+# error "No applicable input method."
 #endif
 
 #define BUFSIZE 128
@@ -36,7 +34,6 @@
 /*
  * (Module-)Global variables
  */
-#if IRQ_HAVE_READ
 static const char *config_keys[] =
 {
        "Irq",
@@ -148,8 +145,6 @@ static void irq_submit (unsigned int irq, counter_t value)
 
 static int irq_read (void)
 {
-#if KERNEL_LINUX
-
 #undef BUFSIZE
 #define BUFSIZE 256
 
@@ -198,19 +193,15 @@ static int irq_read (void)
                irq_submit (irq, irq_value);
        }
        fclose (fh);
-#endif /* KERNEL_LINUX */
 
        return (0);
 } /* int irq_read */
-#endif /* IRQ_HAVE_READ */
 
 void module_register (void)
 {
-#if IRQ_HAVE_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
index 22872f0..c9f130b 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/load.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
 #include "common.h"
 #include "plugin.h"
 
-#if defined(HAVE_GETLOADAVG) || defined(KERNEL_LINUX) || defined(HAVE_LIBSTATGRAB)
-# define LOAD_HAVE_READ 1
-#else
-# define LOAD_HAVE_READ 0
-#endif
-
 #ifdef HAVE_SYS_LOADAVG_H
 #include <sys/loadavg.h>
 #endif
@@ -41,7 +35,6 @@
 #endif
 #endif /* defined(HAVE_GETLOADAVG) */
 
-#if LOAD_HAVE_READ
 static void load_submit (gauge_t snum, gauge_t mnum, gauge_t lnum)
 {
        value_t values[3];
@@ -131,15 +124,16 @@ static int load_read (void)
        lnum = ls->min15;
 
        load_submit (snum, mnum, lnum);
-#endif /* HAVE_LIBSTATGRAB */
+/* #endif HAVE_LIBSTATGRAB */
+
+#else
+# error "No applicable input method."
+#endif
 
        return (0);
 }
-#endif /* LOAD_HAVE_READ */
 
 void module_register (void)
 {
-#if LOAD_HAVE_READ
        plugin_register_read ("load", load_read);
-#endif
 } /* void module_register */
index 7694abc..384ecb5 100644 (file)
 #include "plugin.h"
 #include "configfile.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
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
 
 #define MBMON_DEF_HOST "127.0.0.1"
 #define MBMON_DEF_PORT "411" /* the default for Debian */
@@ -47,7 +42,6 @@ static const char *config_keys[] =
 };
 static int config_keys_num = 2;
 
-#if MBMON_HAVE_READ
 static char *mbmon_host = NULL;
 static char *mbmon_port = NULL;
 
@@ -308,14 +302,11 @@ static int mbmon_read (void)
 
        return (0);
 } /* void mbmon_read */
-#endif /* MBMON_HAVE_READ */
 
 /* module_register
    Register collectd plugin. */
 void module_register (void)
 {
-#if MBMON_HAVE_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 cb7e688..3fbd33f 100644 (file)
 # include <mach/vm_statistics.h>
 #endif
 
-#if defined (HOST_VM_INFO) || HAVE_SYSCTLBYNAME || KERNEL_LINUX || HAVE_LIBKSTAT
-# define MEMORY_HAVE_READ 1
-#else
-# define MEMORY_HAVE_READ 0
-#endif
-
 /* vm_statistics_data_t */
-#if defined(HOST_VM_INFO)
+#if HAVE_HOST_STATISTICS
 static mach_port_t port_host;
 static vm_size_t pagesize;
-/* #endif HOST_VM_INFO */
+/* #endif HAVE_HOST_STATISTICS */
 
 #elif HAVE_SYSCTLBYNAME
 /* no global variables */
@@ -66,15 +60,18 @@ static vm_size_t pagesize;
 #elif HAVE_LIBKSTAT
 static int pagesize;
 static kstat_t *ksp;
-#endif /* HAVE_LIBKSTAT */
+/* #endif HAVE_LIBKSTAT */
+
+#else
+# error "No applicable input method."
+#endif
 
-#if MEMORY_HAVE_READ
 static int memory_init (void)
 {
-#if defined(HOST_VM_INFO)
+#if HAVE_HOST_STATISTICS
        port_host = mach_host_self ();
        host_page_size (port_host, &pagesize);
-/* #endif HOST_VM_INFO */
+/* #endif HAVE_HOST_STATISTICS */
 
 #elif HAVE_SYSCTLBYNAME
 /* no init stuff */
@@ -114,7 +111,7 @@ static void memory_submit (const char *type_instance, gauge_t value)
 
 static int memory_read (void)
 {
-#if defined(HOST_VM_INFO)
+#if HAVE_HOST_STATISTICS
        kern_return_t status;
        vm_statistics_data_t   vm_data;
        mach_msg_type_number_t vm_data_len;
@@ -165,7 +162,7 @@ static int memory_read (void)
        memory_submit ("active",   active);
        memory_submit ("inactive", inactive);
        memory_submit ("free",     free);
-/* #endif HOST_VM_INFO */
+/* #endif HAVE_HOST_STATISTICS */
 
 #elif HAVE_SYSCTLBYNAME
        /*
@@ -321,12 +318,9 @@ static int memory_read (void)
 
        return (0);
 }
-#endif /* MEMORY_HAVE_READ */
 
 void module_register (void)
 {
-#if MEMORY_HAVE_READ
        plugin_register_init ("memory", memory_init);
        plugin_register_read ("memory", memory_read);
-#endif /* MEMORY_HAVE_READ */
 } /* void module_register */
index 21a2144..11ca42c 100644 (file)
 # 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!"
+# error "No applicable input method."
 #endif
 
-#if MULTIMETER_HAVE_READ
 static int fd = -1;
 
 static int multimeter_timeval_sub (struct timeval *tv1, struct timeval *tv2,
@@ -58,6 +55,7 @@ static int multimeter_timeval_sub (struct timeval *tv1, struct timeval *tv2,
         }
        return (0);
 }
+
 #define LINE_LENGTH 14
 static int multimeter_read_value(double *value)
 {
@@ -248,13 +246,10 @@ static int multimeter_shutdown (void)
 
        return (0);
 }
-#endif /* MULTIMETER_HAVE_READ */
 
 void module_register (void)
 {
-#if MULTIMETER_HAVE_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 9014e5f..d472853 100644 (file)
 #include <mysql/mysql.h>
 #endif
 
-#if HAVE_LIBMYSQLCLIENT
-# define MYSQL_HAVE_READ 1
-#else
-# define MYSQL_HAVE_READ 0
-#endif
-
 /* TODO: Understand `Select_*' and possibly do that stuff as well.. */
 
-#if MYSQL_HAVE_READ
 static const char *config_keys[] =
 {
        "Host",
@@ -322,12 +315,9 @@ static int mysql_read (void)
 
        return (0);
 } /* int mysql_read */
-#endif /* MYSQL_HAVE_READ */
 
 void module_register (void)
 {
-#if MYSQL_HAVE_READ
        plugin_register_config ("mysql", config, config_keys, config_keys_num);
        plugin_register_read ("mysql", mysql_read);
-#endif /* MYSQL_HAVE_READ */
 } /* void module_register */
diff --git a/src/netlink.c b/src/netlink.c
new file mode 100644 (file)
index 0000000..22afdc7
--- /dev/null
@@ -0,0 +1,648 @@
+/**
+ * collectd - src/netlink.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"
+
+#include <asm/types.h>
+#include <sys/socket.h>
+
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#if HAVE_LINUX_GEN_STATS_H
+# include <linux/gen_stats.h>
+#endif
+#if HAVE_LINUX_PKT_SCHED_H
+# include <linux/pkt_sched.h>
+#endif
+
+#if HAVE_LIBNETLINK_H
+# include <libnetlink.h>
+#elif HAVE_IPROUTE_LIBNETLINK_H
+# include <iproute/libnetlink.h>
+#elif HAVE_LINUX_LIBNETLINK_H
+# include <linux/libnetlink.h>
+#endif
+
+typedef struct ir_ignorelist_s
+{
+  char *device;
+  char *type;
+  char *inst;
+  struct ir_ignorelist_s *next;
+} ir_ignorelist_t;
+
+static int ir_ignorelist_invert = 1;
+static ir_ignorelist_t *ir_ignorelist_head = NULL;
+
+static struct rtnl_handle rth;
+
+static char **iflist = NULL;
+static size_t iflist_len = 0;
+
+static const char *config_keys[] =
+{
+       "Interface",
+       "VerboseInterface",
+       "QDisc",
+       "Class",
+       "Filter",
+       "IgnoreSelected"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static int add_ignorelist (const char *dev, const char *type,
+    const char *inst)
+{
+  ir_ignorelist_t *entry;
+
+  entry = (ir_ignorelist_t *) malloc (sizeof (ir_ignorelist_t));
+  if (entry == NULL)
+    return (-1);
+
+  memset (entry, '\0', sizeof (ir_ignorelist_t));
+
+  if (strcasecmp (dev, "All") != 0)
+  {
+    entry->device = strdup (dev);
+    if (entry->device == NULL)
+    {
+      sfree (entry);
+      return (-1);
+    }
+  }
+
+  entry->type = strdup (type);
+  if (entry->type == NULL)
+  {
+    sfree (entry->device);
+    sfree (entry);
+    return (-1);
+  }
+
+  if (inst != NULL)
+  {
+    entry->inst = strdup (inst);
+    if (entry->inst == NULL)
+    {
+      sfree (entry->type);
+      sfree (entry->device);
+      sfree (entry);
+      return (-1);
+    }
+  }
+
+  entry->next = ir_ignorelist_head;
+  ir_ignorelist_head = entry;
+
+  return (0);
+} /* int add_ignorelist */
+
+/* 
+ * Checks wether a data set should be ignored. Returns `true' is the value
+ * should be ignored, `false' otherwise.
+ */
+static int check_ignorelist (const char *dev,
+    const char *type, const char *type_instance)
+{
+  ir_ignorelist_t *i;
+
+  assert ((dev != NULL) && (type != NULL));
+
+  if (ir_ignorelist_head == NULL)
+    return (ir_ignorelist_invert ? 0 : 1);
+
+  for (i = ir_ignorelist_head; i != NULL; i = i->next)
+  {
+    /* i->device == NULL  =>  match all devices */
+    if ((i->device != NULL)
+       && (strcasecmp (i->device, dev) != 0))
+      continue;
+
+    if (strcasecmp (i->type, type) != 0)
+      continue;
+
+    if ((i->inst != NULL) && (type_instance != NULL)
+       && (strcasecmp (i->inst, type_instance) != 0))
+      continue;
+
+    DEBUG ("netlink plugin: check_ignorelist: "
+       "(dev = %s; type = %s; inst = %s) matched "
+       "(dev = %s; type = %s; inst = %s)",
+       dev, type,
+       type_instance == NULL ? "(nil)" : type_instance,
+       i->device == NULL ? "(nil)" : i->device,
+       i->type,
+       i->inst == NULL ? "(nil)" : i->inst);
+
+    return (ir_ignorelist_invert ? 0 : 1);
+  } /* for i */
+
+  return (ir_ignorelist_invert);
+} /* int check_ignorelist */
+
+static void submit_one (const char *dev, const char *type,
+    const char *type_instance, counter_t value)
+{
+  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, "netlink");
+  strncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
+
+  if (type_instance != NULL)
+    strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+  plugin_dispatch_values (type, &vl);
+} /* void submit_one */
+
+static void submit_two (const char *dev, const char *type,
+    const char *type_instance,
+    counter_t rx, counter_t tx)
+{
+  value_t values[2];
+  value_list_t vl = VALUE_LIST_INIT;
+
+  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, "netlink");
+  strncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
+
+  if (type_instance != NULL)
+    strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+  plugin_dispatch_values (type, &vl);
+} /* void submit_two */
+
+static int link_filter (const struct sockaddr_nl *sa,
+    const struct nlmsghdr *nmh, void *args)
+{
+  struct ifinfomsg *msg;
+  int msg_len;
+  struct rtattr *attrs[IFLA_MAX + 1];
+  struct rtnl_link_stats *stats;
+
+  const char *dev;
+
+  if (nmh->nlmsg_type != RTM_NEWLINK)
+  {
+    ERROR ("netlink plugin: link_filter: Don't know how to handle type %i.",
+       nmh->nlmsg_type);
+    return (-1);
+  }
+
+  msg = NLMSG_DATA (nmh);
+
+  msg_len = nmh->nlmsg_len - sizeof (struct ifinfomsg);
+  if (msg_len < 0)
+  {
+    ERROR ("netlink plugin: link_filter: msg_len = %i < 0;", msg_len);
+    return (-1);
+  }
+
+  memset (attrs, '\0', sizeof (attrs));
+  if (parse_rtattr (attrs, IFLA_MAX, IFLA_RTA (msg), msg_len) != 0)
+  {
+    ERROR ("netlink plugin: link_filter: parse_rtattr failed.");
+    return (-1);
+  }
+
+  if (attrs[IFLA_IFNAME] == NULL)
+  {
+    ERROR ("netlink plugin: link_filter: attrs[IFLA_IFNAME] == NULL");
+    return (-1);
+  }
+  dev = RTA_DATA (attrs[IFLA_IFNAME]);
+
+  /* Update the `iflist'. It's used to know which interfaces exist and query
+   * them later for qdiscs and classes. */
+  if (msg->ifi_index >= iflist_len)
+  {
+    char **temp;
+
+    temp = (char **) realloc (iflist, (msg->ifi_index + 1) * sizeof (char *));
+    if (temp == NULL)
+    {
+      ERROR ("netlink plugin: link_filter: realloc failed.");
+      return (-1);
+    }
+
+    memset (temp + iflist_len, '\0',
+       (msg->ifi_index + 1 - iflist_len) * sizeof (char *));
+    iflist = temp;
+    iflist_len = msg->ifi_index + 1;
+  }
+  if ((iflist[msg->ifi_index] == NULL)
+      || (strcmp (iflist[msg->ifi_index], dev) != 0))
+  {
+    sfree (iflist[msg->ifi_index]);
+    iflist[msg->ifi_index] = strdup (dev);
+  }
+
+  if (attrs[IFLA_STATS] == NULL)
+  {
+    DEBUG ("netlink plugin: link_filter: No statistics for interface %s.", dev);
+    return (0);
+  }
+  stats = RTA_DATA (attrs[IFLA_STATS]);
+
+  if (check_ignorelist (dev, "interface", NULL) == 0)
+  {
+    submit_two (dev, "if_octets", NULL, stats->rx_bytes, stats->tx_bytes);
+    submit_two (dev, "if_packets", NULL, stats->rx_packets, stats->tx_packets);
+    submit_two (dev, "if_errors", NULL, stats->rx_errors, stats->tx_errors);
+  }
+  else
+  {
+    DEBUG ("netlink plugin: Ignoring %s/interface.", dev);
+  }
+
+  if (check_ignorelist (dev, "if_detail", NULL) == 0)
+  {
+    submit_two (dev, "if_dropped", NULL, stats->rx_dropped, stats->tx_dropped);
+    submit_one (dev, "if_multicast", NULL, stats->multicast);
+    submit_one (dev, "if_collisions", NULL, stats->collisions);
+
+    submit_one (dev, "if_rx_errors", "length", stats->rx_length_errors);
+    submit_one (dev, "if_rx_errors", "over", stats->rx_over_errors);
+    submit_one (dev, "if_rx_errors", "crc", stats->rx_crc_errors);
+    submit_one (dev, "if_rx_errors", "frame", stats->rx_frame_errors);
+    submit_one (dev, "if_rx_errors", "fifo", stats->rx_fifo_errors);
+    submit_one (dev, "if_rx_errors", "missed", stats->rx_missed_errors);
+
+    submit_one (dev, "if_tx_errors", "aborted", stats->tx_aborted_errors);
+    submit_one (dev, "if_tx_errors", "carrier", stats->tx_carrier_errors);
+    submit_one (dev, "if_tx_errors", "fifo", stats->tx_fifo_errors);
+    submit_one (dev, "if_tx_errors", "heartbeat", stats->tx_heartbeat_errors);
+    submit_one (dev, "if_tx_errors", "window", stats->tx_window_errors);
+  }
+  else
+  {
+    DEBUG ("netlink plugin: Ignoring %s/if_detail.", dev);
+  }
+
+  return (0);
+} /* int link_filter */
+
+static int qos_filter (const struct sockaddr_nl *sa,
+    const struct nlmsghdr *nmh, void *args)
+{
+  struct tcmsg *msg;
+  int msg_len;
+  struct rtattr *attrs[TCA_MAX + 1];
+
+  int wanted_ifindex = *((int *) args);
+
+  const char *dev;
+
+  /* char *type_instance; */
+  char *tc_type;
+  char tc_inst[DATA_MAX_NAME_LEN];
+
+  if (nmh->nlmsg_type == RTM_NEWQDISC)
+    tc_type = "qdisc";
+  else if (nmh->nlmsg_type == RTM_NEWTCLASS)
+    tc_type = "class";
+  else if (nmh->nlmsg_type == RTM_NEWTFILTER)
+    tc_type = "filter";
+  else
+  {
+    ERROR ("netlink plugin: qos_filter: Don't know how to handle type %i.",
+       nmh->nlmsg_type);
+    return (-1);
+  }
+
+  msg = NLMSG_DATA (nmh);
+
+  msg_len = nmh->nlmsg_len - sizeof (struct tcmsg);
+  if (msg_len < 0)
+  {
+    ERROR ("netlink plugin: qos_filter: msg_len = %i < 0;", msg_len);
+    return (-1);
+  }
+
+  if (msg->tcm_ifindex != wanted_ifindex)
+  {
+    DEBUG ("netlink plugin: qos_filter: Got %s for interface #%i, "
+       "but expected #%i.",
+       tc_type, msg->tcm_ifindex, wanted_ifindex);
+    return (0);
+  }
+
+  if (msg->tcm_ifindex >= iflist_len)
+  {
+    ERROR ("netlink plugin: qos_filter: msg->tcm_ifindex = %i "
+       ">= iflist_len = %i",
+       msg->tcm_ifindex, iflist_len);
+    return (-1);
+  }
+
+  dev = iflist[msg->tcm_ifindex];
+  if (dev == NULL)
+  {
+    ERROR ("netlink plugin: qos_filter: iflist[%i] == NULL",
+       msg->tcm_ifindex);
+    return (-1);
+  }
+
+  memset (attrs, '\0', sizeof (attrs));
+  if (parse_rtattr (attrs, TCA_MAX, TCA_RTA (msg), msg_len) != 0)
+  {
+    ERROR ("netlink plugin: qos_filter: parse_rtattr failed.");
+    return (-1);
+  }
+
+  if (attrs[TCA_KIND] == NULL)
+  {
+    ERROR ("netlink plugin: qos_filter: attrs[TCA_KIND] == NULL");
+    return (-1);
+  }
+
+  { /* The the ID */
+    uint32_t numberic_id;
+
+    numberic_id = msg->tcm_handle;
+    if (strcmp (tc_type, "filter") == 0)
+      numberic_id = msg->tcm_parent;
+
+    snprintf (tc_inst, sizeof (tc_inst), "%s-%x:%x",
+       (const char *) RTA_DATA (attrs[TCA_KIND]),
+       numberic_id >> 16,
+       numberic_id & 0x0000FFFF);
+    tc_inst[sizeof (tc_inst) - 1] = '\0';
+  }
+
+  DEBUG ("netlink plugin: qos_filter: got %s for %s (%i).",
+      tc_type, dev, msg->tcm_ifindex);
+  
+  if (check_ignorelist (dev, tc_type, tc_inst))
+    return (0);
+
+#if HAVE_TCA_STATS2
+  if (attrs[TCA_STATS2])
+  {
+    struct rtattr *attrs_stats[TCA_STATS_MAX + 1];
+
+    memset (attrs_stats, '\0', sizeof (attrs_stats));
+    parse_rtattr_nested (attrs_stats, TCA_STATS_MAX, attrs[TCA_STATS2]);
+
+    if (attrs_stats[TCA_STATS_BASIC])
+    {
+      struct gnet_stats_basic bs;
+      char type_instance[DATA_MAX_NAME_LEN];
+
+      snprintf (type_instance, sizeof (type_instance), "%s-%s",
+         tc_type, tc_inst);
+      type_instance[sizeof (type_instance) - 1] = '\0';
+
+      memset (&bs, '\0', sizeof (bs));
+      memcpy (&bs, RTA_DATA (attrs_stats[TCA_STATS_BASIC]),
+         MIN (RTA_PAYLOAD (attrs_stats[TCA_STATS_BASIC]), sizeof(bs)));
+
+      submit_one (dev, "ipt_bytes", type_instance, bs.bytes);
+      submit_one (dev, "ipt_packets", type_instance, bs.packets);
+    }
+  }
+#endif /* TCA_STATS2 */
+#if HAVE_TCA_STATS && HAVE_TCA_STATS2
+  else
+#endif
+#if HAVE_TCA_STATS
+  if (attrs[TCA_STATS] != NULL)
+  {
+    struct tc_stats ts;
+    char type_instance[DATA_MAX_NAME_LEN];
+
+    snprintf (type_instance, sizeof (type_instance), "%s-%s",
+       tc_type, tc_inst);
+    type_instance[sizeof (type_instance) - 1] = '\0';
+
+    memset(&ts, '\0', sizeof (ts));
+    memcpy(&ts, RTA_DATA (attrs[TCA_STATS]),
+       MIN (RTA_PAYLOAD (attrs[TCA_STATS]), sizeof (ts)));
+
+    submit_one (dev, "ipt_bytes", type_instance, ts.bytes);
+    submit_one (dev, "ipt_packets", type_instance, ts.packets);
+  }
+#endif /* TCA_STATS */
+#if HAVE_TCA_STATS || HAVE_TCA_STATS2
+  else
+#endif
+  {
+    DEBUG ("netlink plugin: qos_filter: Have neither TCA_STATS2 nor "
+       "TCA_STATS.");
+  }
+
+  return (0);
+} /* int qos_filter */
+
+static int ir_config (const char *key, const char *value)
+{
+  char *new_val;
+  char *fields[8];
+  int fields_num;
+  int status = 1;
+
+  new_val = strdup (value);
+  if (new_val == NULL)
+    return (-1);
+
+  fields_num = strsplit (new_val, fields, STATIC_ARRAY_SIZE (fields));
+  if ((fields_num < 1) || (fields_num > 8))
+  {
+    sfree (new_val);
+    return (-1);
+  }
+
+  if ((strcasecmp (key, "Interface") == 0)
+      || (strcasecmp (key, "VerboseInterface") == 0))
+  {
+    if (fields_num != 1)
+    {
+      ERROR ("netlink plugin: Invalid number of fields for option "
+         "`%s'. Got %i, expected 1.", key, fields_num);
+      status = -1;
+    }
+    else
+    {
+      add_ignorelist (fields[0], "interface", NULL);
+      if (strcasecmp (key, "VerboseInterface") == 0)
+       add_ignorelist (fields[0], "if_detail", NULL);
+      status = 0;
+    }
+  }
+  else if ((strcasecmp (key, "QDisc") == 0)
+      || (strcasecmp (key, "Class") == 0)
+      || (strcasecmp (key, "Filter") == 0))
+  {
+    if ((fields_num < 1) || (fields_num > 2))
+    {
+      ERROR ("netlink plugin: Invalid number of fields for option "
+         "`%s'. Got %i, expected 1 or 2.", key, fields_num);
+      return (-1);
+    }
+    else
+    {
+      add_ignorelist (fields[0], key,
+         (fields_num == 2) ? fields[1] : NULL);
+      status = 0;
+    }
+  }
+  else if (strcasecmp (key, "IgnoreSelected") == 0)
+  {
+    if (fields_num != 1)
+    {
+      ERROR ("netlink plugin: Invalid number of fields for option "
+         "`IgnoreSelected'. Got %i, expected 1.", fields_num);
+      status = -1;
+    }
+    else
+    {
+      if ((strcasecmp (fields[0], "yes") == 0)
+         || (strcasecmp (fields[0], "true") == 0)
+         || (strcasecmp (fields[0], "on") == 0))
+       ir_ignorelist_invert = 0;
+      else
+       ir_ignorelist_invert = 1;
+      status = 0;
+    }
+  }
+
+  sfree (new_val);
+
+  return (status);
+} /* int ir_config */
+
+static int ir_init (void)
+{
+  memset (&rth, '\0', sizeof (rth));
+
+  if (rtnl_open (&rth, 0) != 0)
+  {
+    ERROR ("netlink plugin: ir_init: rtnl_open failed.");
+    return (-1);
+  }
+
+  return (0);
+} /* int ir_init */
+
+static int ir_read (void)
+{
+  struct ifinfomsg im;
+  struct tcmsg tm;
+  int ifindex;
+
+  static const int type_id[] = { RTM_GETQDISC, RTM_GETTCLASS, RTM_GETTFILTER };
+  static const char *type_name[] = { "qdisc", "class", "filter" };
+
+  memset (&im, '\0', sizeof (im));
+  im.ifi_type = AF_UNSPEC;
+
+  if (rtnl_dump_request (&rth, RTM_GETLINK, &im, sizeof (im)) < 0)
+  {
+    ERROR ("netlink plugin: ir_read: rtnl_dump_request failed.");
+    return (-1);
+  }
+
+  if (rtnl_dump_filter (&rth, link_filter, /* arg1 = */ NULL,
+       NULL, NULL) != 0)
+  {
+    ERROR ("netlink plugin: ir_read: rtnl_dump_filter failed.");
+    return (-1);
+  }
+
+  /* `link_filter' will update `iflist' which is used here to iterate over all
+   * interfaces. */
+  for (ifindex = 0; ifindex < iflist_len; ifindex++)
+  {
+    int type_index;
+
+    if (iflist[ifindex] == NULL)
+      continue;
+
+    for (type_index = 0; type_index < STATIC_ARRAY_SIZE (type_id); type_index++)
+    {
+      if (check_ignorelist (iflist[ifindex], type_name[type_index], NULL))
+      {
+       DEBUG ("netlink plugin: ir_read: check_ignorelist (%s, %s, (nil)) "
+           "== TRUE", iflist[ifindex], type_name[type_index]);
+       continue;
+      }
+
+      DEBUG ("netlink plugin: ir_read: querying %s from %s (%i).",
+         type_name[type_index], iflist[ifindex], ifindex);
+
+      memset (&tm, '\0', sizeof (tm));
+      tm.tcm_family = AF_UNSPEC;
+      tm.tcm_ifindex = ifindex;
+
+      if (rtnl_dump_request (&rth, type_id[type_index], &tm, sizeof (tm)) < 0)
+      {
+       ERROR ("netlink plugin: ir_read: rtnl_dump_request failed.");
+       continue;
+      }
+
+      if (rtnl_dump_filter (&rth, qos_filter, (void *) &ifindex,
+           NULL, NULL) != 0)
+      {
+       ERROR ("netlink plugin: ir_read: rtnl_dump_filter failed.");
+       continue;
+      }
+    } /* for (type_index) */
+  } /* for (if_index) */
+
+  return (0);
+} /* int ir_read */
+
+static int ir_shutdown (void)
+{
+  if ((rth.fd != 0) || (rth.seq != 0) || (rth.dump != 0))
+  {
+    rtnl_close(&rth);
+    memset (&rth, '\0', sizeof (rth));
+  }
+  
+  return (0);
+} /* int ir_shutdown */
+
+void module_register (void)
+{
+  plugin_register_config ("netlink", ir_config, config_keys, config_keys_num);
+  plugin_register_init ("netlink", ir_init);
+  plugin_register_read ("netlink", ir_read);
+  plugin_register_shutdown ("netlink", ir_shutdown);
+} /* void module_register */
+
+/*
+ * vim: set shiftwidth=2 softtabstop=2 tabstop=8 :
+ */
index 164759b..c81d711 100644 (file)
@@ -162,7 +162,7 @@ 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 value_list_t send_buffer_vl = VALUE_LIST_STATIC;
 static char         send_buffer_type[DATA_MAX_NAME_LEN];
 static pthread_mutex_t send_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
 
@@ -557,6 +557,13 @@ static int parse_packet (void *buffer, int buffer_len)
                        if (status == 0)
                                vl.time = (time_t) tmp;
                }
+               else if (ntohs (header->type) == TYPE_INTERVAL)
+               {
+                       uint64_t tmp = 0;
+                       status = parse_part_number (&buffer, &buffer_len, &tmp);
+                       if (status == 0)
+                               vl.interval = (int) tmp;
+               }
                else if (ntohs (header->type) == TYPE_HOST)
                {
                        status = parse_part_string (&buffer, &buffer_len,
@@ -1094,6 +1101,16 @@ static int add_to_buffer (char *buffer, int buffer_size,
                vl_def->time = vl->time;
        }
 
+       if (vl_def->interval != vl->interval)
+       {
+               if (write_part_number (&buffer, &buffer_size, TYPE_INTERVAL,
+                                       (uint64_t) vl->interval))
+                       return (-1);
+               vl_def->interval = vl->interval;
+               DEBUG ("network plugin: add_to_buffer: interval = %i",
+                               (int) vl->interval);
+       }
+
        if (strcmp (vl_def->plugin, vl->plugin) != 0)
        {
                if (write_part_string (&buffer, &buffer_size, TYPE_PLUGIN,
index b20fc75..6d8e966 100644 (file)
@@ -61,5 +61,6 @@
 #define TYPE_TYPE            0x0004
 #define TYPE_TYPE_INSTANCE   0x0005
 #define TYPE_VALUES          0x0006
+#define TYPE_INTERVAL        0x0007
 
 #endif /* NETWORK_H */
index 299d63b..77c7f48 100644 (file)
--- a/src/nfs.c
+++ b/src/nfs.c
 #include "common.h"
 #include "plugin.h"
 
-/* #if defined(KERNEL_LINUX) || defined(HAVE_LIBKSTAT) */
-#if KERNEL_LINUX
-# define NFS_HAVE_READ 1
-#else
-# define NFS_HAVE_READ 0
+#if !KERNEL_LINUX
+# error "No applicable input method."
 #endif
 
 /*
@@ -76,7 +73,6 @@ Number      Procedures  Procedures
 21                      commit
 */
 
-#if NFS_HAVE_READ
 static const char *nfs2_procedures_names[] =
 {
        "null",
@@ -209,7 +205,6 @@ static void nfs_procedures_submit (const char *plugin_instance,
        }
 } /* void nfs_procedures_submit */
 
-#if KERNEL_LINUX
 static void nfs_read_stats_file (FILE *fh, char *inst)
 {
        char buffer[BUFSIZE];
@@ -307,7 +302,6 @@ static void nfs_read_stats_file (FILE *fh, char *inst)
                }
        } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
 } /* void nfs_read_stats_file */
-#endif /* defined(KERNEL_LINUX) */
 #undef BUFSIZE
 
 #if HAVE_LIBKSTAT && 0
@@ -340,7 +334,6 @@ static void nfs2_read_kstat (kstat_t *ksp, char *inst)
 
 static int nfs_read (void)
 {
-#if KERNEL_LINUX
        FILE *fh;
 
        if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
@@ -355,9 +348,7 @@ static int nfs_read (void)
                fclose (fh);
        }
 
-/* #endif defined(KERNEL_LINUX) */
-
-#elif HAVE_LIBKSTAT && 0
+#if HAVE_LIBKSTAT && 0
        if (nfs2_ksp_client != NULL)
                nfs2_read_kstat (nfs2_ksp_client, "client");
        if (nfs2_ksp_server != NULL)
@@ -366,11 +357,8 @@ static int nfs_read (void)
 
        return (0);
 }
-#endif /* NFS_HAVE_READ */
 
 void module_register (void)
 {
-#if NFS_HAVE_READ
        plugin_register_read ("nfs", nfs_read);
-#endif
 } /* void module_register */
index 6905fb2..63b037a 100644 (file)
 #include "plugin.h"
 #include "configfile.h"
 
-#if HAVE_SYS_SOCKET_H
-# define NTPD_HAVE_READ 1
-#else
-# define NTPD_HAVE_READ 0
-#endif
-
 #if HAVE_STDINT_H
 # include <stdint.h>
 #endif
@@ -60,7 +54,6 @@ static const char *config_keys[] =
 };
 static int config_keys_num = 2;
 
-#if NTPD_HAVE_READ
 # define NTPD_DEFAULT_HOST "localhost"
 # define NTPD_DEFAULT_PORT "123"
 static int   sock_descr = -1;
@@ -958,13 +951,10 @@ static int ntpd_read (void)
 
        return (0);
 } /* int ntpd_read */
-#endif /* NTPD_HAVE_READ */
 
 void module_register (void)
 {
-#if NTPD_HAVE_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 */
index 087604f..f7f026a 100644 (file)
--- a/src/nut.c
+++ b/src/nut.c
 #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
+#include <pthread.h>
+#include <upsclient.h>
 
 #if HAVE_UPSCONN_T
 typedef UPSCONN_t collectd_upsconn_t;
@@ -42,8 +34,6 @@ typedef UPSCONN collectd_upsconn_t;
 # error "Unable to determine the UPS connection type."
 #endif
 
-
-#if NUT_HAVE_READ
 struct nut_ups_s;
 typedef struct nut_ups_s nut_ups_t;
 struct nut_ups_s
@@ -295,15 +285,12 @@ static int nut_shutdown (void)
 
   return (0);
 } /* int nut_shutdown */
-#endif /* NUT_HAVE_READ */
 
 void module_register (void)
 {
-#if NUT_HAVE_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 e985dac..23ea901 100644 (file)
@@ -194,7 +194,7 @@ static void *plugin_read_thread (void *args)
                                        rf->wait_time = 86400;
 
                                NOTICE ("read-function of plugin `%s' "
-                                               "failed. Will syspend it for %i "
+                                               "failed. Will suspend it for %i "
                                                "seconds.", le->key, rf->wait_left);
                        }
                        else
@@ -378,6 +378,12 @@ int plugin_register_config (const char *name,
        return (0);
 } /* int plugin_register_config */
 
+int plugin_register_complex_config (const char *type,
+               int (*callback) (oconfig_item_t *))
+{
+       return (cf_register_complex (type, callback));
+} /* int plugin_register_complex_config */
+
 int plugin_register_init (const char *name,
                int (*callback) (void))
 {
@@ -462,6 +468,12 @@ int plugin_unregister_config (const char *name)
        return (0);
 } /* int plugin_unregister_config */
 
+int plugin_unregister_complex_config (const char *name)
+{
+       cf_unregister_complex (name);
+       return (0);
+} /* int plugin_unregister_complex_config */
+
 int plugin_unregister_init (const char *name)
 {
        return (plugin_unregister (list_init, name));
@@ -640,10 +652,12 @@ int plugin_dispatch_values (const char *name, value_list_t *vl)
 
        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,
+       DEBUG ("plugin: plugin_dispatch_values: time = %u; interval = %i; "
+                       "host = %s; "
+                       "plugin = %s; plugin_instance = %s; "
+                       "type = %s; type_instance = %s;",
+                       (unsigned int) vl->time, vl->interval,
+                       vl->host,
                        vl->plugin, vl->plugin_instance,
                        ds->type, vl->type_instance);
 
index 83c2109..4ca6c77 100644 (file)
@@ -1,9 +1,8 @@
 #ifndef PLUGIN_H
 #define PLUGIN_H
-
 /**
  * collectd - src/plugin.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 License as published by the
@@ -22,6 +21,9 @@
  *   Florian octo Forster <octo at verplant.org>
  **/
 
+#include "collectd.h"
+#include "configfile.h"
+
 #define DATA_MAX_NAME_LEN 64
 
 #define DS_TYPE_COUNTER 0
@@ -61,6 +63,7 @@ struct value_list_s
        value_t *values;
        int      values_len;
        time_t   time;
+       int      interval;
        char     host[DATA_MAX_NAME_LEN];
        char     plugin[DATA_MAX_NAME_LEN];
        char     plugin_instance[DATA_MAX_NAME_LEN];
@@ -68,7 +71,8 @@ struct value_list_s
 };
 typedef struct value_list_s value_list_t;
 
-#define VALUE_LIST_INIT { NULL, 0, 0, "localhost", "", "", "" }
+#define VALUE_LIST_INIT { NULL, 0, 0, interval_g, "localhost", "", "", "" }
+#define VALUE_LIST_STATIC { NULL, 0, 0, 0, "localhost", "", "", "" }
 
 struct data_source_s
 {
@@ -143,6 +147,8 @@ void plugin_shutdown_all (void);
 int plugin_register_config (const char *name,
                int (*callback) (const char *key, const char *val),
                const char **keys, int keys_num);
+int plugin_register_complex_config (const char *type,
+               int (*callback) (oconfig_item_t *));
 int plugin_register_init (const char *name,
                int (*callback) (void));
 int plugin_register_read (const char *name,
@@ -156,6 +162,7 @@ int plugin_register_log (char *name,
                void (*callback) (int, const char *));
 
 int plugin_unregister_config (const char *name);
+int plugin_unregister_complex_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);
@@ -163,6 +170,7 @@ int plugin_unregister_shutdown (const char *name);
 int plugin_unregister_data_set (const char *name);
 int plugin_unregister_log (const char *name);
 
+
 /*
  * NAME
  *  plugin_dispatch_values
index 5d257f5..22d369d 100644 (file)
 #  ifndef CONFIG_HZ
 #    define CONFIG_HZ 100
 #  endif
-#endif /* KERNEL_LINUX */
-
-#define MODULE_NAME "processes"
+/* #endif KERNEL_LINUX */
 
-#if HAVE_THREAD_INFO || KERNEL_LINUX
-# define PROCESSES_HAVE_READ 1
 #else
-# define PROCESSES_HAVE_READ 0
+# error "No applicable input method."
 #endif
 
 #define BUFSIZE 256
 
-#if PROCESSES_HAVE_READ
-#if HAVE_THREAD_INFO | KERNEL_LINUX
 static const char *config_keys[] =
 {
        "Process",
        NULL
 };
 static int config_keys_num = 1;
-#endif
 
 typedef struct procstat_entry_s
 {
@@ -143,9 +136,7 @@ typedef struct procstat
        struct procstat_entry_s *instances;
 } procstat_t;
 
-#if HAVE_THREAD_INFO | KERNEL_LINUX
 static procstat_t *list_head_g = NULL;
-#endif
 
 #if HAVE_THREAD_INFO
 static mach_port_t port_host_self;
@@ -159,7 +150,6 @@ static mach_msg_type_number_t     pset_list_len;
 static long pagesize_g;
 #endif /* KERNEL_LINUX */
 
-#if HAVE_THREAD_INFO | KERNEL_LINUX
 static void ps_list_register (const char *name)
 {
        procstat_t *new;
@@ -370,7 +360,6 @@ static int ps_config (const char *key, const char *value)
 
        return (0);
 }
-#endif /* HAVE_THREAD_INFO | KERNEL_LINUX */
 
 static int ps_init (void)
 {
@@ -1021,16 +1010,11 @@ static int ps_read (void)
 
        return (0);
 } /* int ps_read */
-#endif /* PROCESSES_HAVE_READ */
 
 void module_register (void)
 {
-#if PROCESSES_HAVE_READ
-#if HAVE_THREAD_INFO | KERNEL_LINUX
        plugin_register_config ("processes", ps_config,
                        config_keys, config_keys_num);
-#endif
        plugin_register_init ("processes", ps_init);
        plugin_register_read ("processes", ps_read);
-#endif /* PROCESSES_HAVE_READ */
 } /* void module_register */
index 8ad0106..77d8716 100644 (file)
@@ -37,9 +37,21 @@ struct rrd_cache_s
        char **values;
        time_t first_value;
        time_t last_value;
+       enum
+       {
+               FLAG_NONE   = 0x00,
+               FLAG_QUEUED = 0x01
+       } flags;
 };
 typedef struct rrd_cache_s rrd_cache_t;
 
+struct rrd_queue_s
+{
+       char *filename;
+       struct rrd_queue_s *next;
+};
+typedef struct rrd_queue_s rrd_queue_t;
+
 /*
  * Private variables
  */
@@ -77,25 +89,54 @@ static const char *config_keys[] =
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
+/* If datadir is zero, the daemon's basedir is used. If stepsize or heartbeat
+ * is zero a default, depending on the `interval' member of the value list is
+ * being used. */
 static char   *datadir   = NULL;
 static int     stepsize  = 0;
 static int     heartbeat = 0;
 static int     rrarows   = 1200;
 static double  xff       = 0.1;
 
+/* XXX: If you need to lock both, cache_lock and queue_lock, at the same time,
+ * ALWAYS lock `cache_lock' first! */
 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;
 
+static rrd_queue_t    *queue_head = NULL;
+static rrd_queue_t    *queue_tail = NULL;
+static pthread_t       queue_thread = 0;
+static pthread_mutex_t queue_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t  queue_cond = PTHREAD_COND_INITIALIZER;
+
+#if !HAVE_THREADSAFE_LIBRRD
+static pthread_mutex_t librrd_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+static int do_shutdown = 0;
+
 /* * * * * * * * * *
  * WARNING:  Magic *
  * * * * * * * * * */
-static int rra_get (char ***ret)
+
+static void rra_free (int rra_num, char **rra_def)
+{
+       int i;
+
+       for (i = 0; i < rra_num; i++)
+       {
+               sfree (rra_def[i]);
+       }
+       sfree (rra_def);
+} /* void rra_free */
+
+static int rra_get (char ***ret, const value_list_t *vl)
 {
-       static char **rra_def = NULL;
-       static int rra_num = 0;
+       char **rra_def;
+       int rra_num;
 
        int *rts;
        int  rts_num;
@@ -110,10 +151,21 @@ static int rra_get (char ***ret)
 
        char buffer[64];
 
-       if ((rra_num != 0) && (rra_def != NULL))
+       /* The stepsize we use here: If it is user-set, use it. If not, use the
+        * interval of the value-list. */
+       int ss;
+
+       if (rrarows <= 0)
+       {
+               *ret = NULL;
+               return (-1);
+       }
+
+       ss = (stepsize > 0) ? stepsize : vl->interval;
+       if (ss <= 0)
        {
-               *ret = rra_def;
-               return (rra_num);
+               *ret = NULL;
+               return (-1);
        }
 
        /* Use the configured timespans or fall back to the built-in defaults */
@@ -133,29 +185,24 @@ static int rra_get (char ***ret)
        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);
-       }
+       rra_num = 0;
 
        cdp_len = 0;
        for (i = 0; i < rts_num; i++)
        {
                span = rts[i];
 
-               if ((span / stepsize) < rrarows)
+               if ((span / ss) < rrarows)
                        continue;
 
                if (cdp_len == 0)
                        cdp_len = 1;
                else
                        cdp_len = (int) floor (((double) span)
-                                       / ((double) (rrarows * stepsize)));
+                                       / ((double) (rrarows * ss)));
 
                cdp_num = (int) ceil (((double) span)
-                               / ((double) (cdp_len * stepsize)));
+                               / ((double) (cdp_len * ss)));
 
                for (j = 0; j < rra_types_num; j++)
                {
@@ -182,7 +229,7 @@ static int rra_get (char ***ret)
 
        *ret = rra_def;
        return (rra_num);
-}
+} /* int rra_get */
 
 static void ds_free (int ds_num, char **ds_def)
 {
@@ -194,7 +241,7 @@ static void ds_free (int ds_num, char **ds_def)
        free (ds_def);
 }
 
-static int ds_get (char ***ret, const data_set_t *ds)
+static int ds_get (char ***ret, const data_set_t *ds, const value_list_t *vl)
 {
        char **ds_def;
        int ds_num;
@@ -256,7 +303,8 @@ static int ds_get (char ***ret, const data_set_t *ds)
 
                status = snprintf (buffer, sizeof (buffer),
                                "DS:%s:%s:%i:%s:%s",
-                               d->name, type, heartbeat,
+                               d->name, type,
+                               (heartbeat > 0) ? heartbeat : (2 * vl->interval),
                                min, max);
                if ((status < 1) || (status >= sizeof (buffer)))
                        break;
@@ -283,6 +331,143 @@ static int ds_get (char ***ret, const data_set_t *ds)
        return (ds_num);
 }
 
+#if HAVE_THREADSAFE_LIBRRD
+static int srrd_create (char *filename, unsigned long pdp_step, time_t last_up,
+               int argc, char **argv)
+{
+       int status;
+
+       optind = 0; /* bug in librrd? */
+       rrd_clear_error ();
+
+       status = rrd_create_r (filename, pdp_step, last_up, argc, argv);
+
+       if (status != 0)
+       {
+               WARNING ("rrdtool plugin: rrd_create_r (%s) failed: %s",
+                               filename, rrd_get_error ());
+       }
+
+       return (status);
+} /* int srrd_create */
+
+static int srrd_update (char *filename, char *template, int argc, char **argv)
+{
+       int status;
+
+       optind = 0; /* bug in librrd? */
+       rrd_clear_error ();
+
+       status = rrd_update_r (filename, template, argc, argv);
+
+       if (status != 0)
+       {
+               WARNING ("rrdtool plugin: rrd_update_r (%s) failed: %s",
+                               filename, rrd_get_error ());
+       }
+
+       return (status);
+} /* int srrd_update */
+/* #endif HAVE_THREADSAFE_LIBRRD */
+
+#else /* !HAVE_THREADSAFE_LIBRRD */
+static int srrd_create (char *filename, unsigned long pdp_step, time_t last_up,
+               int argc, char **argv)
+{
+       int status;
+
+       int new_argc;
+       char **new_argv;
+
+       char pdp_step_str[16];
+       char last_up_str[16];
+
+       new_argc = 6 + argc;
+       new_argv = (char **) malloc ((new_argc + 1) * sizeof (char *));
+       if (new_argv == NULL)
+       {
+               ERROR ("rrdtool plugin: malloc failed.");
+               return (-1);
+       }
+
+       if (last_up == 0)
+               last_up = time (NULL) - 10;
+
+       snprintf (pdp_step_str, sizeof (pdp_step_str), "%lu", pdp_step);
+       pdp_step_str[sizeof (pdp_step_str) - 1] = '\0';
+       snprintf (last_up_str, sizeof (last_up_str), "%u", (unsigned int) last_up);
+       last_up_str[sizeof (last_up_str) - 1] = '\0';
+
+       new_argv[0] = "create";
+       new_argv[1] = filename;
+       new_argv[2] = "-s";
+       new_argv[3] = pdp_step_str;
+       new_argv[4] = "-b";
+       new_argv[5] = last_up_str;
+
+       memcpy (new_argv + 6, argv, argc * sizeof (char *));
+       new_argv[new_argc] = NULL;
+       
+       pthread_mutex_lock (&librrd_lock);
+       optind = 0; /* bug in librrd? */
+       rrd_clear_error ();
+
+       status = rrd_create (new_argc, new_argv);
+       pthread_mutex_unlock (&librrd_lock);
+
+       if (status != 0)
+       {
+               WARNING ("rrdtool plugin: rrd_create (%s) failed: %s",
+                               filename, rrd_get_error ());
+       }
+
+       sfree (new_argv);
+
+       return (status);
+} /* int srrd_create */
+
+static int srrd_update (char *filename, char *template, int argc, char **argv)
+{
+       int status;
+
+       int new_argc;
+       char **new_argv;
+
+       assert (template == NULL);
+
+       new_argc = 2 + argc;
+       new_argv = (char **) malloc ((new_argc + 1) * sizeof (char *));
+       if (new_argv == NULL)
+       {
+               ERROR ("rrdtool plugin: malloc failed.");
+               return (-1);
+       }
+
+       new_argv[0] = "update";
+       new_argv[1] = filename;
+
+       memcpy (new_argv + 2, argv, argc * sizeof (char *));
+       new_argv[new_argc] = NULL;
+
+       pthread_mutex_lock (&librrd_lock);
+       optind = 0; /* bug in librrd? */
+       rrd_clear_error ();
+
+       status = rrd_update (new_argc, new_argv);
+       pthread_mutex_unlock (&librrd_lock);
+
+       if (status != 0)
+       {
+               WARNING ("rrdtool plugin: rrd_update_r failed: %s: %s",
+                               argv[1], rrd_get_error ());
+       }
+
+       sfree (new_argv);
+
+       return (status);
+} /* int srrd_update */
+#endif /* !HAVE_THREADSAFE_LIBRRD */
+
 static int rrd_create_file (char *filename, const data_set_t *ds, const value_list_t *vl)
 {
        char **argv;
@@ -291,27 +476,24 @@ static int rrd_create_file (char *filename, const data_set_t *ds, const value_li
        int rra_num;
        char **ds_def;
        int ds_num;
-       int i, j;
-       char stepsize_str[16];
-       char begin_str[16];
        int status = 0;
 
        if (check_create_dir (filename))
                return (-1);
 
-       if ((rra_num = rra_get (&rra_def)) < 1)
+       if ((rra_num = rra_get (&rra_def, vl)) < 1)
        {
                ERROR ("rrd_create_file failed: Could not calculate RRAs");
                return (-1);
        }
 
-       if ((ds_num = ds_get (&ds_def, ds)) < 1)
+       if ((ds_num = ds_get (&ds_def, ds, vl)) < 1)
        {
                ERROR ("rrd_create_file failed: Could not calculate DSes");
                return (-1);
        }
 
-       argc = ds_num + rra_num + 6;
+       argc = ds_num + rra_num;
 
        if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
        {
@@ -321,47 +503,19 @@ static int rrd_create_file (char *filename, const data_set_t *ds, const value_li
                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);
-       }
+       memcpy (argv, ds_def, ds_num * sizeof (char *));
+       memcpy (argv + ds_num, rra_def, rra_num * sizeof (char *));
+       argv[ds_num + rra_num] = NULL;
 
        assert (vl->time > 10);
-       status = snprintf (begin_str, sizeof (begin_str),
-                       "%llu", (unsigned long long) (vl->time - 10));
-       if ((status < 1) || (status >= sizeof (begin_str)))
-       {
-               ERROR ("rrdtool plugin: snprintf failed.");
-               return (-1);
-       }
-
-       argv[0] = "create";
-       argv[1] = filename;
-       argv[2] = "-b";
-       argv[3] = begin_str;
-       argv[4] = "-s";
-       argv[5] = stepsize_str;
-
-       j = 6;
-       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;
-       }
+       status = srrd_create (filename,
+                       (stepsize > 0) ? stepsize : vl->interval,
+                       vl->time - 10,
+                       argc, argv);
 
        free (argv);
        ds_free (ds_num, ds_def);
+       rra_free (rra_num, rra_def);
 
        return (status);
 }
@@ -446,138 +600,107 @@ static int value_list_to_filename (char *buffer, int buffer_len,
        return (0);
 } /* int value_list_to_filename */
 
-static rrd_cache_t *rrd_cache_insert (const char *filename,
-               const char *value, time_t value_time)
+static void *rrd_queue_thread (void *data)
 {
-       rrd_cache_t *rc = NULL;
-       int new_rc = 0;
-
-       if (cache != NULL)
-               avl_get (cache, filename, (void *) &rc);
-
-       if (rc == NULL)
+       while (42)
        {
-               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;
-               rc->last_value = 0;
-               new_rc = 1;
-       }
-
-       if (rc->last_value >= value_time)
-       {
-               WARNING ("rrdtool plugin: (rc->last_value = %u) >= (value_time = %u)",
-                               (unsigned int) rc->last_value,
-                               (unsigned int) value_time);
-               return (NULL);
-       }
-
-       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)
+               rrd_queue_t *queue_entry;
+               rrd_cache_t *cache_entry;
+               char **values;
+               int    values_num;
+               int    i;
+
+               /* XXX: If you need to lock both, cache_lock and queue_lock, at
+                * the same time, ALWAYS lock `cache_lock' first! */
+
+               /* wait until an entry is available */
+               pthread_mutex_lock (&queue_lock);
+               while ((queue_head == NULL) && (do_shutdown == 0))
+                       pthread_cond_wait (&queue_cond, &queue_lock);
+
+               /* We're in the shutdown phase */
+               if (queue_head == NULL)
                {
-                       void *cache_key = NULL;
-                       avl_remove (cache, filename, &cache_key, NULL);
-                       sfree (cache_key);
+                       pthread_mutex_unlock (&queue_lock);
+                       break;
                }
-               free (rc);
-               return (NULL);
-       }
 
-       rc->values[rc->values_num] = strdup (value);
-       if (rc->values[rc->values_num] != NULL)
-               rc->values_num++;
+               /* Dequeue the first entry */
+               queue_entry = queue_head;
+               if (queue_head == queue_tail)
+                       queue_head = queue_tail = NULL;
+               else
+                       queue_head = queue_head->next;
 
-       if (rc->values_num == 1)
-               rc->first_value = value_time;
-       rc->last_value = value_time;
+               /* Unlock the queue again */
+               pthread_mutex_unlock (&queue_lock);
 
-       /* Insert if this is the first value */
-       if ((cache != NULL) && (new_rc == 1))
-       {
-               void *cache_key = strdup (filename);
+               /* We now need the cache lock so the entry isn't updated while
+                * we make a copy of it's values */
+               pthread_mutex_lock (&cache_lock);
 
-               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_get (cache, queue_entry->filename, (void *) &cache_entry);
 
-               avl_insert (cache, cache_key, rc);
-       }
+               values = cache_entry->values;
+               values_num = cache_entry->values_num;
 
-       DEBUG ("rrd_cache_insert (%s, %s, %u) = %p", filename, value,
-                       (unsigned int) value_time, (void *) rc);
+               cache_entry->values = NULL;
+               cache_entry->values_num = 0;
+               cache_entry->flags = FLAG_NONE;
 
-       return (rc);
-} /* rrd_cache_t *rrd_cache_insert */
+               pthread_mutex_unlock (&cache_lock);
 
-static int rrd_write_cache_entry (const char *filename, rrd_cache_t *rc)
-{
-       char **argv;
-       int    argc;
+               /* Write the values to the RRD-file */
+               srrd_update (queue_entry->filename, NULL, values_num, values);
 
-       char *fn;
-       int status;
+               for (i = 0; i < values_num; i++)
+               {
+                       sfree (values[i]);
+               }
+               sfree (values);
+               sfree (queue_entry->filename);
+               sfree (queue_entry);
+       } /* while (42) */
 
-       int i;
+       pthread_mutex_lock (&cache_lock);
+       avl_destroy (cache);
+       cache = NULL;
+       pthread_mutex_unlock (&cache_lock);
 
-       if (rc->values_num < 1)
-               return (0);
+       pthread_exit ((void *) 0);
+       return ((void *) 0);
+} /* void *rrd_queue_thread */
 
-       argc = rc->values_num + 2;
-       argv = (char **) malloc ((argc + 1) * sizeof (char *));
-       if (argv == NULL)
+static int rrd_queue_cache_entry (const char *filename)
+{
+       rrd_queue_t *queue_entry;
+
+       queue_entry = (rrd_queue_t *) malloc (sizeof (rrd_queue_t));
+       if (queue_entry == NULL)
                return (-1);
 
-       fn = strdup (filename);
-       if (fn == NULL)
+       queue_entry->filename = strdup (filename);
+       if (queue_entry->filename == NULL)
        {
-               free (argv);
+               free (queue_entry);
                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);
+       queue_entry->next = NULL;
 
-       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;
-       }
+       pthread_mutex_lock (&queue_lock);
+       if (queue_tail == NULL)
+               queue_head = queue_entry;
+       else
+               queue_tail->next = queue_entry;
+       queue_tail = queue_entry;
+       pthread_cond_signal (&queue_cond);
+       pthread_mutex_unlock (&queue_lock);
 
-       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;
+       DEBUG ("rrdtool plugin: Put `%s' into the update queue", filename);
 
-       return (status);
-} /* int rrd_write_cache_entry */
+       return (0);
+} /* int rrd_queue_cache_entry */
 
 static void rrd_cache_flush (int timeout)
 {
@@ -591,9 +714,6 @@ static void rrd_cache_flush (int timeout)
        avl_iterator_t *iter;
        int i;
 
-       if (cache == NULL)
-               return;
-
        DEBUG ("rrdtool plugin: Flushing cache, timeout = %i", timeout);
 
        now = time (NULL);
@@ -603,7 +723,17 @@ static void rrd_cache_flush (int timeout)
        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)
+
+               if (rc->flags == FLAG_QUEUED)
+                       continue;
+               else if ((now - rc->first_value) < timeout)
+                       continue;
+               else if (rc->values_num > 0)
+               {
+                       if (rrd_queue_cache_entry (key) == 0)
+                               rc->flags = FLAG_QUEUED;
+               }
+               else /* ancient and no values -> waste of memory */
                {
                        keys = (char **) realloc ((void *) keys,
                                        (keys_num + 1) * sizeof (char *));
@@ -631,8 +761,9 @@ static void rrd_cache_flush (int timeout)
                        continue;
                }
 
-               rrd_write_cache_entry (keys[i], rc);
-               /* rc's value-list is free's by `rrd_write_cache_entry' */
+               assert (rc->values == NULL);
+               assert (rc->values_num == 0);
+
                sfree (rc);
                sfree (key);
                keys[i] = NULL;
@@ -643,13 +774,125 @@ static void rrd_cache_flush (int timeout)
        cache_flush_last = now;
 } /* void rrd_cache_flush */
 
+static int rrd_cache_insert (const char *filename,
+               const char *value, time_t value_time)
+{
+       rrd_cache_t *rc = NULL;
+       int new_rc = 0;
+       char **values_new;
+
+       pthread_mutex_lock (&cache_lock);
+
+       avl_get (cache, filename, (void *) &rc);
+
+       if (rc == NULL)
+       {
+               rc = (rrd_cache_t *) malloc (sizeof (rrd_cache_t));
+               if (rc == NULL)
+                       return (-1);
+               rc->values_num = 0;
+               rc->values = NULL;
+               rc->first_value = 0;
+               rc->last_value = 0;
+               rc->flags = FLAG_NONE;
+               new_rc = 1;
+       }
+
+       if (rc->last_value >= value_time)
+       {
+               pthread_mutex_unlock (&cache_lock);
+               WARNING ("rrdtool plugin: (rc->last_value = %u) >= (value_time = %u)",
+                               (unsigned int) rc->last_value,
+                               (unsigned int) value_time);
+               return (-1);
+       }
+
+       values_new = (char **) realloc ((void *) rc->values,
+                       (rc->values_num + 1) * sizeof (char *));
+       if (values_new == NULL)
+       {
+               char errbuf[1024];
+               void *cache_key = NULL;
+
+               sstrerror (errno, errbuf, sizeof (errbuf));
+
+               avl_remove (cache, filename, &cache_key, NULL);
+               pthread_mutex_unlock (&cache_lock);
+
+               ERROR ("rrdtool plugin: realloc failed: %s", errbuf);
+
+               sfree (cache_key);
+               sfree (rc->values);
+               sfree (rc);
+               return (-1);
+       }
+       rc->values = values_new;
+
+       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 = value_time;
+       rc->last_value = value_time;
+
+       /* Insert if this is the first value */
+       if (new_rc == 1)
+       {
+               void *cache_key = strdup (filename);
+
+               if (cache_key == NULL)
+               {
+                       char errbuf[1024];
+                       sstrerror (errno, errbuf, sizeof (errbuf));
+
+                       pthread_mutex_unlock (&cache_lock);
+
+                       ERROR ("rrdtool plugin: strdup failed: %s", errbuf);
+
+                       sfree (rc->values[0]);
+                       sfree (rc->values);
+                       sfree (rc);
+                       return (-1);
+               }
+
+               avl_insert (cache, cache_key, rc);
+       }
+
+       DEBUG ("rrd_cache_insert (%s, %s, %u) = %p", filename, value,
+                       (unsigned int) value_time, (void *) rc);
+
+       if ((rc->last_value - rc->first_value) >= cache_timeout)
+       {
+               /* XXX: If you need to lock both, cache_lock and queue_lock, at
+                * the same time, ALWAYS lock `cache_lock' first! */
+               if (rc->flags != FLAG_QUEUED)
+               {
+                       if (rrd_queue_cache_entry (filename) == 0)
+                               rc->flags = FLAG_QUEUED;
+               }
+               else
+               {
+                       DEBUG ("rrdtool plugin: `%s' is already queued.", filename);
+               }
+       }
+
+       if ((cache_timeout > 0) &&
+                       ((time (NULL) - cache_flush_last) > cache_flush_timeout))
+               rrd_cache_flush (cache_flush_timeout);
+
+
+       pthread_mutex_unlock (&cache_lock);
+
+       return (0);
+} /* int rrd_cache_insert */
+
 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;
+       int          status;
 
        if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
                return (-1);
@@ -680,37 +923,9 @@ static int rrd_write (const data_set_t *ds, const value_list_t *vl)
                return (-1);
        }
 
-       pthread_mutex_lock (&cache_lock);
-       rc = rrd_cache_insert (filename, values, vl->time);
-       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);
+       status = rrd_cache_insert (filename, values, vl->time);
 
-       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);
+       return (status);
 } /* int rrd_write */
 
 static int rrd_config (const char *key, const char *value)
@@ -759,25 +974,15 @@ static int rrd_config (const char *key, const char *value)
        }
        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;
+               stepsize = atoi (value);
+               if (stepsize < 0)
+                       stepsize = 0;
        }
        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;
+               heartbeat = atoi (value);
+               if (heartbeat < 0)
+                       heartbeat = 0;
        }
        else if (strcasecmp ("RRARows", key) == 0)
        {
@@ -844,47 +1049,75 @@ 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);
 
+       /* Wait for all the values to be written to disk before returning. */
+       if (queue_thread != 0)
+       {
+               pthread_join (queue_thread, NULL);
+               queue_thread = 0;
+               DEBUG ("rrdtool plugin: queue_thread exited.");
+       }
+
+       pthread_mutex_lock (&queue_lock);
+       do_shutdown = 1;
+       pthread_cond_signal (&queue_cond);
+       pthread_mutex_unlock (&queue_lock);
+
        return (0);
 } /* int rrd_shutdown */
 
 static int rrd_init (void)
 {
-       if (stepsize <= 0)
-               stepsize = interval_g;
+       int status;
+
+       if (stepsize < 0)
+               stepsize = 0;
        if (heartbeat <= 0)
-               heartbeat = 2 * interval_g;
+       {
+               if (stepsize > 0)
+                       heartbeat = 2 * stepsize;
+               else
+                       heartbeat = 0;
+       }
 
-       if (heartbeat < interval_g)
+       if ((heartbeat > 0) && (heartbeat < interval_g))
                WARNING ("rrdtool plugin: Your `heartbeat' is "
                                "smaller than your `interval'. This will "
                                "likely cause problems.");
-       else if (stepsize < interval_g)
+       else if ((stepsize > 0) && (stepsize < interval_g))
                WARNING ("rrdtool plugin: Your `stepsize' is "
                                "smaller than your `interval'. This will "
                                "create needlessly big RRD-files.");
 
+       /* Set the cache up */
        pthread_mutex_lock (&cache_lock);
+
+       cache = avl_create ((int (*) (const void *, const void *)) strcmp);
+       if (cache == NULL)
+       {
+               ERROR ("rrdtool plugin: avl_create failed.");
+               return (-1);
+       }
+
+       cache_flush_last = time (NULL);
        if (cache_timeout < 2)
        {
                cache_timeout = 0;
                cache_flush_timeout = 0;
        }
-       else
-       {
-               if (cache_flush_timeout < cache_timeout)
-                       cache_flush_timeout = 10 * cache_timeout;
+       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);
 
+       status = pthread_create (&queue_thread, NULL, rrd_queue_thread, NULL);
+       if (status != 0)
+       {
+               ERROR ("rrdtool plugin: Cannot create queue-thread.");
+               return (-1);
+       }
+
        DEBUG ("rrdtool plugin: rrd_init: datadir = %s; stepsize = %i;"
                        " heartbeat = %i; rrarows = %i; xff = %lf;",
                        (datadir == NULL) ? "(null)" : datadir,
@@ -899,4 +1132,5 @@ void module_register (void)
                        config_keys, config_keys_num);
        plugin_register_init ("rrdtool", rrd_init);
        plugin_register_write ("rrdtool", rrd_write);
+       plugin_register_shutdown ("rrdtool", rrd_shutdown);
 }
index fde8dcd..a30549f 100644 (file)
 
 #if defined(HAVE_SENSORS_SENSORS_H)
 # include <sensors/sensors.h>
-#else
-# undef HAVE_LIBSENSORS
 #endif
 
-#if defined(HAVE_LIBSENSORS)
-# define SENSORS_HAVE_READ 1
-#else
-# define SENSORS_HAVE_READ 0
-#endif
-
-#if SENSORS_HAVE_READ
 #define SENSOR_TYPE_VOLTAGE     0
 #define SENSOR_TYPE_FANSPEED    1
 #define SENSOR_TYPE_TEMPERATURE 2
@@ -433,14 +424,11 @@ static int sensors_read (void)
 
        return (0);
 } /* int sensors_read */
-#endif /* SENSORS_HAVE_READ */
 
 void module_register (void)
 {
-#if SENSORS_HAVE_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 dd063bb..9cfe1dd 100644 (file)
 #include "common.h"
 #include "plugin.h"
 
-#if defined(KERNEL_LINUX)
-# define SERIAL_HAVE_READ 1
-#else
-# define SERIAL_HAVE_READ 0
+#if !KERNEL_LINUX
+# error "No applicable input method."
 #endif
 
-#if SERIAL_HAVE_READ
 static void serial_submit (const char *type_instance,
                counter_t rx, counter_t tx)
 {
@@ -54,7 +51,6 @@ static void serial_submit (const char *type_instance,
 
 static int serial_read (void)
 {
-#ifdef KERNEL_LINUX
        FILE *fh;
        char buffer[1024];
 
@@ -121,13 +117,9 @@ static int serial_read (void)
 
        fclose (fh);
        return (0);
-#endif /* KERNEL_LINUX */
 } /* int serial_read */
-#endif /* SERIAL_HAVE_READ */
 
 void module_register (void)
 {
-#if SERIAL_HAVE_READ
        plugin_register_read ("serial", serial_read);
-#endif /* SERIAL_HAVE_READ */
 } /* void module_register */
diff --git a/src/snmp.c b/src/snmp.c
new file mode 100644 (file)
index 0000000..4bcdcf7
--- /dev/null
@@ -0,0 +1,1347 @@
+/**
+ * collectd - src/snmp.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 <pthread.h>
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+
+/*
+ * Private data structes
+ */
+struct oid_s
+{
+  oid oid[MAX_OID_LEN];
+  size_t oid_len;
+};
+typedef struct oid_s oid_t;
+
+union instance_u
+{
+  char  string[DATA_MAX_NAME_LEN];
+  oid_t oid;
+};
+typedef union instance_u instance_t;
+
+struct data_definition_s
+{
+  char *name; /* used to reference this from the `Collect' option */
+  char *type; /* used to find the data_set */
+  int is_table;
+  instance_t instance;
+  oid_t *values;
+  int values_len;
+  struct data_definition_s *next;
+};
+typedef struct data_definition_s data_definition_t;
+
+struct host_definition_s
+{
+  char *name;
+  char *address;
+  char *community;
+  int version;
+  void *sess_handle;
+  uint32_t interval;
+  time_t next_update;
+  data_definition_t **data_list;
+  int data_list_len;
+  enum          /******************************************************/
+  {             /* This host..                                        */
+    STATE_IDLE, /* - just sits there until `next_update < interval_g' */
+    STATE_WAIT, /* - waits to be queried.                             */
+    STATE_BUSY  /* - is currently being queried.                      */
+  } state;      /******************************************************/
+  struct host_definition_s *next;
+};
+typedef struct host_definition_s host_definition_t;
+
+/* These two types are used to cache values in `csnmp_read_table' to handle
+ * gaps in tables. */
+struct csnmp_list_instances_s
+{
+  oid subid;
+  char instance[DATA_MAX_NAME_LEN];
+  struct csnmp_list_instances_s *next;
+};
+typedef struct csnmp_list_instances_s csnmp_list_instances_t;
+
+struct csnmp_table_values_s
+{
+  oid subid;
+  value_t value;
+  struct csnmp_table_values_s *next;
+};
+typedef struct csnmp_table_values_s csnmp_table_values_t;
+
+/*
+ * Private variables
+ */
+static int do_shutdown = 0;
+
+pthread_t *threads = NULL;
+int threads_num = 0;
+
+static data_definition_t *data_head = NULL;
+static host_definition_t *host_head = NULL;
+
+static pthread_mutex_t host_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t  host_cond = PTHREAD_COND_INITIALIZER;
+
+/*
+ * Private functions
+ */
+/* First there are many functions which do configuration stuff. It's a big
+ * bloated and messy, I'm afraid. */
+
+/*
+ * Callgraph for the config stuff:
+ *  csnmp_config
+ *  +-> call_snmp_init_once
+ *  +-> csnmp_config_add_data
+ *  !   +-> csnmp_config_add_data_type
+ *  !   +-> csnmp_config_add_data_table
+ *  !   +-> csnmp_config_add_data_instance
+ *  !   +-> csnmp_config_add_data_values
+ *  +-> csnmp_config_add_host
+ *      +-> csnmp_config_add_host_address
+ *      +-> csnmp_config_add_host_community
+ *      +-> csnmp_config_add_host_version
+ *      +-> csnmp_config_add_host_collect
+ *      +-> csnmp_config_add_host_interval
+ */
+static void call_snmp_init_once (void)
+{
+  static int have_init = 0;
+
+  if (have_init == 0)
+    init_snmp (PACKAGE_NAME);
+  have_init = 1;
+} /* void call_snmp_init_once */
+
+static int csnmp_config_add_data_type (data_definition_t *dd, oconfig_item_t *ci)
+{
+  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("snmp plugin: `Type' needs exactly one string argument.");
+    return (-1);
+  }
+
+  if (dd->type != NULL)
+    free (dd->type);
+
+  dd->type = strdup (ci->values[0].value.string);
+  if (dd->type == NULL)
+    return (-1);
+
+  return (0);
+} /* int csnmp_config_add_data_type */
+
+static int csnmp_config_add_data_table (data_definition_t *dd, oconfig_item_t *ci)
+{
+  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
+  {
+    WARNING ("snmp plugin: `Table' needs exactly one boolean argument.");
+    return (-1);
+  }
+
+  dd->is_table = ci->values[0].value.boolean ? 1 : 0;
+
+  return (0);
+} /* int csnmp_config_add_data_table */
+
+static int csnmp_config_add_data_instance (data_definition_t *dd, oconfig_item_t *ci)
+{
+  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("snmp plugin: `Instance' needs exactly one string argument.");
+    return (-1);
+  }
+
+  if (dd->is_table)
+  {
+    /* Instance is an OID */
+    dd->instance.oid.oid_len = MAX_OID_LEN;
+
+    if (!read_objid (ci->values[0].value.string,
+         dd->instance.oid.oid, &dd->instance.oid.oid_len))
+    {
+      ERROR ("snmp plugin: read_objid (%s) failed.",
+         ci->values[0].value.string);
+      return (-1);
+    }
+  }
+  else
+  {
+    /* Instance is a simple string */
+    strncpy (dd->instance.string, ci->values[0].value.string, DATA_MAX_NAME_LEN - 1);
+  }
+
+  return (0);
+} /* int csnmp_config_add_data_instance */
+
+static int csnmp_config_add_data_values (data_definition_t *dd, oconfig_item_t *ci)
+{
+  int i;
+
+  if (ci->values_num < 1)
+  {
+    WARNING ("snmp plugin: `Values' needs at least one argument.");
+    return (-1);
+  }
+
+  for (i = 0; i < ci->values_num; i++)
+    if (ci->values[i].type != OCONFIG_TYPE_STRING)
+    {
+      WARNING ("snmp plugin: `Values' needs only string argument.");
+      return (-1);
+    }
+
+  if (dd->values != NULL)
+    free (dd->values);
+  dd->values = (oid_t *) malloc (sizeof (oid_t) * ci->values_num);
+  if (dd->values == NULL)
+    return (-1);
+  dd->values_len = ci->values_num;
+
+  for (i = 0; i < ci->values_num; i++)
+  {
+    dd->values[i].oid_len = MAX_OID_LEN;
+
+    if (NULL == snmp_parse_oid (ci->values[i].value.string,
+         dd->values[i].oid, &dd->values[i].oid_len))
+    {
+      ERROR ("snmp plugin: snmp_parse_oid (%s) failed.",
+         ci->values[i].value.string);
+      free (dd->values);
+      dd->values = NULL;
+      dd->values_len = 0;
+      return (-1);
+    }
+  }
+
+  return (0);
+} /* int csnmp_config_add_data_instance */
+
+static int csnmp_config_add_data (oconfig_item_t *ci)
+{
+  data_definition_t *dd;
+  int status = 0;
+  int i;
+
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("snmp plugin: The `Data' config option needs exactly one string argument.");
+    return (-1);
+  }
+
+  dd = (data_definition_t *) malloc (sizeof (data_definition_t));
+  if (dd == NULL)
+    return (-1);
+  memset (dd, '\0', sizeof (data_definition_t));
+
+  dd->name = strdup (ci->values[0].value.string);
+  if (dd->name == NULL)
+  {
+    free (dd);
+    return (-1);
+  }
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *option = ci->children + i;
+    status = 0;
+
+    if (strcasecmp ("Type", option->key) == 0)
+      status = csnmp_config_add_data_type (dd, option);
+    else if (strcasecmp ("Table", option->key) == 0)
+      status = csnmp_config_add_data_table (dd, option);
+    else if (strcasecmp ("Instance", option->key) == 0)
+      status = csnmp_config_add_data_instance (dd, option);
+    else if (strcasecmp ("Values", option->key) == 0)
+      status = csnmp_config_add_data_values (dd, option);
+    else
+    {
+      WARNING ("snmp plugin: Option `%s' not allowed here.", option->key);
+      status = -1;
+    }
+
+    if (status != 0)
+      break;
+  } /* for (ci->children) */
+
+  while (status == 0)
+  {
+    if (dd->type == NULL)
+    {
+      WARNING ("snmp plugin: `Type' not given for data `%s'", dd->name);
+      status = -1;
+      break;
+    }
+    if (dd->values == NULL)
+    {
+      WARNING ("snmp plugin: No `Value' given for data `%s'", dd->name);
+      status = -1;
+      break;
+    }
+
+    break;
+  } /* while (status == 0) */
+
+  if (status != 0)
+  {
+    sfree (dd->name);
+    sfree (dd->values);
+    sfree (dd);
+    return (-1);
+  }
+
+  DEBUG ("snmp plugin: dd = { name = %s, type = %s, is_table = %s, values_len = %i }",
+      dd->name, dd->type, (dd->is_table != 0) ? "true" : "false", dd->values_len);
+
+  if (data_head == NULL)
+    data_head = dd;
+  else
+  {
+    data_definition_t *last;
+    last = data_head;
+    while (last->next != NULL)
+      last = last->next;
+    last->next = dd;
+  }
+
+  return (0);
+} /* int csnmp_config_add_data */
+
+static int csnmp_config_add_host_address (host_definition_t *hd, oconfig_item_t *ci)
+{
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("snmp plugin: The `Address' config option needs exactly one string argument.");
+    return (-1);
+  }
+
+  if (hd->address == NULL)
+    free (hd->address);
+
+  hd->address = strdup (ci->values[0].value.string);
+  if (hd->address == NULL)
+    return (-1);
+
+  DEBUG ("snmp plugin: host = %s; host->address = %s;",
+      hd->name, hd->address);
+
+  return (0);
+} /* int csnmp_config_add_host_address */
+
+static int csnmp_config_add_host_community (host_definition_t *hd, oconfig_item_t *ci)
+{
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("snmp plugin: The `Community' config option needs exactly one string argument.");
+    return (-1);
+  }
+
+  if (hd->community == NULL)
+    free (hd->community);
+
+  hd->community = strdup (ci->values[0].value.string);
+  if (hd->community == NULL)
+    return (-1);
+
+  DEBUG ("snmp plugin: host = %s; host->community = %s;",
+      hd->name, hd->community);
+
+  return (0);
+} /* int csnmp_config_add_host_community */
+
+static int csnmp_config_add_host_version (host_definition_t *hd, oconfig_item_t *ci)
+{
+  int version;
+
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+  {
+    WARNING ("snmp plugin: The `Version' config option needs exactly one number argument.");
+    return (-1);
+  }
+
+  version = (int) ci->values[0].value.number;
+  if ((version != 1) && (version != 2))
+  {
+    WARNING ("snmp plugin: `Version' must either be `1' or `2'.");
+    return (-1);
+  }
+
+  hd->version = version;
+
+  return (0);
+} /* int csnmp_config_add_host_address */
+
+static int csnmp_config_add_host_collect (host_definition_t *host,
+    oconfig_item_t *ci)
+{
+  data_definition_t *data;
+  data_definition_t **data_list;
+  int data_list_len;
+  int i;
+
+  if (ci->values_num < 1)
+  {
+    WARNING ("snmp plugin: `Collect' needs at least one argument.");
+    return (-1);
+  }
+
+  for (i = 0; i < ci->values_num; i++)
+    if (ci->values[i].type != OCONFIG_TYPE_STRING)
+    {
+      WARNING ("snmp plugin: All arguments to `Collect' must be strings.");
+      return (-1);
+    }
+
+  data_list_len = host->data_list_len + ci->values_num;
+  data_list = (data_definition_t **) realloc (host->data_list,
+      sizeof (data_definition_t *) * data_list_len);
+  if (data_list == NULL)
+    return (-1);
+  host->data_list = data_list;
+
+  for (i = 0; i < ci->values_num; i++)
+  {
+    for (data = data_head; data != NULL; data = data->next)
+      if (strcasecmp (ci->values[i].value.string, data->name) == 0)
+       break;
+
+    if (data == NULL)
+    {
+      WARNING ("snmp plugin: No such data configured: `%s'",
+         ci->values[i].value.string);
+      continue;
+    }
+
+    DEBUG ("snmp plugin: Collect: host = %s, data[%i] = %s;",
+       host->name, host->data_list_len, data->name);
+
+    host->data_list[host->data_list_len] = data;
+    host->data_list_len++;
+  } /* for (values_num) */
+
+  return (0);
+} /* int csnmp_config_add_host_collect */
+
+static int csnmp_config_add_host_interval (host_definition_t *hd, oconfig_item_t *ci)
+{
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+  {
+    WARNING ("snmp plugin: The `Interval' config option needs exactly one number argument.");
+    return (-1);
+  }
+
+  hd->interval = (int) ci->values[0].value.number;
+  if (hd->interval < 0)
+    hd->interval = 0;
+
+  return (0);
+} /* int csnmp_config_add_host_interval */
+
+static int csnmp_config_add_host (oconfig_item_t *ci)
+{
+  host_definition_t *hd;
+  int status = 0;
+  int i;
+
+  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("snmp plugin: `Host' needs exactly one string argument.");
+    return (-1);
+  }
+
+  hd = (host_definition_t *) malloc (sizeof (host_definition_t));
+  if (hd == NULL)
+    return (-1);
+  memset (hd, '\0', sizeof (host_definition_t));
+  hd->version = 2;
+
+  hd->name = strdup (ci->values[0].value.string);
+  if (hd->name == NULL)
+  {
+    free (hd);
+    return (-1);
+  }
+
+  hd->sess_handle = NULL;
+  hd->interval = 0;
+  hd->next_update = 0;
+  hd->state = STATE_IDLE;
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *option = ci->children + i;
+    status = 0;
+
+    if (strcasecmp ("Address", option->key) == 0)
+      status = csnmp_config_add_host_address (hd, option);
+    else if (strcasecmp ("Community", option->key) == 0)
+      status = csnmp_config_add_host_community (hd, option);
+    else if (strcasecmp ("Version", option->key) == 0)
+      status = csnmp_config_add_host_version (hd, option);
+    else if (strcasecmp ("Collect", option->key) == 0)
+      csnmp_config_add_host_collect (hd, option);
+    else if (strcasecmp ("Interval", option->key) == 0)
+      csnmp_config_add_host_interval (hd, option);
+    else
+    {
+      WARNING ("snmp plugin: csnmp_config_add_host: Option `%s' not allowed here.", option->key);
+      status = -1;
+    }
+
+    if (status != 0)
+      break;
+  } /* for (ci->children) */
+
+  while (status == 0)
+  {
+    if (hd->address == NULL)
+    {
+      WARNING ("snmp plugin: `Address' not given for host `%s'", hd->name);
+      status = -1;
+      break;
+    }
+    if (hd->community == NULL)
+    {
+      WARNING ("snmp plugin: `Community' not given for host `%s'", hd->name);
+      status = -1;
+      break;
+    }
+
+    break;
+  } /* while (status == 0) */
+
+  if (status != 0)
+  {
+    sfree (hd->name);
+    sfree (hd);
+    return (-1);
+  }
+
+  DEBUG ("snmp plugin: hd = { name = %s, address = %s, community = %s, version = %i }",
+      hd->name, hd->address, hd->community, hd->version);
+
+  if (host_head == NULL)
+    host_head = hd;
+  else
+  {
+    host_definition_t *last;
+    last = host_head;
+    while (last->next != NULL)
+      last = last->next;
+    last->next = hd;
+  }
+
+  return (0);
+} /* int csnmp_config_add_host */
+
+static int csnmp_config (oconfig_item_t *ci)
+{
+  int i;
+
+  call_snmp_init_once ();
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *child = ci->children + i;
+    if (strcasecmp ("Data", child->key) == 0)
+      csnmp_config_add_data (child);
+    else if (strcasecmp ("Host", child->key) == 0)
+      csnmp_config_add_host (child);
+    else
+    {
+      WARNING ("snmp plugin: Ignoring unknown config option `%s'.", child->key);
+    }
+  } /* for (ci->children) */
+
+  return (0);
+} /* int csnmp_config */
+
+/* End of the config stuff. Now the interesting part begins */
+
+static void csnmp_host_close_session (host_definition_t *host)
+{
+  int status;
+
+  if (host->sess_handle == NULL)
+    return;
+
+  status = snmp_sess_close (host->sess_handle);
+
+  if (status != 0)
+  {
+    char *errstr = NULL;
+
+    snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
+
+    ERROR ("snmp plugin: host %s: snmp_sess_close failed: %s",
+       host->name, (errstr == NULL) ? "Unknown problem" : errstr);
+    sfree (errstr);
+  }
+
+  host->sess_handle = NULL;
+} /* void csnmp_host_close_session */
+
+static void csnmp_host_open_session (host_definition_t *host)
+{
+  struct snmp_session sess;
+
+  if (host->sess_handle != NULL)
+    csnmp_host_close_session (host);
+
+  snmp_sess_init (&sess);
+  sess.peername = host->address;
+  sess.community = (u_char *) host->community;
+  sess.community_len = strlen (host->community);
+  sess.version = (host->version == 1) ? SNMP_VERSION_1 : SNMP_VERSION_2c;
+
+  /* snmp_sess_open will copy the `struct snmp_session *'. */
+  host->sess_handle = snmp_sess_open (&sess);
+
+  if (host->sess_handle == NULL)
+  {
+    char *errstr = NULL;
+
+    snmp_error (&sess, NULL, NULL, &errstr);
+
+    ERROR ("snmp plugin: host %s: snmp_sess_open failed: %s",
+       host->name, (errstr == NULL) ? "Unknown problem" : errstr);
+    sfree (errstr);
+  }
+} /* void csnmp_host_open_session */
+
+static value_t csnmp_value_list_to_value (struct variable_list *vl, int type)
+{
+  value_t ret;
+  uint64_t temp = 0;
+  int defined = 1;
+
+  if ((vl->type == ASN_INTEGER)
+      || (vl->type == ASN_UINTEGER)
+      || (vl->type == ASN_COUNTER)
+#ifdef ASN_TIMETICKS
+      || (vl->type == ASN_TIMETICKS)
+#endif
+      || (vl->type == ASN_GAUGE))
+  {
+    temp = (uint32_t) *vl->val.integer;
+    DEBUG ("snmp plugin: Parsed int32 value is %llu.", temp);
+  }
+  else if (vl->type == ASN_COUNTER64)
+  {
+    temp = (uint32_t) vl->val.counter64->high;
+    temp = temp << 32;
+    temp += (uint32_t) vl->val.counter64->low;
+    DEBUG ("snmp plugin: Parsed int64 value is %llu.", temp);
+  }
+  else
+  {
+    WARNING ("snmp plugin: I don't know the ASN type `%i'", (int) vl->type);
+    defined = 0;
+  }
+
+  if (type == DS_TYPE_COUNTER)
+  {
+    ret.counter = temp;
+  }
+  else if (type == DS_TYPE_GAUGE)
+  {
+    ret.gauge = NAN;
+    if (defined != 0)
+      ret.gauge = temp;
+  }
+
+  return (ret);
+} /* value_t csnmp_value_list_to_value */
+
+static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *data,
+    csnmp_list_instances_t *instance_list,
+    csnmp_table_values_t **value_table)
+{
+  const data_set_t *ds;
+  value_list_t vl = VALUE_LIST_INIT;
+
+  csnmp_list_instances_t *instance_list_ptr;
+  csnmp_table_values_t **value_table_ptr;
+
+  int i;
+
+  ds = plugin_get_ds (data->type);
+  if (!ds)
+  {
+    ERROR ("snmp plugin: DataSet `%s' not defined.", data->type);
+    return (-1);
+  }
+  assert (ds->ds_num == data->values_len);
+
+  value_table_ptr = (csnmp_table_values_t **) malloc (sizeof (csnmp_table_values_t *)
+      * data->values_len);
+  if (value_table_ptr == NULL)
+    return (-1);
+  for (i = 0; i < data->values_len; i++)
+    value_table_ptr[i] = value_table[i];
+
+  vl.values_len = ds->ds_num;
+  vl.values = (value_t *) malloc (sizeof (value_t) * vl.values_len);
+  if (vl.values == NULL)
+  {
+    sfree (value_table_ptr);
+    return (-1);
+  }
+
+  strncpy (vl.host, host->name, sizeof (vl.host));
+  vl.host[sizeof (vl.host) - 1] = '\0';
+  strcpy (vl.plugin, "snmp");
+
+  vl.interval = host->interval;
+  vl.time = time (NULL);
+
+  for (instance_list_ptr = instance_list;
+      instance_list_ptr != NULL;
+      instance_list_ptr = instance_list_ptr->next)
+  {
+    strncpy (vl.type_instance, instance_list_ptr->instance, sizeof (vl.type_instance));
+    vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+
+    for (i = 0; i < data->values_len; i++)
+    {
+      while ((value_table_ptr[i] != NULL)
+         && (value_table_ptr[i]->subid < instance_list_ptr->subid))
+       value_table_ptr[i] = value_table_ptr[i]->next;
+      if ((value_table_ptr[i] == NULL)
+         || (value_table_ptr[i]->subid != instance_list_ptr->subid))
+       break;
+      vl.values[i] = value_table_ptr[i]->value;
+    } /* for (data->values_len) */
+
+    /* If the for-loop was aborted early, not all subid's match. */
+    if (i < data->values_len)
+    {
+      DEBUG ("snmp plugin: host = %s; data = %s; i = %i; "
+         "Skipping SUBID %i",
+         host->name, data->name, i, instance_list_ptr->subid);
+      continue;
+    }
+
+    /* If we get here `vl.type_instance' and all `vl.values' have been set */
+    plugin_dispatch_values (data->type, &vl);
+  } /* for (instance_list) */
+
+  sfree (vl.values);
+  sfree (value_table_ptr);
+
+  return (0);
+} /* int csnmp_dispatch_table */
+
+static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
+{
+  struct snmp_pdu *req;
+  struct snmp_pdu *res;
+  struct variable_list *vb;
+
+  const data_set_t *ds;
+  oid_t *oid_list;
+  uint32_t oid_list_len;
+
+  int status;
+  int i;
+
+  /* `value_table' and `value_table_ptr' implement a linked list for each
+   * value. `instance_list' and `instance_list_ptr' implement a linked list of
+   * instance names. This is used to jump gaps in the table. */
+  csnmp_list_instances_t *instance_list;
+  csnmp_list_instances_t *instance_list_ptr;
+  csnmp_table_values_t **value_table;
+  csnmp_table_values_t **value_table_ptr;
+
+  DEBUG ("snmp plugin: csnmp_read_table (host = %s, data = %s)",
+      host->name, data->name);
+
+  if (host->sess_handle == NULL)
+  {
+    DEBUG ("snmp plugin: csnmp_read_table: host->sess_handle == NULL");
+    return (-1);
+  }
+
+  ds = plugin_get_ds (data->type);
+  if (!ds)
+  {
+    ERROR ("snmp plugin: DataSet `%s' not defined.", data->type);
+    return (-1);
+  }
+
+  if (ds->ds_num != data->values_len)
+  {
+    ERROR ("snmp plugin: DataSet `%s' requires %i values, but config talks about %i",
+       data->type, ds->ds_num, data->values_len);
+    return (-1);
+  }
+
+  /* We need a copy of all the OIDs, because GETNEXT will destroy them. */
+  oid_list_len = data->values_len + 1;
+  oid_list = (oid_t *) malloc (sizeof (oid_t) * (oid_list_len));
+  if (oid_list == NULL)
+    return (-1);
+  memcpy (oid_list, &data->instance.oid, sizeof (oid_t));
+  for (i = 0; i < data->values_len; i++)
+    memcpy (oid_list + (i + 1), data->values + i, sizeof (oid_t));
+
+  /* Allocate the `value_table' */
+  value_table = (csnmp_table_values_t **) malloc (sizeof (csnmp_table_values_t *)
+      * 2 * data->values_len);
+  if (value_table == NULL)
+  {
+    sfree (oid_list);
+    return (-1);
+  }
+  memset (value_table, '\0', sizeof (csnmp_table_values_t *) * 2 * data->values_len);
+  value_table_ptr = value_table + data->values_len;
+  
+  instance_list = NULL;
+  instance_list_ptr = NULL;
+
+  status = 0;
+  while (status == 0)
+  {
+    csnmp_list_instances_t *il;
+
+    req = snmp_pdu_create (SNMP_MSG_GETNEXT);
+    if (req == NULL)
+    {
+      ERROR ("snmp plugin: snmp_pdu_create failed.");
+      status = -1;
+      break;
+    }
+
+    for (i = 0; i < oid_list_len; i++)
+      snmp_add_null_var (req, oid_list[i].oid, oid_list[i].oid_len);
+
+    status = snmp_sess_synch_response (host->sess_handle, req, &res);
+
+    if (status != STAT_SUCCESS)
+    {
+      char *errstr = NULL;
+
+      snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
+      ERROR ("snmp plugin: host %s: snmp_sess_synch_response failed: %s",
+         host->name, (errstr == NULL) ? "Unknown problem" : errstr);
+      csnmp_host_close_session (host);
+
+      status = -1;
+      break;
+    }
+    status = 0;
+    assert (res != NULL);
+
+    vb = res->variables;
+    if (vb == NULL)
+    {
+      status = -1;
+      break;
+    }
+
+    /* Check if we left the subtree */
+    if (snmp_oid_ncompare (data->instance.oid.oid, data->instance.oid.oid_len,
+         vb->name, vb->name_length,
+         data->instance.oid.oid_len) != 0)
+      break;
+
+    /* Allocate a new `csnmp_list_instances_t', insert the instance name and
+     * add it to the list */
+    il = (csnmp_list_instances_t *) malloc (sizeof (csnmp_list_instances_t));
+    if (il == NULL)
+    {
+      status = -1;
+      break;
+    }
+    il->subid = vb->name[vb->name_length - 1];
+    il->next = NULL;
+
+    /* Get instance name */
+    if ((vb->type == ASN_OCTET_STR) || (vb->type == ASN_BIT_STR))
+    {
+      char *ptr;
+      size_t instance_len;
+
+      instance_len = sizeof (il->instance) - 1;
+      if (instance_len > vb->val_len)
+       instance_len = vb->val_len;
+
+      strncpy (il->instance, (char *) ((vb->type == ASN_OCTET_STR)
+           ? vb->val.string
+           : vb->val.bitstring),
+         instance_len);
+      il->instance[instance_len] = '\0';
+
+      for (ptr = il->instance; *ptr != '\0'; ptr++)
+      {
+       if ((*ptr > 0) && (*ptr < 32))
+         *ptr = ' ';
+       else if (*ptr == '/')
+         *ptr = '_';
+      }
+      DEBUG ("snmp plugin: il->instance = `%s';", il->instance);
+    }
+    else
+    {
+      value_t val = csnmp_value_list_to_value (vb, DS_TYPE_COUNTER);
+      snprintf (il->instance, sizeof (il->instance),
+         "%llu", val.counter);
+    }
+    il->instance[sizeof (il->instance) - 1] = '\0';
+    DEBUG ("snmp plugin: data = `%s'; il->instance = `%s';",
+       data->name, il->instance);
+
+    if (instance_list_ptr == NULL)
+      instance_list = il;
+    else
+      instance_list_ptr->next = il;
+    instance_list_ptr = il;
+
+    /* Copy OID to oid_list[0] */
+    memcpy (oid_list[0].oid, vb->name, sizeof (oid) * vb->name_length);
+    oid_list[0].oid_len = vb->name_length;
+
+    for (i = 0; i < data->values_len; i++)
+    {
+      csnmp_table_values_t *vt;
+
+      vb = vb->next_variable;
+      if (vb == NULL)
+      {
+       status = -1;
+       break;
+      }
+
+      /* Check if we left the subtree */
+      if (snmp_oid_ncompare (data->values[i].oid,
+           data->values[i].oid_len,
+           vb->name, vb->name_length,
+           data->values[i].oid_len) != 0)
+      {
+       DEBUG ("snmp plugin: host = %s; data = %s; Value %i left its subtree.",
+           host->name, data->name, i);
+       continue;
+      }
+
+      if ((value_table_ptr[i] != NULL)
+         && (vb->name[vb->name_length - 1] <= value_table_ptr[i]->subid))
+      {
+       DEBUG ("snmp plugin: host = %s; data = %s; i = %i; SUBID is not increasing.",
+           host->name, data->name, i);
+       continue;
+      }
+
+      vt = (csnmp_table_values_t *) malloc (sizeof (csnmp_table_values_t));
+      if (vt != NULL)
+      {
+       vt->subid = vb->name[vb->name_length - 1];
+       vt->value = csnmp_value_list_to_value (vb, ds->ds[i].type);
+       vt->next = NULL;
+
+       if (value_table_ptr[i] == NULL)
+         value_table[i] = vt;
+       else
+         value_table_ptr[i]->next = vt;
+       value_table_ptr[i] = vt;
+      }
+
+      /* Copy OID to oid_list[i + 1] */
+      memcpy (oid_list[i + 1].oid, vb->name, sizeof (oid) * vb->name_length);
+      oid_list[i + 1].oid_len = vb->name_length;
+    } /* for (i = data->values_len) */
+
+    if (res != NULL)
+      snmp_free_pdu (res);
+    res = NULL;
+  } /* while (status == 0) */
+
+  if (status == 0)
+    csnmp_dispatch_table (host, data, instance_list, value_table);
+
+  /* Free all allocated variables here */
+  while (instance_list != NULL)
+  {
+    instance_list_ptr = instance_list->next;
+    sfree (instance_list);
+    instance_list = instance_list_ptr;
+  }
+
+  for (i = 0; i < data->values_len; i++)
+  {
+    csnmp_table_values_t *tmp;
+    while (value_table[i] != NULL)
+    {
+      tmp = value_table[i]->next;
+      sfree (value_table[i]);
+      value_table[i] = tmp;
+    }
+  }
+
+  sfree (value_table);
+  sfree (oid_list);
+
+  return (0);
+} /* int csnmp_read_table */
+
+static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
+{
+  struct snmp_pdu *req;
+  struct snmp_pdu *res;
+  struct variable_list *vb;
+
+  const data_set_t *ds;
+  value_list_t vl = VALUE_LIST_INIT;
+
+  int status;
+  int i;
+
+  DEBUG ("snmp plugin: csnmp_read_value (host = %s, data = %s)",
+      host->name, data->name);
+
+  if (host->sess_handle == NULL)
+  {
+    DEBUG ("snmp plugin: csnmp_read_table: host->sess_handle == NULL");
+    return (-1);
+  }
+
+  ds = plugin_get_ds (data->type);
+  if (!ds)
+  {
+    ERROR ("snmp plugin: DataSet `%s' not defined.", data->type);
+    return (-1);
+  }
+
+  if (ds->ds_num != data->values_len)
+  {
+    ERROR ("snmp plugin: DataSet `%s' requires %i values, but config talks about %i",
+       data->type, ds->ds_num, data->values_len);
+    return (-1);
+  }
+
+  vl.values_len = ds->ds_num;
+  vl.values = (value_t *) malloc (sizeof (value_t) * vl.values_len);
+  if (vl.values == NULL)
+    return (-1);
+  for (i = 0; i < vl.values_len; i++)
+  {
+    if (ds->ds[i].type == DS_TYPE_COUNTER)
+      vl.values[i].counter = 0;
+    else
+      vl.values[i].gauge = NAN;
+  }
+
+  strncpy (vl.host, host->name, sizeof (vl.host));
+  vl.host[sizeof (vl.host) - 1] = '\0';
+  strcpy (vl.plugin, "snmp");
+  strncpy (vl.type_instance, data->instance.string, sizeof (vl.type_instance));
+  vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+
+  vl.interval = host->interval;
+
+  req = snmp_pdu_create (SNMP_MSG_GET);
+  if (req == NULL)
+  {
+    ERROR ("snmp plugin: snmp_pdu_create failed.");
+    sfree (vl.values);
+    return (-1);
+  }
+
+  for (i = 0; i < data->values_len; i++)
+    snmp_add_null_var (req, data->values[i].oid, data->values[i].oid_len);
+  status = snmp_sess_synch_response (host->sess_handle, req, &res);
+
+  if (status != STAT_SUCCESS)
+  {
+    char *errstr = NULL;
+
+    snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
+    ERROR ("snmp plugin: host %s: snmp_sess_synch_response failed: %s",
+       host->name, (errstr == NULL) ? "Unknown problem" : errstr);
+    csnmp_host_close_session (host);
+    sfree (errstr);
+
+    return (-1);
+  }
+
+  vl.time = time (NULL);
+
+  for (vb = res->variables; vb != NULL; vb = vb->next_variable)
+  {
+#if COLLECT_DEBUG
+    char buffer[1024];
+    snprint_variable (buffer, sizeof (buffer),
+       vb->name, vb->name_length, vb);
+    DEBUG ("snmp plugin: Got this variable: %s", buffer);
+#endif /* COLLECT_DEBUG */
+
+    for (i = 0; i < data->values_len; i++)
+      if (snmp_oid_compare (data->values[i].oid, data->values[i].oid_len,
+           vb->name, vb->name_length) == 0)
+       vl.values[i] = csnmp_value_list_to_value (vb, ds->ds[i].type);
+  } /* for (res->variables) */
+
+  snmp_free_pdu (res);
+
+  DEBUG ("snmp plugin: -> plugin_dispatch_values (%s, &vl);", data->type);
+  plugin_dispatch_values (data->type, &vl);
+  sfree (vl.values);
+
+  return (0);
+} /* int csnmp_read_value */
+
+static int csnmp_read_host (host_definition_t *host)
+{
+  int i;
+  time_t time_start;
+  time_t time_end;
+
+  time_start = time (NULL);
+  DEBUG ("snmp plugin: csnmp_read_host (%s) started at %u;", host->name,
+      (unsigned int) time_start);
+
+  if (host->sess_handle == NULL)
+    csnmp_host_open_session (host);
+
+  if (host->sess_handle == NULL)
+    return (-1);
+
+  for (i = 0; i < host->data_list_len; i++)
+  {
+    data_definition_t *data = host->data_list[i];
+
+    if (data->is_table)
+      csnmp_read_table (host, data);
+    else
+      csnmp_read_value (host, data);
+  }
+
+  time_end = time (NULL);
+  DEBUG ("snmp plugin: csnmp_read_host (%s) finished at %u;", host->name,
+      (unsigned int) time_end);
+  if ((time_end - time_start) > host->interval)
+  {
+    WARNING ("snmp plugin: Host `%s' should be queried every %i seconds, "
+       "but reading all values takes %i seconds.",
+       host->name, host->interval, time_end - time_start);
+  }
+
+  return (0);
+} /* int csnmp_read_host */
+
+static void *csnmp_read_thread (void *data)
+{
+  host_definition_t *host;
+
+  pthread_mutex_lock (&host_lock);
+  while (do_shutdown == 0)
+  {
+    pthread_cond_wait (&host_cond, &host_lock);
+
+    for (host = host_head; host != NULL; host = host->next)
+    {
+      if (do_shutdown != 0)
+       break;
+      if (host->state != STATE_WAIT)
+       continue;
+
+      host->state = STATE_BUSY;
+      pthread_mutex_unlock (&host_lock);
+      csnmp_read_host (host);
+      pthread_mutex_lock (&host_lock);
+      host->state = STATE_IDLE;
+    } /* for (host) */
+  } /* while (do_shutdown == 0) */
+  pthread_mutex_unlock (&host_lock);
+
+  pthread_exit ((void *) 0);
+  return ((void *) 0);
+} /* void *csnmp_read_thread */
+
+static int csnmp_init (void)
+{
+  host_definition_t *host;
+  int i;
+
+  if (host_head == NULL)
+  {
+    NOTICE ("snmp plugin: No host has been defined.");
+    return (-1);
+  }
+
+  call_snmp_init_once ();
+
+  threads_num = 0;
+  for (host = host_head; host != NULL; host = host->next)
+  {
+    threads_num++;
+    /* We need to initialize `interval' here, because `interval_g' isn't
+     * initialized during `configure'. */
+    host->next_update = time (NULL);
+    if (host->interval == 0)
+    {
+      host->interval = interval_g;
+    }
+    else if (host->interval < interval_g)
+    {
+      host->interval = interval_g;
+      WARNING ("snmp plugin: Data for host `%s' will be collected every %i seconds.",
+         host->name, host->interval);
+    }
+
+    csnmp_host_open_session (host);
+  } /* for (host) */
+
+  /* Now start the reading threads */
+  if (threads_num > 3)
+  {
+    threads_num = 3 + ((threads_num - 3) / 10);
+    if (threads_num > 10)
+      threads_num = 10;
+  }
+
+  threads = (pthread_t *) malloc (threads_num * sizeof (pthread_t));
+  if (threads == NULL)
+  {
+    ERROR ("snmp plugin: malloc failed.");
+    return (-1);
+  }
+  memset (threads, '\0', threads_num * sizeof (pthread_t));
+
+  for (i = 0; i < threads_num; i++)
+      pthread_create (threads + i, NULL, csnmp_read_thread, (void *) 0);
+
+  return (0);
+} /* int csnmp_init */
+
+static int csnmp_read (void)
+{
+  host_definition_t *host;
+  time_t now;
+
+  if (host_head == NULL)
+  {
+    INFO ("snmp plugin: No hosts configured.");
+    return (-1);
+  }
+
+  now = time (NULL);
+
+  pthread_mutex_lock (&host_lock);
+  for (host = host_head; host != NULL; host = host->next)
+  {
+    if (host->state != STATE_IDLE)
+      continue;
+
+    /* Skip this host if the next or a later iteration will be sufficient. */
+    if (host->next_update >= (now + interval_g))
+      continue;
+
+    host->state = STATE_WAIT;
+    host->next_update = now + host->interval;
+  } /* for (host) */
+
+  pthread_cond_broadcast (&host_cond);
+  pthread_mutex_unlock (&host_lock);
+
+  return (0);
+} /* int csnmp_read */
+
+static int csnmp_shutdown (void)
+{
+  host_definition_t *host_this;
+  host_definition_t *host_next;
+
+  data_definition_t *data_this;
+  data_definition_t *data_next;
+
+  int i;
+
+  pthread_mutex_lock (&host_lock);
+  do_shutdown = 1;
+  pthread_cond_broadcast (&host_cond);
+  pthread_mutex_unlock (&host_lock);
+
+  for (i = 0; i < threads_num; i++)
+    pthread_join (threads[i], NULL);
+
+  /* Now that all the threads have exited, let's free all the global variables.
+   * This isn't really neccessary, I guess, but I think it's good stile to do
+   * so anyway. */
+  host_this = host_head;
+  host_head = NULL;
+  while (host_this != NULL)
+  {
+    host_next = host_this->next;
+
+    csnmp_host_close_session (host_this);
+
+    sfree (host_this->name);
+    sfree (host_this->address);
+    sfree (host_this->community);
+    sfree (host_this->data_list);
+    sfree (host_this);
+
+    host_this = host_next;
+  }
+
+  data_this = data_head;
+  data_head = NULL;
+  while (data_this != NULL)
+  {
+    data_next = data_this->next;
+
+    sfree (data_this->name);
+    sfree (data_this->type);
+    sfree (data_this->values);
+    sfree (data_this);
+
+    data_this = data_next;
+  }
+
+  return (0);
+} /* int csnmp_shutdown */
+
+void module_register (void)
+{
+  plugin_register_complex_config ("snmp", csnmp_config);
+  plugin_register_init ("snmp", csnmp_init);
+  plugin_register_read ("snmp", csnmp_read);
+  plugin_register_shutdown ("snmp", csnmp_shutdown);
+} /* void module_register */
+
+/*
+ * vim: shiftwidth=2 softtabstop=2 tabstop=8
+ */
index 3018cb9..4a414b7 100644 (file)
 #  include <kvm.h>
 #endif
 
-#if KERNEL_LINUX || HAVE_LIBKSTAT || defined(VM_SWAPUSAGE) || HAVE_LIBKVM || HAVE_LIBSTATGRAB
-# define SWAP_HAVE_READ 1
-#else
-# define SWAP_HAVE_READ 0
-#endif
-
 #undef  MAX
 #define MAX(x,y) ((x) > (y) ? (x) : (y))
 
-#if SWAP_HAVE_READ
 #if KERNEL_LINUX
 /* No global variables */
 /* #endif KERNEL_LINUX */
@@ -66,6 +59,10 @@ int kvm_pagesize;
 
 #elif HAVE_LIBSTATGRAB
 /* No global variables */
+/* #endif HAVE_LIBSTATGRAB */
+
+#else
+# error "No applicable input method."
 #endif /* HAVE_LIBSTATGRAB */
 
 static int swap_init (void)
@@ -300,12 +297,9 @@ static int swap_read (void)
 
        return (0);
 } /* int swap_read */
-#endif /* SWAP_HAVE_READ */
 
 void module_register (void)
 {
-#if SWAP_HAVE_READ
        plugin_register_init ("swap", swap_init);
        plugin_register_read ("swap", swap_read);
-#endif /* SWAP_HAVE_READ */
 } /* void module_register */
index 5e01f0d..465688e 100644 (file)
 #include "common.h"
 #include "plugin.h"
 
-#if defined(HAVE_LIBKSTAT)
-# define TAPE_HAVE_READ 1
-#else
-# define TAPE_HAVE_READ 0
+#if !HAVE_LIBKSTAT
+# error "No applicable input method."
 #endif
 
-#if TAPE_HAVE_READ
-#if defined(HAVE_LIBKSTAT)
 #define MAX_NUMTAPE 256
 extern kstat_ctl_t *kc;
 static kstat_t *ksp[MAX_NUMTAPE];
 static int numtape = 0;
-#endif /* HAVE_LIBKSTAT */
 
 static int tape_init (void)
 {
-#ifdef HAVE_LIBKSTAT
        kstat_t *ksp_chain;
 
        numtape = 0;
@@ -58,10 +52,9 @@ static int tape_init (void)
                        continue;
                ksp[numtape++] = ksp_chain;
        }
-#endif
 
        return (0);
-}
+} /* int tape_init */
 
 static void tape_submit (const char *plugin_instance,
                const char *type,
@@ -87,24 +80,23 @@ static void tape_submit (const char *plugin_instance,
 static int tape_read (void)
 {
 
-#if defined(HAVE_LIBKSTAT)
-# if HAVE_KSTAT_IO_T_WRITES && HAVE_KSTAT_IO_T_NWRITES && HAVE_KSTAT_IO_T_WTIME
-#  define KIO_ROCTETS reads
-#  define KIO_WOCTETS writes
-#  define KIO_ROPS    nreads
-#  define KIO_WOPS    nwrites
-#  define KIO_RTIME   rtime
-#  define KIO_WTIME   wtime
-# elif HAVE_KSTAT_IO_T_NWRITTEN && HAVE_KSTAT_IO_T_WRITES && HAVE_KSTAT_IO_T_WTIME
-#  define KIO_ROCTETS nread
-#  define KIO_WOCTETS nwritten
-#  define KIO_ROPS    reads
-#  define KIO_WOPS    writes
-#  define KIO_RTIME   rtime
-#  define KIO_WTIME   wtime
-# else
-#  error "kstat_io_t does not have the required members"
-# endif
+#if HAVE_KSTAT_IO_T_WRITES && HAVE_KSTAT_IO_T_NWRITES && HAVE_KSTAT_IO_T_WTIME
+# define KIO_ROCTETS reads
+# define KIO_WOCTETS writes
+# define KIO_ROPS    nreads
+# define KIO_WOPS    nwrites
+# define KIO_RTIME   rtime
+# define KIO_WTIME   wtime
+#elif HAVE_KSTAT_IO_T_NWRITTEN && HAVE_KSTAT_IO_T_WRITES && HAVE_KSTAT_IO_T_WTIME
+# define KIO_ROCTETS nread
+# define KIO_WOCTETS nwritten
+# define KIO_ROPS    reads
+# define KIO_WOPS    writes
+# define KIO_RTIME   rtime
+# define KIO_WTIME   wtime
+#else
+# error "kstat_io_t does not have the required members"
+#endif
        static kstat_io_t kio;
        int i;
 
@@ -130,16 +122,12 @@ static int tape_read (void)
                                        kio.KIO_RTIME, kio.KIO_WTIME);
                }
        }
-#endif /* defined(HAVE_LIBKSTAT) */
 
        return (0);
 }
-#endif /* TAPE_HAVE_READ */
 
 void module_register (void)
 {
-#if TAPE_HAVE_READ
        plugin_register_init ("tape", tape_init);
        plugin_register_read ("tape", tape_read);
-#endif /* TAPE_HAVE_READ */
 }
index 68b966b..884dfcd 100644 (file)
@@ -2,6 +2,7 @@ apache_bytes            count:COUNTER:0:134217728
 apache_connections     count:GAUGE:0:65535
 apache_requests                count:COUNTER:0:134217728
 apache_scoreboard      count:GAUGE:0:65535
+bitrate                        value:GAUGE:0:4294967295
 charge                 value:GAUGE:0:U
 counter                        value:COUNTER:U:U
 cpu                    value:COUNTER:0:4294967295
@@ -26,9 +27,14 @@ frequency            frequency:GAUGE:0:U
 frequency_offset       ppm:GAUGE:-1000000:1000000
 gauge                  value:GAUGE:U:U
 humitidy               value:GAUGE:0:100
+if_collisions          value:COUNTER:0:4294967295
+if_dropped             rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
 if_errors              rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
+if_multicast           value:COUNTER:0:4294967295
 if_octets              rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
 if_packets             rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
+if_rx_errors           value:COUNTER:0:4294967295
+if_tx_errors           value:COUNTER:0:4294967295
 ipt_bytes              value:COUNTER:0:134217728
 ipt_packets            value:COUNTER:0:134217728
 irq                    value:COUNTER:U:65535
index ddf4b67..43e29c2 100644 (file)
@@ -23,6 +23,7 @@
 #include "common.h"
 #include "plugin.h"
 #include "configfile.h"
+#include "utils_cmd_putval.h"
 
 /* Folks without pthread will need to disable this plugin. */
 #include <pthread.h>
@@ -36,7 +37,7 @@
 # define UNIX_PATH_MAX sizeof (((struct sockaddr_un *)0)->sun_path)
 #endif
 
-#define US_DEFAULT_PATH PREFIX"/var/run/"PACKAGE_NAME"-unixsock"
+#define US_DEFAULT_PATH LOCALSTATEDIR"/run/"PACKAGE_NAME"-unixsock"
 
 /*
  * Private data structures
@@ -329,7 +330,7 @@ static void cache_flush (int max_age)
        } /* while (this != NULL) */
 
        pthread_mutex_unlock (&cache_lock);
-} /* int cache_flush */
+} /* void cache_flush */
 
 static int us_open_socket (void)
 {
@@ -488,148 +489,55 @@ static int us_handle_getval (FILE *fh, char **fields, int fields_num)
        return (0);
 } /* int us_handle_getval */
 
-static int us_handle_putval (FILE *fh, char **fields, int fields_num)
+static int us_handle_listval (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;
+       char buffer[1024];
+       char **value_list = NULL;
+       int value_list_len = 0;
+       value_cache_t *entry;
+       int i;
 
-       if (fields_num != 3)
+       if (fields_num != 1)
        {
-               DEBUG ("unixsock plugin: Wrong number of fields: %i", fields_num);
-               fprintf (fh, "-1 Wrong number of fields: Got %i, expected 3.\n",
+               DEBUG ("unixsock plugin: us_handle_listval: "
+                               "Wrong number of fields: %i", fields_num);
+               fprintf (fh, "-1 Wrong number of fields: Got %i, expected 1.\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);
-       }
-
-       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))))
-       {
-               fprintf (fh, "-1 Identifier too long.");
-               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)
-               {
-                       fprintf (fh, "-1 No time found.");
-                       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 *));
-       if (value_ptr == NULL)
-       {
-               fprintf (fh, "-1 calloc failed.");
-               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);
-                       fprintf (fh, "-1 Number of values incorrect: Got %i, "
-                                       "expected %i.", i, ds->ds_num);
-                       return (-1);
-               }
-       } /* done parsing the value-list */
+       pthread_mutex_lock (&cache_lock);
 
-       vl.values_len = ds->ds_num;
-       vl.values = (value_t *) malloc (vl.values_len * sizeof (value_t));
-       if (vl.values == NULL)
+       for (entry = cache_head; entry != NULL; entry = entry->next)
        {
-               sfree (value_ptr);
-               fprintf (fh, "-1 malloc failed.");
-               return (-1);
-       }
-       DEBUG ("value_ptr = 0x%p; vl.values = 0x%p;", (void *) value_ptr, (void *) vl.values);
+               char **tmp;
 
-       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) */
+               snprintf (buffer, sizeof (buffer), "%u %s\n",
+                               (unsigned int) entry->time, entry->name);
+               buffer[sizeof (buffer) - 1] = '\0';
+               
+               tmp = realloc (value_list, sizeof (char *) * (value_list_len + 1));
+               if (tmp == NULL)
+                       continue;
+               value_list = tmp;
 
-       plugin_dispatch_values (type, &vl);
+               value_list[value_list_len] = strdup (buffer);
 
-       DEBUG ("value_ptr = 0x%p; vl.values = 0x%p;", (void *) value_ptr, (void *) vl.values);
+               if (value_list[value_list_len] != NULL)
+                       value_list_len++;
+       } /* for (entry) */
 
-       sfree (value_ptr);
-       sfree (vl.values); 
+       pthread_mutex_unlock (&cache_lock);
 
-       fprintf (fh, "0 Success\n");
+       DEBUG ("unixsock plugin: us_handle_listval: value_list_len = %i", value_list_len);
+       fprintf (fh, "%i Values found\n", value_list_len);
+       for (i = 0; i < value_list_len; i++)
+               fputs (value_list[i], fh);
        fflush (fh);
 
        return (0);
-} /* int us_handle_putval */
+} /* int us_handle_listval */
 
 static void *us_handle_client (void *arg)
 {
@@ -684,7 +592,11 @@ static void *us_handle_client (void *arg)
                }
                else if (strcasecmp (fields[0], "putval") == 0)
                {
-                       us_handle_putval (fh, fields, fields_num);
+                       handle_putval (fh, fields, fields_num);
+               }
+               else if (strcasecmp (fields[0], "listval") == 0)
+               {
+                       us_handle_listval (fh, fields, fields_num);
                }
                else
                {
index 7df06c2..afe26e1 100644 (file)
 
 #if HAVE_UTMPX_H
 # include <utmpx.h>
-#else /* !HAVE_UTMPX_H */
-# if HAVE_UTMP_H
-#  include <utmp.h>
-# endif /* HAVE_UTMP_H */
-#endif /* HAVE_UTMPX_H */
+/* #endif HAVE_UTMPX_H */
 
-#define MODULE_NAME "users"
+#elif HAVE_UTMP_H
+# include <utmp.h>
+/* #endif HAVE_UTMP_H */
 
-#if HAVE_GETUTXENT || HAVE_GETUTENT
-# define USERS_HAVE_READ 1
 #else
-# define USERS_HAVE_READ 0
+# error "No applicable input method."
 #endif
 
-#if USERS_HAVE_READ
 static void users_submit (gauge_t value)
 {
        value_t values[1];
@@ -92,15 +87,16 @@ static int users_read (void)
        endutent();
 
        users_submit (users);
-#endif /* HAVE_GETUTENT */
+/* #endif HAVE_GETUTENT */
+
+#else
+# error "No applicable input method."
+#endif
 
        return (0);
 } /* int users_read */
-#endif /* USERS_HAVE_READ */
 
 void module_register (void)
 {
-#if USERS_HAVE_READ
        plugin_register_read ("users", users_read);
-#endif
 } /* void module_register(void) */
diff --git a/src/utils_cmd_putval.c b/src/utils_cmd_putval.c
new file mode 100644 (file)
index 0000000..7cf0b6d
--- /dev/null
@@ -0,0 +1,217 @@
+/**
+ * collectd - src/utils_cms_putval.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"
+
+static int parse_value (const data_set_t *ds, value_list_t *vl,
+               const char *type,
+               FILE *fh, char *buffer)
+{
+       char *dummy;
+       char *ptr;
+       char *saveptr;
+       int i;
+
+       char *time_str = buffer;
+       char *value_str = strchr (time_str, ':');
+       if (value_str == NULL)
+       {
+               fprintf (fh, "-1 No time found.");
+               return (-1);
+       }
+       *value_str = '\0'; value_str++;
+
+       vl->time = (time_t) atoi (time_str);
+       if (vl->time == 0)
+               vl->time = time (NULL);
+
+       i = 0;
+       dummy = value_str;
+       saveptr = NULL;
+       while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL)
+       {
+               dummy = NULL;
+
+               if (i >= vl->values_len)
+               {
+                       i = vl->values_len + 1;
+                       break;
+               }
+
+               if (strcmp (ptr, "U") == 0)
+                       vl->values[i].gauge = NAN;
+               else if (ds->ds[i].type == DS_TYPE_COUNTER)
+                       vl->values[i].counter = atoll (ptr);
+               else if (ds->ds[i].type == DS_TYPE_GAUGE)
+                       vl->values[i].gauge = atof (ptr);
+
+               i++;
+       } /* while (strtok_r) */
+
+       if (i != vl->values_len)
+       {
+               char identifier[128];
+               FORMAT_VL (identifier, sizeof (identifier), vl, ds);
+               ERROR ("cmd putval: parse_value: "
+                               "Number of values incorrect: "
+                               "Got %i, expected %i. Identifier is `%s'.",
+                               i, vl->values_len, identifier);
+               fprintf (fh, "-1 Number of values incorrect: "
+                               "Got %i, expected %i.\n",
+                               i, vl->values_len);
+               return (-1);
+       }
+
+       plugin_dispatch_values (type, vl);
+       return (0);
+} /* int parse_value */
+
+static int parse_option (value_list_t *vl, char *buffer)
+{
+       char *option = buffer;
+       char *value;
+
+       if ((vl == NULL) || (option == NULL))
+               return (-1);
+
+       value = strchr (option, '=');
+       if (value == NULL)
+               return (-1);
+       *value = '\0'; value++;
+
+       if (strcasecmp ("interval", option) == 0)
+       {
+               vl->interval = atoi (value);
+               if (vl->interval <= 0)
+                       vl->interval = interval_g;
+       }
+       else
+               return (1);
+
+       return (0);
+} /* int parse_option */
+
+int 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;
+
+       if (fields_num < 3)
+       {
+               DEBUG ("cmd putval: Wrong number of fields: %i",
+                               fields_num);
+               fprintf (fh, "-1 Wrong number of fields: Got %i, "
+                               "expected at least 3.\n",
+                               fields_num);
+               fflush (fh);
+               return (-1);
+       }
+
+       status = parse_identifier (fields[1], &hostname,
+                       &plugin, &plugin_instance,
+                       &type, &type_instance);
+       if (status != 0)
+       {
+               DEBUG ("cmd putval: Cannot parse `%s'", fields[1]);
+               fprintf (fh, "-1 Cannot parse identifier.\n");
+               fflush (fh);
+               return (-1);
+       }
+
+       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))))
+       {
+               fprintf (fh, "-1 Identifier too long.");
+               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);
+
+       ds = plugin_get_ds (type);
+       if (ds == NULL)
+               return (-1);
+
+       vl.values_len = ds->ds_num;
+       vl.values = (value_t *) malloc (vl.values_len * sizeof (value_t));
+       if (vl.values == NULL)
+       {
+               fprintf (fh, "-1 malloc failed.");
+               return (-1);
+       }
+
+       /* All the remaining fields are part of the optionlist. */
+       for (i = 2; i < fields_num; i++)
+       {
+               if (strchr (fields[i], ':') != NULL)
+               {
+                       /* It's parse_value's job to write an error to `fh'.
+                        * This is not the case with `parse_option below.
+                        * Neither will write an success message. */
+                       if (parse_value (ds, &vl, type, fh, fields[i]) != 0)
+                               break;
+               }
+               else if (strchr (fields[i], '=') != NULL)
+               {
+                       if (parse_option (&vl, fields[i]) != 0)
+                       {
+                               fprintf (fh, "-1 Error parsing option `%s'",
+                                               fields[i]);
+                               break;
+                       }
+               }
+               else
+               {
+                       WARNING ("cmd putval: handle_putval: "
+                                       "Cannot parse field #%i `%s'; "
+                                       "Ignoring it.\n",
+                                       i, fields[i]);
+               }
+       }
+       /* Done parsing the options. */
+
+       if (i == fields_num)
+               fprintf (fh, "0 Success\n");
+       fflush (fh);
+
+       sfree (vl.values); 
+
+       return (0);
+} /* int handle_putval */
+
diff --git a/src/utils_cmd_putval.h b/src/utils_cmd_putval.h
new file mode 100644 (file)
index 0000000..609efcb
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+ * collectd - src/utils_cms_putval.h
+ * 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>
+ **/
+
+#ifndef UTILS_CMD_PUTVAL_H
+#define UTILS_CMD_PUTVAL_H 1
+
+#include "plugin.h"
+
+int handle_putval (FILE *fh, char **fields, int fields_num);
+
+#endif /* UTILS_CMD_PUTVAL_H */
index 8d524e7..7b83c61 100644 (file)
 
 #define BUFSIZE 512
 
-#define MODULE_NAME "vserver"
 #define PROCDIR "/proc/virtual"
 
-#if defined(KERNEL_LINUX)
-# define VSERVER_HAVE_READ 1
-#else
-# define VSERVER_HAVE_READ 0
-#endif /* defined(KERNEL_LINUX) */
+#if !KERNEL_LINUX
+# error "No applicable input method."
+#endif
 
-#if VSERVER_HAVE_READ
 static int pagesize = 0;
 
 static int vserver_init (void)
@@ -306,14 +302,11 @@ static int vserver_read (void)
 
        return (0);
 } /* int vserver_read */
-#endif /* VSERVER_HAVE_READ */
 
 void module_register (void)
 {
-#if VSERVER_HAVE_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 1067549..4870598 100644 (file)
 #include "common.h"
 #include "plugin.h"
 
-#if defined(KERNEL_LINUX)
-# define WIRELESS_HAVE_READ 1
-#else
-# define WIRELESS_HAVE_READ 0
+#if !KERNEL_LINUX
+# error "No applicable input method."
 #endif
 
 #define WIRELESS_PROC_FILE "/proc/net/wireless"
 
-#if WIRELESS_HAVE_READ
 #if 0
 static double wireless_dbm_to_watt (double dbm)
 {
@@ -160,11 +157,8 @@ static int wireless_read (void)
 
        return (0);
 } /* int wireless_read */
-#endif /* WIRELESS_HAVE_READ */
 
 void module_register (void)
 {
-#if WIRELESS_HAVE_READ
        plugin_register_read ("wireless", wireless_read);
-#endif /* WIRELESS_HAVE_READ */
 } /* void module_register */
diff --git a/src/xmms.c b/src/xmms.c
new file mode 100644 (file)
index 0000000..1e646d2
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+ * collectd - src/xmms.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"
+
+#include <xmms/xmmsctrl.h>
+
+static gint xmms_session;
+
+static void cxmms_submit (const char *type, gauge_t value)
+{
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
+
+       values[0].gauge = value;
+
+       vl.values = values;
+       vl.values_len = 1;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname_g);
+       strcpy (vl.plugin, "xmms");
+
+       plugin_dispatch_values (type, &vl);
+} /* void cxmms_submit */
+
+int cxmms_read (void)
+{
+  gint rate;
+  gint freq;
+  gint nch;
+
+  if (!xmms_remote_is_running (xmms_session))
+    return (0);
+
+  xmms_remote_get_info (xmms_session, &rate, &freq, &nch);
+
+  if ((freq == 0) || (nch == 0))
+    return (-1);
+
+  cxmms_submit ("bitrate", rate);
+  cxmms_submit ("frequency", freq);
+
+  return (0);
+} /* int read */
+
+void module_register (void)
+{
+  plugin_register_read ("xmms", cxmms_read);
+} /* void module_register */
+
+/*
+ * vim: shiftwidth=2:softtabstop=2:textwidth=78
+ */
diff --git a/version-gen.sh b/version-gen.sh
new file mode 100755 (executable)
index 0000000..acae67b
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+DEFAULT_VERSION="4.1.2.git"
+
+VERSION="$( git describe 2> /dev/null | sed -e 's/^collectd-//' )"
+
+if test -z "$VERSION"; then
+       VERSION="$DEFAULT_VERSION"
+fi
+
+VERSION=$( echo "$VERSION" | sed -e 's/-/./g' )
+
+echo -n $VERSION
+