Merge branch 'collectd-4.4' into collectd-4.5
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Sat, 24 Jan 2009 10:04:22 +0000 (11:04 +0100)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Sat, 24 Jan 2009 10:04:22 +0000 (11:04 +0100)
108 files changed:
AUTHORS
ChangeLog
README
TODO
bindings/perl/Collectd.pm
bindings/perl/Collectd/Unixsock.pm
configure.in
contrib/collection.cgi
contrib/cussh.pl
contrib/examples/myplugin.c
src/Makefile.am
src/apache.c
src/apcups.c
src/apple_sensors.c
src/ascent.c
src/battery.c
src/collectd-exec.pod
src/collectd-perl.pod
src/collectd-unixsock.pod
src/collectd.c
src/collectd.conf.in
src/collectd.conf.pod
src/collectd.h
src/common.c
src/common.h
src/configfile.c
src/cpu.c
src/cpufreq.c
src/csv.c
src/df.c
src/disk.c
src/dns.c
src/email.c
src/entropy.c
src/exec.c
src/filecount.c [new file with mode: 0644]
src/hddtemp.c
src/interface.c
src/ipmi.c
src/iptables.c
src/ipvs.c
src/irq.c
src/libiptc/Makefile.am
src/liboconfig/scanner.l
src/libvirt.c
src/load.c
src/logfile.c
src/mbmon.c
src/memcached.c
src/memory.c
src/multimeter.c
src/mysql.c
src/netlink.c
src/network.c
src/nfs.c
src/nginx.c
src/notify_desktop.c [new file with mode: 0644]
src/notify_email.c [new file with mode: 0644]
src/ntpd.c
src/nut.c
src/onewire.c [new file with mode: 0644]
src/perl.c
src/ping.c
src/plugin.c
src/plugin.h
src/postgresql.c [new file with mode: 0644]
src/postgresql_default.conf [new file with mode: 0644]
src/powerdns.c
src/processes.c
src/rrdtool.c
src/sensors.c
src/serial.c
src/snmp.c
src/swap.c
src/tape.c
src/tcpconns.c
src/teamspeak2.c
src/thermal.c [new file with mode: 0644]
src/types.db
src/types_list.c
src/unixsock.c
src/users.c
src/utils_cache.c
src/utils_cmd_flush.c
src/utils_cmd_flush.h
src/utils_cmd_getval.c
src/utils_cmd_getval.h
src/utils_cmd_listval.c
src/utils_cmd_listval.h
src/utils_cmd_putnotif.c
src/utils_cmd_putnotif.h
src/utils_cmd_putval.c
src/utils_cmd_putval.h
src/utils_complain.c [new file with mode: 0644]
src/utils_complain.h [new file with mode: 0644]
src/utils_dns.c
src/utils_ignorelist.c
src/utils_mount.c
src/utils_parse_option.c [new file with mode: 0644]
src/utils_parse_option.h [new file with mode: 0644]
src/utils_tail_match.c
src/utils_threshold.c
src/uuid.c
src/vmem.c
src/vserver.c
src/wireless.c
src/xmms.c
version-gen.sh

diff --git a/AUTHORS b/AUTHORS
index 7f92d55..234d431 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,82 +1,98 @@
-This package was written by:
-  Florian octo Forster <octo at verplant.org>
+Permanent project members
+=========================
 
-apcups plugin by:
-  Anthony Gialluca <tonyabg at charter.net>
+Florian "octo" Forster <octo at verplant.org>
+ - Initial author.
 
-cpufreq, multimeter and irq plugin, as well as some bugfixes in the exec plugin
-by:
-  Peter Holik <peter at holik.at>
+Sebastian "tokkee" Harl <sh at tokkee.org>
+ - Bugfixes and enhancments in many places all around the project.
+ - perl plugin.
+ - users plugin.
+ - vserver plugin.
+ - Debian package.
 
-hddtemp plugin by:
-  Vincent Stehlé <vincent.stehle at free.fr>
 
-iptables plugin by:
-  Sjoerd van der Berg <harekiet at gmail.com>
+Contributors (sorted alphabetically)
+====================================
 
-libvirt plugin by:
-  Richard W. M. Jones <rjones at redhat.com>
+Alessandro Iurlano <alessandro.iurlano at gmail.com>
+ - Initial filecount plugin.
 
-mbmon plugin by:
-  Flavio Stanchina <flavio at stanchina.net>
+Alvaro Barcellos <alvaro.barcellos at gmail.com>
+ - Don't-fork patch.
 
-memcached plugin by:
-  Antony Dovgal <tony at daylessday.org>
+Anthony Gialluca <tonyabg at charter.net>
+ - apcups plugin.
 
-nfs plugin by:
-  Jason Pepas <cell at ices.utexas.edu>
+Antony Dovgal <tony at daylessday.org>
+ - memcached plugin.
 
-perl plugin by:
-  Sebastian Harl <sh at tokkee.org>
+Christophe Kalt <collectd at klb.taranis.org>
+ - The version 3 `log' mode.
+ - Many Solaris related hints and fixes.
 
-powerdns plugin and initial `tail' subsystem by:
-  Luke Herberling <collectd at c-ware.com>
+Dan Berrange <berrange at redhat.com>
+ - uuid plugin.
 
-processes plugin by:
-  Lyonel Vincent <lyonel at ezix.org>
+David Bacher <drbacher at gmail.com>
+ - serial plugin.
 
-sensors plugin has been improved by:
-  LuboÅ¡ StanÄ›k <kolektor at atlas.cz>
+Flavio Stanchina <flavio at stanchina.net>
+ - mbmon plugin.
 
-serial plugin by:
-  David Bacher <drbacher at gmail.com>
+Jason Pepas <cell at ices.utexas.edu>
+ - nfs plugin.
 
-tape plugin by:
-  Scott Garrett <sgarrett at technomancer.com>
+LuboÅ¡ StanÄ›k <kolektor at atlas.cz>
+ - sensors plugin improvements.
+ - Time and effort to find a nasty bug in the ntpd-plugin.
 
-teamspeak2 plugin by:
-  Stefan Hacker <stefan.hacker at web.de>
+Luke Herberling <collectd at c-ware.com>
+ - powerdns plugin.
+ - Initial `tail' subsystem by:
 
-users plugin by:
-  Sebastian Harl <sh at tokkee.org>
+Lyonel Vincent <lyonel at ezix.org>
+ - processes plugin.
 
-uuid plugin by:
-  Dan Berrange <berrange at redhat.com>
-  Richard W.M. Jones <rjones at redhat.com>
+Michael Stapelberg <michael+git@stapelberg.de>
+ - OpenBSD port of the tcpconns plugin.
 
-vserver plugin by:
-  Sebastian Harl <sh at tokkee.org>
+Niki W. Waibel <niki.waibel at newlogic.com>
+ - Initial autotools fixes.
+ - libltdl code.
+ - getmnt-wizardry.
 
-PID-file patch by:
-  Tommie Gannert <d00-tga at d.kth.se>
+Oleg King <king2 at kaluga.ru>
+ - Added support for the statgrab library to
+   + the cpu plugin,
+   + the disk plugin, and
+   + the users plugin.
 
-Don't-fork-patch by:
-  Alvaro Barcellos <alvaro.barcellos at gmail.com>
+Peter Holik <peter at holik.at>
+ - cpufreq plugin.
+ - multimeter plugin.
+ - irq plugin.
+ - Some bugfixes in the exec plugin.
+ - Notifications in the ipmi plugin.
 
-Many autotools related fixes, libltdl code, getmnt-wizardry and much help has
-contributed:
-  Niki W. Waibel <niki.waibel at newlogic.com>
+Richard W. M. Jones <rjones at redhat.com>
+ - libvirt plugin.
+ - uuid plugin.
 
-The `log' mode has been written by:
-  Christophe Kalt <collectd at klb.taranis.org>
+Scott Garrett <sgarrett at technomancer.com>
+ - tape plugin.
 
-Much time and effort to find a nasty bug in the ntpd-plugin has been
-contributed by:
-  LuboÅ¡ StanÄ›k <lubek at users.sourceforge.net>
+Sjoerd van der Berg <harekiet at gmail.com>
+ - iptables plugin.
 
-Support for the statgrab library has been added to the cpu, disk and users
-plugins by
-  Oleg King <king2 at kaluga.ru>
+Stefan Hacker <stefan.hacker at web.de>
+ - teamspeak2 plugin.
+
+Tommie Gannert <d00-tga at d.kth.se>
+ - PID-file patch.
+
+Vincent Stehlé <vincent.stehle at free.fr>
+ - hddtemp plugin.
 
 collectd is available at:
   <http://collectd.org/>
index be7f350..7f6ec05 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,97 @@
+2009-01-02, Version 4.5.2
+       * build system: Check for `mysql.h' and `mysql/mysql.h', since the
+         file may be in both locations, especially when the database was
+         installed in a non-standard path. Thanks to Dusty Doris for
+         reporting this.
+       * build system: Handle the _POSIX_PTHREAD_SEMANTICS defined, needed by
+         Solaris, in the configure script automatically.
+       * build system, tcpconns plugin: Check for `kvm_nlist' and
+         `kvm_openfiles' before enabling the plugin: Solaris provides a KVM
+         library with similar functions to the BSD variant, but doesn't
+         provide these necessary functions.
+       * collectd.conf(5): Various fixes and clarifications.
+       * collectd: Remove a GNUism (unnamed unions), thus improving
+         portability.
+       * collectd, apcups plugin: Include "collectd.h" before <stdlib.h>.
+         This solves portability problems, especially for Solaris.
+       * dns plugin: Fix a portability problem with NetBSD.
+       * filecount plugin: Fix an off-by-one error. This error may cause a
+         segmentation fault.
+       * network plugin: Fix the handling of `type' in the network protocol.
+         Due to a programming mistake, only 4 or 8 bytes would be copied to a
+         much larger buffer. This caused the `type' to be transferred much
+         more often than necessary. In some cases, e. g. the `cpu' and
+         `cpufreq' plugins being used at the same time, data may be corrupted
+         in those files. Thanks to Bruno Prémont for debugging and reporting
+         this issue.
+       * processes plugin: Fix a possible segmentation fault when specifying
+         invalid configuration options.
+       * unixsock plugin: Make sure the initialization function is run only
+         once. This resolves a file descriptor leak under systems which run
+         the initialization more than once, such as Solaris.
+
+2008-10-16, Version 4.5.1
+       * build system: Change `--enable-<plugin>' to abort with an error if
+         dependencies are not met. Thanks to Bruno Prémont for the patch.
+         Also, the poisoning of various string functions has been restricted
+         to debug builds.
+       * collectd: Fix a memory leak in the global value cache. With every
+         *missing* value a couple of bytes would be leaked. Another memory
+         leak in the configuration handling code has been fixed. Thanks to
+         Niraj Tolia for reporting these issues.
+       * collectd: Fix an off-by-one error in the ignorelist functionality.
+         When using regular expressions, the last character would be missing,
+         possibly matching differently from what one would expect.
+       * collectdmon: Don't block SIGCHLD. This fixes a potential portability
+         problem.
+       * collectd-nagios: Fix handling of the `-d' option. Thanks to Fabian
+         Linzberger for reporting the bug.
+       * iptables plugin: Fix an off-by-one error. If a string was just one
+         character too long, it was truncated instead of reporting an error.
+       * network plugin: Fix a memory leak in the configuration handling
+         code. Thanks to Niraj Tolia for reporting this issue.
+       * perl plugin: Log an error message if bootstrapping `Collectd' fails.
+       * postgresql plugin: Don't reopen connection during reinitialization.
+         This fixes a bug under Solaris and potentially other platforms.
+         Missing calls to `PQclear' have been added, too. This fixes memory
+         leaks. Thanks to ``Admin'' for reporting these bugs.
+       * snmp plugin: Don't expect null-terminated strings from the Net-SNMP
+         library.
+       * tail plugin: Call `clearerr(3)' after reading an EOF. This fixes
+         problems with some `libc's. Thanks to Matthias Lay for reporting the
+         bug.
+
+2008-09-04, Version 4.5.0
+       * collectd: Added the ability to flush certain identifiers.
+       * collectd: The concept of `notification meta data' has been
+         introduced.
+       * filecount plugin: The new filecount plugin counts the number of
+         files in a directory and its subdirectories.
+       * ipmi plugin: Sensor names have been changed to ensure unique names.
+         Notifications upon added and removed sensors can now be generated.
+       * notify_desktop plugin: This new plugin sends notifications to the
+         X desktop using the structure defined in the `Desktop Notification
+         Specification'.
+       * notify_email plugin: This new plugin sends out notifications via
+         email, using the `esmtp' library.
+       * onewire plugin: The new experimental(!) onewire plugin reads values,
+         such as temperatures, from sensors connected to the computer via the
+         onewire bus.
+       * perl plugin: Improved synchronized access to internal data structures
+         and fixed a possible dead-lock.
+       * perl plugin: Added the ability to flush certain identifiers and marked
+         plugin_flush_all() and plugin_flush_one() as deprecated in favor of
+         plugin_flush().
+       * perl plugin: Added the ability to configure Perl plugins.
+       * postgresql plugin: The new postgresql plugin collects statistics
+         about or from a PostgreSQL database.
+       * processes plugin: The `ProcessMatch' option has been added.
+       * rrdtool plugin: Implement throttling of the `update queue' to lessen
+         IO load.
+       * tcpconns plugin: This plugin has been ported to OpenBSD.
+       * thermal plugin: The new thermal plugin collects system temperatures
+         using Linux ACPI thermal zone data.
+
 2009-01-02, Version 4.4.5
        * build system: Check for `mysql.h' and `mysql/mysql.h', since the
          file may be in both locations, especially when the database was
diff --git a/README b/README
index 97b66f7..e698786 100644 (file)
--- a/README
+++ b/README
@@ -62,6 +62,9 @@ Features
       Values gathered by a custom program or script.
       See collectd-exec(5).
 
+    - filecount
+      Count the number of files in directories.
+
     - hddtemp
       Harddisk temperatures using hddtempd.
 
@@ -132,6 +135,10 @@ Features
       Network UPS tools: UPS current, voltage, power, charge, utilisation,
       temperature, etc. See upsd(8).
 
+    - onewire (EXPERIMENTAL!)
+      Read onewire sensors using the owcapu library of the owfs project.
+      Please read in collectd.conf(5) why this plugin is experimental.
+
     - perl
       The perl plugin implements a Perl-interpreter into collectd. You can
       write your own plugins in Perl and return arbitrary values using this
@@ -141,6 +148,10 @@ Features
       Network latency: Time to reach the default gateway or another given
       host.
 
+    - postgresql
+      PostgreSQL database statistics: active server connections, transaction
+      numbers, block IO, table row manipulations.
+
     - processes
       Process counts: Number of running, sleeping, zombie, ... processes.
 
@@ -230,6 +241,16 @@ Features
 
   * Notifications can be handled by the following plugins:
 
+    - notify_desktop
+      Send a desktop notification to a notification daemon, as defined in
+      the Desktop Notification Specification. To actually display the
+      notifications, notification-daemon is required.
+      See http://www.galago-project.org/specs/notification/.
+
+    - notify_email
+      Send an E-mail with the notification message to the configured
+      recipients.
+
     - exec
       Execute a program or script to handle the notification.
       See collectd-exec(5).
@@ -315,9 +336,16 @@ Prerequisites
     used and should be found in various implementations for hopefully all
     platforms.
 
+  * CoreFoundation.framework and IOKit.framework (optional)
+    For compiling on Darwin in general and the `apple_sensors' plugin in
+    particular.
+
   * libcurl (optional)
     If you want to use the `apache', `ascent', or `nginx' plugin.
 
+  * libesmtp (optional)
+    For the `notify_email' plugin.
+
   * libhal (optional)
     If present, the uuid plugin will check for UUID from HAL.
 
@@ -333,10 +361,17 @@ Prerequisites
   * libnetsnmp (optional)
     For the `snmp' plugin.
 
+  * libnotify (optional)
+    For the `notify_desktop' plugin.
+
   * 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.
 
+  * libowcapi (optional)
+    Used by the `onewire' plugin to read values from onewire sensors (or the
+    owserver(1) daemon).
+
   * libpcap (optional)
     Used to capture packets by the `dns' plugin.
 
@@ -344,38 +379,37 @@ Prerequisites
     Obviously used by the `perl' plugin. The library has to be compiled with
     ithread support (introduced in Perl 5.6.0).
 
+  * libpq (optional)
+    The PostgreSQL C client library used by the `postgresql' plugin.
+
   * librrd (optional; headers and library; rrdtool 1.0 and 1.2 both work fine)
     If built without `librrd' the resulting binary will be `client only', i.e.
     will send its values via multicast and not create any RRD files itself.
     Alternatively you can chose to write CSV-files (Comma Separated Values)
     instead.
 
+  * librt, libsocket, libkstat, libdevinfo (optional)
+    Various standard Solaris libraries which provide system functions.
+
   * libsensors (optional)
     To read from `lm_sensors', see the `sensors' plugin.
 
-  * libstatgrab may be used to collect statistics on systems other than Linux
-    and/or Solaris. Note that CPU- and disk-statistics, while being provided
-    by this library, are not supported in collectd right now..
+  * libstatgrab (optional) may be used to collect statistics on systems other
+    than Linux and/or Solaris. Note that CPU- and disk-statistics, while being
+    provided by this library, are not supported in collectd right now..
     <http://www.i-scream.org/libstatgrab/> 
 
   * 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.
-
-  * CoreFoundation.framework and IOKit.framework
-    For compiling on Darwin in general and the `apple_sensors' plugin in
-    particular.
-
   * libvirt (optional)
     Collect statistics from virtual machines.
 
   * libxml2 (optional)
     Parse XML data. This is needed for the `ascent' and `libvirt' plugins.
 
+  * libxmms (optional)
+
 
 Configuring / Compiling / Installing
 ------------------------------------
diff --git a/TODO b/TODO
index 08fcec1..b5cd6b5 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,8 +1,6 @@
-For version 4.4:
-* PowerDNS plugin
-
-For version 4.3:
-* unixsock plugin: Remove the custom cache if possible.
+* Parse options/identifiers with spaces in them correctly.
+* Figure out what to do with the onewire plugin.
+* Custom notification messages?
 
 src/battery.c: commend not working code.
 
index cca349e..738206b 100644 (file)
@@ -56,6 +56,7 @@ our %EXPORT_TAGS = (
                        TYPE_LOG
                        TYPE_NOTIF
                        TYPE_FLUSH
+                       TYPE_CONFIG
                        TYPE_DATASET
        ) ],
        'ds_types' => [ qw(
@@ -98,6 +99,7 @@ our $interval_g;
 Exporter::export_ok_tags ('all');
 
 my @plugins : shared = ();
+my %cf_callbacks : shared = ();
 
 my %types = (
        TYPE_INIT,     "init",
@@ -133,6 +135,8 @@ sub DEBUG   { _log (scalar caller, LOG_DEBUG,   shift); }
 sub plugin_call_all {
        my $type = shift;
 
+       my %plugins;
+
        our $cb_name = undef;
 
        if (! defined $type) {
@@ -148,9 +152,13 @@ sub plugin_call_all {
                return;
        }
 
-       lock @plugins;
-       foreach my $plugin (keys %{$plugins[$type]}) {
-               my $p = $plugins[$type]->{$plugin};
+       {
+               lock %{$plugins[$type]};
+               %plugins = %{$plugins[$type]};
+       }
+
+       foreach my $plugin (keys %plugins) {
+               my $p = $plugins{$plugin};
 
                my $status = 0;
 
@@ -238,7 +246,8 @@ sub plugin_register {
                return;
        }
 
-       if ((! defined $plugins[$type]) && (TYPE_DATASET != $type)) {
+       if ((! defined $plugins[$type]) && (TYPE_DATASET != $type)
+                       && (TYPE_CONFIG != $type)) {
                ERROR ("Collectd::plugin_register: Invalid type \"$type\"");
                return;
        }
@@ -246,6 +255,16 @@ sub plugin_register {
        if ((TYPE_DATASET == $type) && ("ARRAY" eq ref $data)) {
                return plugin_register_data_set ($name, $data);
        }
+       elsif ((TYPE_CONFIG == $type) && (! ref $data)) {
+               my $pkg = scalar caller;
+
+               if ($data !~ m/^$pkg\:\:/) {
+                       $data = $pkg . "::" . $data;
+               }
+
+               lock %cf_callbacks;
+               $cf_callbacks{$name} = $data;
+       }
        elsif ((TYPE_DATASET != $type) && (! ref $data)) {
                my $pkg = scalar caller;
 
@@ -261,7 +280,7 @@ sub plugin_register {
                        cb_name   => $data,
                );
 
-               lock @plugins;
+               lock %{$plugins[$type]};
                $plugins[$type]->{$name} = \%p;
        }
        else {
@@ -285,8 +304,12 @@ sub plugin_unregister {
        if (TYPE_DATASET == $type) {
                return plugin_unregister_data_set ($name);
        }
+       elsif (TYPE_CONFIG == $type) {
+               lock %cf_callbacks;
+               delete $cf_callbacks{$name};
+       }
        elsif (defined $plugins[$type]) {
-               lock @plugins;
+               lock %{$plugins[$type]};
                delete $plugins[$type]->{$name};
        }
        else {
@@ -299,28 +322,101 @@ sub plugin_flush {
        my %args = @_;
 
        my $timeout = -1;
+       my @plugins = ();
+       my @ids     = ();
 
        DEBUG ("Collectd::plugin_flush:"
                . (defined ($args{'timeout'}) ? " timeout = $args{'timeout'}" : "")
-               . (defined ($args{'plugins'}) ? " plugins = $args{'plugins'}" : ""));
+               . (defined ($args{'plugins'}) ? " plugins = $args{'plugins'}" : "")
+               . (defined ($args{'identifiers'})
+                       ? " identifiers = $args{'identifiers'}" : ""));
 
        if (defined ($args{'timeout'}) && ($args{'timeout'} > 0)) {
                $timeout = $args{'timeout'};
        }
 
-       if (! defined $args{'plugins'}) {
-               plugin_flush_all ($timeout);
+       if (defined ($args{'plugins'})) {
+               if ("ARRAY" eq ref ($args{'plugins'})) {
+                       @plugins = @{$args{'plugins'}};
+               }
+               else {
+                       @plugins = ($args{'plugins'});
+               }
        }
        else {
-               if ("ARRAY" eq ref ($args{'plugins'})) {
-                       foreach my $plugin (@{$args{'plugins'}}) {
-                               plugin_flush_one ($timeout, $plugin);
-                       }
+               @plugins = (undef);
+       }
+
+       if (defined ($args{'identifiers'})) {
+               if ("ARRAY" eq ref ($args{'identifiers'})) {
+                       @ids = @{$args{'identifiers'}};
                }
                else {
-                       plugin_flush_one ($timeout, $args{'plugins'});
+                       @ids = ($args{'identifiers'});
                }
        }
+       else {
+               @ids = (undef);
+       }
+
+       foreach my $plugin (@plugins) {
+               foreach my $id (@ids) {
+                       _plugin_flush($plugin, $timeout, $id);
+               }
+       }
+}
+
+sub plugin_flush_one {
+       my $timeout = shift;
+       my $name    = shift;
+
+       WARNING ("Collectd::plugin_flush_one is deprecated - "
+               . "use Collectd::plugin_flush instead.");
+
+       if (! (defined ($timeout) && defined ($name))) {
+               ERROR ("Usage: Collectd::plugin_flush_one(timeout, name)");
+               return;
+       }
+
+       plugin_flush (plugins => $name, timeout => $timeout);
+}
+
+sub plugin_flush_all {
+       my $timeout = shift;
+
+       WARNING ("Collectd::plugin_flush_all is deprecated - "
+               . "use Collectd::plugin_flush instead.");
+
+       if (! defined ($timeout)) {
+               ERROR ("Usage: Collectd::plugin_flush_all(timeout)");
+               return;
+       }
+
+       plugin_flush (timeout => $timeout);
+}
+
+sub _plugin_dispatch_config {
+       my $plugin = shift;
+       my $config = shift;
+
+       our $cb_name = undef;
+
+       if (! (defined ($plugin) && defined ($config))) {
+               return;
+       }
+
+       if (! defined $cf_callbacks{$plugin}) {
+               WARNING ("Found a configuration for the \"$plugin\" plugin, but "
+                       . "the plugin isn't loaded or didn't register "
+                       . "a configuration callback.");
+               return;
+       }
+
+       {
+               lock %cf_callbacks;
+               $cb_name = $cf_callbacks{$plugin};
+       }
+       call_by_name ($config);
 }
 
 1;
index 29fac3e..eb6e389 100644 (file)
@@ -57,8 +57,19 @@ use Carp (qw(cluck confess));
 use IO::Socket::UNIX;
 use Regexp::Common (qw(number));
 
+our $Debug = 0;
+
 return (1);
 
+sub _debug
+{
+       if (!$Debug)
+       {
+               return;
+       }
+       print @_;
+}
+
 sub _create_socket
 {
        my $path = shift;
@@ -71,7 +82,7 @@ sub _create_socket
        return ($sock);
 } # _create_socket
 
-=head1 VALUE IDENTIFIER
+=head1 VALUE IDENTIFIERS
 
 The values in the collectd are identified using an five-tuple (host, plugin,
 plugin-instance, type, type-instance) where only plugin-instance and
@@ -134,6 +145,22 @@ sub _parse_identifier
        return ($ident);
 } # _parse_identifier
 
+sub _escape_argument
+{
+       my $string = shift;
+
+       if ($string =~ m/^\w+$/)
+       {
+               return ("$string");
+       }
+
+       $string =~ s#\\#\\\\#g;
+       $string =~ s#"#\\"#g;
+       $string = "\"$string\"";
+
+       return ($string);
+}
+
 =head1 PUBLIC METHODS
 
 =over 4
@@ -175,7 +202,7 @@ sub getval
        my %args = @_;
 
        my $status;
-       my $fh = $obj->{'sock'} or confess;
+       my $fh = $obj->{'sock'} or confess ('object has no filehandle');
        my $msg;
        my $identifier;
 
@@ -183,13 +210,13 @@ sub getval
 
        $identifier = _create_identifier (\%args) or return;
 
-       $msg = "GETVAL $identifier\n";
-       #print "-> $msg";
-       send ($fh, $msg, 0) or confess ("send: $!");
+       $msg = 'GETVAL ' . _escape_argument ($identifier) . "\n";
+       _debug "-> $msg";
+       print $fh $msg;
 
-       $msg = undef;
-       recv ($fh, $msg, 1024, 0) or confess ("recv: $!");
-       #print "<- $msg";
+       $msg = <$fh>;
+       chomp ($msg);
+       _debug "<- $msg\n";
 
        ($status, $msg) = split (' ', $msg, 2);
        if ($status <= 0)
@@ -198,9 +225,12 @@ sub getval
                return;
        }
 
-       for (split (' ', $msg))
+       for (my $i = 0; $i < $status; $i++)
        {
-               my $entry = $_;
+               my $entry = <$fh>;
+               chomp ($entry);
+               _debug "<- $entry\n";
+
                if ($entry =~ m/^(\w+)=NaN$/)
                {
                        $ret->{$1} = undef;
@@ -219,8 +249,8 @@ sub getval
 Submits a value-list to the daemon. If the B<time> argument is omitted
 C<time()> is used. The required argument B<values> is a reference to an array
 of values that is to be submitted. The number of values must match the number
-of values expected for the given B<type> (see L<VALUE IDENTIFIER>), though this
-is checked by the daemon, not the Perl module. Also, gauge data-sources
+of values expected for the given B<type> (see L<VALUE IDENTIFIERS>), though
+this is checked by the daemon, not the Perl module. Also, gauge data-sources
 (e.E<nbsp>g. system-load) may be C<undef>. Returns true upon success and false
 otherwise.
 
@@ -240,7 +270,8 @@ sub putval
 
        if (defined $args{'interval'})
        {
-               $interval = ' interval=' . $args{'interval'};
+               $interval = ' interval='
+               . _escape_argument ($args{'interval'});
        }
 
        $identifier = _create_identifier (\%args) or return;
@@ -260,12 +291,16 @@ sub putval
                $values = join (':', $time, map { defined ($_) ? $_ : 'U' } (@{$args{'values'}}));
        }
 
-       $msg = "PUTVAL $identifier$interval $values\n";
-       #print "-> $msg";
-       send ($fh, $msg, 0) or confess ("send: $!");
-       $msg = undef;
-       recv ($fh, $msg, 1024, 0) or confess ("recv: $!");
-       #print "<- $msg";
+       $msg = 'PUTVAL '
+       . _escape_argument ($identifier)
+       . $interval
+       . ' ' . _escape_argument ($values) . "\n";
+       _debug "-> $msg";
+       print $fh $msg;
+
+       $msg = <$fh>;
+       chomp ($msg);
+       _debug "<- $msg\n";
 
        ($status, $msg) = split (' ', $msg, 2);
        return (1) if ($status == 0);
@@ -290,10 +325,12 @@ sub listval
        my $status;
        my $fh = $obj->{'sock'} or confess;
 
-       $msg = "LISTVAL\n";
-       send ($fh, $msg, 0) or confess ("send: $!");
+       _debug "LISTVAL\n";
+       print $fh "LISTVAL\n";
 
        $msg = <$fh>;
+       chomp ($msg);
+       _debug "<- $msg\n";
        ($status, $msg) = split (' ', $msg, 2);
        if ($status < 0)
        {
@@ -308,6 +345,7 @@ sub listval
 
                $msg = <$fh>;
                chomp ($msg);
+               _debug "<- $msg\n";
 
                ($time, $ident) = split (' ', $msg, 2);
 
@@ -362,7 +400,6 @@ sub putnotif
        my $fh = $obj->{'sock'} or confess;
 
        my $msg; # message sent to the socket
-       my $opt_msg; # message of the notification
        
        if (!$args{'message'})
        {
@@ -388,16 +425,16 @@ sub putnotif
                $args{'time'} = time ();
        }
        
-       $opt_msg = $args{'message'};
-       delete ($args{'message'});
-
        $msg = 'PUTNOTIF '
-       . join (' ', map { $_ . '=' . $args{$_} } (keys %args))
-       . " message=$opt_msg\n";
+       . join (' ', map { $_ . '=' . _escape_argument ($args{$_}) } (keys %args))
+       . "\n";
 
-       send ($fh, $msg, 0) or confess ("send: $!");
-       $msg = undef;
-       recv ($fh, $msg, 1024, 0) or confess ("recv: $!");
+       _debug "-> $msg";
+       print $fh $msg;
+
+       $msg = <$fh>;
+       chomp ($msg);
+       _debug "<- $msg\n";
 
        ($status, $msg) = split (' ', $msg, 2);
        return (1) if ($status == 0);
@@ -406,7 +443,7 @@ sub putnotif
        return;
 } # putnotif
 
-=item I<$obj>-E<gt>B<flush> (B<timeout> =E<gt> I<$timeout>, B<plugins> =E<gt> [...]);
+=item I<$obj>-E<gt>B<flush> (B<timeout> =E<gt> I<$timeout>, B<plugins> =E<gt> [...], B<identifier>  =E<gt> [...]);
 
 Flush cached data.
 
@@ -421,7 +458,14 @@ flushed.
 
 =item B<plugins>
 
-If this option is specified, only the selected plugins will be flushed. 
+If this option is specified, only the selected plugins will be flushed. The
+argument is a reference to an array of strings.
+
+=item B<identifier>
+
+If this option is specified, only the given identifier(s) will be flushed. The
+argument is a reference to an array of identifiers. Identifiers, in this case,
+are hash references and have the members as outlined in L<VALUE IDENTIFIERS>.
 
 =back
 
@@ -437,7 +481,7 @@ sub flush
        my $status = 0;
        my $msg    = "FLUSH";
 
-       if ($args{'timeout'})
+       if (defined ($args{'timeout'}))
        {
                $msg .= " timeout=" . $args{'timeout'};
        }
@@ -450,11 +494,39 @@ sub flush
                }
        }
 
+       if ($args{'identifier'})
+       {
+               for (@{$args{'identifier'}})
+               {
+                       my $identifier = $_;
+                       my $ident_str;
+
+                       if (ref ($identifier) ne 'HASH')
+                       {
+                               cluck ("The argument of the `identifier' "
+                                       . "option must be an array reference "
+                                       . "of hash references.");
+                               return;
+                       }
+
+                       $ident_str = _create_identifier ($identifier);
+                       if (!$ident_str)
+                       {
+                               return;
+                       }
+
+                       $msg .= ' identifier=' . _escape_argument ($ident_str);
+               }
+       }
+
        $msg .= "\n";
 
-       send ($fh, $msg, 0) or confess ("send: $!");
-       $msg = undef;
-       recv ($fh, $msg, 1024, 0) or confess ("recv: $!");
+       _debug "-> $msg";
+       print $fh $msg;
+
+       $msg = <$fh>;
+       chomp ($msg);
+       _debug "<- $msg\n";
 
        ($status, $msg) = split (' ', $msg, 2);
        return (1) if ($status == 0);
@@ -463,6 +535,16 @@ sub flush
        return;
 }
 
+sub error
+{
+       my $obj = shift;
+       if ($obj->{'error'})
+       {
+               return ($obj->{'error'});
+       }
+       return;
+}
+
 =item I<$obj>-E<gt>destroy ();
 
 Closes the socket before the object is destroyed. This function is also
index 8332429..7a4c151 100644 (file)
@@ -45,6 +45,9 @@ case $host_os in
        *darwin*)
        ac_system="Darwin"
        ;;
+       *openbsd*)
+       ac_system="OpenBSD"
+       ;;
        *)
        ac_system="unknown"
 esac
@@ -74,7 +77,7 @@ AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
 AC_HEADER_DIRENT
 
-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 endian.h sys/isa_defs.h)
+AC_CHECK_HEADERS(stdio.h stdint.h stdbool.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 endian.h sys/isa_defs.h)
 
 # For ping library
 AC_CHECK_HEADERS(netinet/in_systm.h, [], [],
@@ -1244,6 +1247,15 @@ then
 fi
 
 with_libkvm="no"
+AC_CHECK_LIB(kvm, kvm_getprocs, [with_kvm_getprocs="yes"], [with_kvm_getprocs="no"])
+if test "x$with_kvm_getprocs" = "xyes"
+then
+       AC_DEFINE(HAVE_LIBKVM_GETPROCS, 1,
+                 [Define to 1 if you have the 'kvm' library with the 'kvm_getprocs' symbol (-lkvm)])
+       with_libkvm="yes"
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBKVM_GETPROCS, test "x$with_kvm_getprocs" = "xyes")
+
 AC_CHECK_LIB(kvm, kvm_getswapinfo, [with_kvm_getswapinfo="yes"], [with_kvm_getswapinfo="no"])
 if test "x$with_kvm_getswapinfo" = "xyes"
 then
@@ -1253,6 +1265,24 @@ then
 fi
 AM_CONDITIONAL(BUILD_WITH_LIBKVM_GETSWAPINFO, test "x$with_kvm_getswapinfo" = "xyes")
 
+AC_CHECK_LIB(kvm, kvm_nlist, [with_kvm_nlist="yes"], [with_kvm_nlist="no"])
+if test "x$with_kvm_nlist" = "xyes"
+then
+       AC_DEFINE(HAVE_LIBKVM_NLIST, 1,
+                 [Define to 1 if you have the 'kvm' library with the 'kvm_nlist' symbol (-lkvm)])
+       with_libkvm="yes"
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBKVM_NLIST, test "x$with_kvm_nlist" = "xyes")
+
+AC_CHECK_LIB(kvm, kvm_openfiles, [with_kvm_openfiles="yes"], [with_kvm_openfiles="no"])
+if test "x$with_kvm_openfiles" = "xyes"
+then
+       AC_DEFINE(HAVE_LIBKVM_NLIST, 1,
+                 [Define to 1 if you have the 'kvm' library with the 'kvm_openfiles' symbol (-lkvm)])
+       with_libkvm="yes"
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBKVM_OPENFILES, test "x$with_kvm_openfiles" = "xyes")
+
 with_sensors_cflags=""
 with_sensors_ldflags=""
 AC_ARG_WITH(lm-sensors, [AS_HELP_STRING([--with-lm-sensors@<:@=PREFIX@:>@], [Path to lm_sensors.])],
@@ -1493,6 +1523,52 @@ fi
 AM_CONDITIONAL(BUILD_WITH_LIBOPING, test "x$with_liboping" = "xyes")
 AM_CONDITIONAL(BUILD_WITH_OWN_LIBOPING, test "x$with_own_liboping" = "xyes")
 
+with_libowcapi_cppflags=""
+with_libowcapi_libs="-lowcapi"
+AC_ARG_WITH(libowcapi, [AS_HELP_STRING([--with-libowcapi@<:@=PREFIX@:>@], [Path to libowcapi.])],
+[
+       if test "x$withval" != "xno" && test "x$withval" != "xyes"
+       then
+               with_libowcapi_cppflags="-I$withval/include"
+               with_libowcapi_libs="-L$withval/lib -lowcapi"
+               with_libowcapi="yes"
+       else
+               with_libowcapi="$withval"
+       fi
+],
+[
+       with_libowcapi="yes"
+])
+if test "x$with_libowcapi" = "xyes"
+then
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       CPPFLAGS="$with_libowcapi_cppflags"
+       
+       AC_CHECK_HEADERS(owcapi.h, [with_libowcapi="yes"], [with_libowcapi="no (owcapi.h not found)"])
+
+       CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_libowcapi" = "xyes"
+then
+       SAVE_LDFLAGS="$LDFLAGS"
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       LDFLAGS="$with_libowcapi_libs"
+       CPPFLAGS="$with_libowcapi_cppflags"
+       
+       AC_CHECK_LIB(owcapi, OW_get, [with_libowcapi="yes"], [with_libowcapi="no (libowcapi not found)"])
+
+       LDFLAGS="$SAVE_LDFLAGS"
+       CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_libowcapi" = "xyes"
+then
+       BUILD_WITH_LIBOWCAPI_CPPFLAGS="$with_libowcapi_cppflags"
+       BUILD_WITH_LIBOWCAPI_LIBS="$with_libowcapi_libs"
+       AC_SUBST(BUILD_WITH_LIBOWCAPI_CPPFLAGS)
+       AC_SUBST(BUILD_WITH_LIBOWCAPI_LIBS)
+fi
+
+
 AC_ARG_WITH(libpcap, [AS_HELP_STRING([--with-libpcap@<:@=PREFIX@:>@], [Path to libpcap.])],
 [
        if test "x$withval" != "xno" && test "x$withval" != "xyes"
@@ -1531,10 +1607,52 @@ AC_DEFINE_UNQUOTED(COLLECT_LIBPCAP, [$collect_libpcap],
        [Wether or not to use the pcap library])
 AM_CONDITIONAL(BUILD_WITH_LIBPCAP, test "x$with_libpcap" = "xyes")
 
+AC_ARG_WITH(libesmtp, [AS_HELP_STRING([--with-libesmtp@<:@=PREFIX@:>@], [Path to libesmtp.])],
+[
+       if test "x$withval" != "xno" && test "x$withval" != "xyes"
+       then
+               LDFLAGS="$LDFLAGS -L$withval/lib"
+               CPPFLAGS="$CPPFLAGS -I$withval/include -D_THREAD_SAFE"
+               with_libesmtp="yes"
+       else
+               with_libesmtp="$withval"
+       fi
+],
+[
+       with_libesmtp="yes"
+])
+if test "x$with_libesmtp" = "xyes"
+then
+       AC_CHECK_LIB(esmtp, smtp_create_session,
+       [
+               AC_DEFINE(HAVE_LIBESMTP, 1, [Define to 1 if you have the esmtp library (-lesmtp).])
+       ], [with_libesmtp="no (libesmtp not found)"])
+fi
+if test "x$with_libesmtp" = "xyes"
+then
+       AC_CHECK_HEADERS(libesmtp.h,
+       [
+               AC_DEFINE(HAVE_LIBESMTP_H, 1, [Define to 1 if you have the <libesmtp.h> header file.])
+       ], [with_libesmtp="no (libesmtp.h not found)"])
+fi
+if test "x$with_libesmtp" = "xyes"
+then
+       collect_libesmtp=1
+else
+       collect_libesmtp=0
+fi
+AC_DEFINE_UNQUOTED(COLLECT_LIBESMTP, [$collect_libesmtp],
+       [Wether or not to use the esmtp library])
+AM_CONDITIONAL(BUILD_WITH_LIBESMTP, test "x$with_libesmtp" = "xyes")
+
 perl_interpreter="perl"
 AC_ARG_WITH(libperl, [AS_HELP_STRING([--with-libperl@<:@=PREFIX@:>@], [Path to libperl.])],
 [
-       if test "x$withval" != "xno" && test "x$withval" != "xyes"
+       if test -x "$withval"
+       then
+               perl_interpreter="$withval"
+               with_libperl="yes"
+       else if test "x$withval" != "xno" && test "x$withval" != "xyes"
        then
                LDFLAGS="$LDFLAGS -L$withval/lib"
                CPPFLAGS="$CPPFLAGS -I$withval/include"
@@ -1542,7 +1660,7 @@ AC_ARG_WITH(libperl, [AS_HELP_STRING([--with-libperl@<:@=PREFIX@:>@], [Path to l
                with_libperl="yes"
        else
                with_libperl="$withval"
-       fi
+       fi; fi
 ],
 [
        with_libperl="yes"
@@ -1552,7 +1670,7 @@ AC_MSG_CHECKING([for perl])
 perl_interpreter=`which "$perl_interpreter" 2> /dev/null`
 if test -x "$perl_interpreter"
 then
-       AC_MSG_RESULT([yes])
+       AC_MSG_RESULT([yes ($perl_interpreter)])
 else
        perl_interpreter=""
        AC_MSG_RESULT([no])
@@ -1575,13 +1693,14 @@ then
     AC_LINK_IFELSE(
       AC_LANG_PROGRAM(
       [[
+#define PERL_NO_GET_CONTEXT
 #include <EXTERN.h>
 #include <perl.h>
 #include <XSUB.h>
       ]],
       [[
-       PerlInterpreter *perl = NULL;
-       Perl_load_module (perl, PERL_LOADMOD_NOIMPORT,
+       dTHX;
+       load_module (PERL_LOADMOD_NOIMPORT,
                         newSVpv ("Collectd::Plugin::FooBar", 24),
                         Nullsv);
       ]]),
@@ -1771,6 +1890,10 @@ then
 fi
 AM_CONDITIONAL(BUILD_WITH_LIBNETSNMP, test "x$with_libnetsnmp" = "xyes")
 
+PKG_CHECK_MODULES([LIBNOTIFY], [libnotify],
+               [with_libnotify="yes"],
+               [with_libnotify="no ($LIBNOTIFY_PKG_ERRORS)"])
+
 with_libupsclient="no (pkg-config isn't available)"
 with_libupsclient_cflags=""
 with_libupsclient_libs=""
@@ -2094,6 +2217,93 @@ then
        AC_SUBST(BUILD_WITH_OPENIPMI_LIBS)
 fi
 
+dnl Check for libpq.
+with_pg_config="pg_config"
+with_libpq_includedir=""
+with_libpq_libdir=""
+with_libpq_cppflags=""
+with_libpq_ldflags=""
+AC_ARG_WITH(libpq, [AS_HELP_STRING([--with-libpq@<:@=PREFIX@:>@],
+       [Path to libpq.])],
+[
+       if test "x$withval" = "xno"
+       then
+               with_libpq="no"
+       else if test "x$withval" = "xyes"
+       then
+               with_libpq="yes"
+       else
+               if test -f "$withval" && test -x "$withval";
+               then
+                       with_pg_config="$withval"
+               else if test -x "$withval/bin/pg_config"
+               then
+                       with_pg_config="$withval/bin/pg_config"
+               fi; fi
+               with_libpq="yes"
+       fi; fi
+],
+[
+       with_libpq="yes"
+])
+if test "x$with_libpq" = "xyes"
+then
+       with_libpq_includedir=`$with_pg_config --includedir 2> /dev/null`
+       pg_config_status=$?
+
+       if test $pg_config_status -eq 0
+       then
+               if test -n "$with_libpq_includedir"; then
+                       for dir in $with_libpq_includedir; do
+                               with_libpq_cppflags="$with_libpq_cppflags -I$dir"
+                       done
+               fi
+       else
+               AC_MSG_WARN([$with_pg_config returned with status $pg_config_status])
+       fi
+
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       CPPFLAGS="$CPPFLAGS $with_libpq_cppflags"
+
+       AC_CHECK_HEADERS(libpq-fe.h, [],
+               [with_libpq="no (libpq-fe.h not found)"], [])
+
+       CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_libpq" = "xyes"
+then
+       with_libpq_libdir=`$with_pg_config --libdir 2> /dev/null`
+       pg_config_status=$?
+
+       if test $pg_config_status -eq 0
+       then
+               if test -n "$with_libpq_libdir"; then
+                       for dir in $with_libpq_libdir; do
+                               with_libpq_ldflags="$with_libpq_ldflags -L$dir"
+                       done
+               fi
+       else
+               AC_MSG_WARN([$with_pg_config returned with status $pg_config_status])
+       fi
+
+       SAVE_LDFLAGS="$LDFLAGS"
+       LDFLAGS="$LDFLAGS $with_libpq_ldflags"
+
+       AC_CHECK_LIB(pq, PQconnectdb,
+               [with_libpq="yes"],
+               [with_libpq="no (symbol 'PQconnectdb' not found)"])
+
+       LDFLAGS="$SAVE_LDFLAGS"
+fi
+if test "x$with_libpq" = "xyes"
+then
+       BUILD_WITH_LIBPQ_CPPFLAGS="$with_libpq_cppflags"
+       BUILD_WITH_LIBPQ_LDFLAGS="$with_libpq_ldflags"
+       AC_SUBST(BUILD_WITH_LIBPQ_CPPFLAGS)
+       AC_SUBST(BUILD_WITH_LIBPQ_LDFLAGS)
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBPQ, test "x$with_libpq" = "xyes")
+
 dnl Check for libvirt and libxml2 libraries.
 with_libxml2="no (pkg-config isn't available)"
 with_libxml2_cflags=""
@@ -2344,6 +2554,7 @@ plugin_serial="no"
 plugin_swap="no"
 plugin_tape="no"
 plugin_tcpconns="no"
+plugin_thermal="no"
 plugin_users="no"
 plugin_vmem="no"
 plugin_vserver="no"
@@ -2366,6 +2577,7 @@ then
        plugin_serial="yes"
        plugin_swap="yes"
        plugin_tcpconns="yes"
+       plugin_thermal="yes"
        plugin_vmem="yes"
        plugin_vserver="yes"
        plugin_wireless="yes"
@@ -2376,6 +2588,11 @@ then
        fi
 fi
 
+if test "x$ac_system" = "xOpenBSD"
+then
+       plugin_tcpconns="yes"
+fi
+
 # Mac OS X devices
 if test "x$with_libiokit" = "xyes"
 then
@@ -2476,11 +2693,21 @@ then
        plugin_processes="yes"
 fi
 
+if test "x$with_kvm_getprocs" = "xyes"
+then
+       plugin_processes="yes"
+fi
+
 if test "x$with_kvm_getswapinfo" = "xyes"
 then
        plugin_swap="yes"
 fi
 
+if test "x$with_kvm_openfiles$with_kvm_nlist" = "xyesyes"
+then
+       plugin_tcpconns="yes"
+fi
+
 if test "x$have_getutent" = "xyes"
 then
        plugin_users="yes"
@@ -2503,12 +2730,14 @@ 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([notify_desktop], [$with_libnotify], [Desktop notifications])
 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([filecount],   [yes],                [Count files in directories])
 AC_PLUGIN([hddtemp],     [yes],                [Query hddtempd])
 AC_PLUGIN([interface],   [$plugin_interface],  [Interface traffic statistics])
 AC_PLUGIN([iptables],    [$with_libiptc],      [IPTables rule counters])
@@ -2527,10 +2756,13 @@ AC_PLUGIN([netlink],     [$with_libnetlink],   [Enhanced Linux network statistic
 AC_PLUGIN([network],     [yes],                [Network communication plugin])
 AC_PLUGIN([nfs],         [$plugin_nfs],        [NFS statistics])
 AC_PLUGIN([nginx],       [$with_libcurl],      [nginx statistics])
+AC_PLUGIN([notify_email], [$with_libesmtp],    [Email notifier])
 AC_PLUGIN([ntpd],        [yes],                [NTPd statistics])
 AC_PLUGIN([nut],         [$with_libupsclient], [Network UPS tools statistics])
+AC_PLUGIN([onewire],     [$with_libowcapi],    [OneWire sensor statistics])
 AC_PLUGIN([perl],        [$plugin_perl],       [Embed a Perl interpreter])
 AC_PLUGIN([ping],        [$with_liboping],     [Network latency statistics])
+AC_PLUGIN([postgresql],  [$with_libpq],        [PostgreSQL database statistics])
 AC_PLUGIN([powerdns],    [yes],                [PowerDNS statistics])
 AC_PLUGIN([processes],   [$plugin_processes],  [Process statistics])
 AC_PLUGIN([rrdtool],     [$with_rrdtool],      [RRDTool output plugin])
@@ -2543,6 +2775,7 @@ AC_PLUGIN([tail],        [yes],                [Parsing of logfiles])
 AC_PLUGIN([tape],        [$plugin_tape],       [Tape drive statistics])
 AC_PLUGIN([tcpconns],    [$plugin_tcpconns],   [TCP connection statistics])
 AC_PLUGIN([teamspeak2],  [yes],                [TeamSpeak2 server statistics])
+AC_PLUGIN([thermal],     [$plugin_thermal],    [Linux ACPI thermal zone statistics])
 AC_PLUGIN([unixsock],    [yes],                [Unixsock communication plugin])
 AC_PLUGIN([users],       [$plugin_users],      [User statistics])
 AC_PLUGIN([uuid],        [yes],                [UUID as hostname plugin])
@@ -2624,91 +2857,100 @@ cat <<EOF;
 
 Configuration:
   Libraries:
-    libcurl . . . . . . $with_libcurl
-    libiokit  . . . . . $with_libiokit
-    libiptc . . . . . . $with_libiptc
-    libkstat  . . . . . $with_kstat
-    libkvm  . . . . . . $with_libkvm
-    libmysql  . . . . . $with_libmysql
-    libnetlink  . . . . $with_libnetlink
-    libnetsnmp  . . . . $with_libnetsnmp
-    liboconfig  . . . . $with_liboconfig
-    libopenipmi . . . . $with_libopenipmipthread
-    liboping  . . . . . $with_liboping
-    libpcap . . . . . . $with_libpcap
-    libperl . . . . . . $with_libperl
-    libpthread  . . . . $with_libpthread
-    librrd  . . . . . . $with_rrdtool
-    libsensors  . . . . $with_lm_sensors
-    libstatgrab . . . . $with_libstatgrab
-    libupsclient  . . . $with_libupsclient
-    libvirt . . . . . . $with_libvirt
-    libxml2 . . . . . . $with_libxml2
-    libxmms . . . . . . $with_libxmms
+    libcurl . . . . . . . $with_libcurl
+    libesmtp  . . . . . . $with_libesmtp
+    libiokit  . . . . . . $with_libiokit
+    libiptc . . . . . . . $with_libiptc
+    libkstat  . . . . . . $with_kstat
+    libkvm  . . . . . . . $with_libkvm
+    libmysql  . . . . . . $with_libmysql
+    libnetlink  . . . . . $with_libnetlink
+    libnetsnmp  . . . . . $with_libnetsnmp
+    libnotify . . . . . . $with_libnotify
+    liboconfig  . . . . . $with_liboconfig
+    libopenipmi . . . . . $with_libopenipmipthread
+    liboping  . . . . . . $with_liboping
+    libpcap . . . . . . . $with_libpcap
+    libperl . . . . . . . $with_libperl
+    libpthread  . . . . . $with_libpthread
+    libpq . . . . . . . . $with_libpq
+    librrd  . . . . . . . $with_rrdtool
+    libsensors  . . . . . $with_lm_sensors
+    libstatgrab . . . . . $with_libstatgrab
+    libupsclient  . . . . $with_libupsclient
+    libvirt . . . . . . . $with_libvirt
+    libxml2 . . . . . . . $with_libxml2
+    libxmms . . . . . . . $with_libxmms
 
   Features:
-    daemon mode . . . . $enable_daemon
-    debug . . . . . . . $enable_debug
+    daemon mode . . . . $enable_daemon
+    debug . . . . . . . $enable_debug
 
   Bindings:
-    perl  . . . . . . . $with_perl_bindings
+    perl  . . . . . . . $with_perl_bindings
 
   Modules:
-    apache  . . . . . . $enable_apache
-    apcups  . . . . . . $enable_apcups
-    apple_sensors . . . $enable_apple_sensors
-    ascent  . . . . . . $enable_ascent
-    battery . . . . . . $enable_battery
-    cpu . . . . . . . . $enable_cpu
-    cpufreq . . . . . . $enable_cpufreq
-    csv . . . . . . . . $enable_csv
-    df  . . . . . . . . $enable_df
-    disk  . . . . . . . $enable_disk
-    dns . . . . . . . . $enable_dns
-    email . . . . . . . $enable_email
-    entropy . . . . . . $enable_entropy
-    exec  . . . . . . . $enable_exec
-    hddtemp . . . . . . $enable_hddtemp
-    interface . . . . . $enable_interface
-    iptables  . . . . . $enable_iptables
-    ipmi  . . . . . . . $enable_ipmi
-    ipvs  . . . . . . . $enable_ipvs
-    irq . . . . . . . . $enable_irq
-    libvirt . . . . . . $enable_libvirt
-    load  . . . . . . . $enable_load
-    logfile . . . . . . $enable_logfile
-    mbmon . . . . . . . $enable_mbmon
-    memcached . . . . . $enable_memcached
-    memory  . . . . . . $enable_memory
-    multimeter  . . . . $enable_multimeter
-    mysql . . . . . . . $enable_mysql
-    netlink . . . . . . $enable_netlink
-    network . . . . . . $enable_network
-    nfs . . . . . . . . $enable_nfs
-    nginx . . . . . . . $enable_nginx
-    ntpd  . . . . . . . $enable_ntpd
-    nut . . . . . . . . $enable_nut
-    perl  . . . . . . . $enable_perl
-    ping  . . . . . . . $enable_ping
-    powerdns  . . . . . $enable_powerdns
-    processes . . . . . $enable_processes
-    rrdtool . . . . . . $enable_rrdtool
-    sensors . . . . . . $enable_sensors
-    serial  . . . . . . $enable_serial
-    snmp  . . . . . . . $enable_snmp
-    swap  . . . . . . . $enable_swap
-    syslog  . . . . . . $enable_syslog
-    tail  . . . . . . . $enable_tail
-    tape  . . . . . . . $enable_tape
-    tcpconns  . . . . . $enable_tcpconns
-    teamspeak2  . . . . $enable_teamspeak2
-    unixsock  . . . . . $enable_unixsock
-    users . . . . . . . $enable_users
-    uuid  . . . . . . . $enable_uuid
-    vmem  . . . . . . . $enable_vmem
-    vserver . . . . . . $enable_vserver
-    wireless  . . . . . $enable_wireless
-    xmms  . . . . . . . $enable_xmms
+    apache  . . . . . . . $enable_apache
+    apcups  . . . . . . . $enable_apcups
+    apple_sensors . . . . $enable_apple_sensors
+    ascent  . . . . . . . $enable_ascent
+    battery . . . . . . . $enable_battery
+    cpu . . . . . . . . . $enable_cpu
+    cpufreq . . . . . . . $enable_cpufreq
+    csv . . . . . . . . . $enable_csv
+    df  . . . . . . . . . $enable_df
+    disk  . . . . . . . . $enable_disk
+    dns . . . . . . . . . $enable_dns
+    email . . . . . . . . $enable_email
+    entropy . . . . . . . $enable_entropy
+    exec  . . . . . . . . $enable_exec
+    filecount . . . . . . $enable_filecount
+    hddtemp . . . . . . . $enable_hddtemp
+    interface . . . . . . $enable_interface
+    iptables  . . . . . . $enable_iptables
+    ipmi  . . . . . . . . $enable_ipmi
+    ipvs  . . . . . . . . $enable_ipvs
+    irq . . . . . . . . . $enable_irq
+    libvirt . . . . . . . $enable_libvirt
+    load  . . . . . . . . $enable_load
+    logfile . . . . . . . $enable_logfile
+    mbmon . . . . . . . . $enable_mbmon
+    memcached . . . . . . $enable_memcached
+    memory  . . . . . . . $enable_memory
+    multimeter  . . . . . $enable_multimeter
+    mysql . . . . . . . . $enable_mysql
+    netlink . . . . . . . $enable_netlink
+    network . . . . . . . $enable_network
+    nfs . . . . . . . . . $enable_nfs
+    nginx . . . . . . . . $enable_nginx
+    notify_desktop  . . . $enable_notify_desktop
+    notify_email  . . . . $enable_notify_email
+    ntpd  . . . . . . . . $enable_ntpd
+    nut . . . . . . . . . $enable_nut
+    onewire . . . . . . . $enable_onewire
+    perl  . . . . . . . . $enable_perl
+    ping  . . . . . . . . $enable_ping
+    postgresql  . . . . . $enable_postgresql
+    powerdns  . . . . . . $enable_powerdns
+    processes . . . . . . $enable_processes
+    rrdtool . . . . . . . $enable_rrdtool
+    sensors . . . . . . . $enable_sensors
+    serial  . . . . . . . $enable_serial
+    snmp  . . . . . . . . $enable_snmp
+    swap  . . . . . . . . $enable_swap
+    syslog  . . . . . . . $enable_syslog
+    tail  . . . . . . . . $enable_tail
+    tape  . . . . . . . . $enable_tape
+    tcpconns  . . . . . . $enable_tcpconns
+    teamspeak2  . . . . . $enable_teamspeak2
+    thermal . . . . . . . $enable_thermal
+    unixsock  . . . . . . $enable_unixsock
+    users . . . . . . . . $enable_users
+    uuid  . . . . . . . . $enable_uuid
+    vmem  . . . . . . . . $enable_vmem
+    vserver . . . . . . . $enable_vserver
+    wireless  . . . . . . $enable_wireless
+    xmms  . . . . . . . . $enable_xmms
 
 EOF
 
index 6990fb3..fa26f82 100755 (executable)
@@ -2048,6 +2048,76 @@ sub load_graph_definitions
     'GPRINT:ping_avg:AVERAGE:%4.1lf ms Avg,',
     'GPRINT:ping_max:MAX:%4.1lf ms Max,',
     'GPRINT:ping_avg:LAST:%4.1lf ms Last'],
+    pg_blks => ['DEF:pg_blks_avg={file}:value:AVERAGE',
+    'DEF:pg_blks_min={file}:value:MIN',
+    'DEF:pg_blks_max={file}:value:MAX',
+    "AREA:pg_blks_max#$HalfBlue",
+    "AREA:pg_blks_min#$Canvas",
+    "LINE1:pg_blks_avg#$FullBlue:Blocks",
+    'GPRINT:pg_blks_min:MIN:%4.1lf%s Min,',
+    'GPRINT:pg_blks_avg:AVERAGE:%4.1lf%s Avg,',
+    'GPRINT:pg_blks_max:MAX:%4.1lf%s Max,',
+    'GPRINT:pg_blks_avg:LAST:%4.1lf%s Last'],
+    pg_db_size => ['DEF:pg_db_size_avg={file}:value:AVERAGE',
+    'DEF:pg_db_size_min={file}:value:MIN',
+    'DEF:pg_db_size_max={file}:value:MAX',
+    "AREA:pg_db_size_max#$HalfBlue",
+    "AREA:pg_db_size_min#$Canvas",
+    "LINE1:pg_db_size_avg#$FullBlue:Bytes",
+    'GPRINT:pg_db_size_min:MIN:%4.1lf%s Min,',
+    'GPRINT:pg_db_size_avg:AVERAGE:%4.1lf%s Avg,',
+    'GPRINT:pg_db_size_max:MAX:%4.1lf%s Max,',
+    'GPRINT:pg_db_size_avg:LAST:%4.1lf%s Last'],
+    pg_n_tup_c => ['DEF:pg_n_tup_avg={file}:value:AVERAGE',
+    'DEF:pg_n_tup_min={file}:value:MIN',
+    'DEF:pg_n_tup_max={file}:value:MAX',
+    "AREA:pg_n_tup_max#$HalfBlue",
+    "AREA:pg_n_tup_min#$Canvas",
+    "LINE1:pg_n_tup_avg#$FullBlue:Tuples",
+    'GPRINT:pg_n_tup_min:MIN:%4.1lf%s Min,',
+    'GPRINT:pg_n_tup_avg:AVERAGE:%4.1lf%s Avg,',
+    'GPRINT:pg_n_tup_max:MAX:%4.1lf%s Max,',
+    'GPRINT:pg_n_tup_avg:LAST:%4.1lf%s Last'],
+    pg_n_tup_g => ['DEF:pg_n_tup_avg={file}:value:AVERAGE',
+    'DEF:pg_n_tup_min={file}:value:MIN',
+    'DEF:pg_n_tup_max={file}:value:MAX',
+    "AREA:pg_n_tup_max#$HalfBlue",
+    "AREA:pg_n_tup_min#$Canvas",
+    "LINE1:pg_n_tup_avg#$FullBlue:Tuples",
+    'GPRINT:pg_n_tup_min:MIN:%4.1lf%s Min,',
+    'GPRINT:pg_n_tup_avg:AVERAGE:%4.1lf%s Avg,',
+    'GPRINT:pg_n_tup_max:MAX:%4.1lf%s Max,',
+    'GPRINT:pg_n_tup_avg:LAST:%4.1lf%s Last'],
+    pg_numbackends => ['DEF:pg_numbackends_avg={file}:value:AVERAGE',
+    'DEF:pg_numbackends_min={file}:value:MIN',
+    'DEF:pg_numbackends_max={file}:value:MAX',
+    "AREA:pg_numbackends_max#$HalfBlue",
+    "AREA:pg_numbackends_min#$Canvas",
+    "LINE1:pg_numbackends_avg#$FullBlue:Backends",
+    'GPRINT:pg_numbackends_min:MIN:%4.1lf%s Min,',
+    'GPRINT:pg_numbackends_avg:AVERAGE:%4.1lf%s Avg,',
+    'GPRINT:pg_numbackends_max:MAX:%4.1lf%s Max,',
+    'GPRINT:pg_numbackends_avg:LAST:%4.1lf%s Last'],
+    pg_scan => ['DEF:pg_scan_avg={file}:value:AVERAGE',
+    'DEF:pg_scan_min={file}:value:MIN',
+    'DEF:pg_scan_max={file}:value:MAX',
+    "AREA:pg_scan_max#$HalfBlue",
+    "AREA:pg_scan_min#$Canvas",
+    "LINE1:pg_scan_avg#$FullBlue:Scans",
+    'GPRINT:pg_scan_min:MIN:%4.1lf%s Min,',
+    'GPRINT:pg_scan_avg:AVERAGE:%4.1lf%s Avg,',
+    'GPRINT:pg_scan_max:MAX:%4.1lf%s Max,',
+    'GPRINT:pg_scan_avg:LAST:%4.1lf%s Last'],
+    pg_xact => ['DEF:pg_xact_avg={file}:value:AVERAGE',
+    'DEF:pg_xact_min={file}:value:MIN',
+    'DEF:pg_xact_max={file}:value:MAX',
+    "AREA:pg_xact_max#$HalfBlue",
+    "AREA:pg_xact_min#$Canvas",
+    "LINE1:pg_xact_avg#$FullBlue:Transactions",
+    'GPRINT:pg_xact_min:MIN:%4.1lf%s Min,',
+    'GPRINT:pg_xact_avg:AVERAGE:%4.1lf%s Avg,',
+    'GPRINT:pg_xact_max:MAX:%4.1lf%s Max,',
+    'GPRINT:pg_xact_avg:LAST:%4.1lf%s Last'],
     power => ['-v', 'Watt',
     'DEF:avg={file}:value:AVERAGE',
     'DEF:min={file}:value:MIN',
index 9b578e6..ee4c893 100755 (executable)
@@ -245,6 +245,15 @@ sub flush {
                        elsif ($option eq "timeout") {
                                $args{"timeout"} = $value;
                        }
+                       elsif ($option eq "identifier") {
+                               my $id = getid (\$value);
+                               if (!$id)
+                               {
+                                       print STDERR "Not a valid identifier: \"$value\"\n";
+                                       next;
+                               }
+                               push @{$args{"identifier"}}, $id;
+                       }
                        else {
                                print STDERR "Invalid option \"$option\".\n";
                                return;
index 240c6c3..f68cc1a 100644 (file)
@@ -98,8 +98,8 @@ static int my_read (void)
        vl.values     = values;
        vl.values_len = 1;
        vl.time       = time (NULL);
-       strcpy (vl.host, hostname_g);
-       strcpy (vl.plugin, "myplugin");
+       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       sstrncpy (vl.plugin, "myplugin", sizeof (vl.plugin));
        /* optionally set vl.plugin_instance and vl.type_instance to reasonable
         * values (default: "") */
 
index 34de4fb..1b46b9b 100644 (file)
@@ -21,6 +21,7 @@ if BUILD_FEATURE_DAEMON
 AM_CPPFLAGS += -DPIDFILE='"${localstatedir}/run/${PACKAGE_NAME}.pid"'
 endif
 AM_CPPFLAGS += -DPLUGINDIR='"${pkglibdir}"'
+AM_CPPFLAGS += -DPKGDATADIR='"${pkgdatadir}"'
 
 sbin_PROGRAMS = collectd collectdmon
 bin_PROGRAMS = collectd-nagios
@@ -31,6 +32,7 @@ collectd_SOURCES = collectd.c collectd.h \
                   plugin.c plugin.h \
                   utils_avltree.c utils_avltree.h \
                   utils_cache.c utils_cache.h \
+                  utils_complain.c utils_complain.h \
                   utils_ignorelist.c utils_ignorelist.h \
                   utils_llist.c utils_llist.h \
                   utils_tail_match.c utils_tail_match.h \
@@ -41,7 +43,7 @@ collectd_SOURCES = collectd.c collectd.h \
                   types_list.c types_list.h
 
 collectd_CPPFLAGS =  $(AM_CPPFLAGS) $(LTDLINCL)
-collectd_CFLAGS =
+collectd_CFLAGS = $(AM_CFLAGS)
 collectd_LDFLAGS = -export-dynamic
 collectd_LDADD =
 collectd_DEPENDENCIES =
@@ -95,7 +97,7 @@ if BUILD_PLUGIN_APACHE
 pkglib_LTLIBRARIES += apache.la
 apache_la_SOURCES = apache.c
 apache_la_LDFLAGS = -module -avoid-version
-apache_la_CFLAGS =
+apache_la_CFLAGS = $(AM_CFLAGS)
 apache_la_LIBADD =
 collectd_LDADD += "-dlopen" apache.la
 if BUILD_WITH_LIBCURL
@@ -128,7 +130,8 @@ if BUILD_PLUGIN_ASCENT
 pkglib_LTLIBRARIES += ascent.la
 ascent_la_SOURCES = ascent.c
 ascent_la_LDFLAGS = -module -avoid-version
-ascent_la_CFLAGS = $(BUILD_WITH_LIBCURL_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
+ascent_la_CFLAGS = $(AM_CFLAGS) \
+               $(BUILD_WITH_LIBCURL_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
 ascent_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
 collectd_LDADD += "-dlopen" ascent.la
 collectd_DEPENDENCIES += ascent.la
@@ -148,7 +151,7 @@ endif
 if BUILD_PLUGIN_CPU
 pkglib_LTLIBRARIES += cpu.la
 cpu_la_SOURCES = cpu.c
-cpu_la_CFLAGS =
+cpu_la_CFLAGS = $(AM_CFLAGS)
 cpu_la_LDFLAGS = -module -avoid-version
 cpu_la_LIBADD = 
 if BUILD_WITH_LIBKSTAT
@@ -192,7 +195,7 @@ endif
 if BUILD_PLUGIN_DISK
 pkglib_LTLIBRARIES += disk.la
 disk_la_SOURCES = disk.c
-disk_la_CFLAGS =
+disk_la_CFLAGS = $(AM_CFLAGS)
 disk_la_LDFLAGS = -module -avoid-version
 disk_la_LIBADD = 
 if BUILD_WITH_LIBKSTAT
@@ -242,6 +245,7 @@ endif
 if BUILD_PLUGIN_EXEC
 pkglib_LTLIBRARIES += exec.la
 exec_la_SOURCES = exec.c \
+                 utils_parse_option.h utils_parse_option.c \
                  utils_cmd_putnotif.c utils_cmd_putnotif.h \
                  utils_cmd_putval.c utils_cmd_putval.h
 exec_la_LDFLAGS = -module -avoid-version
@@ -252,6 +256,14 @@ collectd_LDADD += "-dlopen" exec.la
 collectd_DEPENDENCIES += exec.la
 endif
 
+if BUILD_PLUGIN_FILECOUNT
+pkglib_LTLIBRARIES += filecount.la
+filecount_la_SOURCES = filecount.c
+filecount_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" filecount.la
+collectd_DEPENDENCIES += filecount.la
+endif
+
 if BUILD_PLUGIN_HDDTEMP
 pkglib_LTLIBRARIES += hddtemp.la
 hddtemp_la_SOURCES = hddtemp.c
@@ -266,7 +278,7 @@ endif
 if BUILD_PLUGIN_INTERFACE
 pkglib_LTLIBRARIES += interface.la
 interface_la_SOURCES = interface.c
-interface_la_CFLAGS =
+interface_la_CFLAGS = $(AM_CFLAGS)
 interface_la_LDFLAGS = -module -avoid-version
 interface_la_LIBADD =
 collectd_LDADD += "-dlopen" interface.la
@@ -301,7 +313,7 @@ endif
 if BUILD_PLUGIN_IPMI
 pkglib_LTLIBRARIES += ipmi.la
 ipmi_la_SOURCES = ipmi.c
-ipmi_la_CFLAGS = $(BUILD_WITH_OPENIPMI_CFLAGS)
+ipmi_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_OPENIPMI_CFLAGS)
 ipmi_la_LDFLAGS = -module -avoid-version
 ipmi_la_LIBADD = $(BUILD_WITH_OPENIPMI_LIBS)
 collectd_LDADD += "-dlopen" ipmi.la
@@ -311,7 +323,7 @@ endif
 if BUILD_PLUGIN_IPVS
 pkglib_LTLIBRARIES += ipvs.la
 ipvs_la_SOURCES = ipvs.c
-ipvs_la_CFLAGS = $(KERNEL_CFLAGS)
+ipvs_la_CFLAGS = $(AM_CFLAGS) $(KERNEL_CFLAGS)
 ipvs_la_LDFLAGS = -module -avoid-version
 collectd_LDADD += "-dlopen" ipvs.la
 collectd_DEPENDENCIES += ipvs.la
@@ -328,7 +340,8 @@ endif
 if BUILD_PLUGIN_LIBVIRT
 pkglib_LTLIBRARIES += libvirt.la
 libvirt_la_SOURCES = libvirt.c
-libvirt_la_CFLAGS = $(BUILD_WITH_LIBVIRT_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
+libvirt_la_CFLAGS = $(AM_CFLAGS) \
+               $(BUILD_WITH_LIBVIRT_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
 libvirt_la_LIBADD = $(BUILD_WITH_LIBVIRT_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
 libvirt_la_LDFLAGS = -module -avoid-version
 collectd_LDADD += "-dlopen" libvirt.la
@@ -338,7 +351,7 @@ endif
 if BUILD_PLUGIN_LOAD
 pkglib_LTLIBRARIES += load.la
 load_la_SOURCES = load.c
-load_la_CFLAGS =
+load_la_CFLAGS = $(AM_CFLAGS)
 load_la_LDFLAGS = -module -avoid-version
 load_la_LIBADD =
 collectd_LDADD += "-dlopen" load.la
@@ -372,7 +385,6 @@ if BUILD_PLUGIN_MEMCACHED
 pkglib_LTLIBRARIES += memcached.la
 memcached_la_SOURCES = memcached.c
 memcached_la_LDFLAGS = -module -avoid-version
-memcached_la_CFLAGS =
 memcached_la_LIBADD =
 if BUILD_WITH_LIBSOCKET
 memcached_la_LDFLAGS += -lsocket
@@ -384,7 +396,7 @@ endif
 if BUILD_PLUGIN_MEMORY
 pkglib_LTLIBRARIES += memory.la
 memory_la_SOURCES = memory.c
-memory_la_CFLAGS =
+memory_la_CFLAGS = $(AM_CFLAGS)
 memory_la_LDFLAGS = -module -avoid-version
 memory_la_LIBADD =
 collectd_LDADD += "-dlopen" memory.la
@@ -413,7 +425,7 @@ if BUILD_PLUGIN_MYSQL
 pkglib_LTLIBRARIES += mysql.la
 mysql_la_SOURCES = mysql.c
 mysql_la_LDFLAGS = -module -avoid-version
-mysql_la_CFLAGS =
+mysql_la_CFLAGS = $(AM_CFLAGS)
 mysql_la_LIBADD =
 collectd_LDADD += "-dlopen" mysql.la
 if BUILD_WITH_LIBMYSQL
@@ -427,7 +439,7 @@ 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_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBNETLINK_CFLAGS)
 netlink_la_LIBADD = $(BUILD_WITH_LIBNETLINK_LIBS)
 collectd_LDADD += "-dlopen" netlink.la
 collectd_DEPENDENCIES += netlink.la
@@ -469,6 +481,23 @@ collectd_LDADD += "-dlopen" nginx.la
 collectd_DEPENDENCIES += nginx.la
 endif
 
+if BUILD_PLUGIN_NOTIFY_DESKTOP
+pkglib_LTLIBRARIES += notify_desktop.la
+notify_desktop_la_SOURCES = notify_desktop.c
+notify_desktop_la_CFLAGS = $(AM_CFLAGS) $(LIBNOTIFY_CFLAGS)
+notify_desktop_la_LDFLAGS = -module -avoid-version $(LIBNOTIFY_LIBS)
+collectd_LDADD += "-dlopen" notify_desktop.la
+collectd_DEPENDENCIES += notify_desktop.la
+endif
+
+if BUILD_PLUGIN_NOTIFY_EMAIL
+pkglib_LTLIBRARIES += notify_email.la
+notify_email_la_SOURCES = notify_email.c
+notify_email_la_LDFLAGS = -L/usr/local/lib -lesmtp -lssl -lcrypto -pthread -module -avoid-version
+collectd_LDADD += "-dlopen" notify_email.la
+collectd_DEPENDENCIES += notify_email.la
+endif
+
 if BUILD_PLUGIN_NTPD
 pkglib_LTLIBRARIES += ntpd.la
 ntpd_la_SOURCES = ntpd.c
@@ -489,14 +518,28 @@ collectd_LDADD += "-dlopen" nut.la
 collectd_DEPENDENCIES += nut.la
 endif
 
+if BUILD_PLUGIN_ONEWIRE
+pkglib_LTLIBRARIES += onewire.la
+onewire_la_SOURCES = onewire.c
+onewire_la_CFLAGS = $(AM_CFLAGS)
+onewire_la_CPPFLAGS = $(BUILD_WITH_LIBOWCAPI_CPPFLAGS)
+onewire_la_LIBADD = $(BUILD_WITH_LIBOWCAPI_LIBS)
+onewire_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" onewire.la
+collectd_DEPENDENCIES += onewire.la
+endif
+
 if BUILD_PLUGIN_PERL
 pkglib_LTLIBRARIES += perl.la
 perl_la_SOURCES = perl.c
+# Despite C99 providing the "bool" type thru stdbool.h, Perl defines its own
+# version of that type if HAS_BOOL is not defined... *sigh*
+perl_la_CPPFLAGS = $(AM_CPPFLAGS) -DHAS_BOOL=1
 perl_la_CFLAGS  = $(AM_CFLAGS) \
-                 $(PERL_CFLAGS) \
-                 -DXS_VERSION=\"$(VERSION)\" -DVERSION=\"$(VERSION)\"
+               $(PERL_CFLAGS) \
+               -DXS_VERSION=\"$(VERSION)\" -DVERSION=\"$(VERSION)\"
 perl_la_LDFLAGS = -module -avoid-version \
-                 $(PERL_LDFLAGS)
+               $(PERL_LDFLAGS)
 collectd_LDADD += "-dlopen" perl.la
 collectd_DEPENDENCIES += perl.la
 endif
@@ -515,6 +558,16 @@ collectd_LDADD += "-dlopen" ping.la
 collectd_DEPENDENCIES += ping.la
 endif
 
+if BUILD_PLUGIN_POSTGRESQL
+pkglib_LTLIBRARIES += postgresql.la
+postgresql_la_SOURCES = postgresql.c
+postgresql_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBPQ_CPPFLAGS)
+postgresql_la_LDFLAGS = -module -avoid-version \
+               $(BUILD_WITH_LIBPQ_LDFLAGS) -lpq
+collectd_LDADD += "-dlopen" postgresql.la
+collectd_DEPENDENCIES += postgresql.la
+endif
+
 if BUILD_PLUGIN_POWERDNS
 pkglib_LTLIBRARIES += powerdns.la
 powerdns_la_SOURCES = powerdns.c
@@ -527,15 +580,19 @@ if BUILD_PLUGIN_PROCESSES
 pkglib_LTLIBRARIES += processes.la
 processes_la_SOURCES = processes.c
 processes_la_LDFLAGS = -module -avoid-version
+processes_la_LIBADD =
 collectd_LDADD += "-dlopen" processes.la
 collectd_DEPENDENCIES += processes.la
+if BUILD_WITH_LIBKVM_GETPROCS
+processes_la_LIBADD += -lkvm
+endif
 endif
 
 if BUILD_PLUGIN_RRDTOOL
 pkglib_LTLIBRARIES += rrdtool.la
 rrdtool_la_SOURCES = rrdtool.c
 rrdtool_la_LDFLAGS = -module -avoid-version
-rrdtool_la_CFLAGS = $(BUILD_WITH_LIBRRD_CFLAGS)
+rrdtool_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBRRD_CFLAGS)
 rrdtool_la_LIBADD = $(BUILD_WITH_LIBRRD_LDFLAGS)
 collectd_LDADD += "-dlopen" rrdtool.la
 collectd_DEPENDENCIES += rrdtool.la
@@ -544,7 +601,7 @@ endif
 if BUILD_PLUGIN_SENSORS
 pkglib_LTLIBRARIES += sensors.la
 sensors_la_SOURCES = sensors.c
-sensors_la_CFLAGS = $(BUILD_WITH_LIBSENSORS_CFLAGS)
+sensors_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBSENSORS_CFLAGS)
 sensors_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBSENSORS_LDFLAGS)
 sensors_la_LIBADD = -lsensors
 collectd_LDADD += "-dlopen" sensors.la
@@ -563,7 +620,7 @@ if BUILD_PLUGIN_SNMP
 pkglib_LTLIBRARIES += snmp.la
 snmp_la_SOURCES = snmp.c
 snmp_la_LDFLAGS = -module -avoid-version
-snmp_la_CFLAGS =
+snmp_la_CFLAGS = $(AM_CFLAGS)
 snmp_la_LIBADD =
 if BUILD_WITH_LIBNETSNMP
 snmp_la_CFLAGS += $(BUILD_WITH_LIBSNMP_CFLAGS)
@@ -579,7 +636,7 @@ endif
 if BUILD_PLUGIN_SWAP
 pkglib_LTLIBRARIES += swap.la
 swap_la_SOURCES = swap.c
-swap_la_CFLAGS =
+swap_la_CFLAGS = $(AM_CFLAGS)
 swap_la_LDFLAGS = -module -avoid-version
 swap_la_LIBADD =
 collectd_LDADD += "-dlopen" swap.la
@@ -627,8 +684,12 @@ if BUILD_PLUGIN_TCPCONNS
 pkglib_LTLIBRARIES += tcpconns.la
 tcpconns_la_SOURCES = tcpconns.c
 tcpconns_la_LDFLAGS = -module -avoid-version
+tcpconns_la_LIBADD =
 collectd_LDADD += "-dlopen" tcpconns.la
 collectd_DEPENDENCIES += tcpconns.la
+if BUILD_WITH_LIBKVM_NLIST
+tcpconns_la_LIBADD += -lkvm
+endif
 endif
 
 if BUILD_PLUGIN_TEAMSPEAK2
@@ -639,9 +700,18 @@ collectd_LDADD += "-dlopen" teamspeak2.la
 collectd_DEPENDENCIES += teamspeak2.la
 endif
 
+if BUILD_PLUGIN_THERMAL
+pkglib_LTLIBRARIES += thermal.la
+thermal_la_SOURCES = thermal.c
+thermal_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" thermal.la
+collectd_DEPENDENCIES += thermal.la
+endif
+
 if BUILD_PLUGIN_UNIXSOCK
 pkglib_LTLIBRARIES += unixsock.la
 unixsock_la_SOURCES = unixsock.c \
+                     utils_parse_option.h utils_parse_option.c \
                      utils_cmd_flush.h utils_cmd_flush.c \
                      utils_cmd_getval.h utils_cmd_getval.c \
                      utils_cmd_listval.h utils_cmd_listval.c \
@@ -655,7 +725,7 @@ endif
 if BUILD_PLUGIN_USERS
 pkglib_LTLIBRARIES += users.la
 users_la_SOURCES = users.c
-users_la_CFLAGS =
+users_la_CFLAGS = $(AM_CFLAGS)
 users_la_LDFLAGS = -module -avoid-version
 users_la_LIBADD =
 if BUILD_WITH_LIBSTATGRAB
@@ -669,7 +739,7 @@ endif
 if BUILD_PLUGIN_UUID
 pkglib_LTLIBRARIES += uuid.la
 uuid_la_SOURCES = uuid.c
-uuid_la_CFLAGS  = $(BUILD_WITH_LIBHAL_CFLAGS)
+uuid_la_CFLAGS  = $(AM_CFLAGS) $(BUILD_WITH_LIBHAL_CFLAGS)
 uuid_la_LIBADD  = $(BUILD_WITH_LIBHAL_LIBS)
 uuid_la_LDFLAGS = -module -avoid-version
 collectd_LDADD += "-dlopen" uuid.la
@@ -721,13 +791,24 @@ EXTRA_DIST = types.db
 
 EXTRA_DIST += collectd-email.pod collectd-exec.pod collectd-nagios.pod \
        collectd-perl.pod collectd-snmp.pod collectd-unixsock.pod \
-       collectd.conf.pod collectd.pod collectdmon.pod types.db.pod
+       collectd.conf.pod collectd.pod collectdmon.pod types.db.pod \
+       postgresql_default.conf
 
 .pod.1:
-       pod2man --release=$(VERSION) --center=$(PACKAGE) $< >.pod2man.tmp 2>/dev/null && mv -f .pod2man.tmp $@ || true
+       pod2man --release=$(VERSION) --center=$(PACKAGE) $< \
+               >.pod2man.tmp 2>/dev/null && mv -f .pod2man.tmp $@ || true
+       @if grep '\<POD ERRORS\>' $@ >/dev/null 2>&1; \
+       then \
+               echo "$@ has some POD errors!"; false; \
+       fi
 
 .pod.5:
-       pod2man --section=5 --release=$(VERSION) --center=$(PACKAGE) $< >.pod2man.tmp 2>/dev/null && mv -f .pod2man.tmp $@ || true
+       pod2man --section=5 --release=$(VERSION) --center=$(PACKAGE) $< \
+               >.pod2man.tmp 2>/dev/null && mv -f .pod2man.tmp $@ || true
+       @if grep '\<POD ERRORS\>' $@ >/dev/null 2>&1; \
+       then \
+               echo "$@ has some POD errors!"; false; \
+       fi
 
 install-exec-hook:
        $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
@@ -738,3 +819,6 @@ install-exec-hook:
                $(INSTALL) -m 0640 collectd.conf $(DESTDIR)$(sysconfdir)/collectd.conf; \
        fi; \
        cp -f $(srcdir)/types.db $(DESTDIR)$(pkglibdir)/;
+       $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
+       $(INSTALL) -m 0644 $(srcdir)/postgresql_default.conf \
+               $(DESTDIR)$(pkgdatadir)/postgresql_default.conf;
index a2f41f4..c6bf8ad 100644 (file)
@@ -146,7 +146,7 @@ static int init (void)
        {
                int status;
 
-               status = snprintf (credentials, sizeof (credentials), "%s:%s",
+               status = ssnprintf (credentials, sizeof (credentials), "%s:%s",
                                user, (pass == NULL) ? "" : pass);
                if (status >= sizeof (credentials))
                {
@@ -155,7 +155,6 @@ static int init (void)
                                        "truncated.");
                        return (-1);
                }
-               credentials[sizeof (credentials) - 1] = '\0';
 
                curl_easy_setopt (curl, CURLOPT_USERPWD, credentials);
        }
@@ -202,15 +201,13 @@ static void submit_counter (const char *type, const char *type_instance,
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "apache", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
+       sstrncpy (vl.type, type, sizeof (vl.type));
 
        if (type_instance != NULL)
-       {
-               strncpy (vl.type_instance, type_instance,
+               sstrncpy (vl.type_instance, type_instance,
                                sizeof (vl.type_instance));
-               vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
-       }
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void submit_counter */
 
 static void submit_gauge (const char *type, const char *type_instance,
@@ -227,15 +224,13 @@ static void submit_gauge (const char *type, const char *type_instance,
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "apache", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
+       sstrncpy (vl.type, type, sizeof (vl.type));
 
        if (type_instance != NULL)
-       {
-               strncpy (vl.type_instance, type_instance,
+               sstrncpy (vl.type_instance, type_instance,
                                sizeof (vl.type_instance));
-               vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
-       }
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void submit_counter */
 
 static void submit_scoreboard (char *buf)
index 462006a..ca026b9 100644 (file)
@@ -117,8 +117,7 @@ static int net_open (char *host, int port)
        assert ((port > 0x00000000) && (port <= 0x0000FFFF));
 
        /* Convert the port to a string */
-       snprintf (port_str, 8, "%i", port);
-       port_str[7] = '\0';
+       ssnprintf (port_str, sizeof (port_str), "%i", port);
 
        /* Resolve name */
        memset ((void *) &ai_hints, '\0', sizeof (ai_hints));
@@ -369,9 +368,10 @@ static void apc_submit_generic (char *type, char *type_inst, double value)
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "apcups", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
-       strncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
+       sstrncpy (vl.type, type, sizeof (vl.type));
+       sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 }
 
 static void apc_submit (struct apc_detail_s *apcups_detail)
index 5e957b6..d312027 100644 (file)
@@ -91,9 +91,10 @@ static void as_submit (const char *type, const char *type_instance,
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "apple_sensors", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
+       sstrncpy (vl.type, type, sizeof (vl.type));
        sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 }
 
 static int as_read (void)
@@ -146,10 +147,10 @@ static int as_read (void)
                if (CFGetTypeID (property) != CFStringGetTypeID ())
                        continue;
                if (!CFStringGetCString (property,
-                                       type, 128,
+                                       type, sizeof (type),
                                        kCFStringEncodingASCII))
                        continue;
-               type[127] = '\0';
+               type[sizeof (type) - 1] = '\0';
 
                /* Copy the sensor location. This will be used as `instance'. */
                property = NULL;
@@ -160,10 +161,10 @@ static int as_read (void)
                if (CFGetTypeID (property) != CFStringGetTypeID ())
                        continue;
                if (!CFStringGetCString (property,
-                                       inst, 128,
+                                       inst, sizeof (inst),
                                        kCFStringEncodingASCII))
                        continue;
-               inst[127] = '\0';
+               inst[sizeof (inst) - 1] = '\0';
                for (i = 0; i < 128; i++)
                {
                        if (inst[i] == '\0')
index e0b6ba2..6285176 100644 (file)
@@ -91,10 +91,12 @@ struct player_info_s
 typedef struct player_info_s player_info_t;
 #define PLAYER_INFO_STATIC_INIT { -1, -1, -1, -1, -1 }
 
-static char *url    = NULL;
-static char *user   = NULL;
-static char *pass   = NULL;
-static char *cacert = NULL;
+static char *url         = NULL;
+static char *user        = NULL;
+static char *pass        = NULL;
+static char *verify_peer = NULL;
+static char *verify_host = NULL;
+static char *cacert      = NULL;
 
 static CURL *curl = NULL;
 
@@ -108,6 +110,8 @@ static const char *config_keys[] =
   "URL",
   "User",
   "Password",
+  "VerifyPeer",
+  "VerifyHost",
   "CACert"
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
@@ -130,10 +134,12 @@ static int ascent_submit_gauge (const char *plugin_instance, /* {{{ */
     sstrncpy (vl.plugin_instance, plugin_instance,
         sizeof (vl.plugin_instance));
 
+  sstrncpy (vl.type, type, sizeof (vl.type));
+
   if (type_instance != NULL)
     sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-  plugin_dispatch_values (type, &vl);
+  plugin_dispatch_values (&vl);
   return (0);
 } /* }}} int ascent_submit_gauge */
 
@@ -502,6 +508,10 @@ static int ascent_config (const char *key, const char *value) /* {{{ */
     return (config_set (&user, value));
   else if (strcasecmp (key, "Password") == 0)
     return (config_set (&pass, value));
+  else if (strcasecmp (key, "VerifyPeer") == 0)
+    return (config_set (&verify_peer, value));
+  else if (strcasecmp (key, "VerifyHost") == 0)
+    return (config_set (&verify_host, value));
   else if (strcasecmp (key, "CACert") == 0)
     return (config_set (&cacert, value));
   else
@@ -538,7 +548,7 @@ static int ascent_init (void) /* {{{ */
   {
     int status;
 
-    status = snprintf (credentials, sizeof (credentials), "%s:%s",
+    status = ssnprintf (credentials, sizeof (credentials), "%s:%s",
         user, (pass == NULL) ? "" : pass);
     if (status >= sizeof (credentials))
     {
@@ -546,13 +556,22 @@ static int ascent_init (void) /* {{{ */
           "credentials have been truncated.");
       return (-1);
     }
-    credentials[sizeof (credentials) - 1] = '\0';
 
     curl_easy_setopt (curl, CURLOPT_USERPWD, credentials);
   }
 
   curl_easy_setopt (curl, CURLOPT_URL, url);
 
+  if ((verify_peer == NULL) || (strcmp (verify_peer, "true") == 0))
+    curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 1);
+  else
+    curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0);
+
+  if ((verify_host == NULL) || (strcmp (verify_host, "true") == 0))
+    curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 2);
+  else
+    curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0);
+
   if (cacert != NULL)
     curl_easy_setopt (curl, CURLOPT_CAINFO, cacert);
 
index badd8e7..416f339 100644 (file)
@@ -61,6 +61,7 @@
 #elif KERNEL_LINUX
 static int   battery_pmu_num = 0;
 static char *battery_pmu_file = "/proc/pmu/battery_%i";
+static const char *battery_acpi_dir = "/proc/acpi/battery";
 #endif /* KERNEL_LINUX */
 
 static int battery_init (void)
@@ -75,7 +76,7 @@ static int battery_init (void)
 
        for (battery_pmu_num = 0; ; battery_pmu_num++)
        {
-               len = snprintf (filename, sizeof (filename), battery_pmu_file, battery_pmu_num);
+               len = ssnprintf (filename, sizeof (filename), battery_pmu_file, battery_pmu_num);
 
                if ((len < 0) || ((unsigned int)len >= sizeof (filename)))
                        break;
@@ -101,8 +102,9 @@ static void battery_submit (const char *plugin_instance, const char *type, doubl
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "battery", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+       sstrncpy (vl.type, type, sizeof (vl.type));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void battery_submit */
 
 #if HAVE_IOKIT_PS_IOPOWERSOURCES_H || HAVE_IOKIT_IOKITLIB_H
@@ -312,6 +314,100 @@ static void get_via_generic_iokit (double *ret_charge,
 }
 #endif /* HAVE_IOKIT_IOKITLIB_H */
 
+#if KERNEL_LINUX
+static int battery_read_acpi (const char *dir, const char *name,
+               void *user_data)
+{
+       double  current = INVALID_VALUE;
+       double  voltage = INVALID_VALUE;
+       double  charge  = INVALID_VALUE;
+       double *valptr = NULL;
+       int charging = 0;
+
+       char filename[256];
+       FILE *fh;
+
+       char buffer[1024];
+       char *fields[8];
+       int numfields;
+       char *endptr;
+       int len;
+
+       len = ssnprintf (filename, sizeof (filename), "%s/%s/state", battery_acpi_dir, name);
+
+       if ((len < 0) || ((unsigned int)len >= sizeof (filename)))
+               return -1;
+
+       if ((fh = fopen (filename, "r")) == NULL) {
+               char errbuf[1024];
+               ERROR ("Cannot open `%s': %s", filename,
+                       sstrerror (errno, errbuf, sizeof (errbuf)));
+               return -1;
+       }
+
+       /*
+        * [11:00] <@tokkee> $ cat /proc/acpi/battery/BAT1/state
+        * [11:00] <@tokkee> present:                 yes
+        * [11:00] <@tokkee> capacity state:          ok
+        * [11:00] <@tokkee> charging state:          charging
+        * [11:00] <@tokkee> present rate:            1724 mA
+        * [11:00] <@tokkee> remaining capacity:      4136 mAh
+        * [11:00] <@tokkee> present voltage:         12428 mV
+        */
+       while (fgets (buffer, sizeof (buffer), fh) != NULL)
+       {
+               numfields = strsplit (buffer, fields, 8);
+
+               if (numfields < 3)
+                       continue;
+
+               if ((strcmp (fields[0], "charging") == 0)
+                               && (strcmp (fields[1], "state:") == 0))
+               {
+                       if (strcmp (fields[2], "charging") == 0)
+                               charging = 1;
+                       else
+                               charging = 0;
+                       continue;
+               }
+
+               if ((strcmp (fields[0], "present") == 0)
+                               && (strcmp (fields[1], "rate:") == 0))
+                       valptr = &current;
+               else if ((strcmp (fields[0], "remaining") == 0)
+                               && (strcmp (fields[1], "capacity:") == 0))
+                       valptr = &charge;
+               else if ((strcmp (fields[0], "present") == 0)
+                               && (strcmp (fields[1], "voltage:") == 0))
+                       valptr = &voltage;
+               else
+                       continue;
+
+               endptr = NULL;
+               errno  = 0;
+               *valptr = strtod (fields[2], &endptr) / 1000.0;
+
+               if ((fields[2] == endptr) || (errno != 0))
+                       *valptr = INVALID_VALUE;
+       } /* while (fgets (buffer, sizeof (buffer), fh) != NULL) */
+
+       fclose (fh);
+
+       if ((current != INVALID_VALUE) && (charging == 0))
+                       current *= -1;
+
+       if (charge != INVALID_VALUE)
+               battery_submit ("0", "charge", charge);
+       if (current != INVALID_VALUE)
+               battery_submit ("0", "current", current);
+       if (voltage != INVALID_VALUE)
+               battery_submit ("0", "voltage", voltage);
+
+       return 0;
+}
+#endif /* KERNEL_LINUX */
+
+
 static int battery_read (void)
 {
 #if HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H
@@ -359,11 +455,11 @@ static int battery_read (void)
                double  charge  = INVALID_VALUE;
                double *valptr = NULL;
 
-               len = snprintf (filename, sizeof (filename), battery_pmu_file, i);
+               len = ssnprintf (filename, sizeof (filename), battery_pmu_file, i);
                if ((len < 0) || ((unsigned int)len >= sizeof (filename)))
                        continue;
 
-               len = snprintf (batnum_str, sizeof (batnum_str), "%i", i);
+               len = ssnprintf (batnum_str, sizeof (batnum_str), "%i", i);
                if ((len < 0) || ((unsigned int)len >= sizeof (batnum_str)))
                        continue;
 
@@ -411,111 +507,9 @@ static int battery_read (void)
                        battery_submit ("0", "voltage", voltage);
        }
 
-       if (access ("/proc/acpi/battery", R_OK | X_OK) == 0)
-       {
-               double  current = INVALID_VALUE;
-               double  voltage = INVALID_VALUE;
-               double  charge  = INVALID_VALUE;
-               double *valptr = NULL;
-               int charging = 0;
-
-               struct dirent *ent;
-               DIR *dh;
+       walk_directory (battery_acpi_dir, battery_read_acpi,
+                       /* user_data = */ NULL);
 
-               if ((dh = opendir ("/proc/acpi/battery")) == NULL)
-               {
-                       char errbuf[1024];
-                       ERROR ("Cannot open `/proc/acpi/battery': %s",
-                                       sstrerror (errno, errbuf, sizeof (errbuf)));
-                       return (-1);
-               }
-
-               while ((ent = readdir (dh)) != NULL)
-               {
-                       if (ent->d_name[0] == '.')
-                               continue;
-
-                       len = snprintf (filename, sizeof (filename),
-                                       "/proc/acpi/battery/%s/state",
-                                       ent->d_name);
-                       if ((len < 0) || ((unsigned int)len >= sizeof (filename)))
-                               continue;
-
-                       if ((fh = fopen (filename, "r")) == NULL)
-                       {
-                               char errbuf[1024];
-                               ERROR ("Cannot open `%s': %s", filename,
-                                               sstrerror (errno, errbuf,
-                                                       sizeof (errbuf)));
-                               continue;
-                       }
-
-                       /*
-                        * [11:00] <@tokkee> $ cat /proc/acpi/battery/BAT1/state
-                        * [11:00] <@tokkee> present:                 yes
-                        * [11:00] <@tokkee> capacity state:          ok
-                        * [11:00] <@tokkee> charging state:          charging
-                        * [11:00] <@tokkee> present rate:            1724 mA
-                        * [11:00] <@tokkee> remaining capacity:      4136 mAh
-                        * [11:00] <@tokkee> present voltage:         12428 mV
-                        */
-                       while (fgets (buffer, sizeof (buffer), fh) != NULL)
-                       {
-                               numfields = strsplit (buffer, fields, 8);
-
-                               if (numfields < 3)
-                                       continue;
-
-                               if ((strcmp (fields[0], "present") == 0)
-                                               && (strcmp (fields[1], "rate:") == 0))
-                                       valptr = &current;
-                               else if ((strcmp (fields[0], "remaining") == 0)
-                                               && (strcmp (fields[1], "capacity:") == 0))
-                                       valptr = &charge;
-                               else if ((strcmp (fields[0], "present") == 0)
-                                               && (strcmp (fields[1], "voltage:") == 0))
-                                       valptr = &voltage;
-                               else
-                                       valptr = NULL;
-
-                               if ((strcmp (fields[0], "charging") == 0)
-                                               && (strcmp (fields[1], "state:") == 0))
-                               {
-                                       if (strcmp (fields[2], "charging") == 0)
-                                               charging = 1;
-                                       else
-                                               charging = 0;
-                               }
-
-                               if (valptr != NULL)
-                               {
-                                       char *endptr;
-
-                                       endptr = NULL;
-                                       errno  = 0;
-
-                                       *valptr = strtod (fields[2], &endptr) / 1000.0;
-
-                                       if ((fields[2] == endptr) || (errno != 0))
-                                               *valptr = INVALID_VALUE;
-                               }
-                       } /* while (fgets (buffer, sizeof (buffer), fh) != NULL) */
-
-                       fclose (fh);
-
-                       if ((current != INVALID_VALUE) && (charging == 0))
-                                       current *= -1;
-
-                       if (charge != INVALID_VALUE)
-                               battery_submit ("0", "charge", charge);
-                       if (current != INVALID_VALUE)
-                               battery_submit ("0", "current", current);
-                       if (voltage != INVALID_VALUE)
-                               battery_submit ("0", "voltage", voltage);
-               }
-
-               closedir (dh);
-       }
 #endif /* KERNEL_LINUX */
 
        return (0);
index 59ce399..d935c70 100644 (file)
@@ -85,7 +85,8 @@ description of the format of this file.
 
 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.
+other options will be ignored. Values that contain spaces must be quoted with
+double quotes.
 
 I<Valuelist> is a colon-separated list of the time and the values, each either
 an integer if the data-source is a counter, or a double if the data-source is
@@ -139,10 +140,9 @@ Valid options are:
 =item B<message=>I<Message> (B<REQUIRED>)
 
 Sets the message of the notification. This is the message that will be made
-accessible to the user, so it should contain some useful information. This
-option must be the last option because the rest of the line will be its value,
-even if there are spaces and equal-signs following it! This option is
-mandatory.
+accessible to the user, so it should contain some useful information. As with
+all options: If the message includes spaces, it must be quoted with double
+quotes. This option is mandatory.
 
 =item B<severity=failure>|B<warning>|B<okay> (B<REQUIRED>)
 
index 8cdf08b..c3fcb10 100644 (file)
@@ -11,6 +11,10 @@ collectd-perl - Documentation of collectd's C<perl plugin>
     BaseName "Collectd::Plugin"
     EnableDebugger ""
     LoadPlugin "FooBar"
+
+    <Plugin FooBar>
+      Foo "Bar"
+    </Plugin>
   </Plugin>
 
 =head1 DESCRIPTION
@@ -36,6 +40,16 @@ causes the Perl-interpreter to be initialized.
 Prepends I<Name>B<::> to all plugin names loaded after this option. This is
 provided for convenience to keep plugin names short.
 
+=item E<lt>B<Plugin> I<Name>E<gt> block
+
+This block may be used to pass on configuration settings to a Perl plugin. The
+configuration is converted into a config-item data type which is passed to the
+registered configuration callback. See below for details about the config-item
+data type and how to register callbacks.
+
+The I<name> identifies the callback. It is used literally and independent of
+the B<BaseName> setting.
+
 =item B<EnableDebugger> I<Package>[=I<option>,...]
 
 Run collectd under the control of the Perl source debugger. If I<Package> is
@@ -71,6 +85,13 @@ example. The following types of B<callback functions> are known to collectd
 
 =over 4
 
+=item configuration functions
+
+This type of functions is called during configuration if an appropriate
+B<Plugin> block has been encountered. It is called once for each B<Plugin>
+block which matches the name of the callback as provided with the
+B<plugin_register> method - see below.
+
 =item init functions
 
 This type of functions is called once after loading the module and before any
@@ -140,6 +161,19 @@ and collectd:
 
 =over 4
 
+=item Config-Item
+
+A config-item is one structure which keeps the informations provided in the
+configuration file. The array of children keeps one entry for each
+configuration option. Each such entry is another config-item structure, which
+may nest further if nested blocks are used.
+
+  {
+    key      => key,
+    values   => [ val1, val2, ... ],
+    children => [ { ... }, { ... }, ... ]
+  }
+
 =item Data-Set
 
 A data-set is a list of one or more data-sources. Each data-source defines a
@@ -166,6 +200,7 @@ layout looks like this:
     time   => time (),
     host   => $hostname_g,
     plugin => 'myplugin',
+    type   => 'myplugin',
     plugin_instance => '',
     type_instance   => ''
   }
@@ -203,6 +238,8 @@ I<type> can be one of:
 
 =over 4
 
+=item TYPE_CONFIG
+
 =item TYPE_INIT
 
 =item TYPE_READ
@@ -247,6 +284,11 @@ arguments:
 
 =over 4
 
+=item TYPE_CONFIG
+
+The only argument passed is I<config-item>. See above for the layout of this
+data type.
+
 =item TYPE_INIT
 
 =item TYPE_READ
@@ -262,8 +304,9 @@ string. For the layout of I<data-set> and I<value-list> see above.
 
 =item TYPE_FLUSH
 
-The only argument passed is I<timeout> which indicates that only data older
-than I<timeout> seconds is to be flushed.
+The arguments passed are I<timeout> and I<identifier>. I<timeout> indicates
+that only data older than I<timeout> seconds is to be flushed. I<identifier>
+specifies which values are to be flushed.
 
 =item TYPE_LOG
 
@@ -285,29 +328,46 @@ data type.
 Removes a callback or data-set from collectd's internal list of
 functionsE<nbsp>/ datasets.
 
-=item B<plugin_dispatch_values> (I<type>, I<value-list>)
+=item B<plugin_dispatch_values> (I<value-list>)
 
-Submits a I<value-list> of type I<type> to the daemon. If the data-set I<type>
+Submits a I<value-list> to the daemon. If the data-set identified by
+I<value-list>->{I<type>}
 is found (and the number of values matches the number of data-sources) then the
 type, data-set and value-list is passed to all write-callbacks that are
 registered with the daemon.
 
-=item B<plugin_flush> ([B<timeout> => I<timeout>,] [B<plugins> => I<...>])
+B<Note>: Prior to version 4.4 of collectd, the data-set type used to be passed
+as the first argument to B<plugin_register>. This syntax is still supported
+for backwards compatibility but has been deprecated and will be removed in
+some future version of collectd.
 
-Flush one or more plugins. I<timeout> is passed on to the registered
-flush-callbacks. If omitted, C<-1> is used. If the I<plugins> argument has
-been specified, only named plugins will be flushed. The argument's value may
-either be a string or a reference to an array of strings.
+=item B<plugin_flush> ([B<timeout> => I<timeout>][, B<plugins> => I<...>][,
+B<identifiers> => I<...>])
+
+Flush one or more plugins. I<timeout> and the specified I<identifiers> are
+passed on to the registered flush-callbacks. If omitted, the timeout defaults
+to C<-1>. The identifier defaults to the undefined value. If the I<plugins>
+argument has been specified, only named plugins will be flushed. The value of
+the B<plugins> and B<identifiers> arguments may either be a string or a
+reference to an array of strings.
 
 =item B<plugin_flush_one> (I<timeout>, I<plugin>)
 
 This is identical to using "plugin_flush (timeout =E<gt> I<timeout>, plugins
 =E<gt> I<plugin>".
 
+B<Note>: Starting with version 4.5 of collectd, B<plugin_flush_one> has been
+deprecated and will be removed in some future version of collectd. Use
+B<plugin_flush> instead.
+
 =item B<plugin_flush_all> (I<timeout>)
 
 This is identical to using "plugin_flush (timeout =E<gt> I<timeout>)".
 
+B<Note>: Starting with version 4.5 of collectd, B<plugin_flush_all> has been
+deprecated and will be removed in some future version of collectd. Use
+B<plugin_flush> instead.
+
 =item B<plugin_dispatch_notification> (I<notification>)
 
 Submits a I<notification> to the daemon which will then pass it to all
@@ -377,6 +437,8 @@ available (B<:all> will export all of them):
 
 =over 4
 
+=item B<TYPE_CONFIG>
+
 =item B<TYPE_INIT>
 
 =item B<TYPE_READ>
@@ -389,6 +451,8 @@ available (B<:all> will export all of them):
 
 =item B<TYPE_LOG>
 
+=item B<TYPE_DATASET>
+
 =back
 
 =item B<:ds_types>
@@ -539,6 +603,14 @@ reasons. Therefore, END blocks are only executed once when collectd shuts
 down. You should not rely on END blocks anyway - use B<shutdown functions>
 instead.
 
+=item
+
+The perl plugin exports the internal API of collectd which is considered
+unstable and subject to change at any time. We try hard to not break backwards
+compatibility in the Perl API during the life cycle of one major release.
+However, this cannot be guaranteed at all times. Watch out for warnings
+dispatched by the perl plugin after upgrades.
+
 =back
 
 =head1 KNOWN BUGS
index 971cb36..ca00a6d 100644 (file)
@@ -94,7 +94,8 @@ data-sets is available in the B<types.db> file.
 
 The I<OptionList> is an optional list of I<Options>, where each option is a
 key-value-pair. A list of currently understood options can be found below, all
-other options will be ignored.
+other options will be ignored. Values that contain spaces must be quoted with
+double quotes.
 
 I<Valuelist> is a colon-separated list of the time and the values, each either
 an integer if the data-source is a counter, or a double if the data-source is
@@ -142,10 +143,9 @@ Valid options are:
 =item B<message=>I<Message> (B<REQUIRED>)
 
 Sets the message of the notification. This is the message that will be made
-accessible to the user, so it should contain some useful information. This
-option must be the last option because the rest of the line will be its value,
-even if there are spaces and equal-signs following it! This option is
-mandatory.
+accessible to the user, so it should contain some useful information. As with
+all options: If the message includes spaces, it must be quoted with double
+quotes. This option is mandatory.
 
 =item B<severity=failure>|B<warning>|B<okay> (B<REQUIRED>)
 
@@ -183,19 +183,25 @@ Example:
   -> | PUTNOTIF type=temperature severity=warning time=1201094702 message=The roof is on fire!
   <- | 0 Success
 
-=item B<FLUSH> [B<timeout=>I<Timeout>] [B<plugin=>I<Plugin> [...]]
+=item B<FLUSH> [B<timeout=>I<Timeout>] [B<plugin=>I<Plugin> [...]] [B<identifier=>I<Ident> [...]]
 
 Flushes all cached data older than I<Timeout> seconds. If no timeout has been
-specified, it defaults to -1 which causes all data to be flushed. B<timeout>
-may be specified multiple times - each occurrence applies to plugins listed
-afterwards.
+specified, it defaults to -1 which causes all data to be flushed.
+
+If the B<plugin> option has been specified, only the I<Plugin> plugin will be
+flushed. You can have multiple B<plugin> options to flush multiple plugins in
+one go. If the B<plugin> option is not given all plugins providing a flush
+callback will be flushed.
 
-If specified, only specific plugins are flushed. Otherwise all plugins
-providing a flush callback are flushed.
+If the B<identifier> option is given only the specified values will be flushed.
+This is meant to be used by graphing or displaying frontends which want to have
+the lastest values for a specific graph. Again, you can specify the
+B<identifier> option multiple times to flush several values. If this option is
+not specified at all, all values will be flushed.
 
 Example:
-  -> | FLUSH
-  <- | 0 Done
+  -> | FLUSH plugin=rrdtool identifier=localhost/df/df-root identifier=localhost/df/df-var
+  <- | 0 Done: 2 successful, 0 errors
 
 =back
 
@@ -206,13 +212,15 @@ Value or value-lists are identified in a uniform fashion:
 I<Hostname>/I<Plugin>/I<Type>
 
 Where I<Plugin> and I<Type> are both either of type "I<Name>" or
-"I<Name>-I<Instance>". This sounds more complicated than it is, so here are
+"I<Name>-I<Instance>". If the identifier includes spaces, it must be quoted
+using double quotes. This sounds more complicated than it is, so here are
 some examples:
 
   myhost/cpu-0/cpu-user
   myhost/load/load
   myhost/memory/memory-used
   myhost/disk-sda/disk_octets
+  "myups/snmp/temperature-Outlet 1"
 
 =head1 ABSTRACTION LAYER
 
index d6ec81a..9526ec9 100644 (file)
@@ -50,7 +50,7 @@ static int loop = 0;
 static void *do_flush (void *arg)
 {
        INFO ("Flushing all data.");
-       plugin_flush_all (-1);
+       plugin_flush (NULL, -1, NULL);
        INFO ("Finished flushing all data.");
        pthread_exit (NULL);
        return NULL;
@@ -90,8 +90,7 @@ static int init_hostname (void)
        str = global_option_get ("Hostname");
        if (str != NULL)
        {
-               strncpy (hostname_g, str, sizeof (hostname_g));
-               hostname_g[sizeof (hostname_g) - 1] = '\0';
+               sstrncpy (hostname_g, str, sizeof (hostname_g));
                return (0);
        }
 
@@ -127,8 +126,7 @@ static int init_hostname (void)
                if (ai_ptr->ai_canonname == NULL)
                        continue;
 
-               strncpy (hostname_g, ai_ptr->ai_canonname, sizeof (hostname_g));
-               hostname_g[sizeof (hostname_g) - 1] = '\0';
+               sstrncpy (hostname_g, ai_ptr->ai_canonname, sizeof (hostname_g));
                break;
        }
 
index 7a7ef86..9f14257 100644 (file)
@@ -40,6 +40,7 @@ FQDNLookup   true
 @BUILD_PLUGIN_EMAIL_TRUE@LoadPlugin email
 @BUILD_PLUGIN_ENTROPY_TRUE@LoadPlugin entropy
 @BUILD_PLUGIN_EXEC_TRUE@LoadPlugin exec
+@BUILD_PLUGIN_FILECOUNT_TRUE@LoadPlugin filecount
 @BUILD_PLUGIN_HDDTEMP_TRUE@LoadPlugin hddtemp
 @BUILD_PLUGIN_INTERFACE_TRUE@LoadPlugin interface
 @BUILD_PLUGIN_IPTABLES_TRUE@LoadPlugin iptables
@@ -57,10 +58,14 @@ FQDNLookup   true
 @BUILD_PLUGIN_NETWORK_TRUE@LoadPlugin network
 @BUILD_PLUGIN_NFS_TRUE@LoadPlugin nfs
 @BUILD_PLUGIN_NGINX_TRUE@LoadPlugin nginx
+@BUILD_PLUGIN_NOTIFY_DESKTOP_TRUE@LoadPlugin notify_desktop
+@BUILD_PLUGIN_NOTIFY_EMAIL_TRUE@LoadPlugin notify_email
 @BUILD_PLUGIN_NTPD_TRUE@LoadPlugin ntpd
 @BUILD_PLUGIN_NUT_TRUE@LoadPlugin nut
+@BUILD_PLUGIN_ONEWIRE_TRUE@LoadPlugin onewire
 @BUILD_PLUGIN_PERL_TRUE@LoadPlugin perl
 @BUILD_PLUGIN_PING_TRUE@LoadPlugin ping
+@BUILD_PLUGIN_POSTGRESQL_TRUE@LoadPlugin postgresql
 @BUILD_PLUGIN_POWERDNS_TRUE@LoadPlugin powerdns
 @BUILD_PLUGIN_PROCESSES_TRUE@LoadPlugin processes
 @BUILD_PLUGIN_RRDTOOL_TRUE@LoadPlugin rrdtool
@@ -72,6 +77,7 @@ FQDNLookup   true
 @BUILD_PLUGIN_TAPE_TRUE@LoadPlugin tape
 @BUILD_PLUGIN_TCPCONNS_TRUE@LoadPlugin tcpconns
 @BUILD_PLUGIN_TEAMSPEAK2_TRUE@LoadPlugin teamspeak2
+@BUILD_PLUGIN_THERMAL_TRUE@LoadPlugin thermal
 @BUILD_PLUGIN_UNIXSOCK_TRUE@LoadPlugin unixsock
 @BUILD_PLUGIN_USERS_TRUE@LoadPlugin users
 @BUILD_PLUGIN_UUID_TRUE@LoadPlugin uuid
@@ -134,6 +140,15 @@ FQDNLookup   true
 #      NotificationExec "user:group" "/path/to/exec"
 #</Plugin>
 
+#<Plugin filecount>
+#      <Directory "/path/to/dir">
+#              Instance "foodir"
+#              Name "*.conf"
+#              MTime "-5m"
+#              Size "+10k"
+#      </Directory>
+#</Plugin>
+
 @BUILD_PLUGIN_HDDTEMP_TRUE@<Plugin hddtemp>
 #      Host "127.0.0.1"
 #      Port "7634"
@@ -209,6 +224,24 @@ FQDNLookup   true
 #      CACert "/etc/ssl/ca.crt"
 #</Plugin>
 
+#<Plugin notify_desktop>
+#      OkayTimeout 1000
+#      WarningTimeout 5000
+#      FailureTimeout 0
+#</Plugin>
+
+#<Plugin notify_email>
+#       SMTPServer "localhost"
+#      SMTPPort 25
+#      SMTPUser "my-username"
+#      SMTPPassword "my-password"
+#      From "collectd@main0server.com"
+#      # <WARNING/FAILURE/OK> on <hostname>. beware! do not use not more than two %s in this string!!!
+#      Subject "Aaaaaa!! %s on %s!!!!!"
+#      Recipient "email1@domain1.net"
+#      Recipient "email2@domain2.com"
+#</Plugin>
+
 #<Plugin ntpd>
 #      Host "localhost"
 #      Port 123
@@ -219,11 +252,22 @@ FQDNLookup   true
 #      UPS "upsname@hostname:port"
 #</Plugin>
 
+#<Plugin onewire>
+#      Device "-s localhost:4304"
+#      Sensor "F10FCA000800"
+#      IgnoreSelected false
+#</Plugin>
+
 #<Plugin perl>
 #      IncludeDir "/my/include/path"
 #      BaseName "Collectd::Plugin"
 #      EnableDebugger ""
 #      LoadPlugin foo
+#
+#      <Plugin foo>
+#              Foo "Bar"
+#              Qux "Baz"
+#      </Plugin>
 #</Plugin>
 
 #<Plugin ping>
@@ -231,6 +275,31 @@ FQDNLookup   true
 #      TTL 255
 #</Plugin>
 
+#<Plugin postgresql>
+#      <Query magic>
+#              Query "SELECT magic, spells FROM wizard WHERE host = $1;"
+#              Param hostname
+#              Column gauge magic
+#              Column counter spells
+#      </Query>
+#
+#      <Database foo>
+#              Host "hostname"
+#              Port 5432
+#              User "username"
+#              Password "secret"
+#
+#              SSLMode "prefer"
+#              KRBSrvName "kerberos_service_name"
+#
+#              Query magic
+#      </Database>
+#
+#      <Database bar>
+#              Service "service_name"
+#      </Database>
+#</Plugin>
+
 #<Plugin powerdns>
 #  <Server "server_name">
 #    Collect "latency"
@@ -334,6 +403,12 @@ FQDNLookup   true
 #      Server "8767"
 #</Plugin>
 
+#<Plugin thermal>
+#      ForceUseProcfs false
+#      Device "THRM"
+#      IgnoreSelected false
+#</Plugin>
+
 #<Plugin unixsock>
 #      SocketFile "@prefix@/var/run/@PACKAGE_NAME@-unixsock"
 #      SocketGroup "collectd"
index d50f7ce..7ca8506 100644 (file)
@@ -30,7 +30,11 @@ section-start or -end. Empty lines and everything after the hash-symbol `#' is
 ignored. Values are either string, enclosed in double-quotes,
 (floating-point-)numbers or a boolean expression, i.E<nbsp>e. either B<true> or
 B<false>. String containing of only alphanumeric characters and underscores do
-not need to be quoted.
+not need to be quoted. Lines may be wrapped by using `\' as the last character
+before the newline. This allows long lines to be split into multiple lines.
+Quoted strings may be wrapped as well. However, those are treated special in
+that whitespace at the beginning of the following lines will be ignored, which
+allows for nicely indenting the wrapped lines.
 
 The configuration is read and processed in order, i.E<nbsp>e. from top to
 bottom. So the plugins are loaded in the order listed in this config file. It
@@ -232,6 +236,19 @@ Optional user name needed for authentication.
 
 Optional password needed for authentication.
 
+=item B<VerifyPeer> B<true|false>
+
+Enable or disable peer SSL certificate verification. See
+L<http://curl.haxx.se/docs/sslcerts.html> for details. Enabled by default.
+
+=item B<VerifyHost> B<true|false>
+
+Enable or disable peer host name verification. If enabled, the plugin checks
+if the C<Common Name> or a C<Subject Alternate Name> field of the SSL
+certificate matches the host name provided by the B<URL> option. If this
+identity check fails, the connection is aborted. Obviously, only works when
+connecting to a SSL enabled server. Enabled by default.
+
 =item B<CACert> I<File>
 
 File that holds one or more SSL certificates. If you want to use HTTPS you will
@@ -403,6 +420,79 @@ expected from them. This is documented in great detail in L<collectd-exec(5)>.
 
 =back
 
+=head2 Plugin C<filecount>
+
+The C<filecount> plugin counts the number of files in a certain directory (and
+its subdirectories) and their combined size. The configuration is very straight
+forward:
+
+  <Plugin "filecount">
+    <Directory "/var/qmail/queue/mess">
+      Instance "qmail-message"
+    </Directory>
+    <Directory "/var/qmail/queue/todo">
+      Instance "qmail-todo"
+    </Directory>
+    <Directory "/var/lib/php5">
+      Instance "php5-sessions"
+      Name "sess_*"
+    </Directory>
+  </Plugin>
+
+The example above counts the number of files in QMail's queue directories and
+the number of PHP5 sessions. Jfiy: The "todo" queue holds the messages that
+QMail has not yet looked at, the "message" queue holds the messages that were
+classified into "local" and "remote".
+
+As you can see, the configuration consists of one or more C<Directory> blocks,
+each of which specifies a directory in which to count the files. Within those
+blocks, the following options are recognized:
+
+=over 4
+
+=item B<Instance> I<Instance>
+
+Sets the plugin instance to I<Instance>. That instance name must be unique, but
+it's your responsibility, the plugin doesn't check for that. If not given, the
+instance is set to the directory name with all slashes replaced by underscores
+and all leading underscores removed.
+
+=item B<Name> I<Pattern>
+
+Only count files that match I<Pattern>, where I<Pattern> is a shell-like
+wildcard as understood by L<fnmatch(3)>. Only the B<filename> is checked
+against the pattern, not the entire path. In case this makes it easier for you:
+This option has been named after the B<-name> parameter to L<find(1)>.
+
+=item B<MTime> I<Age>
+
+Count only files of a specific age: If I<Age> is greater than zero, only files
+that haven't been touched in the last I<Age> seconds are counted. If I<Age> is
+a negative number, this is inversed. For example, if B<-60> is specified, only
+files that have been modified in the last minute will be counted.
+
+The number can also be followed by a "multiplier" to easily specify a larger
+timespan. When given in this notation, the argument must in quoted, i.E<nbsp>e.
+must be passed as string. So the B<-60> could also be written as B<"-1m"> (one
+minute). Valid multipliers are C<s> (second), C<m> (minute), C<h> (hour), C<d>
+(day), C<w> (week), and C<y> (year). There is no "month" multiplier. You can
+also specify fractional numbers, e.E<nbsp>g. B<"0.5d"> is identical to
+B<"12h">.
+
+=item B<Size> I<Size>
+
+Count only files of a specific size. When I<Size> is a positive number, only
+files that are at least this big are counted. If I<Size> is a negative number,
+this is inversed, i.E<nbsp>e. only files smaller than the absolute value of
+I<Size> are counted.
+
+As with the B<MTime> option, a "multiplier" may be added. For a detailed
+description see above. Valid multipliers here are C<b> (byte), C<k> (kilobyte),
+C<m> (megabyte), C<g> (gigabyte), C<t> (terabyte), and C<p> (petabyte). Please
+note that there are 1000 bytes in a kilobyte, not 1024.
+
+=back
+
 =head2 Plugin C<hddtemp>
 
 To get values from B<hddtemp> collectd connects to B<localhost> (127.0.0.1),
@@ -450,7 +540,7 @@ similar interfaces. Thus, you can use the B<Interface>-option to pick the
 interfaces you're interested in. Sometimes, however, it's easier/preferred
 to collect all interfaces I<except> a few ones. This option enables you to
 do that: By setting B<IgnoreSelected> to I<true> the effect of
-B<Interface> is inversed: All selected interfaces are ignored and all
+B<Interface> is inverted: All selected interfaces are ignored and all
 other interfaces are collected.
 
 =back
@@ -471,6 +561,20 @@ This option enables you to do that: By setting B<IgnoreSelected> to I<true>
 the effect of B<Sensor> is inverted: All selected sensors are ignored and
 all other sensors are collected.
 
+=item B<NotifySensorAdd> I<true>|I<false>
+
+If a sensor appears after initialization time of a minute a notification
+is sent.
+
+=item B<NotifySensorRemove> I<true>|I<false>
+
+If a sensor disappears a notification is sent.
+
+=item B<NotifySensorNotPresent> I<true>|I<false>
+
+If you have for example dual power supply and one of them is (un)plugged then
+a notification is sent.
+
 =back
 
 =head2 Plugin C<iptables>
@@ -508,7 +612,7 @@ irqs. This may not be practical, especially if no interrupts happen. Thus, you
 can use the B<Irq>-option to pick the interrupt you're interested in.
 Sometimes, however, it's easier/preferred to collect all interrupts I<except> a
 few ones. This option enables you to do that: By setting B<IgnoreSelected> to
-I<true> the effect of B<Irq> is inversed: All selected interrupts are ignored
+I<true> the effect of B<Irq> is inverted: All selected interrupts are ignored
 and all other interrupts are collected.
 
 =back
@@ -769,7 +873,7 @@ Here are some examples to help you understand the above text more easily:
 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
+B<IgnoreSelected> to B<true>, this behavior is inverted, i.E<nbsp>e. the
 specified statistics will not be collected.
 
 =back
@@ -877,6 +981,32 @@ and are checked by default depends on the distribution you use.
 
 =back
 
+=head2 Plugin C<notify_desktop>
+
+This plugin sends a desktop notification to a notification daemon, as defined
+in the Desktop Notification Specification. To actually display the
+notifications, B<notification-daemon> is required and B<collectd> has to be
+able to access the X server.
+
+The Desktop Notification Specification can be found at
+L<http://www.galago-project.org/specs/notification/>.
+
+=over 4
+
+=item B<OkayTimeout> I<timeout>
+
+=item B<WarningTimeout> I<timeout>
+
+=item B<FailureTimeout> I<timeout>
+
+Set the I<timeout>, in milliseconds, after which to expire the notification
+for C<OKAY>, C<WARNING> and C<FAILURE> severities respectively. If zero has
+been specified, the displayed notification will not be closed at all - the
+user has to do so herself. These options default to 5000. If a negative number
+has been specified, the default is used as well.
+
+=back
+
 =head2 Plugin C<ntpd>
 
 =over 4
@@ -909,6 +1039,68 @@ L<upsc(8)>.
 
 =back
 
+=head2 Plugin C<onewire>
+
+B<EXPERIMENTAL!> See notes below.
+
+The C<onewire> plugin uses the B<owcapi> library from the B<owfs> project
+L<http://owfs.org/> to read sensors connected via the onewire bus.
+
+Currently only temperature sensors (sensors with the family code C<10>,
+e.E<nbsp>g. DS1820, DS18S20, DS1920) can be read. If you have other sensors you
+would like to have included, please send a sort request to the mailing list.
+
+Hubs (the DS2409 chips) are working, but read the note, why this plugin is
+experimental, below.
+
+=over 4
+
+=item B<Device> I<Device>
+
+Sets the device to read the values from. This can either be a "real" hardware
+device, such as a serial port or an USB port, or the address of the
+L<owserver(1)> socket, usually B<localhost:4304>.
+
+Though the documentation claims to automatically recognize the given address
+format, with versionE<nbsp>2.7p4 we had to specify the type explicitly. So
+with that version, the following configuration worked for us:
+
+  <Plugin onewire>
+    Device "-s localhost:4304"
+  </Plugin>
+
+This directive is B<required> and does not have a default value.
+
+=item B<Sensor> I<Sensor>
+
+Selects sensors to collect or to ignore, depending on B<IgnoreSelected>, see
+below. Sensors are specified without the family byte at the beginning, to you'd
+use C<F10FCA000800>, and B<not> include the leading C<10.> family byte and
+point.
+
+=item B<IgnoreSelected> I<true>|I<false>
+
+If no configuration if given, the B<onewire> plugin will collect data from all
+sensors found. This may not be practical, especially if sensors are added and
+removed regularly. Sometimes, however, it's easier/preferred to collect only
+specific sensors or all sensors I<except> a few specified ones. This option
+enables you to do that: By setting B<IgnoreSelected> to I<true> the effect of
+B<Sensor> is inverted: All selected interfaces are ignored and all other
+interfaces are collected.
+
+=back
+
+B<EXPERIMENTAL!> The C<onewire> plugin is experimental, because it doesn't yet
+work with big setups. It works with one sensor being attached to one
+controller, but as soon as you throw in a couple more senors and maybe a hub
+or two, reading all values will take more than ten seconds (the default
+interval). We will probably add some separate thread for reading the sensors
+and some cache or something like that, but it's not done yet. We will try to
+maintain backwards compatibility in the future, but we can't probmise. So in
+short: If it works for you: Great! But kaap in mind that the config I<might>
+change, though this is unlikely. Oh, and if you want to help improving this
+plugin, just send a short notice to the mailing list. ThanksE<nbsp>:)
+
 =head2 Plugin C<perl>
 
 This plugin embeds a Perl-interpreter into collectd and provides an interface
@@ -929,6 +1121,241 @@ Sets the Time-To-Live of generated ICMP packets.
 
 =back
 
+=head2 Plugin C<postgresql>
+
+The C<postgresql> plugin queries statistics from PostgreSQL databases. It
+keeps a persistent connection to all configured databases and tries to
+reconnect if the connection has been interrupted. A database is configured by
+specifying a B<Database> block as described below. The default statistics are
+collected from PostgreSQL's B<statistics collector> which thus has to be
+enabled for this plugin to work correctly. This should usually be the case by
+default. See the section "The Statistics Collector" of the B<PostgreSQL
+Documentation> for details.
+
+By specifying custom database queries using a B<Query> block as described
+below, you may collect any data that is available from some PostgreSQL
+database. This way, you are able to access statistics of external daemons
+which are available in a PostgreSQL database or use future or special
+statistics provided by PostgreSQL without the need to upgrade your collectd
+installation.
+
+The B<PostgreSQL Documentation> manual can be found at
+L<http://www.postgresql.org/docs/manuals/>.
+
+  <Plugin postgresql>
+    <Query magic>
+      Query "SELECT magic, spells FROM wizard WHERE host = $1;"
+      Param hostname
+      Column gauge magic
+      Column counter spells
+    </Query>
+
+    <Database foo>
+      Host "hostname"
+      Port "5432"
+      User "username"
+      Password "secret"
+      SSLMode "prefer"
+      KRBSrvName "kerberos_service_name"
+      Query magic
+    </Database>
+    <Database bar>
+      Service "service_name"
+    </Database>
+  </Plugin>
+
+The B<Query> block defines one database query which may later be used by a
+database definition. It accepts a single mandatory argument which specifies
+the name of the query. The names of all queries have to be unique. The
+following configuration options are available to define the query:
+
+=over 4
+
+=item B<Query> I<sql query>
+
+Specify the I<sql query> which the plugin should execute. The string may
+contain the tokens B<$1>, B<$2>, etc. which are used to reference the first,
+second, etc. parameter. The value of the parameters is specified by the
+B<Param> configuration option - see below for details. To include a literal
+B<$> character followed by a number, surround it with single quotes (B<'>).
+
+Any SQL command which may return data (such as C<SELECT> or C<SHOW>) is
+allowed. Note, however, that only a single command may be used. Semicolons are
+allowed as long as a single non-empty command has been specified only.
+
+=item B<Param> I<hostname>|I<database>|I<username>
+
+Specify the parameters which should be passed to the SQL query. The parameters
+are referred to in the SQL query as B<$1>, B<$2>, etc. in the same order as
+they appear in the configuration file. The value of the parameter is
+determined depending on the value of the B<Param> option as follows:
+
+=over 4
+
+=item I<hostname>
+
+The configured hostname of the database connection. If a UNIX domain socket is
+used, the parameter expands to "localhost".
+
+=item I<database>
+
+The name of the database of the current connection.
+
+=item I<username>
+
+The username used to connect to the database.
+
+=back
+
+Please note that parameters are only supported by PostgreSQL's protocol
+version 3 and above which was introduced in version 7.4 of PostgreSQL.
+
+=item B<Column> I<type> [I<type instance>]
+
+Specify the I<type> and optional I<type instance> used to dispatch the value
+of each result column. Detailed information about types and their
+configuration can be found in L<types.db(5)>. The number and order of the
+B<Column> options has to match the columns of the query result.
+
+=item B<MinPGVersion> I<version>
+
+=item B<MaxPGVersion> I<version>
+
+Specify the minimum or maximum version of PostgreSQL that this query should be
+used with. Some statistics might only be available with certain versions of
+PostgreSQL. This allows you to specify multiple queries with the same name but
+which apply to different versions, thus allowing you to use the same
+configuration in a heterogeneous environment.
+
+The I<version> has to be specified as the concatenation of the major, minor
+and patch-level versions, each represented as two-decimal-digit numbers. For
+example, version 8.2.3 will become 80203.
+
+=back
+
+The following predefined queries are available (the definitions can be found
+in the F<postgresql_default.conf> file which, by default, is available at
+C<I<prefix>/share/collectd/>):
+
+=over 4
+
+=item B<backends>
+
+This query collects the number of backends, i.E<nbsp>e. the number of
+connected clients.
+
+=item B<transactions>
+
+This query collects the numbers of committed and rolled-back transactions of
+the user tables.
+
+=item B<queries>
+
+This query collects the numbers of various table modifications (i.E<nbsp>e.
+insertions, updates, deletions) of the user tables.
+
+=item B<query_plans>
+
+This query collects the numbers of various table scans and returned tuples of
+the user tables.
+
+=item B<table_states>
+
+This query collects the numbers of live and dead rows in the user tables.
+
+=item B<disk_io>
+
+This query collects disk block access counts for user tables.
+
+=item B<disk_usage>
+
+This query collects the on-disk size of the database in bytes.
+
+=back
+
+The B<Database> block defines one PostgreSQL database for which to collect
+statistics. It accepts a single mandatory argument which specifies the
+database name. None of the other options are required. PostgreSQL will use
+default values as documented in the section "CONNECTING TO A DATABASE" in the
+L<psql(1)> manpage. However, be aware that those defaults may be influenced by
+the user collectd is run as and special environment variables. See the manpage
+for details.
+
+=over 4
+
+=item B<Host> I<hostname>
+
+Specify the hostname or IP of the PostgreSQL server to connect to. If the
+value begins with a slash, it is interpreted as the directory name in which to
+look for the UNIX domain socket.
+
+This option is also used to determine the hostname that is associated with a
+collected data set. If it has been omitted or either begins with with a slash
+or equals B<localhost> it will be replaced with the global hostname definition
+of collectd. Any other value will be passed literally to collectd when
+dispatching values. Also see the global B<Hostname> and B<FQDNLookup> options.
+
+=item B<Port> I<port>
+
+Specify the TCP port or the local UNIX domain socket file extension of the
+server.
+
+=item B<User> I<username>
+
+Specify the username to be used when connecting to the server.
+
+=item B<Password> I<password>
+
+Specify the password to be used when connecting to the server.
+
+=item B<SSLMode> I<disable>|I<allow>|I<prefer>|I<require>
+
+Specify whether to use an SSL connection when contacting the server. The
+following modes are supported:
+
+=over 4
+
+=item I<disable>
+
+Do not use SSL at all.
+
+=item I<allow>
+
+First, try to connect without using SSL. If that fails, try using SSL.
+
+=item I<prefer> (default)
+
+First, try to connect using SSL. If that fails, try without using SSL.
+
+=item I<require>
+
+Use SSL only.
+
+=back
+
+=item B<KRBSrvName> I<kerberos_service_name>
+
+Specify the Kerberos service name to use when authenticating with Kerberos 5
+or GSSAPI. See the sections "Kerberos authentication" and "GSSAPI" of the
+B<PostgreSQL Documentation> for details.
+
+=item B<Service> I<service_name>
+
+Specify the PostgreSQL service name to use for additional parameters. That
+service has to be defined in F<pg_service.conf> and holds additional
+connection parameters. See the section "The Connection Service File" in the
+B<PostgreSQL Documentation> for details.
+
+=item B<Query> I<query>
+
+Specify a I<query> which should be executed for the database connection. This
+may be any of the predefined or user-defined queries. If no such option is
+given, it defaults to "backends", "transactions", "queries", "query_plans",
+"table_states", "disk_io" and "disk_usage". Else, the specified queries are
+used only.
+
+=back
+
 =head2 Plugin C<powerdns>
 
 The C<powerdns> plugin queries statistics from an authoritative PowerDNS
@@ -1133,7 +1560,7 @@ Set the "XFiles Factor". The default is 0.1. If unsure, don't set this option.
 
 =item B<CacheFlush> I<Seconds>
 
-When the C<rrdtool plugin> uses a cache (by setting B<CacheTimeout>, see below)
+When the C<rrdtool> plugin uses a cache (by setting B<CacheTimeout>, see below)
 it writes all values for a certain RRD-file if the oldest value is older than
 (or equal to) the number of seconds specified. If some RRD-file is not updated
 anymore for some reason (the computer was shut down, the network is broken,
@@ -1152,6 +1579,30 @@ reduces IO-operations and thus lessens the load produced by updating the files.
 The trade off is that the graphs kind of "drag behind" and that more memory is
 used.
 
+=item B<WritesPerSecond> B<Updates>
+
+When collecting many statistics with collectd and the C<rrdtool> plugin, you
+will run serious performance problems. The B<CacheFlush> setting and the
+internal update queue assert that collectd continues to work just fine even
+under heavy load, but the system may become very unresponsive and slow. This is
+a problem especially if you create graphs from the RRD files on the same
+machine, for example using the C<graph.cgi> script included in the
+C<contrib/collection3/> directory.
+
+This setting is designed for very large setups. Setting this option to a value
+between 25 and 80 updates per second, depending on your hardware, will leave
+the server responsive enough to draw graphs even while all the cached values
+are written to disk. Flushed values, i.E<nbsp>e. values that are forced to disk
+by the B<FLUSH> command, are B<not> effected by this limit. They are still
+written as fast as possible, so that web frontends have up to date data when
+generating graphs.
+
+For example: If you have 100,000 RRD files and set B<WritesPerSecond> to 30
+updates per second, writing all values to disk will take approximately
+56E<nbsp>minutes. Together with the flushing ability that's integrated into
+"collection3" you'll end up with a responsive and fast system, up to date
+graphs and basically a "backup" of your values every hour.
+
 =back
 
 =head2 Plugin C<sensors>
@@ -1180,7 +1631,7 @@ sensors. This may not be practical, especially for uninteresting sensors.
 Thus, you can use the B<Sensor>-option to pick the sensors you're interested
 in. Sometimes, however, it's easier/preferred to collect all sensors I<except> a
 few ones. This option enables you to do that: By setting B<IgnoreSelected> to
-I<true> the effect of B<Sensor> is inversed: All selected sensors are ignored
+I<true> the effect of B<Sensor> is inverted: All selected sensors are ignored
 and all other sensors are collected.
 
 =back
@@ -1383,6 +1834,32 @@ port in numeric form.
 
 =back
 
+=head2 Plugin C<thermal>
+
+=over 4
+
+=item B<ForceUseProcfs> I<true>|I<false>
+
+By default, the C<thermal> plugin tries to read the statistics from the Linux
+C<sysfs> interface. If that is not available, the plugin falls back to the
+C<procfs> interface. By setting this option to I<true>, you can force the
+plugin to use the latter. This option defaults to I<false>.
+
+=item B<Device> I<Device>
+
+Selects the name of the thermal device that you want to collect or ignore,
+depending on the value of the B<IgnoreSelected> option. This option may be
+used multiple times to specify a list of devices.
+
+=item B<IgnoreSelected> I<true>|I<false>
+
+Invert the selection: If set to true, all devices B<except> the ones that
+match the device names specified by the B<Device> option are collected. By
+default only selected devices are collected if a selection is made. If no
+selection is configured at all, B<all> devices are selected.
+
+=back
+
 =head2 Plugin C<unixsock>
 
 =over 4
@@ -1610,6 +2087,7 @@ L<types.db(5)>,
 L<hddtemp(8)>,
 L<kstat(3KSTAT)>,
 L<mbmon(1)>,
+L<psql(1)>,
 L<rrdtool(1)>,
 L<sensors(1)>
 
index 895413a..6fed900 100644 (file)
@@ -56,6 +56,9 @@
 #if HAVE_STDINT_H
 # include <stdint.h>
 #endif
+#if HAVE_STDBOOL_H
+# include <stdbool.h>
+#endif
 #if HAVE_UNISTD_H
 # include <unistd.h>
 #endif
 #define PLUGINDIR PREFIX "/lib/" PACKAGE_NAME
 #endif
 
+#ifndef PKGDATADIR
+#define PKGDATADIR PREFIX "/share/" PACKAGE_NAME
+#endif
+
 #ifndef COLLECTD_GRP_NAME
 # define COLLECTD_GRP_NAME "collectd"
 #endif
index 8dbf976..119d284 100644 (file)
@@ -61,6 +61,19 @@ char *sstrncpy (char *dest, const char *src, size_t n)
        return (dest);
 } /* char *sstrncpy */
 
+int ssnprintf (char *dest, size_t n, const char *format, ...)
+{
+       int ret = 0;
+       va_list ap;
+
+       va_start (ap, format);
+       ret = vsnprintf (dest, n, format, ap);
+       dest[n - 1] = '\0';
+       va_end (ap);
+
+       return (ret);
+} /* int ssnprintf */
+
 char *sstrdup (const char *s)
 {
        char *r;
@@ -91,7 +104,7 @@ char *sstrerror (int errnum, char *buf, size_t buflen)
                pthread_mutex_lock (&strerror_r_lock);
 
                temp = strerror (errnum);
-               strncpy (buf, temp, buflen);
+               sstrncpy (buf, temp, buflen);
 
                pthread_mutex_unlock (&strerror_r_lock);
        }
@@ -104,9 +117,9 @@ char *sstrerror (int errnum, char *buf, size_t buflen)
                if (buf[0] == '\0')
                {
                        if ((temp != NULL) && (temp != buf) && (temp[0] != '\0'))
-                               strncpy (buf, temp, buflen);
+                               sstrncpy (buf, temp, buflen);
                        else
-                               strncpy (buf, "strerror_r did not return "
+                               sstrncpy (buf, "strerror_r did not return "
                                                "an error message", buflen);
                }
        }
@@ -115,13 +128,12 @@ char *sstrerror (int errnum, char *buf, size_t buflen)
 #else
        if (strerror_r (errnum, buf, buflen) != 0)
        {
-               snprintf (buf, buflen, "Error #%i; "
+               ssnprintf (buf, buflen, "Error #%i; "
                                "Additionally, strerror_r failed.",
                                errnum);
        }
 #endif /* STRERROR_R_CHAR_P */
 
-       buf[buflen - 1] = '\0';
        return (buf);
 } /* char *sstrerror */
 
@@ -376,7 +388,7 @@ int check_create_dir (const char *file_orig)
 
        if ((len = strlen (file_orig)) < 1)
                return (-1);
-       else if (len >= 512)
+       else if (len >= sizeof (file_copy))
                return (-1);
 
        /*
@@ -391,8 +403,7 @@ int check_create_dir (const char *file_orig)
        /*
         * Create a copy for `strtok_r' to destroy
         */
-       strncpy (file_copy, file_orig, 512);
-       file_copy[511] = '\0';
+       sstrncpy (file_copy, file_orig, sizeof (file_copy));
 
        /*
         * Break into components. This will eat up several slashes in a row and
@@ -477,8 +488,7 @@ int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
        if (kc == NULL)
                return (-1);
 
-       snprintf (ident, 128, "%s,%i,%s", module, instance, name);
-       ident[127] = '\0';
+       ssnprintf (ident, sizeof (ident), "%s,%i,%s", module, instance, name);
 
        if (*ksp_ptr == NULL)
        {
@@ -663,21 +673,21 @@ int format_name (char *ret, int ret_len,
        if ((plugin_instance == NULL) || (strlen (plugin_instance) == 0))
        {
                if ((type_instance == NULL) || (strlen (type_instance) == 0))
-                       status = snprintf (ret, ret_len, "%s/%s/%s",
+                       status = ssnprintf (ret, ret_len, "%s/%s/%s",
                                        hostname, plugin, type);
                else
-                       status = snprintf (ret, ret_len, "%s/%s/%s-%s",
+                       status = ssnprintf (ret, ret_len, "%s/%s/%s-%s",
                                        hostname, plugin, type,
                                        type_instance);
        }
        else
        {
                if ((type_instance == NULL) || (strlen (type_instance) == 0))
-                       status = snprintf (ret, ret_len, "%s/%s-%s/%s",
+                       status = ssnprintf (ret, ret_len, "%s/%s-%s/%s",
                                        hostname, plugin, plugin_instance,
                                        type);
                else
-                       status = snprintf (ret, ret_len, "%s/%s-%s/%s-%s",
+                       status = ssnprintf (ret, ret_len, "%s/%s-%s/%s-%s",
                                        hostname, plugin, plugin_instance,
                                        type, type_instance);
        }
@@ -838,26 +848,75 @@ int notification_init (notification_t *n, int severity, const char *message,
        n->severity = severity;
 
        if (message != NULL)
-               strncpy (n->message, message, sizeof (n->message));
+               sstrncpy (n->message, message, sizeof (n->message));
        if (host != NULL)
-               strncpy (n->host, host, sizeof (n->host));
+               sstrncpy (n->host, host, sizeof (n->host));
        if (plugin != NULL)
-               strncpy (n->plugin, plugin, sizeof (n->plugin));
+               sstrncpy (n->plugin, plugin, sizeof (n->plugin));
        if (plugin_instance != NULL)
-               strncpy (n->plugin_instance, plugin_instance,
+               sstrncpy (n->plugin_instance, plugin_instance,
                                sizeof (n->plugin_instance));
        if (type != NULL)
-               strncpy (n->type, type, sizeof (n->type));
+               sstrncpy (n->type, type, sizeof (n->type));
        if (type_instance != NULL)
-               strncpy (n->type_instance, type_instance,
+               sstrncpy (n->type_instance, type_instance,
                                sizeof (n->type_instance));
 
-       n->message[sizeof (n->message) - 1] = '\0';
-       n->host[sizeof (n->host) - 1] = '\0';
-       n->plugin[sizeof (n->plugin) - 1] = '\0';
-       n->plugin_instance[sizeof (n->plugin_instance) - 1] = '\0';
-       n->type[sizeof (n->type) - 1] = '\0';
-       n->type_instance[sizeof (n->type_instance) - 1] = '\0';
-
        return (0);
 } /* int notification_init */
+
+int walk_directory (const char *dir, dirwalk_callback_f callback,
+               void *user_data)
+{
+       struct dirent *ent;
+       DIR *dh;
+       int success;
+       int failure;
+
+       success = 0;
+       failure = 0;
+
+       if ((dh = opendir (dir)) == NULL)
+       {
+               char errbuf[1024];
+               ERROR ("walk_directory: Cannot open '%s': %s", dir,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return -1;
+       }
+
+       while ((ent = readdir (dh)) != NULL)
+       {
+               int status;
+
+               if (ent->d_name[0] == '.')
+                       continue;
+
+               status = (*callback) (dir, ent->d_name, user_data);
+               if (status != 0)
+                       failure++;
+               else
+                       success++;
+       }
+
+       closedir (dh);
+
+       if ((success == 0) && (failure > 0))
+               return (-1);
+       return (0);
+}
+
+int read_file_contents (const char *filename, char *buf, int bufsize)
+{
+       FILE *fh;
+       int n;
+
+       if ((fh = fopen (filename, "r")) == NULL)
+               return -1;
+
+       n = fread(buf, 1, bufsize, fh);
+       fclose(fh);
+
+       return n;
+}
+
+
index 9e7e4aa..f463b77 100644 (file)
@@ -41,6 +41,7 @@
 #define STATIC_ARRAY_SIZE(a) (sizeof (a) / sizeof (*(a)))
 
 char *sstrncpy (char *dest, const char *src, size_t n);
+int ssnprintf (char *dest, size_t n, const char *format, ...);
 char *sstrdup(const char *s);
 void *smalloc(size_t size);
 char *sstrerror (int errnum, char *buf, size_t buflen);
@@ -201,4 +202,11 @@ int notification_init (notification_t *n, int severity, const char *message,
        notification_init (n, NOTIF_FAILURE, NULL, \
                        (vl)->host, (vl)->plugin, (vl)->plugin_instance, \
                        (ds)->type, (vl)->type_instance)
+
+typedef int (*dirwalk_callback_f)(const char *dirname, const char *filename,
+               void *user_data);
+int walk_directory (const char *dir, dirwalk_callback_f callback,
+               void *user_data);
+int read_file_contents (const char *filename, char *buf, int bufsize);
+
 #endif /* COMMON_H */
index 00009db..bb57ca2 100644 (file)
@@ -155,7 +155,8 @@ static int cf_dispatch (const char *type, const char *orig_key,
 
        for (i = 0; i < cf_cb->keys_num; i++)
        {
-               if (strcasecmp (cf_cb->keys[i], key) == 0)
+               if ((cf_cb->keys[i] != NULL)
+                               && (strcasecmp (cf_cb->keys[i], key) == 0))
                {
                        ret = (*cf_cb->callback) (key, value);
                        break;
@@ -182,8 +183,7 @@ static int dispatch_global_option (const oconfig_item_t *ci)
        else if (ci->values[0].type == OCONFIG_TYPE_NUMBER)
        {
                char tmp[128];
-               snprintf (tmp, sizeof (tmp), "%lf", ci->values[0].value.number);
-               tmp[127] = '\0';
+               ssnprintf (tmp, sizeof (tmp), "%lf", ci->values[0].value.number);
                return (global_option_set (ci->key, tmp));
        }
        else if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN)
@@ -258,13 +258,13 @@ static int dispatch_value_plugin (const char *plugin, oconfig_item_t *ci)
                int status = -1;
 
                if (ci->values[i].type == OCONFIG_TYPE_STRING)
-                       status = snprintf (buffer_ptr, buffer_free, " %s",
+                       status = ssnprintf (buffer_ptr, buffer_free, " %s",
                                        ci->values[i].value.string);
                else if (ci->values[i].type == OCONFIG_TYPE_NUMBER)
-                       status = snprintf (buffer_ptr, buffer_free, " %lf",
+                       status = ssnprintf (buffer_ptr, buffer_free, " %lf",
                                        ci->values[i].value.number);
                else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN)
-                       status = snprintf (buffer_ptr, buffer_free, " %s",
+                       status = ssnprintf (buffer_ptr, buffer_free, " %s",
                                        ci->values[i].value.boolean
                                        ? "true" : "false");
 
@@ -548,7 +548,7 @@ static oconfig_item_t *cf_read_dir (const char *dir, int depth)
                if ((de->d_name[0] == '.') || (de->d_name[0] == '\0'))
                        continue;
 
-               status = snprintf (name, sizeof (name), "%s/%s",
+               status = ssnprintf (name, sizeof (name), "%s/%s",
                                dir, de->d_name);
                if (status >= sizeof (name))
                {
index 0fadc06..e9ab783 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -182,12 +182,12 @@ static void submit (int cpu_num, const char *type_instance, counter_t value)
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "cpu", sizeof (vl.plugin));
-       snprintf (vl.plugin_instance, sizeof (vl.type_instance),
+       ssnprintf (vl.plugin_instance, sizeof (vl.type_instance),
                        "%i", cpu_num);
-       vl.plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
+       sstrncpy (vl.type, "cpu", sizeof (vl.type));
        sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       plugin_dispatch_values ("cpu", &vl);
+       plugin_dispatch_values (&vl);
 }
 
 static int cpu_read (void)
index 74e542b..3738b54 100644 (file)
@@ -37,7 +37,7 @@ static int cpufreq_init (void)
 
        while (1)
        {
-               status = snprintf (filename, sizeof (filename),
+               status = ssnprintf (filename, sizeof (filename),
                                "/sys/devices/system/cpu/cpu%d/cpufreq/"
                                "scaling_cur_freq", num_cpu);
                if ((status < 1) || ((unsigned int)status >= sizeof (filename)))
@@ -70,10 +70,11 @@ static void cpufreq_submit (int cpu_num, double value)
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "cpufreq", sizeof (vl.plugin));
-       snprintf (vl.type_instance, sizeof (vl.type_instance),
+       sstrncpy (vl.type, "cpufreq", sizeof (vl.type));
+       ssnprintf (vl.type_instance, sizeof (vl.type_instance),
                        "%i", cpu_num);
 
-       plugin_dispatch_values ("cpufreq", &vl);
+       plugin_dispatch_values (&vl);
 }
 
 static int cpufreq_read (void)
@@ -87,7 +88,7 @@ static int cpufreq_read (void)
 
        for (i = 0; i < num_cpu; i++)
        {
-               status = snprintf (filename, sizeof (filename),
+               status = ssnprintf (filename, sizeof (filename),
                                "/sys/devices/system/cpu/cpu%d/cpufreq/"
                                "scaling_cur_freq", i);
                if ((status < 1) || ((unsigned int)status >= sizeof (filename)))
index ff59f91..a94b700 100644 (file)
--- a/src/csv.c
+++ b/src/csv.c
@@ -45,9 +45,11 @@ static int value_list_to_string (char *buffer, int buffer_len,
        int i;
        gauge_t *rates = NULL;
 
+       assert (0 == strcmp (ds->type, vl->type));
+
        memset (buffer, '\0', buffer_len);
 
-       status = snprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+       status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
        if ((status < 1) || (status >= buffer_len))
                return (-1);
        offset = status;
@@ -62,7 +64,7 @@ static int value_list_to_string (char *buffer, int buffer_len,
                {
                        if (store_rates == 0)
                        {
-                               status = snprintf (buffer + offset,
+                               status = ssnprintf (buffer + offset,
                                                buffer_len - offset,
                                                ",%llu",
                                                vl->values[i].counter);
@@ -77,14 +79,14 @@ static int value_list_to_string (char *buffer, int buffer_len,
                                                        "uc_get_rate failed.");
                                        return (-1);
                                }
-                               status = snprintf (buffer + offset,
+                               status = ssnprintf (buffer + offset,
                                                buffer_len - offset,
                                                ",%lf", rates[i]);
                        }
                }
                else /* if (ds->ds[i].type == DS_TYPE_GAUGE) */
                {
-                       status = snprintf (buffer + offset, buffer_len - offset,
+                       status = ssnprintf (buffer + offset, buffer_len - offset,
                                        ",%lf", vl->values[i].gauge);
                }
 
@@ -107,37 +109,39 @@ static int value_list_to_filename (char *buffer, int buffer_len,
        int offset = 0;
        int status;
 
+       assert (0 == strcmp (ds->type, vl->type));
+
        if (datadir != NULL)
        {
-               status = snprintf (buffer + offset, buffer_len - offset,
+               status = ssnprintf (buffer + offset, buffer_len - offset,
                                "%s/", datadir);
                if ((status < 1) || (status >= buffer_len - offset))
                        return (-1);
                offset += status;
        }
 
-       status = snprintf (buffer + offset, buffer_len - offset,
+       status = ssnprintf (buffer + offset, buffer_len - offset,
                        "%s/", vl->host);
        if ((status < 1) || (status >= buffer_len - offset))
                return (-1);
        offset += status;
 
        if (strlen (vl->plugin_instance) > 0)
-               status = snprintf (buffer + offset, buffer_len - offset,
+               status = ssnprintf (buffer + offset, buffer_len - offset,
                                "%s-%s/", vl->plugin, vl->plugin_instance);
        else
-               status = snprintf (buffer + offset, buffer_len - offset,
+               status = ssnprintf (buffer + offset, buffer_len - offset,
                                "%s/", vl->plugin);
        if ((status < 1) || (status >= buffer_len - offset))
                return (-1);
        offset += status;
 
        if (strlen (vl->type_instance) > 0)
-               status = snprintf (buffer + offset, buffer_len - offset,
-                               "%s-%s", ds->type, vl->type_instance);
+               status = ssnprintf (buffer + offset, buffer_len - offset,
+                               "%s-%s", vl->type, vl->type_instance);
        else
-               status = snprintf (buffer + offset, buffer_len - offset,
-                               "%s", ds->type);
+               status = ssnprintf (buffer + offset, buffer_len - offset,
+                               "%s", vl->type);
        if ((status < 1) || (status >= buffer_len - offset))
                return (-1);
        offset += status;
@@ -242,6 +246,11 @@ static int csv_write (const data_set_t *ds, const value_list_t *vl)
        struct flock fl;
        int          status;
 
+       if (0 != strcmp (ds->type, vl->type)) {
+               ERROR ("csv plugin: DS type does not match value list type");
+               return -1;
+       }
+
        if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
                return (-1);
 
index 6bd9250..26d2382 100644 (file)
--- a/src/df.c
+++ b/src/df.c
@@ -128,9 +128,10 @@ static void df_submit (char *df_name,
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "df", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
-       strncpy (vl.type_instance, df_name, sizeof (vl.type_instance));
+       sstrncpy (vl.type, "df", sizeof (vl.host));
+       sstrncpy (vl.type_instance, df_name, sizeof (vl.type_instance));
 
-       plugin_dispatch_values ("df", &vl);
+       plugin_dispatch_values (&vl);
 } /* void df_submit */
 
 static int df_read (void)
@@ -173,13 +174,13 @@ static int df_read (void)
 
                if (strcmp (mnt_ptr->dir, "/") == 0)
                {
-                       strncpy (mnt_name, "root", sizeof (mnt_name));
+                       sstrncpy (mnt_name, "root", sizeof (mnt_name));
                }
                else
                {
                        int i, len;
 
-                       strncpy (mnt_name, mnt_ptr->dir + 1, sizeof (mnt_name));
+                       sstrncpy (mnt_name, mnt_ptr->dir + 1, sizeof (mnt_name));
                        len = strlen (mnt_name);
 
                        for (i = 0; i < len; i++)
index 20afd30..29aa979 100644 (file)
@@ -215,10 +215,11 @@ static void disk_submit (const char *plugin_instance,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "disk", sizeof (vl.plugin));
-       strncpy (vl.plugin_instance, plugin_instance,
+       sstrncpy (vl.plugin_instance, plugin_instance,
                        sizeof (vl.plugin_instance));
+       sstrncpy (vl.type, type, sizeof (vl.type));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void disk_submit */
 
 #if HAVE_IOKIT_IOKITLIB_H
@@ -375,7 +376,8 @@ static int disk_read (void)
                write_tme = dict_get_value (stats_dict,
                                kIOBlockStorageDriverStatisticsTotalWriteTimeKey);
 
-               if (snprintf (disk_name, 64, "%i-%i", disk_major, disk_minor) >= 64)
+               if (ssnprintf (disk_name, sizeof (disk_name),
+                               "%i-%i", disk_major, disk_minor) >= sizeof (disk_name))
                {
                        DEBUG ("snprintf (major, minor) failed.");
                        CFRelease (child_dict);
index 69cb192..c04169f 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
@@ -301,9 +301,10 @@ static void submit_counter (const char *type, const char *type_instance,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "dns", sizeof (vl.plugin));
-       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+       sstrncpy (vl.type, type, sizeof (vl.type));
+       sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void submit_counter */
 
 static void submit_octets (counter_t queries, counter_t responses)
@@ -319,8 +320,9 @@ static void submit_octets (counter_t queries, counter_t responses)
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "dns", sizeof (vl.plugin));
+       sstrncpy (vl.type, "dns_octets", sizeof (vl.type));
 
-       plugin_dispatch_values ("dns_octets", &vl);
+       plugin_dispatch_values (&vl);
 } /* void submit_counter */
 
 static int dns_read (void)
index cc68d3f..5e103ed 100644 (file)
@@ -396,9 +396,7 @@ static void *open_connection (void *arg)
        }
 
        addr.sun_family = AF_UNIX;
-
-       strncpy (addr.sun_path, path, (size_t)(UNIX_PATH_MAX - 1));
-       addr.sun_path[UNIX_PATH_MAX - 1] = '\0';
+       sstrncpy (addr.sun_path, path, (size_t)(UNIX_PATH_MAX - 1));
 
        errno = 0;
        if (-1 == bind (connector_socket, (struct sockaddr *)&addr,
@@ -661,9 +659,10 @@ static void email_submit (const char *type, const char *type_instance, gauge_t v
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "email", sizeof (vl.plugin));
-       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+       sstrncpy (vl.type, type, sizeof (vl.type));
+       sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void email_submit */
 
 /* Copy list l1 to list l2. l2 may partly exist already, but it is assumed
index 69ce314..2e20a67 100644 (file)
@@ -41,10 +41,9 @@ static void entropy_submit (double entropy)
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "entropy", sizeof (vl.plugin));
-       sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
-       sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
+       sstrncpy (vl.type, "entropy", sizeof (vl.type));
 
-       plugin_dispatch_values ("entropy", &vl);
+       plugin_dispatch_values (&vl);
 }
 
 static int entropy_read (void)
index 07c35c9..a78f902 100644 (file)
@@ -170,10 +170,9 @@ static int exec_config_exec (oconfig_item_t *ci) /* {{{ */
   {
     char *tmp = strrchr (ci->values[1].value.string, '/');
     if (tmp == NULL)
-      strncpy (buffer, ci->values[1].value.string, sizeof (buffer));
+      sstrncpy (buffer, ci->values[1].value.string, sizeof (buffer));
     else
-      strncpy (buffer, tmp + 1, sizeof (buffer));
-    buffer[sizeof (buffer) - 1] = '\0';
+      sstrncpy (buffer, tmp + 1, sizeof (buffer));
   }
   pl->argv[0] = strdup (buffer);
   if (pl->argv[0] == NULL)
@@ -196,17 +195,16 @@ static int exec_config_exec (oconfig_item_t *ci) /* {{{ */
     {
       if (ci->values[i + 1].type == OCONFIG_TYPE_NUMBER)
       {
-       snprintf (buffer, sizeof (buffer), "%lf",
+       ssnprintf (buffer, sizeof (buffer), "%lf",
            ci->values[i + 1].value.number);
       }
       else
       {
        if (ci->values[i + 1].value.boolean)
-         strncpy (buffer, "true", sizeof (buffer));
+         sstrncpy (buffer, "true", sizeof (buffer));
        else
-         strncpy (buffer, "false", sizeof (buffer));
+         sstrncpy (buffer, "false", sizeof (buffer));
       }
-      buffer[sizeof (buffer) - 1] = '\0';
 
       pl->argv[i] = strdup (buffer);
     }
@@ -492,19 +490,19 @@ static int fork_child (program_list_t *pl, int *fd_in, int *fd_out, int *fd_err)
 
 static int parse_line (char *buffer) /* {{{ */
 {
-  char *fields[256];
-  int fields_num;
-
-  fields[0] = "PUTVAL";
-  fields_num = strsplit (buffer, fields + 1, STATIC_ARRAY_SIZE(fields) - 1);
-
-  if (strcasecmp (fields[1], "putval") == 0)
-    return (handle_putval (stdout, fields + 1, fields_num));
-  else if (strcasecmp (fields[1], "putnotif") == 0)
-    return (handle_putnotif (stdout, fields + 1, fields_num));
-
-  /* compatibility code */
-  return (handle_putval (stdout, fields, fields_num + 1));
+  if (strncasecmp ("PUTVAL", buffer, strlen ("PUTVAL")) == 0)
+    return (handle_putval (stdout, buffer));
+  else if (strncasecmp ("PUTNOTIF", buffer, strlen ("PUTNOTIF")) == 0)
+    return (handle_putnotif (stdout, buffer));
+  else
+  {
+    /* For backwards compatibility */
+    char tmp[1220];
+    /* Let's annoy the user a bit.. */
+    INFO ("exec plugin: Prepending `PUTVAL' to this line: %s", buffer);
+    ssnprintf (tmp, sizeof (tmp), "PUTVAL %s", buffer);
+    return (handle_putval (stdout, tmp));
+  }
 } /* int parse_line }}} */
 
 static void *exec_read_one (void *arg) /* {{{ */
@@ -639,7 +637,8 @@ static void *exec_read_one (void *arg) /* {{{ */
 static void *exec_notification_one (void *arg) /* {{{ */
 {
   program_list_t *pl = ((program_list_and_notification_t *) arg)->pl;
-  const notification_t *n = &((program_list_and_notification_t *) arg)->n;
+  notification_t *n = &((program_list_and_notification_t *) arg)->n;
+  notification_meta_t *meta;
   int fd;
   FILE *fh;
   int pid;
@@ -688,6 +687,21 @@ static void *exec_notification_one (void *arg) /* {{{ */
   if (strlen (n->type_instance) > 0)
     fprintf (fh, "TypeInstance: %s\n", n->type_instance);
 
+  for (meta = n->meta; meta != NULL; meta = meta->next)
+  {
+    if (meta->type == NM_TYPE_STRING)
+      fprintf (fh, "%s: %s\n", meta->name, meta->nm_value.nm_string);
+    else if (meta->type == NM_TYPE_SIGNED_INT)
+      fprintf (fh, "%s: %"PRIi64"\n", meta->name, meta->nm_value.nm_signed_int);
+    else if (meta->type == NM_TYPE_UNSIGNED_INT)
+      fprintf (fh, "%s: %"PRIu64"\n", meta->name, meta->nm_value.nm_unsigned_int);
+    else if (meta->type == NM_TYPE_DOUBLE)
+      fprintf (fh, "%s: %e\n", meta->name, meta->nm_value.nm_double);
+    else if (meta->type == NM_TYPE_BOOLEAN)
+      fprintf (fh, "%s: %s\n", meta->name,
+         meta->nm_value.nm_boolean ? "true" : "false");
+  }
+
   fprintf (fh, "\n%s\n", n->message);
 
   fflush (fh);
@@ -698,6 +712,7 @@ static void *exec_notification_one (void *arg) /* {{{ */
   DEBUG ("exec plugin: Child %i exited with status %i.",
       pid, status);
 
+  plugin_notification_meta_free (n);
   sfree (arg);
   pthread_exit ((void *) 0);
   return (NULL);
@@ -774,6 +789,11 @@ static int exec_notification (const notification_t *n)
     pln->pl = pl;
     memcpy (&pln->n, n, sizeof (notification_t));
 
+    /* Set the `meta' member to NULL, otherwise `plugin_notification_meta_copy'
+     * will run into an endless loop. */
+    pln->n.meta = NULL;
+    plugin_notification_meta_copy (&pln->n, n);
+
     pthread_attr_init (&attr);
     pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
     pthread_create (&t, &attr, exec_notification_one, (void *) pln);
diff --git a/src/filecount.c b/src/filecount.c
new file mode 100644 (file)
index 0000000..f071379
--- /dev/null
@@ -0,0 +1,546 @@
+/**
+ * collectd - src/filecount.c
+ * Copyright (C) 2008  Alessandro Iurlano
+ * Copyright (C) 2008  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:
+ *   Alessandro Iurlano <alessandro.iurlano at gmail.com>
+ *   Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"       
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <fnmatch.h>
+
+struct fc_directory_conf_s
+{
+  char *path;
+  char *instance;
+
+  /* Data counters */
+  uint64_t files_num;
+  uint64_t files_size;
+
+  /* Selectors */
+  char *name;
+  int64_t mtime;
+  int64_t size;
+
+  /* Helper for the recursive functions */
+  time_t now;
+};
+typedef struct fc_directory_conf_s fc_directory_conf_t;
+
+static fc_directory_conf_t **directories = NULL;
+static size_t directories_num = 0;
+
+static void fc_submit_dir (const fc_directory_conf_t *dir)
+{
+  value_t values[1];
+  value_list_t vl = VALUE_LIST_INIT;
+
+  values[0].gauge = (gauge_t) dir->files_num;
+
+  vl.values = values;
+  vl.values_len = STATIC_ARRAY_SIZE (values);
+  vl.time = time (NULL);
+  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+  sstrncpy (vl.plugin, "filecount", sizeof (vl.plugin));
+  sstrncpy (vl.plugin_instance, dir->instance, sizeof (vl.plugin_instance));
+  sstrncpy (vl.type, "files", sizeof (vl.type));
+
+  plugin_dispatch_values (&vl);
+
+  values[0].gauge = (gauge_t) dir->files_size;
+  sstrncpy (vl.type, "bytes", sizeof (vl.type));
+
+  plugin_dispatch_values (&vl);
+} /* void fc_submit_dir */
+
+/*
+ * Config:
+ * <Plugin filecount>
+ *   <Directory /path/to/dir>
+ *     Instance "foobar"
+ *     Name "*.conf"
+ *     MTime -3600
+ *     Size "+10M"
+ *   </Directory>
+ * </Plugin>
+ *
+ * Collect:
+ * - Number of files
+ * - Total size
+ */
+
+static int fc_config_set_instance (fc_directory_conf_t *dir, const char *str)
+{
+  char buffer[1024];
+  char *ptr;
+  char *copy;
+
+  sstrncpy (buffer, str, sizeof (buffer));
+  for (ptr = buffer; *ptr != 0; ptr++)
+    if (*ptr == '/')
+      *ptr = '_';
+
+  for (ptr = buffer; *ptr == '_'; ptr++)
+    /* do nothing */;
+
+  if (*ptr == 0)
+    return (-1);
+
+  copy = strdup (ptr);
+  if (copy == NULL)
+    return (-1);
+
+  sfree (dir->instance);
+  dir->instance = copy;
+
+  return (0);
+} /* int fc_config_set_instance */
+
+static int fc_config_add_dir_instance (fc_directory_conf_t *dir,
+    oconfig_item_t *ci)
+{
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("filecount plugin: The `Instance' config option needs exactly "
+        "one string argument.");
+    return (-1);
+  }
+
+  return (fc_config_set_instance (dir, ci->values[0].value.string));
+} /* int fc_config_add_dir_instance */
+
+static int fc_config_add_dir_name (fc_directory_conf_t *dir,
+    oconfig_item_t *ci)
+{
+  char *temp;
+
+  if ((ci->values_num != 1)
+      || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("filecount plugin: The `Name' config option needs exactly one "
+        "string argument.");
+    return (-1);
+  }
+
+  temp = strdup (ci->values[0].value.string);
+  if (temp == NULL)
+  {
+    ERROR ("filecount plugin: strdup failed.");
+    return (-1);
+  }
+
+  sfree (dir->name);
+  dir->name = temp;
+
+  return (0);
+} /* int fc_config_add_dir_name */
+
+static int fc_config_add_dir_mtime (fc_directory_conf_t *dir,
+    oconfig_item_t *ci)
+{
+  char *endptr;
+  double temp;
+
+  if ((ci->values_num != 1)
+      || ((ci->values[0].type != OCONFIG_TYPE_STRING)
+        && (ci->values[0].type != OCONFIG_TYPE_NUMBER)))
+  {
+    WARNING ("filecount plugin: The `MTime' config option needs exactly one "
+        "string or numeric argument.");
+    return (-1);
+  }
+
+  if (ci->values[0].type == OCONFIG_TYPE_NUMBER)
+  {
+    dir->mtime = (int64_t) ci->values[0].value.number;
+    return (0);
+  }
+
+  errno = 0;
+  endptr = NULL;
+  temp = strtod (ci->values[0].value.string, &endptr);
+  if ((errno != 0) || (endptr == NULL)
+      || (endptr == ci->values[0].value.string))
+  {
+    WARNING ("filecount plugin: Converting `%s' to a number failed.",
+        ci->values[0].value.string);
+    return (-1);
+  }
+
+  switch (*endptr)
+  {
+    case 0:
+    case 's':
+    case 'S':
+      break;
+
+    case 'm':
+    case 'M':
+      temp *= 60;
+      break;
+
+    case 'h':
+    case 'H':
+      temp *= 3600;
+      break;
+
+    case 'd':
+    case 'D':
+      temp *= 86400;
+      break;
+
+    case 'w':
+    case 'W':
+      temp *= 7 * 86400;
+      break;
+
+    case 'y':
+    case 'Y':
+      temp *= 31557600; /* == 365.25 * 86400 */
+      break;
+
+    default:
+      WARNING ("filecount plugin: Invalid suffix for `MTime': `%c'", *endptr);
+      return (-1);
+  } /* switch (*endptr) */
+
+  dir->mtime = (int64_t) temp;
+
+  return (0);
+} /* int fc_config_add_dir_mtime */
+
+static int fc_config_add_dir_size (fc_directory_conf_t *dir,
+    oconfig_item_t *ci)
+{
+  char *endptr;
+  double temp;
+
+  if ((ci->values_num != 1)
+      || ((ci->values[0].type != OCONFIG_TYPE_STRING)
+        && (ci->values[0].type != OCONFIG_TYPE_NUMBER)))
+  {
+    WARNING ("filecount plugin: The `Size' config option needs exactly one "
+        "string or numeric argument.");
+    return (-1);
+  }
+
+  if (ci->values[0].type == OCONFIG_TYPE_NUMBER)
+  {
+    dir->size = (int64_t) ci->values[0].value.number;
+    return (0);
+  }
+
+  errno = 0;
+  endptr = NULL;
+  temp = strtod (ci->values[0].value.string, &endptr);
+  if ((errno != 0) || (endptr == NULL)
+      || (endptr == ci->values[0].value.string))
+  {
+    WARNING ("filecount plugin: Converting `%s' to a number failed.",
+        ci->values[0].value.string);
+    return (-1);
+  }
+
+  switch (*endptr)
+  {
+    case 0:
+    case 'b':
+    case 'B':
+      break;
+
+    case 'k':
+    case 'K':
+      temp *= 1000.0;
+      break;
+
+    case 'm':
+    case 'M':
+      temp *= 1000.0 * 1000.0;
+      break;
+
+    case 'g':
+    case 'G':
+      temp *= 1000.0 * 1000.0 * 1000.0;
+      break;
+
+    case 't':
+    case 'T':
+      temp *= 1000.0 * 1000.0 * 1000.0 * 1000.0;
+      break;
+
+    case 'p':
+    case 'P':
+      temp *= 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0;
+      break;
+
+    default:
+      WARNING ("filecount plugin: Invalid suffix for `Size': `%c'", *endptr);
+      return (-1);
+  } /* switch (*endptr) */
+
+  dir->size = (int64_t) temp;
+
+  return (0);
+} /* int fc_config_add_dir_size */
+
+static int fc_config_add_dir (oconfig_item_t *ci)
+{
+  fc_directory_conf_t *dir;
+  int status;
+  int i;
+
+  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("filecount plugin: `Directory' needs exactly one string "
+        "argument.");
+    return (-1);
+  }
+
+  /* Initialize `dir' */
+  dir = (fc_directory_conf_t *) malloc (sizeof (*dir));
+  if (dir == NULL)
+  {
+    ERROR ("filecount plugin: malloc failed.");
+    return (-1);
+  }
+  memset (dir, 0, sizeof (*dir));
+
+  dir->path = strdup (ci->values[0].value.string);
+  if (dir->path == NULL)
+  {
+    ERROR ("filecount plugin: strdup failed.");
+    return (-1);
+  }
+
+  fc_config_set_instance (dir, dir->path);
+
+  dir->name = NULL;
+  dir->mtime = 0;
+  dir->size = 0;
+
+  status = 0;
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *option = ci->children + i;
+
+    if (strcasecmp ("Instance", option->key) == 0)
+      status = fc_config_add_dir_instance (dir, option);
+    else if (strcasecmp ("Name", option->key) == 0)
+      status = fc_config_add_dir_name (dir, option);
+    else if (strcasecmp ("MTime", option->key) == 0)
+      status = fc_config_add_dir_mtime (dir, option);
+    else if (strcasecmp ("Size", option->key) == 0)
+      status = fc_config_add_dir_size (dir, option);
+    else
+    {
+      WARNING ("filecount plugin: fc_config_add_dir: "
+          "Option `%s' not allowed here.", option->key);
+      status = -1;
+    }
+
+    if (status != 0)
+      break;
+  } /* for (ci->children) */
+
+  if (status == 0)
+  {
+    fc_directory_conf_t **temp;
+
+    temp = (fc_directory_conf_t **) realloc (directories,
+        sizeof (*directories) * (directories_num + 1));
+    if (temp == NULL)
+    {
+      ERROR ("filecount plugin: realloc failed.");
+      status = -1;
+    }
+    else
+    {
+      directories = temp;
+      directories[directories_num] = dir;
+      directories_num++;
+    }
+  }
+
+  if (status != 0)
+  {
+    sfree (dir->name);
+    sfree (dir->instance);
+    sfree (dir->path);
+    sfree (dir);
+    return (-1);
+  }
+
+  return (0);
+} /* int fc_config_add_dir */
+
+static int fc_config (oconfig_item_t *ci)
+{
+  int i;
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *child = ci->children + i;
+    if (strcasecmp ("Directory", child->key) == 0)
+      fc_config_add_dir (child);
+    else
+    {
+      WARNING ("filecount plugin: Ignoring unknown config option `%s'.",
+          child->key);
+    }
+  } /* for (ci->children) */
+
+  return (0);
+} /* int fc_config */
+
+static int fc_init (void)
+{
+  if (directories_num < 1)
+  {
+    WARNING ("filecount plugin: No directories have been configured.");
+    return (-1);
+  }
+
+  return (0);
+} /* int fc_init */
+
+static int fc_read_dir_callback (const char *dirname, const char *filename,
+    void *user_data)
+{
+  fc_directory_conf_t *dir = user_data;
+  char abs_path[PATH_MAX];
+  struct stat statbuf;
+  int status;
+
+  if (dir == NULL)
+    return (-1);
+
+  ssnprintf (abs_path, sizeof (abs_path), "%s/%s", dirname, filename);
+
+  status = lstat (abs_path, &statbuf);
+  if (status != 0)
+  {
+    ERROR ("filecount plugin: stat (%s) failed.", abs_path);
+    return (-1);
+  }
+
+  if (S_ISDIR (statbuf.st_mode))
+  {
+    status = walk_directory (abs_path, fc_read_dir_callback, dir);
+    return (status);
+  }
+  else if (!S_ISREG (statbuf.st_mode))
+  {
+    return (0);
+  }
+
+  if (dir->name != NULL)
+  {
+    status = fnmatch (dir->name, filename, /* flags = */ 0);
+    if (status != 0)
+      return (0);
+  }
+
+  if (dir->mtime != 0)
+  {
+    time_t mtime = dir->now;
+
+    if (dir->mtime < 0)
+      mtime += dir->mtime;
+    else
+      mtime -= dir->mtime;
+
+    DEBUG ("filecount plugin: Only collecting files that were touched %s %u.",
+        (dir->mtime < 0) ? "after" : "before",
+        (unsigned int) mtime);
+
+    if (((dir->mtime < 0) && (statbuf.st_mtime < mtime))
+        || ((dir->mtime > 0) && (statbuf.st_mtime > mtime)))
+      return (0);
+  }
+
+  if (dir->size != 0)
+  {
+    off_t size;
+
+    if (dir->size < 0)
+      size = (off_t) ((-1) * dir->size);
+    else
+      size = (off_t) dir->size;
+
+    if (((dir->size < 0) && (statbuf.st_size > size))
+        || ((dir->size > 0) && (statbuf.st_size < size)))
+      return (0);
+  }
+
+  dir->files_num++;
+  dir->files_size += (uint64_t) statbuf.st_size;
+
+  return (0);
+} /* int fc_read_dir_callback */
+
+static int fc_read_dir (fc_directory_conf_t *dir)
+{
+  int status;
+
+  dir->files_num = 0;
+  dir->files_size = 0;
+
+  if (dir->mtime != 0)
+    dir->now = time (NULL);
+
+  status = walk_directory (dir->path, fc_read_dir_callback, dir);
+  if (status != 0)
+  {
+    WARNING ("filecount plugin: walk_directory (%s) failed.", dir->path);
+    return (-1);
+  }
+
+  fc_submit_dir (dir);
+
+  return (0);
+} /* int fc_read_dir */
+
+static int fc_read (void)
+{
+  size_t i;
+
+  for (i = 0; i < directories_num; i++)
+    fc_read_dir (directories[i]);
+
+  return (0);
+} /* int fc_read */
+
+void module_register (void)
+{
+  plugin_register_complex_config ("filecount", fc_config);
+  plugin_register_init ("filecount", fc_init);
+  plugin_register_read ("filecount", fc_read);
+} /* void module_register */
+
+/*
+ * vim: set sw=2 sts=2 et :
+ */
index cb49577..9f4a725 100644 (file)
@@ -223,11 +223,10 @@ static int hddtemp_config (const char *key, const char *value)
        {
                int port = (int) (atof (value));
                if ((port > 0) && (port <= 65535))
-                       snprintf (hddtemp_port, sizeof (hddtemp_port),
+                       ssnprintf (hddtemp_port, sizeof (hddtemp_port),
                                        "%i", port);
                else
-                       strncpy (hddtemp_port, value, sizeof (hddtemp_port));
-               hddtemp_port[sizeof (hddtemp_port) - 1] = '\0';
+                       sstrncpy (hddtemp_port, value, sizeof (hddtemp_port));
        }
        else if (strcasecmp (key, "TranslateDevicename") == 0)
        {
@@ -430,7 +429,7 @@ static char *hddtemp_get_major_minor (char *drive)
        if ((ret = (char *) malloc (128 * sizeof (char))) == NULL)
                return (NULL);
 
-       if (snprintf (ret, 128, "%i-%i", list->major, list->minor) >= 128)
+       if (ssnprintf (ret, 128, "%i-%i", list->major, list->minor) >= 128)
        {
                free (ret);
                return (NULL);
@@ -451,9 +450,10 @@ static void hddtemp_submit (char *type_instance, double value)
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "hddtemp", sizeof (vl.plugin));
-       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+       sstrncpy (vl.type, "temperature", sizeof (vl.type));
+       sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       plugin_dispatch_values ("temperature", &vl);
+       plugin_dispatch_values (&vl);
 }
 
 static int hddtemp_read (void)
index 2add89d..806a336 100644 (file)
@@ -199,9 +199,10 @@ static void if_submit (const char *dev, const char *type,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "interface", sizeof (vl.plugin));
-       strncpy (vl.type_instance, dev, sizeof (vl.type_instance));
+       sstrncpy (vl.type, type, sizeof (vl.type));
+       sstrncpy (vl.type_instance, dev, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void if_submit */
 
 static int interface_read (void)
index 2d6d248..f3ba95a 100644 (file)
@@ -1,6 +1,7 @@
 /**
  * collectd - src/ipmi.c
  * Copyright (C) 2008  Florian octo Forster
+ * Copyright (C) 2008  Peter Holik
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -17,6 +18,7 @@
  *
  * Authors:
  *   Florian octo Forster <octo at verplant.org>
+ *   Peter Holik <peter at holik.at>
  **/
 
 #include "collectd.h"
@@ -41,6 +43,9 @@ typedef struct c_ipmi_sensor_list_s c_ipmi_sensor_list_t;
 struct c_ipmi_sensor_list_s
 {
   ipmi_sensor_id_t sensor_id;
+  char sensor_name[DATA_MAX_NAME_LEN];
+  char sensor_type[DATA_MAX_NAME_LEN];
+  int sensor_not_present;
   c_ipmi_sensor_list_t *next;
 };
 
@@ -50,18 +55,26 @@ struct c_ipmi_sensor_list_s
 static pthread_mutex_t sensor_list_lock = PTHREAD_MUTEX_INITIALIZER;
 static c_ipmi_sensor_list_t *sensor_list = NULL;
 
+static int c_ipmi_init_in_progress = 0;
 static int c_ipmi_active = 0;
 static pthread_t thread_id = (pthread_t) 0;
 
 static const char *config_keys[] =
 {
        "Sensor",
-       "IgnoreSelected"
+       "IgnoreSelected",
+       "NotifySensorAdd",
+       "NotifySensorRemove",
+       "NotifySensorNotPresent"
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
 static ignorelist_t *ignorelist = NULL;
 
+static int c_ipmi_nofiy_add = 0;
+static int c_ipmi_nofiy_remove = 0;
+static int c_ipmi_nofiy_notpresent = 0;
+
 /*
  * Misc private functions
  */
@@ -106,36 +119,73 @@ static void sensor_read_handler (ipmi_sensor_t *sensor,
   value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  char sensor_name[IPMI_SENSOR_NAME_LEN];
-  char *sensor_name_ptr;
-  int sensor_type;
-  const char *type;
-
-  memset (sensor_name, 0, sizeof (sensor_name));
-  ipmi_sensor_get_name (sensor, sensor_name, sizeof (sensor_name));
-  sensor_name[sizeof (sensor_name) - 1] = 0;
-
-  sensor_name_ptr = strstr (sensor_name, ").");
-  if (sensor_name_ptr == NULL)
-    sensor_name_ptr = sensor_name;
-  else
-    sensor_name_ptr += 2;
+  c_ipmi_sensor_list_t *list_item = (c_ipmi_sensor_list_t *)user_data;
 
   if (err != 0)
   {
-    INFO ("ipmi plugin: sensor_read_handler: Removing sensor %s, "
-        "because it failed with status %#x.",
-        sensor_name_ptr, err);
-    sensor_list_remove (sensor);
+    if ((err & 0xff) == IPMI_NOT_PRESENT_CC)
+    {
+      if (list_item->sensor_not_present == 0)
+      {
+        list_item->sensor_not_present = 1;
+
+        INFO ("ipmi plugin: sensor_read_handler: sensor %s "
+            "not present.", list_item->sensor_name);
+
+        if (c_ipmi_nofiy_notpresent)
+        {
+          notification_t n = { NOTIF_WARNING, time(NULL), "", "", "ipmi",
+            "", "", "", NULL };
+
+          sstrncpy (n.host, hostname_g, sizeof (n.host));
+          sstrncpy (n.type_instance, list_item->sensor_name,
+              sizeof (n.type_instance));
+          sstrncpy (n.type, list_item->sensor_type, sizeof (n.type));
+          ssnprintf (n.message, sizeof (n.message),
+              "sensor %s not present", list_item->sensor_name);
+
+          plugin_dispatch_notification (&n);
+        }
+      }
+    }
+    else
+    {
+      INFO ("ipmi plugin: sensor_read_handler: Removing sensor %s, "
+          "because it failed with status %#x.",
+          list_item->sensor_name, err);
+      sensor_list_remove (sensor);
+    }
     return;
   }
+  else if (list_item->sensor_not_present == 1)
+  {
+    list_item->sensor_not_present = 0;
+
+    INFO ("ipmi plugin: sensor_read_handler: sensor %s present.",
+        list_item->sensor_name);
+
+    if (c_ipmi_nofiy_notpresent)
+    {
+      notification_t n = { NOTIF_OKAY, time(NULL), "", "", "ipmi",
+        "", "", "", NULL };
+
+      sstrncpy (n.host, hostname_g, sizeof (n.host));
+      sstrncpy (n.type_instance, list_item->sensor_name,
+          sizeof (n.type_instance));
+      sstrncpy (n.type, list_item->sensor_type, sizeof (n.type));
+      ssnprintf (n.message, sizeof (n.message),
+          "sensor %s present", list_item->sensor_name);
+
+      plugin_dispatch_notification (&n);
+    }
+  }
 
   if (value_present != IPMI_BOTH_VALUES_PRESENT)
   {
     INFO ("ipmi plugin: sensor_read_handler: Removing sensor %s, "
         "because it provides %s. If you need this sensor, "
         "please file a bug report.",
-        sensor_name_ptr,
+        list_item->sensor_name,
         (value_present == IPMI_RAW_VALUE_PRESENT)
         ? "only the raw value"
         : "no value");
@@ -143,13 +193,60 @@ static void sensor_read_handler (ipmi_sensor_t *sensor,
     return;
   }
 
-  /* Both `ignorelist' and `plugin_instance' may be NULL. */
-  if (ignorelist_match (ignorelist, sensor_name_ptr) != 0)
+  values[0].gauge = value;
+
+  vl.values = values;
+  vl.values_len = 1;
+  vl.time = time (NULL);
+
+  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+  sstrncpy (vl.plugin, "ipmi", sizeof (vl.plugin));
+  sstrncpy (vl.type, list_item->sensor_type, sizeof (vl.type));
+  sstrncpy (vl.type_instance, list_item->sensor_name, sizeof (vl.type_instance));
+
+  plugin_dispatch_values (&vl);
+} /* void sensor_read_handler */
+
+static int sensor_list_add (ipmi_sensor_t *sensor)
+{
+  ipmi_sensor_id_t sensor_id;
+  c_ipmi_sensor_list_t *list_item;
+  c_ipmi_sensor_list_t *list_prev;
+
+  char sensor_name[DATA_MAX_NAME_LEN];
+  char *sensor_name_ptr;
+  int sensor_type, len;
+  const char *type;
+  ipmi_entity_t *ent = ipmi_sensor_get_entity(sensor);
+
+  sensor_id = ipmi_sensor_convert_to_id (sensor);
+
+  memset (sensor_name, 0, sizeof (sensor_name));
+  ipmi_sensor_get_name (sensor, sensor_name, sizeof (sensor_name));
+  sensor_name[sizeof (sensor_name) - 1] = 0;
+
+  len = DATA_MAX_NAME_LEN - strlen(sensor_name);
+  strncat(sensor_name, " ", len--);
+  strncat(sensor_name, ipmi_entity_get_entity_id_string(ent), len);
+
+  sensor_name_ptr = strstr (sensor_name, ").");
+  if (sensor_name_ptr == NULL)
+    sensor_name_ptr = sensor_name;
+  else
   {
-    sensor_list_remove (sensor);
-    return;
+    char *sensor_name_ptr_id = strstr (sensor_name, "(");
+
+    sensor_name_ptr += 2;
+    len = DATA_MAX_NAME_LEN - strlen(sensor_name);
+    strncat(sensor_name, " ", len--);
+    strncat(sensor_name, sensor_name_ptr_id, 
+      MIN(sensor_name_ptr - sensor_name_ptr_id - 1, len));
   }
 
+  /* Both `ignorelist' and `plugin_instance' may be NULL. */
+  if (ignorelist_match (ignorelist, sensor_name_ptr) != 0)
+    return (0);
+
   /* FIXME: Use rate unit or base unit to scale the value */
 
   sensor_type = ipmi_sensor_get_sensor_type (sensor);
@@ -174,38 +271,16 @@ static void sensor_read_handler (ipmi_sensor_t *sensor,
     default:
       {
         const char *sensor_type_str;
-        
+
         sensor_type_str = ipmi_sensor_get_sensor_type_string (sensor);
-        INFO ("ipmi plugin: sensor_read_handler: Removing sensor %s, "
+        INFO ("ipmi plugin: sensor_list_add: Ignore sensor %s, "
             "because I don't know how to handle its type (%#x, %s). "
             "If you need this sensor, please file a bug report.",
             sensor_name_ptr, sensor_type, sensor_type_str);
-        sensor_list_remove (sensor);
-        return;
+        return (-1);
       }
   } /* switch (sensor_type) */
 
-  values[0].gauge = value;
-
-  vl.values = values;
-  vl.values_len = 1;
-  vl.time = time (NULL);
-
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
-  sstrncpy (vl.plugin, "ipmi", sizeof (vl.plugin));
-  sstrncpy (vl.type_instance, sensor_name_ptr, sizeof (vl.type_instance));
-
-  plugin_dispatch_values (type, &vl);
-} /* void sensor_read_handler */
-
-static int sensor_list_add (ipmi_sensor_t *sensor)
-{
-  ipmi_sensor_id_t sensor_id;
-  c_ipmi_sensor_list_t *list_item;
-  c_ipmi_sensor_list_t *list_prev;
-
-  sensor_id = ipmi_sensor_convert_to_id (sensor);
-
   pthread_mutex_lock (&sensor_list_lock);
 
   list_prev = NULL;
@@ -238,8 +313,27 @@ static int sensor_list_add (ipmi_sensor_t *sensor)
   else
     sensor_list = list_item;
 
+  sstrncpy (list_item->sensor_name, sensor_name_ptr,
+            sizeof (list_item->sensor_name));
+  sstrncpy (list_item->sensor_type, type, sizeof (list_item->sensor_type));
+
   pthread_mutex_unlock (&sensor_list_lock);
 
+  if (c_ipmi_nofiy_add && (c_ipmi_init_in_progress == 0))
+  {
+    notification_t n = { NOTIF_OKAY, time(NULL), "", "", "ipmi",
+                         "", "", "", NULL };
+
+    sstrncpy (n.host, hostname_g, sizeof (n.host));
+    sstrncpy (n.type_instance, list_item->sensor_name,
+              sizeof (n.type_instance));
+    sstrncpy (n.type, list_item->sensor_type, sizeof (n.type));
+    ssnprintf (n.message, sizeof (n.message),
+              "sensor %s added", list_item->sensor_name);
+
+    plugin_dispatch_notification (&n);
+  }
+
   return (0);
 } /* int sensor_list_add */
 
@@ -279,6 +373,21 @@ static int sensor_list_remove (ipmi_sensor_t *sensor)
 
   pthread_mutex_unlock (&sensor_list_lock);
 
+  if (c_ipmi_nofiy_remove && c_ipmi_active)
+  {
+    notification_t n = { NOTIF_WARNING, time(NULL), "", "",
+                         "ipmi", "", "", "", NULL };
+
+    sstrncpy (n.host, hostname_g, sizeof (n.host));
+    sstrncpy (n.type_instance, list_item->sensor_name,
+              sizeof (n.type_instance));
+    sstrncpy (n.type, list_item->sensor_type, sizeof (n.type));
+    ssnprintf (n.message, sizeof (n.message),
+              "sensor %s removed", list_item->sensor_name);
+
+    plugin_dispatch_notification (&n);
+  }
+
   free (list_item);
   return (0);
 } /* int sensor_list_remove */
@@ -294,7 +403,7 @@ static int sensor_list_read_all (void)
       list_item = list_item->next)
   {
     ipmi_sensor_id_get_reading (list_item->sensor_id,
-        sensor_read_handler, /* user data = */ NULL);
+        sensor_read_handler, /* user data = */ list_item);
   } /* for (list_item) */
 
   pthread_mutex_unlock (&sensor_list_lock);
@@ -482,11 +591,32 @@ static int c_ipmi_config (const char *key, const char *value)
   {
     int invert = 1;
     if ((strcasecmp ("True", value) == 0)
-       || (strcasecmp ("Yes", value) == 0)
-       || (strcasecmp ("On", value) == 0))
+        || (strcasecmp ("Yes", value) == 0)
+        || (strcasecmp ("On", value) == 0))
       invert = 0;
     ignorelist_set_invert (ignorelist, invert);
   }
+  else if (strcasecmp ("NotifySensorAdd", key) == 0)
+  {
+    if ((strcasecmp ("True", value) == 0)
+        || (strcasecmp ("Yes", value) == 0)
+        || (strcasecmp ("On", value) == 0))
+      c_ipmi_nofiy_add = 1;
+  }
+  else if (strcasecmp ("NotifySensorRemove", key) == 0)
+  {
+    if ((strcasecmp ("True", value) == 0)
+        || (strcasecmp ("Yes", value) == 0)
+        || (strcasecmp ("On", value) == 0))
+      c_ipmi_nofiy_remove = 1;
+  }
+  else if (strcasecmp ("NotifySensorNotPresent", key) == 0)
+  {
+    if ((strcasecmp ("True", value) == 0)
+        || (strcasecmp ("Yes", value) == 0)
+        || (strcasecmp ("On", value) == 0))
+      c_ipmi_nofiy_notpresent = 1;
+  }
   else
   {
     return (-1);
@@ -499,6 +629,9 @@ static int c_ipmi_init (void)
 {
   int status;
 
+  /* Don't send `ADD' notifications during startup (~ 1 minute) */
+  c_ipmi_init_in_progress = 1 + (60 / interval_g);
+
   c_ipmi_active = 1;
 
   status = pthread_create (&thread_id, /* attr = */ NULL, thread_main,
@@ -523,7 +656,12 @@ static int c_ipmi_read (void)
   }
 
   sensor_list_read_all ();
-  
+
+  if (c_ipmi_init_in_progress > 0)
+    c_ipmi_init_in_progress--;
+  else
+    c_ipmi_init_in_progress = 0;
+
   return (0);
 } /* int c_ipmi_read */
 
index ea8c65e..e1694af 100644 (file)
@@ -107,25 +107,23 @@ static int iptables_config (const char *key, const char *value)
                table = fields[0];
                chain = fields[1];
 
-               table_len = strlen (table);
-               if ((unsigned int)table_len >= sizeof(temp.table))
+               table_len = strlen (table) + 1;
+               if ((unsigned int)table_len > sizeof(temp.table))
                {
                        ERROR ("Table `%s' too long.", table);
                        free (value_copy);
                        return (1);
                }
-               strncpy (temp.table, table, table_len);
-               temp.table[table_len] = '\0';
+               sstrncpy (temp.table, table, table_len);
 
-               chain_len = strlen (chain);
-               if ((unsigned int)chain_len >= sizeof(temp.chain))
+               chain_len = strlen (chain) + 1;
+               if ((unsigned int)chain_len > sizeof(temp.chain))
                {
                        ERROR ("Chain `%s' too long.", chain);
                        free (value_copy);
                        return (1);
                }
-               strncpy (temp.chain, chain, chain_len);
-               temp.chain[chain_len] = '\0'; 
+               sstrncpy (temp.chain, chain, chain_len);
 
                if (fields_num >= 3)
                {
@@ -154,7 +152,7 @@ static int iptables_config (const char *key, const char *value)
                }
 
                if (fields_num >= 4)
-                   strncpy (temp.name, fields[3], sizeof (temp.name) - 1);
+                   sstrncpy (temp.name, fields[3], sizeof (temp.name));
 
                free (value_copy);
                value_copy = NULL;
@@ -224,31 +222,32 @@ static int submit_match (const struct ipt_entry_match *match,
     sstrncpy (vl.host, hostname_g, sizeof (vl.host));
     sstrncpy (vl.plugin, "iptables", sizeof (vl.plugin));
 
-    status = snprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
+    status = ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
            "%s-%s", chain->table, chain->chain);
     if ((status < 1) || ((unsigned int)status >= sizeof (vl.plugin_instance)))
        return (0);
 
     if (chain->name[0] != '\0')
     {
-       strncpy (vl.type_instance, chain->name, sizeof (vl.type_instance));
+       sstrncpy (vl.type_instance, chain->name, sizeof (vl.type_instance));
     }
     else
     {
        if (chain->rule_type == RTYPE_NUM)
-           snprintf (vl.type_instance, sizeof (vl.type_instance),
+           ssnprintf (vl.type_instance, sizeof (vl.type_instance),
                    "%i", chain->rule.num);
        else
-           strncpy (vl.type_instance, (char *) match->data,
+           sstrncpy (vl.type_instance, (char *) match->data,
                    sizeof (vl.type_instance));
     }
-    vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
 
+    sstrncpy (vl.type, "ipt_bytes", sizeof (vl.type));
     values[0].counter = (counter_t) entry->counters.bcnt;
-    plugin_dispatch_values ("ipt_bytes", &vl);
+    plugin_dispatch_values (&vl);
 
+    sstrncpy (vl.type, "ipt_packets", sizeof (vl.type));
     values[0].counter = (counter_t) entry->counters.pcnt;
-    plugin_dispatch_values ("ipt_packets", &vl);
+    plugin_dispatch_values (&vl);
 
     return (0);
 } /* void submit_match */
index 2de28dd..85e65d2 100644 (file)
@@ -191,7 +191,7 @@ static int get_pi (struct ip_vs_service_entry *se, char *pi, size_t size)
 
        /* inet_ntoa() returns a pointer to a statically allocated buffer
         * I hope non-glibc systems behave the same */
-       len = snprintf (pi, size, "%s_%s%u", inet_ntoa (addr),
+       len = ssnprintf (pi, size, "%s_%s%u", inet_ntoa (addr),
                        (se->protocol == IPPROTO_TCP) ? "TCP" : "UDP",
                        ntohs (se->port));
 
@@ -215,7 +215,7 @@ static int get_ti (struct ip_vs_dest_entry *de, char *ti, size_t size)
 
        /* inet_ntoa() returns a pointer to a statically allocated buffer
         * I hope non-glibc systems behave the same */
-       len = snprintf (ti, size, "%s_%u", inet_ntoa (addr),
+       len = ssnprintf (ti, size, "%s_%u", inet_ntoa (addr),
                        ntohs (de->port));
 
        if ((0 > len) || (size <= len)) {
@@ -241,9 +241,11 @@ static void cipvs_submit_connections (char *pi, char *ti, counter_t value)
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "ipvs", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, pi, sizeof (vl.plugin_instance));
-       sstrncpy (vl.type_instance, (NULL != ti) ? ti : "total", sizeof (vl.type_instance));
+       sstrncpy (vl.type, "connections", sizeof (vl.type));
+       sstrncpy (vl.type_instance, (NULL != ti) ? ti : "total",
+               sizeof (vl.type_instance));
 
-       plugin_dispatch_values ("connections", &vl);
+       plugin_dispatch_values (&vl);
        return;
 } /* cipvs_submit_connections */
 
@@ -265,9 +267,11 @@ static void cipvs_submit_if (char *pi, char *t, char *ti,
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "ipvs", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, pi, sizeof (vl.plugin_instance));
-       sstrncpy (vl.type_instance, (NULL != ti) ? ti : "total", sizeof (vl.type_instance));
+       sstrncpy (vl.type, t, sizeof (vl.type));
+       sstrncpy (vl.type_instance, (NULL != ti) ? ti : "total",
+               sizeof (vl.type_instance));
 
-       plugin_dispatch_values (t, &vl);
+       plugin_dispatch_values (&vl);
        return;
 } /* cipvs_submit_if */
 
index 93c6076..9b7e618 100644 (file)
--- a/src/irq.c
+++ b/src/irq.c
@@ -134,13 +134,14 @@ static void irq_submit (unsigned int irq, counter_t value)
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "irq", sizeof (vl.plugin));
+       sstrncpy (vl.type, "irq", sizeof (vl.type));
 
-       status = snprintf (vl.type_instance, sizeof (vl.type_instance),
+       status = ssnprintf (vl.type_instance, sizeof (vl.type_instance),
                        "%u", irq);
        if ((status < 1) || ((unsigned int)status >= sizeof (vl.type_instance)))
                return;
 
-       plugin_dispatch_values ("irq", &vl);
+       plugin_dispatch_values (&vl);
 } /* void irq_submit */
 
 static int irq_read (void)
index 338aecb..ffa9887 100644 (file)
@@ -10,5 +10,6 @@ noinst_LTLIBRARIES = libiptc.la
 
 libiptc_la_CFLAGS = -DIPTABLES_VERSION=\"1.4.0\" -I$(KERNEL_DIR)/include
 libiptc_la_SOURCES = libip4tc.c libip6tc.c \
-               ipt_kernel_headers.h libip6tc.h libiptc.h linux_list.h
+               ipt_kernel_headers.h libip6tc.h libiptc.h linux_list.h \
+               xtables.h libxtc.h
 
index 4d9fc3d..b559e86 100644 (file)
@@ -1,6 +1,7 @@
 /**
  * oconfig - src/scanner.l
  * Copyright (C) 2007  Florian octo Forster <octo at verplant.org>
+ * Copyright (C) 2008  Sebastian tokkee Harl <sh at tokkee.org>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
 #include "oconfig.h"
 #include "aux_types.h"
 #include "parser.h"
+
+/* multiline string buffer */
+static char *ml_buffer = NULL;
+static int   ml_pos    = 0;
+static int   ml_len    = 0;
+
+#define ml_free (ml_len - ml_pos)
+
+static void ml_append (char *);
+
+#ifdef yyterminate
+# undef yyterminate
+#endif
+#define yyterminate() \
+       do { free (ml_buffer); ml_buffer = NULL; ml_pos = 0; ml_len = 0; \
+               return YY_NULL; } while (0)
 %}
 %option yylineno
 %option noyywrap
+%x ML
 WHITE_SPACE [\ \t\b]
-QUOTED_STRING \"([^\\"]+|\\.)*\"
+NON_WHITE_SPACE [^\ \t\b]
+EOL (\r\n|\n)
+QUOTED_STRING ([^\\"]+|\\.)*
 UNQUOTED_STRING [0-9A-Za-z_]+
 HEX_NUMBER 0[xX][0-9a-fA-F]+
 OCT_NUMBER 0[0-7]+
@@ -43,7 +63,9 @@ IPV4_ADDR {IP_BYTE}\.{IP_BYTE}\.{IP_BYTE}\.{IP_BYTE}(:{PORT})?
 {WHITE_SPACE}          |
 {COMMENT}              {/* ignore */}
 
-\n                     {return (EOL);}
+\\{EOL}                        {/* continue line */}
+
+{EOL}                  {return (EOL);}
 "/"                    {return (SLASH);}
 "<"                    {return (OPENBRAC);}
 ">"                    {return (CLOSEBRAC);}
@@ -54,6 +76,62 @@ IPV4_ADDR {IP_BYTE}\.{IP_BYTE}\.{IP_BYTE}\.{IP_BYTE}(:{PORT})?
 
 {NUMBER}               {yylval.number = strtod (yytext, NULL); return (NUMBER);}
 
-{QUOTED_STRING}                {yylval.string = yytext; return (QUOTED_STRING);}
+\"{QUOTED_STRING}\"    {yylval.string = yytext; return (QUOTED_STRING);}
 {UNQUOTED_STRING}      {yylval.string = yytext; return (UNQUOTED_STRING);}
+
+\"{QUOTED_STRING}\\{EOL} {
+       int len = strlen (yytext);
+
+       ml_pos = 0;
+
+       /* remove "\\<EOL>" */
+       if ('\r' == yytext[len - 2])
+               len -= 3;
+       else
+               len -= 2;
+       yytext[len] = '\0';
+
+       ml_append (yytext);
+       BEGIN (ML);
+}
+<ML>^{WHITE_SPACE}+ {/* remove leading white-space */}
+<ML>{NON_WHITE_SPACE}{QUOTED_STRING}\\{EOL} {
+       int len = strlen (yytext);
+
+       /* remove "\\<EOL>" */
+       if ('\r' == yytext[len - 2])
+               len -= 3;
+       else
+               len -= 2;
+       yytext[len] = '\0';
+
+       ml_append(yytext);
+}
+<ML>{NON_WHITE_SPACE}{QUOTED_STRING}\" {
+       ml_append(yytext);
+       yylval.string = ml_buffer;
+
+       BEGIN (INITIAL);
+       return (QUOTED_STRING);
+}
 %%
+static void ml_append (char *string)
+{
+       int len = strlen (string);
+       int s;
+
+       if (ml_free <= len) {
+               ml_len += len - ml_free + 1;
+               ml_buffer = (char *)realloc (ml_buffer, ml_len);
+               if (NULL == ml_buffer)
+                       YY_FATAL_ERROR ("out of dynamic memory in ml_append");
+       }
+
+       s = snprintf (ml_buffer + ml_pos, ml_free, "%s", string);
+       if ((0 > s) || (ml_free <= s))
+               YY_FATAL_ERROR ("failed to write to multiline buffer");
+
+       ml_pos += s;
+       return;
+} /* ml_append */
+
index 81d7f1c..5acff29 100644 (file)
@@ -634,7 +634,7 @@ ignore_device_match (ignorelist_t *il, const char *domname, const char *devpath)
         ERROR ("libvirt plugin: malloc failed.");
         return 0;
     }
-    snprintf (name, n, "%s:%s", domname, devpath);
+    ssnprintf (name, n, "%s:%s", domname, devpath);
     r = ignorelist_match (il, name);
     free (name);
     return r;
@@ -652,8 +652,7 @@ init_value_list (value_list_t *vl, time_t t, virDomainPtr dom)
     vl->time = t;
     vl->interval = interval_g;
 
-    strncpy (vl->plugin, "libvirt", sizeof (vl->plugin));
-    vl->plugin[sizeof (vl->plugin) - 1] = '\0';
+    sstrncpy (vl->plugin, "libvirt", sizeof (vl->plugin));
 
     vl->host[0] = '\0';
     host_ptr = vl->host;
@@ -706,7 +705,9 @@ cpu_submit (unsigned long long cpu_time,
     vl.values = values;
     vl.values_len = 1;
 
-    plugin_dispatch_values (type, &vl);
+    sstrncpy (vl.type, type, sizeof (vl.type));
+
+    plugin_dispatch_values (&vl);
 }
 
 static void
@@ -723,10 +724,10 @@ vcpu_submit (counter_t cpu_time,
     vl.values = values;
     vl.values_len = 1;
 
-    snprintf (vl.type_instance, sizeof (vl.type_instance), "%d", vcpu_nr);
-    vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+    sstrncpy (vl.type, type, sizeof (vl.type));
+    ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%d", vcpu_nr);
 
-    plugin_dispatch_values (type, &vl);
+    plugin_dispatch_values (&vl);
 }
 
 static void
@@ -744,10 +745,10 @@ submit_counter2 (const char *type, counter_t v0, counter_t v1,
     vl.values = values;
     vl.values_len = 2;
 
-    strncpy (vl.type_instance, devname, sizeof (vl.type_instance));
-    vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+    sstrncpy (vl.type, type, sizeof (vl.type));
+    sstrncpy (vl.type_instance, devname, sizeof (vl.type_instance));
 
-    plugin_dispatch_values (type, &vl);
+    plugin_dispatch_values (&vl);
 } /* void submit_counter2 */
 
 static int
index e0e0c0e..72c7756 100644 (file)
@@ -53,8 +53,9 @@ static void load_submit (gauge_t snum, gauge_t mnum, gauge_t lnum)
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "load", sizeof (vl.plugin));
+       sstrncpy (vl.type, "load", sizeof (vl.type));
 
-       plugin_dispatch_values ("load", &vl);
+       plugin_dispatch_values (&vl);
 }
 
 static int load_read (void)
index 36ac58d..382386b 100644 (file)
@@ -158,7 +158,7 @@ static int logfile_notification (const notification_t *n)
        int   buf_len = sizeof (buf);
        int status;
 
-       status = snprintf (buf_ptr, buf_len, "Notification: severity = %s",
+       status = ssnprintf (buf_ptr, buf_len, "Notification: severity = %s",
                        (n->severity == NOTIF_FAILURE) ? "FAILURE"
                        : ((n->severity == NOTIF_WARNING) ? "WARNING"
                                : ((n->severity == NOTIF_OKAY) ? "OKAY" : "UNKNOWN")));
@@ -170,7 +170,7 @@ static int logfile_notification (const notification_t *n)
 
 #define APPEND(bufptr, buflen, key, value) \
        if ((buflen > 0) && (strlen (value) > 0)) { \
-               int status = snprintf (bufptr, buflen, ", %s = %s", key, value); \
+               int status = ssnprintf (bufptr, buflen, ", %s = %s", key, value); \
                if (status > 0) { \
                        bufptr += status; \
                        buflen -= status; \
index 22a26da..344cadd 100644 (file)
@@ -230,9 +230,10 @@ static void mbmon_submit (const char *type, const char *type_instance,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "mbmon", sizeof (vl.plugin));
-       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+       sstrncpy (vl.type, type, sizeof (vl.type));
+       sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void mbmon_submit */
 
 /* Trim trailing whitespace from a string. */
index c3fa06b..7bdad0a 100644 (file)
@@ -212,11 +212,10 @@ static int memcached_config (const char *key, const char *value) /* {{{ */
        } else if (strcasecmp (key, "Port") == 0) {
                int port = (int) (atof (value));
                if ((port > 0) && (port <= 65535)) {
-                       snprintf (memcached_port, sizeof (memcached_port), "%i", port);
+                       ssnprintf (memcached_port, sizeof (memcached_port), "%i", port);
                } else {
-                       strncpy (memcached_port, value, sizeof (memcached_port));
+                       sstrncpy (memcached_port, value, sizeof (memcached_port));
                }
-               memcached_port[sizeof (memcached_port) - 1] = '\0';
        } else {
                return -1;
        }
@@ -238,13 +237,11 @@ static void submit_counter (const char *type, const char *type_inst,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
+       sstrncpy (vl.type, type, sizeof (vl.type));
        if (type_inst != NULL)
-       {
-               strncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
-               vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
-       }
+               sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void memcached_submit_cmd */
 /* }}} */
 
@@ -262,13 +259,11 @@ static void submit_counter2 (const char *type, const char *type_inst,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
+       sstrncpy (vl.type, type, sizeof (vl.type));
        if (type_inst != NULL)
-       {
-               strncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
-               vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
-       }
+               sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void memcached_submit_cmd */
 /* }}} */
 
@@ -285,13 +280,11 @@ static void submit_gauge (const char *type, const char *type_inst,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
+       sstrncpy (vl.type, type, sizeof (vl.type));
        if (type_inst != NULL)
-       {
-               strncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
-               vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
-       }
+               sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 }
 /* }}} */
 
@@ -309,13 +302,11 @@ static void submit_gauge2 (const char *type, const char *type_inst,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
+       sstrncpy (vl.type, type, sizeof (vl.type));
        if (type_inst != NULL)
-       {
-               strncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
-               vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
-       }
+               sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 }
 /* }}} */
 
index a4a9af3..c31b30e 100644 (file)
@@ -111,10 +111,10 @@ static void memory_submit (const char *type_instance, gauge_t value)
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "memory", sizeof (vl.plugin));
-       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
-       vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+       sstrncpy (vl.type, "memory", sizeof (vl.type));
+       sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       plugin_dispatch_values ("memory", &vl);
+       plugin_dispatch_values (&vl);
 }
 
 static int memory_read (void)
index db35746..9c9c2c1 100644 (file)
@@ -223,8 +223,9 @@ static void multimeter_submit (double value)
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "multimeter", sizeof (vl.plugin));
+       sstrncpy (vl.type, "multimeter", sizeof (vl.type));
 
-       plugin_dispatch_values ("multimeter", &vl);
+       plugin_dispatch_values (&vl);
 }
 
 static int multimeter_read (void)
index 30557f6..4e72b5b 100644 (file)
@@ -130,9 +130,10 @@ static void counter_submit (const char *type, const char *type_instance,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "mysql", sizeof (vl.plugin));
-       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+       sstrncpy (vl.type, type, sizeof (vl.type));
+       sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void counter_submit */
 
 static void qcache_submit (counter_t hits, counter_t inserts,
@@ -153,8 +154,9 @@ static void qcache_submit (counter_t hits, counter_t inserts,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "mysql", sizeof (vl.plugin));
+       sstrncpy (vl.type, "mysql_qcache", sizeof (vl.type));
 
-       plugin_dispatch_values ("mysql_qcache", &vl);
+       plugin_dispatch_values (&vl);
 } /* void qcache_submit */
 
 static void threads_submit (gauge_t running, gauge_t connected, gauge_t cached,
@@ -173,8 +175,9 @@ static void threads_submit (gauge_t running, gauge_t connected, gauge_t cached,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "mysql", sizeof (vl.plugin));
+       sstrncpy (vl.type, "mysql_threads", sizeof (vl.type));
 
-       plugin_dispatch_values ("mysql_threads", &vl);
+       plugin_dispatch_values (&vl);
 } /* void threads_submit */
 
 static void traffic_submit (counter_t rx, counter_t tx)
@@ -190,8 +193,9 @@ static void traffic_submit (counter_t rx, counter_t tx)
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "mysql", sizeof (vl.plugin));
+       sstrncpy (vl.type, "mysql_octets", sizeof (vl.type));
 
-       plugin_dispatch_values ("mysql_octets", &vl);
+       plugin_dispatch_values (&vl);
 } /* void traffic_submit */
 
 static int mysql_read (void)
index d6288e9..d14e510 100644 (file)
@@ -173,12 +173,13 @@ static void submit_one (const char *dev, const char *type,
   vl.time = time (NULL);
   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "netlink", sizeof (vl.plugin));
-  strncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
+  sstrncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
+  sstrncpy (vl.type, type, sizeof (vl.type));
 
   if (type_instance != NULL)
-    strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+    sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-  plugin_dispatch_values (type, &vl);
+  plugin_dispatch_values (&vl);
 } /* void submit_one */
 
 static void submit_two (const char *dev, const char *type,
@@ -196,16 +197,17 @@ static void submit_two (const char *dev, const char *type,
   vl.time = time (NULL);
   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "netlink", sizeof (vl.plugin));
-  strncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
+  sstrncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
+  sstrncpy (vl.type, type, sizeof (vl.type));
 
   if (type_instance != NULL)
-    strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+    sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-  plugin_dispatch_values (type, &vl);
+  plugin_dispatch_values (&vl);
 } /* void submit_two */
 
 static int link_filter (const struct sockaddr_nl *sa,
-    const struct nlmsghdr *nmh, void *args)
+    struct nlmsghdr *nmh, void *args)
 {
   struct ifinfomsg *msg;
   int msg_len;
@@ -315,7 +317,7 @@ static int link_filter (const struct sockaddr_nl *sa,
 } /* int link_filter */
 
 static int qos_filter (const struct sockaddr_nl *sa,
-    const struct nlmsghdr *nmh, void *args)
+    struct nlmsghdr *nmh, void *args)
 {
   struct tcmsg *msg;
   int msg_len;
@@ -395,11 +397,10 @@ static int qos_filter (const struct sockaddr_nl *sa,
     if (strcmp (tc_type, "filter") == 0)
       numberic_id = msg->tcm_parent;
 
-    snprintf (tc_inst, sizeof (tc_inst), "%s-%x:%x",
+    ssnprintf (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).",
@@ -421,9 +422,8 @@ static int qos_filter (const struct sockaddr_nl *sa,
       struct gnet_stats_basic bs;
       char type_instance[DATA_MAX_NAME_LEN];
 
-      snprintf (type_instance, sizeof (type_instance), "%s-%s",
+      ssnprintf (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]),
@@ -443,9 +443,8 @@ static int qos_filter (const struct sockaddr_nl *sa,
     struct tc_stats ts;
     char type_instance[DATA_MAX_NAME_LEN];
 
-    snprintf (type_instance, sizeof (type_instance), "%s-%s",
+    ssnprintf (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]),
index 3a52a43..9e391bb 100644 (file)
@@ -178,7 +178,6 @@ 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_STATIC;
-static char         send_buffer_type[DATA_MAX_NAME_LEN];
 static pthread_mutex_t send_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
 
 static c_avl_tree_t      *cache_tree = NULL;
@@ -246,7 +245,7 @@ static int cache_flush (void)
        return (0);
 } /* int cache_flush */
 
-static int cache_check (const char *type, const value_list_t *vl)
+static int cache_check (const value_list_t *vl)
 {
        char key[1024];
        time_t *value = NULL;
@@ -256,7 +255,7 @@ static int cache_check (const char *type, const value_list_t *vl)
                return (-1);
 
        if (format_name (key, sizeof (key), vl->host, vl->plugin,
-                               vl->plugin_instance, type, vl->type_instance))
+                               vl->plugin_instance, vl->type, vl->type_instance))
                return (-1);
 
        pthread_mutex_lock (&cache_lock);
@@ -678,14 +677,12 @@ static int parse_packet (void *buffer, int buffer_len)
        int status;
 
        value_list_t vl = VALUE_LIST_INIT;
-       char type[DATA_MAX_NAME_LEN];
        notification_t n;
 
        DEBUG ("network plugin: parse_packet: buffer = %p; buffer_len = %i;",
                        buffer, buffer_len);
 
        memset (&vl, '\0', sizeof (vl));
-       memset (&type, '\0', sizeof (type));
        memset (&n, '\0', sizeof (n));
        status = 0;
 
@@ -722,10 +719,10 @@ static int parse_packet (void *buffer, int buffer_len)
                        if ((vl.time > 0)
                                        && (strlen (vl.host) > 0)
                                        && (strlen (vl.plugin) > 0)
-                                       && (strlen (type) > 0)
-                                       && (cache_check (type, &vl) == 0))
+                                       && (strlen (vl.type) > 0)
+                                       && (cache_check (&vl) == 0))
                        {
-                               plugin_dispatch_values (type, &vl);
+                               plugin_dispatch_values (&vl);
                        }
                        else
                        {
@@ -782,9 +779,9 @@ static int parse_packet (void *buffer, int buffer_len)
                else if (pkg_type == TYPE_TYPE)
                {
                        status = parse_part_string (&buffer, &buffer_len,
-                                       type, sizeof (type));
+                                       vl.type, sizeof (vl.type));
                        if (status == 0)
-                               sstrncpy (n.type, type, sizeof (n.type));
+                               sstrncpy (n.type, vl.type, sizeof (n.type));
                }
                else if (pkg_type == TYPE_TYPE_INSTANCE)
                {
@@ -1395,7 +1392,7 @@ static void network_send_buffer (const char *buffer, int buffer_len)
 } /* void network_send_buffer */
 
 static int add_to_buffer (char *buffer, int buffer_size,
-               value_list_t *vl_def, char *type_def, size_t type_def_size,
+               value_list_t *vl_def,
                const data_set_t *ds, const value_list_t *vl)
 {
        char *buffer_orig = buffer;
@@ -1441,12 +1438,12 @@ static int add_to_buffer (char *buffer, int buffer_size,
                sstrncpy (vl_def->plugin_instance, vl->plugin_instance, sizeof (vl_def->plugin_instance));
        }
 
-       if (strcmp (type_def, ds->type) != 0)
+       if (strcmp (vl_def->type, vl->type) != 0)
        {
                if (write_part_string (&buffer, &buffer_size, TYPE_TYPE,
-                                       ds->type, strlen (ds->type)) != 0)
+                                       vl->type, strlen (vl->type)) != 0)
                        return (-1);
-               sstrncpy (type_def, ds->type, type_def_size);
+               sstrncpy (vl_def->type, ds->type, sizeof (vl_def->type));
        }
 
        if (strcmp (vl_def->type_instance, vl->type_instance) != 0)
@@ -1472,8 +1469,7 @@ static void flush_buffer (void)
        network_send_buffer (send_buffer, send_buffer_fill);
        send_buffer_ptr  = send_buffer;
        send_buffer_fill = 0;
-       memset (&send_buffer_vl, '\0', sizeof (send_buffer_vl));
-       memset (send_buffer_type, '\0', sizeof (send_buffer_type));
+       memset (&send_buffer_vl, 0, sizeof (send_buffer_vl));
 }
 
 static int network_write (const data_set_t *ds, const value_list_t *vl)
@@ -1483,7 +1479,7 @@ static int network_write (const data_set_t *ds, const value_list_t *vl)
        /* If the value is already in the cache, we have received it via the
         * network. We write it again if forwarding is activated. It's then in
         * the cache and should we receive it again we will ignore it. */
-       status = cache_check (ds->type, vl);
+       status = cache_check (vl);
        if ((network_config_forward == 0)
                        && (status != 0))
                return (0);
@@ -1493,7 +1489,6 @@ static int network_write (const data_set_t *ds, const value_list_t *vl)
        status = add_to_buffer (send_buffer_ptr,
                        sizeof (send_buffer) - send_buffer_fill,
                        &send_buffer_vl,
-                       send_buffer_type, sizeof (send_buffer_type),
                        ds, vl);
        if (status >= 0)
        {
@@ -1508,7 +1503,6 @@ static int network_write (const data_set_t *ds, const value_list_t *vl)
                status = add_to_buffer (send_buffer_ptr,
                                sizeof (send_buffer) - send_buffer_fill,
                                &send_buffer_vl,
-                               send_buffer_type, sizeof (send_buffer_type),
                                ds, vl);
 
                if (status >= 0)
@@ -1730,8 +1724,7 @@ static int network_init (void)
 
        send_buffer_ptr  = send_buffer;
        send_buffer_fill = 0;
-       memset (&send_buffer_vl, '\0', sizeof (send_buffer_vl));
-       memset (send_buffer_type, '\0', sizeof (send_buffer_type));
+       memset (&send_buffer_vl, 0, sizeof (send_buffer_vl));
 
        cache_tree = c_avl_create ((int (*) (const void *, const void *)) strcmp);
        cache_flush_last = time (NULL);
@@ -1774,7 +1767,14 @@ static int network_init (void)
        return (0);
 } /* int network_init */
 
-static int network_flush (int timeout)
+/* 
+ * The flush option of the network plugin cannot flush individual identifiers.
+ * All the values are added to a buffer and sent when the buffer is full, the
+ * requested value may or may not be in there, it's not worth finding out. We
+ * just send the buffer if `flush'  is called - if the requested value was in
+ * there, good. If not, well, then there is nothing to flush.. -octo
+ */
+static int network_flush (int timeout, const char *identifier)
 {
        pthread_mutex_lock (&send_buffer_lock);
 
index 91e6788..f2db895 100644 (file)
--- a/src/nfs.c
+++ b/src/nfs.c
@@ -190,18 +190,19 @@ static void nfs_procedures_submit (const char *plugin_instance,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "nfs", sizeof (vl.plugin));
-       strncpy (vl.plugin_instance, plugin_instance,
+       sstrncpy (vl.plugin_instance, plugin_instance,
                        sizeof (vl.plugin_instance));
+       sstrncpy (vl.type, "nfs_procedure", sizeof (vl.type));
 
        for (i = 0; i < len; i++)
        {
                values[0].counter = val[i];
-               strncpy (vl.type_instance, names[i],
+               sstrncpy (vl.type_instance, names[i],
                                sizeof (vl.type_instance));
                DEBUG ("%s-%s/nfs_procedure-%s = %llu",
                                vl.plugin, vl.plugin_instance,
                                vl.type_instance, val[i]);
-               plugin_dispatch_values ("nfs_procedure", &vl);
+               plugin_dispatch_values (&vl);
        }
 } /* void nfs_procedures_submit */
 
@@ -240,9 +241,8 @@ static void nfs_read_stats_file (FILE *fh, char *inst)
                                continue;
                        }
 
-                       snprintf (plugin_instance, sizeof (plugin_instance),
+                       ssnprintf (plugin_instance, sizeof (plugin_instance),
                                        "v2%s", inst);
-                       plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
 
                        values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
                        if (values == NULL)
@@ -277,9 +277,8 @@ static void nfs_read_stats_file (FILE *fh, char *inst)
                                continue;
                        }
 
-                       snprintf (plugin_instance, sizeof (plugin_instance),
+                       ssnprintf (plugin_instance, sizeof (plugin_instance),
                                        "v3%s", inst);
-                       plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
 
                        values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
                        if (values == NULL)
index 283e8f6..91bcf75 100644 (file)
@@ -122,7 +122,8 @@ static int init (void)
 
   if (user != NULL)
   {
-    if (snprintf (credentials, 1024, "%s:%s", user, pass == NULL ? "" : pass) >= 1024)
+    if (ssnprintf (credentials, sizeof (credentials),
+         "%s:%s", user, pass == NULL ? "" : pass) >= sizeof (credentials))
     {
       ERROR ("nginx plugin: Credentials would have been truncated.");
       return (-1);
@@ -180,14 +181,12 @@ static void submit (char *type, char *inst, long long value)
   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "nginx", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
+  sstrncpy (vl.type, type, sizeof (vl.type));
 
   if (inst != NULL)
-  {
-    strncpy (vl.type_instance, inst, sizeof (vl.type_instance));
-    vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
-  }
+    sstrncpy (vl.type_instance, inst, sizeof (vl.type_instance));
 
-  plugin_dispatch_values (type, &vl);
+  plugin_dispatch_values (&vl);
 } /* void submit */
 
 static int nginx_read (void)
diff --git a/src/notify_desktop.c b/src/notify_desktop.c
new file mode 100644 (file)
index 0000000..2e62e88
--- /dev/null
@@ -0,0 +1,161 @@
+/**
+ * collectd - src/notify_desktop.c
+ * Copyright (C) 2008  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>
+ **/
+
+/*
+ * This plugin sends desktop notifications to a notification daemon.
+ */
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+
+#include <glib.h>
+#include <libnotify/notify.h>
+
+#define log_info(...) INFO ("notify_desktop: " __VA_ARGS__)
+#define log_warn(...) WARNING ("notify_desktop: " __VA_ARGS__)
+#define log_err(...) ERROR ("notify_desktop: " __VA_ARGS__)
+
+#define DEFAULT_TIMEOUT 5000
+
+static int okay_timeout = DEFAULT_TIMEOUT;
+static int warn_timeout = DEFAULT_TIMEOUT;
+static int fail_timeout = DEFAULT_TIMEOUT;
+
+static int set_timeout (oconfig_item_t *ci, int *timeout)
+{
+       if ((0 != ci->children_num) || (1 != ci->values_num)
+                       || (OCONFIG_TYPE_NUMBER != ci->values[0].type)) {
+               log_err ("%s expects a single number argument.", ci->key);
+               return 1;
+       }
+
+       *timeout = (int)ci->values[0].value.number;
+       if (0 > *timeout)
+               *timeout = DEFAULT_TIMEOUT;
+       return 0;
+} /* set_timeout */
+
+static int c_notify_config (oconfig_item_t *ci)
+{
+       int i = 0;
+
+       for (i = 0; i < ci->children_num; ++i) {
+               oconfig_item_t *c = ci->children + i;
+
+               if (0 == strcasecmp (c->key, "OkayTimeout"))
+                       set_timeout (c, &okay_timeout);
+               else if (0 == strcasecmp (c->key, "WarningTimeout"))
+                       set_timeout (c, &warn_timeout);
+               else if (0 == strcasecmp (c->key, "FailureTimeout"))
+                       set_timeout (c, &fail_timeout);
+       }
+       return 0;
+} /* c_notify_config */
+
+static int c_notify (const notification_t *n)
+{
+       NotifyNotification *notification = NULL;
+       NotifyUrgency       urgency      = NOTIFY_URGENCY_LOW;
+       int                 timeout      = okay_timeout;
+
+       char summary[1024];
+
+       if (NOTIF_WARNING == n->severity) {
+               urgency = NOTIFY_URGENCY_NORMAL;
+               timeout = warn_timeout;
+       }
+       else if (NOTIF_FAILURE == n->severity) {
+               urgency = NOTIFY_URGENCY_CRITICAL;
+               timeout = fail_timeout;
+       }
+
+       ssnprintf (summary, sizeof (summary), "collectd %s notification",
+                       (NOTIF_FAILURE == n->severity) ? "FAILURE"
+                               : (NOTIF_WARNING == n->severity) ? "WARNING"
+                               : (NOTIF_OKAY == n->severity) ? "OKAY" : "UNKNOWN");
+
+       notification = notify_notification_new (summary, n->message, NULL, NULL);
+       if (NULL == notification) {
+               log_err ("Failed to create a new notification.");
+               return -1;
+       }
+
+       notify_notification_set_urgency (notification, urgency);
+       notify_notification_set_timeout (notification, timeout);
+
+       if (! notify_notification_show (notification, NULL))
+               log_err ("Failed to display notification.");
+
+       g_object_unref (G_OBJECT (notification));
+       return 0;
+} /* c_notify */
+
+static int c_notify_shutdown (void)
+{
+       plugin_unregister_init ("notify_desktop");
+       plugin_unregister_notification ("notify_desktop");
+       plugin_unregister_shutdown ("notify_desktop");
+
+       if (notify_is_initted ())
+               notify_uninit ();
+       return 0;
+} /* c_notify_shutdown */
+
+static int c_notify_init (void)
+{
+       char *name         = NULL;
+       char *vendor       = NULL;
+       char *version      = NULL;
+       char *spec_version = NULL;
+
+       if (! notify_init (PACKAGE_STRING)) {
+               log_err ("Failed to initialize libnotify.");
+               return -1;
+       }
+
+       if (! notify_get_server_info (&name, &vendor, &version, &spec_version))
+               log_warn ("Failed to get the notification server info. "
+                               "Check if you have a notification daemon running.");
+       else {
+               log_info ("Found notification daemon: %s (%s) %s (spec version %s)",
+                               name, vendor, version, spec_version);
+               free (name);
+               free (vendor);
+               free (version);
+               free (spec_version);
+       }
+
+       plugin_register_notification ("notify_desktop", c_notify);
+       plugin_register_shutdown ("notify_desktop", c_notify_shutdown);
+       return 0;
+} /* c_notify_init */
+
+void module_register (void)
+{
+       plugin_register_complex_config ("notify_desktop", c_notify_config);
+       plugin_register_init ("notify_desktop", c_notify_init);
+       return;
+} /* module_register */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
+
diff --git a/src/notify_email.c b/src/notify_email.c
new file mode 100644 (file)
index 0000000..dc4e47f
--- /dev/null
@@ -0,0 +1,287 @@
+/**
+ * collectd - src/notify_email.c
+ * Copyright (C) 2008  Oleg King
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Oleg King <king2 at kaluga.ru>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#include <auth-client.h>
+#include <libesmtp.h>
+
+#define MAXSTRING               256
+
+static const char *config_keys[] =
+{
+  "SMTPServer",
+  "SMTPPort",
+  "SMTPUser",
+  "SMTPPassword",
+  "From",
+  "Recipient",
+  "Subject"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static char **recipients;
+static int recipients_len = 0;
+
+static smtp_session_t session;
+static smtp_message_t message;
+static auth_context_t authctx = NULL;
+
+static int smtp_port = 25;
+static char *smtp_host = NULL;
+static char *smtp_user = NULL;
+static char *smtp_password = NULL;
+static char *email_from = NULL;
+static char *email_subject = NULL;
+
+#define DEFAULT_SMTP_HOST      "localhost"
+#define DEFAULT_SMTP_FROM      "root@localhost"
+#define DEFAULT_SMTP_SUBJECT   "Collectd notify: %s@%s"
+
+/* Callback to get username and password */
+static int authinteract (auth_client_request_t request, char **result,
+    int fields, void *arg)
+{               
+  int i;
+  for (i = 0; i < fields; i++)
+  {
+    if (request[i].flags & AUTH_USER)
+      result[i] = smtp_user;
+    else if (request[i].flags & AUTH_PASS)
+      result[i] = smtp_password;
+    else
+      return 0;
+  }
+  return 1;
+} /* int authinteract */
+
+/* Callback to print the recipient status */
+static void print_recipient_status (smtp_recipient_t recipient,
+    const char *mailbox, void *arg)
+{
+  const smtp_status_t *status;
+
+  status = smtp_recipient_status (recipient);
+  if (status->text[strlen(status->text) - 2] == '\r')
+    status->text[strlen(status->text) - 2] = 0;
+  INFO ("notify_email: notify sent to %s: %d %s", mailbox, status->code,
+      status->text);
+} /* void print_recipient_status */
+
+/* Callback to monitor SMTP activity */
+static void monitor_cb (const char *buf, int buflen, int writing, void *arg)
+{
+  char log_str[MAXSTRING];
+
+  sstrncpy (log_str, buf, sizeof (log_str));
+  if (buflen > 2)
+    log_str[buflen - 2] = 0; /* replace \n with \0 */
+
+  if (writing == SMTP_CB_HEADERS) {
+    DEBUG ("notify_email plugin: SMTP --- H: %s", log_str);
+    return;
+  }
+  DEBUG (writing
+      ? "notify_email plugin: SMTP >>> C: %s"
+      : "notify_email plugin: SMTP <<< S: %s",
+      log_str);
+} /* void monitor_cb */
+
+static int notify_email_init (void)
+{
+  char server[MAXSTRING];
+
+  auth_client_init();
+  if (!(session = smtp_create_session ())) {
+    ERROR ("notify_email plugin: cannot create SMTP session");
+    return (-1);
+  }
+
+  smtp_set_monitorcb (session, monitor_cb, NULL, 1);
+  smtp_set_hostname (session, hostname_g);
+  ssnprintf(server, sizeof (server), "%s:%i",
+      (smtp_host == NULL) ? DEFAULT_SMTP_HOST : smtp_host,
+      smtp_port);
+  smtp_set_server (session, server);
+
+  if (smtp_user && smtp_password) {
+    authctx = auth_create_context ();
+    auth_set_mechanism_flags (authctx, AUTH_PLUGIN_PLAIN, 0);
+    auth_set_interact_cb (authctx, authinteract, NULL);
+  }
+
+  if ( !smtp_auth_set_context (session, authctx)) {
+    ERROR ("notify_email plugin: cannot set SMTP auth context");
+    return (-1);   
+  }
+
+  return (0);
+} /* int notify_email_init */
+
+static int notify_email_shutdown (void)
+{
+  smtp_destroy_session (session);
+  auth_destroy_context (authctx);
+  auth_client_exit();
+  return (0);
+} /* int notify_email_shutdown */
+
+static int notify_email_config (const char *key, const char *value)
+{
+  if (strcasecmp (key, "Recipient") == 0)
+  {
+    char **tmp;
+
+    tmp = (char **) realloc ((void *) recipients, (recipients_len + 1) * sizeof (char *));
+    if (tmp == NULL) {
+      ERROR ("notify_email: realloc failed.");
+      return (-1);
+    }
+
+    recipients = tmp;
+    recipients[recipients_len] = strdup (value);
+    if (recipients[recipients_len] == NULL) {
+      ERROR ("notify_email: strdup failed.");
+      return (-1);
+    }
+    recipients_len++;
+  }
+  else if (0 == strcasecmp (key, "SMTPServer")) {
+    sfree (smtp_host);
+    smtp_host = strdup (value);
+  }
+  else if (0 == strcasecmp (key, "SMTPPort")) {
+    int port_tmp = atoi (value);
+    if (port_tmp < 1 || port_tmp > 65535)
+    {
+      WARNING ("notify_email plugin: Invalid SMTP port: %i", port_tmp);
+      return (1);
+    }
+    smtp_port = port_tmp;
+  }
+  else if (0 == strcasecmp (key, "SMTPUser")) {
+    sfree (smtp_user);
+    smtp_user = strdup (value);
+  }
+  else if (0 == strcasecmp (key, "SMTPPassword")) {
+    sfree (smtp_password);
+    smtp_password = strdup (value);
+  }
+  else if (0 == strcasecmp (key, "From")) {
+    sfree (email_from);
+    email_from = strdup (value);
+  }
+  else if (0 == strcasecmp (key, "Subject")) {
+    sfree (email_subject);
+    email_subject = strdup (value);
+  }
+  else {
+    return -1;
+  }
+  return 0;
+} /* int notify_email_config (const char *, const char *) */
+
+static int notify_email_notification (const notification_t *n)
+{
+  smtp_recipient_t recipient;
+
+  struct tm timestamp_tm;
+  char timestamp_str[64];
+
+  char severity[32];
+  char subject[MAXSTRING];
+
+  char buf[4096] = "";
+  int  buf_len = sizeof (buf);
+  int i;
+
+  ssnprintf (severity, sizeof (severity), "%s",
+      (n->severity == NOTIF_FAILURE) ? "FAILURE"
+      : ((n->severity == NOTIF_WARNING) ? "WARNING"
+        : ((n->severity == NOTIF_OKAY) ? "OKAY" : "UNKNOWN")));
+
+  ssnprintf (subject, sizeof (subject),
+      (email_subject == NULL) ? DEFAULT_SMTP_SUBJECT : email_subject,
+      severity, n->host);
+
+  localtime_r (&n->time, &timestamp_tm);
+  strftime (timestamp_str, sizeof (timestamp_str), "%Y-%m-%d %H:%M:%S",
+      &timestamp_tm);
+  timestamp_str[sizeof (timestamp_str) - 1] = '\0';
+
+  /* Let's make RFC822 message text with \r\n EOLs */
+  ssnprintf (buf, buf_len,
+      "MIME-Version: 1.0\r\n"
+      "Content-Type: text/plain;\r\n"
+      "Content-Transfer-Encoding: 8bit\r\n"
+      "Subject: %s\r\n"
+      "\r\n"
+      "%s - %s@%s\r\n"
+      "\r\n"
+      "Message: %s",
+      subject,
+      timestamp_str,
+      severity,
+      n->host,
+      n->message);
+
+  if (!(message = smtp_add_message (session))) {
+    ERROR ("notify_email plugin: cannot set SMTP message");
+    return (-1);   
+  }
+  smtp_set_reverse_path (message, email_from);
+  smtp_set_header (message, "To", NULL, NULL);
+  smtp_set_message_str (message, buf);
+
+  for (i = 0; i < recipients_len; i++)
+    recipient = smtp_add_recipient (message, recipients[i]);
+
+  /* Initiate a connection to the SMTP server and transfer the message. */
+  if (!smtp_start_session (session)) {
+    char buf[MAXSTRING];
+    ERROR ("notify_email plugin: SMTP server problem: %s",
+        smtp_strerror (smtp_errno (), buf, sizeof buf));
+    return (-1);
+  } else {
+    const smtp_status_t *status;
+    /* Report on the success or otherwise of the mail transfer. */
+    status = smtp_message_transfer_status (message);
+    DEBUG ("notify_email plugin: SMTP server report: %d %s",
+        status->code, (status->text != NULL) ? status->text : "\n");
+    smtp_enumerate_recipients (message, print_recipient_status, NULL);
+  }
+
+  return (0);
+} /* int notify_email_notification */
+
+void module_register (void)
+{
+  plugin_register_init ("notify_email", notify_email_init);
+  plugin_register_shutdown ("notify_email", notify_email_shutdown);
+  plugin_register_config ("notify_email", notify_email_config,
+      config_keys, config_keys_num);
+  plugin_register_notification ("notify_email", notify_email_notification);
+} /* void module_register (void) */
+
+/* vim: set sw=2 sts=2 ts=8 et : */
index a7ef0fa..44964bb 100644 (file)
@@ -269,11 +269,10 @@ static int ntpd_config (const char *key, const char *value)
        {
                int port = (int) (atof (value));
                if ((port > 0) && (port <= 65535))
-                       snprintf (ntpd_port, sizeof (ntpd_port),
+                       ssnprintf (ntpd_port, sizeof (ntpd_port),
                                        "%i", port);
                else
-                       strncpy (ntpd_port, value, sizeof (ntpd_port));
-               ntpd_port[sizeof (ntpd_port) - 1] = '\0';
+                       sstrncpy (ntpd_port, value, sizeof (ntpd_port));
        }
        else if (strcasecmp (key, "ReverseLookups") == 0)
        {
@@ -305,9 +304,10 @@ static void ntpd_submit (char *type, char *type_inst, double value)
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "ntpd", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
-       strncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
+       sstrncpy (vl.type, type, sizeof (vl.type));
+       sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 }
 
 /* returns `tv0 - tv1' in milliseconds or 0 if `tv1 > tv0' */
@@ -874,7 +874,7 @@ static int ntpd_read (void)
 
                        if (refclock_id < refclock_names_num)
                        {
-                               strncpy (peername, refclock_names[refclock_id],
+                               sstrncpy (peername, refclock_names[refclock_id],
                                                sizeof (peername));
                        }
                        else
@@ -883,7 +883,7 @@ static int ntpd_read (void)
                                addr_obj.s_addr = ptr->srcadr;
                                addr_str = inet_ntoa (addr_obj);
 
-                               strncpy (peername, addr_str, sizeof (peername));
+                               sstrncpy (peername, addr_str, sizeof (peername));
                        }
                }
                else /* Normal network host. */
index 695d93b..8796d58 100644 (file)
--- a/src/nut.c
+++ b/src/nut.c
@@ -124,20 +124,17 @@ static void nut_submit (nut_ups_t *ups, const char *type,
   vl.values = values;
   vl.values_len = STATIC_ARRAY_SIZE (values);
   vl.time = time (NULL);
-  strncpy (vl.host,
+  sstrncpy (vl.host,
       (strcasecmp (ups->hostname, "localhost") == 0)
       ? hostname_g
       : ups->hostname,
       sizeof (vl.host));
   sstrncpy (vl.plugin, "nut", sizeof (vl.plugin));
-  strncpy (vl.plugin_instance, ups->upsname, sizeof (vl.plugin_instance));
-  strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+  sstrncpy (vl.plugin_instance, ups->upsname, sizeof (vl.plugin_instance));
+  sstrncpy (vl.type, type, sizeof (vl.type));
+  sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-  vl.host[sizeof (vl.host) - 1] = '\0';
-  vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0';
-  vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
-
-  plugin_dispatch_values (type, &vl);
+  plugin_dispatch_values (&vl);
 } /* void nut_submit */
 
 static int nut_read_one (nut_ups_t *ups)
diff --git a/src/onewire.c b/src/onewire.c
new file mode 100644 (file)
index 0000000..dd7f527
--- /dev/null
@@ -0,0 +1,312 @@
+/**
+ * collectd - src/owfs.c
+ * Copyright (C) 2008  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 noris.net>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "utils_ignorelist.h"
+
+#include <owcapi.h>
+
+#define OW_FAMILY_LENGTH 8
+#define OW_FAMILY_MAX_FEATURES 2
+struct ow_family_features_s
+{
+  char family[OW_FAMILY_LENGTH];
+  struct
+  {
+    char filename[DATA_MAX_NAME_LEN];
+    char type[DATA_MAX_NAME_LEN];
+    char type_instance[DATA_MAX_NAME_LEN];
+  } features[OW_FAMILY_MAX_FEATURES];
+  size_t features_num;
+};
+typedef struct ow_family_features_s ow_family_features_t;
+
+/* see http://owfs.sourceforge.net/ow_table.html for a list of families */
+static ow_family_features_t ow_family_features[] =
+{
+  {
+    /* family = */ "10.",
+    {
+      {
+        /* filename = */ "temperature",
+        /* type = */ "temperature",
+        /* type_instance = */ ""
+      }
+    },
+    /* features_num = */ 1
+  }
+};
+static int ow_family_features_num = STATIC_ARRAY_SIZE (ow_family_features);
+
+static char *device_g = NULL;
+
+static const char *config_keys[] =
+{
+  "Device",
+  "IgnoreSelected",
+  "Sensor",
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static ignorelist_t *sensor_list;
+
+static int cow_load_config (const char *key, const char *value)
+{
+  if (sensor_list == NULL)
+    sensor_list = ignorelist_create (1);
+
+  if (strcasecmp (key, "Sensor") == 0)
+  {
+    if (ignorelist_add (sensor_list, value))
+    {
+      ERROR ("sensors plugin: "
+          "Cannot add value to ignorelist.");
+      return (1);
+    }
+  }
+  else if (strcasecmp (key, "IgnoreSelected") == 0)
+  {
+    ignorelist_set_invert (sensor_list, 1);
+    if ((strcasecmp (value, "True") == 0)
+        || (strcasecmp (value, "Yes") == 0)
+        || (strcasecmp (value, "On") == 0))
+      ignorelist_set_invert (sensor_list, 0);
+  }
+  else if (strcasecmp (key, "Device") == 0)
+  {
+    char *temp;
+    temp = strdup (value);
+    if (temp == NULL)
+    {
+      ERROR ("onewire plugin: strdup failed.");
+      return (1);
+    }
+    sfree (device_g);
+    device_g = temp;
+  }
+  else
+  {
+    return (-1);
+  }
+
+  return (0);
+}
+
+static int cow_init (void)
+{
+  int status;
+
+  if (device_g == NULL)
+  {
+    ERROR ("onewire plugin: cow_init: No device configured.");
+    return (-1);
+  }
+
+  status = (int) OW_init (device_g);
+  if (status != 0)
+  {
+    ERROR ("onewire plugin: OW_init(%s) failed: %i.", device_g, status);
+    return (1);
+  }
+
+  return (0);
+} /* int cow_init */
+
+static int cow_read_values (const char *path, const char *name,
+    const ow_family_features_t *family_info)
+{
+  value_t values[1];
+  value_list_t vl = VALUE_LIST_INIT;
+  int success = 0;
+  size_t i;
+
+  if (sensor_list != NULL)
+  {
+    DEBUG ("onewire plugin: Checking ignorelist for `%s'", name);
+    if (ignorelist_match (sensor_list, name) != 0)
+      return 0;
+  }
+
+  vl.values = values;
+  vl.values_len = 1;
+  vl.time = time (NULL);
+
+  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+  sstrncpy (vl.plugin, "onewire", sizeof (vl.plugin));
+  sstrncpy (vl.plugin_instance, name, sizeof (vl.plugin_instance));
+
+  for (i = 0; i < family_info->features_num; i++)
+  {
+    char *buffer;
+    size_t buffer_size;
+    int status;
+
+    char file[4096];
+    char *endptr;
+
+    snprintf (file, sizeof (file), "%s/%s",
+        path, family_info->features[i].filename);
+    file[sizeof (file) - 1] = 0;
+
+    buffer = NULL;
+    buffer_size = 0;
+    status = OW_get (file, &buffer, &buffer_size);
+    if (status < 0)
+    {
+      ERROR ("onewire plugin: OW_get (%s/%s) failed. status = %#x;",
+          path, family_info->features[i].filename, status);
+      return (-1);
+    }
+
+    endptr = NULL;
+    values[0].gauge = strtod (buffer, &endptr);
+    if (endptr == NULL)
+    {
+      ERROR ("onewire plugin: Buffer is not a number: %s", buffer);
+      status = -1;
+      continue;
+    }
+
+    sstrncpy (vl.type, family_info->features[i].type, sizeof (vl.type));
+    sstrncpy (vl.type_instance, family_info->features[i].type_instance,
+        sizeof (vl.type_instance));
+
+    plugin_dispatch_values (&vl);
+    success++;
+
+    free (buffer);
+  } /* for (i = 0; i < features_num; i++) */
+
+  return ((success > 0) ? 0 : -1);
+} /* int cow_read_values */
+
+/* Forward declaration so the recursion below works */
+static int cow_read_bus (const char *path);
+
+/*
+ * cow_read_ds2409
+ *
+ * Handles:
+ * - DS2409 - MicroLAN Coupler
+ */
+static int cow_read_ds2409 (const char *path)
+{
+  char subpath[4096];
+  int status;
+
+  status = ssnprintf (subpath, sizeof (subpath), "%s/main", path);
+  if ((status > 0) && (status < sizeof (subpath)))
+    cow_read_bus (subpath);
+
+  status = ssnprintf (subpath, sizeof (subpath), "%s/aux", path);
+  if ((status > 0) && (status < sizeof (subpath)))
+    cow_read_bus (subpath);
+
+  return (0);
+} /* int cow_read_ds2409 */
+
+static int cow_read_bus (const char *path)
+{
+  char *buffer;
+  size_t buffer_size;
+  int status;
+
+  char *buffer_ptr;
+  char *dummy;
+  char *saveptr;
+  char subpath[4096];
+
+  status = OW_get (path, &buffer, &buffer_size);
+  if (status < 0)
+  {
+    ERROR ("onewire plugin: OW_get (%s) failed. status = %#x;",
+        path, status);
+    return (-1);
+  }
+  DEBUG ("onewire plugin: OW_get (%s) returned: %s",
+      path, buffer);
+
+  dummy = buffer;
+  saveptr = NULL;
+  while ((buffer_ptr = strtok_r (dummy, ",/", &saveptr)) != NULL)
+  {
+    int i;
+
+    dummy = NULL;
+
+    if (strcmp ("/", path) == 0)
+      status = ssnprintf (subpath, sizeof (subpath), "/%s", buffer_ptr);
+    else
+      status = ssnprintf (subpath, sizeof (subpath), "%s/%s",
+          path, buffer_ptr);
+    if ((status <= 0) || (status >= sizeof (subpath)))
+      continue;
+
+    for (i = 0; i < ow_family_features_num; i++)
+    {
+      if (strncmp (ow_family_features[i].family, buffer_ptr,
+            strlen (ow_family_features[i].family)) != 0)
+        continue;
+
+      cow_read_values (subpath,
+          buffer_ptr + strlen (ow_family_features[i].family),
+          ow_family_features + i);
+      break;
+    }
+    if (i < ow_family_features_num)
+      continue;
+
+    /* DS2409 */
+    if (strncmp ("1F.", buffer_ptr, strlen ("1F.")) == 0)
+    {
+      cow_read_ds2409 (subpath);
+      continue;
+    }
+  } /* while (strtok_r) */
+
+  free (buffer);
+  return (0);
+} /* int cow_read_bus */
+
+static int cow_read (void)
+{
+  return (cow_read_bus ("/"));
+} /* int cow_read */
+
+static int cow_shutdown (void)
+{
+  OW_finish ();
+  ignorelist_free (sensor_list);
+  return (0);
+} /* int cow_shutdown */
+
+void module_register (void)
+{
+  plugin_register_init ("onewire", cow_init);
+  plugin_register_read ("onewire", cow_read);
+  plugin_register_shutdown ("onewire", cow_shutdown);
+  plugin_register_config ("onewire", cow_load_config,
+    config_keys, config_keys_num);
+}
+
+/* vim: set sw=2 sts=2 ts=8 et fdm=marker cindent : */
index 3df11a3..343c83a 100644 (file)
@@ -71,6 +71,7 @@
 
 #define PLUGIN_TYPES    7
 
+#define PLUGIN_CONFIG   254
 #define PLUGIN_DATASET  255
 
 #define log_debug(...) DEBUG ("perl: " __VA_ARGS__)
@@ -84,8 +85,7 @@ void boot_DynaLoader (PerlInterpreter *, CV *);
 static XS (Collectd_plugin_register_ds);
 static XS (Collectd_plugin_unregister_ds);
 static XS (Collectd_plugin_dispatch_values);
-static XS (Collectd_plugin_flush_one);
-static XS (Collectd_plugin_flush_all);
+static XS (Collectd__plugin_flush);
 static XS (Collectd_plugin_dispatch_notification);
 static XS (Collectd_plugin_log);
 static XS (Collectd_call_by_name);
@@ -139,8 +139,7 @@ static struct {
        { "Collectd::plugin_register_data_set",   Collectd_plugin_register_ds },
        { "Collectd::plugin_unregister_data_set", Collectd_plugin_unregister_ds },
        { "Collectd::plugin_dispatch_values",     Collectd_plugin_dispatch_values },
-       { "Collectd::plugin_flush_one",           Collectd_plugin_flush_one },
-       { "Collectd::plugin_flush_all",           Collectd_plugin_flush_all },
+       { "Collectd::_plugin_flush",              Collectd__plugin_flush },
        { "Collectd::plugin_dispatch_notification",
                Collectd_plugin_dispatch_notification },
        { "Collectd::plugin_log",                 Collectd_plugin_log },
@@ -160,6 +159,7 @@ struct {
        { "Collectd::TYPE_LOG",        PLUGIN_LOG },
        { "Collectd::TYPE_NOTIF",      PLUGIN_NOTIF },
        { "Collectd::TYPE_FLUSH",      PLUGIN_FLUSH },
+       { "Collectd::TYPE_CONFIG",     PLUGIN_CONFIG },
        { "Collectd::TYPE_DATASET",    PLUGIN_DATASET },
        { "Collectd::DS_TYPE_COUNTER", DS_TYPE_COUNTER },
        { "Collectd::DS_TYPE_GAUGE",   DS_TYPE_GAUGE },
@@ -216,8 +216,7 @@ static int hv2data_source (pTHX_ HV *hash, data_source_t *ds)
                return -1;
 
        if (NULL != (tmp = hv_fetch (hash, "name", 4, 0))) {
-               strncpy (ds->name, SvPV_nolen (*tmp), DATA_MAX_NAME_LEN);
-               ds->name[DATA_MAX_NAME_LEN - 1] = '\0';
+               sstrncpy (ds->name, SvPV_nolen (*tmp), sizeof (ds->name));
        }
        else {
                log_err ("hv2data_source: No DS name given.");
@@ -379,6 +378,10 @@ static int value_list2hv (pTHX_ value_list_t *vl, data_set_t *ds, HV *hash)
                                newSVpv (vl->plugin_instance, 0), 0))
                        return -1;
 
+       if ('\0' != vl->type[0])
+               if (NULL == hv_store (hash, "type", 4, newSVpv (vl->type, 0), 0))
+                       return -1;
+
        if ('\0' != vl->type_instance[0])
                if (NULL == hv_store (hash, "type_instance", 13,
                                newSVpv (vl->type_instance, 0), 0))
@@ -423,6 +426,81 @@ static int notification2hv (pTHX_ notification_t *n, HV *hash)
        return 0;
 } /* static int notification2hv (notification_t *, HV *) */
 
+static int oconfig_item2hv (pTHX_ oconfig_item_t *ci, HV *hash)
+{
+       int i;
+
+       AV *values;
+       AV *children;
+
+       if (NULL == hv_store (hash, "key", 3, newSVpv (ci->key, 0), 0))
+               return -1;
+
+       values = newAV ();
+       if (0 < ci->values_num)
+               av_extend (values, ci->values_num);
+
+       if (NULL == hv_store (hash, "values", 6, newRV_noinc ((SV *)values), 0)) {
+               av_clear (values);
+               av_undef (values);
+               return -1;
+       }
+
+       for (i = 0; i < ci->values_num; ++i) {
+               SV *value;
+
+               switch (ci->values[i].type) {
+                       case OCONFIG_TYPE_STRING:
+                               value = newSVpv (ci->values[i].value.string, 0);
+                               break;
+                       case OCONFIG_TYPE_NUMBER:
+                               value = newSVnv ((NV)ci->values[i].value.number);
+                               break;
+                       case OCONFIG_TYPE_BOOLEAN:
+                               value = ci->values[i].value.boolean ? &PL_sv_yes : &PL_sv_no;
+                               break;
+                       default:
+                               log_err ("oconfig_item2hv: Invalid value type %i.",
+                                               ci->values[i].type);
+                               value = &PL_sv_undef;
+               }
+
+               if (NULL == av_store (values, i, value)) {
+                       sv_free (value);
+                       return -1;
+               }
+       }
+
+       /* ignoring 'parent' member which is uninteresting in this case */
+
+       children = newAV ();
+       if (0 < ci->children_num)
+               av_extend (children, ci->children_num);
+
+       if (NULL == hv_store (hash, "children", 8, newRV_noinc ((SV *)children), 0)) {
+               av_clear (children);
+               av_undef (children);
+               return -1;
+       }
+
+       for (i = 0; i < ci->children_num; ++i) {
+               HV *child = newHV ();
+
+               if (0 != oconfig_item2hv (aTHX_ ci->children + i, child)) {
+                       hv_clear (child);
+                       hv_undef (child);
+                       return -1;
+               }
+
+               if (NULL == av_store (children, i, newRV_noinc ((SV *)child))) {
+                       hv_clear (child);
+                       hv_undef (child);
+                       return -1;
+               }
+       }
+       return 0;
+} /* static int oconfig_item2hv (pTHX_ oconfig_item_t *, HV *) */
+
 /*
  * Internal functions.
  */
@@ -430,12 +508,11 @@ static int notification2hv (pTHX_ notification_t *n, HV *hash)
 static char *get_module_name (char *buf, size_t buf_len, const char *module) {
        int status = 0;
        if (base_name[0] == '\0')
-               status = snprintf (buf, buf_len, "%s", module);
+               status = ssnprintf (buf, buf_len, "%s", module);
        else
-               status = snprintf (buf, buf_len, "%s::%s", base_name, module);
+               status = ssnprintf (buf, buf_len, "%s::%s", base_name, module);
        if ((status < 0) || ((unsigned int)status >= buf_len))
                return (NULL);
-       buf[buf_len - 1] = '\0';
        return (buf);
 } /* char *get_module_name */
 
@@ -481,8 +558,7 @@ static int pplugin_register_data_set (pTHX_ char *name, AV *dataset)
                                ds[i].name, ds[i].type, ds[i].min, ds[i].max);
        }
 
-       strncpy (set->type, name, DATA_MAX_NAME_LEN);
-       set->type[DATA_MAX_NAME_LEN - 1] = '\0';
+       sstrncpy (set->type, name, sizeof (set->type));
 
        set->ds_num = len + 1;
        set->ds = ds;
@@ -517,7 +593,7 @@ static int pplugin_unregister_data_set (char *name)
  *   type_instance   => $tinstance,
  * }
  */
-static int pplugin_dispatch_values (pTHX_ char *name, HV *values)
+static int pplugin_dispatch_values (pTHX_ HV *values)
 {
        value_list_t list = VALUE_LIST_INIT;
        value_t      *val = NULL;
@@ -526,9 +602,16 @@ static int pplugin_dispatch_values (pTHX_ char *name, HV *values)
 
        int ret = 0;
 
-       if ((NULL == name) || (NULL == values))
+       if (NULL == values)
                return -1;
 
+       if (NULL == (tmp = hv_fetch (values, "type", 4, 0))) {
+               log_err ("pplugin_dispatch_values: No type given.");
+               return -1;
+       }
+
+       sstrncpy (list.type, SvPV_nolen (*tmp), sizeof (list.type));
+
        if ((NULL == (tmp = hv_fetch (values, "values", 6, 0)))
                        || (! (SvROK (*tmp) && (SVt_PVAV == SvTYPE (SvRV (*tmp)))))) {
                log_err ("pplugin_dispatch_values: No valid values given.");
@@ -544,7 +627,8 @@ static int pplugin_dispatch_values (pTHX_ char *name, HV *values)
 
                val = (value_t *)smalloc (len * sizeof (value_t));
 
-               list.values_len = av2value (aTHX_ name, (AV *)SvRV (*tmp), val, len);
+               list.values_len = av2value (aTHX_ list.type, (AV *)SvRV (*tmp),
+                               val, len);
                list.values = val;
 
                if (-1 == list.values_len) {
@@ -561,29 +645,24 @@ static int pplugin_dispatch_values (pTHX_ char *name, HV *values)
        }
 
        if (NULL != (tmp = hv_fetch (values, "host", 4, 0))) {
-               strncpy (list.host, SvPV_nolen (*tmp), DATA_MAX_NAME_LEN);
-               list.host[DATA_MAX_NAME_LEN - 1] = '\0';
+               sstrncpy (list.host, SvPV_nolen (*tmp), sizeof (list.host));
        }
        else {
                sstrncpy (list.host, hostname_g, sizeof (list.host));
        }
 
-       if (NULL != (tmp = hv_fetch (values, "plugin", 6, 0))) {
-               strncpy (list.plugin, SvPV_nolen (*tmp), DATA_MAX_NAME_LEN);
-               list.plugin[DATA_MAX_NAME_LEN - 1] = '\0';
-       }
+       if (NULL != (tmp = hv_fetch (values, "plugin", 6, 0)))
+               sstrncpy (list.plugin, SvPV_nolen (*tmp), sizeof (list.plugin));
 
-       if (NULL != (tmp = hv_fetch (values, "plugin_instance", 15, 0))) {
-               strncpy (list.plugin_instance, SvPV_nolen (*tmp), DATA_MAX_NAME_LEN);
-               list.plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
-       }
+       if (NULL != (tmp = hv_fetch (values, "plugin_instance", 15, 0)))
+               sstrncpy (list.plugin_instance, SvPV_nolen (*tmp),
+                               sizeof (list.plugin_instance));
 
-       if (NULL != (tmp = hv_fetch (values, "type_instance", 13, 0))) {
-               strncpy (list.type_instance, SvPV_nolen (*tmp), DATA_MAX_NAME_LEN);
-               list.type_instance[DATA_MAX_NAME_LEN - 1] = '\0';
-       }
+       if (NULL != (tmp = hv_fetch (values, "type_instance", 13, 0)))
+               sstrncpy (list.type_instance, SvPV_nolen (*tmp),
+                               sizeof (list.type_instance));
 
-       ret = plugin_dispatch_values (name, &list);
+       ret = plugin_dispatch_values (&list);
 
        sfree (val);
        return ret;
@@ -626,31 +705,25 @@ static int pplugin_dispatch_notification (pTHX_ HV *notif)
                n.time = time (NULL);
 
        if (NULL != (tmp = hv_fetch (notif, "message", 7, 0)))
-               strncpy (n.message, SvPV_nolen (*tmp), sizeof (n.message));
-       n.message[sizeof (n.message) - 1] = '\0';
+               sstrncpy (n.message, SvPV_nolen (*tmp), sizeof (n.message));
 
        if (NULL != (tmp = hv_fetch (notif, "host", 4, 0)))
-               strncpy (n.host, SvPV_nolen (*tmp), sizeof (n.host));
+               sstrncpy (n.host, SvPV_nolen (*tmp), sizeof (n.host));
        else
-               strncpy (n.host, hostname_g, sizeof (n.host));
-       n.host[sizeof (n.host) - 1] = '\0';
+               sstrncpy (n.host, hostname_g, sizeof (n.host));
 
        if (NULL != (tmp = hv_fetch (notif, "plugin", 6, 0)))
-               strncpy (n.plugin, SvPV_nolen (*tmp), sizeof (n.plugin));
-       n.plugin[sizeof (n.plugin) - 1] = '\0';
+               sstrncpy (n.plugin, SvPV_nolen (*tmp), sizeof (n.plugin));
 
        if (NULL != (tmp = hv_fetch (notif, "plugin_instance", 15, 0)))
-               strncpy (n.plugin_instance, SvPV_nolen (*tmp),
+               sstrncpy (n.plugin_instance, SvPV_nolen (*tmp),
                                sizeof (n.plugin_instance));
-       n.plugin_instance[sizeof (n.plugin_instance) - 1] = '\0';
 
        if (NULL != (tmp = hv_fetch (notif, "type", 4, 0)))
-               strncpy (n.type, SvPV_nolen (*tmp), sizeof (n.type));
-       n.type[sizeof (n.type) - 1] = '\0';
+               sstrncpy (n.type, SvPV_nolen (*tmp), sizeof (n.type));
 
        if (NULL != (tmp = hv_fetch (notif, "type_instance", 13, 0)))
-               strncpy (n.type_instance, SvPV_nolen (*tmp), sizeof (n.type_instance));
-       n.type_instance[sizeof (n.type_instance) - 1] = '\0';
+               sstrncpy (n.type_instance, SvPV_nolen (*tmp), sizeof (n.type_instance));
        return plugin_dispatch_notification (&n);
 } /* static int pplugin_dispatch_notification (HV *) */
 
@@ -699,6 +772,7 @@ static int pplugin_call_all (pTHX_ int type, ...)
                 *   time   => $time,
                 *   host   => $hostname,
                 *   plugin => $plugin,
+                *   type   => $type,
                 *   plugin_instance => $instance,
                 *   type_instance   => $type_instance
                 * };
@@ -770,8 +844,10 @@ static int pplugin_call_all (pTHX_ int type, ...)
        else if (PLUGIN_FLUSH == type) {
                /*
                 * $_[0] = $timeout;
+                * $_[1] = $identifier;
                 */
                XPUSHs (sv_2mortal (newSViv (va_arg (ap, int))));
+               XPUSHs (sv_2mortal (newSVpv (va_arg (ap, char *), 0)));
        }
 
        PUTBACK;
@@ -874,33 +950,43 @@ static XS (Collectd_plugin_unregister_ds)
  */
 static XS (Collectd_plugin_dispatch_values)
 {
-       SV *values = NULL;
+       SV *values     = NULL;
+       int values_idx = 0;
 
        int ret = 0;
 
        dXSARGS;
 
-       if (2 != items) {
-               log_err ("Usage: Collectd::plugin_dispatch_values(name, values)");
+       if (2 == items) {
+               log_warn ("Collectd::plugin_dispatch_values with two arguments "
+                               "is deprecated - pass the type through values->{type}.");
+               values_idx = 1;
+       }
+       else if (1 != items) {
+               log_err ("Usage: Collectd::plugin_dispatch_values(values)");
                XSRETURN_EMPTY;
        }
 
-       log_debug ("Collectd::plugin_dispatch_values: "
-                       "name = \"%s\", values=\"%s\"",
-                       SvPV_nolen (ST (0)), SvPV_nolen (ST (1)));
+       log_debug ("Collectd::plugin_dispatch_values: values=\"%s\"",
+                       SvPV_nolen (ST (values_idx)));
 
-       values = ST (1);
+       values = ST (values_idx);
 
        if (! (SvROK (values) && (SVt_PVHV == SvTYPE (SvRV (values))))) {
                log_err ("Collectd::plugin_dispatch_values: Invalid values.");
                XSRETURN_EMPTY;
        }
 
-       if ((NULL == ST (0)) || (NULL == values))
+       if (((2 == items) && (NULL == ST (0))) || (NULL == values))
+               XSRETURN_EMPTY;
+
+       if ((2 == items) && (NULL == hv_store ((HV *)SvRV (values), "type", 4,
+                       newSVsv (ST (0)), 0))) {
+               log_err ("Collectd::plugin_dispatch_values: Could not store type.");
                XSRETURN_EMPTY;
+       }
 
-       ret = pplugin_dispatch_values (aTHX_ SvPV_nolen (ST (0)),
-                       (HV *)SvRV (values));
+       ret = pplugin_dispatch_values (aTHX_ (HV *)SvRV (values));
 
        if (0 == ret)
                XSRETURN_YES;
@@ -909,52 +995,47 @@ static XS (Collectd_plugin_dispatch_values)
 } /* static XS (Collectd_plugin_dispatch_values) */
 
 /*
- * Collectd::plugin_flush_one (timeout, name).
+ * Collectd::_plugin_flush (plugin, timeout, identifier).
+ *
+ * plugin:
+ *   name of the plugin to flush
  *
  * timeout:
  *   timeout to use when flushing the data
  *
- * name:
- *   name of the plugin to flush
+ * identifier:
+ *   data-set identifier to flush
  */
-static XS (Collectd_plugin_flush_one)
+static XS (Collectd__plugin_flush)
 {
+       char *plugin  = NULL;
+       int   timeout = -1;
+       char *id      = NULL;
+
        dXSARGS;
 
-       if (2 != items) {
-               log_err ("Usage: Collectd::plugin_flush_one(timeout, name)");
+       if (3 != items) {
+               log_err ("Usage: Collectd::_plugin_flush(plugin, timeout, id)");
                XSRETURN_EMPTY;
        }
 
-       log_debug ("Collectd::plugin_flush_one: timeout = %i, name = \"%s\"",
-                       (int)SvIV (ST (0)), SvPV_nolen (ST (1)));
+       if (SvOK (ST (0)))
+               plugin = SvPV_nolen (ST (0));
 
-       if (0 == plugin_flush_one ((int)SvIV (ST (0)), SvPV_nolen (ST (1))))
-               XSRETURN_YES;
-       else
-               XSRETURN_EMPTY;
-} /* static XS (Collectd_plugin_flush_one) */
+       if (SvOK (ST (1)))
+               timeout = (int)SvIV (ST (1));
 
-/*
- * Collectd::plugin_flush_all (timeout).
- *
- * timeout:
- *   timeout to use when flushing the data
- */
-static XS (Collectd_plugin_flush_all)
-{
-       dXSARGS;
-
-       if (1 != items) {
-               log_err ("Usage: Collectd::plugin_flush_all(timeout)");
-               XSRETURN_EMPTY;
-       }
+       if (SvOK (ST (2)))
+               id = SvPV_nolen (ST (2));
 
-       log_debug ("Collectd::plugin_flush_all: timeout = %i", (int)SvIV (ST (0)));
+       log_debug ("Collectd::_plugin_flush: plugin = \"%s\", timeout = %i, "
+                       "id = \"%s\"", plugin, timeout, id);
 
-       plugin_flush_all ((int)SvIV (ST (0)));
-       XSRETURN_YES;
-} /* static XS (Collectd_plugin_flush_all) */
+       if (0 == plugin_flush (plugin, timeout, id))
+               XSRETURN_YES;
+       else
+               XSRETURN_EMPTY;
+} /* static XS (Collectd__plugin_flush) */
 
 /*
  * Collectd::plugin_dispatch_notification (notif).
@@ -1011,7 +1092,7 @@ static XS (Collectd_plugin_log)
                XSRETURN_EMPTY;
        }
 
-       plugin_log (SvIV (ST (0)), SvPV_nolen (ST (1)));
+       plugin_log (SvIV (ST (0)), "%s", SvPV_nolen (ST (1)));
        XSRETURN_YES;
 } /* static XS (Collectd_plugin_log) */
 
@@ -1261,7 +1342,7 @@ static int perl_notify (const notification_t *notif)
        return pplugin_call_all (aTHX_ PLUGIN_NOTIF, notif);
 } /* static int perl_notify (const notification_t *) */
 
-static int perl_flush (const int timeout)
+static int perl_flush (int timeout, const char *identifier)
 {
        dTHX;
 
@@ -1277,7 +1358,7 @@ static int perl_flush (const int timeout)
 
                aTHX = t->interp;
        }
-       return pplugin_call_all (aTHX_ PLUGIN_FLUSH, timeout);
+       return pplugin_call_all (aTHX_ PLUGIN_FLUSH, timeout, identifier);
 } /* static int perl_flush (const int) */
 
 static int perl_shutdown (void)
@@ -1358,8 +1439,7 @@ static int g_pv_get (pTHX_ SV *var, MAGIC *mg)
 static int g_pv_set (pTHX_ SV *var, MAGIC *mg)
 {
        char *pv = mg->mg_ptr;
-       strncpy (pv, SvPV_nolen (var), DATA_MAX_NAME_LEN);
-       pv[DATA_MAX_NAME_LEN - 1] = '\0';
+       sstrncpy (pv, SvPV_nolen (var), DATA_MAX_NAME_LEN);
        return 0;
 } /* static int g_pv_set (pTHX_ SV *, MAGIC *) */
 
@@ -1562,8 +1642,7 @@ static int perl_config_basename (pTHX_ oconfig_item_t *ci)
        value = ci->values[0].value.string;
 
        log_debug ("perl_config: Setting plugin basename to \"%s\"", value);
-       strncpy (base_name, value, sizeof (base_name));
-       base_name[sizeof (base_name) - 1] = '\0';
+       sstrncpy (base_name, value, sizeof (base_name));
        return 0;
 } /* static int perl_config_basename (oconfig_item_it *) */
 
@@ -1646,30 +1725,99 @@ static int perl_config_includedir (pTHX_ oconfig_item_t *ci)
        return 0;
 } /* static int perl_config_includedir (oconfig_item_it *) */
 
+/*
+ * <Plugin> block
+ */
+static int perl_config_plugin (pTHX_ oconfig_item_t *ci)
+{
+       int retvals = 0;
+       int ret     = 0;
+
+       char *plugin;
+       HV   *config;
+
+       dSP;
+
+       if ((1 != ci->values_num) || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+               log_err ("LoadPlugin expects a single string argument.");
+               return 1;
+       }
+
+       plugin = ci->values[0].value.string;
+       config = newHV ();
+
+       if (0 != oconfig_item2hv (aTHX_ ci, config)) {
+               hv_clear (config);
+               hv_undef (config);
+
+               log_err ("Unable to convert configuration to a Perl hash value.");
+               config = Nullhv;
+       }
+
+       ENTER;
+       SAVETMPS;
+
+       PUSHMARK (SP);
+
+       XPUSHs (sv_2mortal (newSVpv (plugin, 0)));
+       XPUSHs (sv_2mortal (newRV_noinc ((SV *)config)));
+
+       PUTBACK;
+
+       retvals = call_pv ("Collectd::_plugin_dispatch_config", G_SCALAR);
+
+       SPAGAIN;
+       if (0 < retvals) {
+               SV *tmp = POPs;
+               if (! SvTRUE (tmp))
+                       ret = 1;
+       }
+       else
+               ret = 1;
+
+       PUTBACK;
+       FREETMPS;
+       LEAVE;
+       return ret;
+} /* static int perl_config_plugin (oconfig_item_it *) */
+
 static int perl_config (oconfig_item_t *ci)
 {
+       int status = 0;
        int i = 0;
 
        dTHXa (NULL);
 
        for (i = 0; i < ci->children_num; ++i) {
                oconfig_item_t *c = ci->children + i;
+               int current_status = 0;
 
                if (NULL != perl_threads)
                        aTHX = PERL_GET_CONTEXT;
 
                if (0 == strcasecmp (c->key, "LoadPlugin"))
-                       perl_config_loadplugin (aTHX_ c);
+                       current_status = perl_config_loadplugin (aTHX_ c);
                else if (0 == strcasecmp (c->key, "BaseName"))
-                       perl_config_basename (aTHX_ c);
+                       current_status = perl_config_basename (aTHX_ c);
                else if (0 == strcasecmp (c->key, "EnableDebugger"))
-                       perl_config_enabledebugger (aTHX_ c);
+                       current_status = perl_config_enabledebugger (aTHX_ c);
                else if (0 == strcasecmp (c->key, "IncludeDir"))
-                       perl_config_includedir (aTHX_ c);
+                       current_status = perl_config_includedir (aTHX_ c);
+               else if (0 == strcasecmp (c->key, "Plugin"))
+                       current_status = perl_config_plugin (aTHX_ c);
                else
                        log_warn ("Ignoring unknown config key \"%s\".", c->key);
+
+               /* fatal error - it's up to perl_config_* to clean up */
+               if (0 > current_status) {
+                       log_err ("Configuration failed with a fatal error - "
+                                       "plugin disabled!");
+                       return current_status;
+               }
+
+               status += current_status;
        }
-       return 0;
+       return status;
 } /* static int perl_config (oconfig_item_t *) */
 
 void module_register (void)
index 09de77c..ac5b0f8 100644 (file)
@@ -189,9 +189,10 @@ static void ping_submit (char *host, double latency)
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "ping", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
-       strncpy (vl.type_instance, host, sizeof (vl.type_instance));
+       sstrncpy (vl.type_instance, host, sizeof (vl.type_instance));
+       sstrncpy (vl.type, "ping", sizeof (vl.type));
 
-       plugin_dispatch_values ("ping", &vl);
+       plugin_dispatch_values (&vl);
 }
 
 static int ping_read (void)
index e72561b..a887327 100644 (file)
@@ -21,6 +21,7 @@
  **/
 
 #include "collectd.h"
+#include "utils_complain.h"
 
 #include <ltdl.h>
 
@@ -328,7 +329,8 @@ int plugin_load (const char *type)
 
        /* `cpu' should not match `cpufreq'. To solve this we add `.so' to the
         * type when matching the filename */
-       if (snprintf (typename, BUFSIZE, "%s.so", type) >= BUFSIZE)
+       if (ssnprintf (typename, sizeof (typename),
+                       "%s.so", type) >= sizeof (typename))
        {
                WARNING ("snprintf: truncated: `%s.so'", type);
                return (-1);
@@ -348,7 +350,8 @@ int plugin_load (const char *type)
                if (strncasecmp (de->d_name, typename, typename_len))
                        continue;
 
-               if (snprintf (filename, BUFSIZE, "%s/%s", dir, de->d_name) >= BUFSIZE)
+               if (ssnprintf (filename, sizeof (filename),
+                               "%s/%s", dir, de->d_name) >= sizeof (filename))
                {
                        WARNING ("snprintf: truncated: `%s/%s'", dir, de->d_name);
                        continue;
@@ -439,7 +442,8 @@ int plugin_register_write (const char *name,
        return (register_callback (&list_write, name, (void *) callback));
 } /* int plugin_register_write */
 
-int plugin_register_flush (const char *name, int (*callback) (const int))
+int plugin_register_flush (const char *name,
+               int (*callback) (const int timeout, const char *identifier))
 {
        return (register_callback (&list_flush, name, (void *) callback));
 } /* int plugin_register_flush */
@@ -661,42 +665,31 @@ void plugin_read_all (void)
        pthread_mutex_unlock (&read_lock);
 } /* void plugin_read_all */
 
-int plugin_flush_one (int timeout, const char *name)
+int plugin_flush (const char *plugin, int timeout, const char *identifier)
 {
-       int (*callback) (int);
-       llentry_t *le;
-       int status;
-
-       if (list_flush == NULL)
-               return (-1);
-
-       le = llist_search (list_flush, name);
-       if (le == NULL)
-               return (-1);
-       callback = (int (*) (int)) le->value;
-
-       status = (*callback) (timeout);
-
-       return (status);
-} /* int plugin_flush_ont */
-
-void plugin_flush_all (int timeout)
-{
-       int (*callback) (int);
-       llentry_t *le;
-
-       if (list_flush == NULL)
-               return;
-
-       le = llist_head (list_flush);
-       while (le != NULL)
-       {
-               callback = (int (*) (int)) le->value;
-               le = le->next;
-
-               (*callback) (timeout);
-       }
-} /* void plugin_flush_all */
+  int (*callback) (int timeout, const char *identifier);
+  llentry_t *le;
+
+  if (list_flush == NULL)
+    return (0);
+
+  le = llist_head (list_flush);
+  while (le != NULL)
+  {
+    if ((plugin != NULL)
+        && (strcmp (plugin, le->key) != 0))
+    {
+      le = le->next;
+      continue;
+    }
+
+    callback = (int (*) (int, const char *)) le->value;
+    (*callback) (timeout, identifier);
+
+    le = le->next;
+  }
+  return (0);
+} /* int plugin_flush */
 
 void plugin_shutdown_all (void)
 {
@@ -723,20 +716,25 @@ void plugin_shutdown_all (void)
        }
 } /* void plugin_shutdown_all */
 
-int plugin_dispatch_values (const char *name, value_list_t *vl)
+int plugin_dispatch_values (value_list_t *vl)
 {
+       static c_complain_t no_write_complaint = C_COMPLAIN_INIT;
+
        int (*callback) (const data_set_t *, const value_list_t *);
        data_set_t *ds;
        llentry_t *le;
 
-       if (list_write == NULL)
-       {
-               ERROR ("plugin_dispatch_values: No write callback has been "
-                               "registered. Please load at least one plugin "
-                               "that provides a write function.");
+       if ((vl == NULL) || (*vl->type == '\0')) {
+               ERROR ("plugin_dispatch_values: Invalid value list.");
                return (-1);
        }
 
+       if (list_write == NULL)
+               c_complain_once (LOG_WARNING, &no_write_complaint,
+                               "plugin_dispatch_values: No write callback has been "
+                               "registered. Please load at least one output plugin, "
+                               "if you want the collected data to be stored.");
+
        if (data_sets == NULL)
        {
                ERROR ("plugin_dispatch_values: No data sets registered. "
@@ -745,9 +743,9 @@ int plugin_dispatch_values (const char *name, value_list_t *vl)
                return (-1);
        }
 
-       if (c_avl_get (data_sets, name, (void *) &ds) != 0)
+       if (c_avl_get (data_sets, vl->type, (void *) &ds) != 0)
        {
-               INFO ("plugin_dispatch_values: Dataset not found: %s", name);
+               INFO ("plugin_dispatch_values: Dataset not found: %s", vl->type);
                return (-1);
        }
 
@@ -758,7 +756,15 @@ int plugin_dispatch_values (const char *name, value_list_t *vl)
                        (unsigned int) vl->time, vl->interval,
                        vl->host,
                        vl->plugin, vl->plugin_instance,
-                       ds->type, vl->type_instance);
+                       vl->type, vl->type_instance);
+
+#if COLLECT_DEBUG
+       assert (0 == strcmp (ds->type, vl->type));
+#else
+       if (0 != strcmp (ds->type, vl->type))
+               WARNING ("plugin_dispatch_values: (ds->type = %s) != (vl->type = %s)",
+                               ds->type, vl->type);
+#endif
 
 #if COLLECT_DEBUG
        assert (ds->ds_num == vl->values_len);
@@ -776,6 +782,7 @@ int plugin_dispatch_values (const char *name, value_list_t *vl)
        escape_slashes (vl->host, sizeof (vl->host));
        escape_slashes (vl->plugin, sizeof (vl->plugin));
        escape_slashes (vl->plugin_instance, sizeof (vl->plugin_instance));
+       escape_slashes (vl->type, sizeof (vl->type));
        escape_slashes (vl->type_instance, sizeof (vl->type_instance));
 
        /* Update the value cache */
@@ -864,3 +871,179 @@ const data_set_t *plugin_get_ds (const char *name)
 
        return (ds);
 } /* data_set_t *plugin_get_ds */
+
+static int plugin_notification_meta_add (notification_t *n,
+    const char *name,
+    enum notification_meta_type_e type,
+    const void *value)
+{
+  notification_meta_t *meta;
+  notification_meta_t *tail;
+
+  if ((n == NULL) || (name == NULL) || (value == NULL))
+  {
+    ERROR ("plugin_notification_meta_add: A pointer is NULL!");
+    return (-1);
+  }
+
+  meta = (notification_meta_t *) malloc (sizeof (notification_meta_t));
+  if (meta == NULL)
+  {
+    ERROR ("plugin_notification_meta_add: malloc failed.");
+    return (-1);
+  }
+  memset (meta, 0, sizeof (notification_meta_t));
+
+  sstrncpy (meta->name, name, sizeof (meta->name));
+  meta->type = type;
+
+  switch (type)
+  {
+    case NM_TYPE_STRING:
+    {
+      meta->nm_value.nm_string = strdup ((const char *) value);
+      if (meta->nm_value.nm_string == NULL)
+      {
+        ERROR ("plugin_notification_meta_add: strdup failed.");
+        sfree (meta);
+        return (-1);
+      }
+      break;
+    }
+    case NM_TYPE_SIGNED_INT:
+    {
+      meta->nm_value.nm_signed_int = *((int64_t *) value);
+      break;
+    }
+    case NM_TYPE_UNSIGNED_INT:
+    {
+      meta->nm_value.nm_unsigned_int = *((uint64_t *) value);
+      break;
+    }
+    case NM_TYPE_DOUBLE:
+    {
+      meta->nm_value.nm_double = *((double *) value);
+      break;
+    }
+    case NM_TYPE_BOOLEAN:
+    {
+      meta->nm_value.nm_boolean = *((bool *) value);
+      break;
+    }
+    default:
+    {
+      ERROR ("plugin_notification_meta_add: Unknown type: %i", type);
+      sfree (meta);
+      return (-1);
+    }
+  } /* switch (type) */
+
+  meta->next = NULL;
+  tail = n->meta;
+  while ((tail != NULL) && (tail->next != NULL))
+    tail = tail->next;
+
+  if (tail == NULL)
+    n->meta = meta;
+  else
+    tail->next = meta;
+
+  return (0);
+} /* int plugin_notification_meta_add */
+
+int plugin_notification_meta_add_string (notification_t *n,
+    const char *name,
+    const char *value)
+{
+  return (plugin_notification_meta_add (n, name, NM_TYPE_STRING, value));
+}
+
+int plugin_notification_meta_add_signed_int (notification_t *n,
+    const char *name,
+    int64_t value)
+{
+  return (plugin_notification_meta_add (n, name, NM_TYPE_SIGNED_INT, &value));
+}
+
+int plugin_notification_meta_add_unsigned_int (notification_t *n,
+    const char *name,
+    uint64_t value)
+{
+  return (plugin_notification_meta_add (n, name, NM_TYPE_UNSIGNED_INT, &value));
+}
+
+int plugin_notification_meta_add_double (notification_t *n,
+    const char *name,
+    double value)
+{
+  return (plugin_notification_meta_add (n, name, NM_TYPE_DOUBLE, &value));
+}
+
+int plugin_notification_meta_add_boolean (notification_t *n,
+    const char *name,
+    bool value)
+{
+  return (plugin_notification_meta_add (n, name, NM_TYPE_BOOLEAN, &value));
+}
+
+int plugin_notification_meta_copy (notification_t *dst,
+    const notification_t *src)
+{
+  notification_meta_t *meta;
+
+  assert (dst != NULL);
+  assert (src != NULL);
+  assert (dst != src);
+  assert ((src->meta == NULL) || (src->meta != dst->meta));
+
+  for (meta = src->meta; meta != NULL; meta = meta->next)
+  {
+    if (meta->type == NM_TYPE_STRING)
+      plugin_notification_meta_add_string (dst, meta->name,
+          meta->nm_value.nm_string);
+    else if (meta->type == NM_TYPE_SIGNED_INT)
+      plugin_notification_meta_add_signed_int (dst, meta->name,
+          meta->nm_value.nm_signed_int);
+    else if (meta->type == NM_TYPE_UNSIGNED_INT)
+      plugin_notification_meta_add_unsigned_int (dst, meta->name,
+          meta->nm_value.nm_unsigned_int);
+    else if (meta->type == NM_TYPE_DOUBLE)
+      plugin_notification_meta_add_double (dst, meta->name,
+          meta->nm_value.nm_double);
+    else if (meta->type == NM_TYPE_BOOLEAN)
+      plugin_notification_meta_add_boolean (dst, meta->name,
+          meta->nm_value.nm_boolean);
+  }
+
+  return (0);
+} /* int plugin_notification_meta_copy */
+
+int plugin_notification_meta_free (notification_t *n)
+{
+  notification_meta_t *this;
+  notification_meta_t *next;
+
+  if (n == NULL)
+  {
+    ERROR ("plugin_notification_meta_free: n == NULL!");
+    return (-1);
+  }
+
+  this = n->meta;
+  n->meta = NULL;
+  while (this != NULL)
+  {
+    next = this->next;
+
+    if (this->type == NM_TYPE_STRING)
+    {
+      free ((char *)this->nm_value.nm_string);
+      this->nm_value.nm_string = NULL;
+    }
+    sfree (this);
+
+    this = next;
+  }
+
+  return (0);
+} /* int plugin_notification_meta_free */
index 318b547..dc3bbb0 100644 (file)
@@ -74,12 +74,13 @@ struct value_list_s
        char     host[DATA_MAX_NAME_LEN];
        char     plugin[DATA_MAX_NAME_LEN];
        char     plugin_instance[DATA_MAX_NAME_LEN];
+       char     type[DATA_MAX_NAME_LEN];
        char     type_instance[DATA_MAX_NAME_LEN];
 };
 typedef struct value_list_s value_list_t;
 
-#define VALUE_LIST_INIT { NULL, 0, 0, interval_g, "localhost", "", "", "" }
-#define VALUE_LIST_STATIC { NULL, 0, 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
 {
@@ -98,6 +99,30 @@ struct data_set_s
 };
 typedef struct data_set_s data_set_t;
 
+enum notification_meta_type_e
+{
+       NM_TYPE_STRING,
+       NM_TYPE_SIGNED_INT,
+       NM_TYPE_UNSIGNED_INT,
+       NM_TYPE_DOUBLE,
+       NM_TYPE_BOOLEAN
+};
+
+typedef struct notification_meta_s
+{
+       char name[DATA_MAX_NAME_LEN];
+       enum notification_meta_type_e type;
+       union
+       {
+               const char *nm_string;
+               int64_t nm_signed_int;
+               uint64_t nm_unsigned_int;
+               double nm_double;
+               bool nm_boolean;
+       } nm_value;
+       struct notification_meta_s *next;
+} notification_meta_t;
+
 typedef struct notification_s
 {
        int    severity;
@@ -108,6 +133,7 @@ typedef struct notification_s
        char   plugin_instance[DATA_MAX_NAME_LEN];
        char   type[DATA_MAX_NAME_LEN];
        char   type_instance[DATA_MAX_NAME_LEN];
+       notification_meta_t *meta;
 } notification_t;
 
 /*
@@ -150,10 +176,9 @@ int plugin_load (const char *name);
 
 void plugin_init_all (void);
 void plugin_read_all (void);
-void plugin_flush_all (int timeout);
 void plugin_shutdown_all (void);
 
-int plugin_flush_one (int timeout, const char *name);
+int plugin_flush (const char *plugin, int timeout, const char *identifier);
 
 /*
  * The `plugin_register_*' functions are used to make `config', `init',
@@ -172,7 +197,7 @@ int plugin_register_read (const char *name,
 int plugin_register_write (const char *name,
                int (*callback) (const data_set_t *ds, const value_list_t *vl));
 int plugin_register_flush (const char *name,
-               int (*callback) (const int));
+               int (*callback) (const int timeout, const char *identifier));
 int plugin_register_shutdown (char *name,
                int (*callback) (void));
 int plugin_register_data_set (const data_set_t *ds);
@@ -204,11 +229,10 @@ int plugin_unregister_notification (const char *name);
  *  write-functions.
  *
  * ARGUMENTS
- *  `name'      Name/type of the data-set that describe the values in `vl'.
  *  `vl'        Value list of the values that have been read by a `read'
  *              function.
  */
-int plugin_dispatch_values (const char *name, value_list_t *vl);
+int plugin_dispatch_values (value_list_t *vl);
 
 int plugin_dispatch_notification (const notification_t *notif);
 
@@ -227,4 +251,25 @@ void plugin_log (int level, const char *format, ...)
 
 const data_set_t *plugin_get_ds (const char *name);
 
+int plugin_notification_meta_add_string (notification_t *n,
+    const char *name,
+    const char *value);
+int plugin_notification_meta_add_signed_int (notification_t *n,
+    const char *name,
+    int64_t value);
+int plugin_notification_meta_add_unsigned_int (notification_t *n,
+    const char *name,
+    uint64_t value);
+int plugin_notification_meta_add_double (notification_t *n,
+    const char *name,
+    double value);
+int plugin_notification_meta_add_boolean (notification_t *n,
+    const char *name,
+    bool value);
+
+int plugin_notification_meta_copy (notification_t *dst,
+    const notification_t *src);
+
+int plugin_notification_meta_free (notification_t *n);
+
 #endif /* PLUGIN_H */
diff --git a/src/postgresql.c b/src/postgresql.c
new file mode 100644 (file)
index 0000000..faad16c
--- /dev/null
@@ -0,0 +1,906 @@
+/**
+ * collectd - src/postgresql.c
+ * Copyright (C) 2008  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>
+ **/
+
+/*
+ * This module collects PostgreSQL database statistics.
+ */
+
+#include "collectd.h"
+#include "common.h"
+
+#include "configfile.h"
+#include "plugin.h"
+
+#include "utils_complain.h"
+
+#include <pg_config_manual.h>
+#include <libpq-fe.h>
+
+#define log_err(...) ERROR ("postgresql: " __VA_ARGS__)
+#define log_warn(...) WARNING ("postgresql: " __VA_ARGS__)
+#define log_info(...) INFO ("postgresql: " __VA_ARGS__)
+
+#ifndef C_PSQL_DEFAULT_CONF
+# define C_PSQL_DEFAULT_CONF PKGDATADIR "/postgresql_default.conf"
+#endif
+
+/* Appends the (parameter, value) pair to the string
+ * pointed to by 'buf' suitable to be used as argument
+ * for PQconnectdb(). If value equals NULL, the pair
+ * is ignored. */
+#define C_PSQL_PAR_APPEND(buf, buf_len, parameter, value) \
+       if ((0 < (buf_len)) && (NULL != (value)) && ('\0' != *(value))) { \
+               int s = ssnprintf (buf, buf_len, " %s = '%s'", parameter, value); \
+               if (0 < s) { \
+                       buf     += s; \
+                       buf_len -= s; \
+               } \
+       }
+
+/* Returns the tuple (major, minor, patchlevel)
+ * for the given version number. */
+#define C_PSQL_SERVER_VERSION3(server_version) \
+       (server_version) / 10000, \
+       (server_version) / 100 - (int)((server_version) / 10000) * 100, \
+       (server_version) - (int)((server_version) / 100) * 100
+
+/* Returns true if the given host specifies a
+ * UNIX domain socket. */
+#define C_PSQL_IS_UNIX_DOMAIN_SOCKET(host) \
+       ((NULL == (host)) || ('\0' == *(host)) || ('/' == *(host)))
+
+/* Returns the tuple (host, delimiter, port) for a
+ * given (host, port) pair. Depending on the value of
+ * 'host' a UNIX domain socket or a TCP socket is
+ * assumed. */
+#define C_PSQL_SOCKET3(host, port) \
+       ((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, \
+       C_PSQL_IS_UNIX_DOMAIN_SOCKET (host) ? "/.s.PGSQL." : ":", \
+       port
+
+typedef enum {
+       C_PSQL_PARAM_HOST = 1,
+       C_PSQL_PARAM_DB,
+       C_PSQL_PARAM_USER,
+} c_psql_param_t;
+
+typedef struct {
+       char *type;
+       char *type_instance;
+       int   ds_type;
+} c_psql_col_t;
+
+typedef struct {
+       char *name;
+       char *query;
+
+       c_psql_param_t *params;
+       int             params_num;
+
+       c_psql_col_t *cols;
+       int           cols_num;
+
+       int min_pg_version;
+       int max_pg_version;
+} c_psql_query_t;
+
+typedef struct {
+       PGconn      *conn;
+       c_complain_t conn_complaint;
+
+       int proto_version;
+
+       int max_params_num;
+
+       /* user configuration */
+       c_psql_query_t **queries;
+       int              queries_num;
+
+       char *host;
+       char *port;
+       char *database;
+       char *user;
+       char *password;
+
+       char *sslmode;
+
+       char *krbsrvname;
+
+       char *service;
+} c_psql_database_t;
+
+static char *def_queries[] = {
+       "backends",
+       "transactions",
+       "queries",
+       "query_plans",
+       "table_states",
+       "disk_io",
+       "disk_usage"
+};
+static int def_queries_num = STATIC_ARRAY_SIZE (def_queries);
+
+static c_psql_query_t *queries          = NULL;
+static int             queries_num      = 0;
+
+static c_psql_database_t *databases     = NULL;
+static int                databases_num = 0;
+
+static c_psql_query_t *c_psql_query_new (const char *name)
+{
+       c_psql_query_t *query;
+
+       ++queries_num;
+       if (NULL == (queries = (c_psql_query_t *)realloc (queries,
+                               queries_num * sizeof (*queries)))) {
+               log_err ("Out of memory.");
+               exit (5);
+       }
+       query = queries + queries_num - 1;
+
+       query->name  = sstrdup (name);
+       query->query = NULL;
+
+       query->params     = NULL;
+       query->params_num = 0;
+
+       query->cols     = NULL;
+       query->cols_num = 0;
+
+       query->min_pg_version = 0;
+       query->max_pg_version = INT_MAX;
+       return query;
+} /* c_psql_query_new */
+
+static void c_psql_query_delete (c_psql_query_t *query)
+{
+       int i;
+
+       sfree (query->name);
+       sfree (query->query);
+
+       sfree (query->params);
+       query->params_num = 0;
+
+       for (i = 0; i < query->cols_num; ++i) {
+               sfree (query->cols[i].type);
+               sfree (query->cols[i].type_instance);
+       }
+       sfree (query->cols);
+       query->cols_num = 0;
+       return;
+} /* c_psql_query_delete */
+
+static c_psql_query_t *c_psql_query_get (const char *name, int server_version)
+{
+       int i;
+
+       for (i = 0; i < queries_num; ++i)
+               if (0 == strcasecmp (name, queries[i].name)
+                               && ((-1 == server_version)
+                                       || ((queries[i].min_pg_version <= server_version)
+                                               && (server_version <= queries[i].max_pg_version))))
+                       return queries + i;
+       return NULL;
+} /* c_psql_query_get */
+
+static c_psql_database_t *c_psql_database_new (const char *name)
+{
+       c_psql_database_t *db;
+
+       ++databases_num;
+       if (NULL == (databases = (c_psql_database_t *)realloc (databases,
+                               databases_num * sizeof (*databases)))) {
+               log_err ("Out of memory.");
+               exit (5);
+       }
+
+       db = databases + (databases_num - 1);
+
+       db->conn = NULL;
+
+       db->conn_complaint.last     = 0;
+       db->conn_complaint.interval = 0;
+
+       db->proto_version = 0;
+
+       db->max_params_num = 0;
+
+       db->queries     = NULL;
+       db->queries_num = 0;
+
+       db->database   = sstrdup (name);
+       db->host       = NULL;
+       db->port       = NULL;
+       db->user       = NULL;
+       db->password   = NULL;
+
+       db->sslmode    = NULL;
+
+       db->krbsrvname = NULL;
+
+       db->service    = NULL;
+       return db;
+} /* c_psql_database_new */
+
+static void c_psql_database_delete (c_psql_database_t *db)
+{
+       PQfinish (db->conn);
+       db->conn = NULL;
+
+       sfree (db->queries);
+       db->queries_num = 0;
+
+       sfree (db->database);
+       sfree (db->host);
+       sfree (db->port);
+       sfree (db->user);
+       sfree (db->password);
+
+       sfree (db->sslmode);
+
+       sfree (db->krbsrvname);
+
+       sfree (db->service);
+       return;
+} /* c_psql_database_delete */
+
+static void submit (const c_psql_database_t *db,
+               const char *type, const char *type_instance,
+               value_t *values, size_t values_len)
+{
+       value_list_t vl = VALUE_LIST_INIT;
+
+       vl.values     = values;
+       vl.values_len = values_len;
+       vl.time       = time (NULL);
+
+       if (C_PSQL_IS_UNIX_DOMAIN_SOCKET (db->host)
+                       || (0 == strcmp (db->host, "localhost")))
+               sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       else
+               sstrncpy (vl.host, db->host, sizeof (vl.host));
+
+       sstrncpy (vl.plugin, "postgresql", sizeof (vl.plugin));
+       sstrncpy (vl.plugin_instance, db->database, sizeof (vl.plugin_instance));
+
+       sstrncpy (vl.type, type, sizeof (vl.type));
+
+       if (NULL != type_instance)
+               sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+       plugin_dispatch_values (&vl);
+       return;
+} /* submit */
+
+static void submit_counter (const c_psql_database_t *db,
+               const char *type, const char *type_instance,
+               const char *value)
+{
+       value_t values[1];
+
+       if ((NULL == value) || ('\0' == *value))
+               return;
+
+       values[0].counter = atoll (value);
+       submit (db, type, type_instance, values, 1);
+       return;
+} /* submit_counter */
+
+static void submit_gauge (const c_psql_database_t *db,
+               const char *type, const char *type_instance,
+               const char *value)
+{
+       value_t values[1];
+
+       if ((NULL == value) || ('\0' == *value))
+               return;
+
+       values[0].gauge = atof (value);
+       submit (db, type, type_instance, values, 1);
+       return;
+} /* submit_gauge */
+
+static int c_psql_check_connection (c_psql_database_t *db)
+{
+       /* "ping" */
+       PQclear (PQexec (db->conn, "SELECT 42;"));
+
+       if (CONNECTION_OK != PQstatus (db->conn)) {
+               PQreset (db->conn);
+
+               /* trigger c_release() */
+               if (0 == db->conn_complaint.interval)
+                       db->conn_complaint.interval = 1;
+
+               if (CONNECTION_OK != PQstatus (db->conn)) {
+                       c_complain (LOG_ERR, &db->conn_complaint,
+                                       "Failed to connect to database %s: %s",
+                                       db->database, PQerrorMessage (db->conn));
+                       return -1;
+               }
+
+               db->proto_version = PQprotocolVersion (db->conn);
+               if (3 > db->proto_version)
+                       log_warn ("Protocol version %d does not support parameters.",
+                                       db->proto_version);
+       }
+
+       c_release (LOG_INFO, &db->conn_complaint,
+                       "Successfully reconnected to database %s", PQdb (db->conn));
+       return 0;
+} /* c_psql_check_connection */
+
+static PGresult *c_psql_exec_query_params (c_psql_database_t *db,
+               c_psql_query_t *query)
+{
+       char *params[db->max_params_num];
+       int   i;
+
+       assert (db->max_params_num >= query->params_num);
+
+       for (i = 0; i < query->params_num; ++i) {
+               switch (query->params[i]) {
+                       case C_PSQL_PARAM_HOST:
+                               params[i] = C_PSQL_IS_UNIX_DOMAIN_SOCKET (db->host)
+                                       ? "localhost" : db->host;
+                               break;
+                       case C_PSQL_PARAM_DB:
+                               params[i] = db->database;
+                               break;
+                       case C_PSQL_PARAM_USER:
+                               params[i] = db->user;
+                               break;
+                       default:
+                               assert (0);
+               }
+       }
+
+       return PQexecParams (db->conn, query->query, query->params_num, NULL,
+                       (const char *const *)((0 == query->params_num) ? NULL : params),
+                       NULL, NULL, /* return text data */ 0);
+} /* c_psql_exec_query_params */
+
+static PGresult *c_psql_exec_query_noparams (c_psql_database_t *db,
+               c_psql_query_t *query)
+{
+       return PQexec (db->conn, query->query);
+} /* c_psql_exec_query_noparams */
+
+static int c_psql_exec_query (c_psql_database_t *db, int idx)
+{
+       c_psql_query_t *query;
+       PGresult       *res;
+
+       int rows, cols;
+       int i;
+
+       if (idx >= db->queries_num)
+               return -1;
+
+       query = db->queries[idx];
+
+       if (3 <= db->proto_version)
+               res = c_psql_exec_query_params (db, query);
+       else if (0 == query->params_num)
+               res = c_psql_exec_query_noparams (db, query);
+       else {
+               log_err ("Connection to database \"%s\" does not support parameters "
+                               "(protocol version %d) - cannot execute query \"%s\".",
+                               db->database, db->proto_version, query->name);
+               return -1;
+       }
+
+       if (PGRES_TUPLES_OK != PQresultStatus (res)) {
+               log_err ("Failed to execute SQL query: %s",
+                               PQerrorMessage (db->conn));
+               log_info ("SQL query was: %s", query->query);
+               PQclear (res);
+               return -1;
+       }
+
+       rows = PQntuples (res);
+       if (1 > rows) {
+               PQclear (res);
+               return 0;
+       }
+
+       cols = PQnfields (res);
+       if (query->cols_num != cols) {
+               log_err ("SQL query returned wrong number of fields "
+                               "(expected: %i, got: %i)", query->cols_num, cols);
+               log_info ("SQL query was: %s", query->query);
+               PQclear (res);
+               return -1;
+       }
+
+       for (i = 0; i < rows; ++i) {
+               int j;
+
+               for (j = 0; j < cols; ++j) {
+                       c_psql_col_t col = query->cols[j];
+
+                       char *value = PQgetvalue (res, i, j);
+
+                       if (col.ds_type == DS_TYPE_COUNTER)
+                               submit_counter (db, col.type, col.type_instance, value);
+                       else if (col.ds_type == DS_TYPE_GAUGE)
+                               submit_gauge (db, col.type, col.type_instance, value);
+               }
+       }
+       PQclear (res);
+       return 0;
+} /* c_psql_exec_query */
+
+static int c_psql_read (void)
+{
+       int success = 0;
+       int i;
+
+       for (i = 0; i < databases_num; ++i) {
+               c_psql_database_t *db = databases + i;
+
+               int j;
+
+               assert (NULL != db->database);
+
+               if (0 != c_psql_check_connection (db))
+                       continue;
+
+               for (j = 0; j < db->queries_num; ++j)
+                       c_psql_exec_query (db, j);
+
+               ++success;
+       }
+
+       if (! success)
+               return -1;
+       return 0;
+} /* c_psql_read */
+
+static int c_psql_shutdown (void)
+{
+       int i;
+
+       if ((NULL == databases) || (0 == databases_num))
+               return 0;
+
+       plugin_unregister_read ("postgresql");
+       plugin_unregister_shutdown ("postgresql");
+
+       for (i = 0; i < databases_num; ++i) {
+               c_psql_database_t *db = databases + i;
+               c_psql_database_delete (db);
+       }
+
+       sfree (databases);
+       databases_num = 0;
+
+       for (i = 0; i < queries_num; ++i) {
+               c_psql_query_t *query = queries + i;
+               c_psql_query_delete (query);
+       }
+
+       sfree (queries);
+       queries_num = 0;
+       return 0;
+} /* c_psql_shutdown */
+
+static int c_psql_init (void)
+{
+       int i;
+
+       if ((NULL == databases) || (0 == databases_num))
+               return 0;
+
+       for (i = 0; i < queries_num; ++i) {
+               c_psql_query_t *query = queries + i;
+               int j;
+
+               for (j = 0; j < query->cols_num; ++j) {
+                       c_psql_col_t     *col = query->cols + j;
+                       const data_set_t *ds;
+
+                       ds = plugin_get_ds (col->type);
+                       if (NULL == ds) {
+                               log_err ("Column: Unknown type \"%s\".", col->type);
+                               c_psql_shutdown ();
+                               return -1;
+                       }
+
+                       if (1 != ds->ds_num) {
+                               log_err ("Column: Invalid type \"%s\" - types defining "
+                                               "one data source are supported only (got: %i).",
+                                               col->type, ds->ds_num);
+                               c_psql_shutdown ();
+                               return -1;
+                       }
+
+                       col->ds_type = ds->ds[0].type;
+               }
+       }
+
+       for (i = 0; i < databases_num; ++i) {
+               c_psql_database_t *db = databases + i;
+
+               char  conninfo[4096];
+               char *buf     = conninfo;
+               int   buf_len = sizeof (conninfo);
+               int   status;
+
+               char *server_host;
+               int   server_version;
+
+               int j;
+
+               /* this will happen during reinitialization */
+               if (NULL != db->conn) {
+                       c_psql_check_connection (db);
+                       continue;
+               }
+
+               status = ssnprintf (buf, buf_len, "dbname = '%s'", db->database);
+               if (0 < status) {
+                       buf     += status;
+                       buf_len -= status;
+               }
+
+               C_PSQL_PAR_APPEND (buf, buf_len, "host",       db->host);
+               C_PSQL_PAR_APPEND (buf, buf_len, "port",       db->port);
+               C_PSQL_PAR_APPEND (buf, buf_len, "user",       db->user);
+               C_PSQL_PAR_APPEND (buf, buf_len, "password",   db->password);
+               C_PSQL_PAR_APPEND (buf, buf_len, "sslmode",    db->sslmode);
+               C_PSQL_PAR_APPEND (buf, buf_len, "krbsrvname", db->krbsrvname);
+               C_PSQL_PAR_APPEND (buf, buf_len, "service",    db->service);
+
+               db->conn = PQconnectdb (conninfo);
+               if (0 != c_psql_check_connection (db))
+                       continue;
+
+               db->proto_version = PQprotocolVersion (db->conn);
+
+               server_host    = PQhost (db->conn);
+               server_version = PQserverVersion (db->conn);
+               log_info ("Sucessfully connected to database %s (user %s) "
+                               "at server %s%s%s (server version: %d.%d.%d, "
+                               "protocol version: %d, pid: %d)",
+                               PQdb (db->conn), PQuser (db->conn),
+                               C_PSQL_SOCKET3 (server_host, PQport (db->conn)),
+                               C_PSQL_SERVER_VERSION3 (server_version),
+                               db->proto_version, PQbackendPID (db->conn));
+
+               if (3 > db->proto_version)
+                       log_warn ("Protocol version %d does not support parameters.",
+                                       db->proto_version);
+
+               /* Now that we know the PostgreSQL server version, we can get the
+                * right version of each query definition. */
+               for (j = 0; j < db->queries_num; ++j) {
+                       c_psql_query_t *tmp;
+
+                       tmp = c_psql_query_get (db->queries[j]->name, server_version);
+
+                       if (tmp == db->queries[j])
+                               continue;
+
+                       if (NULL == tmp) {
+                               log_err ("Query \"%s\" not found for server version %i - "
+                                               "please check your configuration.",
+                                               db->queries[j]->name, server_version);
+
+                               if (db->queries_num - j - 1 > 0)
+                                       memmove (db->queries + j, db->queries + j + 1,
+                                                       (db->queries_num - j - 1) * sizeof (*db->queries));
+
+                               --db->queries_num;
+                               --j;
+                               continue;
+                       }
+
+                       db->queries[j] = tmp;
+               }
+       }
+
+       plugin_register_read ("postgresql", c_psql_read);
+       plugin_register_shutdown ("postgresql", c_psql_shutdown);
+       return 0;
+} /* c_psql_init */
+
+static int config_set_s (char *name, char **var, const oconfig_item_t *ci)
+{
+       if ((0 != ci->children_num) || (1 != ci->values_num)
+                       || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+               log_err ("%s expects a single string argument.", name);
+               return 1;
+       }
+
+       sfree (*var);
+       *var = sstrdup (ci->values[0].value.string);
+       return 0;
+} /* config_set_s */
+
+static int config_set_i (char *name, int *var, const oconfig_item_t *ci)
+{
+       if ((0 != ci->children_num) || (1 != ci->values_num)
+                       || (OCONFIG_TYPE_NUMBER != ci->values[0].type)) {
+               log_err ("%s expects a single number argument.", name);
+               return 1;
+       }
+
+       *var = (int)ci->values[0].value.number;
+       return 0;
+} /* config_set_i */
+
+static int config_set_param (c_psql_query_t *query, const oconfig_item_t *ci)
+{
+       c_psql_param_t param;
+       char          *param_str;
+
+       if ((0 != ci->children_num) || (1 != ci->values_num)
+                       || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+               log_err ("Param expects a single string argument.");
+               return 1;
+       }
+
+       param_str = ci->values[0].value.string;
+       if (0 == strcasecmp (param_str, "hostname"))
+               param = C_PSQL_PARAM_HOST;
+       else if (0 == strcasecmp (param_str, "database"))
+               param = C_PSQL_PARAM_DB;
+       else if (0 == strcasecmp (param_str, "username"))
+               param = C_PSQL_PARAM_USER;
+       else {
+               log_err ("Invalid parameter \"%s\".", param_str);
+               return 1;
+       }
+
+       ++query->params_num;
+       if (NULL == (query->params = (c_psql_param_t *)realloc (query->params,
+                               query->params_num * sizeof (*query->params)))) {
+               log_err ("Out of memory.");
+               exit (5);
+       }
+
+       query->params[query->params_num - 1] = param;
+       return 0;
+} /* config_set_param */
+
+static int config_set_column (c_psql_query_t *query, const oconfig_item_t *ci)
+{
+       c_psql_col_t *col;
+
+       int i;
+
+       if ((0 != ci->children_num)
+                       || (1 > ci->values_num) || (2 < ci->values_num)) {
+               log_err ("Column expects either one or two arguments.");
+               return 1;
+       }
+
+       for (i = 0; i < ci->values_num; ++i) {
+               if (OCONFIG_TYPE_STRING != ci->values[i].type) {
+                       log_err ("Column expects either one or two string arguments.");
+                       return 1;
+               }
+       }
+
+       ++query->cols_num;
+       if (NULL == (query->cols = (c_psql_col_t *)realloc (query->cols,
+                               query->cols_num * sizeof (*query->cols)))) {
+               log_err ("Out of memory.");
+               exit (5);
+       }
+
+       col = query->cols + query->cols_num - 1;
+
+       col->ds_type = -1;
+
+       col->type = sstrdup (ci->values[0].value.string);
+       col->type_instance = (2 == ci->values_num)
+               ? sstrdup (ci->values[1].value.string) : NULL;
+       return 0;
+} /* config_set_column */
+
+static int set_query (c_psql_database_t *db, const char *name)
+{
+       c_psql_query_t *query;
+
+       query = c_psql_query_get (name, -1);
+       if (NULL == query) {
+               log_err ("Query \"%s\" not found - please check your configuration.",
+                               name);
+               return 1;
+       }
+
+       ++db->queries_num;
+       if (NULL == (db->queries = (c_psql_query_t **)realloc (db->queries,
+                               db->queries_num * sizeof (*db->queries)))) {
+               log_err ("Out of memory.");
+               exit (5);
+       }
+
+       if (query->params_num > db->max_params_num)
+               db->max_params_num = query->params_num;
+
+       db->queries[db->queries_num - 1] = query;
+       return 0;
+} /* set_query */
+
+static int config_set_query (c_psql_database_t *db, const oconfig_item_t *ci)
+{
+       if ((0 != ci->children_num) || (1 != ci->values_num)
+                       || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+               log_err ("Query expects a single string argument.");
+               return 1;
+       }
+       return set_query (db, ci->values[0].value.string);
+} /* config_set_query */
+
+static int c_psql_config_query (oconfig_item_t *ci)
+{
+       c_psql_query_t *query;
+
+       int i;
+
+       if ((1 != ci->values_num)
+                       || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+               log_err ("<Query> expects a single string argument.");
+               return 1;
+       }
+
+       query = c_psql_query_new (ci->values[0].value.string);
+
+       for (i = 0; i < ci->children_num; ++i) {
+               oconfig_item_t *c = ci->children + i;
+
+               if (0 == strcasecmp (c->key, "Query"))
+                       config_set_s ("Query", &query->query, c);
+               else if (0 == strcasecmp (c->key, "Param"))
+                       config_set_param (query, c);
+               else if (0 == strcasecmp (c->key, "Column"))
+                       config_set_column (query, c);
+               else if (0 == strcasecmp (c->key, "MinPGVersion"))
+                       config_set_i ("MinPGVersion", &query->min_pg_version, c);
+               else if (0 == strcasecmp (c->key, "MaxPGVersion"))
+                       config_set_i ("MaxPGVersion", &query->max_pg_version, c);
+               else
+                       log_warn ("Ignoring unknown config key \"%s\".", c->key);
+       }
+
+       for (i = 0; i < queries_num - 1; ++i) {
+               c_psql_query_t *q = queries + i;
+
+               if ((0 == strcasecmp (q->name, query->name))
+                               && (q->min_pg_version <= query->max_pg_version)
+                               && (query->min_pg_version <= q->max_pg_version)) {
+                       log_err ("Ignoring redefinition (with overlapping version ranges) "
+                                       "of query \"%s\".", query->name);
+                       c_psql_query_delete (query);
+                       --queries_num;
+                       return 1;
+               }
+       }
+
+       if (query->min_pg_version > query->max_pg_version) {
+               log_err ("Query \"%s\": MinPGVersion > MaxPGVersion.",
+                               query->name);
+               c_psql_query_delete (query);
+               --queries_num;
+               return 1;
+       }
+
+       if (NULL == query->query) {
+               log_err ("Query \"%s\" does not include an SQL query string - "
+                               "please check your configuration.", query->name);
+               c_psql_query_delete (query);
+               --queries_num;
+               return 1;
+       }
+       return 0;
+} /* c_psql_config_query */
+
+static int c_psql_config_database (oconfig_item_t *ci)
+{
+       c_psql_database_t *db;
+
+       int i;
+
+       if ((1 != ci->values_num)
+                       || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+               log_err ("<Database> expects a single string argument.");
+               return 1;
+       }
+
+       db = c_psql_database_new (ci->values[0].value.string);
+
+       for (i = 0; i < ci->children_num; ++i) {
+               oconfig_item_t *c = ci->children + i;
+
+               if (0 == strcasecmp (c->key, "Host"))
+                       config_set_s ("Host", &db->host, c);
+               else if (0 == strcasecmp (c->key, "Port"))
+                       config_set_s ("Port", &db->port, c);
+               else if (0 == strcasecmp (c->key, "User"))
+                       config_set_s ("User", &db->user, c);
+               else if (0 == strcasecmp (c->key, "Password"))
+                       config_set_s ("Password", &db->password, c);
+               else if (0 == strcasecmp (c->key, "SSLMode"))
+                       config_set_s ("SSLMode", &db->sslmode, c);
+               else if (0 == strcasecmp (c->key, "KRBSrvName"))
+                       config_set_s ("KRBSrvName", &db->krbsrvname, c);
+               else if (0 == strcasecmp (c->key, "Service"))
+                       config_set_s ("Service", &db->service, c);
+               else if (0 == strcasecmp (c->key, "Query"))
+                       config_set_query (db, c);
+               else
+                       log_warn ("Ignoring unknown config key \"%s\".", c->key);
+       }
+
+       if (NULL == db->queries) {
+               for (i = 0; i < def_queries_num; ++i)
+                       set_query (db, def_queries[i]);
+       }
+       return 0;
+}
+
+static int c_psql_config (oconfig_item_t *ci)
+{
+       static int have_def_config = 0;
+
+       int i;
+
+       if (0 == have_def_config) {
+               oconfig_item_t *c;
+
+               have_def_config = 1;
+
+               c = oconfig_parse_file (C_PSQL_DEFAULT_CONF);
+               if (NULL == c)
+                       log_err ("Failed to read default config ("C_PSQL_DEFAULT_CONF").");
+               else
+                       c_psql_config (c);
+
+               if (NULL == queries)
+                       log_err ("Default config ("C_PSQL_DEFAULT_CONF") did not define "
+                                       "any queries - please check your installation.");
+       }
+
+       for (i = 0; i < ci->children_num; ++i) {
+               oconfig_item_t *c = ci->children + i;
+
+               if (0 == strcasecmp (c->key, "Query"))
+                       c_psql_config_query (c);
+               else if (0 == strcasecmp (c->key, "Database"))
+                       c_psql_config_database (c);
+               else
+                       log_warn ("Ignoring unknown config key \"%s\".", c->key);
+       }
+       return 0;
+} /* c_psql_config */
+
+void module_register (void)
+{
+       plugin_register_complex_config ("postgresql", c_psql_config);
+       plugin_register_init ("postgresql", c_psql_init);
+} /* module_register */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
+
diff --git a/src/postgresql_default.conf b/src/postgresql_default.conf
new file mode 100644 (file)
index 0000000..61844a0
--- /dev/null
@@ -0,0 +1,93 @@
+# Pre-defined queries of collectd's postgresql plugin.
+
+<Query backends>
+       Query "SELECT count(*) \
+               FROM pg_stat_activity \
+               WHERE datname = $1;"
+
+       Param database
+
+       Column pg_numbackends
+</Query>
+
+<Query transactions>
+       Query "SELECT xact_commit, xact_rollback \
+               FROM pg_stat_database \
+               WHERE datname = $1;"
+
+       Param database
+
+       Column pg_xact commit
+       Column pg_xact rollback
+</Query>
+
+<Query queries>
+       Query "SELECT sum(n_tup_ins), sum(n_tup_upd), sum(n_tup_del) \
+               FROM pg_stat_user_tables;"
+
+       Column pg_n_tup_c ins
+       Column pg_n_tup_c upd
+       Column pg_n_tup_c del
+
+       MaxPGVersion 80299
+</Query>
+
+<Query queries>
+       Query "SELECT sum(n_tup_ins), sum(n_tup_upd), sum(n_tup_del), \
+                       sum(n_tup_hot_upd) \
+               FROM pg_stat_user_tables;"
+
+       Column pg_n_tup_c ins
+       Column pg_n_tup_c upd
+       Column pg_n_tup_c del
+       Column pg_n_tup_c hot_upd
+
+       MinPGVersion 80300
+</Query>
+
+<Query query_plans>
+       Query "SELECT sum(seq_scan), sum(seq_tup_read), \
+                       sum(idx_scan), sum(idx_tup_fetch) \
+               FROM pg_stat_user_tables;"
+
+       Column pg_scan seq
+       Column pg_scan seq_tup_read
+       Column pg_scan idx
+       Column pg_scan idx_tup_fetch
+</Query>
+
+<Query table_states>
+       Query "SELECT sum(n_live_tup), sum(n_dead_tup) \
+               FROM pg_stat_user_tables;"
+
+       Column pg_n_tup_g live
+       Column pg_n_tup_g dead
+
+       MinPGVersion 80300
+</Query>
+
+<Query disk_io>
+       Query "SELECT sum(heap_blks_read), sum(heap_blks_hit), \
+                       sum(idx_blks_read), sum(idx_blks_hit), \
+                       sum(toast_blks_read), sum(toast_blks_hit), \
+                       sum(tidx_blks_read), sum(tidx_blks_hit) \
+               FROM pg_statio_user_tables;"
+
+       Column pg_blks heap_read
+       Column pg_blks heap_hit
+       Column pg_blks idx_read
+       Column pg_blks idx_hit
+       Column pg_blks toast_read
+       Column pg_blks toast_hit
+       Column pg_blks tidx_read
+       Column pg_blks tidx_hit
+</Query>
+
+<Query disk_usage>
+       Query "SELECT pg_database_size($1);"
+
+       Param database
+
+       Column pg_db_size
+</Query>
+
index a0ad3a4..189c46f 100644 (file)
@@ -320,11 +320,12 @@ static void submit (const char *plugin_instance, /* {{{ */
   vl.time = time (NULL);
   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "powerdns", sizeof (vl.plugin));
+  sstrncpy (vl.type, type, sizeof (vl.type));
   if (type_instance != NULL)
     sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
   sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
 
-  plugin_dispatch_values (type, &vl);
+  plugin_dispatch_values (&vl);
 } /* }}} static void submit */
 
 static int powerdns_get_data_dgram (list_item_t *item, /* {{{ */
@@ -349,10 +350,9 @@ static int powerdns_get_data_dgram (list_item_t *item, /* {{{ */
 
   memset (&sa_unix, 0, sizeof (sa_unix));
   sa_unix.sun_family = AF_UNIX;
-  strncpy (sa_unix.sun_path,
+  sstrncpy (sa_unix.sun_path,
       (local_sockpath != NULL) ? local_sockpath : PDNS_LOCAL_SOCKPATH,
       sizeof (sa_unix.sun_path));
-  sa_unix.sun_path[sizeof (sa_unix.sun_path) - 1] = 0;
 
   status = unlink (sa_unix.sun_path);
   if ((status != 0) && (errno != ENOENT))
@@ -860,7 +860,8 @@ static int powerdns_config_add_server (oconfig_item_t *ci) /* {{{ */
     }
 
     item->sockaddr.sun_family = AF_UNIX;
-    sstrncpy (item->sockaddr.sun_path, socket_temp, UNIX_PATH_MAX);
+    sstrncpy (item->sockaddr.sun_path, socket_temp,
+      sizeof (item->sockaddr.sun_path));
 
     e = llentry_create (item->instance, item);
     if (e == NULL)
index c837681..8cf2562 100644 (file)
@@ -1,7 +1,8 @@
 /**
  * collectd - src/processes.c
  * Copyright (C) 2005  Lyonel Vincent
- * Copyright (C) 2006-2007  Florian Forster (Mach code)
+ * Copyright (C) 2006-2008  Florian Forster (Mach code)
+ * Copyright (C) 2008  Oleg King
  *
  * 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
@@ -20,6 +21,7 @@
  * Authors:
  *   Lyonel Vincent <lyonel at ezix.org>
  *   Florian octo Forster <octo at verplant.org>
+ *   Oleg King <king2 at kaluga.ru>
  **/
 
 #include "collectd.h"
 #  endif
 /* #endif KERNEL_LINUX */
 
+#elif HAVE_LIBKVM_GETPROCS
+#  include <kvm.h>
+#  include <sys/user.h>
+#  include <sys/proc.h>
+#  if HAVE_SYS_SYSCTL_H
+#    include <sys/sysctl.h>
+#  endif
+/* #endif HAVE_LIBKVM_GETPROCS */
+
 #else
 # error "No applicable input method."
 #endif
 
+#if HAVE_REGEX_H
+# include <regex.h>
+#endif
+
 #define BUFSIZE 256
 
 static const char *config_keys[] =
 {
        "Process",
-       NULL
+       "ProcessMatch"
 };
-static int config_keys_num = 1;
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
 typedef struct procstat_entry_s
 {
@@ -121,6 +136,9 @@ typedef struct procstat_entry_s
 typedef struct procstat
 {
        char          name[PROCSTAT_NAME_LEN];
+#if HAVE_REGEX_H
+       regex_t *re;
+#endif
 
        unsigned long num_proc;
        unsigned long num_lwp;
@@ -148,22 +166,77 @@ static mach_msg_type_number_t     pset_list_len;
 
 #elif KERNEL_LINUX
 static long pagesize_g;
-#endif /* KERNEL_LINUX */
+/* #endif KERNEL_LINUX */
 
-static void ps_list_register (const char *name)
+#elif HAVE_LIBKVM_GETPROCS
+/* no global variables */
+#endif /* HAVE_LIBKVM_GETPROCS */
+
+/* put name of process from config to list_head_g tree
+   list_head_g is a list of 'procstat_t' structs with
+   processes names we want to watch */
+static void ps_list_register (const char *name, const char *regexp)
 {
        procstat_t *new;
        procstat_t *ptr;
+       int status;
 
-       if ((new = (procstat_t *) malloc (sizeof (procstat_t))) == NULL)
+       new = (procstat_t *) malloc (sizeof (procstat_t));
+       if (new == NULL)
+       {
+               ERROR ("processes plugin: ps_list_register: malloc failed.");
                return;
+       }
        memset (new, 0, sizeof (procstat_t));
-       strncpy (new->name, name, PROCSTAT_NAME_LEN);
+       sstrncpy (new->name, name, sizeof (new->name));
+
+#if HAVE_REGEX_H
+       if (regexp != NULL)
+       {
+               DEBUG ("ProcessMatch: adding \"%s\" as criteria to process %s.", regexp, name);
+               new->re = (regex_t *) malloc (sizeof (regex_t));
+               if (new->re == NULL)
+               {
+                       ERROR ("processes plugin: ps_list_register: malloc failed.");
+                       sfree (new);
+                       return;
+               }
 
+               status = regcomp (new->re, regexp, REG_EXTENDED | REG_NOSUB);
+               if (status != 0)
+               {
+                       DEBUG ("ProcessMatch: compiling the regular expression \"%s\" failed.", regexp);
+                       sfree(new->re);
+                       return;
+               }
+       }
+#else
+       if (regexp != NULL)
+       {
+               ERROR ("processes plugin: ps_list_register: "
+                               "Regular expression \"%s\" found in config "
+                               "file, but support for regular expressions "
+                               "has been dispabled at compile time.",
+                               regexp);
+               sfree (new);
+               return;
+       }
+#endif
+       
        for (ptr = list_head_g; ptr != NULL; ptr = ptr->next)
        {
                if (strcmp (ptr->name, name) == 0)
+               {
+                       WARNING ("processes plugin: You have configured more "
+                                       "than one `Process' or "
+                                       "`ProcessMatch' with the same name. "
+                                       "All but the first setting will be "
+                                       "ignored.");
+                       sfree (new->re);
+                       sfree (new);
                        return;
+               }
+
                if (ptr->next == NULL)
                        break;
        }
@@ -172,20 +245,40 @@ static void ps_list_register (const char *name)
                list_head_g = new;
        else
                ptr->next = new;
-}
+} /* void ps_list_register */
 
-static procstat_t *ps_list_search (const char *name)
+/* try to match name against entry, returns 1 if success */
+static int ps_list_match (const char *name, const char *cmdline, procstat_t *ps)
 {
-       procstat_t *ptr;
+#if HAVE_REGEX_H
+       if (ps->re != NULL)
+       {
+               int status;
+               const char *str;
 
-       for (ptr = list_head_g; ptr != NULL; ptr = ptr->next)
-               if (strcmp (ptr->name, name) == 0)
-                       break;
+               str = cmdline;
+               if ((str == NULL) || (str[0] == 0))
+                       str = name;
 
-       return (ptr);
-}
+               assert (str != NULL);
+
+               status = regexec (ps->re, str,
+                               /* nmatch = */ 0,
+                               /* pmatch = */ NULL,
+                               /* eflags = */ 0);
+               if (status == 0)
+                       return (1);
+       }
+       else
+#endif
+       if (strcmp (ps->name, name) == 0)
+               return (1);
+
+       return (0);
+} /* int ps_list_match */
 
-static void ps_list_add (const char *name, procstat_entry_t *entry)
+/* add process entry to 'instances' of process 'name' (or refresh it) */
+static void ps_list_add (const char *name, const char *cmdline, procstat_entry_t *entry)
 {
        procstat_t *ps;
        procstat_entry_t *pse;
@@ -193,115 +286,119 @@ static void ps_list_add (const char *name, procstat_entry_t *entry)
        if (entry->id == 0)
                return;
 
-       if ((ps = ps_list_search (name)) == NULL)
-               return;
-
-       for (pse = ps->instances; pse != NULL; pse = pse->next)
-               if ((pse->id == entry->id) || (pse->next == NULL))
-                       break;
-
-       if ((pse == NULL) || (pse->id != entry->id))
+       for (ps = list_head_g; ps != NULL; ps = ps->next)
        {
-               procstat_entry_t *new;
+               if ((ps_list_match (name, cmdline, ps)) == 0)
+                       continue;
 
-               new = (procstat_entry_t *) malloc (sizeof (procstat_entry_t));
-               if (new == NULL)
-                       return;
-               memset (new, 0, sizeof (procstat_entry_t));
-               new->id = entry->id;
+               for (pse = ps->instances; pse != NULL; pse = pse->next)
+                       if ((pse->id == entry->id) || (pse->next == NULL))
+                               break;
 
-               if (pse == NULL)
-                       ps->instances = new;
-               else
-                       pse->next = new;
-
-               pse = new;
-       }
+               if ((pse == NULL) || (pse->id != entry->id))
+               {
+                       procstat_entry_t *new;
+                       
+                       new = (procstat_entry_t *) malloc (sizeof (procstat_entry_t));
+                       if (new == NULL)
+                               return;
+                       memset (new, 0, sizeof (procstat_entry_t));
+                       new->id = entry->id;
+                       
+                       if (pse == NULL)
+                               ps->instances = new;
+                       else
+                               pse->next = new;
 
-       pse->age = 0;
-       pse->num_proc = entry->num_proc;
-       pse->num_lwp  = entry->num_lwp;
-       pse->vmem_rss = entry->vmem_rss;
+                       pse = new;
+               }
 
-       ps->num_proc += pse->num_proc;
-       ps->num_lwp  += pse->num_lwp;
-       ps->vmem_rss += pse->vmem_rss;
+               pse->age = 0;
+               pse->num_proc = entry->num_proc;
+               pse->num_lwp  = entry->num_lwp;
+               pse->vmem_rss = entry->vmem_rss;
 
-       if ((entry->vmem_minflt_counter == 0)
-                       && (entry->vmem_majflt_counter == 0))
-       {
-               pse->vmem_minflt_counter += entry->vmem_minflt;
-               pse->vmem_minflt = entry->vmem_minflt;
+               ps->num_proc += pse->num_proc;
+               ps->num_lwp  += pse->num_lwp;
+               ps->vmem_rss += pse->vmem_rss;
 
-               pse->vmem_majflt_counter += entry->vmem_majflt;
-               pse->vmem_majflt = entry->vmem_majflt;
-       }
-       else
-       {
-               if (entry->vmem_minflt_counter < pse->vmem_minflt_counter)
+               if ((entry->vmem_minflt_counter == 0)
+                               && (entry->vmem_majflt_counter == 0))
                {
-                       pse->vmem_minflt = entry->vmem_minflt_counter
-                               + (ULONG_MAX - pse->vmem_minflt_counter);
-               }
-               else
-               {
-                       pse->vmem_minflt = entry->vmem_minflt_counter - pse->vmem_minflt_counter;
-               }
-               pse->vmem_minflt_counter = entry->vmem_minflt_counter;
+                       pse->vmem_minflt_counter += entry->vmem_minflt;
+                       pse->vmem_minflt = entry->vmem_minflt;
 
-               if (entry->vmem_majflt_counter < pse->vmem_majflt_counter)
-               {
-                       pse->vmem_majflt = entry->vmem_majflt_counter
-                               + (ULONG_MAX - pse->vmem_majflt_counter);
+                       pse->vmem_majflt_counter += entry->vmem_majflt;
+                       pse->vmem_majflt = entry->vmem_majflt;
                }
                else
                {
-                       pse->vmem_majflt = entry->vmem_majflt_counter - pse->vmem_majflt_counter;
+                       if (entry->vmem_minflt_counter < pse->vmem_minflt_counter)
+                       {
+                               pse->vmem_minflt = entry->vmem_minflt_counter
+                                       + (ULONG_MAX - pse->vmem_minflt_counter);
+                       }
+                       else
+                       {
+                               pse->vmem_minflt = entry->vmem_minflt_counter - pse->vmem_minflt_counter;
+                       }
+                       pse->vmem_minflt_counter = entry->vmem_minflt_counter;
+                       
+                       if (entry->vmem_majflt_counter < pse->vmem_majflt_counter)
+                       {
+                               pse->vmem_majflt = entry->vmem_majflt_counter
+                                       + (ULONG_MAX - pse->vmem_majflt_counter);
+                       }
+                       else
+                       {
+                               pse->vmem_majflt = entry->vmem_majflt_counter - pse->vmem_majflt_counter;
+                       }
+                       pse->vmem_majflt_counter = entry->vmem_majflt_counter;
                }
-               pse->vmem_majflt_counter = entry->vmem_majflt_counter;
-       }
-
-       ps->vmem_minflt_counter += pse->vmem_minflt;
-       ps->vmem_majflt_counter += pse->vmem_majflt;
 
-       if ((entry->cpu_user_counter == 0)
-                       && (entry->cpu_system_counter == 0))
-       {
-               pse->cpu_user_counter += entry->cpu_user;
-               pse->cpu_user = entry->cpu_user;
+               ps->vmem_minflt_counter += pse->vmem_minflt;
+               ps->vmem_majflt_counter += pse->vmem_majflt;
 
-               pse->cpu_system_counter += entry->cpu_system;
-               pse->cpu_system = entry->cpu_system;
-       }
-       else
-       {
-               if (entry->cpu_user_counter < pse->cpu_user_counter)
+               if ((entry->cpu_user_counter == 0)
+                               && (entry->cpu_system_counter == 0))
                {
-                       pse->cpu_user = entry->cpu_user_counter
-                               + (ULONG_MAX - pse->cpu_user_counter);
-               }
-               else
-               {
-                       pse->cpu_user = entry->cpu_user_counter - pse->cpu_user_counter;
-               }
-               pse->cpu_user_counter = entry->cpu_user_counter;
+                       pse->cpu_user_counter += entry->cpu_user;
+                       pse->cpu_user = entry->cpu_user;
 
-               if (entry->cpu_system_counter < pse->cpu_system_counter)
-               {
-                       pse->cpu_system = entry->cpu_system_counter
-                               + (ULONG_MAX - pse->cpu_system_counter);
+                       pse->cpu_system_counter += entry->cpu_system;
+                       pse->cpu_system = entry->cpu_system;
                }
                else
                {
-                       pse->cpu_system = entry->cpu_system_counter - pse->cpu_system_counter;
+                       if (entry->cpu_user_counter < pse->cpu_user_counter)
+                       {
+                               pse->cpu_user = entry->cpu_user_counter
+                                       + (ULONG_MAX - pse->cpu_user_counter);
+                       }
+                       else
+                       {
+                               pse->cpu_user = entry->cpu_user_counter - pse->cpu_user_counter;
+                       }
+                       pse->cpu_user_counter = entry->cpu_user_counter;
+                       
+                       if (entry->cpu_system_counter < pse->cpu_system_counter)
+                       {
+                               pse->cpu_system = entry->cpu_system_counter
+                                       + (ULONG_MAX - pse->cpu_system_counter);
+                       }
+                       else
+                       {
+                               pse->cpu_system = entry->cpu_system_counter - pse->cpu_system_counter;
+                       }
+                       pse->cpu_system_counter = entry->cpu_system_counter;
                }
-               pse->cpu_system_counter = entry->cpu_system_counter;
-       }
 
-       ps->cpu_user_counter   += pse->cpu_user;
-       ps->cpu_system_counter += pse->cpu_system;
+               ps->cpu_user_counter   += pse->cpu_user;
+               ps->cpu_system_counter += pse->cpu_system;
+       }
 }
 
+/* remove old entries from instances of processes in list_head_g */
 static void ps_list_reset (void)
 {
        procstat_t *ps;
@@ -347,11 +444,31 @@ static void ps_list_reset (void)
        } /* for (ps = list_head_g; ps != NULL; ps = ps->next) */
 }
 
+/* put all pre-defined 'Process' names from config to list_head_g tree */
 static int ps_config (const char *key, const char *value)
 {
        if (strcasecmp (key, "Process") == 0)
        {
-               ps_list_register (value);
+               ps_list_register (value, NULL);
+       }
+       else if (strcasecmp (key, "ProcessMatch") == 0)
+       {
+               char *new_val;
+               char *fields[3];
+               int fields_num;
+
+               new_val = strdup (value);
+               if (new_val == NULL)
+                       return (1);
+               fields_num = strsplit (new_val, fields,
+                               STATIC_ARRAY_SIZE (fields));
+               if (fields_num != 2)
+               {
+                       sfree (new_val);
+                       return (1);
+               }
+               ps_list_register (fields[0], fields[1]);
+               sfree (new_val);
        }
        else
        {
@@ -394,11 +511,16 @@ static int ps_init (void)
        pagesize_g = sysconf(_SC_PAGESIZE);
        DEBUG ("pagesize_g = %li; CONFIG_HZ = %i;",
                        pagesize_g, CONFIG_HZ);
-#endif /* KERNEL_LINUX */
+/* #endif KERNEL_LINUX */
+
+#elif HAVE_LIBKVM_GETPROCS
+/* no initialization */
+#endif /* HAVE_LIBKVM_GETPROCS */
 
        return (0);
 } /* int ps_init */
 
+/* submit global state (e.g.: qty of zombies, running, etc..) */
 static void ps_submit_state (const char *state, double value)
 {
        value_t values[1];
@@ -412,11 +534,13 @@ static void ps_submit_state (const char *state, double value)
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "processes", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
-       strncpy (vl.type_instance, state, sizeof (vl.type_instance));
+       sstrncpy (vl.type, "ps_state", sizeof (vl.type));
+       sstrncpy (vl.type_instance, state, sizeof (vl.type_instance));
 
-       plugin_dispatch_values ("ps_state", &vl);
+       plugin_dispatch_values (&vl);
 }
 
+/* submit info about specific process (e.g.: memory taken, cpu usage, etc..) */
 static void ps_submit_proc_list (procstat_t *ps)
 {
        value_t values[2];
@@ -427,26 +551,30 @@ static void ps_submit_proc_list (procstat_t *ps)
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "processes", sizeof (vl.plugin));
-       strncpy (vl.plugin_instance, ps->name, sizeof (vl.plugin_instance));
+       sstrncpy (vl.plugin_instance, ps->name, sizeof (vl.plugin_instance));
 
+       sstrncpy (vl.type, "ps_rss", sizeof (vl.type));
        vl.values[0].gauge = ps->vmem_rss;
        vl.values_len = 1;
-       plugin_dispatch_values ("ps_rss", &vl);
+       plugin_dispatch_values (&vl);
 
+       sstrncpy (vl.type, "ps_cputime", sizeof (vl.type));
        vl.values[0].counter = ps->cpu_user_counter;
        vl.values[1].counter = ps->cpu_system_counter;
        vl.values_len = 2;
-       plugin_dispatch_values ("ps_cputime", &vl);
+       plugin_dispatch_values (&vl);
 
+       sstrncpy (vl.type, "ps_count", sizeof (vl.type));
        vl.values[0].gauge = ps->num_proc;
        vl.values[1].gauge = ps->num_lwp;
        vl.values_len = 2;
-       plugin_dispatch_values ("ps_count", &vl);
+       plugin_dispatch_values (&vl);
 
+       sstrncpy (vl.type, "ps_pagefaults", sizeof (vl.type));
        vl.values[0].counter = ps->vmem_minflt_counter;
        vl.values[1].counter = ps->vmem_majflt_counter;
        vl.values_len = 2;
-       plugin_dispatch_values ("ps_pagefaults", &vl);
+       plugin_dispatch_values (&vl);
 
        DEBUG ("name = %s; num_proc = %lu; num_lwp = %lu; vmem_rss = %lu; "
                        "vmem_minflt_counter = %lu; vmem_majflt_counter = %lu; "
@@ -456,6 +584,7 @@ static void ps_submit_proc_list (procstat_t *ps)
                        ps->cpu_user_counter, ps->cpu_system_counter);
 } /* void ps_submit_proc_list */
 
+/* ------- additional functions for KERNEL_LINUX/HAVE_THREAD_INFO ------- */
 #if KERNEL_LINUX
 static int *ps_read_tasks (int pid)
 {
@@ -467,8 +596,7 @@ static int *ps_read_tasks (int pid)
        DIR           *dh;
        struct dirent *ent;
 
-       snprintf (dirname, 64, "/proc/%i/task", pid);
-       dirname[63] = '\0';
+       ssnprintf (dirname, sizeof (dirname), "/proc/%i/task", pid);
 
        if ((dh = opendir (dirname)) == NULL)
        {
@@ -523,7 +651,6 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
 {
        char  filename[64];
        char  buffer[1024];
-       FILE *fh;
 
        char *fields[64];
        char  fields_len;
@@ -540,19 +667,12 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
 
        memset (ps, 0, sizeof (procstat_t));
 
-       snprintf (filename, 64, "/proc/%i/stat", pid);
-       filename[63] = '\0';
+       ssnprintf (filename, sizeof (filename), "/proc/%i/stat", pid);
 
-       if ((fh = fopen (filename, "r")) == NULL)
+       i = read_file_contents (filename, buffer, sizeof(buffer) - 1);
+       if (i <= 0)
                return (-1);
-
-       if (fgets (buffer, 1024, fh) == NULL)
-       {
-               fclose (fh);
-               return (-1);
-       }
-
-       fclose (fh);
+       buffer[i] = 0;
 
        fields_len = strsplit (buffer, fields, 64);
        if (fields_len < 24)
@@ -663,7 +783,9 @@ static int mach_get_task_name (task_t t, int *pid, char *name, size_t name_max_l
        return (0);
 }
 #endif /* HAVE_THREAD_INFO */
+/* ------- end of additional functions for KERNEL_LINUX/HAVE_THREAD_INFO ------- */
 
+/* do actual readings from kernel */
 static int ps_read (void)
 {
 #if HAVE_THREAD_INFO
@@ -731,7 +853,13 @@ static int ps_read (void)
                        if (mach_get_task_name (task_list[task],
                                                &task_pid,
                                                task_name, PROCSTAT_NAME_LEN) == 0)
-                               ps = ps_list_search (task_name);
+                       {
+                               /* search for at least one match */
+                               for (ps = list_head_g; ps != NULL; ps = ps->next)
+                                       /* FIXME: cmdline should be here instead of NULL */
+                                       if (ps_list_match (task_name, NULL, ps) == 1)
+                                               break;
+                       }
 
                        /* Collect more detailed statistics for this process */
                        if (ps != NULL)
@@ -889,7 +1017,8 @@ static int ps_read (void)
                        }
 
                        if (ps != NULL)
-                               ps_list_add (task_name, &pse);
+                               /* FIXME: cmdline should be here instead of NULL */
+                               ps_list_add (task_name, NULL, &pse);
                } /* for (task_list) */
 
                if ((status = vm_deallocate (port_task_self,
@@ -992,7 +1121,8 @@ static int ps_read (void)
                        case 'W': paging++;   break;
                }
 
-               ps_list_add (ps.name, &pse);
+               /* FIXME: cmdline should be here instead of NULL */
+               ps_list_add (ps.name, NULL, &pse);
        }
 
        closedir (proc);
@@ -1006,7 +1136,129 @@ static int ps_read (void)
 
        for (ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
                ps_submit_proc_list (ps_ptr);
-#endif /* KERNEL_LINUX */
+/* #endif KERNEL_LINUX */
+
+#elif HAVE_LIBKVM_GETPROCS
+       int running  = 0;
+       int sleeping = 0;
+       int zombies  = 0;
+       int stopped  = 0;
+       int blocked  = 0;
+       int idle     = 0;
+       int wait     = 0;
+
+       kvm_t *kd;
+       char errbuf[1024];
+       char cmdline[ARG_MAX];
+       char *cmdline_ptr;
+       struct kinfo_proc *procs;          /* array of processes */
+       char **argv;
+       int count;                         /* returns number of processes */
+       int i;
+
+       procstat_t *ps_ptr;
+       procstat_entry_t pse;
+
+       ps_list_reset ();
+
+       /* Open the kvm interface, get a descriptor */
+       kd = kvm_open (NULL, NULL, NULL, 0, errbuf);
+       if (kd == NULL)
+       {
+               ERROR ("processes plugin: Cannot open kvm interface: %s",
+                               errbuf);
+               return (0);
+       }
+
+       /* Get the list of processes. */
+       procs = kvm_getprocs(kd, KERN_PROC_ALL, 0, &count);
+       if (procs == NULL)
+       {
+               kvm_close (kd);
+               ERROR ("processes plugin: Cannot get kvm processes list: %s",
+                               kvm_geterr(kd));
+               return (0);
+       }
+
+       /* Iterate through the processes in kinfo_proc */
+       for (i = 0; i < count; i++)
+       {
+               /* retrieve the arguments */
+               cmdline[0] = 0;
+               cmdline_ptr = NULL;
+
+               argv = kvm_getargv (kd, (const struct kinfo_proc *) &(procs[i]), 0);
+               if (argv != NULL)
+               {
+                       int status;
+                       int argc;
+
+                       argc = 0;
+                       while (argv[argc] != NULL)
+                               argc++;
+
+                       status = strjoin (cmdline, sizeof (cmdline),
+                                       argv, argc, " ");
+
+                       if (status < 0)
+                       {
+                               WARNING ("processes plugin: Command line did "
+                                               "not fit into buffer.");
+                       }
+                       else
+                       {
+                               cmdline_ptr = &cmdline[0];
+                       }
+               }
+
+               pse.id       = procs[i].ki_pid;
+               pse.age      = 0;
+
+               pse.num_proc = 1;
+               pse.num_lwp  = procs[i].ki_numthreads;
+
+               pse.vmem_rss = procs[i].ki_rssize * getpagesize();
+               pse.vmem_minflt = 0;
+               pse.vmem_minflt_counter = procs[i].ki_rusage.ru_minflt;
+               pse.vmem_majflt = 0;
+               pse.vmem_majflt_counter = procs[i].ki_rusage.ru_majflt;
+
+               pse.cpu_user = 0;
+               pse.cpu_user_counter = procs[i].ki_rusage.ru_utime.tv_sec
+                       * 1000
+                       + procs[i].ki_rusage.ru_utime.tv_usec;
+               pse.cpu_system = 0;
+               pse.cpu_system_counter = procs[i].ki_rusage.ru_stime.tv_sec
+                       * 1000
+                       + procs[i].ki_rusage.ru_stime.tv_usec;
+
+               switch (procs[i].ki_stat)
+               {
+                       case SSTOP:     stopped++;      break;
+                       case SSLEEP:    sleeping++;     break;
+                       case SRUN:      running++;      break;
+                       case SIDL:      idle++;         break;
+                       case SWAIT:     wait++;         break;
+                       case SLOCK:     blocked++;      break;
+                       case SZOMB:     zombies++;      break;
+               }
+
+               ps_list_add (procs[i].ki_comm, cmdline_ptr, &pse);
+       }
+
+       kvm_close(kd);
+
+       ps_submit_state ("running",  running);
+       ps_submit_state ("sleeping", sleeping);
+       ps_submit_state ("zombies",  zombies);
+       ps_submit_state ("stopped",  stopped);
+       ps_submit_state ("blocked",  blocked);
+       ps_submit_state ("idle",     idle);
+       ps_submit_state ("wait",     wait);
+
+       for (ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
+               ps_submit_proc_list (ps_ptr);
+#endif /* HAVE_LIBKVM_GETPROCS */
 
        return (0);
 } /* int ps_read */
index ac81d55..e1c7902 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/rrdtool.c
- * Copyright (C) 2006,2007  Florian octo Forster
+ * Copyright (C) 2006-2008  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
@@ -42,11 +42,19 @@ struct rrd_cache_s
        enum
        {
                FLAG_NONE   = 0x00,
-               FLAG_QUEUED = 0x01
+               FLAG_QUEUED = 0x01,
+               FLAG_FLUSHQ = 0x02
        } flags;
 };
 typedef struct rrd_cache_s rrd_cache_t;
 
+enum rrd_queue_dir_e
+{
+  QUEUE_INSERT_FRONT,
+  QUEUE_INSERT_BACK
+};
+typedef enum rrd_queue_dir_e rrd_queue_dir_t;
+
 struct rrd_queue_s
 {
        char *filename;
@@ -87,7 +95,8 @@ static const char *config_keys[] =
        "HeartBeat",
        "RRARows",
        "RRATimespan",
-       "XFF"
+       "XFF",
+       "WritesPerSecond"
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
@@ -99,6 +108,7 @@ static int     stepsize  = 0;
 static int     heartbeat = 0;
 static int     rrarows   = 1200;
 static double  xff       = 0.1;
+static double  write_rate = 0.0;
 
 /* XXX: If you need to lock both, cache_lock and queue_lock, at the same time,
  * ALWAYS lock `cache_lock' first! */
@@ -110,6 +120,8 @@ static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
 
 static rrd_queue_t    *queue_head = NULL;
 static rrd_queue_t    *queue_tail = NULL;
+static rrd_queue_t    *flushq_head = NULL;
+static rrd_queue_t    *flushq_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;
@@ -211,7 +223,7 @@ static int rra_get (char ***ret, const value_list_t *vl)
                        if (rra_num >= rra_max)
                                break;
 
-                       if (snprintf (buffer, sizeof (buffer), "RRA:%s:%3.1f:%u:%u",
+                       if (ssnprintf (buffer, sizeof (buffer), "RRA:%s:%3.1f:%u:%u",
                                                rra_types[j], xff,
                                                cdp_len, cdp_num) >= sizeof (buffer))
                        {
@@ -288,22 +300,16 @@ static int ds_get (char ***ret, const data_set_t *ds, const value_list_t *vl)
                        sstrncpy (min, "U", sizeof (min));
                }
                else
-               {
-                       snprintf (min, sizeof (min), "%lf", d->min);
-                       min[sizeof (min) - 1] = '\0';
-               }
+                       ssnprintf (min, sizeof (min), "%lf", d->min);
 
                if (isnan (d->max))
                {
                        sstrncpy (max, "U", sizeof (max));
                }
                else
-               {
-                       snprintf (max, sizeof (max), "%lf", d->max);
-                       max[sizeof (max) - 1] = '\0';
-               }
+                       ssnprintf (max, sizeof (max), "%lf", d->max);
 
-               status = snprintf (buffer, sizeof (buffer),
+               status = ssnprintf (buffer, sizeof (buffer),
                                "DS:%s:%s:%i:%s:%s",
                                d->name, type,
                                (heartbeat > 0) ? heartbeat : (2 * vl->interval),
@@ -335,7 +341,7 @@ static int ds_get (char ***ret, const data_set_t *ds, const value_list_t *vl)
 
 #if HAVE_THREADSAFE_LIBRRD
 static int srrd_create (char *filename, unsigned long pdp_step, time_t last_up,
-               int argc, char **argv)
+               int argc, const char **argv)
 {
        int status;
 
@@ -353,7 +359,8 @@ static int srrd_create (char *filename, unsigned long pdp_step, time_t last_up,
        return (status);
 } /* int srrd_create */
 
-static int srrd_update (char *filename, char *template, int argc, char **argv)
+static int srrd_update (char *filename, char *template,
+               int argc, const char **argv)
 {
        int status;
 
@@ -374,7 +381,7 @@ static int srrd_update (char *filename, char *template, int argc, char **argv)
 
 #else /* !HAVE_THREADSAFE_LIBRRD */
 static int srrd_create (char *filename, unsigned long pdp_step, time_t last_up,
-               int argc, char **argv)
+               int argc, const char **argv)
 {
        int status;
 
@@ -395,10 +402,8 @@ static int srrd_create (char *filename, unsigned long pdp_step, time_t last_up,
        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';
+       ssnprintf (pdp_step_str, sizeof (pdp_step_str), "%lu", pdp_step);
+       ssnprintf (last_up_str, sizeof (last_up_str), "%u", (unsigned int) last_up);
 
        new_argv[0] = "create";
        new_argv[1] = filename;
@@ -428,7 +433,8 @@ static int srrd_create (char *filename, unsigned long pdp_step, time_t last_up,
        return (status);
 } /* int srrd_create */
 
-static int srrd_update (char *filename, char *template, int argc, char **argv)
+static int srrd_update (char *filename, char *template,
+               int argc, const char **argv)
 {
        int status;
 
@@ -513,7 +519,7 @@ static int rrd_create_file (char *filename, const data_set_t *ds, const value_li
        status = srrd_create (filename,
                        (stepsize > 0) ? stepsize : vl->interval,
                        vl->time - 10,
-                       argc, argv);
+                       argc, (const char **)argv);
 
        free (argv);
        ds_free (ds_num, ds_def);
@@ -531,7 +537,7 @@ static int value_list_to_string (char *buffer, int buffer_len,
 
        memset (buffer, '\0', buffer_len);
 
-       status = snprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+       status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
        if ((status < 1) || (status >= buffer_len))
                return (-1);
        offset = status;
@@ -543,10 +549,10 @@ static int value_list_to_string (char *buffer, int buffer_len,
                        return (-1);
 
                if (ds->ds[i].type == DS_TYPE_COUNTER)
-                       status = snprintf (buffer + offset, buffer_len - offset,
+                       status = ssnprintf (buffer + offset, buffer_len - offset,
                                        ":%llu", vl->values[i].counter);
                else
-                       status = snprintf (buffer + offset, buffer_len - offset,
+                       status = ssnprintf (buffer + offset, buffer_len - offset,
                                        ":%lf", vl->values[i].gauge);
 
                if ((status < 1) || (status >= (buffer_len - offset)))
@@ -566,35 +572,35 @@ static int value_list_to_filename (char *buffer, int buffer_len,
 
        if (datadir != NULL)
        {
-               status = snprintf (buffer + offset, buffer_len - offset,
+               status = ssnprintf (buffer + offset, buffer_len - offset,
                                "%s/", datadir);
                if ((status < 1) || (status >= buffer_len - offset))
                        return (-1);
                offset += status;
        }
 
-       status = snprintf (buffer + offset, buffer_len - offset,
+       status = ssnprintf (buffer + offset, buffer_len - offset,
                        "%s/", vl->host);
        if ((status < 1) || (status >= buffer_len - offset))
                return (-1);
        offset += status;
 
        if (strlen (vl->plugin_instance) > 0)
-               status = snprintf (buffer + offset, buffer_len - offset,
+               status = ssnprintf (buffer + offset, buffer_len - offset,
                                "%s-%s/", vl->plugin, vl->plugin_instance);
        else
-               status = snprintf (buffer + offset, buffer_len - offset,
+               status = ssnprintf (buffer + offset, buffer_len - offset,
                                "%s/", vl->plugin);
        if ((status < 1) || (status >= buffer_len - offset))
                return (-1);
        offset += status;
 
        if (strlen (vl->type_instance) > 0)
-               status = snprintf (buffer + offset, buffer_len - offset,
-                               "%s-%s.rrd", ds->type, vl->type_instance);
+               status = ssnprintf (buffer + offset, buffer_len - offset,
+                               "%s-%s.rrd", vl->type, vl->type_instance);
        else
-               status = snprintf (buffer + offset, buffer_len - offset,
-                               "%s.rrd", ds->type);
+               status = ssnprintf (buffer + offset, buffer_len - offset,
+                               "%s.rrd", vl->type);
        if ((status < 1) || (status >= buffer_len - offset))
                return (-1);
        offset += status;
@@ -604,6 +610,11 @@ static int value_list_to_filename (char *buffer, int buffer_len,
 
 static void *rrd_queue_thread (void *data)
 {
+        struct timeval tv_next_update;
+        struct timeval tv_now;
+
+        gettimeofday (&tv_next_update, /* timezone = */ NULL);
+
        while (42)
        {
                rrd_queue_t *queue_entry;
@@ -612,27 +623,79 @@ static void *rrd_queue_thread (void *data)
                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)
-               {
-                       pthread_mutex_unlock (&queue_lock);
-                       break;
-               }
-
-               /* Dequeue the first entry */
-               queue_entry = queue_head;
-               if (queue_head == queue_tail)
-                       queue_head = queue_tail = NULL;
-               else
-                       queue_head = queue_head->next;
+                pthread_mutex_lock (&queue_lock);
+                /* Wait for values to arrive */
+                while (true)
+                {
+                  struct timespec ts_wait;
+                  int status;
+
+                  while ((flushq_head == NULL) && (queue_head == NULL)
+                      && (do_shutdown == 0))
+                    pthread_cond_wait (&queue_cond, &queue_lock);
+
+                  if ((flushq_head == NULL) && (queue_head == NULL))
+                    break;
+
+                  /* Don't delay if there's something to flush */
+                  if (flushq_head != NULL)
+                    break;
+
+                  /* Don't delay if we're shutting down */
+                  if (do_shutdown != 0)
+                    break;
+
+                  /* Don't delay if no delay was configured. */
+                  if (write_rate <= 0.0)
+                    break;
+
+                  gettimeofday (&tv_now, /* timezone = */ NULL);
+                  status = timeval_sub_timespec (&tv_next_update, &tv_now,
+                      &ts_wait);
+                  /* We're good to go */
+                  if (status != 0)
+                    break;
+
+                  /* We're supposed to wait a bit with this update, so we'll
+                   * wait for the next addition to the queue or to the end of
+                   * the wait period - whichever comes first. */
+                  ts_wait.tv_sec = tv_next_update.tv_sec;
+                  ts_wait.tv_nsec = 1000 * tv_next_update.tv_usec;
+
+                  status = pthread_cond_timedwait (&queue_cond, &queue_lock,
+                      &ts_wait);
+                  if (status == ETIMEDOUT)
+                    break;
+                } /* while (true) */
+
+                /* XXX: If you need to lock both, cache_lock and queue_lock, at
+                 * the same time, ALWAYS lock `cache_lock' first! */
+
+                /* We're in the shutdown phase */
+                if ((flushq_head == NULL) && (queue_head == NULL))
+                {
+                  pthread_mutex_unlock (&queue_lock);
+                  break;
+                }
+
+                if (flushq_head != NULL)
+                {
+                  /* Dequeue the first flush entry */
+                  queue_entry = flushq_head;
+                  if (flushq_head == flushq_tail)
+                    flushq_head = flushq_tail = NULL;
+                  else
+                    flushq_head = flushq_head->next;
+                }
+                else /* if (queue_head != NULL) */
+                {
+                  /* Dequeue the first regular entry */
+                  queue_entry = queue_head;
+                  if (queue_head == queue_tail)
+                    queue_head = queue_tail = NULL;
+                  else
+                    queue_head = queue_head->next;
+                }
 
                /* Unlock the queue again */
                pthread_mutex_unlock (&queue_lock);
@@ -652,8 +715,23 @@ static void *rrd_queue_thread (void *data)
 
                pthread_mutex_unlock (&cache_lock);
 
+               /* Update `tv_next_update' */
+               if (write_rate > 0.0) 
+                {
+                  gettimeofday (&tv_now, /* timezone = */ NULL);
+                  tv_next_update.tv_sec = tv_now.tv_sec;
+                  tv_next_update.tv_usec = tv_now.tv_usec
+                    + ((suseconds_t) (1000000 * write_rate));
+                  while (tv_next_update.tv_usec > 1000000)
+                  {
+                    tv_next_update.tv_sec++;
+                    tv_next_update.tv_usec -= 1000000;
+                  }
+                }
+
                /* Write the values to the RRD-file */
-               srrd_update (queue_entry->filename, NULL, values_num, values);
+               srrd_update (queue_entry->filename, NULL,
+                               values_num, (const char **)values);
                DEBUG ("rrdtool plugin: queue thread: Wrote %i values to %s",
                                values_num, queue_entry->filename);
 
@@ -675,36 +753,79 @@ static void *rrd_queue_thread (void *data)
        return ((void *) 0);
 } /* void *rrd_queue_thread */
 
-static int rrd_queue_cache_entry (const char *filename)
+static int rrd_queue_enqueue (const char *filename,
+    rrd_queue_t **head, rrd_queue_t **tail)
 {
-       rrd_queue_t *queue_entry;
+  rrd_queue_t *queue_entry;
 
-       queue_entry = (rrd_queue_t *) malloc (sizeof (rrd_queue_t));
-       if (queue_entry == NULL)
-               return (-1);
+  queue_entry = (rrd_queue_t *) malloc (sizeof (rrd_queue_t));
+  if (queue_entry == NULL)
+    return (-1);
 
-       queue_entry->filename = strdup (filename);
-       if (queue_entry->filename == NULL)
-       {
-               free (queue_entry);
-               return (-1);
-       }
+  queue_entry->filename = strdup (filename);
+  if (queue_entry->filename == NULL)
+  {
+    free (queue_entry);
+    return (-1);
+  }
 
-       queue_entry->next = NULL;
+  queue_entry->next = NULL;
 
-       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);
+  pthread_mutex_lock (&queue_lock);
 
-       DEBUG ("rrdtool plugin: Put `%s' into the update queue", filename);
+  if (*tail == NULL)
+    *head = queue_entry;
+  else
+    (*tail)->next = queue_entry;
+  *tail = queue_entry;
 
-       return (0);
-} /* int rrd_queue_cache_entry */
+  pthread_cond_signal (&queue_cond);
+  pthread_mutex_unlock (&queue_lock);
+
+  return (0);
+} /* int rrd_queue_enqueue */
+
+static int rrd_queue_dequeue (const char *filename,
+    rrd_queue_t **head, rrd_queue_t **tail)
+{
+  rrd_queue_t *this;
+  rrd_queue_t *prev;
+
+  pthread_mutex_lock (&queue_lock);
+
+  prev = NULL;
+  this = *head;
+
+  while (this != NULL)
+  {
+    if (strcmp (this->filename, filename) == 0)
+      break;
+    
+    prev = this;
+    this = this->next;
+  }
+
+  if (this == NULL)
+  {
+    pthread_mutex_unlock (&queue_lock);
+    return (-1);
+  }
+
+  if (prev == NULL)
+    *head = this->next;
+  else
+    prev->next = this->next;
+
+  if (this->next == NULL)
+    *tail = prev;
+
+  pthread_mutex_unlock (&queue_lock);
+
+  sfree (this->filename);
+  sfree (this);
+
+  return (0);
+} /* int rrd_queue_dequeue */
 
 static void rrd_cache_flush (int timeout)
 {
@@ -726,13 +847,16 @@ static void rrd_cache_flush (int timeout)
        iter = c_avl_get_iterator (cache);
        while (c_avl_iterator_next (iter, (void *) &key, (void *) &rc) == 0)
        {
-               if (rc->flags == FLAG_QUEUED)
+               if (rc->flags != FLAG_NONE)
                        continue;
                else if ((now - rc->first_value) < timeout)
                        continue;
                else if (rc->values_num > 0)
                {
-                       if (rrd_queue_cache_entry (key) == 0)
+                       int status;
+
+                       status = rrd_queue_enqueue (key, &queue_head,  &queue_tail);
+                       if (status == 0)
                                rc->flags = FLAG_QUEUED;
                }
                else /* ancient and no values -> waste of memory */
@@ -778,6 +902,63 @@ static void rrd_cache_flush (int timeout)
        cache_flush_last = now;
 } /* void rrd_cache_flush */
 
+static int rrd_cache_flush_identifier (int timeout, const char *identifier)
+{
+  rrd_cache_t *rc;
+  time_t now;
+  int status;
+  char key[2048];
+
+  if (identifier == NULL)
+  {
+    rrd_cache_flush (timeout);
+    return (0);
+  }
+
+  now = time (NULL);
+
+  if (datadir == NULL)
+    snprintf (key, sizeof (key), "%s.rrd",
+        identifier);
+  else
+    snprintf (key, sizeof (key), "%s/%s.rrd",
+        datadir, identifier);
+  key[sizeof (key) - 1] = 0;
+
+  status = c_avl_get (cache, key, (void *) &rc);
+  if (status != 0)
+  {
+    WARNING ("rrdtool plugin: rrd_cache_flush_identifier: "
+        "c_avl_get (%s) failed. Does that file really exist?",
+        key);
+    return (status);
+  }
+
+  if (rc->flags == FLAG_FLUSHQ)
+  {
+    status = 0;
+  }
+  else if (rc->flags == FLAG_QUEUED)
+  {
+    rrd_queue_dequeue (key, &queue_head, &queue_tail);
+    status = rrd_queue_enqueue (key, &flushq_head, &flushq_tail);
+    if (status == 0)
+      rc->flags = FLAG_FLUSHQ;
+  }
+  else if ((now - rc->first_value) < timeout)
+  {
+    status = 0;
+  }
+  else if (rc->values_num > 0)
+  {
+    status = rrd_queue_enqueue (key, &flushq_head, &flushq_tail);
+    if (status == 0)
+      rc->flags = FLAG_FLUSHQ;
+  }
+
+  return (status);
+} /* int rrd_cache_flush_identifier */
+
 static int rrd_cache_insert (const char *filename,
                const char *value, time_t value_time)
 {
@@ -864,17 +1045,20 @@ static int rrd_cache_insert (const char *filename,
        }
 
        DEBUG ("rrdtool plugin: rrd_cache_insert: file = %s; "
-                       "values_num = %i; age = %u;",
+                       "values_num = %i; age = %lu;",
                        filename, rc->values_num,
-                       rc->last_value - rc->first_value);
+                       (unsigned long)(rc->last_value - rc->first_value));
 
        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 (rc->flags == FLAG_NONE)
                {
-                       if (rrd_queue_cache_entry (filename) == 0)
+                       int status;
+
+                       status = rrd_queue_enqueue (filename, &queue_head, &queue_tail);
+                       if (status == 0)
                                rc->flags = FLAG_QUEUED;
                }
                else
@@ -887,7 +1071,6 @@ static int rrd_cache_insert (const char *filename,
                        ((time (NULL) - cache_flush_last) > cache_flush_timeout))
                rrd_cache_flush (cache_flush_timeout);
 
-
        pthread_mutex_unlock (&cache_lock);
 
        return (0);
@@ -913,6 +1096,11 @@ static int rrd_write (const data_set_t *ds, const value_list_t *vl)
        char         values[512];
        int          status;
 
+       if (0 != strcmp (ds->type, vl->type)) {
+               ERROR ("rrdtool plugin: DS type does not match value list type");
+               return -1;
+       }
+
        if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
                return (-1);
 
@@ -947,7 +1135,7 @@ static int rrd_write (const data_set_t *ds, const value_list_t *vl)
        return (status);
 } /* int rrd_write */
 
-static int rrd_flush (const int timeout)
+static int rrd_flush (int timeout, const char *identifier)
 {
        pthread_mutex_lock (&cache_lock);
 
@@ -956,7 +1144,8 @@ static int rrd_flush (const int timeout)
                return (0);
        }
 
-       rrd_cache_flush (timeout);
+       rrd_cache_flush_identifier (timeout, identifier);
+
        pthread_mutex_unlock (&cache_lock);
        return (0);
 } /* int rrd_flush */
@@ -1086,6 +1275,25 @@ static int rrd_config (const char *key, const char *value)
                }
                xff = tmp;
        }
+       else if (strcasecmp ("WritesPerSecond", key) == 0)
+       {
+               double wps = atof (value);
+
+               if (wps < 0.0)
+               {
+                       fprintf (stderr, "rrdtool: `WritesPerSecond' must be "
+                                       "greater than or equal to zero.");
+                       return (1);
+               }
+               else if (wps == 0.0)
+               {
+                       write_rate = 0.0;
+               }
+               else
+               {
+                       write_rate = 1.0 / wps;
+               }
+       }
        else
        {
                return (-1);
index 0968e31..5ed82a8 100644 (file)
@@ -182,7 +182,7 @@ static int sensors_snprintf_chip_name (char *buf, size_t buf_size,
 
        if (chip->bus == SENSORS_CHIP_NAME_BUS_ISA)
        {
-               status = snprintf (buf, buf_size,
+               status = ssnprintf (buf, buf_size,
                                "%s-isa-%04x",
                                chip->prefix,
                                chip->addr);
@@ -480,11 +480,10 @@ static void sensors_submit (const char *plugin_instance,
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       status = snprintf (match_key, sizeof (match_key), "%s/%s-%s",
+       status = ssnprintf (match_key, sizeof (match_key), "%s/%s-%s",
                        plugin_instance, type, type_instance);
        if (status < 1)
                return;
-       match_key[sizeof (match_key) - 1] = '\0';
 
        if (sensor_list != NULL)
        {
@@ -499,17 +498,14 @@ static void sensors_submit (const char *plugin_instance,
        vl.values_len = 1;
        vl.time = time (NULL);
 
-       strncpy (vl.host, hostname_g, sizeof (vl.host));
-       vl.host[sizeof (vl.host) - 1] = '\0';
-       strncpy (vl.plugin, "sensors", sizeof (vl.plugin));
-       vl.plugin[sizeof (vl.plugin) - 1] = '\0';
-       strncpy (vl.plugin_instance, plugin_instance,
+       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       sstrncpy (vl.plugin, "sensors", sizeof (vl.plugin));
+       sstrncpy (vl.plugin_instance, plugin_instance,
                        sizeof (vl.plugin_instance));
-       vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0';
-       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
-       vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+       sstrncpy (vl.type, type, sizeof (vl.type));
+       sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void sensors_submit */
 
 static int sensors_read (void)
@@ -536,11 +532,9 @@ static int sensors_read (void)
                                sizeof (plugin_instance), fl->chip);
                if (status < 0)
                        continue;
-               plugin_instance[sizeof (plugin_instance) - 1] = '\0';
 
-               strncpy (type_instance, fl->data->name,
+               sstrncpy (type_instance, fl->data->name,
                                sizeof (type_instance));
-               type_instance[sizeof (type_instance) - 1] = '\0';
 
                sensors_submit (plugin_instance,
                                sensor_type_name_map[fl->type],
@@ -567,11 +561,9 @@ static int sensors_read (void)
                                sizeof (plugin_instance), fl->chip);
                if (status < 0)
                        continue;
-               plugin_instance[sizeof (plugin_instance) - 1] = '\0';
 
-               strncpy (type_instance, fl->feature->name,
+               sstrncpy (type_instance, fl->feature->name,
                                sizeof (type_instance));
-               type_instance[sizeof (type_instance) - 1] = '\0';
 
                if (fl->feature->type == SENSORS_FEATURE_IN)
                        type = "voltage";
index 4f08a34..1c874e5 100644 (file)
@@ -43,10 +43,11 @@ static void serial_submit (const char *type_instance,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "serial", sizeof (vl.plugin));
-       strncpy (vl.type_instance, type_instance,
+       sstrncpy (vl.type, "serial_octets", sizeof (vl.type));
+       sstrncpy (vl.type_instance, type_instance,
                        sizeof (vl.type_instance));
 
-       plugin_dispatch_values ("serial_octets", &vl);
+       plugin_dispatch_values (&vl);
 }
 
 static int serial_read (void)
index 408defa..4d6e769 100644 (file)
@@ -198,7 +198,8 @@ static int csnmp_config_add_data_instance (data_definition_t *dd, oconfig_item_t
   else
   {
     /* Instance is a simple string */
-    strncpy (dd->instance.string, ci->values[0].value.string, DATA_MAX_NAME_LEN - 1);
+    sstrncpy (dd->instance.string, ci->values[0].value.string,
+       sizeof (dd->instance.string));
   }
 
   return (0);
@@ -716,13 +717,61 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type,
     temp += (uint32_t) vl->val.counter64->low;
     DEBUG ("snmp plugin: Parsed int64 value is %"PRIu64".", temp);
   }
+  else if (vl->type == ASN_OCTET_STR)
+  {
+    /* We'll handle this later.. */
+  }
   else
   {
     WARNING ("snmp plugin: I don't know the ASN type `%i'", (int) vl->type);
     defined = 0;
   }
 
-  if (type == DS_TYPE_COUNTER)
+  if (vl->type == ASN_OCTET_STR)
+  {
+    char *endptr;
+
+    endptr = NULL;
+    if (vl->val.string != NULL)
+    {
+      char string[64];
+      size_t string_length;
+
+      string_length = sizeof (string) - 1;
+      if (vl->val_len < string_length)
+       string_length = vl->val_len;
+
+      /* The strings we get from the Net-SNMP library may not be null
+       * terminated. That is why we're using `membpy' here and not `strcpy'.
+       * `string_length' is set to `vl->val_len' which holds the length of the
+       * string.  -octo */
+      memcpy (string, vl->val.string, string_length);
+      string[string_length] = 0;
+
+      if (type == DS_TYPE_COUNTER)
+      {
+       ret.counter = (counter_t) strtoll (string, &endptr, /* base = */ 0);
+       DEBUG ("snmp plugin: csnmp_value_list_to_value: String to counter: %s -> %llu",
+           string, (unsigned long long) ret.counter);
+      }
+      else if (type == DS_TYPE_GAUGE)
+      {
+       ret.gauge = (gauge_t) strtod (string, &endptr);
+       DEBUG ("snmp plugin: csnmp_value_list_to_value: String to gauge: %s -> %g",
+           string, (double) ret.gauge);
+      }
+    }
+
+    /* Check if an error occurred */
+    if ((vl->val.string == NULL) || (endptr == (char *) vl->val.string))
+    {
+      if (type == DS_TYPE_COUNTER)
+       ret.counter = 0;
+      else if (type == DS_TYPE_GAUGE)
+       ret.gauge = NAN;
+    }
+  }
+  else if (type == DS_TYPE_COUNTER)
   {
     ret.counter = temp;
   }
@@ -829,15 +878,15 @@ static int csnmp_instance_list_add (csnmp_list_instances_t **head,
     char *ptr;
     size_t instance_len;
 
+    memset (il->instance, 0, sizeof (il->instance));
     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)
+    sstrncpy (il->instance, (char *) ((vb->type == ASN_OCTET_STR)
          ? vb->val.string
          : vb->val.bitstring),
-       instance_len);
-    il->instance[instance_len] = '\0';
+       instance_len + 1);
 
     for (ptr = il->instance; *ptr != '\0'; ptr++)
     {
@@ -851,10 +900,9 @@ static int csnmp_instance_list_add (csnmp_list_instances_t **head,
   else
   {
     value_t val = csnmp_value_list_to_value (vb, DS_TYPE_COUNTER, 1.0, 0.0);
-    snprintf (il->instance, sizeof (il->instance),
+    ssnprintf (il->instance, sizeof (il->instance),
        "%llu", val.counter);
   }
-  il->instance[sizeof (il->instance) - 1] = '\0';
 
   /* TODO: Debugging output */
 
@@ -907,8 +955,7 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
     return (-1);
   }
 
-  strncpy (vl.host, host->name, sizeof (vl.host));
-  vl.host[sizeof (vl.host) - 1] = '\0';
+  sstrncpy (vl.host, host->name, sizeof (vl.host));
   sstrncpy (vl.plugin, "snmp", sizeof (vl.plugin));
 
   vl.interval = host->interval;
@@ -972,30 +1019,28 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
        || (instance_list_ptr->subid == value_table_ptr[0]->subid));
 #endif
 
+    sstrncpy (vl.type, data->type, sizeof (vl.type));
+
     {
       char temp[DATA_MAX_NAME_LEN];
 
       if (instance_list_ptr == NULL)
-       snprintf (temp, sizeof (temp), "%u",
-           (uint32_t) subid);
+       ssnprintf (temp, sizeof (temp), "%u", (uint32_t) subid);
       else
-       strncpy (temp, instance_list_ptr->instance,
-           sizeof (temp));
-      temp[sizeof (temp) - 1] = '\0';
+       sstrncpy (temp, instance_list_ptr->instance, sizeof (temp));
 
       if (data->instance_prefix == NULL)
-       strncpy (vl.type_instance, temp, sizeof (vl.type_instance));
+       sstrncpy (vl.type_instance, temp, sizeof (vl.type_instance));
       else
-       snprintf (vl.type_instance, sizeof (vl.type_instance), "%s%s",
+       ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s%s",
            data->instance_prefix, temp);
-      vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
     }
 
     for (i = 0; i < data->values_len; i++)
       vl.values[i] = value_table_ptr[i]->value;
 
     /* If we get here `vl.type_instance' and all `vl.values' have been set */
-    plugin_dispatch_values (data->type, &vl);
+    plugin_dispatch_values (&vl);
 
     subid++;
   } /* while (have_more != 0) */
@@ -1292,11 +1337,10 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
       vl.values[i].gauge = NAN;
   }
 
-  strncpy (vl.host, host->name, sizeof (vl.host));
-  vl.host[sizeof (vl.host) - 1] = '\0';
+  sstrncpy (vl.host, host->name, sizeof (vl.host));
   sstrncpy (vl.plugin, "snmp", sizeof (vl.plugin));
-  strncpy (vl.type_instance, data->instance.string, sizeof (vl.type_instance));
-  vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+  sstrncpy (vl.type, data->type, sizeof (vl.type));
+  sstrncpy (vl.type_instance, data->instance.string, sizeof (vl.type_instance));
 
   vl.interval = host->interval;
 
@@ -1354,8 +1398,8 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
     snmp_free_pdu (res);
   res = NULL;
 
-  DEBUG ("snmp plugin: -> plugin_dispatch_values (%s, &vl);", data->type);
-  plugin_dispatch_values (data->type, &vl);
+  DEBUG ("snmp plugin: -> plugin_dispatch_values (&vl);");
+  plugin_dispatch_values (&vl);
   sfree (vl.values);
 
   return (0);
index 7fa72dc..8c09e35 100644 (file)
@@ -126,9 +126,10 @@ static void swap_submit (const char *type_instance, double value)
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "swap", sizeof (vl.plugin));
-       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+       sstrncpy (vl.type, "swap", sizeof (vl.type));
+       sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       plugin_dispatch_values ("swap", &vl);
+       plugin_dispatch_values (&vl);
 } /* void swap_submit */
 
 static int swap_read (void)
index 5b5cdb4..caca537 100644 (file)
@@ -71,10 +71,11 @@ static void tape_submit (const char *plugin_instance,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "tape", sizeof (vl.plugin));
-       strncpy (vl.plugin_instance, plugin_instance,
+       sstrncpy (vl.plugin_instance, plugin_instance,
                        sizeof (vl.plugin_instance));
+       sstrncpy (vl.type, type, sizeof (vl.type));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void tape_submit */
 
 static int tape_read (void)
index ff663b8..aa1fa38 100644 (file)
  *   Florian octo Forster <octo at verplant.org>
  **/
 
+/**
+ * Code within `HAVE_LIBKVM_NLIST' blocks is provided under the following
+ * license:
+ *
+ * $collectd: parts of tcpconns.c, 2008/08/08 03:48:30 Michael Stapelberg $
+ * $OpenBSD: inet.c,v 1.100 2007/06/19 05:28:30 ray Exp $
+ * $NetBSD: inet.c,v 1.14 1995/10/03 21:42:37 thorpej Exp $
+ *
+ * Copyright (c) 1983, 1988, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
 
-#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME
+#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME && !HAVE_LIBKVM_NLIST
 # error "No applicable input method."
 #endif
 
 # include <netinet/tcpip.h>
 # include <netinet/tcp_seq.h>
 # include <netinet/tcp_var.h>
-#endif /* HAVE_SYSCTLBYNAME */
+/* #endif HAVE_SYSCTLBYNAME */
+
+/* This is for OpenBSD and possibly NetBSD. */
+#elif HAVE_LIBKVM_NLIST
+# include <sys/queue.h>
+# include <sys/socket.h>
+# include <net/route.h>
+# include <netinet/in.h>
+# include <netinet/in_systm.h>
+# include <netinet/ip.h>
+# include <netinet/in_pcb.h>
+# include <netinet/tcp.h>
+# include <netinet/tcp_timer.h>
+# include <netinet/tcp_var.h>
+# include <netdb.h>
+# include <arpa/inet.h>
+# include <nlist.h>
+# include <kvm.h>
+#endif /* HAVE_LIBKVM_NLIST */
 
 #if KERNEL_LINUX
 static const char *tcp_state[] =
@@ -100,7 +154,32 @@ static const char *tcp_state[] =
 # define TCP_STATE_LISTEN 1
 # define TCP_STATE_MIN 0
 # define TCP_STATE_MAX 10
-#endif /* HAVE_SYSCTLBYNAME */
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif HAVE_LIBKVM_NLIST
+static const char *tcp_state[] =
+{
+  "CLOSED",
+  "LISTEN",
+  "SYN_SENT",
+  "SYN_RECV",
+  "ESTABLISHED",
+  "CLOSE_WAIT",
+  "FIN_WAIT1",
+  "CLOSING",
+  "LAST_ACK",
+  "FIN_WAIT2",
+  "TIME_WAIT"
+};
+
+static kvm_t *kvmd;
+static u_long      inpcbtable_off = 0;
+struct inpcbtable *inpcbtable_ptr = NULL;
+
+# define TCP_STATE_LISTEN 1
+# define TCP_STATE_MIN 1
+# define TCP_STATE_MAX 10
+#endif /* HAVE_LIBKVM_NLIST */
 
 #define PORT_COLLECT_LOCAL  0x01
 #define PORT_COLLECT_REMOTE 0x02
@@ -137,39 +216,36 @@ static void conn_submit_port_entry (port_entry_t *pe)
   vl.time = time (NULL);
   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "tcpconns", sizeof (vl.plugin));
+  sstrncpy (vl.type, "tcp_connections", sizeof (vl.type));
 
   if (((port_collect_listening != 0) && (pe->flags & PORT_IS_LISTENING))
       || (pe->flags & PORT_COLLECT_LOCAL))
   {
-    snprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
+    ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
        "%"PRIu16"-local", pe->port);
-    vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0';
 
     for (i = 1; i <= TCP_STATE_MAX; i++)
     {
       vl.values[0].gauge = pe->count_local[i];
 
-      strncpy (vl.type_instance, tcp_state[i], sizeof (vl.type_instance));
-      vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+      sstrncpy (vl.type_instance, tcp_state[i], sizeof (vl.type_instance));
 
-      plugin_dispatch_values ("tcp_connections", &vl);
+      plugin_dispatch_values (&vl);
     }
   }
 
   if (pe->flags & PORT_COLLECT_REMOTE)
   {
-    snprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
+    ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
        "%"PRIu16"-remote", pe->port);
-    vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0';
 
     for (i = 1; i <= TCP_STATE_MAX; i++)
     {
       vl.values[0].gauge = pe->count_remote[i];
 
-      strncpy (vl.type_instance, tcp_state[i], sizeof (vl.type_instance));
-      vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+      sstrncpy (vl.type_instance, tcp_state[i], sizeof (vl.type_instance));
 
-      plugin_dispatch_values ("tcp_connections", &vl);
+      plugin_dispatch_values (&vl);
     }
   }
 } /* void conn_submit */
@@ -363,7 +439,10 @@ static int conn_read_file (const char *file)
 /* #endif KERNEL_LINUX */
 
 #elif HAVE_SYSCTLBYNAME
-#endif /* HAVE_SYSCTLBYNAME */
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif HAVE_LIBKVM_NLIST
+#endif /* HAVE_LIBKVM_NLIST */
 
 static int conn_config (const char *key, const char *value)
 {
@@ -518,7 +597,107 @@ static int conn_read (void)
 
   return (0);
 } /* int conn_read */
-#endif /* HAVE_SYSCTLBYNAME */
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif HAVE_LIBKVM_NLIST
+static int kread (u_long addr, void *buf, int size)
+{
+  int status;
+
+  status = kvm_read (kvmd, addr, buf, size);
+  if (status != size)
+  {
+    ERROR ("tcpconns plugin: kvm_read failed (got %i, expected %i): %s\n",
+       status, size, kvm_geterr (kvmd));
+    return (-1);
+  }
+  return (0);
+} /* int kread */
+
+static int conn_init (void)
+{
+  char buf[_POSIX2_LINE_MAX];
+  struct nlist nl[] =
+  {
+#define N_TCBTABLE 0
+    { "_tcbtable" },
+    { "" }
+  };
+  int status;
+
+  kvmd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, buf);
+  if (kvmd == NULL)
+  {
+    ERROR ("tcpconns plugin: kvm_openfiles failed: %s", buf);
+    return (-1);
+  }
+
+  status = kvm_nlist (kvmd, nl);
+  if (status < 0)
+  {
+    ERROR ("tcpconns plugin: kvm_nlist failed with status %i.", status);
+    return (-1);
+  }
+
+  if (nl[N_TCBTABLE].n_type == 0)
+  {
+    ERROR ("tcpconns plugin: Error looking up kernel's namelist: "
+       "N_TCBTABLE is invalid.");
+    return (-1);
+  }
+
+  inpcbtable_off = (u_long) nl[N_TCBTABLE].n_value;
+  inpcbtable_ptr = (struct inpcbtable *) nl[N_TCBTABLE].n_value;
+
+  return (0);
+} /* int conn_init */
+
+static int conn_read (void)
+{
+  struct inpcbtable table;
+  struct inpcb *head;
+  struct inpcb *next;
+  struct inpcb inpcb;
+  struct tcpcb tcpcb;
+  int status;
+
+  conn_reset_port_entry ();
+
+  /* Read the pcbtable from the kernel */
+  status = kread (inpcbtable_off, &table, sizeof (table));
+  if (status != 0)
+    return (-1);
+
+  /* Get the `head' pcb */
+  head = (struct inpcb *) &(inpcbtable_ptr->inpt_queue);
+  /* Get the first pcb */
+  next = CIRCLEQ_FIRST (&table.inpt_queue);
+
+  while (next != head)
+  {
+    /* Read the pcb pointed to by `next' into `inpcb' */
+    kread ((u_long) next, &inpcb, sizeof (inpcb));
+
+    /* Advance `next' */
+    next = CIRCLEQ_NEXT (&inpcb, inp_queue);
+
+    /* Ignore sockets, that are not connected. */
+    if (!(inpcb.inp_flags & INP_IPV6)
+       && (inet_lnaof(inpcb.inp_laddr) == INADDR_ANY))
+      continue;
+    if ((inpcb.inp_flags & INP_IPV6)
+       && IN6_IS_ADDR_UNSPECIFIED (&inpcb.inp_laddr6))
+      continue;
+
+    kread ((u_long) inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb));
+    conn_handle_ports (ntohs(inpcb.inp_lport), ntohs(inpcb.inp_fport), tcpcb.t_state);
+  } /* while (next != head) */
+
+  conn_submit_all ();
+
+  return (0);
+}
+#endif /* HAVE_LIBKVM_NLIST */
 
 void module_register (void)
 {
@@ -526,10 +705,14 @@ void module_register (void)
                        config_keys, config_keys_num);
 #if KERNEL_LINUX
        plugin_register_init ("tcpconns", conn_init);
+#elif HAVE_SYSCTLBYNAME
+       /* no initialization */
+#elif HAVE_LIBKVM_NLIST
+       plugin_register_init ("tcpconns", conn_init);
 #endif
        plugin_register_read ("tcpconns", conn_read);
 } /* void module_register */
 
 /*
- * vim: set shiftwidth=2 softtabstop=2 tabstop=8 :
+ * vim: set shiftwidth=2 softtabstop=2 tabstop=8 fdm=marker :
  */
index 52a1007..5cd427a 100644 (file)
@@ -136,12 +136,14 @@ static void tss2_submit_gauge (const char *plugin_instance,
        if (plugin_instance != NULL)
                sstrncpy (vl.plugin_instance, plugin_instance,
                                sizeof (vl.plugin_instance));
-       
+
+       sstrncpy (vl.type, type, sizeof (vl.type));
+
        if (type_instance != NULL)
                sstrncpy (vl.type_instance, type_instance,
                                sizeof (vl.type_instance));
        
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void tss2_submit_gauge */
 
 static void tss2_submit_io (const char *plugin_instance, const char *type,
@@ -165,8 +167,10 @@ static void tss2_submit_io (const char *plugin_instance, const char *type,
        if (plugin_instance != NULL)
                sstrncpy (vl.plugin_instance, plugin_instance,
                                sizeof (vl.plugin_instance));
-       
-       plugin_dispatch_values (type, &vl);
+
+       sstrncpy (vl.type, type, sizeof (vl.type));
+
+       plugin_dispatch_values (&vl);
 } /* void tss2_submit_gauge */
 
 static void tss2_close_socket (void)
@@ -372,8 +376,7 @@ static int tss2_select_vserver (FILE *read_fh, FILE *write_fh, vserver_list_t *v
        int status;
 
        /* Send request */
-       snprintf (command, sizeof (command), "sel %i\r\n", vserver->port);
-       command[sizeof (command) - 1] = 0;
+       ssnprintf (command, sizeof (command), "sel %i\r\n", vserver->port);
 
        status = tss2_send_request (write_fh, command);
        if (status != 0)
@@ -527,9 +530,8 @@ static int tss2_read_vserver (vserver_list_t *vserver)
        else
        {
                /* Request server information */
-               snprintf (plugin_instance, sizeof (plugin_instance), "vserver%i",
+               ssnprintf (plugin_instance, sizeof (plugin_instance), "vserver%i",
                                vserver->port);
-               plugin_instance[sizeof (plugin_instance) - 1] = 0;
 
                /* Select the server */
                status = tss2_select_vserver (read_fh, write_fh, vserver);
diff --git a/src/thermal.c b/src/thermal.c
new file mode 100644 (file)
index 0000000..b613648
--- /dev/null
@@ -0,0 +1,272 @@
+/**
+ * collectd - src/thermal.c
+ * Copyright (C) 2008  MichaÅ‚ MirosÅ‚aw
+ *
+ * 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:
+ *   MichaÅ‚ MirosÅ‚aw <mirq-linux at rere.qmqm.pl>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+#include "utils_ignorelist.h"
+
+#if !KERNEL_LINUX
+# error "This module is for Linux only."
+#endif
+
+const char *const dirname_sysfs = "/sys/class/thermal";
+const char *const dirname_procfs = "/proc/acpi/thermal_zone";
+
+static char force_procfs = 0;
+static ignorelist_t *device_list;
+static value_list_t vl_temp_template = VALUE_LIST_STATIC;
+static value_list_t vl_state_template = VALUE_LIST_STATIC;
+
+enum dev_type {
+       TEMP = 0,
+       COOLING_DEV
+};
+
+static void thermal_submit (const char *plugin_instance, enum dev_type dt,
+               gauge_t value)
+{
+       value_list_t vl = (dt == TEMP) ? vl_temp_template : vl_state_template;
+       value_t vt;
+
+       vt.gauge = value;
+
+       vl.values = &vt;
+       vl.time = time (NULL);
+       sstrncpy (vl.plugin, "thermal", sizeof(vl.plugin));
+       sstrncpy (vl.plugin_instance, plugin_instance,
+                       sizeof(vl.plugin_instance));
+       sstrncpy (vl.type, (dt == TEMP) ? "temperature" : "gauge",
+                       sizeof (vl.type));
+
+       plugin_dispatch_values (&vl);
+}
+
+static int thermal_sysfs_device_read (const char *dir, const char *name,
+               void *user_data)
+{
+       char filename[256];
+       char data[1024];
+       int len;
+       int ok = 0;
+
+       if (device_list && ignorelist_match (device_list, name))
+               return -1;
+
+       len = snprintf (filename, sizeof (filename), "%s/%s/temp", dirname_sysfs, name);
+       if ((len < 0) || ((unsigned int)len >= sizeof (filename)))
+               return -1;
+
+       len = read_file_contents (filename, data, sizeof(data));
+       if (len > 1 && data[--len] == '\n') {
+               char *endptr = NULL;
+               double temp;
+
+               data[len] = 0;
+               errno = 0;
+               temp = strtod (data, &endptr) / 1000.0;
+
+               if (endptr == data + len && errno == 0) {
+                       thermal_submit(name, TEMP, temp);
+                       ++ok;
+               }
+       }
+
+       len = snprintf (filename, sizeof (filename), "%s/%s/cur_state", dirname_sysfs, name);
+       if ((len < 0) || ((unsigned int)len >= sizeof (filename)))
+               return -1;
+
+       len = read_file_contents (filename, data, sizeof(data));
+       if (len > 1 && data[--len] == '\n') {
+               char *endptr = NULL;
+               double state;
+
+               data[len] = 0;
+               errno = 0;
+               state = strtod (data, &endptr);
+
+               if (endptr == data + len && errno == 0) {
+                       thermal_submit(name, COOLING_DEV, state);
+                       ++ok;
+               }
+       }
+
+       return ok ? 0 : -1;
+}
+
+static int thermal_procfs_device_read (const char *dir, const char *name,
+               void *user_data)
+{
+       const char str_temp[] = "temperature:";
+       char filename[256];
+       char data[1024];
+       int len;
+
+       if (device_list && ignorelist_match (device_list, name))
+               return -1;
+
+       /**
+        * rechot ~ # cat /proc/acpi/thermal_zone/THRM/temperature
+        * temperature:             55 C
+        */
+       
+       len = snprintf (filename, sizeof (filename), "%s/%s/temperature", dirname_procfs, name);
+       if ((len < 0) || ((unsigned int)len >= sizeof (filename)))
+               return -1;
+
+       len = read_file_contents (filename, data, sizeof(data));
+       if (len > sizeof(str_temp) && data[--len] == '\n' && !strncmp(data, str_temp, sizeof(str_temp)-1)) {
+               char *endptr = NULL;
+               double temp;
+               double celsius, add;
+               
+               if (data[--len] == 'C') {
+                       add = 0;
+                       celsius = 1;
+               } else if (data[len] == 'F') {
+                       add = -32;
+                       celsius = 5/9;
+               } else if (data[len] == 'K') {
+                       add = -273.15;
+                       celsius = 1;
+               } else
+                       return -1;
+
+               while (len > 0 && data[--len] == ' ')
+                       ;
+               data[len + 1] = 0;
+
+               while (len > 0 && data[--len] != ' ')
+                       ;
+               ++len;
+
+               errno = 0;
+               temp = (strtod (data + len, &endptr) + add) * celsius;
+
+               if (endptr != data + len && errno == 0) {
+                       thermal_submit(name, TEMP, temp);
+                       return 0;
+               }
+       }
+
+       return -1;
+}
+
+static const char *config_keys[] = {
+       "Device",
+       "IgnoreSelected",
+       "ForceUseProcfs"
+};
+
+static int thermal_config (const char *key, const char *value)
+{
+       if (device_list == NULL)
+               device_list = ignorelist_create (1);
+
+       if (strcasecmp (key, "Device") == 0)
+       {
+               if (ignorelist_add (device_list, value))
+               {
+                       ERROR ("thermal plugin: "
+                                       "Cannot add value to ignorelist.");
+                       return 1;
+               }
+       }
+       else if (strcasecmp (key, "IgnoreSelected") == 0)
+       {
+               ignorelist_set_invert (device_list, 1);
+               if ((strcasecmp (value, "True") == 0)
+                               || (strcasecmp (value, "Yes") == 0)
+                               || (strcasecmp (value, "On") == 0))
+                       ignorelist_set_invert (device_list, 0);
+       }
+       else if (strcasecmp (key, "ForceUseProcfs") == 0)
+       {
+               force_procfs = 0;
+               if ((strcasecmp (value, "True") == 0)
+                               || (strcasecmp (value, "Yes") == 0)
+                               || (strcasecmp (value, "On") == 0))
+                       force_procfs = 1;
+       }
+       else
+       {
+               return -1;
+       }
+
+       return 0;
+}
+
+static int thermal_sysfs_read (void)
+{
+       return walk_directory (dirname_sysfs, thermal_sysfs_device_read,
+                       /* user_data = */ NULL);
+}
+
+static int thermal_procfs_read (void)
+{
+       return walk_directory (dirname_procfs, thermal_procfs_device_read,
+                       /* user_data = */ NULL);
+}
+
+static int thermal_init (void)
+{
+       int ret = -1;
+
+       if (!force_procfs && access (dirname_sysfs, R_OK | X_OK) == 0) {
+               ret = plugin_register_read ("thermal", thermal_sysfs_read);
+       } else if (access (dirname_procfs, R_OK | X_OK) == 0) {
+               ret = plugin_register_read ("thermal", thermal_procfs_read);
+       }
+
+       if (!ret) {
+               vl_temp_template.values_len = 1;
+               vl_temp_template.interval = interval_g;
+               sstrncpy (vl_temp_template.host, hostname_g,
+                       sizeof(vl_temp_template.host));
+               sstrncpy (vl_temp_template.plugin, "thermal",
+                       sizeof(vl_temp_template.plugin));
+               sstrncpy (vl_temp_template.type_instance, "temperature",
+                       sizeof(vl_temp_template.type_instance));
+
+               vl_state_template = vl_temp_template;
+               sstrncpy (vl_state_template.type_instance, "cooling_state",
+                       sizeof(vl_state_template.type_instance));
+       }
+
+       return ret;
+}
+
+static int thermal_shutdown (void)
+{
+       ignorelist_free (device_list);
+
+       return 0;
+}
+
+void module_register (void)
+{
+       plugin_register_config ("thermal", thermal_config,
+                       config_keys, STATIC_ARRAY_SIZE(config_keys));
+       plugin_register_init ("thermal", thermal_init);
+       plugin_register_shutdown ("thermal", thermal_shutdown);
+}
+
index 438b3db..a3b51dc 100644 (file)
@@ -3,8 +3,9 @@ apache_connections      count:GAUGE:0:65535
 apache_requests                count:COUNTER:0:134217728
 apache_scoreboard      count:GAUGE:0:65535
 bitrate                        value:GAUGE:0:4294967295
+bytes                  value:GAUGE:0:U
 cache_result           value:COUNTER:0:4294967295
-cache_size              value:GAUGE:0:4294967295
+cache_size             value:GAUGE:0:4294967295
 charge                 value:GAUGE:0:U
 connections            value:COUNTER:0:U
 counter                        value:COUNTER:U:U
@@ -28,6 +29,7 @@ email_count           value:GAUGE:0:U
 email_size             value:GAUGE:0:U
 entropy                        entropy:GAUGE:0:4294967295
 fanspeed               value:GAUGE:0:U
+files                  value:GAUGE:0:U
 frequency              frequency:GAUGE:0:U
 frequency_offset       ppm:GAUGE:-1000000:1000000
 gauge                  value:GAUGE:U:U
@@ -63,6 +65,13 @@ nfs_procedure                value:COUNTER:0:4294967295
 nginx_connections      value:GAUGE:0:U
 nginx_requests         value:COUNTER:0:134217728
 percent                        percent:GAUGE:0:100.1
+pg_blks                        value:COUNTER:0:U
+pg_db_size             value:GAUGE:0:U
+pg_n_tup_c             value:COUNTER:0:U
+pg_n_tup_g             value:GAUGE:0:U
+pg_numbackends         value:GAUGE:0:U
+pg_scan                        value:COUNTER:0:U
+pg_xact                        value:COUNTER:0:U
 ping                   ping:GAUGE:0:65535
 players                        value:GAUGE:0:1000000
 power                  value:GAUGE:0:U
index 3be792d..7600c34 100644 (file)
@@ -34,7 +34,7 @@ static int parse_ds (data_source_t *dsrc, char *buf, size_t buf_len)
 
   if (buf_len < 11)
   {
-    ERROR ("parse_ds: (buf_len = %u) < 11", buf_len);
+    ERROR ("parse_ds: (buf_len = %zu) < 11", buf_len);
     return (-1);
   }
 
@@ -62,8 +62,7 @@ static int parse_ds (data_source_t *dsrc, char *buf, size_t buf_len)
     return (-1);
   }
 
-  strncpy (dsrc->name, fields[0], sizeof (dsrc->name));
-  dsrc->name[sizeof (dsrc->name) - 1] = '\0';
+  sstrncpy (dsrc->name, fields[0], sizeof (dsrc->name));
 
   if (strcasecmp (fields[1], "GAUGE") == 0)
     dsrc->type = DS_TYPE_GAUGE;
@@ -105,8 +104,7 @@ static void parse_line (char *buf)
 
   memset (ds, '\0', sizeof (data_set_t));
 
-  strncpy (ds->type, fields[0], sizeof (ds->type));
-  ds->type[sizeof (ds->type) - 1] = '\0';
+  sstrncpy (ds->type, fields[0], sizeof (ds->type));
 
   ds->ds_num = fields_num - 1;
   ds->ds = (data_source_t *) calloc (ds->ds_num, sizeof (data_source_t));
index 3dac88a..3bdd8c2 100644 (file)
@@ -86,8 +86,8 @@ static int us_open_socket (void)
 
        memset (&sa, '\0', sizeof (sa));
        sa.sun_family = AF_UNIX;
-       strncpy (sa.sun_path, (sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
-                       sizeof (sa.sun_path) - 1);
+       sstrncpy (sa.sun_path, (sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
+                       sizeof (sa.sun_path));
        /* unlink (sa.sun_path); */
 
        DEBUG ("unixsock plugin: socket path = %s", sa.sun_path);
@@ -159,15 +159,12 @@ static void *us_handle_client (void *arg)
 {
        int fd;
        FILE *fhin, *fhout;
-       char buffer[1024];
-       char *fields[128];
-       int   fields_num;
 
        fd = *((int *) arg);
        free (arg);
        arg = NULL;
 
-       DEBUG ("Reading from fd #%i", fd);
+       DEBUG ("unixsock plugin: us_handle_client: Reading from fd #%i", fd);
 
        fhin  = fdopen (fd, "r");
        if (fhin == NULL)
@@ -202,7 +199,11 @@ static void *us_handle_client (void *arg)
 
        while (42)
        {
-               int len;
+               char buffer[1024];
+               char buffer_copy[1024];
+               char *fields[128];
+               int   fields_num;
+               int   len;
 
                errno = 0;
                if (fgets (buffer, sizeof (buffer), fhin) == NULL)
@@ -225,9 +226,9 @@ static void *us_handle_client (void *arg)
                if (len == 0)
                        continue;
 
-               DEBUG ("fgets -> buffer = %s; len = %i;", buffer, len);
+               sstrncpy (buffer_copy, buffer, sizeof (buffer_copy));
 
-               fields_num = strsplit (buffer, fields,
+               fields_num = strsplit (buffer_copy, fields,
                                sizeof (fields) / sizeof (fields[0]));
 
                if (fields_num < 1)
@@ -238,23 +239,23 @@ static void *us_handle_client (void *arg)
 
                if (strcasecmp (fields[0], "getval") == 0)
                {
-                       handle_getval (fhout, fields, fields_num);
+                       handle_getval (fhout, buffer);
                }
                else if (strcasecmp (fields[0], "putval") == 0)
                {
-                       handle_putval (fhout, fields, fields_num);
+                       handle_putval (fhout, buffer);
                }
                else if (strcasecmp (fields[0], "listval") == 0)
                {
-                       handle_listval (fhout, fields, fields_num);
+                       handle_listval (fhout, buffer);
                }
                else if (strcasecmp (fields[0], "putnotif") == 0)
                {
-                       handle_putnotif (fhout, fields, fields_num);
+                       handle_putnotif (fhout, buffer);
                }
                else if (strcasecmp (fields[0], "flush") == 0)
                {
-                       handle_flush (fhout, fields, fields_num);
+                       handle_flush (fhout, buffer);
                }
                else
                {
@@ -269,7 +270,7 @@ static void *us_handle_client (void *arg)
                }
        } /* while (fgets) */
 
-       DEBUG ("Exiting..");
+       DEBUG ("unixsock plugin: us_handle_client: Exiting..");
        fclose (fhin);
        fclose (fhout);
 
index d0bd63c..1231075 100644 (file)
@@ -51,8 +51,9 @@ static void users_submit (gauge_t value)
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "users", sizeof (vl.plugin));
+       sstrncpy (vl.type, "users", sizeof (vl.plugin));
 
-       plugin_dispatch_values ("users", &vl);
+       plugin_dispatch_values (&vl);
 } /* void users_submit */
 
 static int users_read (void)
index 7938412..824b7c8 100644 (file)
@@ -156,13 +156,12 @@ static int uc_send_notification (const char *name)
     return (-1);
   }
 
-  snprintf (n.message, sizeof (n.message),
+  ssnprintf (n.message, sizeof (n.message),
       "%s has not been updated for %i seconds.", name,
       (int) (n.time - ce->last_update));
 
   pthread_mutex_unlock (&cache_lock);
 
-  n.message[sizeof (n.message) - 1] = '\0';
   plugin_dispatch_notification (&n);
 
   return (0);
@@ -328,7 +327,7 @@ int uc_check_timeout (void)
     }
     else
     {
-      WARNING ("uc_check_timeout: ut_check_interesting (%s) returned ",
+      WARNING ("uc_check_timeout: ut_check_interesting (%s) returned "
          "invalid status %i.",
          keys[i], status);
     }
@@ -453,10 +452,9 @@ int uc_update (const data_set_t *ds, const value_list_t *vl)
   n.severity = NOTIF_OKAY;
   n.time = vl->time;
 
-  snprintf (n.message, sizeof (n.message),
+  ssnprintf (n.message, sizeof (n.message),
       "Received a value for %s. It was missing for %u seconds.",
       name, (unsigned int) update_delay);
-  n.message[sizeof (n.message) - 1] = '\0';
 
   plugin_dispatch_notification (&n);
 
@@ -527,7 +525,7 @@ gauge_t *uc_get_rate (const data_set_t *ds, const value_list_t *vl)
   if (ret_num != ds->ds_num)
   {
     ERROR ("utils_cache: uc_get_rate: ds[%s] has %i values, "
-       "but uc_get_rate_by_name returned %i.",
+       "but uc_get_rate_by_name returned %zu.",
        ds->type, ds->ds_num, ret_num);
     sfree (ret);
     return (NULL);
index 6fa8b7b..0e7b350 100644 (file)
@@ -24,6 +24,7 @@
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
+#include "utils_parse_option.h"
 
 #define print_to_socket(fh, ...) \
        if (fprintf (fh, __VA_ARGS__) < 0) { \
                return -1; \
        }
 
-int handle_flush (FILE *fh, char **fields, int fields_num)
+static int add_to_array (char ***array, int *array_num, char *value)
+{
+       char **temp;
+
+       temp = (char **) realloc (*array, sizeof (char *) * (*array_num + 1));
+       if (temp == NULL)
+               return (-1);
+
+       *array = temp;
+       (*array)[*array_num] = value;
+       (*array_num)++;
+
+       return (0);
+} /* int add_to_array */
+
+int handle_flush (FILE *fh, char *buffer)
 {
        int success = 0;
        int error   = 0;
 
        int timeout = -1;
+       char **plugins = NULL;
+       int plugins_num = 0;
+       char **identifiers = NULL;
+       int identifiers_num = 0;
 
        int i;
 
-       for (i = 1; i < fields_num; i++)
+       if ((fh == NULL) || (buffer == NULL))
+               return (-1);
+
+       DEBUG ("utils_cmd_flush: handle_flush (fh = %p, buffer = %s);",
+                       (void *) fh, buffer);
+
+       if (strncasecmp ("FLUSH", buffer, strlen ("FLUSH")) != 0)
        {
-               char *option = fields[i];
-               int   status = 0;
+               print_to_socket (fh, "-1 Cannot parse command.\n");
+               return (-1);
+       }
+       buffer += strlen ("FLUSH");
+
+       while (*buffer != 0)
+       {
+               char *opt_key;
+               char *opt_value;
+               int status;
 
-               if (strncasecmp ("plugin=", option, strlen ("plugin=")) == 0)
+               opt_key = NULL;
+               opt_value = NULL;
+               status = parse_option (&buffer, &opt_key, &opt_value);
+               if (status != 0)
                {
-                       char *plugin = option + strlen ("plugin=");
+                       print_to_socket (fh, "-1 Parsing options failed.\n");
+                       sfree (plugins);
+                       sfree (identifiers);
+                       return (-1);
+               }
 
-                       if (0 == plugin_flush_one (timeout, plugin))
-                               ++success;
-                       else
-                               ++error;
+               if (strcasecmp ("plugin", opt_key) == 0)
+               {
+                       add_to_array (&plugins, &plugins_num, opt_value);
                }
-               else if (strncasecmp ("timeout=", option, strlen ("timeout=")) == 0)
+               else if (strcasecmp ("identifier", opt_key) == 0)
                {
-                       char *endptr = NULL;
-                       char *value  = option + strlen ("timeout=");
-
+                       add_to_array (&identifiers, &identifiers_num, opt_value);
+               }
+               else if (strcasecmp ("timeout", opt_key) == 0)
+               {
+                       char *endptr;
+                       
                        errno = 0;
-                       timeout = strtol (value, &endptr, 0);
+                       endptr = NULL;
+                       timeout = strtol (opt_value, &endptr, 0);
 
-                       if ((endptr == value) || (0 != errno))
-                               status = -1;
-                       else if (0 >= timeout)
+                       if ((endptr == opt_value) || (errno != 0))
+                       {
+                               print_to_socket (fh, "-1 Invalid value for option `timeout': "
+                                               "%s\n", opt_value);
+                               sfree (plugins);
+                               sfree (identifiers);
+                               return (-1);
+                       }
+                       else if (timeout <= 0)
                                timeout = -1;
                }
                else
-                       status = -1;
-
-               if (status != 0)
                {
-                       print_to_socket (fh, "-1 Cannot parse option %s\n", option);
+                       print_to_socket (fh, "-1 Cannot parse option %s\n", opt_key);
+                       sfree (plugins);
+                       sfree (identifiers);
                        return (-1);
                }
+       } /* while (*buffer != 0) */
+
+       /* Add NULL entries for `any plugin' and/or `any value' if nothing was
+        * specified. */
+       if (plugins_num == 0)
+               add_to_array (&plugins, &plugins_num, NULL);
+
+       if (identifiers_num == 0)
+               add_to_array (&identifiers, &identifiers_num, NULL);
+
+       for (i = 0; i < plugins_num; i++)
+       {
+               char *plugin;
+               int j;
+
+               plugin = plugins[i];
+
+               for (j = 0; j < identifiers_num; j++)
+               {
+                       char *identifier;
+                       int status;
+
+                       identifier = identifiers[j];
+                       status = plugin_flush (plugin, timeout, identifier);
+                       if (status == 0)
+                               success++;
+                       else
+                               error++;
+               }
        }
 
        if ((success + error) > 0)
@@ -86,10 +164,12 @@ int handle_flush (FILE *fh, char **fields, int fields_num)
        }
        else
        {
-               plugin_flush_all (timeout);
+               plugin_flush (NULL, timeout, NULL);
                print_to_socket (fh, "0 Done\n");
        }
 
+       sfree (plugins);
+       sfree (identifiers);
        return (0);
 } /* int handle_flush */
 
index 334f086..dccafd1 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef UTILS_CMD_FLUSH_H
 #define UTILS_CMD_FLUSH_H 1
 
-int handle_flush (FILE *fh, char **fields, int fields_num);
+int handle_flush (FILE *fh, char *buffer);
 
 #endif /* UTILS_CMD_FLUSH_H */
 
index 470d302..186ef9b 100644 (file)
@@ -24,6 +24,7 @@
 #include "plugin.h"
 
 #include "utils_cache.h"
+#include "utils_parse_option.h"
 
 #define print_to_socket(fh, ...) \
   if (fprintf (fh, __VA_ARGS__) < 0) { \
     return -1; \
   }
 
-int handle_getval (FILE *fh, char **fields, int fields_num)
+int handle_getval (FILE *fh, char *buffer)
 {
+  char *command;
+  char *identifier;
+  char *identifier_copy;
+
   char *hostname;
   char *plugin;
   char *plugin_instance;
@@ -43,39 +48,58 @@ int handle_getval (FILE *fh, char **fields, int fields_num)
   gauge_t *values;
   size_t values_num;
 
-  char *identifier_copy;
-
   const data_set_t *ds;
 
   int   status;
   int   i;
 
-  if (fields_num != 2)
+  if ((fh == NULL) || (buffer == NULL))
+    return (-1);
+
+  DEBUG ("utils_cmd_getval: handle_getval (fh = %p, buffer = %s);",
+      (void *) fh, buffer);
+
+  command = NULL;
+  status = parse_string (&buffer, &command);
+  if (status != 0)
   {
-    DEBUG ("unixsock plugin: Wrong number of fields: %i", fields_num);
-    print_to_socket (fh, "-1 Wrong number of fields: Got %i, expected 2.\n",
-       fields_num);
+    print_to_socket (fh, "-1 Cannot parse command.\n");
     return (-1);
   }
-  DEBUG ("unixsock plugin: Got query for `%s'", fields[1]);
+  assert (command != NULL);
 
-  if (strlen (fields[1]) < strlen ("h/p/t"))
+  if (strcasecmp ("GETVAL", command) != 0)
   {
-    print_to_socket (fh, "-1 Invalied identifier, %s\n", fields[1]);
+    print_to_socket (fh, "-1 Unexpected command: `%s'.\n", command);
+    return (-1);
+  }
+
+  identifier = NULL;
+  status = parse_string (&buffer, &identifier);
+  if (status != 0)
+  {
+    print_to_socket (fh, "-1 Cannot parse identifier.\n");
+    return (-1);
+  }
+  assert (identifier != NULL);
+
+  if (*buffer != 0)
+  {
+    print_to_socket (fh, "-1 Garbage after end of command: %s\n", buffer);
     return (-1);
   }
 
   /* parse_identifier() modifies its first argument,
    * returning pointers into it */
-  identifier_copy = sstrdup (fields[1]);
+  identifier_copy = sstrdup (identifier);
 
   status = parse_identifier (identifier_copy, &hostname,
       &plugin, &plugin_instance,
       &type, &type_instance);
   if (status != 0)
   {
-    DEBUG ("unixsock plugin: Cannot parse `%s'", fields[1]);
-    print_to_socket (fh, "-1 Cannot parse identifier.\n");
+    DEBUG ("handle_getval: Cannot parse identifier `%s'.", identifier);
+    print_to_socket (fh, "-1 Cannot parse identifier `%s'.\n", identifier);
     sfree (identifier_copy);
     return (-1);
   }
@@ -83,7 +107,7 @@ int handle_getval (FILE *fh, char **fields, int fields_num)
   ds = plugin_get_ds (type);
   if (ds == NULL)
   {
-    DEBUG ("unixsock plugin: plugin_get_ds (%s) == NULL;", type);
+    DEBUG ("handle_getval: plugin_get_ds (%s) == NULL;", type);
     print_to_socket (fh, "-1 Type `%s' is unknown.\n", type);
     sfree (identifier_copy);
     return (-1);
@@ -91,7 +115,7 @@ int handle_getval (FILE *fh, char **fields, int fields_num)
 
   values = NULL;
   values_num = 0;
-  status = uc_get_rate_by_name (fields[1], &values, &values_num);
+  status = uc_get_rate_by_name (identifier, &values, &values_num);
   if (status != 0)
   {
     print_to_socket (fh, "-1 No such value\n");
index d7bd115..86134cd 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef UTILS_CMD_GETVAL_H
 #define UTILS_CMD_GETVAL_H 1
 
-int handle_getval (FILE *fh, char **fields, int fields_num);
+int handle_getval (FILE *fh, char *buffer);
 
 #endif /* UTILS_CMD_GETVAL_H */
 
index 6f03e75..bca83a9 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "utils_cmd_listval.h"
 #include "utils_cache.h"
+#include "utils_parse_option.h"
 
 #define print_to_socket(fh, ...) \
   if (fprintf (fh, __VA_ARGS__) < 0) { \
     return -1; \
   }
 
-int handle_listval (FILE *fh, char **fields, int fields_num)
+int handle_listval (FILE *fh, char *buffer)
 {
+  char *command;
   char **names = NULL;
   time_t *times = NULL;
   size_t number = 0;
   size_t i;
   int status;
 
-  if (fields_num != 1)
+  DEBUG ("utils_cmd_listval: handle_listval (fh = %p, buffer = %s);",
+      (void *) fh, buffer);
+
+  command = NULL;
+  status = parse_string (&buffer, &command);
+  if (status != 0)
+  {
+    print_to_socket (fh, "-1 Cannot parse command.\n");
+    return (-1);
+  }
+  assert (command != NULL);
+
+  if (strcasecmp ("LISTVAL", command) != 0)
+  {
+    print_to_socket (fh, "-1 Unexpected command: `%s'.\n", command);
+    return (-1);
+  }
+
+  if (*buffer != 0)
   {
-    DEBUG ("command listval: us_handle_listval: Wrong number of fields: %i",
-       fields_num);
-    print_to_socket (fh, "-1 Wrong number of fields: Got %i, expected 1.\n",
-       fields_num);
+    print_to_socket (fh, "-1 Garbage after end of command: %s\n", buffer);
     return (-1);
   }
 
index c918796..73146e7 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef UTILS_CMD_LISTVAL_H
 #define UTILS_CMD_LISTVAL_H 1
 
-int handle_listval (FILE *fh, char **fields, int fields_num);
+int handle_listval (FILE *fh, char *buffer);
 
 #endif /* UTILS_CMD_LISTVAL_H */
 
index eb7d60b..5a9faff 100644 (file)
@@ -23,6 +23,8 @@
 #include "common.h"
 #include "plugin.h"
 
+#include "utils_parse_option.h"
+
 #define print_to_socket(fh, ...) \
   if (fprintf (fh, __VA_ARGS__) < 0) { \
     char errbuf[1024]; \
@@ -31,7 +33,7 @@
     return -1; \
   }
 
-static int parse_option_severity (notification_t *n, char *value)
+static int set_option_severity (notification_t *n, const char *value)
 {
   if (strcasecmp (value, "Failure") == 0)
     n->severity = NOTIF_FAILURE;
@@ -43,9 +45,9 @@ static int parse_option_severity (notification_t *n, char *value)
     return (-1);
 
   return (0);
-} /* int parse_option_severity */
+} /* int set_option_severity */
 
-static int parse_option_time (notification_t *n, char *value)
+static int set_option_time (notification_t *n, const char *value)
 {
   time_t tmp;
   
@@ -56,25 +58,22 @@ static int parse_option_time (notification_t *n, char *value)
   n->time = tmp;
 
   return (0);
-} /* int parse_option_time */
+} /* int set_option_time */
 
-static int parse_option (notification_t *n, char *buffer)
+static int set_option (notification_t *n, const char *option, const char *value)
 {
-  char *option = buffer;
-  char *value;
-
-  if ((n == NULL) || (option == NULL))
+  if ((n == NULL) || (option == NULL) || (value == NULL))
     return (-1);
 
-  value = strchr (option, '=');
-  if (value == NULL)
-    return (-1);
-  *value = '\0'; value++;
+  DEBUG ("utils_cmd_putnotif: set_option (option = %s, value = %s);",
+      option, value);
 
   if (strcasecmp ("severity", option) == 0)
-    return (parse_option_severity (n, value));
+    return (set_option_severity (n, value));
   else if (strcasecmp ("time", option) == 0)
-    return (parse_option_time (n, value));
+    return (set_option_time (n, value));
+  else if (strcasecmp ("message", option) == 0)
+    sstrncpy (n->message, value, sizeof (n->message));
   else if (strcasecmp ("host", option) == 0)
     sstrncpy (n->host, value, sizeof (n->host));
   else if (strcasecmp ("plugin", option) == 0)
@@ -89,61 +88,55 @@ static int parse_option (notification_t *n, char *buffer)
     return (1);
 
   return (0);
-} /* int parse_option */
+} /* int set_option */
 
-static int parse_message (notification_t *n, char **fields, int fields_num)
+int handle_putnotif (FILE *fh, char *buffer)
 {
+  char *command;
+  notification_t n;
   int status;
 
-  /* Strip off the leading `message=' */
-  fields[0] += strlen ("message=");
-
-  status = strjoin (n->message, sizeof (n->message), fields, fields_num, " ");
-  if (status < 0)
+  if ((fh == NULL) || (buffer == NULL))
     return (-1);
 
-  return (0);
-} /* int parse_message */
+  DEBUG ("utils_cmd_putnotif: handle_putnotif (fh = %p, buffer = %s);",
+      (void *) fh, buffer);
 
-int handle_putnotif (FILE *fh, char **fields, int fields_num)
-{
-  notification_t n;
-  int status;
-  int i;
+  command = NULL;
+  status = parse_string (&buffer, &command);
+  if (status != 0)
+  {
+    print_to_socket (fh, "-1 Cannot parse command.\n");
+    return (-1);
+  }
+  assert (command != NULL);
 
-  /* Required fields: `PUTNOTIF', severity, time, message */
-  if (fields_num < 4)
+  if (strcasecmp ("PUTNOTIF", command) != 0)
   {
-    DEBUG ("cmd putnotif: Wrong number of fields: %i", fields_num);
-    print_to_socket (fh, "-1 Wrong number of fields: Got %i, "
-       "expected at least 4.\n",
-       fields_num);
+    print_to_socket (fh, "-1 Unexpected command: `%s'.\n", command);
     return (-1);
   }
 
   memset (&n, '\0', sizeof (n));
 
   status = 0;
-  for (i = 1; i < fields_num; i++)
+  while (*buffer != 0)
   {
-    if (strncasecmp (fields[i], "message=", strlen ("message=")) == 0)
+    char *key;
+    char *value;
+
+    status = parse_option (&buffer, &key, &value);
+    if (status != 0)
     {
-      status = parse_message (&n, fields + i, fields_num - i);
-      if (status != 0)
-      {
-       print_to_socket (fh, "-1 Error parsing the message. Have you hit the "
-           "limit of %u bytes?\n", (unsigned int) sizeof (n.message));
-      }
+      print_to_socket (fh, "-1 Malformed option.\n");
       break;
     }
-    else
+
+    status = set_option (&n, key, value);
+    if (status != 0)
     {
-      status = parse_option (&n, fields[i]);
-      if (status != 0)
-      {
-       print_to_socket (fh, "-1 Error parsing option `%s'\n", fields[i]);
-       break;
-      }
+      print_to_socket (fh, "-1 Error parsing option `%s'\n", key);
+      break;
     }
   } /* for (i) */
 
index 08b3bb3..8d5475b 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef UTILS_CMD_PUTNOTIF_H
 #define UTILS_CMD_PUTNOTIF_H 1
 
-int handle_putnotif (FILE *fh, char **fields, int fields_num);
+int handle_putnotif (FILE *fh, char *buffer);
 
 /* vim: set shiftwidth=2 softtabstop=2 tabstop=8 : */
 
index 16a09b1..91b7016 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/utils_cms_putval.c
- * Copyright (C) 2007  Florian octo Forster
+ * Copyright (C) 2007,2008  Florian octo Forster
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -23,6 +23,8 @@
 #include "common.h"
 #include "plugin.h"
 
+#include "utils_parse_option.h"
+
 #define print_to_socket(fh, ...) \
        if (fprintf (fh, __VA_ARGS__) < 0) { \
                char errbuf[1024]; \
@@ -32,7 +34,6 @@
        }
 
 static int parse_value (const data_set_t *ds, value_list_t *vl,
-               const char *type,
                FILE *fh, char *buffer)
 {
        char *dummy;
@@ -90,28 +91,27 @@ static int parse_value (const data_set_t *ds, value_list_t *vl,
                return (-1);
        }
 
-       plugin_dispatch_values (type, vl);
+       plugin_dispatch_values (vl);
        return (0);
 } /* int parse_value */
 
-static int parse_option (value_list_t *vl, char *buffer)
+static int set_option (value_list_t *vl, const char *key, const char *value)
 {
-       char *option = buffer;
-       char *value;
-
-       if ((vl == NULL) || (option == NULL))
-               return (-1);
-
-       value = strchr (option, '=');
-       if (value == NULL)
+       if ((vl == NULL) || (key == NULL) || (value == NULL))
                return (-1);
-       *value = '\0'; value++;
 
-       if (strcasecmp ("interval", option) == 0)
+       if (strcasecmp ("interval", key) == 0)
        {
-               vl->interval = atoi (value);
-               if (vl->interval <= 0)
-                       vl->interval = interval_g;
+               int tmp;
+               char *endptr;
+
+               endptr = NULL;
+               errno = 0;
+               tmp = strtol (value, &endptr, 0);
+
+               if ((errno == 0) && (endptr != NULL)
+                               && (endptr != value) && (tmp > 0))
+                       vl->interval = tmp;
        }
        else
                return (1);
@@ -119,42 +119,63 @@ static int parse_option (value_list_t *vl, char *buffer)
        return (0);
 } /* int parse_option */
 
-int handle_putval (FILE *fh, char **fields, int fields_num)
+int handle_putval (FILE *fh, char *buffer)
 {
+       char *command;
+       char *identifier;
        char *hostname;
        char *plugin;
        char *plugin_instance;
        char *type;
        char *type_instance;
        int   status;
-       int   i;
+       int   values_submitted;
 
        char *identifier_copy;
 
        const data_set_t *ds;
        value_list_t vl = VALUE_LIST_INIT;
 
-       if (fields_num < 3)
+       DEBUG ("utils_cmd_putval: handle_putval (fh = %p, buffer = %s);",
+                       (void *) fh, buffer);
+
+       command = NULL;
+       status = parse_string (&buffer, &command);
+       if (status != 0)
        {
-               DEBUG ("cmd putval: Wrong number of fields: %i",
-                               fields_num);
-               print_to_socket (fh, "-1 Wrong number of fields: Got %i, "
-                               "expected at least 3.\n",
-                               fields_num);
+               print_to_socket (fh, "-1 Cannot parse command.\n");
                return (-1);
        }
+       assert (command != NULL);
+
+       if (strcasecmp ("PUTVAL", command) != 0)
+       {
+               print_to_socket (fh, "-1 Unexpected command: `%s'.\n", command);
+               return (-1);
+       }
+
+       identifier = NULL;
+       status = parse_string (&buffer, &identifier);
+       if (status != 0)
+       {
+               print_to_socket (fh, "-1 Cannot parse identifier.\n");
+               return (-1);
+       }
+       assert (identifier != NULL);
 
        /* parse_identifier() modifies its first argument,
         * returning pointers into it */
-       identifier_copy = sstrdup (fields[1]);
+       identifier_copy = sstrdup (identifier);
 
        status = parse_identifier (identifier_copy, &hostname,
                        &plugin, &plugin_instance,
                        &type, &type_instance);
        if (status != 0)
        {
-               DEBUG ("cmd putval: Cannot parse `%s'", fields[1]);
-               print_to_socket (fh, "-1 Cannot parse identifier.\n");
+               DEBUG ("handle_putval: Cannot parse identifier `%s'.",
+                               identifier);
+               print_to_socket (fh, "-1 Cannot parse identifier `%s'.\n",
+                               identifier);
                sfree (identifier_copy);
                return (-1);
        }
@@ -173,6 +194,7 @@ int handle_putval (FILE *fh, char **fields, int fields_num)
 
        sstrncpy (vl.host, hostname, sizeof (vl.host));
        sstrncpy (vl.plugin, plugin, sizeof (vl.plugin));
+       sstrncpy (vl.type, type, sizeof (vl.type));
        if (plugin_instance != NULL)
                sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
        if (type_instance != NULL)
@@ -180,54 +202,73 @@ int handle_putval (FILE *fh, char **fields, int fields_num)
 
        ds = plugin_get_ds (type);
        if (ds == NULL) {
+               print_to_socket (fh, "-1 Type `%s' isn't defined.\n", type);
                sfree (identifier_copy);
                return (-1);
        }
 
+       /* Free identifier_copy */
+       hostname = NULL;
+       plugin = NULL; plugin_instance = NULL;
+       type = NULL;   type_instance = NULL;
+       sfree (identifier_copy);
+
        vl.values_len = ds->ds_num;
        vl.values = (value_t *) malloc (vl.values_len * sizeof (value_t));
        if (vl.values == NULL)
        {
                print_to_socket (fh, "-1 malloc failed.\n");
-               sfree (identifier_copy);
                return (-1);
        }
 
        /* All the remaining fields are part of the optionlist. */
-       for (i = 2; i < fields_num; i++)
+       values_submitted = 0;
+       while (*buffer != 0)
        {
-               if (strchr (fields[i], ':') != NULL)
+               char *string = NULL;
+               char *value  = NULL;
+
+               status = parse_option (&buffer, &string, &value);
+               if (status < 0)
                {
-                       /* 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;
+                       /* parse_option failed, buffer has been modified.
+                        * => we need to abort */
+                       print_to_socket (fh, "-1 Misformatted option.\n");
+                       return (-1);
                }
-               else if (strchr (fields[i], '=') != NULL)
+               else if (status == 0)
                {
-                       if (parse_option (&vl, fields[i]) != 0)
-                       {
-                               print_to_socket (fh, "-1 Error parsing option `%s'\n",
-                                               fields[i]);
-                               break;
-                       }
+                       assert (string != NULL);
+                       assert (value != NULL);
+                       set_option (&vl, string, value);
+                       continue;
                }
-               else
+               /* else: parse_option but buffer has not been modified. This is
+                * the default if no `=' is found.. */
+
+               status = parse_string (&buffer, &string);
+               if (status != 0)
                {
-                       WARNING ("cmd putval: handle_putval: "
-                                       "Cannot parse field #%i `%s'; "
-                                       "Ignoring it.\n",
-                                       i, fields[i]);
+                       print_to_socket (fh, "-1 Misformatted value.\n");
+                       return (-1);
                }
-       }
+               assert (string != NULL);
+
+               status = parse_value (ds, &vl, fh, string);
+               if (status != 0)
+               {
+                       /* An error has already been printed. */
+                       return (-1);
+               }
+               values_submitted++;
+       } /* while (*buffer != 0) */
        /* Done parsing the options. */
 
-       if (i == fields_num)
-               print_to_socket (fh, "0 Success\n");
+       print_to_socket (fh, "0 Success: %i %s been dispatched.\n",
+                       values_submitted,
+                       (values_submitted == 1) ? "value has" : "values have");
 
        sfree (vl.values); 
-       sfree (identifier_copy);
 
        return (0);
 } /* int handle_putval */
index 2ae4532..9ba52cc 100644 (file)
@@ -22,6 +22,6 @@
 #ifndef UTILS_CMD_PUTVAL_H
 #define UTILS_CMD_PUTVAL_H 1
 
-int handle_putval (FILE *fh, char **fields, int fields_num);
+int handle_putval (FILE *fh, char *buffer);
 
 #endif /* UTILS_CMD_PUTVAL_H */
diff --git a/src/utils_complain.c b/src/utils_complain.c
new file mode 100644 (file)
index 0000000..9074b18
--- /dev/null
@@ -0,0 +1,102 @@
+/**
+ * collectd - src/utils_complain.c
+ * Copyright (C) 2006-2007  Florian octo Forster
+ * Copyright (C) 2008  Sebastian tokkee Harl
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at verplant.org>
+ *   Sebastian tokkee Harl <sh at tokkee.org>
+ **/
+
+#include "collectd.h"
+#include "utils_complain.h"
+#include "plugin.h"
+
+/* vcomplain returns 0 if it did not report, 1 else */
+static int vcomplain (int level, c_complain_t *c,
+               const char *format, va_list ap)
+{
+       time_t now;
+       char   message[512];
+
+       now = time (NULL);
+
+       if (c->last + c->interval > now)
+               return 0;
+
+       c->last = now;
+
+       if (c->interval < interval_g)
+               c->interval = interval_g;
+       else
+               c->interval *= 2;
+
+       if (c->interval > 86400)
+               c->interval = 86400;
+
+       vsnprintf (message, sizeof (message), format, ap);
+       message[sizeof (message) - 1] = '\0';
+
+       plugin_log (level, "%s", message);
+       return 1;
+} /* vcomplain */
+
+void c_complain (int level, c_complain_t *c, const char *format, ...)
+{
+       va_list ap;
+
+       /* reset the old interval */
+       if (c->interval < 0)
+               c->interval *= -1;
+
+       va_start (ap, format);
+       vcomplain (level, c, format, ap);
+       va_end (ap);
+} /* c_complain */
+
+void c_complain_once (int level, c_complain_t *c, const char *format, ...)
+{
+       va_list ap;
+
+       if (c->interval < 0)
+               return;
+
+       va_start (ap, format);
+       if (vcomplain (level, c, format, ap))
+               c->interval *= -1;
+       va_end (ap);
+} /* c_complain_once */
+
+void c_do_release (int level, c_complain_t *c, const char *format, ...)
+{
+       char message[512];
+       va_list ap;
+
+       if (c->interval == 0)
+               return;
+
+       c->interval = 0;
+
+       va_start (ap, format);
+       vsnprintf (message, sizeof (message), format, ap);
+       message[sizeof (message) - 1] = '\0';
+       va_end (ap);
+
+       plugin_log (level, "%s", message);
+} /* c_release */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
+
diff --git a/src/utils_complain.h b/src/utils_complain.h
new file mode 100644 (file)
index 0000000..e93d823
--- /dev/null
@@ -0,0 +1,96 @@
+/**
+ * collectd - src/utils_complain.h
+ * Copyright (C) 2006-2007  Florian octo Forster
+ * Copyright (C) 2008  Sebastian tokkee Harl
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at verplant.org>
+ *   Sebastian tokkee Harl <sh at tokkee.org>
+ **/
+
+#ifndef UTILS_COMPLAIN_H
+#define UTILS_COMPLAIN_H 1
+
+#include <time.h>
+
+typedef struct
+{
+       /* time of the last report */
+       time_t last;
+
+       /* how long to wait until reporting again
+        *   0 indicates that the complaint is no longer valid
+        * < 0 indicates that the complaint has been reported once
+        *     => c_complain_once will not report again
+        *     => c_complain uses the absolute value to reset the old value */
+       int interval;
+} c_complain_t;
+
+#define C_COMPLAIN_INIT { 0, 0 }
+
+/*
+ * NAME
+ *   c_complain
+ *
+ * DESCRIPTION
+ *   Complain about something. This function will report a message (usually
+ *   indicating some error condition) using the collectd logging mechanism.
+ *   When this function is called again, reporting the message again will be
+ *   deferred by an increasing interval (up to one day) to prevent flooding
+ *   the logs. A call to `c_release' resets the counter.
+ *
+ * PARAMETERS
+ *   `level'  The log level passed to `plugin_log'.
+ *   `c'      Identifier for the complaint.
+ *   `format' Message format - see the documentation of printf(3).
+ */
+void c_complain (int level, c_complain_t *c, const char *format, ...);
+
+/*
+ * NAME
+ *   c_complain_once
+ *
+ * DESCRIPTION
+ *   Complain about something once. This function will not report anything
+ *   again, unless `c_release' has been called in between. If used after some
+ *   calls to `c_complain', it will report again on the next interval and stop
+ *   after that.
+ *
+ *   See `c_complain' for further details and a description of the parameters.
+ */
+void c_complain_once (int level, c_complain_t *c, const char *format, ...);
+
+/*
+ * NAME
+ *   c_release
+ *
+ * DESCRIPTION
+ *   Release a complaint. This will report a message once, marking the
+ *   complaint as released.
+ *
+ *   See `c_complain' for a description of the parameters.
+ */
+void c_do_release (int level, c_complain_t *c, const char *format, ...);
+#define c_release(level, c, ...) \
+       do { \
+               if ((c)->interval != 0) \
+                       c_do_release(level, c, __VA_ARGS__); \
+       } while (0)
+
+#endif /* UTILS_COMPLAIN_H */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
+
index 5316a71..c16b3c1 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "collectd.h"
 #include "plugin.h"
+#include "common.h"
 
 #if HAVE_NETINET_IN_SYSTM_H
 # include <netinet/in_systm.h>
@@ -384,7 +385,7 @@ handle_dns(const char *buf, int len,
     if (0 != x)
        return 0;
     if ('\0' == qh.qname[0])
-       strncpy (qh.qname, ".", sizeof (qh.qname));
+       sstrncpy (qh.qname, ".", sizeof (qh.qname));
     while ((t = strchr(qh.qname, '\n')))
        *t = ' ';
     while ((t = strchr(qh.qname, '\r')))
@@ -815,8 +816,7 @@ const char *qtype_str(int t)
            case T_ANY:         return ("ANY"); /* ... 255 */
 #endif /* __BIND >= 19950621 */
            default:
-                   snprintf (buf, 32, "#%i", t);
-                   buf[31] = '\0';
+                   ssnprintf (buf, sizeof (buf), "#%i", t);
                    return (buf);
     }; /* switch (t) */
     /* NOTREACHED */
@@ -843,7 +843,7 @@ const char *opcode_str (int o)
        return "Update";
        break;
     default:
-       snprintf(buf, 30, "Opcode%d", o);
+       ssnprintf(buf, sizeof (buf), "Opcode%d", o);
        return buf;
     }
     /* NOTREACHED */
@@ -887,8 +887,7 @@ const char *rcode_str (int rcode)
 #endif  /* RFC2136 rcodes */
 #endif /* __BIND >= 19950621 */
                default:
-                       snprintf (buf, 32, "RCode%i", rcode);
-                       buf[31] = '\0';
+                       ssnprintf (buf, sizeof (buf), "RCode%i", rcode);
                        return (buf);
        }
        /* Never reached */
index 689b4a4..de42d0f 100644 (file)
@@ -311,8 +311,7 @@ int ignorelist_add (ignorelist_t *il, const char *entry)
                /* We need to copy `entry' since it's const */
                entry_copy_size = entry_len - 1;
                entry_copy = smalloc (entry_copy_size);
-               strncpy (entry_copy, entry + 1, entry_copy_size);
-               entry_copy[entry_copy_size - 1] = 0;
+               sstrncpy (entry_copy, entry + 1, entry_copy_size);
 
                DEBUG("I'm about to add regex entry: %s", entry_copy);
                ret = ignorelist_append_regex(il, entry_copy);
index 44ad7ea..c53431f 100644 (file)
@@ -260,7 +260,7 @@ uuidcache_init(void)
                        * (This is useful, if the cdrom on /dev/hdc must not
                        * be accessed.)
                        */
-                               snprintf(device, sizeof(device), "%s/%s",
+                               ssnprintf(device, sizeof(device), "%s/%s",
                                        DEVLABELDIR, ptname);
                                if(!get_label_uuid(device, &label, uuid)) {
                                        uuidcache_addentry(sstrdup(device),
@@ -769,8 +769,6 @@ cu_mount_getoptionvalue(char *line, char *keyword)
        return r;
 } /* char *cu_mount_getoptionvalue(char *line, char *keyword) */
 
-
-
 int
 cu_mount_type(const char *type)
 {
@@ -782,5 +780,3 @@ cu_mount_type(const char *type)
        return CUMT_UNKNOWN;
 } /* int cu_mount_type(const char *type) */
 
-
-
diff --git a/src/utils_parse_option.c b/src/utils_parse_option.c
new file mode 100644 (file)
index 0000000..d94c140
--- /dev/null
@@ -0,0 +1,153 @@
+/**
+ * collectd - src/utils_parse_option.c
+ * Copyright (C) 2008  Florian Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Author:
+ *   Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "utils_parse_option.h"
+
+int parse_string (char **ret_buffer, char **ret_string)
+{
+  char *buffer;
+  char *string;
+
+  buffer = *ret_buffer;
+
+  /* Eat up leading spaces. */
+  string = buffer;
+  while (isspace ((int) *string))
+    string++;
+  if (*string == 0)
+    return (1);
+
+  /* A quoted string */
+  if (*string == '"')
+  {
+    char *dst;
+
+    string++;
+    if (*string == 0)
+      return (1);
+
+    dst = string;
+    buffer = string;
+    while ((*buffer != '"') && (*buffer != 0))
+    {
+      /* Un-escape backslashes */
+      if (*buffer == '\\')
+      {
+        buffer++;
+        /* Catch a backslash at the end of buffer */
+        if (*buffer == 0)
+          return (-1);
+      }
+      *dst = *buffer;
+      buffer++;
+      dst++;
+    }
+    /* No quote sign has been found */
+    if (*buffer == 0)
+      return (-1);
+
+    *dst = 0;
+    dst++;
+    *buffer = 0;
+    buffer++;
+
+    /* Check for trailing spaces. */
+    if ((*buffer != 0) && !isspace ((int) *buffer))
+      return (-1);
+  }
+  else /* an unquoted string */
+  {
+    buffer = string;
+    while ((*buffer != 0) && !isspace ((int) *buffer))
+      buffer++;
+    if (*buffer != 0)
+    {
+      *buffer = 0;
+      buffer++;
+    }
+  }
+  
+  /* Eat up trailing spaces */
+  while (isspace ((int) *buffer))
+    buffer++;
+
+  *ret_buffer = buffer;
+  *ret_string = string;
+
+  return (0);
+} /* int parse_string */
+
+/*
+ * parse_option
+ * ------------
+ *  Parses an ``option'' as used with the unixsock and exec commands. An
+ *  option is of the form:
+ *    name0="value"
+ *    name1="value with \"quotes\""
+ *    name2="value \\ backslash"
+ *  However, if the value does *not* contain a space character, you can skip
+ *  the quotes.
+ */
+int parse_option (char **ret_buffer, char **ret_key, char **ret_value)
+{
+  char *buffer;
+  char *key;
+  char *value;
+  int status;
+
+  buffer = *ret_buffer;
+
+  /* Eat up leading spaces */
+  key = buffer;
+  while (isspace ((int) *key))
+    key++;
+  if (*key == 0)
+    return (1);
+
+  /* Look for the equal sign */
+  buffer = key;
+  while (isalnum ((int) *buffer))
+    buffer++;
+  if ((*buffer != '=') || (buffer == key))
+    return (1);
+  *buffer = 0;
+  buffer++;
+  /* Empty values must be written as "" */
+  if (isspace ((int) *buffer) || (*buffer == 0))
+    return (-1);
+
+  status = parse_string (&buffer, &value);
+  if (status != 0)
+    return (-1);
+
+  /* NB: parse_string will have eaten up all trailing spaces. */
+
+  *ret_buffer = buffer;
+  *ret_key = key;
+  *ret_value = value;
+
+  return (0);
+} /* int parse_option */
+
+/* vim: set sw=2 ts=8 tw=78 et : */
diff --git a/src/utils_parse_option.h b/src/utils_parse_option.h
new file mode 100644 (file)
index 0000000..cb7f6d3
--- /dev/null
@@ -0,0 +1,30 @@
+/**
+ * collectd - src/utils_parse_option.h
+ * Copyright (C) 2008  Florian Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; 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_PARSE_OPTION
+#define UTILS_PARSE_OPTION 1
+
+int parse_string (char **ret_buffer, char **ret_string);
+int parse_option (char **ret_buffer, char **ret_key, char **ret_value);
+
+#endif /* UTILS_PARSE_OPTION */
+
+/* vim: set sw=2 ts=8 tw=78 et : */
index 34fe2dc..f518b1c 100644 (file)
@@ -85,10 +85,11 @@ static int simple_submit_match (cu_match_t *match, void *user_data)
   sstrncpy (vl.plugin, data->plugin, sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, data->plugin_instance,
       sizeof (vl.plugin_instance));
+  sstrncpy (vl.type, data->type, sizeof (vl.type));
   sstrncpy (vl.type_instance, data->type_instance,
       sizeof (vl.type_instance));
 
-  plugin_dispatch_values (data->type, &vl);
+  plugin_dispatch_values (&vl);
 
   if (match_value->ds_type & UTILS_MATCH_DS_TYPE_GAUGE)
   {
index ddce422..68b85a3 100644 (file)
@@ -184,9 +184,8 @@ static int ut_config_type_instance (threshold_t *th, oconfig_item_t *ci)
     return (-1);
   }
 
-  strncpy (th->type_instance, ci->values[0].value.string,
+  sstrncpy (th->type_instance, ci->values[0].value.string,
       sizeof (th->type_instance));
-  th->type_instance[sizeof (th->type_instance) - 1] = '\0';
 
   return (0);
 } /* int ut_config_type_instance */
@@ -284,8 +283,7 @@ static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci)
   }
 
   memcpy (&th, th_orig, sizeof (th));
-  strncpy (th.type, ci->values[0].value.string, sizeof (th.type));
-  th.type[sizeof (th.type) - 1] = '\0';
+  sstrncpy (th.type, ci->values[0].value.string, sizeof (th.type));
 
   th.warning_min = NAN;
   th.warning_max = NAN;
@@ -340,9 +338,8 @@ static int ut_config_plugin_instance (threshold_t *th, oconfig_item_t *ci)
     return (-1);
   }
 
-  strncpy (th->plugin_instance, ci->values[0].value.string,
+  sstrncpy (th->plugin_instance, ci->values[0].value.string,
       sizeof (th->plugin_instance));
-  th->plugin_instance[sizeof (th->plugin_instance) - 1] = '\0';
 
   return (0);
 } /* int ut_config_plugin_instance */
@@ -369,8 +366,7 @@ static int ut_config_plugin (const threshold_t *th_orig, oconfig_item_t *ci)
   }
 
   memcpy (&th, th_orig, sizeof (th));
-  strncpy (th.plugin, ci->values[0].value.string, sizeof (th.plugin));
-  th.plugin[sizeof (th.plugin) - 1] = '\0';
+  sstrncpy (th.plugin, ci->values[0].value.string, sizeof (th.plugin));
 
   for (i = 0; i < ci->children_num; i++)
   {
@@ -417,8 +413,7 @@ static int ut_config_host (const threshold_t *th_orig, oconfig_item_t *ci)
   }
 
   memcpy (&th, th_orig, sizeof (th));
-  strncpy (th.host, ci->values[0].value.string, sizeof (th.host));
-  th.host[sizeof (th.host) - 1] = '\0';
+  sstrncpy (th.host, ci->values[0].value.string, sizeof (th.host));
 
   for (i = 0; i < ci->children_num; i++)
   {
@@ -501,46 +496,45 @@ int ut_config (const oconfig_item_t *ci)
  */
 /* }}} */
 
-static threshold_t *threshold_search (const data_set_t *ds,
-    const value_list_t *vl)
+static threshold_t *threshold_search (const value_list_t *vl)
 {
   threshold_t *th;
 
   if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
-         ds->type, vl->type_instance)) != NULL)
+         vl->type, vl->type_instance)) != NULL)
     return (th);
   else if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
-         ds->type, NULL)) != NULL)
+         vl->type, NULL)) != NULL)
     return (th);
   else if ((th = threshold_get (vl->host, vl->plugin, NULL,
-         ds->type, vl->type_instance)) != NULL)
+         vl->type, vl->type_instance)) != NULL)
     return (th);
   else if ((th = threshold_get (vl->host, vl->plugin, NULL,
-         ds->type, NULL)) != NULL)
+         vl->type, NULL)) != NULL)
     return (th);
   else if ((th = threshold_get (vl->host, "", NULL,
-         ds->type, vl->type_instance)) != NULL)
+         vl->type, vl->type_instance)) != NULL)
     return (th);
   else if ((th = threshold_get (vl->host, "", NULL,
-         ds->type, NULL)) != NULL)
+         vl->type, NULL)) != NULL)
     return (th);
   else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
-         ds->type, vl->type_instance)) != NULL)
+         vl->type, vl->type_instance)) != NULL)
     return (th);
   else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
-         ds->type, NULL)) != NULL)
+         vl->type, NULL)) != NULL)
     return (th);
   else if ((th = threshold_get ("", vl->plugin, NULL,
-         ds->type, vl->type_instance)) != NULL)
+         vl->type, vl->type_instance)) != NULL)
     return (th);
   else if ((th = threshold_get ("", vl->plugin, NULL,
-         ds->type, NULL)) != NULL)
+         vl->type, NULL)) != NULL)
     return (th);
   else if ((th = threshold_get ("", "", NULL,
-         ds->type, vl->type_instance)) != NULL)
+         vl->type, vl->type_instance)) != NULL)
     return (th);
   else if ((th = threshold_get ("", "", NULL,
-         ds->type, NULL)) != NULL)
+         vl->type, NULL)) != NULL)
     return (th);
 
   return (NULL);
@@ -597,35 +591,43 @@ static int ut_report_state (const data_set_t *ds,
 
   n.time = vl->time;
 
-  status = snprintf (buf, bufsize, "Host %s, plugin %s",
+  status = ssnprintf (buf, bufsize, "Host %s, plugin %s",
       vl->host, vl->plugin);
   buf += status;
   bufsize -= status;
 
   if (vl->plugin_instance[0] != '\0')
   {
-    status = snprintf (buf, bufsize, " (instance %s)",
+    status = ssnprintf (buf, bufsize, " (instance %s)",
        vl->plugin_instance);
     buf += status;
     bufsize -= status;
   }
 
-  status = snprintf (buf, bufsize, " type %s", ds->type);
+  status = ssnprintf (buf, bufsize, " type %s", vl->type);
   buf += status;
   bufsize -= status;
 
   if (vl->type_instance[0] != '\0')
   {
-    status = snprintf (buf, bufsize, " (instance %s)",
+    status = ssnprintf (buf, bufsize, " (instance %s)",
        vl->type_instance);
     buf += status;
     bufsize -= status;
   }
 
+  plugin_notification_meta_add_string (&n, "DataSource",
+      ds->ds[ds_index].name);
+  plugin_notification_meta_add_double (&n, "CurrentValue", values[ds_index]);
+  plugin_notification_meta_add_double (&n, "WarningMin", th->warning_min);
+  plugin_notification_meta_add_double (&n, "WarningMax", th->warning_max);
+  plugin_notification_meta_add_double (&n, "FailureMin", th->failure_min);
+  plugin_notification_meta_add_double (&n, "FailureMax", th->failure_max);
+
   /* Send an okay notification */
   if (state == STATE_OKAY)
   {
-    status = snprintf (buf, bufsize, ": All data sources are within range again.");
+    status = ssnprintf (buf, bufsize, ": All data sources are within range again.");
     buf += status;
     bufsize -= status;
   }
@@ -641,7 +643,7 @@ static int ut_report_state (const data_set_t *ds,
     {
       if (!isnan (min) && !isnan (max))
       {
-       status = snprintf (buf, bufsize, ": Data source \"%s\" is currently "
+       status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
            "%f. That is within the %s region of %f and %f.",
            ds->ds[ds_index].name, values[ds_index],
            (state == STATE_ERROR) ? "failure" : "warning",
@@ -649,7 +651,7 @@ static int ut_report_state (const data_set_t *ds,
       }
       else
       {
-       status = snprintf (buf, bufsize, ": Data source \"%s\" is currently "
+       status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
            "%f. That is %s the %s threshold of %f.",
            ds->ds[ds_index].name, values[ds_index],
            isnan (min) ? "below" : "above",
@@ -659,7 +661,7 @@ static int ut_report_state (const data_set_t *ds,
     }
     else /* is not inverted */
     {
-      status = snprintf (buf, bufsize, ": Data source \"%s\" is currently "
+      status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
          "%f. That is %s the %s threshold of %f.",
          ds->ds[ds_index].name, values[ds_index],
          (values[ds_index] < min) ? "below" : "above",
@@ -672,6 +674,7 @@ static int ut_report_state (const data_set_t *ds,
 
   plugin_dispatch_notification (&n);
 
+  plugin_notification_meta_free (&n);
   return (0);
 } /* }}} int ut_report_state */
 
@@ -783,7 +786,7 @@ int ut_check_threshold (const data_set_t *ds, const value_list_t *vl)
   /* Is this lock really necessary? So far, thresholds are only inserted at
    * startup. -octo */
   pthread_mutex_lock (&threshold_lock);
-  th = threshold_search (ds, vl);
+  th = threshold_search (vl);
   pthread_mutex_unlock (&threshold_lock);
   if (th == NULL)
     return (0);
@@ -866,27 +869,19 @@ int ut_check_interesting (const char *name)
   memset (&ds, '\0', sizeof (ds));
   memset (&vl, '\0', sizeof (vl));
 
-  strncpy (vl.host, host, sizeof (vl.host));
-  vl.host[sizeof (vl.host) - 1] = '\0';
-  strncpy (vl.plugin, plugin, sizeof (vl.plugin));
-  vl.plugin[sizeof (vl.plugin) - 1] = '\0';
+  sstrncpy (vl.host, host, sizeof (vl.host));
+  sstrncpy (vl.plugin, plugin, sizeof (vl.plugin));
   if (plugin_instance != NULL)
-  {
-    strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
-    vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0';
-  }
-  strncpy (ds.type, type, sizeof (ds.type));
-  ds.type[sizeof (ds.type) - 1] = '\0';
+    sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+  sstrncpy (ds.type, type, sizeof (ds.type));
+  sstrncpy (vl.type, type, sizeof (vl.type));
   if (type_instance != NULL)
-  {
-    strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
-    vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
-  }
+    sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
   sfree (name_copy);
   host = plugin = plugin_instance = type = type_instance = NULL;
 
-  th = threshold_search (&ds, &vl);
+  th = threshold_search (&vl);
   if (th == NULL)
     return (0);
   if ((th->flags & UT_FLAG_PERSIST) == 0)
index d54301a..e0de0d9 100644 (file)
@@ -257,8 +257,7 @@ uuid_init (void)
     char *uuid = uuid_get_local ();
 
     if (uuid) {
-        strncpy (hostname_g, uuid, DATA_MAX_NAME_LEN);
-        hostname_g[DATA_MAX_NAME_LEN-1] = '\0';
+        sstrncpy (hostname_g, uuid, DATA_MAX_NAME_LEN);
         sfree (uuid);
         return 0;
     }
index 5341e15..25f7c70 100644 (file)
@@ -50,10 +50,11 @@ static void submit (const char *plugin_instance, const char *type,
   sstrncpy (vl.plugin, "vmem", sizeof (vl.plugin));
   if (plugin_instance != NULL)
     sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+  sstrncpy (vl.type, type, sizeof (vl.type));
   if (type_instance != NULL)
     sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-  plugin_dispatch_values (type, &vl);
+  plugin_dispatch_values (&vl);
 } /* void vmem_submit */
 
 static void submit_two (const char *plugin_instance, const char *type,
index 7188b13..dac4392 100644 (file)
@@ -59,10 +59,11 @@ static void traffic_submit (const char *plugin_instance,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "vserver", sizeof (vl.plugin));
-       strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
-       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+       sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+       sstrncpy (vl.type, "if_octets", sizeof (vl.type));
+       sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       plugin_dispatch_values ("if_octets", &vl);
+       plugin_dispatch_values (&vl);
 } /* void traffic_submit */
 
 static void load_submit (const char *plugin_instance,
@@ -80,9 +81,10 @@ static void load_submit (const char *plugin_instance,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "vserver", sizeof (vl.plugin));
-       strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+       sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+       sstrncpy (vl.type, "load", sizeof (vl.type));
 
-       plugin_dispatch_values ("load", &vl);
+       plugin_dispatch_values (&vl);
 }
 
 static void submit_gauge (const char *plugin_instance, const char *type,
@@ -99,10 +101,11 @@ static void submit_gauge (const char *plugin_instance, const char *type,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "vserver", sizeof (vl.plugin));
-       strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
-       strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+       sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+       sstrncpy (vl.type, type, sizeof (vl.type));
+       sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void submit_gauge */
 
 static inline long long __get_sock_bytes(const char *s)
@@ -185,8 +188,9 @@ static int vserver_read (void)
                        continue;
 
                /* socket message accounting */
-               len = snprintf (file, BUFSIZE, PROCDIR "/%s/cacct", dent->d_name);
-               if ((len < 0) || (len >= BUFSIZE))
+               len = ssnprintf (file, sizeof (file),
+                               PROCDIR "/%s/cacct", dent->d_name);
+               if ((len < 0) || (len >= sizeof (file)))
                        continue;
 
                if (NULL == (fh = fopen (file, "r")))
@@ -232,8 +236,9 @@ static int vserver_read (void)
                }
 
                /* thread information and load */
-               len = snprintf (file, BUFSIZE, PROCDIR "/%s/cvirt", dent->d_name);
-               if ((len < 0) || (len >= BUFSIZE))
+               len = ssnprintf (file, sizeof (file),
+                               PROCDIR "/%s/cvirt", dent->d_name);
+               if ((len < 0) || (len >= sizeof (file)))
                        continue;
 
                if (NULL == (fh = fopen (file, "r")))
@@ -284,8 +289,9 @@ static int vserver_read (void)
                }
 
                /* processes and memory usage */
-               len = snprintf (file, BUFSIZE, PROCDIR "/%s/limit", dent->d_name);
-               if ((len < 0) || (len >= BUFSIZE))
+               len = ssnprintf (file, sizeof (file),
+                               PROCDIR "/%s/limit", dent->d_name);
+               if ((len < 0) || (len >= sizeof (file)))
                        continue;
 
                if (NULL == (fh = fopen (file, "r")))
index 0edaf45..21bbcb4 100644 (file)
@@ -58,10 +58,11 @@ static void wireless_submit (const char *plugin_instance, const char *type,
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "wireless", sizeof (vl.plugin));
-       strncpy (vl.plugin_instance, plugin_instance,
+       sstrncpy (vl.plugin_instance, plugin_instance,
                        sizeof (vl.plugin_instance));
+       sstrncpy (vl.type, type, sizeof (vl.type));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void wireless_submit */
 
 #define POWER_MIN -90.0
index 7f3edf0..09786fc 100644 (file)
@@ -39,8 +39,9 @@ static void cxmms_submit (const char *type, gauge_t value)
        vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "xmms", sizeof (vl.plugin));
+       sstrncpy (vl.type, type, sizeof (vl.type));
 
-       plugin_dispatch_values (type, &vl);
+       plugin_dispatch_values (&vl);
 } /* void cxmms_submit */
 
 int cxmms_read (void)
index b73c848..f933764 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-DEFAULT_VERSION="4.4.5.git"
+DEFAULT_VERSION="4.5.2.git"
 
 VERSION="$( git describe 2> /dev/null | sed -e 's/^collectd-//' )"