--- /dev/null
+Anthony <anthony>
+Florian Forster <octo>
+Florian Forster <octo@dev4.office.noris.de>
+Luboš Staněk <kolektor@atlas.cz>
+Luboš Staněk <lubek@users.sourceforge.net>
+Niki W. Waibel <niki>
+Sebastian Harl <tokkee>
+
- cpufreq
CPU frequency (For laptops with speed step or a similar technology)
+ - dbi
+ Executes SQL statements on various databases and interprets the returned
+ data.
+
- df
Mountpoint usage (Basically the values `df(1)' delivers)
Iptables' counters: Number of bytes that were matched by a certain
iptables rule.
+ - ipmi
+ IPMI (Intelligent Platform Management Interface) sensors information.
+
- ipvs
IPVS connection statistics (number of connections, octets and packets
for each service and destination).
PostgreSQL database statistics: active server connections, transaction
numbers, block IO, table row manipulations.
+ - powerdns
+ PowerDNS name server statistics.
+
- processes
Process counts: Number of running, sleeping, zombie, ... processes.
+ - rrdcached
+ RRDtool caching daemon (RRDcacheD) statistics.
+
- sensors
System sensors, accessed using lm_sensors: Voltages, temperatures and
fan rotation speeds.
- tcpconns
Number of TCP connections to specific local and remote ports.
+ - teamspeak2
+ TeamSpeak2 server statistics.
+
+ - thermal
+ Linux ACPI thermal zone information.
+
- users
Users currently logged in.
you can easily do weird stuff with the plugins we didn't dare think of
;) See collectd-perl(5).
+ - rrdcached
+ Output to round-robin-database (RRD) files using the RRDtool caching
+ daemon (RRDcacheD) - see rrdcached(1). That daemon provides a general
+ implementation of the caching done by the `rrdtool' plugin.
+
- rrdtool
Output to round-robin-database (RRD) files using librrd. See rrdtool(1).
This is likely the most popular destination for such values. Since
needed. Please read collectd-unixsock(5) for a description on how that's
done.
+ * Filtering and rewriting values dispatched to collectd can be done by the
+ following plugins:
+
+ - filter_pcre
+ Filter and rewrite value lists based on Perl-compatible regular
+ expressions.
+
* Logging is, as everything in collectd, provided by plugins. The following
plugins keep up informed about what's going on:
since collectd is programmed multithreaded it benefits from hyperthreading
and multicore processors and makes sure that the daemon isn't idle if only
one plugins waits for an IO-operation to complete.
-
+
* Once set up, hardly any maintenance is necessary. Setup is kept as easy
as possible and the default values should be okay for most users.
* CoreFoundation.framework and IOKit.framework (optional)
For compiling on Darwin in general and the `apple_sensors' plugin in
particular.
+ <http://developer.apple.com/corefoundation/>
* libcurl (optional)
If you want to use the `apache', `ascent', or `nginx' plugin.
+ <http://curl.haxx.se/>
+
+ * libdbi (optional)
+ Used by the `dbi' plugin to connect to various databases.
+ <http://libdbi.sourceforge.net/>
* libesmtp (optional)
For the `notify_email' plugin.
+ <http://www.stafford.uklinux.net/libesmtp/>
* libhal (optional)
If present, the uuid plugin will check for UUID from HAL.
+ <http://hal.freedesktop.org/>
- * libiptc (optional)
+ * libiptc (optional, if not found a version shipped with this distribution
+ can be used if the Linux kernel headers are available)
For querying iptables counters.
+ <http://netfilter.org/>
* libmysqlclient (optional)
Unsurprisingly used by the `mysql' plugin.
+ <http://dev.mysql.com/>
* libnetlink (optional)
Used, obviously, for the `netlink' plugin.
+ <http://www.linuxfoundation.org/en/Net:Iproute2>
* libnetsnmp (optional)
For the `snmp' plugin.
+ <http://www.net-snmp.org/>
* libnotify (optional)
For the `notify_desktop' plugin.
+ <http://www.galago-project.org/>
* 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.
+ <http://verplant.org/liboping/>
* libowcapi (optional)
Used by the `onewire' plugin to read values from onewire sensors (or the
owserver(1) daemon).
+ <http://www.owfs.org/>
* libpcap (optional)
Used to capture packets by the `dns' plugin.
+ <http://www.tcpdump.org/>
+
+ * libpcre (optional)
+ Used by the `filter_pcre' plugin.
+ <http://www.pcre.org/>
* libperl (optional)
Obviously used by the `perl' plugin. The library has to be compiled with
ithread support (introduced in Perl 5.6.0).
+ <http://www.perl.org/>
* libpq (optional)
The PostgreSQL C client library used by the `postgresql' plugin.
+ <http://www.postgresql.org/>
- * 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.
+ * librrd (optional)
+ Used by the `rrdtool' and `rrdcached' plugins. The latter requires RRDtool
+ client support which was added after version 1.3 of RRDtool. Versions 1.0,
+ 1.2 and 1.3 are known to work with the `rrdtool' plugin.
+ <http://oss.oetiker.ch/rrdtool/>
* librt, libsocket, libkstat, libdevinfo (optional)
Various standard Solaris libraries which provide system functions.
+ <http://developers.sun.com/solaris/>
* libsensors (optional)
To read from `lm_sensors', see the `sensors' plugin.
+ <http://www.lm-sensors.org/>
- * 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/>
+ * libstatgrab (optional)
+ Used by various plugins to collect statistics on systems other than Linux
+ and/or Solaris.
+ <http://www.i-scream.org/libstatgrab/>
* libupsclient/nut (optional)
For the `nut' plugin which queries nut's `upsd'.
+ <http://networkupstools.org/>
* libvirt (optional)
Collect statistics from virtual machines.
+ <http://libvirt.org/>
* libxml2 (optional)
Parse XML data. This is needed for the `ascent' and `libvirt' plugins.
+ <http://xmlsoft.org/>
* libxmms (optional)
+ <http://www.xmms.org/>
Configuring / Compiling / Installing
`./configure && make && make install'. For detailed, generic instructions
see INSTALL. For a complete list of configure options and their description,
run `./configure --help'.
-
+
By default, the configure script will check for all build dependencies and
disable all plugins whose requirements cannot be fulfilled (any other plugin
will be enabled). To enable a plugin, install missing dependencies (see
-* Parse options/identifiers with spaces in them correctly.
-* Figure out what to do with the onewire plugin.
+* Finalize the onewire plugin.
* Custom notification messages?
+* Implement moving-average calculation for the threshold stuff.
src/battery.c: commend not working code.
- be free of syntax errors.
* Port nfs module to solaris
* Port tape module to Linux
+* Port the apple_sensors plugin to Linux/PPC.
* Maybe look into porting the serial module
* Build Darwin package
* Maybe let the network plugin configure whether or not notifications should be
[[[[
#include <stdlib.h>
#include <stdio.h>
-#include <stdint.h>
#include <string.h>
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#if HAVE_STDBOOL_H
+# include <stdbool.h>
+#endif
]]]],
[[[[
uint64_t i0;
[[[[
#include <stdlib.h>
#include <stdio.h>
-#include <stdint.h>
#include <string.h>
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#if HAVE_STDBOOL_H
+# include <stdbool.h>
+#endif
#define endianflip(A) ((((uint64_t)(A) & 0xff00000000000000LL) >> 56) | \
(((uint64_t)(A) & 0x00ff000000000000LL) >> 40) | \
(((uint64_t)(A) & 0x0000ff0000000000LL) >> 24) | \
[[[[
#include <stdlib.h>
#include <stdio.h>
-#include <stdint.h>
#include <string.h>
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#if HAVE_STDBOOL_H
+# include <stdbool.h>
+#endif
#define intswap(A) ((((uint64_t)(A) & 0xffffffff00000000LL) >> 32) | \
(((uint64_t)(A) & 0x00000000ffffffffLL) << 32))
]]]],
m4_divert_once([HELP_WITH], [
collectd additional packages:])
-# AC_ARG_WITH (package, help-string, [action-if-given], [action-if-not-given])
-librrd_cflags=""
-librrd_ldflags=""
-librrd_threadsafe="yes"
-AC_ARG_WITH(rrdtool, [AS_HELP_STRING([--with-rrdtool@<:@=PREFIX@:>@], [Path to rrdtool.])],
-[ if test "x$withval" != "xno" && test "x$withval" != "xyes"
- then
- librrd_cflags="-I$withval/include"
- librrd_ldflags="-L$withval/lib"
- with_rrdtool="yes"
- else
- with_rrdtool="$withval"
- fi
-], [with_rrdtool="yes"])
-if test "x$with_rrdtool" = "xyes"
-then
- SAVE_CPPFLAGS="$CPPFLAGS"
- SAVE_LDFLAGS="$LDFLAGS"
-
- CPPFLAGS="$CPPFLAGS $librrd_cflags"
- LDFLAGS="$LDFLAGS $librrd_ldflags"
-
- AC_CHECK_HEADERS(rrd.h,, [with_rrdtool="no (rrd.h not found)"])
-
- CPPFLAGS="$SAVE_CPPFLAGS"
- LDFLAGS="$SAVE_LDFLAGS"
-fi
-if test "x$with_rrdtool" = "xyes"
-then
- SAVE_CPPFLAGS="$CPPFLAGS"
- SAVE_LDFLAGS="$LDFLAGS"
-
- CPPFLAGS="$CPPFLAGS $librrd_cflags"
- LDFLAGS="$LDFLAGS $librrd_ldflags"
-
- AC_CHECK_LIB(rrd_th, rrd_update_r,
- [with_rrdtool="yes"
- librrd_ldflags="$librrd_ldflags -lrrd_th -lm"
- ],
- [librrd_threadsafe="no"
- AC_CHECK_LIB(rrd, rrd_update,
- [with_rrdtool="yes"
- librrd_ldflags="$librrd_ldflags -lrrd -lm"
- ],
- [with_rrdtool="no (symbol 'rrd_update' not found)"],
- [-lm])
- ],
- [-lm])
-
- CPPFLAGS="$SAVE_CPPFLAGS"
- LDFLAGS="$SAVE_LDFLAGS"
-fi
-if test "x$with_rrdtool" = "xyes"
-then
- BUILD_WITH_LIBRRD_CFLAGS="$librrd_cflags"
- BUILD_WITH_LIBRRD_LDFLAGS="$librrd_ldflags"
- AC_SUBST(BUILD_WITH_LIBRRD_CFLAGS)
- AC_SUBST(BUILD_WITH_LIBRRD_LDFLAGS)
-fi
-if test "x$librrd_threadsafe" = "xyes"
-then
- AC_DEFINE(HAVE_THREADSAFE_LIBRRD, 1, [Define to 1 if you have the threadsafe rrd library (-lrrd_th).])
-fi
-
-AC_ARG_WITH(libpthread, [AS_HELP_STRING([--with-libpthread=@<:@=PREFIX@:>@], [Path to libpthread.])],
-[ if test "x$withval" != "xno" \
- && test "x$withval" != "xyes"
- then
- LDFLAGS="$LDFLAGS -L$withval/lib"
- CPPFLAGS="$CPPFLAGS -I$withval/include"
- with_libpthread="yes"
- else
- if test "x$withval" = "xno"
- then
- with_libpthread="no (disabled)"
- fi
- fi
-], [with_libpthread="yes"])
-if test "x$with_libpthread" = "xyes"
-then
- AC_CHECK_LIB(pthread, pthread_create, [with_libpthread="yes"], [with_libpthread="no (libpthread not found)"], [])
-fi
-if test "x$with_libpthread" = "xyes"
-then
- AC_CHECK_HEADERS(pthread.h,, [with_libpthread="no (pthread.h not found)"])
-fi
-if test "x$with_libpthread" = "xyes"
-then
- collect_pthread=1
-else
- collect_pthread=0
-fi
-AC_DEFINE_UNQUOTED(HAVE_LIBPTHREAD, [$collect_pthread],
- [Wether or not to use pthread (POSIX threads) library])
-AM_CONDITIONAL(BUILD_WITH_LIBPTHREAD, test "x$with_libpthread" = "xyes")
-
if test "x$ac_system" = "xSolaris"
then
with_kstat="yes"
AM_CONDITIONAL(BUILD_WITH_LIBKSTAT, test "x$with_kstat" = "xyes")
AM_CONDITIONAL(BUILD_WITH_LIBDEVINFO, test "x$with_devinfo" = "xyes")
-### BEGIN of check for libcurl ###
+with_libiokit="no"
+AC_CHECK_LIB(IOKit, IOServiceGetMatchingServices,
+[
+ with_libiokit="yes"
+],
+[
+ with_libiokit="no"
+])
+AM_CONDITIONAL(BUILD_WITH_LIBIOKIT, test "x$with_libiokit" = "xyes")
+
+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
+ AC_DEFINE(HAVE_LIBKVM_GETSWAPINFO, 1,
+ [Define to 1 if you have the 'kvm' library with the 'kvm_getswapinfo' symbol (-lkvm)])
+ with_libkvm="yes"
+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-libcurl {{{
with_curl_config="curl-config"
with_curl_cflags=""
with_curl_libs=""
AC_SUBST(BUILD_WITH_LIBCURL_LIBS)
fi
AM_CONDITIONAL(BUILD_WITH_LIBCURL, test "x$with_libcurl" = "xyes")
-### END of check for libcurl ###
-
-with_libiokit="no"
-AC_CHECK_LIB(IOKit, IOServiceGetMatchingServices,
-[
- with_libiokit="yes"
-],
-[
- with_libiokit="no"
-])
-AM_CONDITIONAL(BUILD_WITH_LIBIOKIT, test "x$with_libiokit" = "xyes")
+# }}}
-with_libstatgrab_cflags=""
-with_libstatgrab_ldflags=""
-AC_ARG_WITH(libstatgrab, [AS_HELP_STRING([--with-libstatgrab@<:@=PREFIX@:>@], [Path to libstatgrab.])],
+# --with-libdbi {{{
+with_libdbi_cppflags=""
+with_libdbi_ldflags=""
+AC_ARG_WITH(libdbi, [AS_HELP_STRING([--with-libdbi@<:@=PREFIX@:>@], [Path to libdbi.])],
[
- if test "x$withval" != "xno" \
- && test "x$withval" != "xyes"
+ if test "x$withval" != "xno" && test "x$withval" != "xyes"
then
- with_libstatgrab_cflags="-I$withval/include"
- with_libstatgrab_ldflags="-L$withval/lib"
- with_libstatgrab="yes"
+ with_libdbi_cppflags="-I$withval/include"
+ with_libdbi_ldflags="-L$withval/lib"
+ with_libdbi="yes"
else
- with_libstatgrab="$withval"
+ with_libdbi="$withval"
fi
],
[
- if test "x$ac_system" = "xunknown"
- then
- with_libstatgrab="yes"
- else
- with_libstatgrab="no"
- fi
+ with_libdbi="yes"
])
-with_libstatgrab_pkg_config="yes"
-if test "x$with_libstatgrab" = "xyes" \
- && test "x$PKG_CONFIG" != "x"
-then
- AC_MSG_CHECKING([pkg-config for libstatgrab])
- temp_result="found"
- $PKG_CONFIG --exists libstatgrab 2>/dev/null
- if test "$?" != "0"
- then
- with_libstatgrab_pkg_config="no"
- temp_result="not found"
- fi
- AC_MSG_RESULT([$temp_result])
-else
- AC_MSG_NOTICE([pkg-config not available, trying to guess flags for the statgrab library.])
- with_libstatgrab_pkg_config="no"
- with_libstatgrab_ldflags="$with_libstatgrab_ldflags -lstatgrab"
-fi
-
-if test "x$with_libstatgrab" = "xyes" \
- && test "x$with_libstatgrab_pkg_config" = "xyes" \
- && test "x$with_libstatgrab_cflags" = "x"
-then
- AC_MSG_CHECKING([for libstatgrab CFLAGS])
- temp_result="`$PKG_CONFIG --cflags libstatgrab`"
- if test "$?" = "0"
- then
- with_libstatgrab_cflags="$temp_result"
- else
- with_libstatgrab="no ($PKG_CONFIG --cflags libstatgrab failed)"
- temp_result="$PKG_CONFIG --cflags libstatgrab failed"
- fi
- AC_MSG_RESULT([$temp_result])
-fi
-
-if test "x$with_libstatgrab" = "xyes" \
- && test "x$with_libstatgrab_pkg_config" = "xyes" \
- && test "x$with_libstatgrab_ldflags" = "x"
-then
- AC_MSG_CHECKING([for libstatgrab LDFLAGS])
- temp_result="`$PKG_CONFIG --libs libstatgrab`"
- if test "$?" = "0"
- then
- with_libstatgrab_ldflags="$temp_result"
- else
- with_libstatgrab="no ($PKG_CONFIG --libs libstatgrab failed)"
- temp_result="$PKG_CONFIG --libs libstatgrab failed"
- fi
- AC_MSG_RESULT([$temp_result])
-fi
-
-if test "x$with_libstatgrab" = "xyes"
+if test "x$with_libdbi" = "xyes"
then
- SAVE_CPPFLAGS="$CPPFLAGS"
- CPPFLAGS="$CPPFLAGS $with_libstatgrab_cflags"
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_libdbi_cppflags"
- AC_CHECK_HEADERS(statgrab.h,
- [with_libstatgrab="yes"],
- [with_libstatgrab="no (statgrab.h not found)"])
+ AC_CHECK_HEADERS(dbi/dbi.h, [with_libdbi="yes"], [with_libdbi="no (dbi/dbi.h not found)"])
- CPPFLAGS="$SAVE_CPPFLAGS"
+ CPPFLAGS="$SAVE_CPPFLAGS"
fi
-
-if test "x$with_libstatgrab" = "xyes"
+if test "x$with_libdbi" = "xyes"
then
- SAVE_CFLAGS="$CFLAGS"
- SAVE_LDFLAGS="$LDFLAGS"
-
- CFLAGS="$CFLAGS $with_libstatgrab_cflags"
- LDFLAGS="$LDFLAGS $with_libstatgrab_ldflags"
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ SAVE_LDFLAGS="$LDFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_libdbi_cppflags"
+ LDFLAGS="$LDFLAGS $with_libdbi_ldflags"
- AC_CHECK_LIB(statgrab, sg_init,
- [with_libstatgrab="yes"],
- [with_libstatgrab="no (symbol sg_init not found)"])
+ AC_CHECK_LIB(dbi, dbi_initialize, [with_libdbi="yes"], [with_libdbi="no (Symbol 'dbi_initialize' not found)"])
- CFLAGS="$SAVE_CFLAGS"
- LDFLAGS="$SAVE_LDFLAGS"
+ CPPFLAGS="$SAVE_CPPFLAGS"
+ LDFLAGS="$SAVE_LDFLAGS"
fi
-
-AM_CONDITIONAL(BUILD_WITH_LIBSTATGRAB, test "x$with_libstatgrab" = "xyes")
-if test "x$with_libstatgrab" = "xyes"
+if test "x$with_libdbi" = "xyes"
then
- AC_DEFINE(HAVE_LIBSTATGRAB, 1, [Define to 1 if you have the 'statgrab' library (-lstatgrab)])
- BUILD_WITH_LIBSTATGRAB_CFLAGS="$with_libstatgrab_cflags"
- BUILD_WITH_LIBSTATGRAB_LDFLAGS="$with_libstatgrab_ldflags"
- AC_SUBST(BUILD_WITH_LIBSTATGRAB_CFLAGS)
- AC_SUBST(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
+ BUILD_WITH_LIBDBI_CPPFLAGS="$with_libdbi_cppflags"
+ BUILD_WITH_LIBDBI_LDFLAGS="$with_libdbi_ldflags"
+ BUILD_WITH_LIBDBI_LIBS="-ldbi"
+ AC_SUBST(BUILD_WITH_LIBDBI_CPPFLAGS)
+ AC_SUBST(BUILD_WITH_LIBDBI_LDFLAGS)
+ AC_SUBST(BUILD_WITH_LIBDBI_LIBS)
fi
+AM_CONDITIONAL(BUILD_WITH_LIBDBI, test "x$with_libdbi" = "xyes")
+# }}}
-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"
+# --with-libesmtp {{{
+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_DEFINE(HAVE_LIBKVM_GETSWAPINFO, 1,
- [Define to 1 if you have the 'kvm' library with the 'kvm_getswapinfo' symbol (-lkvm)])
- with_libkvm="yes"
+ 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
-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"
+if test "x$with_libesmtp" = "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"
+ 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
-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"
+if test "x$with_libesmtp" = "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"
+ collect_libesmtp=1
+else
+ collect_libesmtp=0
fi
-AM_CONDITIONAL(BUILD_WITH_LIBKVM_OPENFILES, test "x$with_kvm_openfiles" = "xyes")
+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")
+# }}}
-with_sensors_cflags=""
-with_sensors_ldflags=""
-AC_ARG_WITH(lm-sensors, [AS_HELP_STRING([--with-lm-sensors@<:@=PREFIX@:>@], [Path to lm_sensors.])],
+# --with-libiptc {{{
+with_own_libiptc="no"
+AC_ARG_WITH(libiptc, [AS_HELP_STRING([--with-libiptc@<:@=PREFIX@:>@], [Path to libiptc.])],
[
- if test "x$withval" = "xno"
+ if test "x$withval" != "xno" && test "x$withval" != "xyes"
then
- with_lm_sensors="no"
+ LDFLAGS="$LDFLAGS -L$withval/lib"
+ CPPFLAGS="$CPPFLAGS -I$withval/include"
+ with_libiptc="yes"
else
- with_lm_sensors="yes"
- if test "x$withval" != "xyes"
- then
- with_sensors_cflags="-I$withval/include"
- with_sensors_ldflags="-L$withval/lib"
- with_lm_sensors="yes"
- fi
+ with_libiptc="$withval"
fi
],
[
if test "x$ac_system" = "xLinux"
then
- with_lm_sensors="yes"
+ with_libiptc="yes"
else
- with_lm_sensors="no (Linux only library)"
+ with_libiptc="no (Linux only)"
fi
])
-if test "x$with_lm_sensors" = "xyes"
+if test "x$with_libiptc" = "xyes"
then
- SAVE_CPPFLAGS="$CPPFLAGS"
- CPPFLAGS="$CPPFLAGS $with_sensors_cflags"
-
-# AC_CHECK_HEADERS(sensors/sensors.h,
-# [
-# AC_DEFINE(HAVE_SENSORS_SENSORS_H, 1, [Define to 1 if you have the <sensors/sensors.h> header file.])
-# ],
-# [with_lm_sensors="no (sensors/sensors.h not found)"])
- AC_CHECK_HEADERS(sensors/sensors.h, [], [with_lm_sensors="no (sensors/sensors.h not found)"])
-
- CPPFLAGS="$SAVE_CPPFLAGS"
+ AC_CHECK_LIB(iptc, iptc_init,
+ [
+ AC_DEFINE(HAVE_LIBIPTC, 1, [Define to 1 if you have the iptc library (-liptc).])
+ ],
+ [
+ with_libiptc="yes"
+ with_own_libiptc="yes"
+ ])
fi
-if test "x$with_lm_sensors" = "xyes"
+if test "x$with_libiptc" = "xyes" -a "x$with_own_libiptc" != "xyes"
then
- SAVE_CPPFLAGS="$CPPFLAGS"
- SAVE_LDFLAGS="$LDFLAGS"
- CPPFLAGS="$CPPFLAGS $with_sensors_cflags"
- LDFLAGS="$LDFLAGS $with_sensors_ldflags"
+ AC_CHECK_HEADERS(libiptc/libiptc.h,
+ [
+ AC_DEFINE(HAVE_LIBIPTC_LIBIPTC_H, 1, [Define to 1 if you have the <libiptc/libiptc.h> header file.])
+ ],
+ [
+ with_libiptc="yes"
+ with_own_libiptc="yes"
+ ])
+fi
+if test "x$with_libiptc" = "xyes"
+then
+ SAVE_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS $KERNEL_CFLAGS"
- AC_CHECK_LIB(sensors, sensors_init,
+ AC_CHECK_HEADERS(linux/netfilter_ipv4/ip_tables.h linux/netfilter_ipv6/ip6_tables.h, [],
[
- AC_DEFINE(HAVE_LIBSENSORS, 1, [Define to 1 if you have the sensors library (-lsensors).])
+ with_libiptc="no (Linux iptables headers not found - check KERNEL_DIR)"
+ with_own_libiptc="no"
],
- [with_lm_sensors="no (libsensors not found)"])
+ [
+#include "$srcdir/src/libiptc/ipt_kernel_headers.h"
+ ])
- CPPFLAGS="$SAVE_CPPFLAGS"
- LDFLAGS="$SAVE_LDFLAGS"
+ CFLAGS=$SAVE_CFLAGS
fi
-if test "x$with_lm_sensors" = "xyes"
+AM_CONDITIONAL(BUILD_WITH_LIBIPTC, test "x$with_libiptc" = "xyes")
+AM_CONDITIONAL(BUILD_WITH_OWN_LIBIPTC, test "x$with_own_libiptc" = "xyes")
+if test "x$with_own_libiptc" = "xyes"
then
- BUILD_WITH_LIBSENSORS_CFLAGS="$with_sensors_cflags"
- BUILD_WITH_LIBSENSORS_LDFLAGS="$with_sensors_ldflags"
- AC_SUBST(BUILD_WITH_LIBSENSORS_CFLAGS)
- AC_SUBST(BUILD_WITH_LIBSENSORS_LDFLAGS)
+ AC_DEFINE(OWN_LIBIPTC, 1, [Define to 1 if we use the shipped iptc library.])
fi
-AM_CONDITIONAL(BUILD_WITH_LM_SENSORS, test "x$with_lm_sensors" = "xyes")
+# }}}
+# --with-libmysql {{{
with_mysql_config="mysql_config"
with_mysql_cflags=""
with_mysql_libs=""
AC_SUBST(BUILD_WITH_LIBMYSQL_LIBS)
fi
AM_CONDITIONAL(BUILD_WITH_LIBMYSQL, test "x$with_libmysql" = "xyes")
+# }}}
-with_own_liboconfig="no"
-liboconfig_LDFLAGS="$LDFLAGS"
-liboconfig_CPPFLAGS="$CPPFLAGS"
-AC_ARG_WITH(liboconfig, [AS_HELP_STRING([--with-liboconfig@<:@=PREFIX@:>@], [Path to liboconfig.])],
-[
- if test "x$withval" != "xno" && test "x$withval" != "xyes"
- then
- if test -d "$withval/lib"
- then
- liboconfig_LDFLAGS="$LDFLAGS -L$withval/lib"
- fi
- if test -d "$withval/include"
- then
- liboconfig_CPPFLAGS="$CPPFLAGS -I$withval/include"
- fi
- fi
- if test "x$withval" = "xno"
- then
- AC_MSG_ERROR("liboconfig is required")
- fi
-],
-[
- with_liboconfig="yes"
-])
-
-save_LDFLAGS="$LDFLAGS"
-save_CPPFLAGS="$CPPFLAGS"
-LDFLAGS="$liboconfig_LDFLAGS"
-CPPFLAGS="$liboconfig_CPPFLAGS"
-AC_CHECK_LIB(oconfig, oconfig_parse_fh,
+# --with-libnetlink {{{
+with_libnetlink_cflags=""
+with_libnetlink_libs="-lnetlink"
+AC_ARG_WITH(libnetlink, [AS_HELP_STRING([--with-libnetlink@<:@=PREFIX@:>@], [Path to libnetlink.])],
[
- with_liboconfig="yes"
- with_own_liboconfig="no"
+ echo "libnetlink: withval = $withval"
+ if test "x$withval" = "xyes"
+ then
+ with_libnetlink="yes"
+ else if test "x$withval" = "xno"
+ then
+ with_libnetlink="no"
+ else
+ if test -d "$withval/include"
+ then
+ with_libnetlink_cflags="-I$withval/include"
+ with_libnetlink_libs="-L$withval/lib -lnetlink"
+ with_libnetlink="yes"
+ else
+ AC_MSG_ERROR("no such directory: $withval/include")
+ fi
+ fi; fi
],
[
- with_liboconfig="yes"
- with_own_liboconfig="yes"
- LDFLAGS="$save_LDFLAGS"
- CPPFLAGS="$save_CPPFLAGS"
+ if test "x$ac_system" = "xLinux"
+ then
+ with_libnetlink="yes"
+ else
+ with_libnetlink="no (Linux only library)"
+ fi
])
-
-AM_CONDITIONAL(BUILD_WITH_OWN_LIBOCONFIG, test "x$with_own_liboconfig" = "xyes")
-if test "x$with_own_liboconfig" = "xyes"
+if test "x$with_libnetlink" = "xyes"
then
- with_liboconfig="yes (shipped version)"
-fi
+ SAVE_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS $with_libnetlink_cflags"
-#with_liboping="yes"
-with_own_liboping="no"
-liboping_LDFLAGS="$LDFLAGS"
-liboping_CPPFLAGS="$CPPFLAGS"
-AC_ARG_WITH(liboping, [AS_HELP_STRING([--with-liboping@<:@=PREFIX@:>@], [Path to liboping.])],
-[
- if test "x$withval" != "xno" && test "x$withval" != "xyes"
- then
- if test -d "$withval/lib"
- then
- liboping_LDFLAGS="$LDFLAGS -L$withval/lib"
- fi
- if test -d "$withval/include"
- then
- liboping_CPPFLAGS="$CPPFLAGS -I$withval/include"
- fi
- fi
- if test "x$withval" = "xno"
- then
- with_liboping="no"
- with_own_liboping="no"
- else if test "x$withval" = "xyes"
- then
- with_liboping="yes"
- fi; fi
-],
-[
- with_liboping="yes"
-])
+ with_libnetlink="no (libnetlink.h not found)"
-if test "x$with_liboping" = "xyes"
-then
- save_LDFLAGS="$LDFLAGS"
- save_CPPFLAGS="$CPPFLAGS"
- LDFLAGS="$liboping_LDFLAGS"
- CPPFLAGS="$liboping_CPPFLAGS"
- AC_CHECK_LIB(oping, ping_construct,
- [
- with_liboping="yes"
- with_own_liboping="no"
- ],
+ AC_CHECK_HEADERS(libnetlink.h iproute/libnetlink.h linux/libnetlink.h,
[
- with_liboping="yes"
- with_own_liboping="yes"
- LDFLAGS="$save_LDFLAGS"
- CPPFLAGS="$save_CPPFLAGS"
- ])
-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)"])
+ with_libnetlink="yes"
+ break
+ ], [],
+[#include <stdio.h>
+#include <sys/types.h>
+#include <asm/types.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>])
+ AC_CHECK_HEADERS(linux/gen_stats.h linux/pkt_sched.h, [], [],
+[#include <stdio.h>
+#include <sys/types.h>
+#include <asm/types.h>
+#include <sys/socket.h>])
- CPPFLAGS="$SAVE_CPPFLAGS"
+ AC_COMPILE_IFELSE(
+[#include <stdio.h>
+#include <sys/types.h>
+#include <asm/types.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+int main (void)
+{
+ int retval = TCA_STATS2;
+ return (retval);
+}],
+ [AC_DEFINE([HAVE_TCA_STATS2], 1, [True if the enum-member TCA_STATS2 exists])]
+ []);
+
+ AC_COMPILE_IFELSE(
+[#include <stdio.h>
+#include <sys/types.h>
+#include <asm/types.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+int main (void)
+{
+ int retval = TCA_STATS;
+ return (retval);
+}],
+ [AC_DEFINE([HAVE_TCA_STATS], 1, [True if the enum-member TCA_STATS exists])]
+ []);
+
+ CFLAGS="$SAVE_CFLAGS"
fi
-if test "x$with_libowcapi" = "xyes"
+if test "x$with_libnetlink" = "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"
+ AC_CHECK_LIB(netlink, rtnl_open,
+ [with_libnetlink="yes"],
+ [with_libnetlink="no (symbol 'rtnl_open' not found)"],
+ [$with_libnetlink_libs])
fi
-if test "x$with_libowcapi" = "xyes"
+if test "x$with_libnetlink" = "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)
+ BUILD_WITH_LIBNETLINK_CFLAGS="$with_libnetlink_cflags"
+ BUILD_WITH_LIBNETLINK_LIBS="$with_libnetlink_libs"
+ AC_SUBST(BUILD_WITH_LIBNETLINK_CFLAGS)
+ AC_SUBST(BUILD_WITH_LIBNETLINK_LIBS)
fi
+AM_CONDITIONAL(BUILD_WITH_LIBNETLINK, test "x$with_libnetlink" = "xyes")
+# }}}
-
-AC_ARG_WITH(libpcap, [AS_HELP_STRING([--with-libpcap@<:@=PREFIX@:>@], [Path to libpcap.])],
+# --with-libnetsnmp {{{
+with_snmp_config="net-snmp-config"
+with_snmp_cflags=""
+with_snmp_libs=""
+AC_ARG_WITH(libnetsnmp, [AS_HELP_STRING([--with-libnetsnmp@<:@=PREFIX@:>@], [Path to the Net-SNMPD library.])],
[
- if test "x$withval" != "xno" && test "x$withval" != "xyes"
+ if test "x$withval" = "xno"
then
- LDFLAGS="$LDFLAGS -L$withval/lib"
- CPPFLAGS="$CPPFLAGS -I$withval/include"
- with_libpcap="yes"
+ with_libnetsnmp="no"
+ else if test "x$withval" = "xyes"
+ then
+ with_libnetsnmp="yes"
else
- with_libpcap="$withval"
- fi
+ if test -x "$withval"
+ then
+ with_snmp_config="$withval"
+ with_libnetsnmp="yes"
+ else
+ with_snmp_config="$withval/bin/net-snmp-config"
+ with_libnetsnmp="yes"
+ fi
+ fi; fi
],
-[
- with_libpcap="yes"
-])
-if test "x$with_libpcap" = "xyes"
+[with_libnetsnmp="yes"])
+if test "x$with_libnetsnmp" = "xyes"
then
- AC_CHECK_LIB(pcap, pcap_open_live,
- [
- AC_DEFINE(HAVE_LIBPCAP, 1, [Define to 1 if you have the pcap library (-lpcap).])
- ], [with_libpcap="no (libpcap not found)"])
+ with_snmp_cflags=`$with_snmp_config --cflags 2>/dev/null`
+ snmp_config_status=$?
+
+ if test $snmp_config_status -ne 0
+ then
+ with_libnetsnmp="no ($with_snmp_config failed)"
+ else
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_snmp_cflags"
+
+ AC_CHECK_HEADERS(net-snmp/net-snmp-config.h, [], [with_libnetsnmp="no (net-snmp/net-snmp-config.h not found)"])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+ fi
fi
-if test "x$with_libpcap" = "xyes"
+if test "x$with_libnetsnmp" = "xyes"
then
- AC_CHECK_HEADERS(pcap.h,
- [
- AC_DEFINE(HAVE_PCAP_H, 1, [Define to 1 if you have the <pcap.h> header file.])
- ], [with_libpcap="no (pcap.h not found)"])
+ with_snmp_libs=`$with_snmp_config --libs 2>/dev/null`
+ snmp_config_status=$?
+
+ if test $snmp_config_status -ne 0
+ then
+ with_libnetsnmp="no ($with_snmp_config failed)"
+ else
+ AC_CHECK_LIB(netsnmp, init_snmp,
+ [with_libnetsnmp="yes"],
+ [with_libnetsnmp="no (libnetsnmp not found)"],
+ [$with_snmp_libs])
+ fi
fi
-if test "x$with_libpcap" = "xyes"
+if test "x$with_libnetsnmp" = "xyes"
then
- collect_libpcap=1
-else
- collect_libpcap=0
+ BUILD_WITH_LIBSNMP_CFLAGS="$with_snmp_cflags"
+ BUILD_WITH_LIBSNMP_LIBS="$with_snmp_libs"
+ AC_SUBST(BUILD_WITH_LIBSNMP_CFLAGS)
+ AC_SUBST(BUILD_WITH_LIBSNMP_LIBS)
fi
-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")
+AM_CONDITIONAL(BUILD_WITH_LIBNETSNMP, test "x$with_libnetsnmp" = "xyes")
+# }}}
-AC_ARG_WITH(libesmtp, [AS_HELP_STRING([--with-libesmtp@<:@=PREFIX@:>@], [Path to libesmtp.])],
+# --with-liboconfig {{{
+with_own_liboconfig="no"
+liboconfig_LDFLAGS="$LDFLAGS"
+liboconfig_CPPFLAGS="$CPPFLAGS"
+AC_ARG_WITH(liboconfig, [AS_HELP_STRING([--with-liboconfig@<:@=PREFIX@:>@], [Path to liboconfig.])],
[
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"
+ if test -d "$withval/lib"
+ then
+ liboconfig_LDFLAGS="$LDFLAGS -L$withval/lib"
+ fi
+ if test -d "$withval/include"
+ then
+ liboconfig_CPPFLAGS="$CPPFLAGS -I$withval/include"
+ fi
+ fi
+ if test "x$withval" = "xno"
+ then
+ AC_MSG_ERROR("liboconfig is required")
fi
],
[
- with_libesmtp="yes"
+ with_liboconfig="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.])],
+save_LDFLAGS="$LDFLAGS"
+save_CPPFLAGS="$CPPFLAGS"
+LDFLAGS="$liboconfig_LDFLAGS"
+CPPFLAGS="$liboconfig_CPPFLAGS"
+AC_CHECK_LIB(oconfig, oconfig_parse_fh,
[
- 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"
- perl_interpreter="$withval/bin/perl"
- with_libperl="yes"
- else
- with_libperl="$withval"
- fi; fi
+ with_liboconfig="yes"
+ with_own_liboconfig="no"
],
[
- with_libperl="yes"
+ with_liboconfig="yes"
+ with_own_liboconfig="yes"
+ LDFLAGS="$save_LDFLAGS"
+ CPPFLAGS="$save_CPPFLAGS"
])
-AC_MSG_CHECKING([for perl])
-perl_interpreter=`which "$perl_interpreter" 2> /dev/null`
-if test -x "$perl_interpreter"
+AM_CONDITIONAL(BUILD_WITH_OWN_LIBOCONFIG, test "x$with_own_liboconfig" = "xyes")
+if test "x$with_own_liboconfig" = "xyes"
then
- AC_MSG_RESULT([yes ($perl_interpreter)])
-else
- perl_interpreter=""
- AC_MSG_RESULT([no])
+ with_liboconfig="yes (shipped version)"
fi
+# }}}
-AC_SUBST(PERL, "$perl_interpreter")
-
-if test "x$with_libperl" = "xyes" \
+# --with-liboping {{{
+with_own_liboping="no"
+liboping_LDFLAGS="$LDFLAGS"
+liboping_CPPFLAGS="$CPPFLAGS"
+AC_ARG_WITH(liboping, [AS_HELP_STRING([--with-liboping@<:@=PREFIX@:>@], [Path to liboping.])],
+[
+ if test "x$withval" != "xno" && test "x$withval" != "xyes"
+ then
+ if test -d "$withval/lib"
+ then
+ liboping_LDFLAGS="$LDFLAGS -L$withval/lib"
+ fi
+ if test -d "$withval/include"
+ then
+ liboping_CPPFLAGS="$CPPFLAGS -I$withval/include"
+ fi
+ fi
+ if test "x$withval" = "xno"
+ then
+ with_liboping="no"
+ with_own_liboping="no"
+ else if test "x$withval" = "xyes"
+ then
+ with_liboping="yes"
+ fi; fi
+],
+[
+ with_liboping="yes"
+])
+
+if test "x$with_liboping" = "xyes"
+then
+ save_LDFLAGS="$LDFLAGS"
+ save_CPPFLAGS="$CPPFLAGS"
+ LDFLAGS="$liboping_LDFLAGS"
+ CPPFLAGS="$liboping_CPPFLAGS"
+ AC_CHECK_LIB(oping, ping_construct,
+ [
+ with_liboping="yes"
+ with_own_liboping="no"
+ ],
+ [
+ with_liboping="yes"
+ with_own_liboping="yes"
+ LDFLAGS="$save_LDFLAGS"
+ CPPFLAGS="$save_CPPFLAGS"
+ ])
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBOPING, test "x$with_liboping" = "xyes")
+AM_CONDITIONAL(BUILD_WITH_OWN_LIBOPING, test "x$with_own_liboping" = "xyes")
+# }}}
+
+# --with-oracle {{{
+with_oracle_cppflags=""
+with_oracle_libs=""
+AC_ARG_WITH(oracle, [AS_HELP_STRING([--with-oracle@<:@=ORACLE_HOME@:>@], [Path to Oracle.])],
+[
+ if test "x$withval" = "xyes"
+ then
+ if test "x$ORACLE_HOME" = "x"
+ then
+ AC_MSG_WARN([Use of the Oracle library has been forced, but the environment variable ORACLE_HOME is not set.])
+ fi
+ with_oracle="yes"
+ else if test "x$withval" = "xno"
+ then
+ with_oracle="no"
+ else
+ with_oracle="yes"
+ ORACLE_HOME="$withval"
+ fi; fi
+],
+[
+ if test "x$ORACLE_HOME" = "x"
+ then
+ with_oracle="no (ORACLE_HOME is not set)"
+ else
+ with_oracle="yes"
+ fi
+])
+if test "x$ORACLE_HOME" != "x"
+then
+ with_oracle_cppflags="-I$ORACLE_HOME/rdbms/public"
+
+ if test -e "$ORACLE_HOME/lib/ldflags"
+ then
+ with_oracle_libs=`cat "$ORACLE_HOME/lib/ldflags"`
+ fi
+ #with_oracle_libs="-L$ORACLE_HOME/lib $with_oracle_libs -lclntsh"
+ with_oracle_libs="-L$ORACLE_HOME/lib -lclntsh"
+fi
+if test "x$with_oracle" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_oracle_cppflags"
+
+ AC_CHECK_HEADERS(oci.h, [with_oracle="yes"], [with_oracle="no (oci.h not found)"])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_oracle" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ SAVE_LDFLAGS="$LDFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_oracle_cppflags"
+ LDFLAGS="$LDFLAGS $with_oracle_libs"
+
+ AC_CHECK_FUNC(OCIEnvCreate, [with_oracle="yes"], [with_oracle="no (Symbol 'OCIEnvCreate' not found)"])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+ LDFLAGS="$SAVE_LDFLAGS"
+fi
+if test "x$with_oracle" = "xyes"
+then
+ BUILD_WITH_ORACLE_CFLAGS="$with_oracle_cppflags"
+ BUILD_WITH_ORACLE_LIBS="$with_oracle_libs"
+ AC_SUBST(BUILD_WITH_ORACLE_CFLAGS)
+ AC_SUBST(BUILD_WITH_ORACLE_LIBS)
+fi
+# }}}
+
+# --with-libowcapi {{{
+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
+# }}}
+
+# --with-libpcap {{{
+AC_ARG_WITH(libpcap, [AS_HELP_STRING([--with-libpcap@<:@=PREFIX@:>@], [Path to libpcap.])],
+[
+ if test "x$withval" != "xno" && test "x$withval" != "xyes"
+ then
+ LDFLAGS="$LDFLAGS -L$withval/lib"
+ CPPFLAGS="$CPPFLAGS -I$withval/include"
+ with_libpcap="yes"
+ else
+ with_libpcap="$withval"
+ fi
+],
+[
+ with_libpcap="yes"
+])
+if test "x$with_libpcap" = "xyes"
+then
+ AC_CHECK_LIB(pcap, pcap_open_live,
+ [
+ AC_DEFINE(HAVE_LIBPCAP, 1, [Define to 1 if you have the pcap library (-lpcap).])
+ ], [with_libpcap="no (libpcap not found)"])
+fi
+if test "x$with_libpcap" = "xyes"
+then
+ AC_CHECK_HEADERS(pcap.h,
+ [
+ AC_DEFINE(HAVE_PCAP_H, 1, [Define to 1 if you have the <pcap.h> header file.])
+ ], [with_libpcap="no (pcap.h not found)"])
+fi
+if test "x$with_libpcap" = "xyes"
+then
+ collect_libpcap=1
+else
+ collect_libpcap=0
+fi
+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")
+# }}}
+
+# --with-libpcre {{{
+with_pcre_config="pcre-config"
+with_pcre_cflags=""
+with_pcre_libs=""
+AC_ARG_WITH(libpcre, [AS_HELP_STRING([--with-libpcre@<:@=PREFIX@:>@],
+ [Path to libpcre.])],
+ [
+ if test "x$withval" = "xno"
+ then
+ with_libpcre="no"
+ else if test "x$withval" = "xyes"
+ then
+ with_libpcre="yes"
+ else
+ if test -f "$withval" && test -x "$withval"
+ then
+ with_pcre_config="$withval"
+ else if test -x "$withval/bin/pcre-config"
+ then
+ with_pcre_config="$withval/bin/pcre-config"
+ fi; fi
+ with_libpcre="yes"
+ fi; fi
+ ],
+ [
+ with_libpcre="yes"
+ ])
+
+if test "x$with_libpcre" = "xyes"
+then
+ with_pcre_cflags=`$with_pcre_config --cflags 2>/dev/null`
+ pcre_config_status=$?
+
+ if test $pcre_config_status -ne 0
+ then
+ with_libpcre="no ($with_pcre_config failed)"
+ else
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_pcre_cflags"
+
+ AC_CHECK_HEADERS(pcre.h, [], [with_libpcre="no (pcre.h not found)"], [])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+ fi
+fi
+
+if test "x$with_libpcre" = "xyes"
+then
+ with_pcre_libs=`$with_pcre_config --libs 2>/dev/null`
+ pcre_config_status=$?
+
+ if test $pcre_config_status -ne 0
+ then
+ with_libpcre="no ($with_pcre_config failed)"
+ else
+ AC_CHECK_LIB(pcre, pcre_compile,
+ [with_libpcre="yes"],
+ [with_libpcre="no (symbol 'pcre_compile' not found)"],
+ [$with_pcre_libs])
+ fi
+fi
+
+if test "x$with_libpcre" = "xyes"
+then
+ BUILD_WITH_LIBPCRE_CFLAGS="$with_pcre_cflags"
+ BUILD_WITH_LIBPCRE_LIBS="$with_pcre_libs"
+ AC_SUBST(BUILD_WITH_LIBPCRE_CFLAGS)
+ AC_SUBST(BUILD_WITH_LIBPCRE_LIBS)
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBPCRE, test "x$with_libpcre" = "xyes")
+# }}}
+
+# --with-libperl {{{
+perl_interpreter="perl"
+AC_ARG_WITH(libperl, [AS_HELP_STRING([--with-libperl@<:@=PREFIX@:>@], [Path to libperl.])],
+[
+ 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"
+ perl_interpreter="$withval/bin/perl"
+ with_libperl="yes"
+ else
+ with_libperl="$withval"
+ fi; fi
+],
+[
+ with_libperl="yes"
+])
+
+AC_MSG_CHECKING([for perl])
+perl_interpreter=`which "$perl_interpreter" 2> /dev/null`
+if test -x "$perl_interpreter"
+then
+ AC_MSG_RESULT([yes ($perl_interpreter)])
+else
+ perl_interpreter=""
+ AC_MSG_RESULT([no])
+fi
+
+AC_SUBST(PERL, "$perl_interpreter")
+
+if test "x$with_libperl" = "xyes" \
&& test -n "$perl_interpreter"
then
SAVE_CFLAGS=$CFLAGS
CFLAGS=$SAVE_CFLAGS
LDFLAGS=$SAVE_LDFLAGS
fi
+# }}}
-with_own_libiptc="no"
-AC_ARG_WITH(libiptc, [AS_HELP_STRING([--with-libiptc@<:@=PREFIX@:>@], [Path to libiptc.])],
+# --with-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" && test "x$withval" != "xyes"
+ if test "x$withval" = "xno"
then
- LDFLAGS="$LDFLAGS -L$withval/lib"
- CPPFLAGS="$CPPFLAGS -I$withval/include"
- with_libiptc="yes"
- else
- with_libiptc="$withval"
- fi
-],
-[
- if test "x$ac_system" = "xLinux"
+ with_libpq="no"
+ else if test "x$withval" = "xyes"
then
- with_libiptc="yes"
- else
- with_libiptc="no (Linux only)"
- fi
-])
-if test "x$with_libiptc" = "xyes"
-then
- AC_CHECK_LIB(iptc, iptc_init,
- [
- AC_DEFINE(HAVE_LIBIPTC, 1, [Define to 1 if you have the iptc library (-liptc).])
- ],
- [
- with_libiptc="yes"
- with_own_libiptc="yes"
- ])
-fi
-if test "x$with_libiptc" = "xyes" -a "x$with_own_libiptc" != "xyes"
-then
- AC_CHECK_HEADERS(libiptc/libiptc.h,
- [
- AC_DEFINE(HAVE_LIBIPTC_LIBIPTC_H, 1, [Define to 1 if you have the <libiptc/libiptc.h> header file.])
- ],
- [
- with_libiptc="yes"
- with_own_libiptc="yes"
- ])
-fi
-if test "x$with_libiptc" = "xyes"
-then
- SAVE_CFLAGS=$CFLAGS
- CFLAGS="$CFLAGS $KERNEL_CFLAGS"
-
- AC_CHECK_HEADERS(linux/netfilter_ipv4/ip_tables.h linux/netfilter_ipv6/ip6_tables.h, [],
- [
- with_libiptc="no (Linux iptables headers not found - check KERNEL_DIR)"
- with_own_libiptc="no"
- ],
- [
-#include "$srcdir/src/libiptc/ipt_kernel_headers.h"
- ])
-
- CFLAGS=$SAVE_CFLAGS
-fi
-AM_CONDITIONAL(BUILD_WITH_LIBIPTC, test "x$with_libiptc" = "xyes")
-AM_CONDITIONAL(BUILD_WITH_OWN_LIBIPTC, test "x$with_own_libiptc" = "xyes")
-if test "x$with_own_libiptc" = "xyes"
-then
- AC_DEFINE(OWN_LIBIPTC, 1, [Define to 1 if we use the shipped iptc library.])
-fi
-
-with_snmp_config="net-snmp-config"
-with_snmp_cflags=""
-with_snmp_libs=""
-AC_ARG_WITH(libnetsnmp, [AS_HELP_STRING([--with-libnetsnmp@<:@=PREFIX@:>@], [Path to the Net-SNMPD library.])],
-[
- if test "x$withval" = "xno"
- then
- with_libnetsnmp="no"
- else if test "x$withval" = "xyes"
- then
- with_libnetsnmp="yes"
+ with_libpq="yes"
else
- if test -x "$withval"
+ if test -f "$withval" && test -x "$withval";
then
- with_snmp_config="$withval"
- with_libnetsnmp="yes"
- else
- with_snmp_config="$withval/bin/net-snmp-config"
- with_libnetsnmp="yes"
- fi
+ 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_libnetsnmp="yes"])
-if test "x$with_libnetsnmp" = "xyes"
+[
+ with_libpq="yes"
+])
+if test "x$with_libpq" = "xyes"
then
- with_snmp_cflags=`$with_snmp_config --cflags 2>/dev/null`
- snmp_config_status=$?
+ with_libpq_includedir=`$with_pg_config --includedir 2> /dev/null`
+ pg_config_status=$?
- if test $snmp_config_status -ne 0
+ if test $pg_config_status -eq 0
then
- with_libnetsnmp="no ($with_snmp_config failed)"
+ 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
- SAVE_CPPFLAGS="$CPPFLAGS"
- CPPFLAGS="$CPPFLAGS $with_snmp_cflags"
-
- AC_CHECK_HEADERS(net-snmp/net-snmp-config.h, [], [with_libnetsnmp="no (net-snmp/net-snmp-config.h not found)"])
-
- CPPFLAGS="$SAVE_CPPFLAGS"
+ 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_libnetsnmp" = "xyes"
+if test "x$with_libpq" = "xyes"
then
- with_snmp_libs=`$with_snmp_config --libs 2>/dev/null`
- snmp_config_status=$?
+ with_libpq_libdir=`$with_pg_config --libdir 2> /dev/null`
+ pg_config_status=$?
- if test $snmp_config_status -ne 0
+ if test $pg_config_status -eq 0
then
- with_libnetsnmp="no ($with_snmp_config failed)"
+ 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_CHECK_LIB(netsnmp, init_snmp,
- [with_libnetsnmp="yes"],
- [with_libnetsnmp="no (libnetsnmp not found)"],
- [$with_snmp_libs])
+ 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_libnetsnmp" = "xyes"
+if test "x$with_libpq" = "xyes"
then
- BUILD_WITH_LIBSNMP_CFLAGS="$with_snmp_cflags"
- BUILD_WITH_LIBSNMP_LIBS="$with_snmp_libs"
- AC_SUBST(BUILD_WITH_LIBSNMP_CFLAGS)
- AC_SUBST(BUILD_WITH_LIBSNMP_LIBS)
+ 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_LIBNETSNMP, test "x$with_libnetsnmp" = "xyes")
-
-PKG_CHECK_MODULES([LIBNOTIFY], [libnotify],
- [with_libnotify="yes"],
- [with_libnotify="no ($LIBNOTIFY_PKG_ERRORS)"])
+AM_CONDITIONAL(BUILD_WITH_LIBPQ, test "x$with_libpq" = "xyes")
+# }}}
-with_libupsclient="no (pkg-config isn't available)"
-with_libupsclient_cflags=""
-with_libupsclient_libs=""
-if test "x$PKG_CONFIG" != "x"
-then
- pkg-config --exists 'libupsclient' 2>/dev/null
- if test "$?" = "0"
+# --with-libpthread {{{
+AC_ARG_WITH(libpthread, [AS_HELP_STRING([--with-libpthread=@<:@=PREFIX@:>@], [Path to libpthread.])],
+[ if test "x$withval" != "xno" \
+ && test "x$withval" != "xyes"
then
- with_libupsclient="yes"
+ LDFLAGS="$LDFLAGS -L$withval/lib"
+ CPPFLAGS="$CPPFLAGS -I$withval/include"
+ with_libpthread="yes"
else
- with_libupsclient="no (pkg-config doesn't know library)"
+ if test "x$withval" = "xno"
+ then
+ with_libpthread="no (disabled)"
+ fi
fi
+], [with_libpthread="yes"])
+if test "x$with_libpthread" = "xyes"
+then
+ AC_CHECK_LIB(pthread, pthread_create, [with_libpthread="yes"], [with_libpthread="no (libpthread not found)"], [])
fi
-if test "x$with_libupsclient" = "xyes"
+if test "x$with_libpthread" = "xyes"
then
- with_libupsclient_cflags="`pkg-config --cflags 'libupsclient'`"
- if test $? -ne 0
- then
- with_libupsclient="no"
- fi
- with_libupsclient_libs="`pkg-config --libs 'libupsclient'`"
- if test $? -ne 0
- then
- with_libupsclient="no"
- fi
+ AC_CHECK_HEADERS(pthread.h,, [with_libpthread="no (pthread.h not found)"])
fi
-if test "x$with_libupsclient" = "xyes"
+if test "x$with_libpthread" = "xyes"
then
- SAVE_CPPFLAGS="$CPPFLAGS"
- CPPFLAGS="$CPPFLAGS $with_libupsclient_cflags"
-
- AC_CHECK_HEADERS(upsclient.h, [], [with_libupsclient="no (upsclient.h not found)"])
-
- CPPFLAGS="$SAVE_CPPFLAGS"
+ collect_pthread=1
+else
+ collect_pthread=0
fi
-if test "x$with_libupsclient" = "xyes"
+AC_DEFINE_UNQUOTED(HAVE_LIBPTHREAD, [$collect_pthread],
+ [Wether or not to use pthread (POSIX threads) library])
+AM_CONDITIONAL(BUILD_WITH_LIBPTHREAD, test "x$with_libpthread" = "xyes")
+# }}}
+
+# --with-librrd {{{
+# AC_ARG_WITH (package, help-string, [action-if-given], [action-if-not-given])
+librrd_cflags=""
+librrd_ldflags=""
+librrd_threadsafe="yes"
+librrd_rrdc_update="no"
+AC_ARG_WITH(librrd, [AS_HELP_STRING([--with-librrd@<:@=PREFIX@:>@], [Path to rrdtool.])],
+[ if test "x$withval" != "xno" && test "x$withval" != "xyes"
+ then
+ librrd_cflags="-I$withval/include"
+ librrd_ldflags="-L$withval/lib"
+ with_librrd="yes"
+ else
+ with_librrd="$withval"
+ fi
+], [with_librrd="yes"])
+if test "x$with_librrd" = "xyes"
then
SAVE_CPPFLAGS="$CPPFLAGS"
SAVE_LDFLAGS="$LDFLAGS"
- CPPFLAGS="$CPPFLAGS $with_libupsclient_cflags"
- LDFLAGS="$LDFLAGS $with_libupsclient_libs"
+ CPPFLAGS="$CPPFLAGS $librrd_cflags"
+ LDFLAGS="$LDFLAGS $librrd_ldflags"
- AC_CHECK_LIB(upsclient, upscli_connect,
- [with_libupsclient="yes"],
- [with_libupsclient="no (symbol upscli_connect not found)"])
+ AC_CHECK_HEADERS(rrd.h,, [with_librrd="no (rrd.h not found)"])
CPPFLAGS="$SAVE_CPPFLAGS"
LDFLAGS="$SAVE_LDFLAGS"
fi
-if test "x$with_libupsclient" = "xyes"
+if test "x$with_librrd" = "xyes"
then
SAVE_CPPFLAGS="$CPPFLAGS"
- CPPFLAGS="$CPPFLAGS $with_libupsclient_cflags"
+ SAVE_LDFLAGS="$LDFLAGS"
- AC_CHECK_TYPES([UPSCONN_t, UPSCONN], [], [],
-[#include <stdlib.h>
-#include <stdio.h>
-#include <upsclient.h>])
+ CPPFLAGS="$CPPFLAGS $librrd_cflags"
+ LDFLAGS="$LDFLAGS $librrd_ldflags"
+
+ AC_CHECK_LIB(rrd_th, rrd_update_r,
+ [with_librrd="yes"
+ librrd_ldflags="$librrd_ldflags -lrrd_th -lm"
+ ],
+ [librrd_threadsafe="no"
+ AC_CHECK_LIB(rrd, rrd_update,
+ [with_librrd="yes"
+ librrd_ldflags="$librrd_ldflags -lrrd -lm"
+ ],
+ [with_librrd="no (symbol 'rrd_update' not found)"],
+ [-lm])
+ ],
+ [-lm])
+
+ if test "x$librrd_threadsafe" = "xyes"
+ then
+ AC_CHECK_LIB(rrd_th, rrdc_update, [librrd_rrdc_update="yes"], [librrd_rrdc_update="no"])
+ else
+ AC_CHECK_LIB(rrd, rrdc_update, [librrd_rrdc_update="yes"], [librrd_rrdc_update="no"])
+ fi
CPPFLAGS="$SAVE_CPPFLAGS"
+ LDFLAGS="$SAVE_LDFLAGS"
fi
-if test "x$with_libupsclient" = "xyes"
+if test "x$with_librrd" = "xyes"
then
- BUILD_WITH_LIBUPSCLIENT_CFLAGS="$with_libupsclient_cflags"
- BUILD_WITH_LIBUPSCLIENT_LIBS="$with_libupsclient_libs"
- AC_SUBST(BUILD_WITH_LIBUPSCLIENT_CFLAGS)
- AC_SUBST(BUILD_WITH_LIBUPSCLIENT_LIBS)
+ BUILD_WITH_LIBRRD_CFLAGS="$librrd_cflags"
+ BUILD_WITH_LIBRRD_LDFLAGS="$librrd_ldflags"
+ AC_SUBST(BUILD_WITH_LIBRRD_CFLAGS)
+ AC_SUBST(BUILD_WITH_LIBRRD_LDFLAGS)
fi
-
-### BEGIN of check for libxmms ###
-with_xmms_config="xmms-config"
-with_xmms_cflags=""
-with_xmms_libs=""
-AC_ARG_WITH(libxmms, [AS_HELP_STRING([--with-libxmms@<:@=PREFIX@:>@], [Path to libxmms.])],
+if test "x$librrd_threadsafe" = "xyes"
+then
+ AC_DEFINE(HAVE_THREADSAFE_LIBRRD, 1, [Define to 1 if you have the threadsafe rrd library (-lrrd_th).])
+fi
+# }}}
+
+# --with-libsensors {{{
+with_sensors_cflags=""
+with_sensors_ldflags=""
+AC_ARG_WITH(libsensors, [AS_HELP_STRING([--with-libsensors@<:@=PREFIX@:>@], [Path to lm_sensors.])],
[
- if test "x$withval" != "xno" \
- && test "x$withval" != "xyes"
- then
- if test -f "$withval" && test -x "$withval";
- then
- with_xmms_config="$withval"
- else if test -x "$withval/bin/xmms-config"
- then
- with_xmms_config="$withval/bin/xmms-config"
- fi; fi
- with_libxmms="yes"
- else if test "x$withval" = "xno"
+ if test "x$withval" = "xno"
then
- with_libxmms="no"
+ with_libsensors="no"
else
- with_libxmms="yes"
- fi; fi
+ with_libsensors="yes"
+ if test "x$withval" != "xyes"
+ then
+ with_sensors_cflags="-I$withval/include"
+ with_sensors_ldflags="-L$withval/lib"
+ with_libsensors="yes"
+ fi
+ fi
],
[
- with_libxmms="yes"
-])
-if test "x$with_libxmms" = "xyes"
-then
- with_xmms_cflags=`$with_xmms_config --cflags 2>/dev/null`
- xmms_config_status=$?
-
- if test $xmms_config_status -ne 0
+ if test "x$ac_system" = "xLinux"
then
- with_libxmms="no"
+ with_libsensors="yes"
+ else
+ with_libsensors="no (Linux only library)"
fi
-fi
-if test "x$with_libxmms" = "xyes"
+])
+if test "x$with_libsensors" = "xyes"
then
- with_xmms_libs=`$with_xmms_config --libs 2>/dev/null`
- xmms_config_status=$?
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_sensors_cflags"
- if test $xmms_config_status -ne 0
- then
- with_libxmms="no"
- fi
+# AC_CHECK_HEADERS(sensors/sensors.h,
+# [
+# AC_DEFINE(HAVE_SENSORS_SENSORS_H, 1, [Define to 1 if you have the <sensors/sensors.h> header file.])
+# ],
+# [with_libsensors="no (sensors/sensors.h not found)"])
+ AC_CHECK_HEADERS(sensors/sensors.h, [], [with_libsensors="no (sensors/sensors.h not found)"])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
fi
-if test "x$with_libxmms" = "xyes"
+if test "x$with_libsensors" = "xyes"
then
- AC_CHECK_LIB(xmms, xmms_remote_get_info,
- [
- BUILD_WITH_LIBXMMS_CFLAGS="$with_xmms_cflags"
- BUILD_WITH_LIBXMMS_LIBS="$with_xmms_libs"
- AC_SUBST(BUILD_WITH_LIBXMMS_CFLAGS)
- AC_SUBST(BUILD_WITH_LIBXMMS_LIBS)
- ],
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ SAVE_LDFLAGS="$LDFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_sensors_cflags"
+ LDFLAGS="$LDFLAGS $with_sensors_ldflags"
+
+ AC_CHECK_LIB(sensors, sensors_init,
[
- with_libxmms="no"
+ AC_DEFINE(HAVE_LIBSENSORS, 1, [Define to 1 if you have the sensors library (-lsensors).])
],
- [$with_xmms_libs])
+ [with_libsensors="no (libsensors not found)"])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+ LDFLAGS="$SAVE_LDFLAGS"
fi
-with_libxmms_numeric=0
-if test "x$with_libxmms" = "xyes"
+if test "x$with_libsensors" = "xyes"
then
- with_libxmms_numeric=1
+ BUILD_WITH_LIBSENSORS_CFLAGS="$with_sensors_cflags"
+ BUILD_WITH_LIBSENSORS_LDFLAGS="$with_sensors_ldflags"
+ AC_SUBST(BUILD_WITH_LIBSENSORS_CFLAGS)
+ AC_SUBST(BUILD_WITH_LIBSENSORS_LDFLAGS)
fi
-AC_DEFINE_UNQUOTED(HAVE_LIBXMMS, [$with_libxmms_numeric], [Define to 1 if you have the 'xmms' library (-lxmms).])
-AM_CONDITIONAL(BUILD_WITH_LIBXMMS, test "x$with_libxmms" = "xyes")
-### END of check for libxmms ###
+AM_CONDITIONAL(BUILD_WITH_LM_SENSORS, test "x$with_libsensors" = "xyes")
+# }}}
-with_libnetlink_cflags=""
-with_libnetlink_libs="-lnetlink"
-AC_ARG_WITH(libnetlink, [AS_HELP_STRING([--with-libnetlink@<:@=PREFIX@:>@], [Path to libnetlink.])],
+# --with-libstatgrab {{{
+with_libstatgrab_cflags=""
+with_libstatgrab_ldflags=""
+AC_ARG_WITH(libstatgrab, [AS_HELP_STRING([--with-libstatgrab@<:@=PREFIX@:>@], [Path to libstatgrab.])],
[
- echo "libnetlink: withval = $withval"
- if test "x$withval" = "xyes"
- then
- with_libnetlink="yes"
- else if test "x$withval" = "xno"
- then
- with_libnetlink="no"
- else
- if test -d "$withval/include"
- then
- with_libnetlink_cflags="-I$withval/include"
- with_libnetlink_libs="-L$withval/lib -lnetlink"
- with_libnetlink="yes"
- else
- AC_MSG_ERROR("no such directory: $withval/include")
- fi
- fi; fi
+ if test "x$withval" != "xno" \
+ && test "x$withval" != "xyes"
+ then
+ with_libstatgrab_cflags="-I$withval/include"
+ with_libstatgrab_ldflags="-L$withval/lib"
+ with_libstatgrab="yes"
+ else
+ with_libstatgrab="$withval"
+ fi
],
[
- if test "x$ac_system" = "xLinux"
- then
- with_libnetlink="yes"
- else
- with_libnetlink="no (Linux only library)"
- fi
+ if test "x$ac_system" = "xunknown"
+ then
+ with_libstatgrab="yes"
+ else
+ with_libstatgrab="no"
+ fi
])
-if test "x$with_libnetlink" = "xyes"
-then
- SAVE_CFLAGS=$CFLAGS
- CFLAGS="$CFLAGS $with_libnetlink_cflags"
-
- with_libnetlink="no (libnetlink.h not found)"
-
- AC_CHECK_HEADERS(libnetlink.h iproute/libnetlink.h linux/libnetlink.h,
- [
- with_libnetlink="yes"
- break
- ], [],
-[#include <stdio.h>
-#include <sys/types.h>
-#include <asm/types.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>])
- AC_CHECK_HEADERS(linux/gen_stats.h linux/pkt_sched.h, [], [],
-[#include <stdio.h>
-#include <sys/types.h>
-#include <asm/types.h>
-#include <sys/socket.h>])
-
- AC_COMPILE_IFELSE(
-[#include <stdio.h>
-#include <sys/types.h>
-#include <asm/types.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-
-int main (void)
-{
- int retval = TCA_STATS2;
- return (retval);
-}],
- [AC_DEFINE([HAVE_TCA_STATS2], 1, [True if the enum-member TCA_STATS2 exists])]
- []);
-
- AC_COMPILE_IFELSE(
-[#include <stdio.h>
-#include <sys/types.h>
-#include <asm/types.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-
-int main (void)
-{
- int retval = TCA_STATS;
- return (retval);
-}],
- [AC_DEFINE([HAVE_TCA_STATS], 1, [True if the enum-member TCA_STATS exists])]
- []);
-
- CFLAGS="$SAVE_CFLAGS"
-fi
-if test "x$with_libnetlink" = "xyes"
-then
- AC_CHECK_LIB(netlink, rtnl_open,
- [with_libnetlink="yes"],
- [with_libnetlink="no (symbol 'rtnl_open' not found)"],
- [$with_libnetlink_libs])
-fi
-if test "x$with_libnetlink" = "xyes"
-then
- BUILD_WITH_LIBNETLINK_CFLAGS="$with_libnetlink_cflags"
- BUILD_WITH_LIBNETLINK_LIBS="$with_libnetlink_libs"
- AC_SUBST(BUILD_WITH_LIBNETLINK_CFLAGS)
- AC_SUBST(BUILD_WITH_LIBNETLINK_LIBS)
-fi
-AM_CONDITIONAL(BUILD_WITH_LIBNETLINK, test "x$with_libnetlink" = "xyes")
-
-with_libopenipmipthread="yes"
-with_libopenipmipthread_cflags=""
-with_libopenipmipthread_libs=""
-
-AC_MSG_CHECKING([for pkg-config])
-temp_result="no"
-if test "x$PKG_CONFIG" = "x"
+with_libstatgrab_pkg_config="yes"
+if test "x$with_libstatgrab" = "xyes" \
+ && test "x$PKG_CONFIG" != "x"
then
- with_libopenipmipthread="no"
- temp_result="no"
+ AC_MSG_CHECKING([pkg-config for libstatgrab])
+ temp_result="found"
+ $PKG_CONFIG --exists libstatgrab 2>/dev/null
+ if test "$?" != "0"
+ then
+ with_libstatgrab_pkg_config="no"
+ temp_result="not found"
+ fi
+ AC_MSG_RESULT([$temp_result])
else
- temp_result="$PKG_CONFIG"
+ AC_MSG_NOTICE([pkg-config not available, trying to guess flags for the statgrab library.])
+ with_libstatgrab_pkg_config="no"
+ with_libstatgrab_ldflags="$with_libstatgrab_ldflags -lstatgrab"
fi
-AC_MSG_RESULT([$temp_result])
-if test "x$with_libopenipmipthread" = "xyes"
+if test "x$with_libstatgrab" = "xyes" \
+ && test "x$with_libstatgrab_pkg_config" = "xyes" \
+ && test "x$with_libstatgrab_cflags" = "x"
then
- AC_MSG_CHECKING([for libOpenIPMIpthread])
- $PKG_CONFIG --exists OpenIPMIpthread 2>/dev/null
- if test "$?" != "0"
- then
- with_libopenipmipthread="no ($PKG_CONFIG doesn't know OpenIPMIpthread)"
- fi
- AC_MSG_RESULT([$with_libopenipmipthread])
+ AC_MSG_CHECKING([for libstatgrab CFLAGS])
+ temp_result="`$PKG_CONFIG --cflags libstatgrab`"
+ if test "$?" = "0"
+ then
+ with_libstatgrab_cflags="$temp_result"
+ else
+ with_libstatgrab="no ($PKG_CONFIG --cflags libstatgrab failed)"
+ temp_result="$PKG_CONFIG --cflags libstatgrab failed"
+ fi
+ AC_MSG_RESULT([$temp_result])
fi
-if test "x$with_libopenipmipthread" = "xyes"
+if test "x$with_libstatgrab" = "xyes" \
+ && test "x$with_libstatgrab_pkg_config" = "xyes" \
+ && test "x$with_libstatgrab_ldflags" = "x"
then
- AC_MSG_CHECKING([for libOpenIPMIpthread CFLAGS])
- temp_result="`$PKG_CONFIG --cflags OpenIPMIpthread`"
- if test "$?" = "0"
- then
- with_libopenipmipthread_cflags="$temp_result"
- else
- with_libopenipmipthread="no ($PKG_CONFIG --cflags OpenIPMIpthread failed)"
- temp_result="$PKG_CONFIG --cflags OpenIPMIpthread failed"
- fi
- AC_MSG_RESULT([$temp_result])
+ AC_MSG_CHECKING([for libstatgrab LDFLAGS])
+ temp_result="`$PKG_CONFIG --libs libstatgrab`"
+ if test "$?" = "0"
+ then
+ with_libstatgrab_ldflags="$temp_result"
+ else
+ with_libstatgrab="no ($PKG_CONFIG --libs libstatgrab failed)"
+ temp_result="$PKG_CONFIG --libs libstatgrab failed"
+ fi
+ AC_MSG_RESULT([$temp_result])
fi
-if test "x$with_libopenipmipthread" = "xyes"
+if test "x$with_libstatgrab" = "xyes"
then
- AC_MSG_CHECKING([for libOpenIPMIpthread LDFLAGS])
- temp_result="`$PKG_CONFIG --libs OpenIPMIpthread`"
- if test "$?" = "0"
- then
- with_libopenipmipthread_ldflags="$temp_result"
- else
- with_libopenipmipthread="no ($PKG_CONFIG --libs OpenIPMIpthread failed)"
- temp_result="$PKG_CONFIG --libs OpenIPMIpthread failed"
- fi
- AC_MSG_RESULT([$temp_result])
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_libstatgrab_cflags"
+
+ AC_CHECK_HEADERS(statgrab.h,
+ [with_libstatgrab="yes"],
+ [with_libstatgrab="no (statgrab.h not found)"])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
fi
-if test "x$with_libopenipmipthread" = "xyes"
+if test "x$with_libstatgrab" = "xyes"
then
- SAVE_CPPFLAGS="$CPPFLAGS"
- CPPFLAGS="$CPPFLAGS $with_libopenipmipthread_cflags"
+ SAVE_CFLAGS="$CFLAGS"
+ SAVE_LDFLAGS="$LDFLAGS"
- AC_CHECK_HEADERS(OpenIPMI/ipmi_smi.h,
- [with_libopenipmipthread="yes"],
- [with_libopenipmipthread="no (OpenIPMI/ipmi_smi.h not found)"],
-[#include <OpenIPMI/ipmiif.h>
-#include <OpenIPMI/ipmi_err.h>
-#include <OpenIPMI/ipmi_posix.h>
-#include <OpenIPMI/ipmi_conn.h>
-])
+ CFLAGS="$CFLAGS $with_libstatgrab_cflags"
+ LDFLAGS="$LDFLAGS $with_libstatgrab_ldflags"
- CPPFLAGS="$SAVE_CPPFLAGS"
+ AC_CHECK_LIB(statgrab, sg_init,
+ [with_libstatgrab="yes"],
+ [with_libstatgrab="no (symbol sg_init not found)"])
+
+ CFLAGS="$SAVE_CFLAGS"
+ LDFLAGS="$SAVE_LDFLAGS"
fi
-if test "x$with_libopenipmipthread" = "xyes"
+AM_CONDITIONAL(BUILD_WITH_LIBSTATGRAB, test "x$with_libstatgrab" = "xyes")
+if test "x$with_libstatgrab" = "xyes"
then
- BUILD_WITH_OPENIPMI_CFLAGS="$with_libopenipmipthread_cflags"
- BUILD_WITH_OPENIPMI_LIBS="$with_libopenipmipthread_ldflags"
- AC_SUBST(BUILD_WITH_OPENIPMI_CFLAGS)
- AC_SUBST(BUILD_WITH_OPENIPMI_LIBS)
+ AC_DEFINE(HAVE_LIBSTATGRAB, 1, [Define to 1 if you have the 'statgrab' library (-lstatgrab)])
+ BUILD_WITH_LIBSTATGRAB_CFLAGS="$with_libstatgrab_cflags"
+ BUILD_WITH_LIBSTATGRAB_LDFLAGS="$with_libstatgrab_ldflags"
+ AC_SUBST(BUILD_WITH_LIBSTATGRAB_CFLAGS)
+ AC_SUBST(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
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.])],
+# --with-libxmms {{{
+with_xmms_config="xmms-config"
+with_xmms_cflags=""
+with_xmms_libs=""
+AC_ARG_WITH(libxmms, [AS_HELP_STRING([--with-libxmms@<:@=PREFIX@:>@], [Path to libxmms.])],
[
- if test "x$withval" = "xno"
- then
- with_libpq="no"
- else if test "x$withval" = "xyes"
+ if test "x$withval" != "xno" \
+ && 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"
+ with_xmms_config="$withval"
+ else if test -x "$withval/bin/xmms-config"
then
- with_pg_config="$withval/bin/pg_config"
+ with_xmms_config="$withval/bin/xmms-config"
fi; fi
- with_libpq="yes"
+ with_libxmms="yes"
+ else if test "x$withval" = "xno"
+ then
+ with_libxmms="no"
+ else
+ with_libxmms="yes"
fi; fi
],
[
- with_libpq="yes"
+ with_libxmms="yes"
])
-if test "x$with_libpq" = "xyes"
+if test "x$with_libxmms" = "xyes"
then
- with_libpq_includedir=`$with_pg_config --includedir 2> /dev/null`
- pg_config_status=$?
+ with_xmms_cflags=`$with_xmms_config --cflags 2>/dev/null`
+ xmms_config_status=$?
- if test $pg_config_status -eq 0
+ if test $xmms_config_status -ne 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])
+ with_libxmms="no"
fi
+fi
+if test "x$with_libxmms" = "xyes"
+then
+ with_xmms_libs=`$with_xmms_config --libs 2>/dev/null`
+ xmms_config_status=$?
- 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"
+ if test $xmms_config_status -ne 0
+ then
+ with_libxmms="no"
+ fi
fi
-if test "x$with_libpq" = "xyes"
+if test "x$with_libxmms" = "xyes"
then
- with_libpq_libdir=`$with_pg_config --libdir 2> /dev/null`
- pg_config_status=$?
+ AC_CHECK_LIB(xmms, xmms_remote_get_info,
+ [
+ BUILD_WITH_LIBXMMS_CFLAGS="$with_xmms_cflags"
+ BUILD_WITH_LIBXMMS_LIBS="$with_xmms_libs"
+ AC_SUBST(BUILD_WITH_LIBXMMS_CFLAGS)
+ AC_SUBST(BUILD_WITH_LIBXMMS_LIBS)
+ ],
+ [
+ with_libxmms="no"
+ ],
+ [$with_xmms_libs])
+fi
+with_libxmms_numeric=0
+if test "x$with_libxmms" = "xyes"
+then
+ with_libxmms_numeric=1
+fi
+AC_DEFINE_UNQUOTED(HAVE_LIBXMMS, [$with_libxmms_numeric], [Define to 1 if you have the 'xmms' library (-lxmms).])
+AM_CONDITIONAL(BUILD_WITH_LIBXMMS, test "x$with_libxmms" = "xyes")
+# }}}
- if test $pg_config_status -eq 0
+# pkg-config --exists 'libupsclient' {{{
+with_libupsclient="no (pkg-config isn't available)"
+with_libupsclient_cflags=""
+with_libupsclient_libs=""
+if test "x$PKG_CONFIG" != "x"
+then
+ pkg-config --exists 'libupsclient' 2>/dev/null
+ if test "$?" = "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
+ with_libupsclient="yes"
else
- AC_MSG_WARN([$with_pg_config returned with status $pg_config_status])
+ with_libupsclient="no (pkg-config doesn't know library)"
+ fi
+fi
+if test "x$with_libupsclient" = "xyes"
+then
+ with_libupsclient_cflags="`pkg-config --cflags 'libupsclient'`"
+ if test $? -ne 0
+ then
+ with_libupsclient="no"
+ fi
+ with_libupsclient_libs="`pkg-config --libs 'libupsclient'`"
+ if test $? -ne 0
+ then
+ with_libupsclient="no"
fi
+fi
+if test "x$with_libupsclient" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_libupsclient_cflags"
+ AC_CHECK_HEADERS(upsclient.h, [], [with_libupsclient="no (upsclient.h not found)"])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_libupsclient" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
SAVE_LDFLAGS="$LDFLAGS"
- LDFLAGS="$LDFLAGS $with_libpq_ldflags"
- AC_CHECK_LIB(pq, PQconnectdb,
- [with_libpq="yes"],
- [with_libpq="no (symbol 'PQconnectdb' not found)"])
+ CPPFLAGS="$CPPFLAGS $with_libupsclient_cflags"
+ LDFLAGS="$LDFLAGS $with_libupsclient_libs"
+
+ AC_CHECK_LIB(upsclient, upscli_connect,
+ [with_libupsclient="yes"],
+ [with_libupsclient="no (symbol upscli_connect not found)"])
+ CPPFLAGS="$SAVE_CPPFLAGS"
LDFLAGS="$SAVE_LDFLAGS"
fi
-if test "x$with_libpq" = "xyes"
+if test "x$with_libupsclient" = "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)
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_libupsclient_cflags"
+
+ AC_CHECK_TYPES([UPSCONN_t, UPSCONN], [], [],
+[#include <stdlib.h>
+#include <stdio.h>
+#include <upsclient.h>])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
fi
-AM_CONDITIONAL(BUILD_WITH_LIBPQ, test "x$with_libpq" = "xyes")
+if test "x$with_libupsclient" = "xyes"
+then
+ BUILD_WITH_LIBUPSCLIENT_CFLAGS="$with_libupsclient_cflags"
+ BUILD_WITH_LIBUPSCLIENT_LIBS="$with_libupsclient_libs"
+ AC_SUBST(BUILD_WITH_LIBUPSCLIENT_CFLAGS)
+ AC_SUBST(BUILD_WITH_LIBUPSCLIENT_LIBS)
+fi
+# }}}
-dnl Check for libvirt and libxml2 libraries.
+# pkg-config --exists 'libxml-2.0'; pkg-config --exists libvirt {{{
with_libxml2="no (pkg-config isn't available)"
with_libxml2_cflags=""
with_libxml2_ldflags=""
AC_SUBST(BUILD_WITH_LIBVIRT_CFLAGS)
AC_SUBST(BUILD_WITH_LIBVIRT_LIBS)
fi
+# }}}
+
+# $PKG_CONFIG --exists OpenIPMIpthread {{{
+with_libopenipmipthread="yes"
+with_libopenipmipthread_cflags=""
+with_libopenipmipthread_libs=""
+
+AC_MSG_CHECKING([for pkg-config])
+temp_result="no"
+if test "x$PKG_CONFIG" = "x"
+then
+ with_libopenipmipthread="no"
+ temp_result="no"
+else
+ temp_result="$PKG_CONFIG"
+fi
+AC_MSG_RESULT([$temp_result])
+
+if test "x$with_libopenipmipthread" = "xyes"
+then
+ AC_MSG_CHECKING([for libOpenIPMIpthread])
+ $PKG_CONFIG --exists OpenIPMIpthread 2>/dev/null
+ if test "$?" != "0"
+ then
+ with_libopenipmipthread="no ($PKG_CONFIG doesn't know OpenIPMIpthread)"
+ fi
+ AC_MSG_RESULT([$with_libopenipmipthread])
+fi
+
+if test "x$with_libopenipmipthread" = "xyes"
+then
+ AC_MSG_CHECKING([for libOpenIPMIpthread CFLAGS])
+ temp_result="`$PKG_CONFIG --cflags OpenIPMIpthread`"
+ if test "$?" = "0"
+ then
+ with_libopenipmipthread_cflags="$temp_result"
+ else
+ with_libopenipmipthread="no ($PKG_CONFIG --cflags OpenIPMIpthread failed)"
+ temp_result="$PKG_CONFIG --cflags OpenIPMIpthread failed"
+ fi
+ AC_MSG_RESULT([$temp_result])
+fi
+
+if test "x$with_libopenipmipthread" = "xyes"
+then
+ AC_MSG_CHECKING([for libOpenIPMIpthread LDFLAGS])
+ temp_result="`$PKG_CONFIG --libs OpenIPMIpthread`"
+ if test "$?" = "0"
+ then
+ with_libopenipmipthread_ldflags="$temp_result"
+ else
+ with_libopenipmipthread="no ($PKG_CONFIG --libs OpenIPMIpthread failed)"
+ temp_result="$PKG_CONFIG --libs OpenIPMIpthread failed"
+ fi
+ AC_MSG_RESULT([$temp_result])
+fi
+
+if test "x$with_libopenipmipthread" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_libopenipmipthread_cflags"
+
+ AC_CHECK_HEADERS(OpenIPMI/ipmi_smi.h,
+ [with_libopenipmipthread="yes"],
+ [with_libopenipmipthread="no (OpenIPMI/ipmi_smi.h not found)"],
+[#include <OpenIPMI/ipmiif.h>
+#include <OpenIPMI/ipmi_err.h>
+#include <OpenIPMI/ipmi_posix.h>
+#include <OpenIPMI/ipmi_conn.h>
+])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+
+if test "x$with_libopenipmipthread" = "xyes"
+then
+ BUILD_WITH_OPENIPMI_CFLAGS="$with_libopenipmipthread_cflags"
+ BUILD_WITH_OPENIPMI_LIBS="$with_libopenipmipthread_ldflags"
+ AC_SUBST(BUILD_WITH_OPENIPMI_CFLAGS)
+ AC_SUBST(BUILD_WITH_OPENIPMI_LIBS)
+fi
+# }}}
-dnl End of check for libvirt and libxml2 libraries.
+PKG_CHECK_MODULES([LIBNOTIFY], [libnotify],
+ [with_libnotify="yes"],
+ [with_libnotify="no ($LIBNOTIFY_PKG_ERRORS)"])
# Check for enabled/disabled features
#
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([dbi], [$with_libdbi], [General database statistics])
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([entropy], [$plugin_entropy], [Entropy statistics])
AC_PLUGIN([exec], [yes], [Execution of external programs])
AC_PLUGIN([filecount], [yes], [Count files in directories])
+AC_PLUGIN([filter_ignore], [yes], [Ignore specific values])
AC_PLUGIN([hddtemp], [yes], [Query hddtempd])
AC_PLUGIN([interface], [$plugin_interface], [Interface traffic statistics])
AC_PLUGIN([iptables], [$with_libiptc], [IPTables rule counters])
AC_PLUGIN([libvirt], [$plugin_libvirt], [Virtual machine statistics])
AC_PLUGIN([load], [$plugin_load], [System load])
AC_PLUGIN([logfile], [yes], [File logging plugin])
+AC_PLUGIN([match_regex], [yes], [The regex match])
+AC_PLUGIN([match_value], [yes], [The value match])
AC_PLUGIN([mbmon], [yes], [Query mbmond])
AC_PLUGIN([memcached], [yes], [memcached statistics])
AC_PLUGIN([memory], [$plugin_memory], [Memory usage])
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([oracle], [$with_oracle], [Oracle plugin])
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])
-AC_PLUGIN([sensors], [$with_lm_sensors], [lm_sensors statistics])
+AC_PLUGIN([rrdtool], [$with_librrd], [RRDTool output plugin])
+AC_PLUGIN([rrdcached], [$librrd_rrdc_update], [RRDTool output plugin])
+AC_PLUGIN([sensors], [$with_libsensors], [lm_sensors statistics])
AC_PLUGIN([serial], [$plugin_serial], [serial port traffic])
AC_PLUGIN([snmp], [$with_libnetsnmp], [SNMP querying plugin])
AC_PLUGIN([swap], [$plugin_swap], [Swap usage statistics])
AC_PLUGIN([syslog], [$have_syslog], [Syslog logging plugin])
AC_PLUGIN([tail], [yes], [Parsing of logfiles])
AC_PLUGIN([tape], [$plugin_tape], [Tape drive statistics])
+AC_PLUGIN([target_set], [yes], [The set target])
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_SUBST(PERL_BINDINGS)
AC_SUBST(PERL_BINDINGS_OPTIONS)
-AC_OUTPUT(Makefile src/Makefile src/collectd.conf src/libiptc/Makefile src/liboconfig/Makefile src/liboping/Makefile bindings/Makefile)
+AC_OUTPUT(Makefile src/Makefile src/collectd.conf src/libiptc/Makefile src/libcollectdclient/Makefile src/liboconfig/Makefile src/liboping/Makefile bindings/Makefile)
-if test "x$with_rrdtool" = "xyes" \
+if test "x$with_librrd" = "xyes" \
&& test "x$librrd_threadsafe" != "xyes"
then
- with_rrdtool="yes (warning: librrd is not thread-safe)"
+ with_librrd="yes (warning: librrd is not thread-safe)"
fi
if test "x$with_liboping" = "xyes" \
Configuration:
Libraries:
libcurl . . . . . . . $with_libcurl
+ libdbi . . . . . . . $with_libdbi
libesmtp . . . . . . $with_libesmtp
libiokit . . . . . . $with_libiokit
libiptc . . . . . . . $with_libiptc
libopenipmi . . . . . $with_libopenipmipthread
liboping . . . . . . $with_liboping
libpcap . . . . . . . $with_libpcap
+ libpcre . . . . . . . $with_libpcre
libperl . . . . . . . $with_libperl
libpthread . . . . . $with_libpthread
libpq . . . . . . . . $with_libpq
- librrd . . . . . . . $with_rrdtool
- libsensors . . . . . $with_lm_sensors
+ librrd . . . . . . . $with_librrd
+ libsensors . . . . . $with_libsensors
libstatgrab . . . . . $with_libstatgrab
libupsclient . . . . $with_libupsclient
libvirt . . . . . . . $with_libvirt
libxml2 . . . . . . . $with_libxml2
libxmms . . . . . . . $with_libxmms
+ oracle . . . . . . . $with_oracle
Features:
daemon mode . . . . . $enable_daemon
cpu . . . . . . . . . $enable_cpu
cpufreq . . . . . . . $enable_cpufreq
csv . . . . . . . . . $enable_csv
+ dbi . . . . . . . . . $enable_dbi
df . . . . . . . . . $enable_df
disk . . . . . . . . $enable_disk
dns . . . . . . . . . $enable_dns
entropy . . . . . . . $enable_entropy
exec . . . . . . . . $enable_exec
filecount . . . . . . $enable_filecount
+ filter_ignore . . . . $enable_filter_ignore
hddtemp . . . . . . . $enable_hddtemp
interface . . . . . . $enable_interface
iptables . . . . . . $enable_iptables
libvirt . . . . . . . $enable_libvirt
load . . . . . . . . $enable_load
logfile . . . . . . . $enable_logfile
+ match_regex . . . . . $enable_match_regex
+ match_value . . . . . $enable_match_value
mbmon . . . . . . . . $enable_mbmon
memcached . . . . . . $enable_memcached
memory . . . . . . . $enable_memory
ntpd . . . . . . . . $enable_ntpd
nut . . . . . . . . . $enable_nut
onewire . . . . . . . $enable_onewire
+ oracle . . . . . . . $enable_oracle
perl . . . . . . . . $enable_perl
ping . . . . . . . . $enable_ping
postgresql . . . . . $enable_postgresql
powerdns . . . . . . $enable_powerdns
processes . . . . . . $enable_processes
rrdtool . . . . . . . $enable_rrdtool
+ rrdcached . . . . . . $enable_rrdcached
sensors . . . . . . . $enable_sensors
serial . . . . . . . $enable_serial
snmp . . . . . . . . $enable_snmp
syslog . . . . . . . $enable_syslog
tail . . . . . . . . $enable_tail
tape . . . . . . . . $enable_tape
+ target_set . . . . . $enable_target_set
tcpconns . . . . . . $enable_tcpconns
teamspeak2 . . . . . $enable_teamspeak2
thermal . . . . . . . $enable_thermal
if test "x$dependency_error" = "xyes"; then
AC_MSG_ERROR("Some plugins are missing dependencies - see above summary for details")
fi
+
+# vim: set fdm=marker :
can use a hyphen to add a "type instance" to the type.
For a list of already defined "types" look at the F<types.db> file in
-collectd's library path, e.E<nbsp>g. F</usr/lib/collectd/>.
+collectd's shared data directory, e.E<nbsp>g. F</usr/share/collectd/>.
=item B<Interval> I<Seconds>
%attr(0644,root,root) %{_libdir}/%{name}/wireless.so*
%attr(0644,root,root) %{_libdir}/%{name}/wireless.la
-%attr(0644,root,root) %{_libdir}/%{name}/types.db
+%attr(0644,root,root) %{_datadir}/%{name}/types.db
%dir /var/lib/collectd
--- /dev/null
+-- Description
+--------------
+-- This will create a schema to provide collectd with the required permissions
+-- and space for statistic data.
+-- The idea is to store the output of some expensive queries in static tables
+-- and fill these tables with dbms_scheduler jobs as often as necessary.
+-- collectd will then just read from the static tables. This will reduces the
+-- chance that your system will be killed by excessive monitoring queries and
+-- gives the dba control on the interval the information provided to collectd
+-- will be refreshed. You have to create a dbms_scheduler job for each of the
+-- schemas you what to monitor for object-space-usage. See the example below.
+--
+-- Requirements
+---------------
+-- make sure you have:
+-- write permission in $PWD
+-- you have GID of oracle software owner
+-- set $ORACLE_HOME
+-- set $ORACLE_SID
+-- DB is up an running in RW mode
+-- execute like this:
+-- sqlplus /nolog @ create_collectd-schema.dll
+
+spool create_collectd-schema.log
+connect / as sysdba
+
+-- Create user, tablespace and permissions
+
+CREATE TABLESPACE "COLLECTD-TBS"
+ DATAFILE SIZE 30M
+ AUTOEXTEND ON
+ NEXT 10M
+ MAXSIZE 300M
+ LOGGING
+ EXTENT MANAGEMENT LOCAL
+ SEGMENT SPACE MANAGEMENT AUTO
+ DEFAULT NOCOMPRESS;
+
+CREATE ROLE "CREATE_COLLECTD_SCHEMA" NOT IDENTIFIED;
+GRANT CREATE JOB TO "CREATE_COLLECTD_SCHEMA";
+GRANT CREATE SEQUENCE TO "CREATE_COLLECTD_SCHEMA";
+GRANT CREATE SYNONYM TO "CREATE_COLLECTD_SCHEMA";
+GRANT CREATE TABLE TO "CREATE_COLLECTD_SCHEMA";
+GRANT CREATE VIEW TO "CREATE_COLLECTD_SCHEMA";
+GRANT CREATE PROCEDURE TO "CREATE_COLLECTD_SCHEMA";
+
+CREATE USER "COLLECTDU"
+ PROFILE "DEFAULT"
+ IDENTIFIED BY "Change_me-1st"
+ PASSWORD EXPIRE
+ DEFAULT TABLESPACE "COLLECTD-TBS"
+ TEMPORARY TABLESPACE "TEMP"
+ QUOTA UNLIMITED ON "COLLECTD-TBS"
+ ACCOUNT UNLOCK;
+
+GRANT "CONNECT" TO "COLLECTDU";
+GRANT "SELECT_CATALOG_ROLE" TO "COLLECTDU";
+GRANT "CREATE_COLLECTD_SCHEMA" TO "COLLECTDU";
+GRANT analyze any TO "COLLECTDU";
+GRANT select on dba_tables TO "COLLECTDU";
+GRANT select on dba_lobs TO "COLLECTDU";
+GRANT select on dba_indexes TO "COLLECTDU";
+GRANT select on dba_segments TO "COLLECTDU";
+GRANT select on dba_tab_columns TO "COLLECTDU";
+GRANT select on dba_free_space TO "COLLECTDU";
+GRANT select on dba_data_files TO "COLLECTDU";
+-- Create tables and indexes
+
+alter session set current_schema=collectdu;
+
+create table c_tbs_usage (
+ tablespace_name varchar2(30),
+ bytes_free number,
+ bytes_used number,
+ CONSTRAINT "C_TBS_USAGE_UK1" UNIQUE ("TABLESPACE_NAME") USING INDEX
+ TABLESPACE "COLLECTD-TBS" ENABLE)
+ TABLESPACE "COLLECTD-TBS";
+
+CREATE TABLE "COLLECTDU"."C_TBL_SIZE" (
+ "OWNER" VARCHAR2(30 BYTE),
+ "TABLE_NAME" VARCHAR2(30 BYTE),
+ "BYTES" NUMBER,
+ CONSTRAINT "C_TBL_SIZE_UK1" UNIQUE ("OWNER", "TABLE_NAME")
+ USING INDEX TABLESPACE "COLLECTD-TBS" ENABLE)
+ TABLESPACE "COLLECTD-TBS" ;
+
+
+create or replace PROCEDURE get_object_size(owner IN VARCHAR2) AS
+
+v_owner VARCHAR2(30) := owner;
+
+l_free_blks NUMBER;
+l_total_blocks NUMBER;
+l_total_bytes NUMBER;
+l_unused_blocks NUMBER;
+l_unused_bytes NUMBER;
+l_lastusedextfileid NUMBER;
+l_lastusedextblockid NUMBER;
+l_last_used_block NUMBER;
+
+CURSOR cur_tbl IS
+SELECT owner,
+ TABLE_NAME
+FROM dba_tables
+WHERE owner = v_owner;
+
+CURSOR cur_idx IS
+SELECT owner,
+ index_name,
+ TABLE_NAME
+FROM dba_indexes
+WHERE owner = v_owner;
+
+CURSOR cur_lob IS
+SELECT owner,
+ segment_name,
+ TABLE_NAME
+FROM dba_lobs
+WHERE owner = v_owner;
+
+BEGIN
+
+ DELETE FROM c_tbl_size
+ WHERE owner = v_owner;
+ COMMIT;
+
+ FOR r_tbl IN cur_tbl
+ LOOP
+ BEGIN
+ dbms_space.unused_space(segment_owner => r_tbl.owner, segment_name => r_tbl.TABLE_NAME, segment_type => 'TABLE', total_blocks => l_total_blocks, total_bytes => l_total_bytes, unused_blocks => l_unused_blocks, unused_bytes => l_unused_bytes, last_used_extent_file_id => l_lastusedextfileid, last_used_extent_block_id => l_lastusedextblockid, last_used_block => l_last_used_block);
+
+ EXCEPTION
+ WHEN others THEN
+ DBMS_OUTPUT.PUT_LINE('tbl_name: ' || r_tbl.TABLE_NAME);
+ END;
+ INSERT
+ INTO c_tbl_size
+ VALUES(r_tbl.owner, r_tbl.TABLE_NAME, l_total_bytes -l_unused_bytes);
+ END LOOP;
+
+ COMMIT;
+
+ FOR r_idx IN cur_idx
+ LOOP
+ BEGIN
+ dbms_space.unused_space(segment_owner => r_idx.owner, segment_name => r_idx.index_name, segment_type => 'INDEX', total_blocks => l_total_blocks, total_bytes => l_total_bytes, unused_blocks => l_unused_blocks, unused_bytes => l_unused_bytes, last_used_extent_file_id => l_lastusedextfileid, last_used_extent_block_id => l_lastusedextblockid, last_used_block => l_last_used_block);
+
+ EXCEPTION
+ WHEN others THEN
+ DBMS_OUTPUT.PUT_LINE('idx_name: ' || r_idx.index_name);
+ END;
+
+ UPDATE c_tbl_size
+ SET bytes = bytes + l_total_bytes -l_unused_bytes
+ WHERE owner = r_idx.owner
+ AND TABLE_NAME = r_idx.TABLE_NAME;
+ END LOOP;
+
+ COMMIT;
+
+ FOR r_lob IN cur_lob
+ LOOP
+ BEGIN
+ dbms_space.unused_space(segment_owner => r_lob.owner, segment_name => r_lob.segment_name, segment_type => 'LOB', total_blocks => l_total_blocks, total_bytes => l_total_bytes, unused_blocks => l_unused_blocks, unused_bytes => l_unused_bytes, last_used_extent_file_id => l_lastusedextfileid, last_used_extent_block_id => l_lastusedextblockid, last_used_block => l_last_used_block);
+
+ EXCEPTION
+ WHEN others THEN
+ DBMS_OUTPUT.PUT_LINE('lob_name: ' || r_lob.segment_name);
+ END;
+
+ UPDATE c_tbl_size
+ SET bytes = bytes + l_total_bytes -l_unused_bytes
+ WHERE owner = r_lob.owner
+ AND TABLE_NAME = r_lob.TABLE_NAME;
+ END LOOP;
+
+ COMMIT;
+
+END get_object_size;
+/
+
+create or replace PROCEDURE get_tbs_size AS
+BEGIN
+
+execute immediate 'truncate table c_tbs_usage';
+
+insert into c_tbs_usage (
+select df.tablespace_name as tablespace_name,
+ decode(df.maxbytes,
+ 0,
+ sum(fs.bytes),
+ (df.maxbytes-(df.bytes-sum(fs.bytes)))) as bytes_free,
+ decode(df.maxbytes,
+ 0,
+ round((df.bytes-sum(fs.bytes))),
+ round(df.maxbytes-(df.maxbytes-(df.bytes-sum(fs.bytes))))) as bytes_used
+from dba_free_space fs inner join
+ (select
+ tablespace_name,
+ sum(bytes) bytes,
+ sum(decode(maxbytes,0,bytes,maxbytes)) maxbytes
+ from dba_data_files
+ group by tablespace_name ) df
+on fs.tablespace_name = df.tablespace_name
+group by df.tablespace_name,df.maxbytes,df.bytes);
+
+COMMIT;
+
+END get_tbs_size;
+/
+
+BEGIN
+sys.dbms_scheduler.create_job(
+job_name => '"COLLECTDU"."C_TBSSIZE_JOB"',
+job_type => 'PLSQL_BLOCK',
+job_action => 'begin
+ get_tbs_size();
+end;',
+repeat_interval => 'FREQ=MINUTELY;INTERVAL=5',
+start_date => systimestamp at time zone 'Europe/Berlin',
+job_class => '"DEFAULT_JOB_CLASS"',
+auto_drop => FALSE,
+enabled => TRUE);
+END;
+/
+
+BEGIN
+sys.dbms_scheduler.create_job(
+job_name => '"COLLECTDU"."C_TBLSIZE_COLLECTDU_JOB"',
+job_type => 'PLSQL_BLOCK',
+job_action => 'begin
+ get_object_size( owner => ''COLLECTDU'' );
+end;',
+repeat_interval => 'FREQ=HOURLY;INTERVAL=12',
+start_date => systimestamp at time zone 'Europe/Berlin',
+job_class => '"DEFAULT_JOB_CLASS"',
+auto_drop => FALSE,
+enabled => TRUE);
+END;
+/
+
+spool off
+quit
--- /dev/null
+-- Table sizes
+SELECT owner,
+ TABLE_NAME,
+ bytes
+FROM collectdu.c_tbl_size;
+
+-- Tablespace sizes
+SELECT tablespace_name,
+ bytes_free,
+ bytes_used
+FROM collectdu.c_tbs_usage;
+
+-- IO per Tablespace
+SELECT SUM(vf.phyblkrd) *8192 AS
+phy_blk_r,
+ SUM(vf.phyblkwrt) *8192 AS
+phy_blk_w,
+ 'tablespace' AS
+i_prefix,
+ dt.tablespace_name
+FROM((dba_data_files dd JOIN v$filestat vf ON dd.file_id = vf.file#) JOIN dba_tablespaces dt ON dd.tablespace_name = dt.tablespace_name)
+GROUP BY dt.tablespace_name;
+
+-- Buffer Pool Hit Ratio:
+SELECT DISTINCT 100 *ROUND(1 -((MAX(decode(name, 'physical reads cache', VALUE))) /(MAX(decode(name, 'db block gets from cache', VALUE)) + MAX(decode(name, 'consistent gets from cache', VALUE)))), 4) AS
+VALUE,
+ 'BUFFER_CACHE_HIT_RATIO' AS
+buffer_cache_hit_ratio
+FROM v$sysstat;
+
+-- Shared Pool Hit Ratio:
+SELECT
+ 100.0 * sum(PINHITS) / sum(pins) as VALUE,
+ 'SHAREDPOOL_HIT_RATIO' AS SHAREDPOOL_HIT_RATIO
+FROM V$LIBRARYCACHE;
+
+-- PGA Hit Ratio:
+SELECT VALUE,
+ 'PGA_HIT_RATIO' AS
+pga_hit_ratio
+FROM v$pgastat
+WHERE name = 'cache hit percentage';
+
+-- DB Efficiency
+SELECT ROUND(SUM(decode(metric_name, 'Database Wait Time Ratio', VALUE)), 2) AS
+database_wait_time_ratio,
+ ROUND(SUM(decode(metric_name, 'Database CPU Time Ratio', VALUE)), 2) AS
+database_cpu_time_ratio,
+ 'DB_EFFICIENCY' AS
+db_efficiency
+FROM sys.v_$sysmetric
+WHERE metric_name IN('Database CPU Time Ratio', 'Database Wait Time Ratio')
+ AND intsize_csec =
+ (SELECT MAX(intsize_csec)
+ FROM sys.v_$sysmetric);
BaseDir "/var/lib/collectd"
PIDFile "/var/run/collectd.pid"
PluginDir "/usr/lib/collectd"
-TypesDB "/usr/lib/collectd/types.db"
+TypesDB "/usr/share/collectd/types.db"
Interval 10
ReadThreads 5
sed -i 's:#BaseDir "/usr/var/lib/collectd":BaseDir "/var/lib/collectd":' $RPM_BUILD_ROOT/etc/collectd.conf
sed -i 's:#PIDFile "/usr/var/run/collectd.pid":PIDFile "/var/run/collectd.pid":' $RPM_BUILD_ROOT/etc/collectd.conf
sed -i 's:#PluginDir "/usr/lib/collectd":PluginDir "/usr/lib/collectd":' $RPM_BUILD_ROOT/etc/collectd.conf
-sed -i 's:#TypesDB "/usr/lib/collectd/types.db":TypesDB "/usr/lib/collectd/types.db":' $RPM_BUILD_ROOT/etc/collectd.conf
+sed -i 's:#TypesDB "/usr/share/collectd/types.db":TypesDB "/usr/share/collectd/types.db":' $RPM_BUILD_ROOT/etc/collectd.conf
sed -i 's:#Interval 10:Interval 10:' $RPM_BUILD_ROOT/etc/collectd.conf
sed -i 's:#ReadThreads 5:ReadThreads 5:' $RPM_BUILD_ROOT/etc/collectd.conf
##Move config contribs
%attr(0644,root,root) %{_libdir}/%{name}/wireless.so*
%attr(0644,root,root) %{_libdir}/%{name}/wireless.la
-%attr(0644,root,root) %{_libdir}/%{name}/types.db
+%attr(0644,root,root) %{_datadir}/%{name}/types.db
%exclude %{_libdir}/perl5/5.8.8/%{_arch}-linux-thread-multi/perllocal.pod
%attr(0644,root,root) %{_libdir}/perl5/site_perl/5.8.8/Collectd.pm
-SUBDIRS =
+SUBDIRS = libcollectdclient
if BUILD_WITH_OWN_LIBIPTC
SUBDIRS += libiptc
endif
collectd_SOURCES = collectd.c collectd.h \
common.c common.h \
configfile.c configfile.h \
+ filter_chain.c filter_chain.h \
+ meta_data.c meta_data.h \
plugin.c plugin.h \
utils_avltree.c utils_avltree.h \
utils_cache.c utils_cache.h \
utils_tail_match.c utils_tail_match.h \
utils_match.c utils_match.h \
utils_mount.c utils_mount.h \
+ utils_subst.c utils_subst.h \
utils_tail.c utils_tail.h \
utils_threshold.c utils_threshold.h \
types_list.c types_list.h
if BUILD_WITH_LIBSOCKET
collectd_nagios_LDFLAGS += -lsocket
endif
+collectd_nagios_LDADD = libcollectdclient/libcollectdclient.la
+collectd_nagios_DEPENDENCIES = libcollectdclient/libcollectdclient.la
pkglib_LTLIBRARIES =
collectd_DEPENDENCIES += csv.la
endif
+if BUILD_PLUGIN_DBI
+pkglib_LTLIBRARIES += dbi.la
+dbi_la_SOURCES = dbi.c
+dbi_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBDBI_CPPFLAGS)
+dbi_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBDBI_LDFLAGS)
+dbi_la_LIBADD = $(BUILD_WITH_LIBDBI_LIBS)
+collectd_LDADD += "-dlopen" dbi.la
+collectd_DEPENDENCIES += dbi.la
+endif
+
if BUILD_PLUGIN_DF
pkglib_LTLIBRARIES += df.la
df_la_SOURCES = df.c
collectd_DEPENDENCIES += filecount.la
endif
+if BUILD_PLUGIN_FILTER_IGNORE
+pkglib_LTLIBRARIES += filter_ignore.la
+filter_ignore_la_SOURCES = filter_ignore.c
+filter_ignore_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" filter_ignore.la
+collectd_DEPENDENCIES += filter_ignore.la
+endif
+
if BUILD_PLUGIN_HDDTEMP
pkglib_LTLIBRARIES += hddtemp.la
hddtemp_la_SOURCES = hddtemp.c
collectd_DEPENDENCIES += logfile.la
endif
+if BUILD_PLUGIN_MATCH_REGEX
+pkglib_LTLIBRARIES += match_regex.la
+match_regex_la_SOURCES = match_regex.c
+match_regex_la_CPPFLAGS = $(BUILD_WITH_LIBPCRE_CFLAGS)
+match_regex_la_LDFLAGS = -module -avoid-version \
+ $(BUILD_WITH_LIBPCRE_LIBS)
+collectd_LDADD += "-dlopen" match_regex.la
+collectd_DEPENDENCIES += match_regex.la
+endif
+
+if BUILD_PLUGIN_MATCH_VALUE
+pkglib_LTLIBRARIES += match_value.la
+match_value_la_SOURCES = match_value.c
+match_value_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" match_value.la
+collectd_DEPENDENCIES += match_value.la
+endif
+
if BUILD_PLUGIN_MBMON
pkglib_LTLIBRARIES += mbmon.la
mbmon_la_SOURCES = mbmon.c
collectd_DEPENDENCIES += onewire.la
endif
+if BUILD_PLUGIN_ORACLE
+pkglib_LTLIBRARIES += oracle.la
+oracle_la_SOURCES = oracle.c
+oracle_la_CFLAGS = $(AM_CFLAGS)
+oracle_la_CPPFLAGS = $(BUILD_WITH_ORACLE_CFLAGS)
+oracle_la_LIBADD = $(BUILD_WITH_ORACLE_LIBS)
+oracle_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" oracle.la
+collectd_DEPENDENCIES += oracle.la
+endif
+
if BUILD_PLUGIN_PERL
pkglib_LTLIBRARIES += perl.la
perl_la_SOURCES = perl.c
endif
endif
+if BUILD_PLUGIN_RRDCACHED
+pkglib_LTLIBRARIES += rrdcached.la
+rrdcached_la_SOURCES = rrdcached.c utils_rrdcreate.c utils_rrdcreate.h
+rrdcached_la_LDFLAGS = -module -avoid-version
+rrdcached_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBRRD_CFLAGS)
+rrdcached_la_LIBADD = $(BUILD_WITH_LIBRRD_LDFLAGS)
+collectd_LDADD += "-dlopen" rrdcached.la
+collectd_DEPENDENCIES += rrdcached.la
+endif
+
if BUILD_PLUGIN_RRDTOOL
pkglib_LTLIBRARIES += rrdtool.la
-rrdtool_la_SOURCES = rrdtool.c
+rrdtool_la_SOURCES = rrdtool.c utils_rrdcreate.c utils_rrdcreate.h
rrdtool_la_LDFLAGS = -module -avoid-version
rrdtool_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBRRD_CFLAGS)
rrdtool_la_LIBADD = $(BUILD_WITH_LIBRRD_LDFLAGS)
collectd_DEPENDENCIES += tape.la
endif
+if BUILD_PLUGIN_TARGET_SET
+pkglib_LTLIBRARIES += target_set.la
+target_set_la_SOURCES = target_set.c
+target_set_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" target_set.la
+collectd_DEPENDENCIES += target_set.la
+endif
+
if BUILD_PLUGIN_TCPCONNS
pkglib_LTLIBRARIES += tcpconns.la
tcpconns_la_SOURCES = tcpconns.c
else \
$(INSTALL) -m 0640 collectd.conf $(DESTDIR)$(sysconfdir)/collectd.conf; \
fi; \
- cp -f $(srcdir)/types.db $(DESTDIR)$(pkglibdir)/;
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
+ $(INSTALL) -m 0644 $(srcdir)/types.db $(DESTDIR)$(pkgdatadir)/types.db;
$(INSTALL) -m 0644 $(srcdir)/postgresql_default.conf \
$(DESTDIR)$(pkgdatadir)/postgresql_default.conf;
+/**
+ * collectd-nagios - src/collectd-nagios.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 verplant.org>
+ **/
+
+/* Set to C99 and POSIX code */
+#ifndef _ISOC99_SOURCE
+# define _ISOC99_SOURCE
+#endif
+#ifndef _POSIX_SOURCE
+# define _POSIX_SOURCE
+#endif
+#ifndef _POSIX_C_SOURCE
+# define _POSIX_C_SOURCE 200112L
+#endif
+#ifndef _REENTRANT
+# define _REENTRANT
+#endif
+
+/* Disable non-standard extensions */
+#ifdef _BSD_SOURCE
+# undef _BSD_SOURCE
+#endif
+#ifdef _SVID_SOURCE
+# undef _SVID_SOURCE
+#endif
+#ifdef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+
+#if !defined(__GNUC__) || !__GNUC__
+# define __attribute__(x) /**/
+#endif
+
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
+#include <strings.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include "libcollectdclient/client.h"
+
/*
* This is copied directly from collectd.h. Make changes there!
*/
static char **match_ds_g = NULL;
static int match_ds_num_g = 0;
+/* `strdup' is an XSI extension. I don't want to pull in all of XSI just for
+ * that, so here's an own implementation.. It's easy enough. The GCC attributes
+ * are supposed to get good performance.. -octo */
+__attribute__((malloc, nonnull (1)))
+static char *cn_strdup (const char *str) /* {{{ */
+{
+ size_t strsize;
+ char *ret;
+
+ strsize = strlen (str) + 1;
+ ret = (char *) malloc (strsize);
+ if (ret != NULL)
+ memcpy (ret, str, strsize);
+ return (ret);
+} /* }}} char *cn_strdup */
+
static int ignore_ds (const char *name)
{
int i;
range->max = atof (max_ptr);
} /* void parse_range */
-int match_range (range_t *range, double value)
+static int match_range (range_t *range, double value)
{
int ret = 0;
ret = 1;
return (((ret - range->invert) == 0) ? 0 : 1);
-}
-
-static int get_values (int *ret_values_num, double **ret_values,
- char ***ret_values_names)
-{
- struct sockaddr_un sa;
- int status;
- int fd;
- FILE *fh_in, *fh_out;
- char buffer[4096];
-
- int values_num;
- double *values;
- char **values_names;
-
- int i;
- int j;
-
- fd = socket (PF_UNIX, SOCK_STREAM, 0);
- if (fd < 0)
- {
- fprintf (stderr, "socket failed: %s\n",
- strerror (errno));
- return (-1);
- }
-
- memset (&sa, '\0', sizeof (sa));
- sa.sun_family = AF_UNIX;
- strncpy (sa.sun_path, socket_file_g,
- sizeof (sa.sun_path) - 1);
-
- status = connect (fd, (struct sockaddr *) &sa, sizeof (sa));
- if (status != 0)
- {
- fprintf (stderr, "connect failed: %s\n",
- strerror (errno));
- return (-1);
- }
-
- fh_in = fdopen (fd, "r");
- if (fh_in == NULL)
- {
- fprintf (stderr, "fdopen failed: %s\n",
- strerror (errno));
- close (fd);
- return (-1);
- }
-
- fh_out = fdopen (fd, "w");
- if (fh_out == NULL)
- {
- fprintf (stderr, "fdopen failed: %s\n",
- strerror (errno));
- fclose (fh_in);
- return (-1);
- }
-
- fprintf (fh_out, "GETVAL %s/%s\n", hostname_g, value_string_g);
- fflush (fh_out);
-
- if (fgets (buffer, sizeof (buffer), fh_in) == NULL)
- {
- fprintf (stderr, "fgets failed: %s\n",
- strerror (errno));
- fclose (fh_in);
- fclose (fh_out);
- return (-1);
- }
-
- {
- char *ptr = strchr (buffer, ' ');
-
- if (ptr != NULL)
- *ptr = '\0';
-
- values_num = atoi (buffer);
- if (values_num < 1)
- return (-1);
- }
-
- values = (double *) malloc (values_num * sizeof (double));
- if (values == NULL)
- {
- fprintf (stderr, "malloc failed: %s\n",
- strerror (errno));
- return (-1);
- }
-
- values_names = (char **) malloc (values_num * sizeof (char *));
- if (values_names == NULL)
- {
- fprintf (stderr, "malloc failed: %s\n",
- strerror (errno));
- free (values);
- return (-1);
- }
- memset (values_names, 0, values_num * sizeof (char *));
-
- i = 0; /* index of the values returned by the server */
- j = 0; /* number of values in `values_names' and `values' */
- while (fgets (buffer, sizeof (buffer), fh_in) != NULL)
- {
- do /* while (0) */
- {
- char *key;
- char *value;
- char *endptr;
-
- key = buffer;
-
- value = strchr (key, '=');
- if (value == NULL)
- {
- fprintf (stderr, "Cannot parse line: %s\n", buffer);
- break;
- }
- *value = 0;
- value++;
-
- if (ignore_ds (key) != 0)
- break;
-
- endptr = NULL;
- errno = 0;
- values[j] = strtod (value, &endptr);
- if ((endptr == value) || (errno != 0))
- {
- fprintf (stderr, "Could not parse buffer "
- "as number: %s\n", value);
- break;
- }
-
- values_names[j] = strdup (key);
- if (values_names[j] == NULL)
- {
- fprintf (stderr, "strdup failed.\n");
- break;
- }
- j++;
- } while (0);
-
- i++;
- if (i >= values_num)
- break;
- }
- /* Set `values_num' to the number of values actually stored in the
- * array. */
- values_num = j;
-
- fclose (fh_in); fh_in = NULL; fd = -1;
- fclose (fh_out); fh_out = NULL;
-
- *ret_values_num = values_num;
- *ret_values = values;
- *ret_values_names = values_names;
-
- return (0);
-} /* int get_values */
+} /* int match_range */
static void usage (const char *name)
{
exit (1);
} /* void usage */
-int do_check_con_none (int values_num, double *values, char **values_names)
+static int do_check_con_none (int values_num,
+ double *values, char **values_names)
{
- int i;
-
int num_critical = 0;
int num_warning = 0;
int num_okay = 0;
+ const char *status_str = "UNKNOWN";
+ int status_code = RET_UNKNOWN;
+ int i;
for (i = 0; i < values_num; i++)
{
+ if (ignore_ds (values_names[i]))
+ continue;
+
if (isnan (values[i]))
num_warning++;
else if (match_range (&range_critical_g, values[i]) != 0)
num_okay++;
}
- printf ("%i critical, %i warning, %i okay",
+ if ((num_critical == 0) && (num_warning == 0) && (num_okay == 0))
+ {
+ printf ("WARNING: No defined values found\n");
+ return (RET_WARNING);
+ }
+ else if ((num_critical == 0) && (num_warning == 0))
+ {
+ status_str = "OKAY";
+ status_code = RET_OKAY;
+ }
+ else if (num_critical == 0)
+ {
+ status_str = "WARNING";
+ status_code = RET_WARNING;
+ }
+ else
+ {
+ status_str = "CRITICAL";
+ status_code = RET_CRITICAL;
+ }
+
+ printf ("%s: %i critical, %i warning, %i okay", status_str,
num_critical, num_warning, num_okay);
if (values_num > 0)
{
printf (" |");
for (i = 0; i < values_num; i++)
- printf (" %s=%lf;;;;", values_names[i], values[i]);
+ printf (" %s=%g;;;;", values_names[i], values[i]);
}
printf ("\n");
- if ((num_critical != 0) || (values_num == 0))
- return (RET_CRITICAL);
- else if (num_warning != 0)
- return (RET_WARNING);
-
- return (RET_OKAY);
+ return (status_code);
} /* int do_check_con_none */
-int do_check_con_average (int values_num, double *values, char **values_names)
+static int do_check_con_average (int values_num,
+ double *values, char **values_names)
{
int i;
double total;
int total_num;
double average;
+ const char *status_str = "UNKNOWN";
+ int status_code = RET_UNKNOWN;
total = 0.0;
total_num = 0;
for (i = 0; i < values_num; i++)
{
+ if (ignore_ds (values_names[i]))
+ continue;
+
if (!isnan (values[i]))
{
total += values[i];
}
if (total_num == 0)
- average = NAN;
- else
- average = total / total_num;
- printf ("%lf average |", average);
- for (i = 0; i < values_num; i++)
- printf (" %s=%lf;;;;", values_names[i], values[i]);
-
- if (total_num == 0)
+ {
+ printf ("WARNING: No defined values found\n");
return (RET_WARNING);
+ }
- if (isnan (average)
- || match_range (&range_critical_g, average))
- return (RET_CRITICAL);
+ average = total / total_num;
+
+ if (match_range (&range_critical_g, average) != 0)
+ {
+ status_str = "CRITICAL";
+ status_code = RET_CRITICAL;
+ }
else if (match_range (&range_warning_g, average) != 0)
- return (RET_WARNING);
+ {
+ status_str = "WARNING";
+ status_code = RET_WARNING;
+ }
+ else
+ {
+ status_str = "OKAY";
+ status_code = RET_OKAY;
+ }
+
+ printf ("%s: %g average |", status_str, average);
+ for (i = 0; i < values_num; i++)
+ printf (" %s=%g;;;;", values_names[i], values[i]);
+ printf ("\n");
- return (RET_OKAY);
+ return (status_code);
} /* int do_check_con_average */
-int do_check_con_sum (int values_num, double *values, char **values_names)
+static int do_check_con_sum (int values_num, double *values, char **values_names)
{
int i;
double total;
int total_num;
+ const char *status_str = "UNKNOWN";
+ int status_code = RET_UNKNOWN;
total = 0.0;
total_num = 0;
for (i = 0; i < values_num; i++)
{
+ if (ignore_ds (values_names[i]))
+ continue;
+
if (!isnan (values[i]))
{
total += values[i];
if (match_range (&range_critical_g, total) != 0)
{
- printf ("CRITICAL: Sum = %lf\n", total);
- return (RET_CRITICAL);
+ status_str = "CRITICAL";
+ status_code = RET_CRITICAL;
}
else if (match_range (&range_warning_g, total) != 0)
{
- printf ("WARNING: Sum = %lf\n", total);
- return (RET_WARNING);
+ status_str = "WARNING";
+ status_code = RET_WARNING;
}
else
{
- printf ("OKAY: Sum = %lf\n", total);
- return (RET_OKAY);
+ status_str = "OKAY";
+ status_code = RET_OKAY;
}
- return (RET_UNKNOWN);
+ printf ("%s: %g sum |", status_str, total);
+ for (i = 0; i < values_num; i++)
+ printf (" %s=%g;;;;", values_names[i], values[i]);
+ printf ("\n");
+
+ return (status_code);
} /* int do_check_con_sum */
-int do_check (void)
+static int do_check (void)
{
- double *values;
+ lcc_connection_t *connection;
+ gauge_t *values;
char **values_names;
- int values_num;
+ size_t values_num;
+ char address[1024];
+ char ident_str[1024];
+ lcc_identifier_t ident;
+ size_t i;
+ int status;
- if (get_values (&values_num, &values, &values_names) != 0)
+ snprintf (address, sizeof (address), "unix:%s", socket_file_g);
+ address[sizeof (address) - 1] = 0;
+
+ snprintf (ident_str, sizeof (ident_str), "%s/%s",
+ hostname_g, value_string_g);
+ ident_str[sizeof (ident_str) - 1] = 0;
+
+ connection = NULL;
+ status = lcc_connect (address, &connection);
+ if (status != 0)
+ {
+ printf ("ERROR: Connecting to daemon at %s failed.\n",
+ socket_file_g);
+ return (RET_CRITICAL);
+ }
+
+ memset (&ident, 0, sizeof (ident));
+ status = lcc_string_to_identifier (connection, &ident, ident_str);
+ if (status != 0)
{
- fputs ("ERROR: Cannot get values from daemon\n", stdout);
+ printf ("ERROR: Creating an identifier failed: %s.\n",
+ lcc_strerror (connection));
+ LCC_DESTROY (connection);
return (RET_CRITICAL);
}
+ status = lcc_getval (connection, &ident,
+ &values_num, &values, &values_names);
+ if (status != 0)
+ {
+ printf ("ERROR: Retrieving values from the daemon failed: %s.\n",
+ lcc_strerror (connection));
+ LCC_DESTROY (connection);
+ return (RET_CRITICAL);
+ }
+
+ LCC_DESTROY (connection);
+
+ status = RET_UNKNOWN;
if (consolitation_g == CON_NONE)
- return (do_check_con_none (values_num, values, values_names));
+ status = do_check_con_none (values_num, values, values_names);
else if (consolitation_g == CON_AVERAGE)
- return (do_check_con_average (values_num, values, values_names));
+ status = do_check_con_average (values_num, values, values_names);
else if (consolitation_g == CON_SUM)
- return (do_check_con_sum (values_num, values, values_names));
+ status = do_check_con_sum (values_num, values, values_names);
free (values);
- free (values_names); /* FIXME? */
+ if (values_names != NULL)
+ for (i = 0; i < values_num; i++)
+ free (values_names[i]);
+ free (values_names);
- return (RET_UNKNOWN);
-}
+ return (status);
+} /* int do_check */
int main (int argc, char **argv)
{
return (RET_UNKNOWN);
}
match_ds_g = tmp;
- match_ds_g[match_ds_num_g] = strdup (optarg);
+ match_ds_g[match_ds_num_g] = cn_strdup (optarg);
if (match_ds_g[match_ds_num_g] == NULL)
{
- fprintf (stderr, "strdup failed: %s\n",
+ fprintf (stderr, "cn_strdup failed: %s\n",
strerror (errno));
return (RET_UNKNOWN);
}
#BaseDir "@prefix@/var/lib/@PACKAGE_NAME@"
#PIDFile "@prefix@/var/run/@PACKAGE_NAME@.pid"
#PluginDir "@prefix@/lib/@PACKAGE_NAME@"
-#TypesDB "@prefix@/lib/@PACKAGE_NAME@/types.db"
+#TypesDB "@prefix@/share/@PACKAGE_NAME@/types.db"
#Interval 10
#ReadThreads 5
@BUILD_PLUGIN_CPU_TRUE@LoadPlugin cpu
@BUILD_PLUGIN_CPUFREQ_TRUE@LoadPlugin cpufreq
@BUILD_PLUGIN_CSV_TRUE@LoadPlugin csv
+@BUILD_PLUGIN_DBI_TRUE@LoadPlugin dbi
@BUILD_PLUGIN_DF_TRUE@LoadPlugin df
@BUILD_PLUGIN_DISK_TRUE@LoadPlugin disk
@BUILD_PLUGIN_DNS_TRUE@LoadPlugin dns
@BUILD_PLUGIN_POSTGRESQL_TRUE@LoadPlugin postgresql
@BUILD_PLUGIN_POWERDNS_TRUE@LoadPlugin powerdns
@BUILD_PLUGIN_PROCESSES_TRUE@LoadPlugin processes
+@BUILD_PLUGIN_RRDCACHED_TRUE@LoadPlugin rrdcached
@BUILD_PLUGIN_RRDTOOL_TRUE@LoadPlugin rrdtool
@BUILD_PLUGIN_SENSORS_TRUE@LoadPlugin sensors
@BUILD_PLUGIN_SERIAL_TRUE@LoadPlugin serial
@BUILD_PLUGIN_THERMAL_TRUE@LoadPlugin thermal
@BUILD_PLUGIN_UNIXSOCK_TRUE@LoadPlugin unixsock
@BUILD_PLUGIN_USERS_TRUE@LoadPlugin users
-@BUILD_PLUGIN_UUID_TRUE@LoadPlugin uuid
+#LoadPlugin uuid
@BUILD_PLUGIN_VMEM_TRUE@LoadPlugin vmem
@BUILD_PLUGIN_VSERVER_TRUE@LoadPlugin vserver
@BUILD_PLUGIN_WIRELESS_TRUE@LoadPlugin wireless
# StoreRates false
#</Plugin>
+#<Plugin dbi>
+# <Query "num_of_customers">
+# Statement "SELECT 'customers' AS c_key, COUNT(*) AS c_value FROM customers_tbl"
+# Type "gauge"
+# InstancesFrom "c_key"
+# ValuesFrom "c_value"
+# </Query>
+# <Database "customers_db">
+# Driver "mysql"
+# DriverOption "host" "localhost"
+# DriverOption "username" "collectd"
+# DriverOption "password" "AeXohy0O"
+# DriverOption "dbname" "custdb0"
+# #SelectDB "custdb0"
+# Query "num_of_customers"
+# #Query "..."
+# </Database>
+#</Plugin>
+
#<Plugin df>
# Device "/dev/hda1"
# Device "192.168.0.2:/mnt/nfs"
# Name "*.conf"
# MTime "-5m"
# Size "+10k"
+# Recursive true
# </Directory>
#</Plugin>
# Process "name"
#</Plugin>
+#<Plugin rrdcached>
+# DaemonAddress "unix:/tmp/rrdcached.sock"
+# DataDir "@prefix@/var/lib/@PACKAGE_NAME@/rrd"
+# CreateFiles true
+# CollectStatistics true
+#</Plugin>
+
#<Plugin rrdtool>
# DataDir "@prefix@/var/lib/@PACKAGE_NAME@/rrd"
# CacheTimeout 120
# Verbose false
#</Plugin>
+# * * * * * * * * * * * * *
+# * FILTER CONFIGURATION *
+# * * * * * * * * * * * * *
+
+# The following configures collectd's filtering mechanism. Before changing
+# anything in this section, please read the `FILTER CONFIGURATION' section in
+# the collectd.conf(5) manual page.
+
+# Load required matches:
+#@BUILD_PLUGIN_MATCH_REGEX_TRUE@LoadPlugin match_regex
+
+# Load required targets:
+
+# The following block demonstrates the default behavior if no filtering is
+# configured at all: All values will be sent to all available write plugins.
+
+#<Chain "Main">
+# Target "write"
+#</Chain>
=back
+=head2 Plugin C<dbi>
+
+This plugin uses the "B<dbi>" library (L<http://libdbi.sourceforge.net/>) to
+connect to various databases, execute SQL statements and read back the results.
+You can configure how each column is to be interpreted and the plugin will
+generate one data set from each row returned according to these rules.
+
+Because the plugin is very generic, the configuration is a little more complex
+than those of other plugins. It usually looks something like this:
+
+ <Plugin dbi>
+ <Query "out_of_stock">
+ Statement "SELECT category, COUNT(*) AS value FROM products WHERE in_stock = 0 GROUP BY category"
+ Type "gauge"
+ InstancesFrom "category"
+ ValuesFrom "value"
+ </Query>
+ <Database "product_information">
+ Driver "mysql"
+ DriverOption "host" "localhost"
+ DriverOption "username" "collectd"
+ DriverOption "password" "aZo6daiw"
+ DriverOption "dbname" "prod_info"
+ SelectDB "prod_info"
+ Query "out_of_stock"
+ </Database>
+ </Plugin>
+
+The configuration above defines one query and one database. The query is then
+linked to the database with the B<Query> option I<within> the
+B<E<lt>DatabaseE<gt>> block. You can have any number of queries and databases
+and you can also use the B<Include> statement to split up the configuration
+file in multiple, smaller files. However, the B<E<lt>QueryE<gt>> block I<must>
+precede the B<E<lt>DatabaseE<gt>> blocks, because the file is interpreted from
+top to bottom!
+
+The following is a complete list of options:
+
+=head3 B<Query> blocks
+
+Query blocks define SQL statements and how the returned data should be
+interpreted. They are identified by the name that is given in the opening line
+of the block. Thus the name needs to be unique. Other than that, the name is
+not used in collectd.
+
+=over 4
+
+=item B<Statement> I<SQL>
+
+Sets the statement that should be executed on the server. This is B<not>
+interpreted by collectd, but simply passed to the database server. Therefore,
+the SQL dialect that's used depends on the server collectd is connected to.
+
+The query has to return at least two columns, one for the instance and one
+value. You cannot omit the instance, even if the statement is guaranteed to
+always return exactly one line. In that case, you can usually specify something
+like this:
+
+ Statement "SELECT \"instance\", COUNT(*) AS value FROM table"
+
+(That works with MySQL but may not be valid SQL according to the spec. If you
+use a more strict database server, you may have to select from a dummy table or
+something.)
+
+=item B<Type> I<Type>
+
+The B<type> that's used for each line returned. See L<types.db(5)> for more
+details on how types are defined. In short: A type is a predefined layout of
+data and the number of values and type of values has to match the type
+definition.
+
+If you specify "temperature" here, you need exactly one gauge column. If you
+specify "if_octets", you will need two counter columns. See the B<ValuesFrom>
+setting below.
+
+=item B<InstancesFrom> I<column0> [I<column1> ...]
+
+Specifies the columns whose values will be used to create the "TypeInstance"
+for each row. You need to specify at least one column for each query. If you
+specify more than one column, the value of all columns will be join together
+with the hyphen as separation character.
+
+The plugin itself does not check whether or not all built instances are
+different. It's your responsibility to assure that each is unique.
+
+=item B<ValuesFrom> I<column0> [I<column1> ...]
+
+Names the columns whose content is used as the actual data for the data sets
+that are dispatched to the daemon. How many such columns you need is determined
+by the B<Type> setting above. If you specify too many or not enough columns,
+the plugin will complain about that and no data will be submitted to the
+daemon.
+
+The actual data type in the columns is not that important. The plugin will
+automatically cast the values to the right type if it know how to do that. So
+it should be able to handle integer an floating point types, as well as strings
+(if they include a number at the beginning).
+
+=back
+
+=head3 B<Database> blocks
+
+Database blocks define a connection to a database and which queries should be
+sent to that database. Since the used "dbi" library can handle a wide variety
+of databases, the configuration is very generic. If in doubt, refer to libdbi's
+documentationE<nbsp>- we stick as close to the terminology used there.
+
+Each database needs a "name" as string argument in the starting tag of the
+block. This name will be used as "PluginInstance" in the values submitted to
+the daemon. Other than that, that name is not used.
+
+=over 4
+
+=item B<Driver> I<Driver>
+
+Specifies the driver to use to connect to the database. In many cases those
+drivers are named after the database they can connect to, but this is not a
+technical necessity. These drivers are sometimes referred to as "DBD",
+B<D>ataB<B>ase B<D>river, and some distributions ship them in separate
+packages. Drivers for the "dbi" library are developed by the B<libdbi-drivers>
+project at L<http://libdbi-drivers.sourceforge.net/>.
+
+You need to give the driver name as expected by the "dbi" library here. You
+should be able to find that in the documentation for each driver. If you
+mistype the driver name, the plugin will dump a list of all known driver names
+to the log.
+
+=item B<DriverOption> I<Key> I<Value>
+
+Sets driver-specific options. What option a driver supports can be found in the
+documentation for each driver, somewhere at
+L<http://libdbi-drivers.sourceforge.net/>. However, the options "host",
+"username", "password", and "dbname" seem to be deE<nbsp>facto standards.
+
+Unfortunately, drivers are not too keen to report errors when an unknown option
+is passed to them, so invalid settings here may go unnoticed. This is not the
+plugin's fault, it will report errors if it gets them from the libraryE<nbsp>/
+the driver. If a driver complains about an option, the plugin will dump a
+complete list of all options understood by that driver to the log.
+
+=item B<SelectDB> I<Database>
+
+In some cases, the database name you connect with is not the database name you
+want to use for querying data. If this option is set, the plugin will "select"
+(switch to) that database after the connection is established.
+
+=item B<Query> I<QueryName>
+
+Associates the query named I<QueryName> with this database connection. The
+query needs to be defined I<before> this statement, i.E<nbsp>e. all query
+blocks you want to refer to must be placed above the database block you want to
+refer to them from.
+
+=back
+
=head2 Plugin C<df>
=over 4
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.
+=item B<Recursive> I<true>|I<false>
+
+Controls whether or not to recurse into subdirectories. Enabled by default.
+
+=back
+
+=head2 Plugin C<filter_pcre>
+
+This plugin allows you to filter and rewrite value lists based on
+Perl-compatible regular expressions whose syntax and semantics are as close as
+possible to those of the Perl 5 language. See L<pcre(3)> for details.
+
+ <Plugin filter_pcre>
+ <RegEx>
+ Host "^mail\d+$"
+ Plugin "^tcpconns$"
+ TypeInstance "^SYN_"
+
+ Action NoWrite
+ </RegEx>
+
+ <RegEx>
+ Plugin "^sensors$"
+ PluginInstance "^Some Weird Sensor Chip Name Prefix"
+
+ SubstitutePluginInstance "foo"
+ </RegEx>
+ </Plugin>
+
+The configuration consists of one or more C<RegEx> blocks, each of which
+specifies a regular expression identifying a set of value lists and how to
+handle successful matches. A value list keeps the values of a single data-set
+and is identified by the tuple (host, plugin, plugin instance, type, type
+instance). The plugin and type instances are optional components. If they are
+missing they are treated as empty strings. Within those blocks, the following
+options are recognized:
+
+=over 4
+
+=item B<Host> I<regex>
+
+=item B<Plugin> I<regex>
+
+=item B<PluginInstance> I<regex>
+
+=item B<Type> I<regex>
+
+=item B<TypeInstance> I<regex>
+
+Specifies the regular expression for each component of the identifier. If any
+of these options is missing it is interpreted as a pattern which matches any
+string. All five components of a value list have to match the appropriate
+regular expression to trigger the specified action.
+
+=item B<Action> I<NoWrite>|I<NoThresholdCheck>|I<Ignore>
+
+Specify how to handle successful matches:
+
+=over 4
+
+=item B<NoWrite>
+
+Do not send the value list to any output (a.k.a. write) plugins.
+
+=item B<NoThresholdCheck>
+
+Skip threshold checking for this value list.
+
+=item B<Ignore>
+
+Completely ignore this value list.
+
+=back
+
+Two or more actions may be combined by specifying multiple B<Action> options.
+
+=item B<SubstituteHost> I<replacement>
+
+=item B<SubstitutePlugin> I<replacement>
+
+=item B<SubstitutePluginInstance> I<replacement>
+
+=item B<SubstituteType> I<replacement>
+
+=item B<SubstituteTypeInstance> I<replacement>
+
+Upon a successful match, the matching substring will be replaced by the
+specified I<replacement> text. These options require that an appropriate regex
+has been specified before, e.E<nbsp>g. B<SubstituteHost> requires that the
+B<Host> option has been specified before.
+
+B<Note>: It is not recommended to modify the type unless you really know what
+you are doing. The type is used to identify the data-set definition of the
+dispatched values.
+
=back
=head2 Plugin C<hddtemp>
Select this database. Defaults to I<no database> which is a perfectly reasonable
option for what this plugin does.
+=item B<Port> I<Port>
+
+TCP-port to connect to. The port must be specified in its numeric form, but it
+must be passed as a string nonetheless. For example:
+
+ Port "3306"
+
+If B<Host> is set to B<localhost> (the default), this setting has no effect.
+See the documentation for the C<mysql_real_connect> function for details.
+
+=item B<Socket> I<Socket>
+
+Specifies the path to the UNIX domain socket of the MySQL server. This option
+only has any effect, if B<Host> is set to B<localhost> (the default).
+Otherwise, use the B<Port> option above. See the documentation for the
+C<mysql_real_connect> function for details.
+
=back
=head2 Plugin C<netlink>
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<oracle>
+
+The "oracle" plugin uses the Oracle® Call Interface (OCI) to connect to an
+Oracle® Database and lets you execute SQL statements there. It is very similar
+to the "dbi" plugin, because it was written around the same time. See the "dbi"
+plugin's documentation above for details.
+
+ <Plugin oracle>
+ <Query "out_of_stock">
+ Statement "SELECT category, COUNT(*) AS value FROM products WHERE in_stock = 0 GROUP BY category"
+ Type "gauge"
+ InstancesFrom "category"
+ ValuesFrom "value"
+ </Query>
+ <Database "product_information">
+ ConnectID "db01"
+ Username "oracle"
+ Password "secret"
+ Query "out_of_stock"
+ </Database>
+ </Plugin>
+
+=head3 B<Query> blocks
+
+The Query blocks are handled identically to the Query blocks of the "dbi"
+plugin. Please see its documentation above for details on how to specify
+queries.
+
+=head3 B<Database> blocks
+
+Database blocks define a connection to a database and which queries should be
+sent to that database. Each database needs a "name" as string argument in the
+starting tag of the block. This name will be used as "PluginInstance" in the
+values submitted to the daemon. Other than that, that name is not used.
+
+=over 4
+
+=item B<ConnectID> I<ID>
+
+Defines the "database alias" or "service name" to connect to. Usually, these
+names are defined in the file named C<$ORACLE_HOME/network/admin/tnsnames.ora>.
+
+=item B<Username> I<Username>
+
+Username used for authentication.
+
+=item B<Password> I<Password>
+
+Password used for authentication.
+
+=item B<Query> I<QueryName>
+
+Associates the query named I<QueryName> with this database connection. The
+query needs to be defined I<before> this statement, i.E<nbsp>e. all query
+blocks you want to refer to must be placed above the database block you want to
+refer to them from.
+
+=back
+
=head2 Plugin C<perl>
This plugin embeds a Perl-interpreter into collectd and provides an interface
=back
+=head2 Plugin C<rrdcached>
+
+The C<rrdcached> plugin uses the RRDTool accelerator daemon, L<rrdcached(1)>,
+to store values to RRD files in an efficient manner. The combination of the
+C<rrdcached> B<plugin> and the C<rrdcached> B<daemon> is very similar to the
+way the C<rrdtool> plugin works (see below). The added abstraction layer
+provides a number of benefits, though: Because the cache is not within
+C<collectd> anymore, it does not need to be flushed when C<collectd> is to be
+restarted. This results in much shorter (if any) gaps in graphs, especially
+under heavy load. Also, the C<rrdtool> command line utility is aware of the
+daemon so that it can flush values to disk automatically when needed. This
+allows to integrate automated flushing of values into graphing solutions much
+more easily.
+
+There are disadvantages, though: The daemon may reside on a different host, so
+it may not be possible for C<collectd> to create the appropriate RRD files
+anymore. And even if C<rrdcached> runs on the same host, it may run in a
+different base directory, so relative paths may do weird stuff if you're not
+careful.
+
+So the B<recommended configuration> is to let C<collectd> and C<rrdcached> run
+on the same host, communicating via a UNIX domain socket. The B<DataDir>
+setting should be set to an absolute path, so that a changed base directory
+does not result in RRD files being createdE<nbsp>/ expected in the wrong place.
+
+=over 4
+
+=item B<DaemonAddress> I<Address>
+
+Address of the daemon as understood by the C<rrdc_connect> function of the RRD
+library. See L<rrdcached(1)> for details. Example:
+
+ <Plugin "rrdcached">
+ DaemonAddress "unix:/var/run/rrdcached.sock"
+ </Plugin>
+
+=item B<DataDir> I<Directory>
+
+Set the base directory in which the RRD files reside. If this is a relative
+path, it is relative to the working base directory of the C<rrdcached> daemon!
+Use of an absolute path is recommended.
+
+=item B<CreateFiles> B<true>|B<false>
+
+Enables or disables the creation of RRD files. If the daemon is not running
+locally, or B<DataDir> is set to a relative path, this will not work as
+expected. Default is B<true>.
+
+=back
+
=head2 Plugin C<rrdtool>
You can use the settings B<StepSize>, B<HeartBeat>, B<RRARows>, and B<XFF> to
=back
+=head1 FILTER CONFIGURATION
+
+TODO: Update this entire section once development is done.
+
+Starting with collectd 4.6 there is a powerful filtering infrastructure
+implemented in the daemon. The concept has mostly been copied from I<iptables>,
+the packet filter infrastructure for Linux. We'll use a similar terminology, so
+that users that are familiar with iptables feel right at home.
+
+=head2 Terminology
+
+The most important terms are:
+
+=over 4
+
+=item B<Match>
+
+A I<match> is a criteria to select specific values. Examples are, of course, the
+name of the value or it's current value.
+
+=item B<Target>
+
+A I<target> is some action that is to be performed with data. Such actions
+could, for example, be to change part of the value's identifier or to ignore
+the value completely. Built-in functions are B<write> and B<stop>, see below.
+
+Some targets, for example the built-in B<stop> target, signal that processing
+of a value should be stopped. In that case processing of the current chain will
+be aborted.
+
+=item B<Rule>
+
+The combination of any number of matches and at least one target is called a
+I<rule>. The target actions will be performed for all values for which B<all>
+matches apply. If the rule does not have any matches associated with it, the
+target action will be performed for all values.
+
+If any target returns the stop condition, the processing will stop right away.
+This means that any targets following the current one will not be called after
+the stop condition has been returned.
+
+=item B<Chain>
+
+A I<chain> is a list of rules and possibly default targets. The rules are tried
+in order and if one matches, the associated target will be called. If a value
+is handled by a rule, it depends on the target whether or not any subsequent
+rules are considered or if traversal of the chain is aborted. After all rules
+have been checked and no target returned the stop condition, the default
+targets will be executed.
+
+=back
+
+=head2 General structure
+
+The following shows the resulting structure:
+
+ +---------+
+ ! Chain !
+ +---------+
+ !
+ V
+ +---------+ +---------+ +---------+ +---------+
+ ! Rule !->! Match !->! Match !->! Target !
+ +---------+ +---------+ +---------+ +---------+
+ !
+ V
+ +---------+ +---------+ +---------+
+ ! Rule !->! Target !->! Target !
+ +---------+ +---------+ +---------+
+ !
+ V
+ :
+ :
+ !
+ V
+ +---------+ +---------+ +---------+
+ ! Rule !->! Match !->! Target !
+ +---------+ +---------+ +---------+
+ !
+ V
+ +---------+
+ ! Default !
+ ! Target !
+ +---------+
+
+=head2 Synopsis
+
+The configuration reflects this structure directly:
+
+ <Chain "main">
+ <Rule "ignore_mysql_show">
+ <Match "regex">
+ Plugin "^mysql$"
+ Type "^mysql_command$"
+ TypeInstance "^show_"
+ </Match>
+ <Target "stop">
+ </Target>
+ </Rule>
+ <Target "write">
+ Plugin "rrdtool"
+ </Target>
+ </Chain>
+
+The above configuration example will ignore all values where the plugin field
+is "mysql", the type is "mysql_command" and the type instance begins with
+"show_". All other values will be sent to the "rrdtool" write plugin via the
+default target of the chain.
+
+=head2 List of configuration options
+
+=over 4
+
+=item B<Chain> I<Name>
+
+Adds a new chain with a certain name. This name can be used to refer to a
+specific chain, for example to jump to it.
+
+Within the B<Chain> block, there can be B<Rule> blocks and B<Target> blocks.
+
+=item B<Rule> [I<Name>]
+
+Adds a new rule to the current chain. The name of the rule is optional and
+currently has no meaning for the daemon.
+
+Within the B<Rule> block, there may be any number of B<Match> blocks and there
+must be at least one B<Target> block.
+
+=item B<Match> I<Name>
+
+Adds a match to a B<Rule> block. The name specifies what kind of match should
+be performed. Available matches depend on the plugins that have been loaded.
+
+The arguments inside the B<Match> block are passed to the plugin implementing
+the match, so which arguments are valid here depends on the plugin being used.
+If you do not need any to pass any arguments to a match, you can use the
+shorter syntax:
+
+ Match "foobar"
+
+Which is equivalent to:
+
+ <Match "foobar">
+ </Match>
+
+=item B<Target> I<Name>
+
+Add a target to a rule or a default target to a chain. The name specifies what
+kind of target is to be added. Which targets are available depends on the
+plugins being loaded.
+
+The arguments inside the B<Target> block are passed to the plugin implementing
+the target, so which arguments are valid here depends on the plugin being used.
+If you do not need any to pass any arguments to a target, you can use the
+shorter syntax:
+
+ Target "stop"
+
+This is the same as writing:
+
+ <Target "stop">
+ </Target>
+
+=back
+
+=head2 Built-in targets
+
+The following targets are built into the core daemon and therefore need no
+plugins to be loaded:
+
+=over 4
+
+=item B<return>
+
+Signals the "return" condition. This causes the current chain to stop
+processing the value and returns control to the calling chain. The calling
+chain will continue processing targets and rules just after the B<jump> target
+(see below). This is very similar to the B<RETURN> target of iptables, see
+L<iptables(8)>.
+
+This target does not have any options.
+
+Example:
+
+ Target "return"
+
+=item B<stop>
+
+Signals the "stop" condition, causing processing of the value to be aborted
+immediately. This is similar to the B<DROP> target of iptables, see
+L<iptables(8)>.
+
+This target does not have any options.
+
+Example:
+
+ Target "stop"
+
+=item B<write>
+
+Sends the value to write plugins.
+
+Available options:
+
+=over 4
+
+=item B<Plugin> I<Name>
+
+Name of the write plugin to which the data should be sent. This option may be
+given multiple times to send the data to more than one write plugin.
+
+=back
+
+If no plugin is explicitly specified, the values will be sent to all available
+write plugins.
+
+Example:
+
+ <Target "write">
+ Plugin "rrdtool"
+ </Target>
+
+=item B<jump>
+
+Starts processing the rules of another chain. If the end of that chain is
+reached, or a stop condition is encountered, processing will continue right
+after the B<jump> target, i.E<nbsp>e. with the next target or the next rule.
+This is similar to the B<-j> command line option of iptables, see
+L<iptables(8)>.
+
+Available options:
+
+=over 4
+
+=item B<Chain> I<Name>
+
+Jumps to the chain I<Name>. This argument is required and may appear only once.
+
+=back
+
+Example:
+
+ <Target "jump">
+ Chain "foobar"
+ </Target>
+
+=back
+
+=head2 Available matches
+
+=over 4
+
+=item B<regex>
+
+Matches a value using regular expressions.
+
+Available options:
+
+=over 4
+
+=item B<Host> I<Regex>
+
+=item B<Plugin> I<Regex>
+
+=item B<PluginInstance> I<Regex>
+
+=item B<Type> I<Regex>
+
+=item B<TypeInstance> I<Regex>
+
+Match values where the given regular expressions match the various fields of
+the identifier of a value. If multiple regular expressions are given, B<all>
+regexen must match for a value to match.
+
+=back
+
+Example:
+
+ <Match "regex">
+ Host "customer[0-9]+"
+ Plugin "^foobar$"
+ </Match>
+
+=item B<value>
+
+Matches the actual value of data sources against given minimumE<nbsp>/ maximum
+values. If a data-set consists of more than one data-source, all data-sources
+must match the specified ranges for a positive match.
+
+Available options:
+
+=over 4
+
+=item B<Min> I<Value>
+
+Sets the smallest value which still results in a match. If unset, behaves like
+negative infinity.
+
+=item B<Max> I<Value>
+
+Sets the largest value which still results in a match. If unset, behaves like
+positive infinity.
+
+=item B<Invert> B<true>|B<false>
+
+Inverts the selection. If the B<Min> and B<Max> settings result in a match,
+no-match is returned and vice versa.
+
+=back
+
+Either B<Min> or B<Max>, but not both, may be unset.
+
+Example:
+
+ # Match all values smaller than or equal to 100.
+ <Match "value">
+ Max 100
+ </Match>
+
+=back
+
+=head2 Available targets
+
+=over 4
+
+=item B<set>
+
+Sets part of the identifier of a value to a given string.
+
+Available options:
+
+=over 4
+
+=item B<Host> I<String>
+
+=item B<Plugin> I<String>
+
+=item B<PluginInstance> I<String>
+
+=item B<TypeInstance> I<String>
+
+Set the appropriate field to the given string. The strings for plugin instance
+and type instance may be empty, the strings for host and plugin may not be
+empty. It's currently not possible to set the type of a value this way.
+
+=back
+
+Example:
+
+ <Target "set">
+ PluginInstance "coretemp"
+ TypeInstance "core3"
+ </Target>
+
+=back
+
+=head2 Backwards compatibility
+
+If you use collectd with an old configuration, i.E<nbsp>e. one without a
+B<Chain> block, it will behave as it used to. This is equivalent to the
+following configuration:
+
+ <Chain "main">
+ Target "write"
+ </Chain>
+
+If you specify a B<Chain> block anywhere, the B<write> target will not be added
+anywhere and you will have to make sure that it is called where appropriate. We
+suggest to add the above snippet as default target to your main chain.
+
+TODO: Notifications will be implemented using chains, too. Describe that here!
+
+=head2 Examples
+
+Ignore all values, where the hostname does not contain a dot, i.E<nbsp>e. can't
+be an FQDN.
+
+ <Chain "main">
+ <Rule "no_fqdn">
+ <Match "regex">
+ Host "^[^\.]*$"
+ </Match>
+ Target "stop"
+ </Rule>
+ Target "write"
+ </Chain>
+
=head1 SEE ALSO
L<collectd(1)>,
L<collectd-unixsock(5)>,
L<types.db(5)>,
L<hddtemp(8)>,
+L<iptables(8)>,
L<kstat(3KSTAT)>,
L<mbmon(1)>,
+L<pcre(3)>,
L<psql(1)>,
L<rrdtool(1)>,
L<sensors(1)>
#include "configfile.h"
#include "types_list.h"
#include "utils_threshold.h"
+#include "filter_chain.h"
#if HAVE_WORDEXP_H
# include <wordexp.h>
return (dispatch_block_plugin (ci));
else if (strcasecmp (ci->key, "Threshold") == 0)
return (ut_config (ci));
+ else if (strcasecmp (ci->key, "Chain") == 0)
+ return (fc_configure (ci));
return (0);
}
/* Read the default types.db if no `TypesDB' option was given. */
if (cf_default_typesdb)
- read_types_list (PLUGINDIR"/types.db");
+ read_types_list (PKGDATADIR"/types.db");
return (0);
} /* int cf_read */
--- /dev/null
+/**
+ * collectd - src/dbi.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 verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+
+#include <dbi/dbi.h>
+
+/*
+ * Data types
+ */
+struct cdbi_driver_option_s
+{
+ char *key;
+ char *value;
+};
+typedef struct cdbi_driver_option_s cdbi_driver_option_t;
+
+struct cdbi_query_s
+{
+ char *name;
+ char *statement;
+ char *type;
+ char **instances;
+ size_t instances_num;
+ char **values;
+ size_t values_num;
+};
+typedef struct cdbi_query_s cdbi_query_t;
+
+struct cdbi_database_s
+{
+ char *name;
+ char *select_db;
+
+ char *driver;
+ cdbi_driver_option_t *driver_options;
+ size_t driver_options_num;
+
+ cdbi_query_t **queries;
+ size_t queries_num;
+
+ dbi_conn connection;
+};
+typedef struct cdbi_database_s cdbi_database_t;
+
+/*
+ * Global variables
+ */
+static cdbi_query_t **queries = NULL;
+static size_t queries_num = 0;
+static cdbi_database_t **databases = NULL;
+static size_t databases_num = 0;
+
+/*
+ * Functions
+ */
+static const char *cdbi_strerror (dbi_conn conn, /* {{{ */
+ char *buffer, size_t buffer_size)
+{
+ const char *msg;
+ int status;
+
+ if (conn == NULL)
+ {
+ sstrncpy (buffer, "connection is NULL", buffer_size);
+ return (buffer);
+ }
+
+ msg = NULL;
+ status = dbi_conn_error (conn, &msg);
+ if ((status >= 0) && (msg != NULL))
+ ssnprintf (buffer, buffer_size, "%s (status %i)", msg, status);
+ else
+ ssnprintf (buffer, buffer_size, "dbi_conn_error failed with status %i",
+ status);
+
+ return (buffer);
+} /* }}} const char *cdbi_conn_error */
+
+static int cdbi_result_get_field (dbi_result res, /* {{{ */
+ const char *name, int dst_type, value_t *ret_value)
+{
+ value_t value;
+ unsigned int index;
+ unsigned short src_type;
+ dbi_conn connection;
+
+ index = dbi_result_get_field_idx (res, name);
+ if (index < 1)
+ {
+ ERROR ("dbi plugin: cdbi_result_get: No such column: %s.", name);
+ return (-1);
+ }
+
+ src_type = dbi_result_get_field_type_idx (res, index);
+ if (src_type == DBI_TYPE_ERROR)
+ {
+ ERROR ("dbi plugin: cdbi_result_get: "
+ "dbi_result_get_field_type_idx failed.");
+ return (-1);
+ }
+
+ if ((dst_type != DS_TYPE_COUNTER) && (dst_type != DS_TYPE_GAUGE))
+ {
+ ERROR ("dbi plugin: cdbi_result_get: Don't know how to handle "
+ "destination type %i.", dst_type);
+ return (-1);
+ }
+
+ if (src_type == DBI_TYPE_INTEGER)
+ {
+ if (dst_type == DS_TYPE_COUNTER)
+ value.counter = dbi_result_get_ulonglong_idx (res, index);
+ else
+ value.gauge = (gauge_t) dbi_result_get_longlong_idx (res, index);
+ }
+ else if (src_type == DBI_TYPE_DECIMAL)
+ {
+ value.gauge = dbi_result_get_double_idx (res, index);
+ if (dst_type == DS_TYPE_COUNTER)
+ value.counter = (counter_t) round (value.gauge);
+ }
+ else if (src_type == DBI_TYPE_STRING)
+ {
+ const char *string = dbi_result_get_string_idx (res, index);
+ char *endptr = NULL;
+
+ if (string == NULL)
+ value.gauge = NAN;
+ else if (dst_type == DS_TYPE_COUNTER)
+ value.counter = (counter_t) strtoll (string, &endptr, 0);
+ else
+ value.gauge = (gauge_t) strtod (string, &endptr);
+
+ if (string == endptr)
+ {
+ ERROR ("dbi plugin: cdbi_result_get: Can't parse string as number: %s.",
+ string);
+ return (-1);
+ }
+ }
+ else
+ {
+ ERROR ("dbi plugin: cdbi_result_get: Don't know how to handle "
+ "source type %hu.", src_type);
+ return (-1);
+ }
+
+ connection = dbi_result_get_conn (res);
+ if (dbi_conn_error (connection, NULL) != 0)
+ {
+ char errbuf[1024];
+ ERROR ("dbi plugin: cdbi_result_get: dbi_result_get_*_idx failed: %s.",
+ cdbi_strerror (connection, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ *ret_value = value;
+ return (0);
+} /* }}} int cdbi_result_get_field */
+
+static void cdbi_query_free (cdbi_query_t *q) /* {{{ */
+{
+ size_t i;
+
+ if (q == NULL)
+ return;
+
+ sfree (q->name);
+ sfree (q->statement);
+ sfree (q->type);
+
+ for (i = 0; i < q->instances_num; i++)
+ sfree (q->instances[i]);
+ sfree (q->instances);
+
+ for (i = 0; i < q->values_num; i++)
+ sfree (q->values[i]);
+ sfree (q->values);
+
+ sfree (q);
+} /* }}} void cdbi_query_free */
+
+static void cdbi_database_free (cdbi_database_t *db) /* {{{ */
+{
+ size_t i;
+
+ if (db == NULL)
+ return;
+
+ sfree (db->name);
+ sfree (db->driver);
+
+ for (i = 0; i < db->driver_options_num; i++)
+ {
+ sfree (db->driver_options[i].key);
+ sfree (db->driver_options[i].value);
+ }
+ sfree (db->driver_options);
+
+ sfree (db);
+} /* }}} void cdbi_database_free */
+
+static void cdbi_submit (cdbi_database_t *db, cdbi_query_t *q, /* {{{ */
+ char **instances, value_t *values)
+{
+ value_list_t vl = VALUE_LIST_INIT;
+
+ vl.values = values;
+ vl.values_len = (int) q->values_num;
+ vl.time = time (NULL);
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "dbi", sizeof (vl.plugin));
+ sstrncpy (vl.plugin_instance, db->name, sizeof (vl.type_instance));
+ sstrncpy (vl.type, q->type, sizeof (vl.type));
+ strjoin (vl.type_instance, sizeof (vl.type_instance),
+ instances, q->instances_num, "-");
+ vl.type_instance[sizeof (vl.type_instance) - 1] = 0;
+
+ plugin_dispatch_values (&vl);
+} /* }}} void cdbi_submit */
+
+/* Configuration handling functions {{{
+ *
+ * <Plugin dbi>
+ * <Query "plugin_instance0">
+ * Statement "SELECT name, value FROM table"
+ * Type "gauge"
+ * InstancesFrom "name"
+ * ValuesFrom "value"
+ * </Query>
+ *
+ * <Database "plugin_instance1">
+ * Driver "mysql"
+ * DriverOption "hostname" "localhost"
+ * ...
+ * Query "plugin_instance0"
+ * </Database>
+ * </Plugin>
+ */
+
+static int cdbi_config_set_string (char **ret_string, /* {{{ */
+ oconfig_item_t *ci)
+{
+ char *string;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("dbi plugin: The `%s' config option "
+ "needs exactly one string argument.", ci->key);
+ return (-1);
+ }
+
+ string = strdup (ci->values[0].value.string);
+ if (string == NULL)
+ {
+ ERROR ("dbi plugin: strdup failed.");
+ return (-1);
+ }
+
+ if (*ret_string != NULL)
+ free (*ret_string);
+ *ret_string = string;
+
+ return (0);
+} /* }}} int cdbi_config_set_string */
+
+static int cdbi_config_add_string (char ***ret_array, /* {{{ */
+ size_t *ret_array_len, oconfig_item_t *ci)
+{
+ char **array;
+ size_t array_len;
+ int i;
+
+ if (ci->values_num < 1)
+ {
+ WARNING ("dbi plugin: The `%s' config option "
+ "needs at least one argument.", ci->key);
+ return (-1);
+ }
+
+ for (i = 0; i < ci->values_num; i++)
+ {
+ if (ci->values[i].type != OCONFIG_TYPE_STRING)
+ {
+ WARNING ("dbi plugin: Argument %i to the `%s' option "
+ "is not a string.", i + 1, ci->key);
+ return (-1);
+ }
+ }
+
+ array_len = *ret_array_len;
+ array = (char **) realloc (*ret_array,
+ sizeof (char *) * (array_len + ci->values_num));
+ if (array == NULL)
+ {
+ ERROR ("dbi plugin: realloc failed.");
+ return (-1);
+ }
+ *ret_array = array;
+
+ for (i = 0; i < ci->values_num; i++)
+ {
+ array[array_len] = strdup (ci->values[i].value.string);
+ if (array[array_len] == NULL)
+ {
+ ERROR ("dbi plugin: strdup failed.");
+ *ret_array_len = array_len;
+ return (-1);
+ }
+ array_len++;
+ }
+
+ *ret_array_len = array_len;
+ return (0);
+} /* }}} int cdbi_config_add_string */
+
+static int cdbi_config_add_query (oconfig_item_t *ci) /* {{{ */
+{
+ cdbi_query_t *q;
+ int status;
+ int i;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("dbi plugin: The `Query' block "
+ "needs exactly one string argument.");
+ return (-1);
+ }
+
+ q = (cdbi_query_t *) malloc (sizeof (*q));
+ if (q == NULL)
+ {
+ ERROR ("dbi plugin: malloc failed.");
+ return (-1);
+ }
+ memset (q, 0, sizeof (*q));
+
+ status = cdbi_config_set_string (&q->name, ci);
+ if (status != 0)
+ {
+ sfree (q);
+ return (status);
+ }
+
+ /* Fill the `cdbi_query_t' structure.. */
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Statement", child->key) == 0)
+ status = cdbi_config_set_string (&q->statement, child);
+ else if (strcasecmp ("Type", child->key) == 0)
+ status = cdbi_config_set_string (&q->type, child);
+ else if (strcasecmp ("InstancesFrom", child->key) == 0)
+ status = cdbi_config_add_string (&q->instances, &q->instances_num, child);
+ else if (strcasecmp ("ValuesFrom", child->key) == 0)
+ status = cdbi_config_add_string (&q->values, &q->values_num, child);
+ else
+ {
+ WARNING ("dbi plugin: Option `%s' not allowed here.", child->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ }
+
+ /* Check that all necessary options have been given. */
+ while (status == 0)
+ {
+ if (q->statement == NULL)
+ {
+ WARNING ("dbi plugin: `Statement' not given for query `%s'", q->name);
+ status = -1;
+ }
+ if (q->type == NULL)
+ {
+ WARNING ("dbi plugin: `Type' not given for query `%s'", q->name);
+ status = -1;
+ }
+ if (q->instances == NULL)
+ {
+ WARNING ("dbi plugin: `InstancesFrom' not given for query `%s'", q->name);
+ status = -1;
+ }
+ if (q->values == NULL)
+ {
+ WARNING ("dbi plugin: `ValuesFrom' not given for query `%s'", q->name);
+ status = -1;
+ }
+
+ break;
+ } /* while (status == 0) */
+
+ /* If all went well, add this query to the list of queries within the
+ * database structure. */
+ if (status == 0)
+ {
+ cdbi_query_t **temp;
+
+ temp = (cdbi_query_t **) realloc (queries,
+ sizeof (*queries) * (queries_num + 1));
+ if (temp == NULL)
+ {
+ ERROR ("dbi plugin: realloc failed");
+ status = -1;
+ }
+ else
+ {
+ queries = temp;
+ queries[queries_num] = q;
+ queries_num++;
+ }
+ }
+
+ if (status != 0)
+ {
+ cdbi_query_free (q);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int cdbi_config_add_query */
+
+static int cdbi_config_add_database_driver_option (cdbi_database_t *db, /* {{{ */
+ oconfig_item_t *ci)
+{
+ cdbi_driver_option_t *option;
+
+ if ((ci->values_num != 2)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING)
+ || (ci->values[1].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("dbi plugin: The `DriverOption' config option "
+ "needs exactly two string arguments.");
+ return (-1);
+ }
+
+ option = (cdbi_driver_option_t *) realloc (db->driver_options,
+ sizeof (*option) * (db->driver_options_num + 1));
+ if (option == NULL)
+ {
+ ERROR ("dbi plugin: realloc failed");
+ return (-1);
+ }
+
+ db->driver_options = option;
+ option = db->driver_options + db->driver_options_num;
+
+ option->key = strdup (ci->values[0].value.string);
+ if (option->key == NULL)
+ {
+ ERROR ("dbi plugin: strdup failed.");
+ return (-1);
+ }
+
+ option->value = strdup (ci->values[1].value.string);
+ if (option->value == NULL)
+ {
+ ERROR ("dbi plugin: strdup failed.");
+ sfree (option->key);
+ return (-1);
+ }
+
+ db->driver_options_num++;
+ return (0);
+} /* }}} int cdbi_config_add_database_driver_option */
+
+static int cdbi_config_add_database_query (cdbi_database_t *db, /* {{{ */
+ oconfig_item_t *ci)
+{
+ cdbi_query_t *q;
+ cdbi_query_t **temp;
+ size_t i;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("dbi plugin: The `Query' config option "
+ "needs exactly one string argument.");
+ return (-1);
+ }
+
+ q = NULL;
+ for (i = 0; i < queries_num; i++)
+ {
+ if (strcasecmp (queries[i]->name, ci->values[0].value.string) == 0)
+ {
+ q = queries[i];
+ break;
+ }
+ }
+
+ if (q == NULL)
+ {
+ WARNING ("dbi plugin: Database `%s': Unknown query `%s'. "
+ "Please make sure that the <Query \"%s\"> block comes before "
+ "the <Database \"%s\"> block.",
+ db->name, ci->values[0].value.string,
+ ci->values[0].value.string, db->name);
+ return (-1);
+ }
+
+ temp = (cdbi_query_t **) realloc (db->queries,
+ sizeof (*db->queries) * (db->queries_num + 1));
+ if (temp == NULL)
+ {
+ ERROR ("dbi plugin: realloc failed");
+ return (-1);
+ }
+ else
+ {
+ db->queries = temp;
+ db->queries[db->queries_num] = q;
+ db->queries_num++;
+ }
+
+ return (0);
+} /* }}} int cdbi_config_add_database_query */
+
+static int cdbi_config_add_database (oconfig_item_t *ci) /* {{{ */
+{
+ cdbi_database_t *db;
+ int status;
+ int i;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("dbi plugin: The `Database' block "
+ "needs exactly one string argument.");
+ return (-1);
+ }
+
+ db = (cdbi_database_t *) malloc (sizeof (*db));
+ if (db == NULL)
+ {
+ ERROR ("dbi plugin: malloc failed.");
+ return (-1);
+ }
+ memset (db, 0, sizeof (*db));
+
+ status = cdbi_config_set_string (&db->name, ci);
+ if (status != 0)
+ {
+ sfree (db);
+ return (status);
+ }
+
+ /* Fill the `cdbi_database_t' structure.. */
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Driver", child->key) == 0)
+ status = cdbi_config_set_string (&db->driver, child);
+ else if (strcasecmp ("DriverOption", child->key) == 0)
+ status = cdbi_config_add_database_driver_option (db, child);
+ else if (strcasecmp ("SelectDB", child->key) == 0)
+ status = cdbi_config_set_string (&db->select_db, child);
+ else if (strcasecmp ("Query", child->key) == 0)
+ status = cdbi_config_add_database_query (db, child);
+ else
+ {
+ WARNING ("dbi plugin: Option `%s' not allowed here.", child->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ }
+
+ /* Check that all necessary options have been given. */
+ while (status == 0)
+ {
+ if (db->driver == NULL)
+ {
+ WARNING ("dbi plugin: `Driver' not given for database `%s'", db->name);
+ status = -1;
+ }
+ if (db->driver_options_num == 0)
+ {
+ WARNING ("dbi plugin: No `DriverOption' given for database `%s'. "
+ "This will likely not work.", db->name);
+ }
+
+ break;
+ } /* while (status == 0) */
+
+ /* If all went well, add this database to the global list of databases. */
+ if (status == 0)
+ {
+ cdbi_database_t **temp;
+
+ temp = (cdbi_database_t **) realloc (databases,
+ sizeof (*databases) * (databases_num + 1));
+ if (temp == NULL)
+ {
+ ERROR ("dbi plugin: realloc failed");
+ status = -1;
+ }
+ else
+ {
+ databases = temp;
+ databases[databases_num] = db;
+ databases_num++;
+ }
+ }
+
+ if (status != 0)
+ {
+ cdbi_database_free (db);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int cdbi_config_add_database */
+
+static int cdbi_config (oconfig_item_t *ci) /* {{{ */
+{
+ int i;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+ if (strcasecmp ("Query", child->key) == 0)
+ cdbi_config_add_query (child);
+ else if (strcasecmp ("Database", child->key) == 0)
+ cdbi_config_add_database (child);
+ else
+ {
+ WARNING ("snmp plugin: Ignoring unknown config option `%s'.", child->key);
+ }
+ } /* for (ci->children) */
+
+ return (0);
+} /* }}} int cdbi_config */
+
+/* }}} End of configuration handling functions */
+
+static int cdbi_init (void) /* {{{ */
+{
+ static int did_init = 0;
+ int status;
+
+ if (did_init != 0)
+ return (0);
+
+ if (queries_num == 0)
+ {
+ ERROR ("dbi plugin: No <Query> blocks have been found. Without them, "
+ "this plugin can't do anything useful, so we will returns an error.");
+ return (-1);
+ }
+
+ if (databases_num == 0)
+ {
+ ERROR ("dbi plugin: No <Database> blocks have been found. Without them, "
+ "this plugin can't do anything useful, so we will returns an error.");
+ return (-1);
+ }
+
+ status = dbi_initialize (NULL);
+ if (status < 0)
+ {
+ ERROR ("dbi plugin: cdbi_init: dbi_initialize failed with status %i.",
+ status);
+ return (-1);
+ }
+ else if (status == 0)
+ {
+ ERROR ("dbi plugin: `dbi_initialize' could not load any drivers. Please "
+ "install at least one `DBD' or check your installation.");
+ return (-1);
+ }
+ DEBUG ("dbi plugin: cdbi_init: dbi_initialize reports %i driver%s.",
+ status, (status == 1) ? "" : "s");
+
+ return (0);
+} /* }}} int cdbi_init */
+
+static int cdbi_read_database_query (cdbi_database_t *db, /* {{{ */
+ cdbi_query_t *q)
+{
+ dbi_result res;
+ char **instances;
+ value_t *values;
+ const data_set_t *ds;
+ size_t i;
+ int status;
+
+ res = NULL;
+ instances = NULL;
+ values = NULL;
+
+ /* Macro that cleans up dynamically allocated memory and returns the
+ * specified status. */
+#define BAIL_OUT(status) \
+ if (res != NULL) { dbi_result_free (res); res = NULL; } \
+ if (instances != NULL) { sfree (instances[0]); sfree (instances); } \
+ sfree (values); \
+ return (status)
+
+ ds = plugin_get_ds (q->type);
+ if (ds == NULL)
+ {
+ ERROR ("dbi plugin: cdbi_read_database_query: Query `%s': Type `%s' is not "
+ "known by the daemon. See types.db(5) for details.",
+ q->name, q->type);
+ BAIL_OUT (-1);
+ }
+
+ if (((size_t) ds->ds_num) != q->values_num)
+ {
+ ERROR ("dbi plugin: cdbi_read_database_query: Query `%s': The type `%s' "
+ "requires exactly %i value%s, but the configuration specifies %zu.",
+ q->name, q->type,
+ ds->ds_num, (ds->ds_num == 1) ? "" : "s",
+ q->values_num);
+ BAIL_OUT (-1);
+ }
+
+ /* Allocate `instances' and `values' {{{ */
+ instances = (char **) malloc (sizeof (*instances) * q->instances_num);
+ if (instances == NULL)
+ {
+ ERROR ("dbi plugin: malloc failed.");
+ BAIL_OUT (-1);
+ }
+
+ instances[0] = (char *) malloc (q->instances_num * DATA_MAX_NAME_LEN);
+ if (instances[0] == NULL)
+ {
+ ERROR ("dbi plugin: malloc failed.");
+ BAIL_OUT (-1);
+ }
+ for (i = 1; i < q->instances_num; i++)
+ instances[i] = instances[i - 1] + DATA_MAX_NAME_LEN;
+
+ values = (value_t *) malloc (sizeof (*values) * q->values_num);
+ if (values == NULL)
+ {
+ ERROR ("dbi plugin: malloc failed.");
+ BAIL_OUT (-1);
+ }
+ /* }}} */
+
+ res = dbi_conn_query (db->connection, q->statement);
+ if (res == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): "
+ "dbi_conn_query failed: %s",
+ db->name, q->name,
+ cdbi_strerror (db->connection, errbuf, sizeof (errbuf)));
+ BAIL_OUT (-1);
+ }
+
+ status = dbi_result_first_row (res);
+ if (status != 1)
+ {
+ char errbuf[1024];
+ ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): "
+ "dbi_result_first_row failed: %s. Maybe the statement didn't "
+ "return any rows?",
+ db->name, q->name,
+ cdbi_strerror (db->connection, errbuf, sizeof (errbuf)));
+ BAIL_OUT (-1);
+ }
+
+ while (42)
+ {
+ /* Get instance names and values from the result: */
+ for (i = 0; i < q->instances_num; i++) /* {{{ */
+ {
+ const char *inst;
+
+ inst = dbi_result_get_string (res, q->instances[i]);
+ if (dbi_conn_error (db->connection, NULL) != 0)
+ {
+ char errbuf[1024];
+ ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): "
+ "dbi_result_get_string (%s) failed: %s",
+ db->name, q->name, q->instances[i],
+ cdbi_strerror (db->connection, errbuf, sizeof (errbuf)));
+ BAIL_OUT (-1);
+ }
+
+ sstrncpy (instances[i], (inst == NULL) ? "" : inst, DATA_MAX_NAME_LEN);
+ DEBUG ("dbi plugin: cdbi_read_database_query (%s, %s): "
+ "instances[%zu] = %s;",
+ db->name, q->name, i, instances[i]);
+ } /* }}} for (i = 0; i < q->instances_num; i++) */
+
+ for (i = 0; i < q->values_num; i++) /* {{{ */
+ {
+ status = cdbi_result_get_field (res, q->values[i], ds->ds[i].type,
+ values + i);
+ if (status != 0)
+ {
+ BAIL_OUT (-1);
+ }
+
+ if (ds->ds[i].type == DS_TYPE_COUNTER)
+ {
+ DEBUG ("dbi plugin: cdbi_read_database_query (%s, %s): values[%zu] = %llu;",
+ db->name, q->name, i, values[i].counter);
+ }
+ else
+ {
+ DEBUG ("dbi plugin: cdbi_read_database_query (%s, %s): values[%zu] = %g;",
+ db->name, q->name, i, values[i].gauge);
+ }
+ } /* }}} for (i = 0; i < q->values_num; i++) */
+
+ /* Dispatch this row to the daemon. */
+ cdbi_submit (db, q, instances, values);
+
+ /* Get the next row from the database. */
+ status = dbi_result_next_row (res);
+ if (status != 1)
+ {
+ if (dbi_conn_error (db->connection, NULL) != 0)
+ {
+ char errbuf[1024];
+ WARNING ("dbi plugin: cdbi_read_database_query (%s, %s): "
+ "dbi_result_next_row failed: %s.",
+ db->name, q->name,
+ cdbi_strerror (db->connection, errbuf, sizeof (errbuf)));
+ }
+ break;
+ }
+ } /* while (42) */
+
+ BAIL_OUT (0);
+#undef BAIL_OUT
+} /* }}} int cdbi_read_database_query */
+
+static int cdbi_connect_database (cdbi_database_t *db) /* {{{ */
+{
+ dbi_driver driver;
+ dbi_conn connection;
+ size_t i;
+ int status;
+
+ if (db->connection != NULL)
+ {
+ status = dbi_conn_ping (db->connection);
+ if (status != 0) /* connection is alive */
+ return (0);
+
+ dbi_conn_close (db->connection);
+ db->connection = NULL;
+ }
+
+ driver = dbi_driver_open (db->driver);
+ if (driver == NULL)
+ {
+ ERROR ("dbi plugin: cdbi_connect_database: dbi_driver_open (%s) failed.",
+ db->driver);
+ INFO ("dbi plugin: Maybe the driver isn't installed? "
+ "Known drivers are:");
+ for (driver = dbi_driver_list (NULL);
+ driver != NULL;
+ driver = dbi_driver_list (driver))
+ {
+ INFO ("dbi plugin: * %s", dbi_driver_get_name (driver));
+ }
+ return (-1);
+ }
+
+ connection = dbi_conn_open (driver);
+ if (connection == NULL)
+ {
+ ERROR ("dbi plugin: cdbi_connect_database: dbi_conn_open (%s) failed.",
+ db->driver);
+ return (-1);
+ }
+
+ /* Set all the driver options. Because this is a very very very generic
+ * interface, the error handling is kind of long. If an invalid option is
+ * encountered, it will get a list of options understood by the driver and
+ * report that as `INFO'. This way, users hopefully don't have too much
+ * trouble finding out how to configure the plugin correctly.. */
+ for (i = 0; i < db->driver_options_num; i++)
+ {
+ DEBUG ("dbi plugin: cdbi_connect_database (%s): "
+ "key = %s; value = %s;",
+ db->name,
+ db->driver_options[i].key,
+ db->driver_options[i].value);
+
+ status = dbi_conn_set_option (connection,
+ db->driver_options[i].key, db->driver_options[i].value);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ const char *opt;
+
+ ERROR ("dbi plugin: cdbi_connect_database (%s): "
+ "dbi_conn_set_option (%s, %s) failed: %s.",
+ db->name,
+ db->driver_options[i].key, db->driver_options[i].value,
+ cdbi_strerror (connection, errbuf, sizeof (errbuf)));
+
+ INFO ("dbi plugin: This is a list of all options understood "
+ "by the `%s' driver:", db->driver);
+ for (opt = dbi_conn_get_option_list (connection, NULL);
+ opt != NULL;
+ opt = dbi_conn_get_option_list (connection, opt))
+ {
+ INFO ("dbi plugin: * %s", opt);
+ }
+
+ dbi_conn_close (connection);
+ return (-1);
+ }
+ } /* for (i = 0; i < db->driver_options_num; i++) */
+
+ status = dbi_conn_connect (connection);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("dbi plugin: cdbi_connect_database (%s): "
+ "dbi_conn_connect failed: %s",
+ db->name, cdbi_strerror (connection, errbuf, sizeof (errbuf)));
+ dbi_conn_close (connection);
+ return (-1);
+ }
+
+ if (db->select_db != NULL)
+ {
+ status = dbi_conn_select_db (connection, db->select_db);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ WARNING ("dbi plugin: cdbi_connect_database (%s): "
+ "dbi_conn_select_db (%s) failed: %s. Check the `SelectDB' option.",
+ db->name, db->select_db,
+ cdbi_strerror (connection, errbuf, sizeof (errbuf)));
+ dbi_conn_close (connection);
+ return (-1);
+ }
+ }
+
+ db->connection = connection;
+ return (0);
+} /* }}} int cdbi_connect_database */
+
+static int cdbi_read_database (cdbi_database_t *db) /* {{{ */
+{
+ size_t i;
+ int success;
+ int status;
+
+ status = cdbi_connect_database (db);
+ if (status != 0)
+ return (status);
+ assert (db->connection != NULL);
+
+ success = 0;
+ for (i = 0; i < db->queries_num; i++)
+ {
+ status = cdbi_read_database_query (db, db->queries[i]);
+ if (status == 0)
+ success++;
+ }
+
+ if (success == 0)
+ {
+ ERROR ("dbi plugin: All queries failed for database `%s'.", db->name);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int cdbi_read_database */
+
+static int cdbi_read (void) /* {{{ */
+{
+ size_t i;
+ int success = 0;
+ int status;
+
+ for (i = 0; i < databases_num; i++)
+ {
+ status = cdbi_read_database (databases[i]);
+ if (status == 0)
+ success++;
+ }
+
+ if (success == 0)
+ {
+ ERROR ("dbi plugin: No database could be read. Will return an error so "
+ "the plugin will be delayed.");
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int cdbi_read */
+
+static int cdbi_shutdown (void) /* {{{ */
+{
+ size_t i;
+
+ for (i = 0; i < databases_num; i++)
+ {
+ if (databases[i]->connection != NULL)
+ {
+ dbi_conn_close (databases[i]->connection);
+ databases[i]->connection = NULL;
+ }
+ cdbi_database_free (databases[i]);
+ }
+ sfree (databases);
+ databases_num = 0;
+
+ for (i = 0; i < queries_num; i++)
+ cdbi_query_free (queries[i]);
+ sfree (queries);
+ queries_num = 0;
+
+ return (0);
+} /* }}} int cdbi_shutdown */
+
+void module_register (void) /* {{{ */
+{
+ plugin_register_complex_config ("dbi", cdbi_config);
+ plugin_register_init ("dbi", cdbi_init);
+ plugin_register_read ("dbi", cdbi_read);
+ plugin_register_shutdown ("dbi", cdbi_shutdown);
+} /* }}} void module_register */
+
+/*
+ * vim: shiftwidth=2 softtabstop=2 et fdm=marker
+ */
#include <dirent.h>
#include <fnmatch.h>
+#define FC_RECURSIVE 1
+
struct fc_directory_conf_s
{
char *path;
char *instance;
+ int options;
+
/* Data counters */
uint64_t files_num;
uint64_t files_size;
return (0);
} /* int fc_config_add_dir_size */
+static int fc_config_add_dir_recursive (fc_directory_conf_t *dir,
+ oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
+ {
+ WARNING ("filecount plugin: The `Recursive' config options needs exactly "
+ "one boolean argument.");
+ return (-1);
+ }
+
+ if (ci->values[0].value.boolean)
+ dir->options |= FC_RECURSIVE;
+ else
+ dir->options &= ~FC_RECURSIVE;
+
+ return (0);
+} /* int fc_config_add_dir_recursive */
+
static int fc_config_add_dir (oconfig_item_t *ci)
{
fc_directory_conf_t *dir;
fc_config_set_instance (dir, dir->path);
+ dir->options = FC_RECURSIVE;
+
dir->name = NULL;
dir->mtime = 0;
dir->size = 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 if (strcasecmp ("Recursive", option->key) == 0)
+ status = fc_config_add_dir_recursive (dir, option);
else
{
WARNING ("filecount plugin: fc_config_add_dir: "
return (-1);
}
- if (S_ISDIR (statbuf.st_mode))
+ if (S_ISDIR (statbuf.st_mode) && (dir->options & FC_RECURSIVE))
{
status = walk_directory (abs_path, fc_read_dir_callback, dir);
return (status);
--- /dev/null
+/**
+ * collectd - src/filter_chain.h
+ * 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 verplant.org>
+ **/
+
+/*
+ * First tell the compiler to stick to the C99 and POSIX standards as close as
+ * possible.
+ */
+#ifndef __STRICT_ANSI__ /* {{{ */
+# define __STRICT_ANSI__
+#endif
+
+#ifndef _ISOC99_SOURCE
+# define _ISOC99_SOURCE
+#endif
+
+#ifdef _POSIX_C_SOURCE
+# undef _POSIX_C_SOURCE
+#endif
+#define _POSIX_C_SOURCE 200112L
+
+#if 0
+/* Single UNIX needed for strdup. */
+#ifdef _XOPEN_SOURCE
+# undef _XOPEN_SOURCE
+#endif
+#define _XOPEN_SOURCE 500
+#endif
+
+#ifndef _REENTRANT
+# define _REENTRANT
+#endif
+
+#ifndef _THREAD_SAFE
+# define _THREAD_SAFE
+#endif
+
+#ifdef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* }}} */
+
+#include "collectd.h"
+#include "configfile.h"
+#include "plugin.h"
+#include "common.h"
+#include "filter_chain.h"
+
+/*
+ * Data types
+ */
+/* List of matches, used in fc_rule_t and for the global `match_list_head'
+ * variable. */
+struct fc_match_s;
+typedef struct fc_match_s fc_match_t; /* {{{ */
+struct fc_match_s
+{
+ char name[DATA_MAX_NAME_LEN];
+ match_proc_t proc;
+ void *user_data;
+ fc_match_t *next;
+}; /* }}} */
+
+/* List of targets, used in fc_rule_t and for the global `target_list_head'
+ * variable. */
+struct fc_target_s;
+typedef struct fc_target_s fc_target_t; /* {{{ */
+struct fc_target_s
+{
+ char name[DATA_MAX_NAME_LEN];
+ void *user_data;
+ target_proc_t proc;
+ fc_target_t *next;
+}; /* }}} */
+
+/* List of rules, used in fc_chain_t */
+struct fc_rule_s;
+typedef struct fc_rule_s fc_rule_t; /* {{{ */
+struct fc_rule_s
+{
+ char name[DATA_MAX_NAME_LEN];
+ fc_match_t *matches;
+ fc_target_t *targets;
+ fc_rule_t *next;
+}; /* }}} */
+
+/* List of chains, used for `chain_list_head' */
+struct fc_chain_s;
+typedef struct fc_chain_s fc_chain_t; /* {{{ */
+struct fc_chain_s
+{
+ char name[DATA_MAX_NAME_LEN];
+ fc_rule_t *rules;
+ fc_target_t *targets;
+ fc_chain_t *next;
+}; /* }}} */
+
+/*
+ * Global variables
+ */
+static fc_match_t *match_list_head;
+static fc_target_t *target_list_head;
+static fc_chain_t *chain_list_head;
+
+/*
+ * Private functions
+ */
+static void fc_free_matches (fc_match_t *m) /* {{{ */
+{
+ if (m == NULL)
+ return;
+
+ if (m->proc.destroy != NULL)
+ (*m->proc.destroy) (&m->user_data);
+ else if (m->user_data != NULL)
+ {
+ ERROR ("Filter sybsystem: fc_free_matches: There is user data, but no "
+ "destroy functions has been specified. "
+ "Memory will probably be lost!");
+ }
+
+ if (m->next != NULL)
+ fc_free_matches (m->next);
+
+ free (m);
+} /* }}} void fc_free_matches */
+
+static void fc_free_targets (fc_target_t *t) /* {{{ */
+{
+ if (t == NULL)
+ return;
+
+ if (t->proc.destroy != NULL)
+ (*t->proc.destroy) (&t->user_data);
+ else if (t->user_data != NULL)
+ {
+ ERROR ("Filter sybsystem: fc_free_targets: There is user data, but no "
+ "destroy functions has been specified. "
+ "Memory will probably be lost!");
+ }
+
+ if (t->next != NULL)
+ fc_free_targets (t->next);
+
+ free (t);
+} /* }}} void fc_free_targets */
+
+static void fc_free_rules (fc_rule_t *r) /* {{{ */
+{
+ if (r == NULL)
+ return;
+
+ fc_free_matches (r->matches);
+ fc_free_targets (r->targets);
+
+ if (r->next != NULL)
+ fc_free_rules (r->next);
+
+ free (r);
+} /* }}} void fc_free_rules */
+
+static void fc_free_chains (fc_chain_t *c) /* {{{ */
+{
+ if (c == NULL)
+ return;
+
+ fc_free_rules (c->rules);
+ fc_free_targets (c->targets);
+
+ if (c->next != NULL)
+ fc_free_chains (c->next);
+
+ free (c);
+} /* }}} void fc_free_chains */
+
+static char *fc_strdup (const char *orig) /* {{{ */
+{
+ size_t sz;
+ char *dest;
+
+ if (orig == NULL)
+ return (NULL);
+
+ sz = strlen (orig) + 1;
+ dest = (char *) malloc (sz);
+ if (dest == NULL)
+ return (NULL);
+
+ memcpy (dest, orig, sz);
+
+ return (dest);
+} /* }}} char *fc_strdup */
+
+/*
+ * Configuration.
+ *
+ * The configuration looks somewhat like this:
+ *
+ * <Chain "main">
+ * <Rule>
+ * <Match "regex">
+ * Plugin "^mysql$"
+ * Type "^mysql_command$"
+ * TypeInstance "^show_"
+ * </Match>
+ * <Target "drop">
+ * </Target>
+ * </Rule>
+ *
+ * <Target "write">
+ * Plugin "rrdtool"
+ * </Target>
+ * </Chain>
+ */
+static int fc_config_add_match (fc_match_t **matches_head, /* {{{ */
+ oconfig_item_t *ci)
+{
+ fc_match_t *m;
+ fc_match_t *ptr;
+ int status;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("Filter subsystem: `Match' blocks require "
+ "exactly one string argument.");
+ return (-1);
+ }
+
+ ptr = match_list_head;
+ while (ptr != NULL)
+ {
+ if (strcasecmp (ptr->name, ci->values[0].value.string) == 0)
+ break;
+ ptr = ptr->next;
+ }
+
+ if (ptr == NULL)
+ {
+ WARNING ("Filter subsystem: Cannot find a \"%s\" match. "
+ "Did you load the appropriate plugin?",
+ ci->values[0].value.string);
+ return (-1);
+ }
+
+ m = (fc_match_t *) malloc (sizeof (*m));
+ if (m == NULL)
+ {
+ ERROR ("fc_config_add_match: malloc failed.");
+ return (-1);
+ }
+ memset (m, 0, sizeof (*m));
+
+ sstrncpy (m->name, ptr->name, sizeof (m->name));
+ memcpy (&m->proc, &ptr->proc, sizeof (m->proc));
+ assert (m->proc.create != NULL);
+ m->user_data = NULL;
+ m->next = NULL;
+
+ status = (*m->proc.create) (ci, &m->user_data);
+ if (status != 0)
+ {
+ WARNING ("Filter subsystem: Failed to create a %s match.",
+ m->name);
+ fc_free_matches (m);
+ return (-1);
+ }
+
+ if (*matches_head != NULL)
+ {
+ ptr = *matches_head;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = m;
+ }
+ else
+ {
+ *matches_head = m;
+ }
+
+ return (0);
+} /* }}} int fc_config_add_match */
+
+static int fc_config_add_target (fc_target_t **targets_head, /* {{{ */
+ oconfig_item_t *ci)
+{
+ fc_target_t *t;
+ fc_target_t *ptr;
+ int status;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("Filter subsystem: `Target' blocks require "
+ "exactly one string argument.");
+ return (-1);
+ }
+
+ ptr = target_list_head;
+ while (ptr != NULL)
+ {
+ if (strcasecmp (ptr->name, ci->values[0].value.string) == 0)
+ break;
+ ptr = ptr->next;
+ }
+
+ if (ptr == NULL)
+ {
+ WARNING ("Filter subsystem: Cannot find a \"%s\" target. "
+ "Did you load the appropriate plugin?",
+ ci->values[0].value.string);
+ return (-1);
+ }
+
+ t = (fc_target_t *) malloc (sizeof (*t));
+ if (t == NULL)
+ {
+ ERROR ("fc_config_add_match: malloc failed.");
+ return (-1);
+ }
+ memset (t, 0, sizeof (*t));
+
+ sstrncpy (t->name, ptr->name, sizeof (t->name));
+ memcpy (&t->proc, &ptr->proc, sizeof (t->proc));
+ t->user_data = NULL;
+ t->next = NULL;
+
+ if (t->proc.create != NULL)
+ {
+ status = (*t->proc.create) (ci, &t->user_data);
+ if (status != 0)
+ {
+ WARNING ("Filter subsystem: Failed to create a %s match.",
+ t->name);
+ fc_free_targets (t);
+ return (-1);
+ }
+ }
+ else
+ {
+ t->user_data = NULL;
+ }
+
+ if (*targets_head != NULL)
+ {
+ ptr = *targets_head;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = t;
+ }
+ else
+ {
+ *targets_head = t;
+ }
+
+ return (0);
+} /* }}} int fc_config_add_target */
+
+static int fc_config_add_rule (fc_chain_t *chain, /* {{{ */
+ oconfig_item_t *ci)
+{
+ fc_rule_t *rule;
+ char rule_name[2*DATA_MAX_NAME_LEN] = "Unnamed rule";
+ int status = 0;
+ int i;
+
+ if (ci->values_num > 1)
+ {
+ WARNING ("Filter subsystem: `Rule' blocks have at most one argument.");
+ return (-1);
+ }
+ else if ((ci->values_num == 1)
+ && (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("Filter subsystem: `Rule' blocks expect one string argument "
+ "or no argument at all.");
+ return (-1);
+ }
+
+ rule = (fc_rule_t *) malloc (sizeof (*rule));
+ if (rule == NULL)
+ {
+ ERROR ("fc_config_add_rule: malloc failed.");
+ return (-1);
+ }
+ memset (rule, 0, sizeof (*rule));
+ rule->next = NULL;
+
+ if (ci->values_num == 1)
+ {
+ sstrncpy (rule->name, ci->values[0].value.string, sizeof (rule->name));
+ ssnprintf (rule_name, sizeof (rule_name), "Rule \"%s\"",
+ ci->values[0].value.string);
+ }
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *option = ci->children + i;
+ status = 0;
+
+ if (strcasecmp ("Match", option->key) == 0)
+ status = fc_config_add_match (&rule->matches, option);
+ else if (strcasecmp ("Target", option->key) == 0)
+ status = fc_config_add_target (&rule->targets, option);
+ else
+ {
+ WARNING ("Filter subsystem: %s: Option `%s' not allowed "
+ "inside a <Rule> block.", rule_name, option->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ } /* for (ci->children) */
+
+ /* Additional sanity checking. */
+ while (status == 0)
+ {
+ if (rule->targets == NULL)
+ {
+ WARNING ("Filter subsystem: %s: No target has been specified.",
+ rule_name);
+ status = -1;
+ break;
+ }
+
+ break;
+ } /* while (status == 0) */
+
+ if (status != 0)
+ {
+ fc_free_rules (rule);
+ return (-1);
+ }
+
+ if (chain->rules != NULL)
+ {
+ fc_rule_t *ptr;
+
+ ptr = chain->rules;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = rule;
+ }
+ else
+ {
+ chain->rules = rule;
+ }
+
+ return (0);
+} /* }}} int fc_config_add_rule */
+
+static int fc_config_add_chain (const oconfig_item_t *ci) /* {{{ */
+{
+ fc_chain_t *chain;
+ int status = 0;
+ int i;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("Filter subsystem: <Chain> blocks require exactly one "
+ "string argument.");
+ return (-1);
+ }
+
+ chain = (fc_chain_t *) malloc (sizeof (*chain));
+ if (chain == NULL)
+ {
+ ERROR ("fc_config_add_chain: malloc failed.");
+ return (-1);
+ }
+ memset (chain, 0, sizeof (*chain));
+ sstrncpy (chain->name, ci->values[0].value.string, sizeof (chain->name));
+ chain->rules = NULL;
+ chain->targets = NULL;
+ chain->next = NULL;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *option = ci->children + i;
+ status = 0;
+
+ if (strcasecmp ("Rule", option->key) == 0)
+ status = fc_config_add_rule (chain, option);
+ else if (strcasecmp ("Target", option->key) == 0)
+ status = fc_config_add_target (&chain->targets, option);
+ else
+ {
+ WARNING ("Filter subsystem: Chain %s: Option `%s' not allowed "
+ "inside a <Chain> block.", chain->name, option->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ } /* for (ci->children) */
+
+ /* Additional sanity checking. */
+ while (status == 0)
+ {
+ if (chain->targets == NULL)
+ {
+ WARNING ("Filter subsystem: Chain %s: No default target has been "
+ "specified. Please make sure that there is a <Target> block within "
+ "the <Chain> block!", chain->name);
+ status = -1;
+ break;
+ }
+
+ break;
+ } /* while (status == 0) */
+
+ if (status != 0)
+ {
+ fc_free_chains (chain);
+ return (-1);
+ }
+
+ if (chain_list_head != NULL)
+ {
+ fc_chain_t *ptr;
+
+ ptr = chain_list_head;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = chain;
+ }
+ else
+ {
+ chain_list_head = chain;
+ }
+
+ return (0);
+} /* }}} int fc_config_add_chain */
+
+int fc_process_chain (const data_set_t *ds, value_list_t *vl, /* {{{ */
+ fc_chain_t *chain)
+{
+ fc_rule_t *rule;
+ fc_target_t *target;
+ int status;
+
+ if (chain == NULL)
+ return (-1);
+
+ DEBUG ("fc_process_chain (chain = %s);", chain->name);
+
+ status = FC_TARGET_CONTINUE;
+ for (rule = chain->rules; rule != NULL; rule = rule->next)
+ {
+ fc_match_t *match;
+
+ if (rule->name[0] != 0)
+ {
+ DEBUG ("fc_process_chain (%s): Testing the `%s' rule.",
+ chain->name, rule->name);
+ }
+
+ /* N. B.: rule->matches may be NULL. */
+ for (match = rule->matches; match != NULL; match = match->next)
+ {
+ status = (*match->proc.match) (ds, vl, /* meta = */ NULL,
+ &match->user_data);
+ if (status < 0)
+ {
+ WARNING ("fc_process_chain (%s): A match failed.", chain->name);
+ break;
+ }
+ else if (status != FC_MATCH_MATCHES)
+ break;
+ }
+
+ /* for-loop has been aborted: Either error or no match. */
+ if (match != NULL)
+ {
+ status = FC_TARGET_CONTINUE;
+ continue;
+ }
+
+ if (rule->name[0] != 0)
+ {
+ DEBUG ("fc_process_chain (%s): Rule `%s' matches.",
+ chain->name, rule->name);
+ }
+
+ for (target = rule->targets; target != NULL; target = target->next)
+ {
+ /* If we get here, all matches have matched the value. Execute the
+ * target. */
+ status = (*target->proc.invoke) (ds, vl, /* meta = */ NULL,
+ &target->user_data);
+ if (status < 0)
+ {
+ WARNING ("fc_process_chain (%s): A target failed.", chain->name);
+ continue;
+ }
+ else if (status == FC_TARGET_CONTINUE)
+ continue;
+ else if (status == FC_TARGET_STOP)
+ break;
+ else if (status == FC_TARGET_RETURN)
+ break;
+ else
+ {
+ WARNING ("fc_process_chain (%s): Unknown return value "
+ "from target `%s': %i",
+ chain->name, target->name, status);
+ }
+ }
+
+ if ((status == FC_TARGET_STOP)
+ || (status == FC_TARGET_RETURN))
+ {
+ if (rule->name[0] != 0)
+ {
+ DEBUG ("fc_process_chain (%s): Rule `%s' signaled "
+ "the %s condition.",
+ chain->name, rule->name,
+ (status == FC_TARGET_STOP) ? "stop" : "return");
+ }
+ break;
+ }
+ else
+ {
+ status = FC_TARGET_CONTINUE;
+ }
+ } /* for (rule) */
+
+ if (status == FC_TARGET_STOP)
+ return (FC_TARGET_STOP);
+ else if (status == FC_TARGET_RETURN)
+ return (FC_TARGET_CONTINUE);
+
+ /* for-loop has been aborted: A target returned `FC_TARGET_STOP' */
+ if (rule != NULL)
+ return (FC_TARGET_CONTINUE);
+
+ DEBUG ("fc_process_chain (%s): Executing the default targets.",
+ chain->name);
+
+ status = FC_TARGET_CONTINUE;
+ for (target = chain->targets; target != NULL; target = target->next)
+ {
+ /* If we get here, all matches have matched the value. Execute the
+ * target. */
+ status = (*target->proc.invoke) (ds, vl, /* meta = */ NULL,
+ &target->user_data);
+ if (status < 0)
+ {
+ WARNING ("fc_process_chain (%s): The default target failed.",
+ chain->name);
+ }
+ else if (status == FC_TARGET_CONTINUE)
+ continue;
+ else if (status == FC_TARGET_STOP)
+ break;
+ else if (status == FC_TARGET_RETURN)
+ break;
+ else
+ {
+ WARNING ("fc_process_chain (%s): Unknown return value "
+ "from target `%s': %i",
+ chain->name, target->name, status);
+ }
+ }
+
+ if ((status == FC_TARGET_STOP)
+ || (status == FC_TARGET_RETURN))
+ {
+ assert (target != NULL);
+ DEBUG ("fc_process_chain (%s): Default target `%s' signaled "
+ "the %s condition.",
+ chain->name, target->name,
+ (status == FC_TARGET_STOP) ? "stop" : "return");
+ if (status == FC_TARGET_STOP)
+ return (FC_TARGET_STOP);
+ else
+ return (FC_TARGET_CONTINUE);
+ }
+
+ DEBUG ("fc_process_chain (%s): Signaling `continue' at end of chain.",
+ chain->name);
+
+ return (FC_TARGET_CONTINUE);
+} /* }}} int fc_process_chain */
+
+/*
+ * Built-in target "jump"
+ *
+ * Prefix `bit' like `_b_uilt-_i_n _t_arget'
+ */
+static int fc_bit_jump_create (const oconfig_item_t *ci, /* {{{ */
+ void **user_data)
+{
+ oconfig_item_t *ci_chain;
+
+ if (ci->children_num != 1)
+ {
+ ERROR ("Filter subsystem: The built-in target `jump' needs exactly "
+ "one `Chain' argument!");
+ return (-1);
+ }
+
+ ci_chain = ci->children;
+ if (strcasecmp ("Chain", ci_chain->key) != 0)
+ {
+ ERROR ("Filter subsystem: The built-in target `jump' does not "
+ "support the configuration option `%s'.",
+ ci_chain->key);
+ return (-1);
+ }
+
+ if ((ci_chain->values_num != 1)
+ || (ci_chain->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ ERROR ("Filter subsystem: Built-in target `jump': The `Chain' option "
+ "needs exactly one string argument.");
+ return (-1);
+ }
+
+ *user_data = fc_strdup (ci_chain->values[0].value.string);
+ if (*user_data == NULL)
+ {
+ ERROR ("fc_bit_jump_create: fc_strdup failed.");
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int fc_bit_jump_create */
+
+static int fc_bit_jump_destroy (void **user_data) /* {{{ */
+{
+ if (user_data != NULL)
+ {
+ free (*user_data);
+ *user_data = NULL;
+ }
+
+ return (0);
+} /* }}} int fc_bit_jump_destroy */
+
+static int fc_bit_jump_invoke (const data_set_t *ds, /* {{{ */
+ value_list_t *vl, notification_meta_t **meta, void **user_data)
+{
+ char *chain_name;
+ fc_chain_t *chain;
+ int status;
+
+ chain_name = *user_data;
+
+ for (chain = chain_list_head; chain != NULL; chain = chain->next)
+ if (strcasecmp (chain_name, chain->name) == 0)
+ break;
+
+ if (chain == NULL)
+ {
+ ERROR ("Filter subsystem: Built-in target `jump': There is no chain "
+ "named `%s'.", chain_name);
+ return (-1);
+ }
+
+ status = fc_process_chain (ds, vl, chain);
+ if (status < 0)
+ return (status);
+ else if (status == FC_TARGET_STOP)
+ return (FC_TARGET_STOP);
+ else
+ return (FC_TARGET_CONTINUE);
+} /* }}} int fc_bit_jump_invoke */
+
+static int fc_bit_stop_invoke (const data_set_t *ds, /* {{{ */
+ value_list_t *vl, notification_meta_t **meta, void **user_data)
+{
+ return (FC_TARGET_STOP);
+} /* }}} int fc_bit_stop_invoke */
+
+static int fc_bit_return_invoke (const data_set_t *ds, /* {{{ */
+ value_list_t *vl, notification_meta_t **meta, void **user_data)
+{
+ return (FC_TARGET_RETURN);
+} /* }}} int fc_bit_return_invoke */
+
+static int fc_bit_write_create (const oconfig_item_t *ci, /* {{{ */
+ void **user_data)
+{
+ int i;
+
+ char **plugin_list;
+ size_t plugin_list_len;
+
+ plugin_list = NULL;
+ plugin_list_len = 0;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+ char **temp;
+ int j;
+
+ if (strcasecmp ("Plugin", child->key) != 0)
+ {
+ ERROR ("Filter subsystem: The built-in target `write' does not "
+ "support the configuration option `%s'.",
+ child->key);
+ continue;
+ }
+
+ for (j = 0; j < child->values_num; j++)
+ {
+ if (child->values[j].type != OCONFIG_TYPE_STRING)
+ {
+ ERROR ("Filter subsystem: Built-in target `write': "
+ "The `Plugin' option accepts only string arguments.");
+ continue;
+ }
+
+ temp = (char **) realloc (plugin_list, (plugin_list_len + 2)
+ * (sizeof (*plugin_list)));
+ if (temp == NULL)
+ {
+ ERROR ("fc_bit_write_create: realloc failed.");
+ continue;
+ }
+ plugin_list = temp;
+
+ plugin_list[plugin_list_len] = fc_strdup (child->values[j].value.string);
+ if (plugin_list[plugin_list_len] == NULL)
+ {
+ ERROR ("fc_bit_write_create: fc_strdup failed.");
+ continue;
+ }
+ plugin_list_len++;
+ plugin_list[plugin_list_len] = NULL;
+ } /* for (j = 0; j < child->values_num; j++) */
+ } /* for (i = 0; i < ci->children_num; i++) */
+
+ *user_data = plugin_list;
+
+ return (0);
+} /* }}} int fc_bit_write_create */
+
+static int fc_bit_write_destroy (void **user_data) /* {{{ */
+{
+ char **plugin_list;
+ size_t i;
+
+ if ((user_data == NULL) || (*user_data == NULL))
+ return (0);
+
+ plugin_list = *user_data;
+
+ for (i = 0; plugin_list[i] != NULL; i++)
+ free (plugin_list[i]);
+ free (plugin_list);
+
+ return (0);
+} /* }}} int fc_bit_write_destroy */
+
+static int fc_bit_write_invoke (const data_set_t *ds, /* {{{ */
+ value_list_t *vl, notification_meta_t **meta, void **user_data)
+{
+ char **plugin_list;
+ int status;
+
+ plugin_list = NULL;
+ if (user_data != NULL)
+ plugin_list = *user_data;
+
+ if ((plugin_list == NULL) || (plugin_list[0] == NULL))
+ {
+ status = plugin_write (/* plugin = */ NULL, ds, vl);
+ if (status != 0)
+ {
+ INFO ("Filter subsystem: Built-in target `write': Dispatching value to "
+ "all write plugins failed with status %i.", status);
+ }
+ }
+ else
+ {
+ size_t i;
+
+ for (i = 0; plugin_list[i] != NULL; i++)
+ {
+ status = plugin_write (plugin_list[i], ds, vl);
+ if (status != 0)
+ {
+ INFO ("Filter subsystem: Built-in target `write': Dispatching value to "
+ "the `%s' plugin failed with status %i.", plugin_list[i], status);
+ }
+ } /* for (i = 0; plugin_list[i] != NULL; i++) */
+ }
+
+ return (FC_TARGET_CONTINUE);
+} /* }}} int fc_bit_write_invoke */
+
+static int fc_init_once (void) /* {{{ */
+{
+ static int done = 0;
+ target_proc_t tproc;
+
+ if (done != 0)
+ return (0);
+
+ memset (&tproc, 0, sizeof (tproc));
+ tproc.create = fc_bit_jump_create;
+ tproc.destroy = fc_bit_jump_destroy;
+ tproc.invoke = fc_bit_jump_invoke;
+ fc_register_target ("jump", tproc);
+
+ memset (&tproc, 0, sizeof (tproc));
+ tproc.create = NULL;
+ tproc.destroy = NULL;
+ tproc.invoke = fc_bit_stop_invoke;
+ fc_register_target ("stop", tproc);
+
+ memset (&tproc, 0, sizeof (tproc));
+ tproc.create = NULL;
+ tproc.destroy = NULL;
+ tproc.invoke = fc_bit_return_invoke;
+ fc_register_target ("return", tproc);
+
+ memset (&tproc, 0, sizeof (tproc));
+ tproc.create = fc_bit_write_create;
+ tproc.destroy = fc_bit_write_destroy;
+ tproc.invoke = fc_bit_write_invoke;
+ fc_register_target ("write", tproc);
+
+ done++;
+ return (0);
+} /* }}} int fc_init_once */
+
+/*
+ * Public functions
+ */
+/* Add a match to list of available matches. */
+int fc_register_match (const char *name, match_proc_t proc) /* {{{ */
+{
+ fc_match_t *m;
+
+ DEBUG ("fc_register_match (%s);", name);
+
+ m = (fc_match_t *) malloc (sizeof (*m));
+ if (m == NULL)
+ return (-ENOMEM);
+ memset (m, 0, sizeof (*m));
+
+ sstrncpy (m->name, name, sizeof (m->name));
+ memcpy (&m->proc, &proc, sizeof (m->proc));
+ m->next = NULL;
+
+ if (match_list_head == NULL)
+ {
+ match_list_head = m;
+ }
+ else
+ {
+ fc_match_t *ptr;
+
+ ptr = match_list_head;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = m;
+ }
+
+ return (0);
+} /* }}} int fc_register_match */
+
+/* Add a target to list of available targets. */
+int fc_register_target (const char *name, target_proc_t proc) /* {{{ */
+{
+ fc_target_t *t;
+
+ DEBUG ("fc_register_target (%s);", name);
+
+ t = (fc_target_t *) malloc (sizeof (*t));
+ if (t == NULL)
+ return (-ENOMEM);
+ memset (t, 0, sizeof (*t));
+
+ sstrncpy (t->name, name, sizeof (t->name));
+ memcpy (&t->proc, &proc, sizeof (t->proc));
+ t->next = NULL;
+
+ if (target_list_head == NULL)
+ {
+ target_list_head = t;
+ }
+ else
+ {
+ fc_target_t *ptr;
+
+ ptr = target_list_head;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = t;
+ }
+
+ return (0);
+} /* }}} int fc_register_target */
+
+/* Iterate over all rules in the chain and execute all targets for which all
+ * matches match. */
+int fc_process (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+ fc_chain_t *chain;
+
+ for (chain = chain_list_head; chain != NULL; chain = chain->next)
+ if (strcasecmp ("Main", chain->name) == 0)
+ break;
+
+ if (chain != NULL)
+ return (fc_process_chain (ds, vl, chain));
+
+ return (fc_bit_write_invoke (ds, vl,
+ /* meta = */ NULL, /* user_data = */ NULL));
+} /* }}} int fc_process */
+
+int fc_configure (const oconfig_item_t *ci) /* {{{ */
+{
+ fc_init_once ();
+
+ if (ci == NULL)
+ return (-EINVAL);
+
+ if (strcasecmp ("Chain", ci->key) == 0)
+ return (fc_config_add_chain (ci));
+
+ WARNING ("Filter subsystem: Unknown top level config option `%s'.",
+ ci->key);
+
+ return (-1);
+} /* }}} int fc_configure */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
--- /dev/null
+/**
+ * collectd - src/filter_chain.h
+ * 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 verplant.org>
+ **/
+
+#ifndef FILTER_CHAIN_H
+#define FILTER_CHAIN_H 1
+
+#include "collectd.h"
+#include "plugin.h"
+
+#define FC_MATCH_NO_MATCH 0
+#define FC_MATCH_MATCHES 1
+
+#define FC_TARGET_CONTINUE 0
+#define FC_TARGET_STOP 1
+#define FC_TARGET_RETURN 2
+
+/*
+ * Match functions
+ */
+struct match_proc_s
+{
+ int (*create) (const oconfig_item_t *ci, void **user_data);
+ int (*destroy) (void **user_data);
+ int (*match) (const data_set_t *ds, const value_list_t *vl,
+ notification_meta_t **meta, void **user_data);
+};
+typedef struct match_proc_s match_proc_t;
+
+int fc_register_match (const char *name, match_proc_t proc);
+
+/*
+ * Target functions
+ */
+struct target_proc_s
+{
+ int (*create) (const oconfig_item_t *ci, void **user_data);
+ int (*destroy) (void **user_data);
+ int (*invoke) (const data_set_t *ds, value_list_t *vl,
+ notification_meta_t **meta, void **user_data);
+};
+typedef struct target_proc_s target_proc_t;
+
+int fc_register_target (const char *name, target_proc_t proc);
+
+/*
+ * TODO: Chain management
+ */
+#if 0
+int fc_chain_add (const char *chain_name,
+ const char *target_name, int target_argc, char **target_argv);
+int fc_chain_delete (const char *chain_name);
+#endif
+
+/*
+ * TODO: Rule management
+ */
+#if 0
+int fc_rule_add (const char *chain_name, int position,
+ int match_num, const char **match_name, int *match_argc, char ***match_argv,
+ const char *target_name, int target_argc, char **target_argv);
+int fc_rule_delete (const char *chain_name, int position);
+#endif
+
+/*
+ * Processing function
+ */
+int fc_process (const data_set_t *ds, value_list_t *vl);
+
+/*
+ * Shortcut for global configuration
+ */
+int fc_configure (const oconfig_item_t *ci);
+
+#endif /* FILTER_CHAIN_H */
+/* vim: set sw=2 sts=2 et : */
--- /dev/null
+/**
+ * collectd - src/entropy.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 verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+#include "utils_ignorelist.h"
+
+/*
+ * Variables
+ */
+static ignorelist_t *il_host = NULL;
+static ignorelist_t *il_plugin = NULL;
+static ignorelist_t *il_type = NULL;
+
+static const char *config_keys[] =
+{
+ "IgnoreHost",
+ "IgnorePlugin",
+ "IgnoreType"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+/*
+ * Functions
+ */
+static int ignorelist_add_create (ignorelist_t **il_ptr, const char *entry)
+{
+ ignorelist_t *il;
+ int status;
+
+ il = *il_ptr;
+
+ if (il == NULL)
+ {
+ il = ignorelist_create (/* ignore = */ 0);
+ if (il == NULL)
+ {
+ ERROR ("filter_ignore plugin: ignorelist_create failed.");
+ return (-1);
+ }
+ *il_ptr = il;
+ }
+
+ status = ignorelist_add (il, entry);
+ if (status != 0)
+ {
+ ERROR ("filter_ignore plugin: ignorelist_add failed with error %i.",
+ status);
+ return (status);
+ }
+
+ return (0);
+} /* int ignorelist_add_create */
+
+static int fi_config (const char *key, const char *value)
+{
+ int status;
+
+ status = 0;
+
+ if (strcasecmp ("IgnoreHost", key) == 0)
+ status = ignorelist_add_create (&il_host, value);
+ else if (strcasecmp ("IgnorePlugin", key) == 0)
+ status = ignorelist_add_create (&il_plugin, value);
+ else if (strcasecmp ("IgnoreType", key) == 0)
+ status = ignorelist_add_create (&il_type, value);
+ else
+ return (-1);
+
+ if (status < 0)
+ status = status * (-1);
+
+ return (status);
+} /* int fi_config */
+
+static int fi_filter (const data_set_t *ds, value_list_t *vl)
+{
+ int status;
+
+ if (il_host != NULL)
+ {
+ status = ignorelist_match (il_host, vl->host);
+ if (status != 0)
+ return (FILTER_IGNORE);
+ }
+
+ if (il_plugin != NULL)
+ {
+ char buffer[2 * DATA_MAX_NAME_LEN];
+
+ if (vl->plugin_instance[0] == 0)
+ sstrncpy (buffer, vl->plugin, sizeof (buffer));
+ else
+ ssnprintf (buffer, sizeof (buffer), "%s-%s",
+ vl->plugin, vl->plugin_instance);
+
+ status = ignorelist_match (il_plugin, buffer);
+ if (status != 0)
+ return (FILTER_IGNORE);
+ }
+
+ if (il_type != NULL)
+ {
+ char buffer[2 * DATA_MAX_NAME_LEN];
+
+ if (vl->type_instance[0] == 0)
+ sstrncpy (buffer, vl->type, sizeof (buffer));
+ else
+ ssnprintf (buffer, sizeof (buffer), "%s-%s",
+ vl->type, vl->type_instance);
+
+ status = ignorelist_match (il_type, buffer);
+ if (status != 0)
+ return (FILTER_IGNORE);
+ }
+
+ return (0);
+} /* int fi_filter */
+
+void module_register (void)
+{
+ plugin_register_config ("filter_ignore", fi_config,
+ config_keys, config_keys_num);
+ plugin_register_filter ("filter_ignore", fi_filter);
+} /* void module_register */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
#include "common.h"
#include "plugin.h"
#include "configfile.h"
+#include "utils_ignorelist.h"
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
};
static int config_keys_num = 2;
-static char **if_list = NULL;
-static int if_list_num = 0;
-/*
- * if_list_action:
- * 0 => default is to collect selected interface
- * 1 => ignore selcted interfaces
- */
-static int if_list_action = 0;
+static ignorelist_t *ignorelist = NULL;
#ifdef HAVE_LIBKSTAT
#define MAX_NUMIF 256
static int interface_config (const char *key, const char *value)
{
- char **temp;
+ if (ignorelist == NULL)
+ ignorelist = ignorelist_create (/* invert = */ 1);
if (strcasecmp (key, "Interface") == 0)
{
- temp = (char **) realloc (if_list, (if_list_num + 1) * sizeof (char *));
- if (temp == NULL)
- {
- ERROR ("Cannot allocate more memory.");
- return (1);
- }
- if_list = temp;
-
- if ((if_list[if_list_num] = strdup (value)) == NULL)
- {
- ERROR ("Cannot allocate memory.");
- return (1);
- }
- if_list_num++;
+ ignorelist_add (ignorelist, value);
}
else if (strcasecmp (key, "IgnoreSelected") == 0)
{
+ int invert = 1;
if ((strcasecmp (value, "True") == 0)
|| (strcasecmp (value, "Yes") == 0)
|| (strcasecmp (value, "On") == 0))
- if_list_action = 1;
- else
- if_list_action = 0;
+ invert = 0;
+ ignorelist_set_invert (ignorelist, invert);
}
else
{
} /* int interface_init */
#endif /* HAVE_LIBKSTAT */
-/*
- * Check if this interface/instance should be ignored. This is called from
- * both, `submit' and `write' to give client and server the ability to
- * ignore certain stuff..
- */
-static int check_ignore_if (const char *interface)
-{
- int i;
-
- /* If no interfaces are given collect all interfaces. Mostly to be
- * backwards compatible, but also because this is much easier. */
- if (if_list_num < 1)
- return (0);
-
- for (i = 0; i < if_list_num; i++)
- if (strcasecmp (interface, if_list[i]) == 0)
- return (if_list_action);
- return (1 - if_list_action);
-} /* int check_ignore_if */
-
static void if_submit (const char *dev, const char *type,
unsigned long long rx,
unsigned long long tx)
value_t values[2];
value_list_t vl = VALUE_LIST_INIT;
- if (check_ignore_if (dev))
+ if (ignorelist_match (ignorelist, dev) != 0)
return;
values[0].counter = rx;
--- /dev/null
+AUTOMAKE_OPTIONS = foreign no-dependencies
+
+pkginclude_HEADERS = client.h
+lib_LTLIBRARIES = libcollectdclient.la
+
+libcollectdclient_la_SOURCES = client.c
+libcollectdclient_la_LDFLAGS = -version-info 0:0:0
--- /dev/null
+/**
+ * libcollectdclient - src/libcollectdclient/client.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 verplant.org>
+ **/
+
+/* Set to C99 and POSIX code */
+#ifndef _ISOC99_SOURCE
+# define _ISOC99_SOURCE
+#endif
+#ifndef _POSIX_SOURCE
+# define _POSIX_SOURCE
+#endif
+#ifndef _POSIX_C_SOURCE
+# define _POSIX_C_SOURCE 200112L
+#endif
+#ifndef _REENTRANT
+# define _REENTRANT
+#endif
+
+/* Disable non-standard extensions */
+#ifdef _BSD_SOURCE
+# undef _BSD_SOURCE
+#endif
+#ifdef _SVID_SOURCE
+# undef _SVID_SOURCE
+#endif
+#ifdef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+
+#if !defined(__GNUC__) || !__GNUC__
+# define __attribute__(x) /**/
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <netdb.h>
+
+#include "client.h"
+
+/* NI_MAXHOST has been obsoleted by RFC 3493 which is a reason for SunOS 5.11
+ * to no longer define it. We'll use the old, RFC 2553 value here. */
+#ifndef NI_MAXHOST
+# define NI_MAXHOST 1025
+#endif
+
+/* Secure/static macros. They work like `strcpy' and `strcat', but assure null
+ * termination. They work for static buffers only, because they use `sizeof'.
+ * The `SSTRCATF' combines the functionality of `snprintf' and `strcat' which
+ * is very useful to add formatted stuff to the end of a buffer. */
+#define SSTRCPY(d,s) do { \
+ strncpy ((d), (s), sizeof (d)); \
+ (d)[sizeof (d) - 1] = 0; \
+ } while (0)
+
+#define SSTRCAT(d,s) do { \
+ strncat ((d), (s), sizeof (d)); \
+ (d)[sizeof (d) - 1] = 0; \
+ } while (0)
+
+#define SSTRCATF(d, ...) do { \
+ char _b[sizeof (d)]; \
+ snprintf (_b, sizeof (_b), __VA_ARGS__); \
+ _b[sizeof (_b) - 1] = 0; \
+ SSTRCAT ((d), _b); \
+ } while (0)
+
+
+#define LCC_SET_ERRSTR(c, ...) do { \
+ snprintf ((c)->errbuf, sizeof ((c)->errbuf), __VA_ARGS__); \
+ (c)->errbuf[sizeof ((c)->errbuf) - 1] = 0; \
+} while (0)
+
+#if 1
+# define LCC_DEBUG(...) printf (__VA_ARGS__)
+#else
+# define LCC_DEBUG(...) /**/
+#endif
+
+/*
+ * Types
+ */
+struct lcc_connection_s
+{
+ FILE *fh;
+ char errbuf[1024];
+};
+
+struct lcc_response_s
+{
+ int status;
+ char message[1024];
+ char **lines;
+ size_t lines_num;
+};
+typedef struct lcc_response_s lcc_response_t;
+
+/*
+ * Private functions
+ */
+static int lcc_set_errno (lcc_connection_t *c, int err) /* {{{ */
+{
+ if (c == NULL)
+ return (-1);
+
+ strerror_r (err, c->errbuf, sizeof (c->errbuf));
+ c->errbuf[sizeof (c->errbuf) - 1] = 0;
+
+ return (0);
+} /* }}} int lcc_set_errno */
+
+/* lcc_strdup: Since `strdup' is an XSI extension, we provide our own version
+ * here. */
+__attribute__((malloc, nonnull (1)))
+static char *lcc_strdup (const char *str) /* {{{ */
+{
+ size_t strsize;
+ char *ret;
+
+ strsize = strlen (str) + 1;
+ ret = (char *) malloc (strsize);
+ if (ret != NULL)
+ memcpy (ret, str, strsize);
+ return (ret);
+} /* }}} char *lcc_strdup */
+
+__attribute__((nonnull (1, 2)))
+static char *lcc_strescape (char *dest, char *src, size_t dest_size) /* {{{ */
+{
+ size_t dest_pos;
+ size_t src_pos;
+
+ dest_pos = 0;
+ src_pos = 0;
+
+ assert (dest_size >= 3);
+
+ dest[dest_pos] = '"';
+ dest_pos++;
+
+ while (42)
+ {
+ if ((dest_pos == (dest_size - 2))
+ || (src[src_pos] == 0))
+ break;
+
+ if ((src[src_pos] == '"') || (src[src_pos] == '\\'))
+ {
+ /* Check if there is enough space for both characters.. */
+ if (dest_pos == (dest_size - 3))
+ break;
+
+ dest[dest_pos] = '\\';
+ dest_pos++;
+ }
+
+ dest[dest_pos] = src[src_pos];
+ dest_pos++;
+ src_pos++;
+ }
+
+ assert (dest_pos <= (dest_size - 2));
+
+ dest[dest_pos] = '"';
+ dest_pos++;
+
+ dest[dest_pos] = 0;
+ dest_pos++;
+ src_pos++;
+
+ return (dest);
+} /* }}} char *lcc_strescape */
+
+/* lcc_chomp: Removes all control-characters at the end of a string. */
+static void lcc_chomp (char *str) /* {{{ */
+{
+ size_t str_len;
+
+ str_len = strlen (str);
+ while (str_len > 0)
+ {
+ if (str[str_len - 1] >= 32)
+ break;
+ str[str_len - 1] = 0;
+ str_len--;
+ }
+} /* }}} void lcc_chomp */
+
+static void lcc_response_free (lcc_response_t *res) /* {{{ */
+{
+ size_t i;
+
+ if (res == NULL)
+ return;
+
+ for (i = 0; i < res->lines_num; i++)
+ free (res->lines[i]);
+ free (res->lines);
+ res->lines = NULL;
+} /* }}} void lcc_response_free */
+
+static int lcc_send (lcc_connection_t *c, const char *command) /* {{{ */
+{
+ int status;
+
+ LCC_DEBUG ("send: --> %s\n", command);
+
+ status = fprintf (c->fh, "%s\r\n", command);
+ if (status < 0)
+ {
+ lcc_set_errno (c, errno);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int lcc_send */
+
+static int lcc_receive (lcc_connection_t *c, /* {{{ */
+ lcc_response_t *ret_res)
+{
+ lcc_response_t res;
+ char *ptr;
+ char buffer[4096];
+ size_t i;
+
+ memset (&res, 0, sizeof (res));
+
+ /* Read the first line, containing the status and a message */
+ ptr = fgets (buffer, sizeof (buffer), c->fh);
+ if (ptr == NULL)
+ {
+ lcc_set_errno (c, errno);
+ return (-1);
+ }
+ lcc_chomp (buffer);
+ LCC_DEBUG ("receive: <-- %s\n", buffer);
+
+ /* Convert the leading status to an integer and make `ptr' to point to the
+ * beginning of the message. */
+ ptr = NULL;
+ errno = 0;
+ res.status = strtol (buffer, &ptr, 0);
+ if ((errno != 0) || (ptr == &buffer[0]))
+ {
+ lcc_set_errno (c, errno);
+ return (-1);
+ }
+
+ /* Skip white spaces after the status number */
+ while ((*ptr == ' ') || (*ptr == '\t'))
+ ptr++;
+
+ /* Now copy the message. */
+ strncpy (res.message, ptr, sizeof (res.message));
+ res.message[sizeof (res.message) - 1] = 0;
+
+ /* Error or no lines follow: We're done. */
+ if (res.status <= 0)
+ {
+ memcpy (ret_res, &res, sizeof (res));
+ return (0);
+ }
+
+ /* Allocate space for the char-pointers */
+ res.lines_num = (size_t) res.status;
+ res.status = 0;
+ res.lines = (char **) malloc (res.lines_num * sizeof (char *));
+ if (res.lines == NULL)
+ {
+ lcc_set_errno (c, ENOMEM);
+ return (-1);
+ }
+
+ /* Now receive all the lines */
+ for (i = 0; i < res.lines_num; i++)
+ {
+ ptr = fgets (buffer, sizeof (buffer), c->fh);
+ if (ptr == NULL)
+ {
+ lcc_set_errno (c, errno);
+ break;
+ }
+ lcc_chomp (buffer);
+ LCC_DEBUG ("receive: <-- %s\n", buffer);
+
+ res.lines[i] = lcc_strdup (buffer);
+ if (res.lines[i] == NULL)
+ {
+ lcc_set_errno (c, ENOMEM);
+ break;
+ }
+ }
+
+ /* Check if the for-loop exited with an error. */
+ if (i < res.lines_num)
+ {
+ while (i > 0)
+ {
+ i--;
+ free (res.lines[i]);
+ }
+ free (res.lines);
+ return (-1);
+ }
+
+ memcpy (ret_res, &res, sizeof (res));
+ return (0);
+} /* }}} int lcc_receive */
+
+static int lcc_sendreceive (lcc_connection_t *c, /* {{{ */
+ const char *command, lcc_response_t *ret_res)
+{
+ lcc_response_t res;
+ int status;
+
+ status = lcc_send (c, command);
+ if (status != 0)
+ return (status);
+
+ memset (&res, 0, sizeof (res));
+ status = lcc_receive (c, &res);
+ if (status == 0)
+ memcpy (ret_res, &res, sizeof (*ret_res));
+
+ return (status);
+} /* }}} int lcc_sendreceive */
+
+static int lcc_open_unixsocket (lcc_connection_t *c, const char *path) /* {{{ */
+{
+ struct sockaddr_un sa;
+ int fd;
+ int status;
+
+ assert (c != NULL);
+ assert (c->fh == NULL);
+ assert (path != NULL);
+
+ fd = socket (PF_UNIX, SOCK_STREAM, /* protocol = */ 0);
+ if (fd < 0)
+ {
+ lcc_set_errno (c, errno);
+ return (-1);
+ }
+
+ memset (&sa, 0, sizeof (sa));
+ sa.sun_family = AF_UNIX;
+ strncpy (sa.sun_path, path, sizeof (sa.sun_path) - 1);
+
+ status = connect (fd, (struct sockaddr *) &sa, sizeof (sa));
+ if (status != 0)
+ {
+ lcc_set_errno (c, errno);
+ close (fd);
+ return (-1);
+ }
+
+ c->fh = fdopen (fd, "r+");
+ if (c->fh == NULL)
+ {
+ lcc_set_errno (c, errno);
+ close (fd);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int lcc_open_unixsocket */
+
+static int lcc_open_netsocket (lcc_connection_t *c, /* {{{ */
+ const char *addr_orig)
+{
+ struct addrinfo ai_hints;
+ struct addrinfo *ai_res;
+ struct addrinfo *ai_ptr;
+ char addr_copy[NI_MAXHOST];
+ char *addr;
+ char *port;
+ int fd;
+ int status;
+
+ assert (c != NULL);
+ assert (c->fh == NULL);
+ assert (addr_orig != NULL);
+
+ strncpy(addr_copy, addr_orig, sizeof(addr_copy));
+ addr_copy[sizeof(addr_copy) - 1] = '\0';
+ addr = addr_copy;
+
+ memset (&ai_hints, 0, sizeof (ai_hints));
+ ai_hints.ai_flags = 0;
+#ifdef AI_ADDRCONFIG
+ ai_hints.ai_flags |= AI_ADDRCONFIG;
+#endif
+ ai_hints.ai_family = AF_UNSPEC;
+ ai_hints.ai_socktype = SOCK_STREAM;
+
+ port = NULL;
+ if (*addr == '[') /* IPv6+port format */
+ {
+ /* `addr' is something like "[2001:780:104:2:211:24ff:feab:26f8]:12345" */
+ addr++;
+
+ port = strchr (addr, ']');
+ if (port == NULL)
+ {
+ LCC_SET_ERRSTR (c, "malformed address: %s", addr_orig);
+ return (-1);
+ }
+ *port = 0;
+ port++;
+
+ if (*port == ':')
+ port++;
+ else if (*port == 0)
+ port = NULL;
+ else
+ {
+ LCC_SET_ERRSTR (c, "garbage after address: %s", port);
+ return (-1);
+ }
+ } /* if (*addr = ']') */
+ else if (strchr (addr, '.') != NULL) /* Hostname or IPv4 */
+ {
+ port = strrchr (addr, ':');
+ if (port != NULL)
+ {
+ *port = 0;
+ port++;
+ }
+ }
+
+ ai_res = NULL;
+ status = getaddrinfo (addr,
+ port == NULL ? LCC_DEFAULT_PORT : port,
+ &ai_hints, &ai_res);
+ if (status != 0)
+ {
+ LCC_SET_ERRSTR (c, "getaddrinfo: %s", gai_strerror (status));
+ return (-1);
+ }
+
+ for (ai_ptr = ai_res; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
+ {
+ fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
+ if (fd < 0)
+ {
+ status = errno;
+ fd = -1;
+ continue;
+ }
+
+ status = connect (fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
+ if (status != 0)
+ {
+ status = errno;
+ close (fd);
+ fd = -1;
+ continue;
+ }
+
+ c->fh = fdopen (fd, "r+");
+ if (c->fh == NULL)
+ {
+ status = errno;
+ close (fd);
+ fd = -1;
+ continue;
+ }
+
+ assert (status == 0);
+ break;
+ } /* for (ai_ptr) */
+
+ if (status != 0)
+ {
+ lcc_set_errno (c, status);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int lcc_open_netsocket */
+
+static int lcc_open_socket (lcc_connection_t *c, const char *addr) /* {{{ */
+{
+ int status = 0;
+
+ if (addr == NULL)
+ return (-1);
+
+ assert (c != NULL);
+ assert (c->fh == NULL);
+ assert (addr != NULL);
+
+ if (strncmp ("unix:", addr, strlen ("unix:")) == 0)
+ status = lcc_open_unixsocket (c, addr + strlen ("unix:"));
+ else if (addr[0] == '/')
+ status = lcc_open_unixsocket (c, addr);
+ else
+ status = lcc_open_netsocket (c, addr);
+
+ return (status);
+} /* }}} int lcc_open_socket */
+
+/*
+ * Public functions
+ */
+int lcc_connect (const char *address, lcc_connection_t **ret_con) /* {{{ */
+{
+ lcc_connection_t *c;
+
+ if (address == NULL)
+ return (-1);
+
+ if (ret_con == NULL)
+ return (-1);
+
+ c = (lcc_connection_t *) malloc (sizeof (*c));
+ if (c == NULL)
+ return (-1);
+ memset (c, 0, sizeof (*c));
+
+ *ret_con = c;
+ return (lcc_open_socket (c, address));
+} /* }}} int lcc_connect */
+
+int lcc_disconnect (lcc_connection_t *c) /* {{{ */
+{
+ if (c == NULL)
+ return (-1);
+
+ if (c->fh != NULL)
+ {
+ fclose (c->fh);
+ c->fh = NULL;
+ }
+
+ free (c);
+ return (0);
+} /* }}} int lcc_disconnect */
+
+int lcc_getval (lcc_connection_t *c, lcc_identifier_t *ident, /* {{{ */
+ size_t *ret_values_num, gauge_t **ret_values, char ***ret_values_names)
+{
+ char ident_str[6 * LCC_NAME_LEN];
+ char ident_esc[12 * LCC_NAME_LEN];
+ char command[14 * LCC_NAME_LEN];
+
+ lcc_response_t res;
+ size_t values_num;
+ gauge_t *values = NULL;
+ char **values_names = NULL;
+
+ size_t i;
+ int status;
+
+ if (c == NULL)
+ return (-1);
+
+ if (ident == NULL)
+ {
+ lcc_set_errno (c, EINVAL);
+ return (-1);
+ }
+
+ /* Build a commend with an escaped version of the identifier string. */
+ status = lcc_identifier_to_string (c, ident_str, sizeof (ident_str), ident);
+ if (status != 0)
+ return (status);
+
+ snprintf (command, sizeof (command), "GETVAL %s",
+ lcc_strescape (ident_esc, ident_str, sizeof (ident_esc)));
+ command[sizeof (command) - 1] = 0;
+
+ /* Send talk to the daemon.. */
+ status = lcc_sendreceive (c, command, &res);
+ if (status != 0)
+ return (status);
+
+ if (res.status != 0)
+ {
+ LCC_SET_ERRSTR (c, "Server error: %s", res.message);
+ lcc_response_free (&res);
+ return (-1);
+ }
+
+ values_num = res.lines_num;
+
+#define BAIL_OUT(e) do { \
+ lcc_set_errno (c, (e)); \
+ free (values); \
+ if (values_names != NULL) { \
+ for (i = 0; i < values_num; i++) { \
+ free (values_names[i]); \
+ } \
+ } \
+ free (values_names); \
+ lcc_response_free (&res); \
+ return (-1); \
+} while (0)
+
+ /* If neither the values nor the names are requested, return here.. */
+ if ((ret_values == NULL) && (ret_values_names == NULL))
+ {
+ if (ret_values_num != NULL)
+ *ret_values_num = values_num;
+ lcc_response_free (&res);
+ return (0);
+ }
+
+ /* Allocate space for the values */
+ if (ret_values != NULL)
+ {
+ values = (gauge_t *) malloc (values_num * sizeof (*values));
+ if (values == NULL)
+ BAIL_OUT (ENOMEM);
+ }
+
+ if (ret_values_names != NULL)
+ {
+ values_names = (char **) calloc (values_num, sizeof (*values_names));
+ if (values_names == NULL)
+ BAIL_OUT (ENOMEM);
+ }
+
+ for (i = 0; i < res.lines_num; i++)
+ {
+ char *key;
+ char *value;
+ char *endptr;
+
+ key = res.lines[i];
+ value = strchr (key, '=');
+ if (value == NULL)
+ BAIL_OUT (EPROTO);
+
+ *value = 0;
+ value++;
+
+ if (values != NULL)
+ {
+ endptr = NULL;
+ errno = 0;
+ values[i] = strtod (value, &endptr);
+
+ if ((endptr == value) || (errno != 0))
+ BAIL_OUT (errno);
+ }
+
+ if (values_names != NULL)
+ {
+ values_names[i] = lcc_strdup (key);
+ if (values_names[i] == NULL)
+ BAIL_OUT (ENOMEM);
+ }
+ } /* for (i = 0; i < res.lines_num; i++) */
+
+ if (ret_values_num != NULL)
+ *ret_values_num = values_num;
+ if (ret_values != NULL)
+ *ret_values = values;
+ if (ret_values_names != NULL)
+ *ret_values_names = values_names;
+
+ return (0);
+} /* }}} int lcc_getval */
+
+int lcc_putval (lcc_connection_t *c, const lcc_value_list_t *vl) /* {{{ */
+{
+ char ident_str[6 * LCC_NAME_LEN];
+ char ident_esc[12 * LCC_NAME_LEN];
+ char command[1024] = "";
+ lcc_response_t res;
+ int status;
+ size_t i;
+
+ if ((c == NULL) || (vl == NULL) || (vl->values_len < 1)
+ || (vl->values == NULL) || (vl->values_types == NULL))
+ {
+ lcc_set_errno (c, EINVAL);
+ return (-1);
+ }
+
+ status = lcc_identifier_to_string (c, ident_str, sizeof (ident_str),
+ &vl->identifier);
+ if (status != 0)
+ return (status);
+
+ SSTRCATF (command, "PUTVAL %s",
+ lcc_strescape (ident_esc, ident_str, sizeof (ident_esc)));
+
+ if (vl->interval > 0)
+ SSTRCATF (command, " interval=%i", vl->interval);
+
+ if (vl->time > 0)
+ SSTRCATF (command, "%u", (unsigned int) vl->time);
+ else
+ SSTRCAT (command, "N");
+
+ for (i = 0; i < vl->values_len; i++)
+ {
+ if (vl->values_types[i] == LCC_TYPE_COUNTER)
+ SSTRCATF (command, ":%"PRIu64, vl->values[i].counter);
+ else if (vl->values_types[i] == LCC_TYPE_GAUGE)
+ {
+ if (isnan (vl->values[i].gauge))
+ SSTRCPY (command, ":U");
+ else
+ SSTRCATF (command, ":%g", vl->values[i].gauge);
+ }
+ } /* for (i = 0; i < vl->values_len; i++) */
+
+ status = lcc_sendreceive (c, command, &res);
+ if (status != 0)
+ return (status);
+
+ if (res.status != 0)
+ {
+ LCC_SET_ERRSTR (c, "Server error: %s", res.message);
+ lcc_response_free (&res);
+ return (-1);
+ }
+
+ lcc_response_free (&res);
+ return (0);
+} /* }}} int lcc_putval */
+
+int lcc_flush (lcc_connection_t *c, const char *plugin, /* {{{ */
+ lcc_identifier_t *ident, int timeout)
+{
+ char command[1024];
+ lcc_response_t res;
+ int status;
+
+ if (c == NULL)
+ {
+ lcc_set_errno (c, EINVAL);
+ return (-1);
+ }
+
+ SSTRCPY (command, "FLUSH");
+
+ if (timeout > 0)
+ SSTRCATF (command, " timeout=%i", timeout);
+
+ if (plugin != NULL)
+ {
+ char buffer[2 * LCC_NAME_LEN];
+ SSTRCATF (command, " plugin=%s",
+ lcc_strescape (buffer, plugin, sizeof (buffer)));
+ }
+
+ if (ident != NULL)
+ {
+ char ident_str[6 * LCC_NAME_LEN];
+ char ident_esc[12 * LCC_NAME_LEN];
+
+ status = lcc_identifier_to_string (c, ident_str, sizeof (ident_str), ident);
+ if (status != 0)
+ return (status);
+
+ SSTRCATF (command, " identifier=%s",
+ lcc_strescape (ident_esc, ident_str, sizeof (ident_esc)));
+ }
+
+ status = lcc_sendreceive (c, command, &res);
+ if (status != 0)
+ return (status);
+
+ if (res.status != 0)
+ {
+ LCC_SET_ERRSTR (c, "Server error: %s", res.message);
+ lcc_response_free (&res);
+ return (-1);
+ }
+
+ lcc_response_free (&res);
+ return (0);
+} /* }}} int lcc_flush */
+
+/* TODO: Implement lcc_putnotif */
+
+int lcc_listval (lcc_connection_t *c, /* {{{ */
+ lcc_identifier_t **ret_ident, size_t *ret_ident_num)
+{
+ lcc_response_t res;
+ size_t i;
+ int status;
+
+ lcc_identifier_t *ident;
+ size_t ident_num;
+
+ if (c == NULL)
+ return (-1);
+
+ if ((ret_ident == NULL) || (ret_ident_num == NULL))
+ {
+ lcc_set_errno (c, EINVAL);
+ return (-1);
+ }
+
+ status = lcc_sendreceive (c, "LISTVAL", &res);
+ if (status != 0)
+ return (status);
+
+ if (res.status != 0)
+ {
+ LCC_SET_ERRSTR (c, "Server error: %s", res.message);
+ lcc_response_free (&res);
+ return (-1);
+ }
+
+ ident_num = res.lines_num;
+ ident = (lcc_identifier_t *) malloc (ident_num * sizeof (*ident));
+ if (ident == NULL)
+ {
+ lcc_response_free (&res);
+ lcc_set_errno (c, ENOMEM);
+ return (-1);
+ }
+
+ for (i = 0; i < res.lines_num; i++)
+ {
+ char *time_str;
+ char *ident_str;
+
+ /* First field is the time. */
+ time_str = res.lines[i];
+
+ /* Set `ident_str' to the beginning of the second field. */
+ ident_str = time_str;
+ while ((*ident_str != ' ') && (*ident_str != '\t') && (*ident_str != 0))
+ ident_str++;
+ while ((*ident_str == ' ') || (*ident_str == '\t'))
+ {
+ *ident_str = 0;
+ ident_str++;
+ }
+
+ if (*ident_str == 0)
+ {
+ lcc_set_errno (c, EPROTO);
+ status = -1;
+ break;
+ }
+
+ status = lcc_string_to_identifier (c, ident + i, ident_str);
+ if (status != 0)
+ break;
+ }
+
+ lcc_response_free (&res);
+
+ if (status != 0)
+ {
+ free (ident);
+ return (-1);
+ }
+
+ *ret_ident = ident;
+ *ret_ident_num = ident_num;
+
+ return (0);
+} /* }}} int lcc_listval */
+
+const char *lcc_strerror (lcc_connection_t *c) /* {{{ */
+{
+ if (c == NULL)
+ return ("Invalid object");
+ return (c->errbuf);
+} /* }}} const char *lcc_strerror */
+
+int lcc_identifier_to_string (lcc_connection_t *c, /* {{{ */
+ char *string, size_t string_size, const lcc_identifier_t *ident)
+{
+ if ((string == NULL) || (string_size < 6) || (ident == NULL))
+ {
+ lcc_set_errno (c, EINVAL);
+ return (-1);
+ }
+
+ if (ident->plugin_instance[0] == 0)
+ {
+ if (ident->type_instance[0] == 0)
+ snprintf (string, string_size, "%s/%s/%s",
+ ident->host,
+ ident->plugin,
+ ident->type);
+ else
+ snprintf (string, string_size, "%s/%s/%s-%s",
+ ident->host,
+ ident->plugin,
+ ident->type,
+ ident->type_instance);
+ }
+ else
+ {
+ if (ident->type_instance[0] == 0)
+ snprintf (string, string_size, "%s/%s-%s/%s",
+ ident->host,
+ ident->plugin,
+ ident->plugin_instance,
+ ident->type);
+ else
+ snprintf (string, string_size, "%s/%s-%s/%s-%s",
+ ident->host,
+ ident->plugin,
+ ident->plugin_instance,
+ ident->type,
+ ident->type_instance);
+ }
+
+ string[string_size - 1] = 0;
+ return (0);
+} /* }}} int lcc_identifier_to_string */
+
+int lcc_string_to_identifier (lcc_connection_t *c, /* {{{ */
+ lcc_identifier_t *ident, const char *string)
+{
+ char *string_copy;
+ char *host;
+ char *plugin;
+ char *plugin_instance;
+ char *type;
+ char *type_instance;
+
+ string_copy = lcc_strdup (string);
+ if (string_copy == NULL)
+ {
+ lcc_set_errno (c, ENOMEM);
+ return (-1);
+ }
+
+ host = string_copy;
+ plugin = strchr (host, '/');
+ if (plugin == NULL)
+ {
+ LCC_SET_ERRSTR (c, "Malformed identifier string: %s", string);
+ free (string_copy);
+ return (-1);
+ }
+ *plugin = 0;
+ plugin++;
+
+ type = strchr (plugin, '/');
+ if (type == NULL)
+ {
+ LCC_SET_ERRSTR (c, "Malformed identifier string: %s", string);
+ free (string_copy);
+ return (-1);
+ }
+ *type = 0;
+ type++;
+
+ plugin_instance = strchr (plugin, '-');
+ if (plugin_instance != NULL)
+ {
+ *plugin_instance = 0;
+ plugin_instance++;
+ }
+
+ type_instance = strchr (type, '-');
+ if (type_instance != NULL)
+ {
+ *type_instance = 0;
+ type_instance++;
+ }
+
+ memset (ident, 0, sizeof (*ident));
+
+ SSTRCPY (ident->host, host);
+ SSTRCPY (ident->plugin, plugin);
+ if (plugin_instance != NULL)
+ SSTRCPY (ident->plugin_instance, plugin_instance);
+ SSTRCPY (ident->type, type);
+ if (type_instance != NULL)
+ SSTRCPY (ident->type_instance, type_instance);
+
+ free (string_copy);
+ return (0);
+} /* }}} int lcc_string_to_identifier */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
--- /dev/null
+/**
+ * libcollectdclient - src/libcollectdclient/client.h
+ * 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 verplant.org>
+ **/
+
+#ifndef LIBCOLLECTD_COLLECTDCLIENT_H
+#define LIBCOLLECTD_COLLECTDCLIENT_H 1
+
+/*
+ * Includes (for data types)
+ */
+#include <stdint.h>
+#include <inttypes.h>
+#include <time.h>
+
+/*
+ * Defines
+ */
+#define LCC_VERSION 0
+#define LCC_NAME_LEN 64
+#define LCC_DEFAULT_PORT "25826"
+
+/*
+ * Types
+ */
+#define LCC_TYPE_COUNTER 0
+#define LCC_TYPE_GAUGE 1
+
+typedef uint64_t counter_t;
+typedef double gauge_t;
+
+union value_u
+{
+ counter_t counter;
+ gauge_t gauge;
+};
+typedef union value_u value_t;
+
+struct lcc_identifier_s
+{
+ char host[LCC_NAME_LEN];
+ char plugin[LCC_NAME_LEN];
+ char plugin_instance[LCC_NAME_LEN];
+ char type[LCC_NAME_LEN];
+ char type_instance[LCC_NAME_LEN];
+};
+typedef struct lcc_identifier_s lcc_identifier_t;
+#define LCC_IDENTIFIER_INIT { "localhost", "", "", "", "" }
+
+struct lcc_value_list_s
+{
+ value_t *values;
+ int *values_types;
+ size_t values_len;
+ time_t time;
+ int interval;
+ lcc_identifier_t identifier;
+};
+typedef struct lcc_value_list_s lcc_value_list_t;
+#define LCC_VALUE_LIST_INIT { NULL, 0, 0, 0, LCC_IDENTIFIER_INIT }
+
+struct lcc_connection_s;
+typedef struct lcc_connection_s lcc_connection_t;
+
+/*
+ * Functions
+ */
+int lcc_connect (const char *address, lcc_connection_t **ret_con);
+int lcc_disconnect (lcc_connection_t *c);
+#define LCC_DESTROY(c) do { lcc_disconnect (c); (c) = NULL; } while (0)
+
+int lcc_getval (lcc_connection_t *c, lcc_identifier_t *ident,
+ size_t *ret_values_num, gauge_t **ret_values, char ***ret_values_names);
+
+int lcc_putval (lcc_connection_t *c, const lcc_value_list_t *vl);
+
+int lcc_flush (lcc_connection_t *c, const char *plugin,
+ lcc_identifier_t *ident, int timeout);
+
+int lcc_listval (lcc_connection_t *c,
+ lcc_identifier_t **ret_ident, size_t *ret_ident_num);
+
+/* TODO: putnotif */
+
+const char *lcc_strerror (lcc_connection_t *c);
+
+int lcc_identifier_to_string (lcc_connection_t *c,
+ char *string, size_t string_size, const lcc_identifier_t *ident);
+int lcc_string_to_identifier (lcc_connection_t *c,
+ lcc_identifier_t *ident, const char *string);
+
+/* vim: set sw=2 sts=2 et : */
+#endif /* LIBCOLLECTD_COLLECTDCLIENT_H */
AUTOMAKE_OPTIONS = foreign no-dependencies
-EXTRA_DIST = libiptc.c
+EXTRA_DIST = libiptc.c README.collectd
if COMPILER_IS_GCC
AM_CFLAGS = -Wall -Werror
noinst_LTLIBRARIES = libiptc.la
-libiptc_la_CFLAGS = -DIPTABLES_VERSION=\"1.4.0\" -I$(KERNEL_DIR)/include
+libiptc_la_CFLAGS = -I$(KERNEL_DIR)/include
libiptc_la_SOURCES = libip4tc.c libip6tc.c \
ipt_kernel_headers.h libip6tc.h libiptc.h linux_list.h \
xtables.h libxtc.h
--- /dev/null
+ libiptc (IPTables Chains) in collectd
+=======================================
+http://netfilter.org/
+http://collectd.org/
+
+About
+-----
+
+ This is libiptc taken from the iptables source distribution. As it is not
+ meant to be a public interface by upstream it is not shipped in some binary
+ distributions. Thus, collectd ships its own copy as a fall-back.
+
+ The presently available version was imported from iptables 1.4.1.1.
+
+Changes to the iptables upstream sources:
+-----------------------------------------
+
+ * Added copyright headers mentioning the "Netfilter Core Team" as copyright
+ holder.
+
+ * Changed "libiptc/*" includes to "*".
+
+ * Use the shipped copy of "xtables.h" instead of the one possibly available
+ on the system.
+
int ip6tc_commit(ip6tc_handle_t *handle);
/* Get raw socket. */
-int ip6tc_get_raw_socket();
+int ip6tc_get_raw_socket(void);
/* Translates errno numbers into more human-readable form than strerror. */
const char *ip6tc_strerror(int err);
/* Return prefix length, or -1 if not contiguous */
int ipv6_prefix_length(const struct in6_addr *a);
+extern void dump_entries6(const ip6tc_handle_t);
+
#endif /* _LIBIP6TC_H */
*/
#include <sys/types.h>
#include <sys/socket.h>
+#include "xtables.h"
#include "linux_list.h"
#define DEBUGP_C(x, args...)
#endif
-#ifndef IPT_LIB_DIR
-#define IPT_LIB_DIR "/usr/local/lib/iptables"
+#ifdef DEBUG
+#define debug(x, args...) fprintf(stderr, x, ## args)
+#else
+#define debug(x, args...)
#endif
static int sockfd = -1;
struct chain_head *chain_iterator_cur;
struct rule_head *rule_iterator_cur;
+ unsigned int num_chains; /* number of user defined chains */
+
+ struct chain_head **chain_index; /* array for fast chain list access*/
+ unsigned int chain_index_sz;/* size of chain index array */
+
STRUCT_GETINFO info;
STRUCT_GET_ENTRIES *entries;
};
}
/* notify us that the ruleset has been modified by the user */
-static void
+static inline void
set_changed(TC_HANDLE_T h)
{
h->changed = 1;
/**********************************************************************
+ * Chain index (cache utility) functions
+ **********************************************************************
+ * The chain index is an array with pointers into the chain list, with
+ * CHAIN_INDEX_BUCKET_LEN spacing. This facilitates the ability to
+ * speedup chain list searching, by find a more optimal starting
+ * points when searching the linked list.
+ *
+ * The starting point can be found fast by using a binary search of
+ * the chain index. Thus, reducing the previous search complexity of
+ * O(n) to O(log(n/k) + k) where k is CHAIN_INDEX_BUCKET_LEN.
+ *
+ * A nice property of the chain index, is that the "bucket" list
+ * length is max CHAIN_INDEX_BUCKET_LEN (when just build, inserts will
+ * change this). Oppose to hashing, where the "bucket" list length can
+ * vary a lot.
+ */
+#ifndef CHAIN_INDEX_BUCKET_LEN
+#define CHAIN_INDEX_BUCKET_LEN 40
+#endif
+
+/* Another nice property of the chain index is that inserting/creating
+ * chains in chain list don't change the correctness of the chain
+ * index, it only causes longer lists in the buckets.
+ *
+ * To mitigate the performance penalty of longer bucket lists and the
+ * penalty of rebuilding, the chain index is rebuild only when
+ * CHAIN_INDEX_INSERT_MAX chains has been added.
+ */
+#ifndef CHAIN_INDEX_INSERT_MAX
+#define CHAIN_INDEX_INSERT_MAX 355
+#endif
+
+static inline unsigned int iptcc_is_builtin(struct chain_head *c);
+
+
+/* Use binary search in the chain index array, to find a chain_head
+ * pointer closest to the place of the searched name element.
+ *
+ * Notes that, binary search (obviously) requires that the chain list
+ * is sorted by name.
+ */
+static struct list_head *
+iptcc_bsearch_chain_index(const char *name, unsigned int *idx, TC_HANDLE_T handle)
+{
+ unsigned int pos, end;
+ int res;
+
+ struct list_head *list_pos;
+ list_pos=&handle->chains;
+
+ /* Check for empty array, e.g. no user defined chains */
+ if (handle->chain_index_sz == 0) {
+ debug("WARNING: handle->chain_index_sz == 0\n");
+ return list_pos;
+ }
+
+ /* Init */
+ end = handle->chain_index_sz;
+ pos = end / 2;
+
+ debug("bsearch Find chain:%s (pos:%d end:%d)\n", name, pos, end);
+
+ /* Loop */
+ loop:
+ if (!handle->chain_index[pos]) {
+ fprintf(stderr, "ERROR: NULL pointer chain_index[%d]\n", pos);
+ return &handle->chains; /* Be safe, return orig start pos */
+ }
+
+ res = strcmp(name, handle->chain_index[pos]->name);
+ list_pos = &handle->chain_index[pos]->list;
+ *idx = pos;
+
+ debug("bsearch Index[%d] name:%s res:%d ",
+ pos, handle->chain_index[pos]->name, res);
+
+ if (res == 0) { /* Found element, by direct hit */
+ debug("[found] Direct hit pos:%d end:%d\n", pos, end);
+ return list_pos;
+ } else if (res < 0) { /* Too far, jump back */
+ end = pos;
+ pos = pos / 2;
+
+ /* Exit case: First element of array */
+ if (end == 0) {
+ debug("[found] Reached first array elem (end%d)\n",end);
+ return list_pos;
+ }
+ debug("jump back to pos:%d (end:%d)\n", pos, end);
+ goto loop;
+ } else if (res > 0 ){ /* Not far enough, jump forward */
+
+ /* Exit case: Last element of array */
+ if (pos == handle->chain_index_sz-1) {
+ debug("[found] Last array elem (end:%d)\n", end);
+ return list_pos;
+ }
+
+ /* Exit case: Next index less, thus elem in this list section */
+ res = strcmp(name, handle->chain_index[pos+1]->name);
+ if (res < 0) {
+ debug("[found] closest list (end:%d)\n", end);
+ return list_pos;
+ }
+
+ pos = (pos+end)/2;
+ debug("jump forward to pos:%d (end:%d)\n", pos, end);
+ goto loop;
+ }
+
+ return list_pos;
+}
+
+#ifdef DEBUG
+/* Trivial linear search of chain index. Function used for verifying
+ the output of bsearch function */
+static struct list_head *
+iptcc_linearly_search_chain_index(const char *name, TC_HANDLE_T handle)
+{
+ unsigned int i=0;
+ int res=0;
+
+ struct list_head *list_pos;
+ list_pos = &handle->chains;
+
+ if (handle->chain_index_sz)
+ list_pos = &handle->chain_index[0]->list;
+
+ /* Linearly walk of chain index array */
+
+ for (i=0; i < handle->chain_index_sz; i++) {
+ if (handle->chain_index[i]) {
+ res = strcmp(handle->chain_index[i]->name, name);
+ if (res > 0)
+ break; // One step too far
+ list_pos = &handle->chain_index[i]->list;
+ if (res == 0)
+ break; // Direct hit
+ }
+ }
+
+ return list_pos;
+}
+#endif
+
+static int iptcc_chain_index_alloc(TC_HANDLE_T h)
+{
+ unsigned int list_length = CHAIN_INDEX_BUCKET_LEN;
+ unsigned int array_elems;
+ unsigned int array_mem;
+
+ /* Allocate memory for the chain index array */
+ array_elems = (h->num_chains / list_length) +
+ (h->num_chains % list_length ? 1 : 0);
+ array_mem = sizeof(h->chain_index) * array_elems;
+
+ debug("Alloc Chain index, elems:%d mem:%d bytes\n",
+ array_elems, array_mem);
+
+ h->chain_index = malloc(array_mem);
+ if (!h->chain_index) {
+ h->chain_index_sz = 0;
+ return -ENOMEM;
+ }
+ memset(h->chain_index, 0, array_mem);
+ h->chain_index_sz = array_elems;
+
+ return 1;
+}
+
+static void iptcc_chain_index_free(TC_HANDLE_T h)
+{
+ h->chain_index_sz = 0;
+ free(h->chain_index);
+}
+
+
+#ifdef DEBUG
+static void iptcc_chain_index_dump(TC_HANDLE_T h)
+{
+ unsigned int i = 0;
+
+ /* Dump: contents of chain index array */
+ for (i=0; i < h->chain_index_sz; i++) {
+ if (h->chain_index[i]) {
+ fprintf(stderr, "Chain index[%d].name: %s\n",
+ i, h->chain_index[i]->name);
+ }
+ }
+}
+#endif
+
+/* Build the chain index */
+static int iptcc_chain_index_build(TC_HANDLE_T h)
+{
+ unsigned int list_length = CHAIN_INDEX_BUCKET_LEN;
+ unsigned int chains = 0;
+ unsigned int cindex = 0;
+ struct chain_head *c;
+
+ /* Build up the chain index array here */
+ debug("Building chain index\n");
+
+ debug("Number of user defined chains:%d bucket_sz:%d array_sz:%d\n",
+ h->num_chains, list_length, h->chain_index_sz);
+
+ if (h->chain_index_sz == 0)
+ return 0;
+
+ list_for_each_entry(c, &h->chains, list) {
+
+ /* Issue: The index array needs to start after the
+ * builtin chains, as they are not sorted */
+ if (!iptcc_is_builtin(c)) {
+ cindex=chains / list_length;
+
+ /* Safe guard, break out on array limit, this
+ * is useful if chains are added and array is
+ * rebuild, without realloc of memory. */
+ if (cindex >= h->chain_index_sz)
+ break;
+
+ if ((chains % list_length)== 0) {
+ debug("\nIndex[%d] Chains:", cindex);
+ h->chain_index[cindex] = c;
+ }
+ chains++;
+ }
+ debug("%s, ", c->name);
+ }
+ debug("\n");
+
+ return 1;
+}
+
+static int iptcc_chain_index_rebuild(TC_HANDLE_T h)
+{
+ debug("REBUILD chain index array\n");
+ iptcc_chain_index_free(h);
+ if ((iptcc_chain_index_alloc(h)) < 0)
+ return -ENOMEM;
+ iptcc_chain_index_build(h);
+ return 1;
+}
+
+/* Delete chain (pointer) from index array. Removing an element from
+ * the chain list only affects the chain index array, if the chain
+ * index points-to/uses that list pointer.
+ *
+ * There are different strategies, the simple and safe is to rebuild
+ * the chain index every time. The more advanced is to update the
+ * array index to point to the next element, but that requires some
+ * house keeping and boundry checks. The advanced is implemented, as
+ * the simple approach behaves badly when all chains are deleted
+ * because list_for_each processing will always hit the first chain
+ * index, thus causing a rebuild for every chain.
+ */
+static int iptcc_chain_index_delete_chain(struct chain_head *c, TC_HANDLE_T h)
+{
+ struct list_head *index_ptr, *index_ptr2, *next;
+ struct chain_head *c2;
+ unsigned int idx, idx2;
+
+ index_ptr = iptcc_bsearch_chain_index(c->name, &idx, h);
+
+ debug("Del chain[%s] c->list:%p index_ptr:%p\n",
+ c->name, &c->list, index_ptr);
+
+ /* Save the next pointer */
+ next = c->list.next;
+ list_del(&c->list);
+
+ if (index_ptr == &c->list) { /* Chain used as index ptr */
+
+ /* See if its possible to avoid a rebuild, by shifting
+ * to next pointer. Its possible if the next pointer
+ * is located in the same index bucket.
+ */
+ c2 = list_entry(next, struct chain_head, list);
+ index_ptr2 = iptcc_bsearch_chain_index(c2->name, &idx2, h);
+ if (idx != idx2) {
+ /* Rebuild needed */
+ return iptcc_chain_index_rebuild(h);
+ } else {
+ /* Avoiding rebuild */
+ debug("Update cindex[%d] with next ptr name:[%s]\n",
+ idx, c2->name);
+ h->chain_index[idx]=c2;
+ return 0;
+ }
+ }
+ return 0;
+}
+
+
+/**********************************************************************
* iptc cache utility functions (iptcc_*)
**********************************************************************/
/* Is the given chain builtin (1) or user-defined (0) */
-static unsigned int iptcc_is_builtin(struct chain_head *c)
+static inline unsigned int iptcc_is_builtin(struct chain_head *c)
{
return (c->hooknum ? 1 : 0);
}
return NULL;
}
+
/* Returns chain head if found, otherwise NULL. */
static struct chain_head *
iptcc_find_label(const char *name, TC_HANDLE_T handle)
{
struct list_head *pos;
+ struct list_head *list_start_pos;
+ unsigned int i=0;
+ int res;
if (list_empty(&handle->chains))
return NULL;
+ /* First look at builtin chains */
list_for_each(pos, &handle->chains) {
struct chain_head *c = list_entry(pos, struct chain_head, list);
+ if (!iptcc_is_builtin(c))
+ break;
if (!strcmp(c->name, name))
return c;
}
+ /* Find a smart place to start the search via chain index */
+ //list_start_pos = iptcc_linearly_search_chain_index(name, handle);
+ list_start_pos = iptcc_bsearch_chain_index(name, &i, handle);
+
+ /* Handel if bsearch bails out early */
+ if (list_start_pos == &handle->chains) {
+ list_start_pos = pos;
+ }
+#ifdef DEBUG
+ else {
+ /* Verify result of bsearch against linearly index search */
+ struct list_head *test_pos;
+ struct chain_head *test_c, *tmp_c;
+ test_pos = iptcc_linearly_search_chain_index(name, handle);
+ if (list_start_pos != test_pos) {
+ debug("BUG in chain_index search\n");
+ test_c=list_entry(test_pos, struct chain_head,list);
+ tmp_c =list_entry(list_start_pos,struct chain_head,list);
+ debug("Verify search found:\n");
+ debug(" Chain:%s\n", test_c->name);
+ debug("BSearch found:\n");
+ debug(" Chain:%s\n", tmp_c->name);
+ exit(42);
+ }
+ }
+#endif
+
+ /* Initial/special case, no user defined chains */
+ if (handle->num_chains == 0)
+ return NULL;
+
+ /* Start searching through the chain list */
+ list_for_each(pos, list_start_pos->prev) {
+ struct chain_head *c = list_entry(pos, struct chain_head, list);
+ res = strcmp(c->name, name);
+ debug("List search name:%s == %s res:%d\n", name, c->name, res);
+ if (res==0)
+ return c;
+
+ /* We can stop earlier as we know list is sorted */
+ if (res>0 && !iptcc_is_builtin(c)) { /* Walked too far*/
+ debug(" Not in list, walked too far, sorted list\n");
+ return NULL;
+ }
+
+ /* Stop on wrap around, if list head is reached */
+ if (pos == &handle->chains) {
+ debug("Stop, list head reached\n");
+ return NULL;
+ }
+ }
+
+ debug("List search NOT found name:%s\n", name);
return NULL;
}
static inline void iptc_insert_chain(TC_HANDLE_T h, struct chain_head *c)
{
struct chain_head *tmp;
+ struct list_head *list_start_pos;
+ unsigned int i=1;
+
+ /* Find a smart place to start the insert search */
+ list_start_pos = iptcc_bsearch_chain_index(c->name, &i, h);
+
+ /* Handle the case, where chain.name is smaller than index[0] */
+ if (i==0 && strcmp(c->name, h->chain_index[0]->name) <= 0) {
+ h->chain_index[0] = c; /* Update chain index head */
+ list_start_pos = h->chains.next;
+ debug("Update chain_index[0] with %s\n", c->name);
+ }
+
+ /* Handel if bsearch bails out early */
+ if (list_start_pos == &h->chains) {
+ list_start_pos = h->chains.next;
+ }
/* sort only user defined chains */
if (!c->hooknum) {
- list_for_each_entry(tmp, &h->chains, list) {
+ list_for_each_entry(tmp, list_start_pos->prev, list) {
if (!tmp->hooknum && strcmp(c->name, tmp->name) <= 0) {
list_add(&c->list, tmp->list.prev);
return;
}
+
+ /* Stop if list head is reached */
+ if (&tmp->list == &h->chains) {
+ debug("Insert, list head reached add to tail\n");
+ break;
+ }
}
}
errno = -ENOMEM;
return -1;
}
+ h->num_chains++; /* New user defined chain */
__iptcc_p_add_chain(h, c, offset, num);
ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
cache_add_entry, h, &prev, &num);
+ /* Build the chain index, used for chain list search speedup */
+ if ((iptcc_chain_index_alloc(h)) < 0)
+ return -ENOMEM;
+ iptcc_chain_index_build(h);
+
/* Second pass: fixup parsed data from first pass */
list_for_each_entry(c, &h->chains, list) {
struct rule_head *r;
list_for_each_entry(r, &c->rules, list) {
- struct chain_head *c;
+ struct chain_head *lc;
STRUCT_STANDARD_TARGET *t;
if (r->type != IPTCC_R_JUMP)
continue;
t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
- c = iptcc_find_chain_by_offset(h, t->verdict);
- if (!c)
+ lc = iptcc_find_chain_by_offset(h, t->verdict);
+ if (!lc)
return -1;
- r->jump = c;
- c->references++;
+ r->jump = lc;
+ lc->references++;
}
}
return NULL;
}
sockfd_use++;
-
+retry:
s = sizeof(info);
strcpy(info.name, tablename);
return h;
error:
TC_FREE(&h);
+ /* A different process changed the ruleset size, retry */
+ if (errno == EAGAIN)
+ goto retry;
return NULL;
}
free(c);
}
+ iptcc_chain_index_free(*h);
+
free((*h)->entries);
free(*h);
CHECK(handle);
printf("libiptc v%s. %u bytes.\n",
- IPTABLES_VERSION, handle->entries->size);
+ XTABLES_VERSION, handle->entries->size);
printf("Table `%s'\n", handle->info.name);
printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
handle->info.hook_entry[HOOK_PRE_ROUTING],
}
/* How many rules in this chain? */
-unsigned int
+static unsigned int
TC_NUM_RULES(const char *chain, TC_HANDLE_T *handle)
{
struct chain_head *c;
return c->num_rules;
}
-const STRUCT_ENTRY *TC_GET_RULE(const char *chain,
- unsigned int n,
- TC_HANDLE_T *handle)
+static const STRUCT_ENTRY *
+TC_GET_RULE(const char *chain, unsigned int n, TC_HANDLE_T *handle)
{
struct chain_head *c;
struct rule_head *r;
TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
{
static struct chain_head *c;
+ int capacity;
+ int exceeded;
iptc_fn = TC_CREATE_CHAIN;
return 0;
}
+ (*handle)->num_chains++; /* New user defined chain */
DEBUGP("Creating chain `%s'\n", chain);
iptc_insert_chain(*handle, c); /* Insert sorted */
+ /* Inserting chains don't change the correctness of the chain
+ * index (except if its smaller than index[0], but that
+ * handled by iptc_insert_chain). It only causes longer lists
+ * in the buckets. Thus, only rebuild chain index when the
+ * capacity is exceed with CHAIN_INDEX_INSERT_MAX chains.
+ */
+ capacity = (*handle)->chain_index_sz * CHAIN_INDEX_BUCKET_LEN;
+ exceeded = ((((*handle)->num_chains)-capacity));
+ if (exceeded > CHAIN_INDEX_INSERT_MAX) {
+ debug("Capacity(%d) exceeded(%d) rebuild (chains:%d)\n",
+ capacity, exceeded, (*handle)->num_chains);
+ iptcc_chain_index_rebuild(*handle);
+ }
+
set_changed(*handle);
return 1;
}
/* If we are about to delete the chain that is the current
- * iterator, move chain iterator firward. */
+ * iterator, move chain iterator forward. */
if (c == (*handle)->chain_iterator_cur)
iptcc_chain_iterator_advance(*handle);
- list_del(&c->list);
+ (*handle)->num_chains--; /* One user defined chain deleted */
+
+ //list_del(&c->list); /* Done in iptcc_chain_index_delete_chain() */
+ iptcc_chain_index_delete_chain(c, *handle);
free(c);
DEBUGP("chain `%s' deleted\n", chain);
}
-static void counters_nomap(STRUCT_COUNTERS_INFO *newcounters,
- unsigned int index)
+static void counters_nomap(STRUCT_COUNTERS_INFO *newcounters, unsigned int idx)
{
- newcounters->counters[index] = ((STRUCT_COUNTERS) { 0, 0});
+ newcounters->counters[idx] = ((STRUCT_COUNTERS) { 0, 0});
DEBUGP_C("NOMAP => zero\n");
}
static void counters_normal_map(STRUCT_COUNTERS_INFO *newcounters,
- STRUCT_REPLACE *repl,
- unsigned int index,
+ STRUCT_REPLACE *repl, unsigned int idx,
unsigned int mappos)
{
/* Original read: X.
* => Add in X + Y
* => Add in replacement read.
*/
- newcounters->counters[index] = repl->counters[mappos];
+ newcounters->counters[idx] = repl->counters[mappos];
DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos);
}
static void counters_map_zeroed(STRUCT_COUNTERS_INFO *newcounters,
- STRUCT_REPLACE *repl,
- unsigned int index,
- unsigned int mappos,
- STRUCT_COUNTERS *counters)
+ STRUCT_REPLACE *repl, unsigned int idx,
+ unsigned int mappos, STRUCT_COUNTERS *counters)
{
/* Original read: X.
* Atomic read on replacement: X + Y.
* => Add in Y.
* => Add in (replacement read - original read).
*/
- subtract_counters(&newcounters->counters[index],
+ subtract_counters(&newcounters->counters[idx],
&repl->counters[mappos],
counters);
DEBUGP_C("ZEROED => mappos %u\n", mappos);
}
static void counters_map_set(STRUCT_COUNTERS_INFO *newcounters,
- unsigned int index,
- STRUCT_COUNTERS *counters)
+ unsigned int idx, STRUCT_COUNTERS *counters)
{
/* Want to set counter (iptables-restore) */
- memcpy(&newcounters->counters[index], counters,
+ memcpy(&newcounters->counters[idx], counters,
sizeof(STRUCT_COUNTERS));
DEBUGP_C("SET\n");
int iptc_commit(iptc_handle_t *handle);
/* Get raw socket. */
-int iptc_get_raw_socket();
+int iptc_get_raw_socket(void);
/* Translates errno numbers into more human-readable form than strerror. */
const char *iptc_strerror(int err);
+extern void dump_entries(const iptc_handle_t);
+
#ifdef __cplusplus
}
#endif
--- /dev/null
+/**
+ * This file was imported from the iptables sources.
+ * Copyright (C) 1999-2008 Netfilter Core Team
+ *
+ * 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
+ */
+
+#ifndef _LIBXTC_H
+#define _LIBXTC_H
+/* Library which manipulates filtering rules. */
+
+#include "ipt_kernel_headers.h"
+#include <linux/netfilter/x_tables.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef XT_MIN_ALIGN
+/* xt_entry has pointers and u_int64_t's in it, so if you align to
+ it, you'll also align to any crazy matches and targets someone
+ might write */
+#define XT_MIN_ALIGN (__alignof__(struct xt_entry))
+#endif
+
+#ifndef XT_ALIGN
+#define XT_ALIGN(s) (((s) + ((XT_MIN_ALIGN)-1)) & ~((XT_MIN_ALIGN)-1))
+#endif
+
+typedef char xt_chainlabel[32];
+
+#define XTC_LABEL_ACCEPT "ACCEPT"
+#define XTC_LABEL_DROP "DROP"
+#define XTC_LABEL_QUEUE "QUEUE"
+#define XTC_LABEL_RETURN "RETURN"
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBXTC_H */
--- /dev/null
+/**
+ * This file was imported from the iptables sources.
+ * Copyright (C) 1999-2008 Netfilter Core Team
+ *
+ * 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
+ */
+
+#ifndef _XTABLES_H
+#define _XTABLES_H
+
+#include <sys/types.h>
+#include <linux/types.h>
+#include <linux/netfilter/x_tables.h>
+#include "libxtc.h"
+#include <stdbool.h>
+
+#ifndef IPPROTO_SCTP
+#define IPPROTO_SCTP 132
+#endif
+#ifndef IPPROTO_DCCP
+#define IPPROTO_DCCP 33
+#endif
+#ifndef IPPROTO_UDPLITE
+#define IPPROTO_UDPLITE 136
+#endif
+
+#define XTABLES_VERSION "1.4.1.1"
+#define XTABLES_VERSION_CODE (0x10000 * 1 + 0x100 * 4 + 1)
+
+#define XTABLES_API_VERSION(x,y,z) (0x10000*(x) + 0x100*(y) + z)
+
+/* Include file for additions: new matches and targets. */
+struct xtables_match
+{
+ struct xtables_match *next;
+
+ xt_chainlabel name;
+
+ /* Revision of match (0 by default). */
+ u_int8_t revision;
+
+ u_int16_t family;
+
+ const char *version;
+
+ /* Size of match data. */
+ size_t size;
+
+ /* Size of match data relevent for userspace comparison purposes */
+ size_t userspacesize;
+
+ /* Function which prints out usage message. */
+ void (*help)(void);
+
+ /* Initialize the match. */
+ void (*init)(struct xt_entry_match *m);
+
+ /* Function which parses command options; returns true if it
+ ate an option */
+ /* entry is struct ipt_entry for example */
+ int (*parse)(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry,
+ struct xt_entry_match **match);
+
+ /* Final check; exit if not ok. */
+ void (*final_check)(unsigned int flags);
+
+ /* Prints out the match iff non-NULL: put space at end */
+ /* ip is struct ipt_ip * for example */
+ void (*print)(const void *ip,
+ const struct xt_entry_match *match, int numeric);
+
+ /* Saves the match info in parsable form to stdout. */
+ /* ip is struct ipt_ip * for example */
+ void (*save)(const void *ip, const struct xt_entry_match *match);
+
+ /* Pointer to list of extra command-line options */
+ const struct option *extra_opts;
+
+ /* Ignore these men behind the curtain: */
+ unsigned int option_offset;
+ struct xt_entry_match *m;
+ unsigned int mflags;
+#ifdef NO_SHARED_LIBS
+ unsigned int loaded; /* simulate loading so options are merged properly */
+#endif
+};
+
+struct xtables_target
+{
+ struct xtables_target *next;
+
+ xt_chainlabel name;
+
+ /* Revision of target (0 by default). */
+ u_int8_t revision;
+
+ u_int16_t family;
+
+ const char *version;
+
+ /* Size of target data. */
+ size_t size;
+
+ /* Size of target data relevent for userspace comparison purposes */
+ size_t userspacesize;
+
+ /* Function which prints out usage message. */
+ void (*help)(void);
+
+ /* Initialize the target. */
+ void (*init)(struct xt_entry_target *t);
+
+ /* Function which parses command options; returns true if it
+ ate an option */
+ /* entry is struct ipt_entry for example */
+ int (*parse)(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry,
+ struct xt_entry_target **targetinfo);
+
+ /* Final check; exit if not ok. */
+ void (*final_check)(unsigned int flags);
+
+ /* Prints out the target iff non-NULL: put space at end */
+ void (*print)(const void *ip,
+ const struct xt_entry_target *target, int numeric);
+
+ /* Saves the targinfo in parsable form to stdout. */
+ void (*save)(const void *ip,
+ const struct xt_entry_target *target);
+
+ /* Pointer to list of extra command-line options */
+ const struct option *extra_opts;
+
+ /* Ignore these men behind the curtain: */
+ unsigned int option_offset;
+ struct xt_entry_target *t;
+ unsigned int tflags;
+ unsigned int used;
+#ifdef NO_SHARED_LIBS
+ unsigned int loaded; /* simulate loading so options are merged properly */
+#endif
+};
+
+/* Your shared library should call one of these. */
+extern void xtables_register_match(struct xtables_match *me);
+extern void xtables_register_target(struct xtables_target *me);
+
+extern int string_to_number_ll(const char *s,
+ unsigned long long min,
+ unsigned long long max,
+ unsigned long long *ret);
+extern int string_to_number_l(const char *s,
+ unsigned long min,
+ unsigned long max,
+ unsigned long *ret);
+extern int string_to_number(const char *s,
+ unsigned int min,
+ unsigned int max,
+ unsigned int *ret);
+extern bool strtonuml(const char *, char **, unsigned long *,
+ unsigned long, unsigned long);
+extern bool strtonum(const char *, char **, unsigned int *,
+ unsigned int, unsigned int);
+extern int service_to_port(const char *name, const char *proto);
+extern u_int16_t parse_port(const char *port, const char *proto);
+extern void
+parse_interface(const char *arg, char *vianame, unsigned char *mask);
+
+enum exittype {
+ OTHER_PROBLEM = 1,
+ PARAMETER_PROBLEM,
+ VERSION_PROBLEM,
+ RESOURCE_PROBLEM,
+ P_ONLY_ONCE,
+ P_NO_INVERT,
+ P_BAD_VALUE,
+ P_ONE_ACTION,
+};
+
+/* this is a special 64bit data type that is 8-byte aligned */
+#define aligned_u64 u_int64_t __attribute__((aligned(8)))
+
+int check_inverse(const char option[], int *invert, int *my_optind, int argc);
+void exit_error(enum exittype, const char *, ...)__attribute__((noreturn,
+ format(printf,2,3)));
+extern void param_act(unsigned int, const char *, ...);
+extern const char *program_name, *program_version;
+
+extern const char *ipaddr_to_numeric(const struct in_addr *);
+extern const char *ipaddr_to_anyname(const struct in_addr *);
+extern const char *ipmask_to_numeric(const struct in_addr *);
+extern struct in_addr *numeric_to_ipaddr(const char *);
+extern struct in_addr *numeric_to_ipmask(const char *);
+extern void ipparse_hostnetworkmask(const char *, struct in_addr **,
+ struct in_addr *, unsigned int *);
+
+extern struct in6_addr *numeric_to_ip6addr(const char *);
+extern const char *ip6addr_to_numeric(const struct in6_addr *);
+extern const char *ip6addr_to_anyname(const struct in6_addr *);
+extern const char *ip6mask_to_numeric(const struct in6_addr *);
+extern void ip6parse_hostnetworkmask(const char *, struct in6_addr **,
+ struct in6_addr *, unsigned int *);
+
+/**
+ * Print the specified value to standard output, quoting dangerous
+ * characters if required.
+ */
+extern void save_string(const char *value);
+
+#ifdef NO_SHARED_LIBS
+# ifdef _INIT
+# undef _init
+# define _init _INIT
+# endif
+ extern void init_extensions(void);
+#else
+# define _init __attribute__((constructor)) _INIT
+#endif
+
+/* Present in both iptables.c and ip6tables.c */
+extern u_int16_t parse_protocol(const char *s);
+
+#ifdef XTABLES_INTERNAL
+# include <xtables/internal.h>
+#endif
+
+#endif /* _XTABLES_H */
--- /dev/null
+/**
+ * collectd - src/match_regex.c
+ * Copyright (C) 2008 Sebastian Harl
+ * 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
+ *
+ * Authors:
+ * Sebastian Harl <sh at tokkee.org>
+ * Florian Forster <octo at verplant.org>
+ **/
+
+/*
+ * This module allows to filter and rewrite value lists based on
+ * Perl-compatible regular expressions.
+ */
+
+#include "collectd.h"
+#include "filter_chain.h"
+
+#include <sys/types.h>
+#include <regex.h>
+
+#define log_err(...) ERROR ("`regex' match: " __VA_ARGS__)
+#define log_warn(...) WARNING ("`regex' match: " __VA_ARGS__)
+
+/*
+ * private data types
+ */
+
+struct mr_regex_s;
+typedef struct mr_regex_s mr_regex_t;
+struct mr_regex_s
+{
+ regex_t re;
+ char *re_str;
+
+ mr_regex_t *next;
+};
+
+struct mr_match_s;
+typedef struct mr_match_s mr_match_t;
+struct mr_match_s
+{
+ mr_regex_t *host;
+ mr_regex_t *plugin;
+ mr_regex_t *plugin_instance;
+ mr_regex_t *type;
+ mr_regex_t *type_instance;
+};
+
+/*
+ * internal helper functions
+ */
+static void mr_free_regex (mr_regex_t *r) /* {{{ */
+{
+ if (r == NULL)
+ return;
+
+ regfree (&r->re);
+ memset (&r->re, 0, sizeof (r->re));
+ free (r->re_str);
+
+ if (r->next != NULL)
+ mr_free_regex (r->next);
+} /* }}} void mr_free_regex */
+
+static void mr_free_match (mr_match_t *m) /* {{{ */
+{
+ if (m == NULL)
+ return;
+
+ mr_free_regex (m->host);
+ mr_free_regex (m->plugin);
+ mr_free_regex (m->plugin_instance);
+ mr_free_regex (m->type);
+ mr_free_regex (m->type_instance);
+
+ free (m);
+} /* }}} void mr_free_match */
+
+static int mr_match_regexen (mr_regex_t *re_head, /* {{{ */
+ const char *string)
+{
+ mr_regex_t *re;
+
+ if (re_head == NULL)
+ return (FC_MATCH_MATCHES);
+
+ for (re = re_head; re != NULL; re = re->next)
+ {
+ int status;
+
+ status = regexec (&re->re, string,
+ /* nmatch = */ 0, /* pmatch = */ NULL,
+ /* eflags = */ 0);
+ if (status == 0)
+ {
+ DEBUG ("regex match: Regular expression `%s' matches `%s'.",
+ re->re_str, string);
+ }
+ else
+ {
+ DEBUG ("regex match: Regular expression `%s' does not match `%s'.",
+ re->re_str, string);
+ return (FC_MATCH_NO_MATCH);
+ }
+
+ }
+
+ return (FC_MATCH_MATCHES);
+} /* }}} int mr_match_regexen */
+
+static int mr_config_add_regex (mr_regex_t **re_head, /* {{{ */
+ oconfig_item_t *ci)
+{
+ mr_regex_t *re;
+ int status;
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ log_warn ("`%s' needs exactly one string argument.", ci->key);
+ return (-1);
+ }
+
+ re = (mr_regex_t *) malloc (sizeof (*re));
+ if (re == NULL)
+ {
+ log_err ("mr_config_add_regex: malloc failed.");
+ return (-1);
+ }
+ memset (re, 0, sizeof (*re));
+ re->next = NULL;
+
+ re->re_str = strdup (ci->values[0].value.string);
+ if (re->re_str == NULL)
+ {
+ free (re);
+ log_err ("mr_config_add_regex: strdup failed.");
+ return (-1);
+ }
+
+ status = regcomp (&re->re, re->re_str, REG_EXTENDED | REG_NOSUB);
+ if (status != 0)
+ {
+ char errmsg[1024];
+ regerror (status, &re->re, errmsg, sizeof (errmsg));
+ errmsg[sizeof (errmsg) - 1] = 0;
+ log_err ("Compiling regex `%s' for `%s' failed: %s.",
+ re->re_str, ci->key, errmsg);
+ free (re->re_str);
+ free (re);
+ return (-1);
+ }
+
+ if (*re_head == NULL)
+ {
+ *re_head = re;
+ }
+ else
+ {
+ mr_regex_t *ptr;
+
+ ptr = *re_head;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = re;
+ }
+
+ return (0);
+} /* }}} int mr_config_add_regex */
+
+static int mr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
+{
+ mr_match_t *m;
+ int status;
+ int i;
+
+ m = (mr_match_t *) malloc (sizeof (*m));
+ if (m == NULL)
+ {
+ log_err ("mr_create: malloc failed.");
+ return (-ENOMEM);
+ }
+ memset (m, 0, sizeof (*m));
+
+ status = 0;
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if ((strcasecmp ("Host", child->key) == 0)
+ || (strcasecmp ("Hostname", child->key) == 0))
+ status = mr_config_add_regex (&m->host, child);
+ else if (strcasecmp ("Plugin", child->key) == 0)
+ status = mr_config_add_regex (&m->plugin, child);
+ else if (strcasecmp ("PluginInstance", child->key) == 0)
+ status = mr_config_add_regex (&m->plugin_instance, child);
+ else if (strcasecmp ("Type", child->key) == 0)
+ status = mr_config_add_regex (&m->type, child);
+ else if (strcasecmp ("TypeInstance", child->key) == 0)
+ status = mr_config_add_regex (&m->type_instance, child);
+ else
+ {
+ log_err ("The `%s' configuration option is not understood and "
+ "will be ignored.", child->key);
+ status = 0;
+ }
+
+ if (status != 0)
+ break;
+ }
+
+ /* Additional sanity-checking */
+ while (status == 0)
+ {
+ if ((m->host == NULL)
+ && (m->plugin == NULL)
+ && (m->plugin_instance == NULL)
+ && (m->type == NULL)
+ && (m->type_instance == NULL))
+ {
+ log_err ("No (valid) regular expressions have been configured. "
+ "This match will be ignored.");
+ status = -1;
+ }
+
+ break;
+ }
+
+ if (status != 0)
+ {
+ mr_free_match (m);
+ return (status);
+ }
+
+ *user_data = m;
+ return (0);
+} /* }}} int mr_create */
+
+static int mr_destroy (void **user_data) /* {{{ */
+{
+ if ((user_data != NULL) && (*user_data != NULL))
+ mr_free_match (*user_data);
+ return (0);
+} /* }}} int mr_destroy */
+
+static int mr_match (const data_set_t *ds, const value_list_t *vl, /* {{{ */
+ notification_meta_t **meta, void **user_data)
+{
+ mr_match_t *m;
+
+ if ((user_data == NULL) || (*user_data == NULL))
+ return (-1);
+
+ m = *user_data;
+
+ if (mr_match_regexen (m->host, vl->host) == FC_MATCH_NO_MATCH)
+ return (FC_MATCH_NO_MATCH);
+ if (mr_match_regexen (m->plugin, vl->plugin) == FC_MATCH_NO_MATCH)
+ return (FC_MATCH_NO_MATCH);
+ if (mr_match_regexen (m->plugin_instance,
+ vl->plugin_instance) == FC_MATCH_NO_MATCH)
+ return (FC_MATCH_NO_MATCH);
+ if (mr_match_regexen (m->type, vl->type) == FC_MATCH_NO_MATCH)
+ return (FC_MATCH_NO_MATCH);
+ if (mr_match_regexen (m->type_instance,
+ vl->type_instance) == FC_MATCH_NO_MATCH)
+ return (FC_MATCH_NO_MATCH);
+
+ return (FC_MATCH_MATCHES);
+} /* }}} int mr_match */
+
+void module_register (void)
+{
+ match_proc_t mproc;
+
+ memset (&mproc, 0, sizeof (mproc));
+ mproc.create = mr_create;
+ mproc.destroy = mr_destroy;
+ mproc.match = mr_match;
+ fc_register_match ("regex", mproc);
+} /* module_register */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab fdm=marker : */
+
--- /dev/null
+/**
+ * collectd - src/match_value.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
+ *
+ * Authors:
+ * Florian Forster <octo at verplant.org>
+ **/
+
+/*
+ * This module allows to filter and rewrite value lists based on
+ * Perl-compatible regular expressions.
+ */
+
+#include "collectd.h"
+#include "utils_cache.h"
+#include "filter_chain.h"
+
+/*
+ * private data types
+ */
+struct mv_match_s;
+typedef struct mv_match_s mv_match_t;
+struct mv_match_s
+{
+ gauge_t min;
+ gauge_t max;
+ int invert;
+};
+
+/*
+ * internal helper functions
+ */
+static void mv_free_match (mv_match_t *m) /* {{{ */
+{
+ if (m == NULL)
+ return;
+
+ free (m);
+} /* }}} void mv_free_match */
+
+static int mv_config_add_gauge (gauge_t *ret_value, /* {{{ */
+ oconfig_item_t *ci)
+{
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+ {
+ ERROR ("`value' match: `%s' needs exactly one numeric argument.",
+ ci->key);
+ return (-1);
+ }
+
+ *ret_value = ci->values[0].value.number;
+
+ return (0);
+} /* }}} int mv_config_add_gauge */
+
+static int mv_config_add_boolean (int *ret_value, /* {{{ */
+ oconfig_item_t *ci)
+{
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
+ {
+ ERROR ("`value' match: `%s' needs exactly one boolean argument.",
+ ci->key);
+ return (-1);
+ }
+
+ if (ci->values[0].value.boolean)
+ *ret_value = 1;
+ else
+ *ret_value = 0;
+
+ return (0);
+} /* }}} int mv_config_add_boolean */
+
+static int mv_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
+{
+ mv_match_t *m;
+ int status;
+ int i;
+
+ m = (mv_match_t *) malloc (sizeof (*m));
+ if (m == NULL)
+ {
+ ERROR ("mv_create: malloc failed.");
+ return (-ENOMEM);
+ }
+ memset (m, 0, sizeof (*m));
+
+ m->min = NAN;
+ m->max = NAN;
+ m->invert = 0;
+
+ status = 0;
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Min", child->key) == 0)
+ status = mv_config_add_gauge (&m->min, child);
+ else if (strcasecmp ("Max", child->key) == 0)
+ status = mv_config_add_gauge (&m->max, child);
+ else if (strcasecmp ("Invert", child->key) == 0)
+ status = mv_config_add_boolean (&m->invert, child);
+ else
+ {
+ ERROR ("`value' match: The `%s' configuration option is not "
+ "understood and will be ignored.", child->key);
+ status = 0;
+ }
+
+ if (status != 0)
+ break;
+ }
+
+ /* Additional sanity-checking */
+ while (status == 0)
+ {
+ if (isnan (m->min) && isnan (m->max))
+ {
+ ERROR ("`value' match: Neither minimum nor maximum are defined. "
+ "This match will be ignored.");
+ status = -1;
+ }
+
+ break;
+ }
+
+ if (status != 0)
+ {
+ mv_free_match (m);
+ return (status);
+ }
+
+ *user_data = m;
+ return (0);
+} /* }}} int mv_create */
+
+static int mv_destroy (void **user_data) /* {{{ */
+{
+ if ((user_data != NULL) && (*user_data != NULL))
+ mv_free_match (*user_data);
+ return (0);
+} /* }}} int mv_destroy */
+
+static int mv_match (const data_set_t *ds, const value_list_t *vl, /* {{{ */
+ notification_meta_t **meta, void **user_data)
+{
+ mv_match_t *m;
+ gauge_t *values;
+ int status;
+ int i;
+
+ if ((user_data == NULL) || (*user_data == NULL))
+ return (-1);
+
+ m = *user_data;
+
+ values = uc_get_rate (ds, vl);
+ if (values == NULL)
+ {
+ ERROR ("`value' match: Retrieving the current rate from the cache "
+ "failed.");
+ return (-1);
+ }
+
+ status = FC_MATCH_MATCHES;
+ for (i = 0; i < ds->ds_num; i++)
+ {
+ DEBUG ("`value' match: current = %g; min = %g; max = %g; invert = %s;",
+ values[i], m->min, m->max,
+ m->invert ? "true" : "false");
+
+ if ((!isnan (m->min) && (values[i] < m->min))
+ || (!isnan (m->max) && (values[i] > m->max)))
+ {
+ status = FC_MATCH_NO_MATCH;
+ break;
+ }
+ }
+
+ if (m->invert)
+ {
+ if (status == FC_MATCH_MATCHES)
+ status = FC_MATCH_NO_MATCH;
+ else
+ status = FC_MATCH_MATCHES;
+ }
+
+ free (values);
+ return (status);
+} /* }}} int mv_match */
+
+void module_register (void)
+{
+ match_proc_t mproc;
+
+ memset (&mproc, 0, sizeof (mproc));
+ mproc.create = mv_create;
+ mproc.destroy = mv_destroy;
+ mproc.match = mv_match;
+ fc_register_match ("value", mproc);
+} /* module_register */
+
+/* vim: set sw=2 sts=2 tw=78 et fdm=marker : */
+
--- /dev/null
+/**
+ * collectd - src/meta_data.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 verplant.org>
+ **/
+
+/*
+ * First tell the compiler to stick to the C99 and POSIX standards as close as
+ * possible.
+ */
+#ifndef __STRICT_ANSI__ /* {{{ */
+# define __STRICT_ANSI__
+#endif
+
+#ifndef _ISOC99_SOURCE
+# define _ISOC99_SOURCE
+#endif
+
+#ifdef _POSIX_C_SOURCE
+# undef _POSIX_C_SOURCE
+#endif
+#define _POSIX_C_SOURCE 200112L
+
+#if 0
+/* Single UNIX needed for strdup. */
+#ifdef _XOPEN_SOURCE
+# undef _XOPEN_SOURCE
+#endif
+#define _XOPEN_SOURCE 500
+#endif
+
+#ifndef _REENTRANT
+# define _REENTRANT
+#endif
+
+#ifndef _THREAD_SAFE
+# define _THREAD_SAFE
+#endif
+
+#ifdef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* }}} */
+
+#include "collectd.h"
+#include "plugin.h"
+#include "meta_data.h"
+
+#include <pthread.h>
+
+/*
+ * Defines
+ */
+#define MD_TYPE_STRING 1
+#define MD_TYPE_SIGNED_INT 2
+#define MD_TYPE_UNSIGNED_INT 3
+#define MD_TYPE_DOUBLE 4
+
+/*
+ * Data types
+ */
+union meta_value_u
+{
+ char *mv_string;
+ int64_t mv_signed_int;
+ uint64_t mv_unsigned_int;
+ double mv_double;
+};
+typedef union meta_value_u meta_value_t;
+
+struct meta_entry_s;
+typedef struct meta_entry_s meta_entry_t;
+struct meta_entry_s
+{
+ char *key;
+ meta_value_t value;
+ int type;
+ meta_entry_t *next;
+};
+
+struct meta_data_s
+{
+ meta_entry_t *head;
+ pthread_mutex_t lock;
+};
+
+/*
+ * Private functions
+ */
+static char *md_strdup (const char *orig) /* {{{ */
+{
+ size_t sz;
+ char *dest;
+
+ if (orig == NULL)
+ return (NULL);
+
+ sz = strlen (orig) + 1;
+ dest = (char *) malloc (sz);
+ if (dest == NULL)
+ return (NULL);
+
+ memcpy (dest, orig, sz);
+
+ return (dest);
+} /* }}} char *md_strdup */
+
+static meta_entry_t *md_entry_alloc (const char *key) /* {{{ */
+{
+ meta_entry_t *e;
+
+ e = (meta_entry_t *) malloc (sizeof (*e));
+ if (e == NULL)
+ {
+ ERROR ("md_entry_alloc: malloc failed.");
+ return (NULL);
+ }
+ memset (e, 0, sizeof (*e));
+
+ e->key = md_strdup (key);
+ if (e->key == NULL)
+ {
+ free (e);
+ ERROR ("md_entry_alloc: md_strdup failed.");
+ return (NULL);
+ }
+
+ e->type = 0;
+ e->next = NULL;
+
+ return (e);
+} /* }}} meta_entry_t *md_entry_alloc */
+
+static void md_entry_free (meta_entry_t *e) /* {{{ */
+{
+ if (e == NULL)
+ return;
+
+ free (e->key);
+
+ if (e->type == MD_TYPE_STRING)
+ free (e->value.mv_string);
+
+ if (e->next != NULL)
+ md_entry_free (e->next);
+
+ free (e);
+} /* }}} void md_entry_free */
+
+static int md_entry_insert (meta_data_t *md, meta_entry_t *e) /* {{{ */
+{
+ meta_entry_t *this;
+ meta_entry_t *prev;
+
+ if ((md == NULL) || (e == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ prev = NULL;
+ this = md->head;
+ while (this != NULL)
+ {
+ if (strcasecmp (e->key, this->key) == 0)
+ break;
+
+ prev = this;
+ this = this->next;
+ }
+
+ if (this == NULL)
+ {
+ /* This key does not exist yet. */
+ if (md->head == NULL)
+ md->head = e;
+ else
+ {
+ assert (prev != NULL);
+ prev->next = e;
+ }
+
+ e->next = NULL;
+ }
+ else /* (this != NULL) */
+ {
+ if (prev == NULL)
+ md->head = e;
+ else
+ prev->next = e;
+
+ e->next = this->next;
+ }
+
+ pthread_mutex_unlock (&md->lock);
+
+ if (this != NULL)
+ {
+ this->next = NULL;
+ md_entry_free (this);
+ }
+
+ return (0);
+} /* }}} int md_entry_insert */
+
+/* XXX: The lock on md must be held while calling this function! */
+static meta_entry_t *md_entry_lookup (meta_data_t *md, /* {{{ */
+ const char *key)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL))
+ return (NULL);
+
+ for (e = md->head; e != NULL; e = e->next)
+ if (strcasecmp (key, e->key) == 0)
+ break;
+
+ return (e);
+} /* }}} meta_entry_t *md_entry_lookup */
+
+/*
+ * Public functions
+ */
+meta_data_t *meta_data_create (void) /* {{{ */
+{
+ meta_data_t *md;
+
+ md = (meta_data_t *) malloc (sizeof (*md));
+ if (md == NULL)
+ {
+ ERROR ("meta_data_create: malloc failed.");
+ return (NULL);
+ }
+ memset (md, 0, sizeof (*md));
+
+ md->head = NULL;
+ pthread_mutex_init (&md->lock, /* attr = */ NULL);
+
+ return (md);
+} /* }}} meta_data_t *meta_data_create */
+
+void meta_data_destroy (meta_data_t *md) /* {{{ */
+{
+ if (md == NULL)
+ return;
+
+ md_entry_free (md->head);
+ free (md);
+} /* }}} void meta_data_destroy */
+
+int meta_data_exists (meta_data_t *md, const char *key) /* {{{ */
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ for (e = md->head; e != NULL; e = e->next)
+ {
+ if (strcasecmp (key, e->key) == 0)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return (1);
+ }
+ }
+
+ pthread_mutex_unlock (&md->lock);
+ return (0);
+} /* }}} int meta_data_exists */
+
+int meta_data_delete (meta_data_t *md, const char *key) /* {{{ */
+{
+ meta_entry_t *this;
+ meta_entry_t *prev;
+
+ if ((md == NULL) || (key == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ prev = NULL;
+ this = md->head;
+ while (this != NULL)
+ {
+ if (strcasecmp (key, this->key) == 0)
+ break;
+
+ prev = this;
+ this = this->next;
+ }
+
+ if (this == NULL)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ if (prev == NULL)
+ md->head = this->next;
+ else
+ prev->next = this->next;
+
+ pthread_mutex_unlock (&md->lock);
+
+ this->next = NULL;
+ md_entry_free (this);
+
+ return (0);
+} /* }}} int meta_data_delete */
+
+int meta_data_add_string (meta_data_t *md, /* {{{ */
+ const char *key, const char *value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL) || (value == NULL))
+ return (-EINVAL);
+
+ e = md_entry_alloc (key);
+ if (e == NULL)
+ return (-ENOMEM);
+
+ e->value.mv_string = md_strdup (value);
+ if (e->value.mv_string == NULL)
+ {
+ ERROR ("meta_data_add_string: md_strdup failed.");
+ md_entry_free (e);
+ return (-ENOMEM);
+ }
+ e->type = MD_TYPE_STRING;
+
+ return (md_entry_insert (md, e));
+} /* }}} int meta_data_add_string */
+
+int meta_data_add_signed_int (meta_data_t *md, /* {{{ */
+ const char *key, int64_t value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL))
+ return (-EINVAL);
+
+ e = md_entry_alloc (key);
+ if (e == NULL)
+ return (-ENOMEM);
+
+ e->value.mv_signed_int = value;
+ e->type = MD_TYPE_SIGNED_INT;
+
+ return (md_entry_insert (md, e));
+} /* }}} int meta_data_add_signed_int */
+
+int meta_data_add_unsigned_int (meta_data_t *md, /* {{{ */
+ const char *key, uint64_t value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL))
+ return (-EINVAL);
+
+ e = md_entry_alloc (key);
+ if (e == NULL)
+ return (-ENOMEM);
+
+ e->value.mv_unsigned_int = value;
+ e->type = MD_TYPE_UNSIGNED_INT;
+
+ return (md_entry_insert (md, e));
+} /* }}} int meta_data_add_unsigned_int */
+
+int meta_data_add_double (meta_data_t *md, /* {{{ */
+ const char *key, double value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL))
+ return (-EINVAL);
+
+ e = md_entry_alloc (key);
+ if (e == NULL)
+ return (-ENOMEM);
+
+ e->value.mv_double = value;
+ e->type = MD_TYPE_DOUBLE;
+
+ return (md_entry_insert (md, e));
+} /* }}} int meta_data_add_double */
+
+int meta_data_get_string (meta_data_t *md, /* {{{ */
+ const char *key, char **value)
+{
+ meta_entry_t *e;
+ char *temp;
+
+ if ((md == NULL) || (key == NULL) || (value == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ e = md_entry_lookup (md, key);
+ if (e == NULL)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ if (e->type != MD_TYPE_SIGNED_INT)
+ {
+ ERROR ("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ temp = md_strdup (e->value.mv_string);
+ if (temp == NULL)
+ {
+ pthread_mutex_unlock (&md->lock);
+ ERROR ("meta_data_get_string: md_strdup failed.");
+ return (-ENOMEM);
+ }
+
+ pthread_mutex_unlock (&md->lock);
+
+ *value = temp;
+
+ return (0);
+} /* }}} int meta_data_get_string */
+
+int meta_data_get_signed_int (meta_data_t *md, /* {{{ */
+ const char *key, int64_t *value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL) || (value == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ e = md_entry_lookup (md, key);
+ if (e == NULL)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ if (e->type != MD_TYPE_SIGNED_INT)
+ {
+ ERROR ("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ *value = e->value.mv_signed_int;
+
+ pthread_mutex_unlock (&md->lock);
+ return (0);
+} /* }}} int meta_data_get_signed_int */
+
+int meta_data_get_unsigned_int (meta_data_t *md, /* {{{ */
+ const char *key, uint64_t *value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL) || (value == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ e = md_entry_lookup (md, key);
+ if (e == NULL)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ if (e->type != MD_TYPE_UNSIGNED_INT)
+ {
+ ERROR ("meta_data_get_unsigned_int: Type mismatch for key `%s'", e->key);
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ *value = e->value.mv_unsigned_int;
+
+ pthread_mutex_unlock (&md->lock);
+ return (0);
+} /* }}} int meta_data_get_unsigned_int */
+
+int meta_data_get_double (meta_data_t *md, /* {{{ */
+ const char *key, double *value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL) || (value == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ e = md_entry_lookup (md, key);
+ if (e == NULL)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ if (e->type != MD_TYPE_DOUBLE)
+ {
+ ERROR ("meta_data_get_double: Type mismatch for key `%s'", e->key);
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ *value = e->value.mv_double;
+
+ pthread_mutex_unlock (&md->lock);
+ return (0);
+} /* }}} int meta_data_get_double */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
--- /dev/null
+/**
+ * collectd - src/meta_data.h
+ * 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 verplant.org>
+ **/
+
+#ifndef META_DATA_H
+#define META_DATA_H
+
+#include "collectd.h"
+
+struct meta_data_s;
+typedef struct meta_data_s meta_data_t;
+
+meta_data_t *meta_data_create (void);
+void meta_data_destroy (meta_data_t *md);
+
+int meta_data_exists (meta_data_t *md, const char *key);
+int meta_data_delete (meta_data_t *md, const char *key);
+
+int meta_data_add_string (meta_data_t *md,
+ const char *key,
+ const char *value);
+int meta_data_add_signed_int (meta_data_t *md,
+ const char *key,
+ int64_t value);
+int meta_data_add_unsigned_int (meta_data_t *md,
+ const char *key,
+ uint64_t value);
+int meta_data_add_double (meta_data_t *md,
+ const char *key,
+ double value);
+
+int meta_data_get_string (meta_data_t *md,
+ const char *key,
+ char **value);
+int meta_data_get_signed_int (meta_data_t *md,
+ const char *key,
+ int64_t *value);
+int meta_data_get_unsigned_int (meta_data_t *md,
+ const char *key,
+ uint64_t *value);
+int meta_data_get_double (meta_data_t *md,
+ const char *key,
+ double *value);
+
+#endif /* META_DATA_H */
+/* vim: set sw=2 sts=2 et : */
"User",
"Password",
"Database",
+ "Port",
+ "Socket",
NULL
};
-static int config_keys_num = 4;
+static int config_keys_num = 6;
static char *host = "localhost";
static char *user;
static char *pass;
static char *db = NULL;
+static char *socket = NULL;
+static int port = 0;
static MYSQL *getconnection (void)
{
return (NULL);
}
- if (mysql_real_connect (con, host, user, pass, db, 0, NULL, 0) == NULL)
+ if (mysql_real_connect (con, host, user, pass, db, port, socket, 0) == NULL)
{
ERROR ("mysql_real_connect failed: %s", mysql_error (con));
state = 0;
return ((pass = strdup (value)) == NULL ? 1 : 0);
else if (strcasecmp (key, "database") == 0)
return ((db = strdup (value)) == NULL ? 1 : 0);
+ else if (strcasecmp (key, "socket") == 0)
+ return ((socket = strdup (value)) == NULL ? 1 : 0);
+ else if (strcasecmp (key, "port") == 0)
+ {
+ char *endptr = NULL;
+ int temp;
+
+ errno = 0;
+ temp = strtol (value, &endptr, 0);
+ if ((errno != 0) || (value == endptr))
+ {
+ ERROR ("mysql plugin: Invalid \"Port\" argument: %s",
+ value);
+ port = 0;
+ return (1);
+ }
+ else if ((temp < 0) || (temp >= 65535))
+ {
+ ERROR ("mysql plugin: Port number out of range: %i",
+ temp);
+ port = 0;
+ return (1);
+ }
+
+ port = temp;
+ return (0);
+ }
else
return (-1);
-}
+} /* int config */
static void counter_submit (const char *type, const char *type_instance,
counter_t value)
--- /dev/null
+/**
+ * collectd - src/oracle.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
+ *
+ * Linking src/oracle.c ("the oracle plugin") statically or dynamically with
+ * other modules is making a combined work based on the oracle plugin. Thus,
+ * the terms and conditions of the GNU General Public License cover the whole
+ * combination.
+ *
+ * In addition, as a special exception, the copyright holders of the oracle
+ * plugin give you permission to combine the oracle plugin with free software
+ * programs or libraries that are released under the GNU LGPL and with code
+ * included in the standard release of the Oracle® Call Interface (OCI) under
+ * the Oracle® Technology Network (OTN) License (or modified versions of such
+ * code, with unchanged license). You may copy and distribute such a system
+ * following the terms of the GNU GPL for the oracle plugin and the licenses of
+ * the other code concerned.
+ *
+ * Note that people who make modified versions of the oracle plugin are not
+ * obligated to grant this special exception for their modified versions; it is
+ * their choice whether to do so. The GNU General Public License gives
+ * permission to release a modified version without this exception; this
+ * exception also makes it possible to release a modified version which carries
+ * forward this exception. However, without this exception the OTN License does
+ * not allow linking with code licensed under the GNU General Public License.
+ *
+ * Oracle® is a registered trademark of Oracle Corporation and/or its
+ * affiliates. Other names may be trademarks of their respective owners.
+ *
+ * Authors:
+ * Florian octo Forster <octo at noris.net>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#include <oci.h>
+
+/*
+ * Data types
+ */
+struct o_query_s
+{
+ char *name;
+ char *statement;
+ char *type;
+ char **instances;
+ size_t instances_num;
+ char **values;
+ size_t values_num;
+
+ OCIStmt *oci_statement;
+};
+typedef struct o_query_s o_query_t;
+
+struct o_database_s
+{
+ char *name;
+ char *connect_id;
+ char *username;
+ char *password;
+
+ o_query_t **queries;
+ size_t queries_num;
+
+ OCISvcCtx *oci_service_context;
+};
+typedef struct o_database_s o_database_t;
+
+/*
+ * Global variables
+ */
+static o_query_t **queries = NULL;
+static size_t queries_num = 0;
+static o_database_t **databases = NULL;
+static size_t databases_num = 0;
+
+OCIEnv *oci_env = NULL;
+OCIError *oci_error = NULL;
+
+/*
+ * Functions
+ */
+static void o_report_error (const char *where, /* {{{ */
+ const char *what, OCIError *eh)
+{
+ char buffer[2048];
+ sb4 error_code;
+ int status;
+
+ status = OCIErrorGet (eh, /* record number = */ 1,
+ /* sqlstate = */ NULL,
+ &error_code,
+ (text *) &buffer[0],
+ (ub4) sizeof (buffer),
+ OCI_HTYPE_ERROR);
+ buffer[sizeof (buffer) - 1] = 0;
+
+ if (status == OCI_SUCCESS)
+ {
+ size_t buffer_length;
+
+ buffer_length = strlen (buffer);
+ while ((buffer_length > 0) && (buffer[buffer_length - 1] < 32))
+ {
+ buffer_length--;
+ buffer[buffer_length] = 0;
+ }
+
+ ERROR ("oracle plugin: %s: %s failed: %s",
+ where, what, buffer);
+ }
+ else
+ {
+ ERROR ("oracle plugin: %s: %s failed. Additionally, OCIErrorGet failed with status %i.",
+ where, what, status);
+ }
+} /* }}} void o_report_error */
+
+static void o_query_free (o_query_t *q) /* {{{ */
+{
+ size_t i;
+
+ if (q == NULL)
+ return;
+
+ sfree (q->name);
+ sfree (q->statement);
+ sfree (q->type);
+
+ for (i = 0; i < q->instances_num; i++)
+ sfree (q->instances[i]);
+ sfree (q->instances);
+
+ for (i = 0; i < q->values_num; i++)
+ sfree (q->values[i]);
+ sfree (q->values);
+
+ sfree (q);
+} /* }}} void o_query_free */
+
+static void o_database_free (o_database_t *db) /* {{{ */
+{
+ if (db == NULL)
+ return;
+
+ sfree (db->name);
+ sfree (db->connect_id);
+ sfree (db->username);
+ sfree (db->password);
+ sfree (db->queries);
+
+ sfree (db);
+} /* }}} void o_database_free */
+
+/* Configuration handling functions {{{
+ *
+ * <Plugin oracle>
+ * <Query "plugin_instance0">
+ * Statement "SELECT name, value FROM table"
+ * Type "gauge"
+ * InstancesFrom "name"
+ * ValuesFrom "value"
+ * </Query>
+ *
+ * <Database "plugin_instance1">
+ * ConnectID "db01"
+ * Username "oracle"
+ * Password "secret"
+ * Query "plugin_instance0"
+ * </Database>
+ * </Plugin>
+ */
+
+static int o_config_set_string (char **ret_string, /* {{{ */
+ oconfig_item_t *ci)
+{
+ char *string;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("oracle plugin: The `%s' config option "
+ "needs exactly one string argument.", ci->key);
+ return (-1);
+ }
+
+ string = strdup (ci->values[0].value.string);
+ if (string == NULL)
+ {
+ ERROR ("oracle plugin: strdup failed.");
+ return (-1);
+ }
+
+ if (*ret_string != NULL)
+ free (*ret_string);
+ *ret_string = string;
+
+ return (0);
+} /* }}} int o_config_set_string */
+
+static int o_config_add_string (char ***ret_array, /* {{{ */
+ size_t *ret_array_len, oconfig_item_t *ci)
+{
+ char **array;
+ size_t array_len;
+ int i;
+
+ if (ci->values_num < 1)
+ {
+ WARNING ("oracle plugin: The `%s' config option "
+ "needs at least one argument.", ci->key);
+ return (-1);
+ }
+
+ for (i = 0; i < ci->values_num; i++)
+ {
+ if (ci->values[i].type != OCONFIG_TYPE_STRING)
+ {
+ WARNING ("oracle plugin: Argument %i to the `%s' option "
+ "is not a string.", i + 1, ci->key);
+ return (-1);
+ }
+ }
+
+ array_len = *ret_array_len;
+ array = (char **) realloc (*ret_array,
+ sizeof (char *) * (array_len + ci->values_num));
+ if (array == NULL)
+ {
+ ERROR ("oracle plugin: realloc failed.");
+ return (-1);
+ }
+ *ret_array = array;
+
+ for (i = 0; i < ci->values_num; i++)
+ {
+ array[array_len] = strdup (ci->values[i].value.string);
+ if (array[array_len] == NULL)
+ {
+ ERROR ("oracle plugin: strdup failed.");
+ *ret_array_len = array_len;
+ return (-1);
+ }
+ array_len++;
+ }
+
+ *ret_array_len = array_len;
+ return (0);
+} /* }}} int o_config_add_string */
+
+static int o_config_add_query (oconfig_item_t *ci) /* {{{ */
+{
+ o_query_t *q;
+ int status;
+ int i;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("oracle plugin: The `Query' block "
+ "needs exactly one string argument.");
+ return (-1);
+ }
+
+ q = (o_query_t *) malloc (sizeof (*q));
+ if (q == NULL)
+ {
+ ERROR ("oracle plugin: malloc failed.");
+ return (-1);
+ }
+ memset (q, 0, sizeof (*q));
+
+ status = o_config_set_string (&q->name, ci);
+ if (status != 0)
+ {
+ sfree (q);
+ return (status);
+ }
+
+ /* Fill the `o_query_t' structure.. */
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Statement", child->key) == 0)
+ status = o_config_set_string (&q->statement, child);
+ else if (strcasecmp ("Type", child->key) == 0)
+ status = o_config_set_string (&q->type, child);
+ else if (strcasecmp ("InstancesFrom", child->key) == 0)
+ status = o_config_add_string (&q->instances, &q->instances_num, child);
+ else if (strcasecmp ("ValuesFrom", child->key) == 0)
+ status = o_config_add_string (&q->values, &q->values_num, child);
+ else
+ {
+ WARNING ("oracle plugin: Option `%s' not allowed here.", child->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ }
+
+ /* Check that all necessary options have been given. */
+ while (status == 0)
+ {
+ if (q->statement == NULL)
+ {
+ WARNING ("oracle plugin: `Statement' not given for query `%s'", q->name);
+ status = -1;
+ }
+ if (q->type == NULL)
+ {
+ WARNING ("oracle plugin: `Type' not given for query `%s'", q->name);
+ status = -1;
+ }
+ if (q->instances == NULL)
+ {
+ WARNING ("oracle plugin: `InstancesFrom' not given for query `%s'", q->name);
+ status = -1;
+ }
+ if (q->values == NULL)
+ {
+ WARNING ("oracle plugin: `ValuesFrom' not given for query `%s'", q->name);
+ status = -1;
+ }
+
+ break;
+ } /* while (status == 0) */
+
+ /* If all went well, add this query to the list of queries within the
+ * database structure. */
+ if (status == 0)
+ {
+ o_query_t **temp;
+
+ temp = (o_query_t **) realloc (queries,
+ sizeof (*queries) * (queries_num + 1));
+ if (temp == NULL)
+ {
+ ERROR ("oracle plugin: realloc failed");
+ status = -1;
+ }
+ else
+ {
+ queries = temp;
+ queries[queries_num] = q;
+ queries_num++;
+ }
+ }
+
+ if (status != 0)
+ {
+ o_query_free (q);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int o_config_add_query */
+
+static int o_config_add_database_query (o_database_t *db, /* {{{ */
+ oconfig_item_t *ci)
+{
+ o_query_t *q;
+ o_query_t **temp;
+ size_t i;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("oracle plugin: The `Query' config option "
+ "needs exactly one string argument.");
+ return (-1);
+ }
+
+ q = NULL;
+ for (i = 0; i < queries_num; i++)
+ {
+ if (strcasecmp (queries[i]->name, ci->values[0].value.string) == 0)
+ {
+ q = queries[i];
+ break;
+ }
+ }
+
+ if (q == NULL)
+ {
+ WARNING ("oracle plugin: Database `%s': Unknown query `%s'. "
+ "Please make sure that the <Query \"%s\"> block comes before "
+ "the <Database \"%s\"> block.",
+ db->name, ci->values[0].value.string,
+ ci->values[0].value.string, db->name);
+ return (-1);
+ }
+
+ temp = (o_query_t **) realloc (db->queries,
+ sizeof (*db->queries) * (db->queries_num + 1));
+ if (temp == NULL)
+ {
+ ERROR ("oracle plugin: realloc failed");
+ return (-1);
+ }
+ else
+ {
+ db->queries = temp;
+ db->queries[db->queries_num] = q;
+ db->queries_num++;
+ }
+
+ return (0);
+} /* }}} int o_config_add_database_query */
+
+static int o_config_add_database (oconfig_item_t *ci) /* {{{ */
+{
+ o_database_t *db;
+ int status;
+ int i;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("oracle plugin: The `Database' block "
+ "needs exactly one string argument.");
+ return (-1);
+ }
+
+ db = (o_database_t *) malloc (sizeof (*db));
+ if (db == NULL)
+ {
+ ERROR ("oracle plugin: malloc failed.");
+ return (-1);
+ }
+ memset (db, 0, sizeof (*db));
+
+ status = o_config_set_string (&db->name, ci);
+ if (status != 0)
+ {
+ sfree (db);
+ return (status);
+ }
+
+ /* Fill the `o_database_t' structure.. */
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("ConnectID", child->key) == 0)
+ status = o_config_set_string (&db->connect_id, child);
+ else if (strcasecmp ("Username", child->key) == 0)
+ status = o_config_set_string (&db->username, child);
+ else if (strcasecmp ("Password", child->key) == 0)
+ status = o_config_set_string (&db->password, child);
+ else if (strcasecmp ("Query", child->key) == 0)
+ status = o_config_add_database_query (db, child);
+ else
+ {
+ WARNING ("oracle plugin: Option `%s' not allowed here.", child->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ }
+
+ /* Check that all necessary options have been given. */
+ while (status == 0)
+ {
+ if (db->connect_id == NULL)
+ {
+ WARNING ("oracle plugin: `ConnectID' not given for query `%s'", db->name);
+ status = -1;
+ }
+ if (db->username == NULL)
+ {
+ WARNING ("oracle plugin: `Username' not given for query `%s'", db->name);
+ status = -1;
+ }
+ if (db->password == NULL)
+ {
+ WARNING ("oracle plugin: `Password' not given for query `%s'", db->name);
+ status = -1;
+ }
+
+ break;
+ } /* while (status == 0) */
+
+ /* If all went well, add this query to the list of queries within the
+ * database structure. */
+ if (status == 0)
+ {
+ o_database_t **temp;
+
+ temp = (o_database_t **) realloc (databases,
+ sizeof (*databases) * (databases_num + 1));
+ if (temp == NULL)
+ {
+ ERROR ("oracle plugin: realloc failed");
+ status = -1;
+ }
+ else
+ {
+ databases = temp;
+ databases[databases_num] = db;
+ databases_num++;
+ }
+ }
+
+ if (status != 0)
+ {
+ o_database_free (db);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int o_config_add_database */
+
+static int o_config (oconfig_item_t *ci) /* {{{ */
+{
+ int i;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+ if (strcasecmp ("Query", child->key) == 0)
+ o_config_add_query (child);
+ else if (strcasecmp ("Database", child->key) == 0)
+ o_config_add_database (child);
+ else
+ {
+ WARNING ("snmp plugin: Ignoring unknown config option `%s'.", child->key);
+ }
+ } /* for (ci->children) */
+
+ return (0);
+} /* }}} int o_config */
+
+/* }}} End of configuration handling functions */
+
+static int o_init (void) /* {{{ */
+{
+ int status;
+
+ if (oci_env != NULL)
+ return (0);
+
+ status = OCIEnvCreate (&oci_env,
+ /* mode = */ OCI_THREADED,
+ /* context = */ NULL,
+ /* malloc = */ NULL,
+ /* realloc = */ NULL,
+ /* free = */ NULL,
+ /* user_data_size = */ 0,
+ /* user_data_ptr = */ NULL);
+ if (status != 0)
+ {
+ ERROR ("oracle plugin: OCIEnvCreate failed with status %i.", status);
+ return (-1);
+ }
+
+ status = OCIHandleAlloc (oci_env, (void *) &oci_error, OCI_HTYPE_ERROR,
+ /* user_data_size = */ 0, /* user_data = */ NULL);
+ if (status != OCI_SUCCESS)
+ {
+ ERROR ("oracle plugin: OCIHandleAlloc (OCI_HTYPE_ERROR) failed "
+ "with status %i.", status);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int o_init */
+
+static void o_submit (o_database_t *db, o_query_t *q, /* {{{ */
+ const data_set_t *ds, char **buffer_instances, char **buffer_values)
+{
+ value_list_t vl = VALUE_LIST_INIT;
+ size_t i;
+
+ assert (((size_t) ds->ds_num) == q->values_num);
+
+ vl.values = (value_t *) malloc (sizeof (value_t) * q->values_num);
+ if (vl.values == NULL)
+ {
+ ERROR ("oracle plugin: malloc failed.");
+ return;
+ }
+ vl.values_len = ds->ds_num;
+
+ for (i = 0; i < q->values_num; i++)
+ {
+ char *endptr;
+
+ endptr = NULL;
+ errno = 0;
+ if (ds->ds[i].type == DS_TYPE_COUNTER)
+ vl.values[i].counter = (counter_t) strtoll (buffer_values[i],
+ &endptr, /* base = */ 0);
+ else if (ds->ds[i].type == DS_TYPE_GAUGE)
+ vl.values[i].gauge = (gauge_t) strtod (buffer_values[i], &endptr);
+ else
+ errno = EINVAL;
+
+ if ((endptr == buffer_values[i]) || (errno != 0))
+ {
+ WARNING ("oracle plugin: o_submit: Parsing `%s' as %s failed.",
+ buffer_values[i],
+ (ds->ds[i].type == DS_TYPE_COUNTER) ? "counter" : "gauge");
+ vl.values[i].gauge = NAN;
+ }
+ }
+
+ vl.time = time (NULL);
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "oracle", sizeof (vl.plugin));
+ sstrncpy (vl.plugin_instance, db->name, sizeof (vl.type_instance));
+ sstrncpy (vl.type, q->type, sizeof (vl.type));
+ strjoin (vl.type_instance, sizeof (vl.type_instance),
+ buffer_instances, q->instances_num, "-");
+ vl.type_instance[sizeof (vl.type_instance) - 1] = 0;
+
+ plugin_dispatch_values (&vl);
+} /* }}} void o_submit */
+
+static int o_read_database_query (o_database_t *db, /* {{{ */
+ o_query_t *q)
+{
+ const data_set_t *ds;
+ ub4 param_counter; /* == number of columns */
+ int status;
+ size_t i;
+ ub4 j;
+
+ /* Scratch area for OCI to write values to */
+ char **buffer_instances;
+ char **buffer_values;
+
+ /* List of indizes of the instance and value columns. Only used for error
+ * checking. */
+ size_t *index_instances;
+ size_t *index_values;
+
+ /* List of `OCIDefine' pointers. These defines map columns to the buffer
+ * space declared above. */
+ OCIDefine **oci_defines;
+
+ ds = plugin_get_ds (q->type); /* {{{ */
+ if (ds == NULL)
+ {
+ WARNING ("oracle plugin: o_read_database_query (%s, %s): "
+ "plugin_get_ds (%s) failed. Please check if the type exists, "
+ "see types.db(5).",
+ db->name, q->name, q->type);
+ return (-1);
+ } /* }}} */
+
+ if (((size_t) ds->ds_num) != q->values_num)
+ {
+ ERROR ("oracle plugin: o_read_database_query (%s, %s): "
+ "The query `%s' uses the type `%s' which requires exactly "
+ "%i value%s, but you specified %zu value-column%s. "
+ "See types.db(5) for details.",
+ db->name, q->name,
+ q->name, q->type,
+ ds->ds_num, (ds->ds_num == 1) ? "" : "s",
+ q->values_num, (q->values_num == 1) ? "" : "s");
+ return (-1);
+ }
+
+ /* Prepare the statement */
+ if (q->oci_statement == NULL) /* {{{ */
+ {
+ status = OCIHandleAlloc (oci_env, (void *) &q->oci_statement,
+ OCI_HTYPE_STMT, /* user_data_size = */ 0, /* user_data = */ NULL);
+ if (status != OCI_SUCCESS)
+ {
+ o_report_error ("o_read_database_query", "OCIHandleAlloc", oci_error);
+ q->oci_statement = NULL;
+ return (-1);
+ }
+
+ status = OCIStmtPrepare (q->oci_statement, oci_error,
+ (text *) q->statement, (ub4) strlen (q->statement),
+ /* language = */ OCI_NTV_SYNTAX,
+ /* mode = */ OCI_DEFAULT);
+ if (status != OCI_SUCCESS)
+ {
+ o_report_error ("o_read_database_query", "OCIStmtPrepare", oci_error);
+ OCIHandleFree (q->oci_statement, OCI_HTYPE_STMT);
+ q->oci_statement = NULL;
+ return (-1);
+ }
+ assert (q->oci_statement != NULL);
+ } /* }}} */
+
+ /* Execute the statement */
+ status = OCIStmtExecute (db->oci_service_context, /* {{{ */
+ q->oci_statement,
+ oci_error,
+ /* iters = */ 0,
+ /* rowoff = */ 0,
+ /* snap_in = */ NULL, /* snap_out = */ NULL,
+ /* mode = */ OCI_DEFAULT);
+ if (status != OCI_SUCCESS)
+ {
+ o_report_error ("o_read_database_query", "OCIStmtExecute", oci_error);
+ ERROR ("oracle plugin: o_read_database_query: "
+ "Failing statement was: %s", q->statement);
+ return (-1);
+ } /* }}} */
+
+ /* Acquire the number of columns returned. */
+ param_counter = 0;
+ status = OCIAttrGet (q->oci_statement, OCI_HTYPE_STMT, /* {{{ */
+ ¶m_counter, /* size pointer = */ NULL,
+ OCI_ATTR_PARAM_COUNT, oci_error);
+ if (status != OCI_SUCCESS)
+ {
+ o_report_error ("o_read_database_query", "OCIAttrGet", oci_error);
+ return (-1);
+ } /* }}} */
+
+ /* Allocate the following buffers:
+ *
+ * - buffer_instances q->instances_num x DATA_MAX_NAME_LEN
+ * - buffer_values q->values_num x NUMBER_BUFFER_SIZE
+ * - index_instances q->instances_num
+ * - index_values q->values_num
+ * - oci_defines q->instances_num+q->values_num
+ * {{{ */
+#define NUMBER_BUFFER_SIZE 64
+
+#define FREE_ALL \
+ if (buffer_instances != NULL) { \
+ sfree (buffer_instances[0]); \
+ sfree (buffer_instances); \
+ } \
+ if (buffer_values != NULL) { \
+ sfree (buffer_values[0]); \
+ sfree (buffer_values); \
+ } \
+ sfree (index_instances); \
+ sfree (index_values); \
+ sfree (oci_defines)
+
+#define ALLOC_OR_FAIL(ptr, ptr_size) \
+ do { \
+ size_t alloc_size = (size_t) ((ptr_size)); \
+ (ptr) = malloc (alloc_size); \
+ if ((ptr) == NULL) { \
+ FREE_ALL; \
+ ERROR ("oracle plugin: o_read_database_query: malloc failed."); \
+ return (-1); \
+ } \
+ memset ((ptr), 0, alloc_size); \
+ } while (0)
+
+ /* Initialize everything to NULL so the above works. */
+ buffer_instances = NULL;
+ buffer_values = NULL;
+ index_instances = NULL;
+ index_values = NULL;
+ oci_defines = NULL;
+
+ ALLOC_OR_FAIL (buffer_instances, q->instances_num * sizeof (char *));
+ ALLOC_OR_FAIL (buffer_instances[0], q->instances_num * DATA_MAX_NAME_LEN
+ * sizeof (char));
+ for (i = 1; i < q->instances_num; i++)
+ buffer_instances[i] = buffer_instances[i - 1] + DATA_MAX_NAME_LEN;
+
+ ALLOC_OR_FAIL (buffer_values, q->values_num * sizeof (char *));
+ ALLOC_OR_FAIL (buffer_values[0], q->values_num * NUMBER_BUFFER_SIZE
+ * sizeof (char));
+ for (i = 1; i < q->values_num; i++)
+ buffer_values[i] = buffer_values[i - 1] + NUMBER_BUFFER_SIZE;
+
+ ALLOC_OR_FAIL (index_instances, q->instances_num * sizeof (size_t));
+ ALLOC_OR_FAIL (index_values, q->values_num * sizeof (size_t));
+
+ ALLOC_OR_FAIL (oci_defines, (q->instances_num + q->values_num)
+ * sizeof (OCIDefine *));
+ /* }}} End of buffer allocations. */
+
+ /* ``Define'' the returned data, i. e. bind the columns to the buffers
+ * returned above. */
+ for (j = 1; j <= param_counter; j++) /* {{{ */
+ {
+ char *column_name;
+ size_t column_name_length;
+ char column_name_copy[DATA_MAX_NAME_LEN];
+ size_t i;
+ OCIParam *oci_param;
+
+ oci_param = NULL;
+
+ status = OCIParamGet (q->oci_statement, OCI_HTYPE_STMT, oci_error,
+ (void *) &oci_param, j);
+ if (status != OCI_SUCCESS)
+ {
+ /* This is probably alright */
+ DEBUG ("oracle plugin: o_read_database_query: status = %#x (= %i);", status, status);
+ o_report_error ("o_read_database_query", "OCIParamGet", oci_error);
+ status = OCI_SUCCESS;
+ break;
+ }
+
+ column_name = NULL;
+ column_name_length = 0;
+ status = OCIAttrGet (oci_param, OCI_DTYPE_PARAM,
+ &column_name, &column_name_length, OCI_ATTR_NAME, oci_error);
+ if (status != OCI_SUCCESS)
+ {
+ o_report_error ("o_read_database_query", "OCIAttrGet (OCI_ATTR_NAME)",
+ oci_error);
+ continue;
+ }
+
+ /* Ensure null-termination. */
+ memset (column_name_copy, 0, sizeof (column_name_copy));
+ if (column_name_length >= sizeof (column_name_copy))
+ column_name_length = sizeof (column_name_copy) - 1;
+ memcpy (column_name_copy, column_name, column_name_length);
+ column_name_copy[column_name_length] = 0;
+
+ DEBUG ("oracle plugin: o_read_database_query: column_name[%u] = %s; column_name_length = %zu;",
+ (unsigned int) j, column_name_copy, column_name_length);
+
+ for (i = 0; i < q->instances_num; i++)
+ {
+ if (strcasecmp (q->instances[i], column_name_copy) != 0)
+ continue;
+
+ status = OCIDefineByPos (q->oci_statement,
+ &oci_defines[i], oci_error, j,
+ buffer_instances[i], DATA_MAX_NAME_LEN, SQLT_STR,
+ NULL, NULL, NULL, OCI_DEFAULT);
+ index_instances[i] = j;
+
+ DEBUG ("oracle plugin: o_read_database_query: column[%u] (%s) -> instances[%zu]",
+ (unsigned int) j, column_name_copy, i);
+ break;
+ }
+
+ for (i = 0; i < q->values_num; i++)
+ {
+ if (strcasecmp (q->values[i], column_name_copy) != 0)
+ continue;
+
+ status = OCIDefineByPos (q->oci_statement,
+ &oci_defines[q->instances_num + i], oci_error, j,
+ buffer_values[i], NUMBER_BUFFER_SIZE, SQLT_STR,
+ NULL, NULL, NULL, OCI_DEFAULT);
+ index_values[i] = j;
+
+ DEBUG ("oracle plugin: o_read_database_query: column[%u] (%s) -> values[%zu]",
+ (unsigned int) j, column_name_copy, i);
+ break;
+ }
+ } /* for (j = 1; j <= param_counter; j++) */
+ /* }}} End of the ``define'' stuff. */
+
+ /* Iterate over all indizes and check that all columns from which we're
+ * supposed to read instances or values have been found. */
+ /* {{{ */
+ status = 0;
+ for (i = 0; i < q->instances_num; i++)
+ {
+ if (index_instances[i] > 0)
+ continue;
+
+ ERROR ("oracle plugin: o_read_database_query (%s, %s): "
+ "Instance %zu of the `%s' query should be read from the column `%s', "
+ "but that column wasn't returned by the SQL statement. Please check "
+ "your configuration.",
+ db->name, q->name, (i + 1), q->name, q->instances[i]);
+ status++;
+ }
+
+ for (i = 0; i < q->values_num; i++)
+ {
+ if (index_values[i] > 0)
+ continue;
+
+ ERROR ("oracle plugin: o_read_database_query (%s, %s): "
+ "Value %zu of the `%s' query should be read from the column `%s', "
+ "but that column wasn't returned by the SQL statement. Please check "
+ "your configuration.",
+ db->name, q->name, (i + 1), q->name, q->values[i]);
+ status++;
+ }
+
+ if (status != 0)
+ {
+ FREE_ALL;
+ return (-1);
+ }
+ /* }}} */
+
+ /* Fetch and handle all the rows that matched the query. */
+ while (42) /* {{{ */
+ {
+ status = OCIStmtFetch2 (q->oci_statement, oci_error,
+ /* nrows = */ 1, /* orientation = */ OCI_FETCH_NEXT,
+ /* fetch offset = */ 0, /* mode = */ OCI_DEFAULT);
+ if (status == OCI_NO_DATA)
+ {
+ status = OCI_SUCCESS;
+ break;
+ }
+ else if ((status != OCI_SUCCESS) && (status != OCI_SUCCESS_WITH_INFO))
+ {
+ o_report_error ("o_read_database_query", "OCIStmtFetch2", oci_error);
+ break;
+ }
+
+ for (i = 0; i < q->instances_num; i++)
+ {
+ DEBUG ("oracle plugin: o_read_database_query: "
+ "buffer_instances[%zu] = %s;",
+ i, buffer_instances[i]);
+ }
+
+ for (i = 0; i < q->values_num; i++)
+ {
+ DEBUG ("oracle plugin: o_read_database_query: "
+ "buffer_values[%zu] = %s;",
+ i, buffer_values[i]);
+ }
+
+ o_submit (db, q, ds, buffer_instances, buffer_values);
+ } /* }}} while (42) */
+
+ /* DEBUG ("oracle plugin: o_read_database_query: This statement succeeded: %s", q->statement); */
+ FREE_ALL;
+
+ return (0);
+#undef FREE_ALL
+#undef ALLOC_OR_FAIL
+} /* }}} int o_read_database_query */
+
+static int o_read_database (o_database_t *db) /* {{{ */
+{
+ size_t i;
+ int status;
+
+ if (db->oci_service_context == NULL)
+ {
+ status = OCILogon (oci_env, oci_error,
+ &db->oci_service_context,
+ (OraText *) db->username, (ub4) strlen (db->username),
+ (OraText *) db->password, (ub4) strlen (db->password),
+ (OraText *) db->connect_id, (ub4) strlen (db->connect_id));
+ if (status != OCI_SUCCESS)
+ {
+ o_report_error ("o_read_database", "OCILogon", oci_error);
+ DEBUG ("oracle plugin: OCILogon (%s): db->oci_service_context = %p;",
+ db->connect_id, db->oci_service_context);
+ db->oci_service_context = NULL;
+ return (-1);
+ }
+ assert (db->oci_service_context != NULL);
+ }
+
+ DEBUG ("oracle plugin: o_read_database: db->connect_id = %s; db->oci_service_context = %p;",
+ db->connect_id, db->oci_service_context);
+
+ for (i = 0; i < db->queries_num; i++)
+ o_read_database_query (db, db->queries[i]);
+
+ return (0);
+} /* }}} int o_read_database */
+
+static int o_read (void) /* {{{ */
+{
+ size_t i;
+
+ for (i = 0; i < databases_num; i++)
+ o_read_database (databases[i]);
+
+ return (0);
+} /* }}} int o_read */
+
+static int o_shutdown (void) /* {{{ */
+{
+ size_t i;
+
+ for (i = 0; i < databases_num; i++)
+ if (databases[i]->oci_service_context != NULL)
+ {
+ OCIHandleFree (databases[i]->oci_service_context, OCI_HTYPE_SVCCTX);
+ databases[i]->oci_service_context = NULL;
+ }
+
+ for (i = 0; i < queries_num; i++)
+ if (queries[i]->oci_statement != NULL)
+ {
+ OCIHandleFree (queries[i]->oci_statement, OCI_HTYPE_STMT);
+ queries[i]->oci_statement = NULL;
+ }
+
+ OCIHandleFree (oci_env, OCI_HTYPE_ENV);
+ return (0);
+} /* }}} int o_shutdown */
+
+void module_register (void) /* {{{ */
+{
+ plugin_register_complex_config ("oracle", o_config);
+ plugin_register_init ("oracle", o_init);
+ plugin_register_read ("oracle", o_read);
+ plugin_register_shutdown ("oracle", o_shutdown);
+} /* }}} void module_register */
+
+/*
+ * vim: shiftwidth=2 softtabstop=2 et fdm=marker
+ */
else if (0 == strcasecmp (c->key, "Plugin"))
current_status = perl_config_plugin (aTHX_ c);
else
+ {
log_warn ("Ignoring unknown config key \"%s\".", c->key);
+ current_status = 0;
+ }
/* fatal error - it's up to perl_config_* to clean up */
if (0 > current_status) {
#include "utils_llist.h"
#include "utils_cache.h"
#include "utils_threshold.h"
+#include "filter_chain.h"
/*
* Private structures
static llist_t *list_init;
static llist_t *list_read;
static llist_t *list_write;
+static llist_t *list_filter;
static llist_t *list_flush;
static llist_t *list_shutdown;
static llist_t *list_log;
return (register_callback (&list_write, name, (void *) callback));
} /* int plugin_register_write */
+int plugin_register_filter (const char *name,
+ int (*callback) (const data_set_t *ds, value_list_t *vl))
+{
+ return (register_callback (&list_filter, name, (void *) callback));
+} /* int plugin_register_filter */
+
int plugin_register_flush (const char *name,
int (*callback) (const int timeout, const char *identifier))
{
return (plugin_unregister (list_write, name));
}
+int plugin_unregister_filter (const char *name)
+{
+ return (plugin_unregister (list_filter, name));
+}
+
int plugin_unregister_flush (const char *name)
{
return (plugin_unregister (list_flush, name));
pthread_mutex_unlock (&read_lock);
} /* void plugin_read_all */
+int plugin_write (const char *plugin, /* {{{ */
+ const data_set_t *ds, const value_list_t *vl)
+{
+ int (*callback) (const data_set_t *ds, const value_list_t *vl);
+ llentry_t *le;
+ int status;
+
+ if (vl == NULL)
+ return (EINVAL);
+
+ if (list_write == NULL)
+ return (ENOENT);
+
+ if (ds == NULL)
+ {
+ ds = plugin_get_ds (vl->type);
+ if (ds == NULL)
+ {
+ ERROR ("plugin_write: Unable to lookup type `%s'.", vl->type);
+ return (ENOENT);
+ }
+ }
+
+ if (plugin == NULL)
+ {
+ int success = 0;
+ int failure = 0;
+
+ le = llist_head (list_write);
+ while (le != NULL)
+ {
+ callback = le->value;
+ status = (*callback) (ds, vl);
+ if (status != 0)
+ failure++;
+ else
+ success++;
+
+ le = le->next;
+ }
+
+ if ((success == 0) && (failure != 0))
+ status = -1;
+ else
+ status = 0;
+ }
+ else /* plugin != NULL */
+ {
+ le = llist_head (list_write);
+ while (le != NULL)
+ {
+ if (strcasecmp (plugin, le->key) == 0)
+ break;
+
+ le = le->next;
+ }
+
+ if (le == NULL)
+ return (ENOENT);
+
+ callback = le->value;
+ status = (*callback) (ds, vl);
+ }
+
+ return (status);
+} /* }}} int plugin_write */
+
int plugin_flush (const char *plugin, int timeout, const char *identifier)
{
int (*callback) (int timeout, const char *identifier);
int plugin_dispatch_values (value_list_t *vl)
{
- static c_complain_t no_write_complaint = C_COMPLAIN_INIT;
+ static c_complain_t no_write_complaint = C_COMPLAIN_INIT_STATIC;
- int (*callback) (const data_set_t *, const value_list_t *);
data_set_t *ds;
- llentry_t *le;
if ((vl == NULL) || (*vl->type == '\0')) {
ERROR ("plugin_dispatch_values: Invalid value list.");
/* Update the value cache */
uc_update (ds, vl);
- ut_check_threshold (ds, vl);
- le = llist_head (list_write);
- while (le != NULL)
- {
- callback = (int (*) (const data_set_t *, const value_list_t *)) le->value;
- (*callback) (ds, vl);
-
- le = le->next;
- }
+ fc_process (ds, vl);
return (0);
} /* int plugin_dispatch_values */
#define NOTIF_WARNING 2
#define NOTIF_OKAY 4
+#define FILTER_NOWRITE 1
+#define FILTER_NOTHRESHOLD_CHECK 2
+/* FILTER_IGNORE has to equal the bitwise or of all other filter flags */
+#define FILTER_IGNORE (FILTER_NOWRITE | FILTER_NOTHRESHOLD_CHECK)
+
/*
* Public data types
*/
void plugin_read_all (void);
void plugin_shutdown_all (void);
+/*
+ * NAME
+ * plugin_write
+ *
+ * DESCRIPTION
+ * Calls the write function of the given plugin with the provided data set and
+ * value list. It differs from `plugin_dispatch_value' in that it does not
+ * update the cache, does no do threshold checking, call the chain subsystem
+ * and so on. It looks up the requested plugin and invokes the function, end
+ * of story.
+ *
+ * ARGUMENTS
+ * plugin Name of the plugin. If NULL, the value is sent to all registered
+ * write functions.
+ * ds Pointer to the data_set_t structure. If NULL, the data set is
+ * looked up according to the `type' member in the `vl' argument.
+ * vl The actual value to be processes. Must not be NULL.
+ *
+ * RETURN VALUE
+ * Returns zero upon success or non-zero if an error occurred. If `plugin' is
+ * NULL and more than one plugin is called, an error is only returned if *all*
+ * plugins fail.
+ *
+ * NOTES
+ * This is the function used by the `write' built-in target. May be used by
+ * other target plugins.
+ */
+int plugin_write (const char *plugin,
+ const data_set_t *ds, const value_list_t *vl);
+
int plugin_flush (const char *plugin, int timeout, const char *identifier);
/*
int (*callback) (void));
int plugin_register_write (const char *name,
int (*callback) (const data_set_t *ds, const value_list_t *vl));
+int plugin_register_filter (const char *name,
+ int (*callback) (const data_set_t *ds, value_list_t *vl));
int plugin_register_flush (const char *name,
int (*callback) (const int timeout, const char *identifier));
int plugin_register_shutdown (char *name,
int plugin_unregister_init (const char *name);
int plugin_unregister_read (const char *name);
int plugin_unregister_write (const char *name);
+int plugin_unregister_filter (const char *name);
int plugin_unregister_flush (const char *name);
int plugin_unregister_shutdown (const char *name);
int plugin_unregister_data_set (const char *name);
db->conn = NULL;
- db->conn_complaint.last = 0;
- db->conn_complaint.interval = 0;
+ C_COMPLAIN_INIT (&db->conn_complaint);
db->proto_version = 0;
--- /dev/null
+/**
+ * collectd - src/rrdcached.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 verplant.org>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+#include "utils_rrdcreate.h"
+
+#include <rrd_client.h>
+
+/*
+ * Private variables
+ */
+static const char *config_keys[] =
+{
+ "DaemonAddress",
+ "DataDir",
+ "CreateFiles",
+ "CollectStatistics"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static char *datadir = NULL;
+static char *daemon_address = NULL;
+static int config_create_files = 1;
+static int config_collect_stats = 1;
+static rrdcreate_config_t rrdcreate_config =
+{
+ /* stepsize = */ 0,
+ /* heartbeat = */ 0,
+ /* rrarows = */ 1200,
+ /* xff = */ 0.1,
+
+ /* timespans = */ NULL,
+ /* timespans_num = */ 0,
+
+ /* consolidation_functions = */ NULL,
+ /* consolidation_functions_num = */ 0
+};
+
+static int value_list_to_string (char *buffer, int buffer_len,
+ const data_set_t *ds, const value_list_t *vl)
+{
+ int offset;
+ int status;
+ int i;
+
+ assert (0 == strcmp (ds->type, vl->type));
+
+ memset (buffer, '\0', buffer_len);
+
+ status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+ if ((status < 1) || (status >= buffer_len))
+ return (-1);
+ offset = status;
+
+ for (i = 0; i < ds->ds_num; i++)
+ {
+ if ((ds->ds[i].type != DS_TYPE_COUNTER)
+ && (ds->ds[i].type != DS_TYPE_GAUGE))
+ return (-1);
+
+ if (ds->ds[i].type == DS_TYPE_COUNTER)
+ {
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ ":%llu", vl->values[i].counter);
+ }
+ else /* if (ds->ds[i].type == DS_TYPE_GAUGE) */
+ {
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ ":%lf", vl->values[i].gauge);
+ }
+
+ if ((status < 1) || (status >= (buffer_len - offset)))
+ return (-1);
+
+ offset += status;
+ } /* for ds->ds_num */
+
+ return (0);
+} /* int value_list_to_string */
+
+static int value_list_to_filename (char *buffer, int buffer_len,
+ const data_set_t *ds, const value_list_t *vl)
+{
+ int offset = 0;
+ int status;
+
+ assert (0 == strcmp (ds->type, vl->type));
+
+ if (datadir != NULL)
+ {
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ "%s/", datadir);
+ if ((status < 1) || (status >= buffer_len - offset))
+ return (-1);
+ offset += status;
+ }
+
+ 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 = ssnprintf (buffer + offset, buffer_len - offset,
+ "%s-%s/", vl->plugin, vl->plugin_instance);
+ else
+ 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 = ssnprintf (buffer + offset, buffer_len - offset,
+ "%s-%s", vl->type, vl->type_instance);
+ else
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ "%s", vl->type);
+ if ((status < 1) || (status >= buffer_len - offset))
+ return (-1);
+ offset += status;
+
+ strncpy (buffer + offset, ".rrd", buffer_len - offset);
+ buffer[buffer_len - 1] = 0;
+
+ return (0);
+} /* int value_list_to_filename */
+
+static int rc_config (const char *key, const char *value)
+{
+ if (strcasecmp ("DataDir", key) == 0)
+ {
+ if (datadir != NULL)
+ free (datadir);
+ datadir = strdup (value);
+ if (datadir != NULL)
+ {
+ int len = strlen (datadir);
+ while ((len > 0) && (datadir[len - 1] == '/'))
+ {
+ len--;
+ datadir[len] = '\0';
+ }
+ if (len <= 0)
+ {
+ free (datadir);
+ datadir = NULL;
+ }
+ }
+ }
+ else if (strcasecmp ("DaemonAddress", key) == 0)
+ {
+ sfree (daemon_address);
+ daemon_address = strdup (value);
+ if (daemon_address == NULL)
+ {
+ ERROR ("rrdcached plugin: strdup failed.");
+ return (1);
+ }
+ }
+ else if (strcasecmp ("CreateFiles", key) == 0)
+ {
+ if ((strcasecmp ("false", value) == 0)
+ || (strcasecmp ("no", value) == 0)
+ || (strcasecmp ("off", value) == 0))
+ config_create_files = 0;
+ else
+ config_create_files = 1;
+ }
+ else if (strcasecmp ("CollectStatistics", key) == 0)
+ {
+ if ((strcasecmp ("false", value) == 0)
+ || (strcasecmp ("no", value) == 0)
+ || (strcasecmp ("off", value) == 0))
+ config_collect_stats = 0;
+ else
+ config_collect_stats = 1;
+ }
+ else
+ {
+ return (-1);
+ }
+ return (0);
+} /* int rc_config */
+
+static int rc_read (void)
+{
+ int status;
+ rrdc_stats_t *head;
+ rrdc_stats_t *ptr;
+
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ if (daemon_address == NULL)
+ return (-1);
+
+ if (config_collect_stats == 0)
+ return (-1);
+
+ vl.values = values;
+ vl.values_len = 1;
+ vl.time = time (NULL);
+
+ if ((strncmp ("unix:", daemon_address, strlen ("unix:")) == 0)
+ || (daemon_address[0] == '/'))
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ else
+ sstrncpy (vl.host, daemon_address, sizeof (vl.host));
+ sstrncpy (vl.plugin, "rrdcached", sizeof (vl.plugin));
+
+ head = NULL;
+ status = rrdc_stats_get (&head);
+ if (status != 0)
+ {
+ ERROR ("rrdcached plugin: rrdc_stats_get failed with status %i.", status);
+ return (-1);
+ }
+
+ for (ptr = head; ptr != NULL; ptr = ptr->next)
+ {
+ if (ptr->type == RRDC_STATS_TYPE_GAUGE)
+ values[0].gauge = (gauge_t) ptr->value.gauge;
+ else if (ptr->type == RRDC_STATS_TYPE_COUNTER)
+ values[0].counter = (counter_t) ptr->value.counter;
+ else
+ continue;
+
+ if (strcasecmp ("QueueLength", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "queue_length", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
+ }
+ else if (strcasecmp ("UpdatesWritten", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "operations", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "write-updates", sizeof (vl.type_instance));
+ }
+ else if (strcasecmp ("DataSetsWritten", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "operations", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "write-data_sets",
+ sizeof (vl.type_instance));
+ }
+ else if (strcasecmp ("TreeNodesNumber", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "gauge", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "tree_nodes", sizeof (vl.type_instance));
+ }
+ else if (strcasecmp ("TreeDepth", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "gauge", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "tree_depth", sizeof (vl.type_instance));
+ }
+ else if (strcasecmp ("FlushesReceived", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "operations", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "receive-flush", sizeof (vl.type_instance));
+ }
+ else if (strcasecmp ("JournalBytes", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "counter", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "journal-bytes", sizeof (vl.type_instance));
+ }
+ else if (strcasecmp ("JournalRotate", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "counter", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "journal-rotates", sizeof (vl.type_instance));
+ }
+ else if (strcasecmp ("UpdatesReceived", ptr->name) == 0)
+ {
+ sstrncpy (vl.type, "operations", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "receive-update", sizeof (vl.type_instance));
+ }
+ else
+ {
+ DEBUG ("rrdcached plugin: rc_read: Unknown statistic `%s'.", ptr->name);
+ continue;
+ }
+
+ plugin_dispatch_values (&vl);
+ } /* for (ptr = head; ptr != NULL; ptr = ptr->next) */
+
+ rrdc_stats_free (head);
+
+ return (0);
+} /* int rc_read */
+
+static int rc_init (void)
+{
+ if (config_collect_stats != 0)
+ plugin_register_read ("rrdcached", rc_read);
+
+ return (0);
+} /* int rc_init */
+
+static int rc_write (const data_set_t *ds, const value_list_t *vl)
+{
+ char filename[512];
+ char values[512];
+ char *values_array[2];
+ int status;
+
+ if (daemon_address == NULL)
+ {
+ ERROR ("rrdcached plugin: daemon_address == NULL.");
+ plugin_unregister_write ("rrdcached");
+ return (-1);
+ }
+
+ if (strcmp (ds->type, vl->type) != 0)
+ {
+ ERROR ("rrdcached plugin: DS type does not match value list type");
+ return (-1);
+ }
+
+ if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
+ {
+ ERROR ("rrdcached plugin: value_list_to_filename failed.");
+ return (-1);
+ }
+
+ if (value_list_to_string (values, sizeof (values), ds, vl) != 0)
+ {
+ ERROR ("rrdcached plugin: value_list_to_string failed.");
+ return (-1);
+ }
+
+ values_array[0] = values;
+ values_array[1] = NULL;
+
+ if (config_create_files != 0)
+ {
+ struct stat statbuf;
+
+ status = stat (filename, &statbuf);
+ if (status != 0)
+ {
+ if (errno != ENOENT)
+ {
+ char errbuf[1024];
+ ERROR ("rrdcached plugin: stat (%s) failed: %s",
+ filename, sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ status = cu_rrd_create_file (filename, ds, vl, &rrdcreate_config);
+ if (status != 0)
+ {
+ ERROR ("rrdcached plugin: cu_rrd_create_file (%s) failed.",
+ filename);
+ return (-1);
+ }
+ }
+ }
+
+ status = rrdc_connect (daemon_address);
+ if (status != 0)
+ {
+ ERROR ("rrdcached plugin: rrdc_connect (%s) failed with status %i.",
+ daemon_address, status);
+ return (-1);
+ }
+
+ status = rrdc_update (filename, /* values_num = */ 1, (void *) values_array);
+ if (status != 0)
+ {
+ ERROR ("rrdcached plugin: rrdc_update (%s, [%s], 1) failed with "
+ "status %i.",
+ filename, values_array[0], status);
+ return (-1);
+ }
+
+ return (0);
+} /* int rc_write */
+
+static int rc_shutdown (void)
+{
+ rrdc_disconnect ();
+ return (0);
+} /* int rc_shutdown */
+
+void module_register (void)
+{
+ plugin_register_config ("rrdcached", rc_config,
+ config_keys, config_keys_num);
+ plugin_register_init ("rrdcached", rc_init);
+ plugin_register_write ("rrdcached", rc_write);
+ plugin_register_shutdown ("rrdcached", rc_shutdown);
+} /* void module_register */
+
+/*
+ * vim: set sw=2 sts=2 et :
+ */
#include "plugin.h"
#include "common.h"
#include "utils_avltree.h"
+#include "utils_rrdcreate.h"
#include <rrd.h>
/*
* Private variables
*/
-static int rra_timespans[] =
-{
- 3600,
- 86400,
- 604800,
- 2678400,
- 31622400
-};
-static int rra_timespans_num = STATIC_ARRAY_SIZE (rra_timespans);
-
-static int *rra_timespans_custom = NULL;
-static int rra_timespans_custom_num = 0;
-
-static char *rra_types[] =
-{
- "AVERAGE",
- "MIN",
- "MAX"
-};
-static int rra_types_num = STATIC_ARRAY_SIZE (rra_types);
-
static const char *config_keys[] =
{
"CacheTimeout",
/* If datadir is zero, the daemon's basedir is used. If stepsize or heartbeat
* is zero a default, depending on the `interval' member of the value list is
* being used. */
-static char *datadir = NULL;
-static int stepsize = 0;
-static int heartbeat = 0;
-static int rrarows = 1200;
-static double xff = 0.1;
-static double write_rate = 0.0;
+static char *datadir = NULL;
+static double write_rate = 0.0;
+static rrdcreate_config_t rrdcreate_config =
+{
+ /* stepsize = */ 0,
+ /* heartbeat = */ 0,
+ /* rrarows = */ 1200,
+ /* xff = */ 0.1,
+
+ /* timespans = */ NULL,
+ /* timespans_num = */ 0,
+
+ /* consolidation_functions = */ NULL,
+ /* consolidation_functions_num = */ 0
+};
/* XXX: If you need to lock both, cache_lock and queue_lock, at the same time,
* ALWAYS lock `cache_lock' first! */
static int do_shutdown = 0;
-/* * * * * * * * * *
- * WARNING: Magic *
- * * * * * * * * * */
-
-static void rra_free (int rra_num, char **rra_def)
-{
- int i;
-
- for (i = 0; i < rra_num; i++)
- {
- sfree (rra_def[i]);
- }
- sfree (rra_def);
-} /* void rra_free */
-
-static int rra_get (char ***ret, const value_list_t *vl)
-{
- char **rra_def;
- int rra_num;
-
- int *rts;
- int rts_num;
-
- int rra_max;
-
- int span;
-
- int cdp_num;
- int cdp_len;
- int i, j;
-
- char buffer[64];
-
- /* The stepsize we use here: If it is user-set, use it. If not, use the
- * interval of the value-list. */
- int ss;
-
- if (rrarows <= 0)
- {
- *ret = NULL;
- return (-1);
- }
-
- ss = (stepsize > 0) ? stepsize : vl->interval;
- if (ss <= 0)
- {
- *ret = NULL;
- return (-1);
- }
-
- /* Use the configured timespans or fall back to the built-in defaults */
- if (rra_timespans_custom_num != 0)
- {
- rts = rra_timespans_custom;
- rts_num = rra_timespans_custom_num;
- }
- else
- {
- rts = rra_timespans;
- rts_num = rra_timespans_num;
- }
-
- rra_max = rts_num * rra_types_num;
-
- if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
- return (-1);
- memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
- rra_num = 0;
-
- cdp_len = 0;
- for (i = 0; i < rts_num; i++)
- {
- span = rts[i];
-
- if ((span / ss) < rrarows)
- span = ss * rrarows;
-
- if (cdp_len == 0)
- cdp_len = 1;
- else
- cdp_len = (int) floor (((double) span)
- / ((double) (rrarows * ss)));
-
- cdp_num = (int) ceil (((double) span)
- / ((double) (cdp_len * ss)));
-
- for (j = 0; j < rra_types_num; j++)
- {
- if (rra_num >= rra_max)
- break;
-
- if (ssnprintf (buffer, sizeof (buffer), "RRA:%s:%3.1f:%u:%u",
- rra_types[j], xff,
- cdp_len, cdp_num) >= sizeof (buffer))
- {
- ERROR ("rra_get: Buffer would have been truncated.");
- continue;
- }
-
- rra_def[rra_num++] = sstrdup (buffer);
- }
- }
-
-#if COLLECT_DEBUG
- DEBUG ("rra_num = %i", rra_num);
- for (i = 0; i < rra_num; i++)
- DEBUG (" %s", rra_def[i]);
-#endif
-
- *ret = rra_def;
- return (rra_num);
-} /* int rra_get */
-
-static void ds_free (int ds_num, char **ds_def)
-{
- int i;
-
- for (i = 0; i < ds_num; i++)
- if (ds_def[i] != NULL)
- free (ds_def[i]);
- free (ds_def);
-}
-
-static int ds_get (char ***ret, const data_set_t *ds, const value_list_t *vl)
-{
- char **ds_def;
- int ds_num;
-
- char min[32];
- char max[32];
- char buffer[128];
-
- DEBUG ("ds->ds_num = %i", ds->ds_num);
-
- ds_def = (char **) malloc (ds->ds_num * sizeof (char *));
- if (ds_def == NULL)
- {
- char errbuf[1024];
- ERROR ("rrdtool plugin: malloc failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (-1);
- }
- memset (ds_def, '\0', ds->ds_num * sizeof (char *));
-
- for (ds_num = 0; ds_num < ds->ds_num; ds_num++)
- {
- data_source_t *d = ds->ds + ds_num;
- char *type;
- int status;
-
- ds_def[ds_num] = NULL;
-
- if (d->type == DS_TYPE_COUNTER)
- type = "COUNTER";
- else if (d->type == DS_TYPE_GAUGE)
- type = "GAUGE";
- else
- {
- ERROR ("rrdtool plugin: Unknown DS type: %i",
- d->type);
- break;
- }
-
- if (isnan (d->min))
- {
- sstrncpy (min, "U", sizeof (min));
- }
- else
- ssnprintf (min, sizeof (min), "%lf", d->min);
-
- if (isnan (d->max))
- {
- sstrncpy (max, "U", sizeof (max));
- }
- else
- ssnprintf (max, sizeof (max), "%lf", d->max);
-
- status = ssnprintf (buffer, sizeof (buffer),
- "DS:%s:%s:%i:%s:%s",
- d->name, type,
- (heartbeat > 0) ? heartbeat : (2 * vl->interval),
- min, max);
- if ((status < 1) || (status >= sizeof (buffer)))
- break;
-
- ds_def[ds_num] = sstrdup (buffer);
- } /* for ds_num = 0 .. ds->ds_num */
-
-#if COLLECT_DEBUG
-{
- int i;
- DEBUG ("ds_num = %i", ds_num);
- for (i = 0; i < ds_num; i++)
- DEBUG (" %s", ds_def[i]);
-}
-#endif
-
- if (ds_num != ds->ds_num)
- {
- ds_free (ds_num, ds_def);
- return (-1);
- }
-
- *ret = ds_def;
- return (ds_num);
-}
-
#if HAVE_THREADSAFE_LIBRRD
-static int srrd_create (char *filename, unsigned long pdp_step, time_t last_up,
- int argc, const char **argv)
-{
- int status;
-
- optind = 0; /* bug in librrd? */
- rrd_clear_error ();
-
- status = rrd_create_r (filename, pdp_step, last_up, argc, (void *) argv);
-
- if (status != 0)
- {
- WARNING ("rrdtool plugin: rrd_create_r (%s) failed: %s",
- filename, rrd_get_error ());
- }
-
- return (status);
-} /* int srrd_create */
-
static int srrd_update (char *filename, char *template,
int argc, const char **argv)
{
/* #endif HAVE_THREADSAFE_LIBRRD */
#else /* !HAVE_THREADSAFE_LIBRRD */
-static int srrd_create (char *filename, unsigned long pdp_step, time_t last_up,
- int argc, const char **argv)
-{
- int status;
-
- int new_argc;
- char **new_argv;
-
- char pdp_step_str[16];
- char last_up_str[16];
-
- new_argc = 6 + argc;
- new_argv = (char **) malloc ((new_argc + 1) * sizeof (char *));
- if (new_argv == NULL)
- {
- ERROR ("rrdtool plugin: malloc failed.");
- return (-1);
- }
-
- if (last_up == 0)
- last_up = time (NULL) - 10;
-
- 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;
- new_argv[2] = "-s";
- new_argv[3] = pdp_step_str;
- new_argv[4] = "-b";
- new_argv[5] = last_up_str;
-
- memcpy (new_argv + 6, argv, argc * sizeof (char *));
- new_argv[new_argc] = NULL;
-
- pthread_mutex_lock (&librrd_lock);
- optind = 0; /* bug in librrd? */
- rrd_clear_error ();
-
- status = rrd_create (new_argc, new_argv);
- pthread_mutex_unlock (&librrd_lock);
-
- if (status != 0)
- {
- WARNING ("rrdtool plugin: rrd_create (%s) failed: %s",
- filename, rrd_get_error ());
- }
-
- sfree (new_argv);
-
- return (status);
-} /* int srrd_create */
-
static int srrd_update (char *filename, char *template,
int argc, const char **argv)
{
} /* int srrd_update */
#endif /* !HAVE_THREADSAFE_LIBRRD */
-static int rrd_create_file (char *filename, const data_set_t *ds, const value_list_t *vl)
-{
- char **argv;
- int argc;
- char **rra_def;
- int rra_num;
- char **ds_def;
- int ds_num;
- int status = 0;
-
- if (check_create_dir (filename))
- return (-1);
-
- if ((rra_num = rra_get (&rra_def, vl)) < 1)
- {
- ERROR ("rrd_create_file failed: Could not calculate RRAs");
- return (-1);
- }
-
- if ((ds_num = ds_get (&ds_def, ds, vl)) < 1)
- {
- ERROR ("rrd_create_file failed: Could not calculate DSes");
- return (-1);
- }
-
- argc = ds_num + rra_num;
-
- if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
- {
- char errbuf[1024];
- ERROR ("rrd_create failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (-1);
- }
-
- memcpy (argv, ds_def, ds_num * sizeof (char *));
- memcpy (argv + ds_num, rra_def, rra_num * sizeof (char *));
- argv[ds_num + rra_num] = NULL;
-
- assert (vl->time > 10);
- status = srrd_create (filename,
- (stepsize > 0) ? stepsize : vl->interval,
- vl->time - 10,
- argc, (const char **)argv);
-
- free (argv);
- ds_free (ds_num, ds_def);
- rra_free (rra_num, rra_def);
-
- return (status);
-}
-
static int value_list_to_string (char *buffer, int buffer_len,
const data_set_t *ds, const value_list_t *vl)
{
{
if (errno == ENOENT)
{
- if (rrd_create_file (filename, ds, vl))
+ status = cu_rrd_create_file (filename,
+ ds, vl, &rrdcreate_config);
+ if (status != 0)
return (-1);
}
else
}
else if (strcasecmp ("StepSize", key) == 0)
{
- stepsize = atoi (value);
- if (stepsize < 0)
- stepsize = 0;
+ int temp = atoi (value);
+ if (temp > 0)
+ rrdcreate_config.stepsize = temp;
}
else if (strcasecmp ("HeartBeat", key) == 0)
{
- heartbeat = atoi (value);
- if (heartbeat < 0)
- heartbeat = 0;
+ int temp = atoi (value);
+ if (temp > 0)
+ rrdcreate_config.heartbeat = temp;
}
else if (strcasecmp ("RRARows", key) == 0)
{
"be greater than 0.\n");
return (1);
}
- rrarows = tmp;
+ rrdcreate_config.rrarows = tmp;
}
else if (strcasecmp ("RRATimespan", key) == 0)
{
{
dummy = NULL;
- tmp_alloc = realloc (rra_timespans_custom,
- sizeof (int) * (rra_timespans_custom_num + 1));
+ tmp_alloc = realloc (rrdcreate_config.timespans,
+ sizeof (int) * (rrdcreate_config.timespans_num + 1));
if (tmp_alloc == NULL)
{
fprintf (stderr, "rrdtool: realloc failed.\n");
free (value_copy);
return (1);
}
- rra_timespans_custom = tmp_alloc;
- rra_timespans_custom[rra_timespans_custom_num] = atoi (ptr);
- if (rra_timespans_custom[rra_timespans_custom_num] != 0)
- rra_timespans_custom_num++;
+ rrdcreate_config.timespans = tmp_alloc;
+ rrdcreate_config.timespans[rrdcreate_config.timespans_num] = atoi (ptr);
+ if (rrdcreate_config.timespans[rrdcreate_config.timespans_num] != 0)
+ rrdcreate_config.timespans_num++;
} /* while (strtok_r) */
- qsort (/* base = */ rra_timespans_custom,
- /* nmemb = */ rra_timespans_custom_num,
- /* size = */ sizeof (rra_timespans_custom[0]),
+ qsort (/* base = */ rrdcreate_config.timespans,
+ /* nmemb = */ rrdcreate_config.timespans_num,
+ /* size = */ sizeof (rrdcreate_config.timespans[0]),
/* compar = */ rrd_compare_numeric);
free (value_copy);
"be in the range 0 to 1 (exclusive).");
return (1);
}
- xff = tmp;
+ rrdcreate_config.xff = tmp;
}
else if (strcasecmp ("WritesPerSecond", key) == 0)
{
{
int status;
- if (stepsize < 0)
- stepsize = 0;
- if (heartbeat <= 0)
- heartbeat = 2 * stepsize;
+ if (rrdcreate_config.stepsize < 0)
+ rrdcreate_config.stepsize = 0;
+ if (rrdcreate_config.heartbeat <= 0)
+ rrdcreate_config.heartbeat = 2 * rrdcreate_config.stepsize;
- if ((heartbeat > 0) && (heartbeat < interval_g))
+ if ((rrdcreate_config.heartbeat > 0)
+ && (rrdcreate_config.heartbeat < interval_g))
WARNING ("rrdtool plugin: Your `heartbeat' is "
"smaller than your `interval'. This will "
"likely cause problems.");
- else if ((stepsize > 0) && (stepsize < interval_g))
+ else if ((rrdcreate_config.stepsize > 0)
+ && (rrdcreate_config.stepsize < interval_g))
WARNING ("rrdtool plugin: Your `stepsize' is "
"smaller than your `interval'. This will "
"create needlessly big RRD-files.");
DEBUG ("rrdtool plugin: rrd_init: datadir = %s; stepsize = %i;"
" heartbeat = %i; rrarows = %i; xff = %lf;",
(datadir == NULL) ? "(null)" : datadir,
- stepsize, heartbeat, rrarows, xff);
+ rrdcreate_config.stepsize,
+ rrdcreate_config.heartbeat,
+ rrdcreate_config.rrarows,
+ rrdcreate_config.xff);
return (0);
} /* int rrd_init */
#include "collectd.h"
#include "common.h"
#include "plugin.h"
+#include "utils_complain.h"
#include <pthread.h>
char *community;
int version;
void *sess_handle;
+ c_complain_t complaint;
uint32_t interval;
time_t next_update;
data_definition_t **data_list;
/*
* Private functions
*/
+/* Many functions to handle the configuration. {{{ */
/* First there are many functions which do configuration stuff. It's a big
* bloated and messy, I'm afraid. */
return (-1);
memset (hd, '\0', sizeof (host_definition_t));
hd->version = 2;
+ C_COMPLAIN_INIT (&hd->complaint);
hd->name = strdup (ci->values[0].value.string);
if (hd->name == NULL)
return (0);
} /* int csnmp_config */
-/* End of the config stuff. Now the interesting part begins */
+/* }}} End of the config stuff. Now the interesting part begins */
static void csnmp_host_close_session (host_definition_t *host)
{
char *errstr = NULL;
snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
- ERROR ("snmp plugin: host %s: snmp_sess_synch_response failed: %s",
+
+ c_complain (LOG_ERR, &host->complaint,
+ "snmp plugin: host %s: snmp_sess_synch_response failed: %s",
host->name, (errstr == NULL) ? "Unknown problem" : errstr);
if (res != NULL)
}
status = 0;
assert (res != NULL);
+ c_release (LOG_INFO, &host->complaint,
+ "snmp plugin: host %s: snmp_sess_synch_response successful.",
+ host->name);
vb = res->variables;
if (vb == NULL)
} /* void module_register */
/*
- * vim: shiftwidth=2 softtabstop=2 tabstop=8
+ * vim: shiftwidth=2 softtabstop=2 tabstop=8 fdm=marker
*/
--- /dev/null
+/**
+ * collectd - src/target_set.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
+ *
+ * Authors:
+ * Florian Forster <octo at verplant.org>
+ **/
+
+/*
+ * First tell the compiler to stick to the C99 and POSIX standards as close as
+ * possible.
+ */
+#ifndef __STRICT_ANSI__ /* {{{ */
+# define __STRICT_ANSI__
+#endif
+
+#ifndef _ISOC99_SOURCE
+# define _ISOC99_SOURCE
+#endif
+
+#ifdef _POSIX_C_SOURCE
+# undef _POSIX_C_SOURCE
+#endif
+#define _POSIX_C_SOURCE 200112L
+
+#if 0
+/* Single UNIX needed for strdup. */
+#ifdef _XOPEN_SOURCE
+# undef _XOPEN_SOURCE
+#endif
+#define _XOPEN_SOURCE 500
+#endif
+
+#ifndef _REENTRANT
+# define _REENTRANT
+#endif
+
+#ifndef _THREAD_SAFE
+# define _THREAD_SAFE
+#endif
+
+#ifdef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* }}} */
+
+#include "collectd.h"
+#include "common.h"
+#include "filter_chain.h"
+
+struct ts_data_s
+{
+ char *host;
+ char *plugin;
+ char *plugin_instance;
+ /* char *type; */
+ char *type_instance;
+};
+typedef struct ts_data_s ts_data_t;
+
+static char *ts_strdup (const char *orig) /* {{{ */
+{
+ size_t sz;
+ char *dest;
+
+ if (orig == NULL)
+ return (NULL);
+
+ sz = strlen (orig) + 1;
+ dest = (char *) malloc (sz);
+ if (dest == NULL)
+ return (NULL);
+
+ memcpy (dest, orig, sz);
+
+ return (dest);
+} /* }}} char *ts_strdup */
+
+static int ts_config_add_string (char **dest, /* {{{ */
+ const oconfig_item_t *ci, int may_be_empty)
+{
+ char *temp;
+
+ if (dest == NULL)
+ return (-EINVAL);
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ ERROR ("Target `set': The `%s' option requires exactly one string "
+ "argument.", ci->key);
+ return (-1);
+ }
+
+ if ((!may_be_empty) && (ci->values[0].value.string[0] == 0))
+ {
+ ERROR ("Target `set': The `%s' option does not accept empty strings.",
+ ci->key);
+ return (-1);
+ }
+
+ temp = ts_strdup (ci->values[0].value.string);
+ if (temp == NULL)
+ {
+ ERROR ("ts_config_add_string: ts_strdup failed.");
+ return (-1);
+ }
+
+ free (*dest);
+ *dest = temp;
+
+ return (0);
+} /* }}} int ts_config_add_string */
+
+static int ts_destroy (void **user_data) /* {{{ */
+{
+ ts_data_t *data;
+
+ if (user_data == NULL)
+ return (-EINVAL);
+
+ data = *user_data;
+ if (data == NULL)
+ return (0);
+
+ free (data->host);
+ free (data->plugin);
+ free (data->plugin_instance);
+ /* free (data->type); */
+ free (data->type_instance);
+ free (data);
+
+ return (0);
+} /* }}} int ts_destroy */
+
+static int ts_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
+{
+ ts_data_t *data;
+ int status;
+ int i;
+
+ data = (ts_data_t *) malloc (sizeof (*data));
+ if (data == NULL)
+ {
+ ERROR ("ts_create: malloc failed.");
+ return (-ENOMEM);
+ }
+ memset (data, 0, sizeof (*data));
+
+ data->host = NULL;
+ data->plugin = NULL;
+ data->plugin_instance = NULL;
+ /* data->type = NULL; */
+ data->type_instance = NULL;
+
+ status = 0;
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if ((strcasecmp ("Host", child->key) == 0)
+ || (strcasecmp ("Hostname", child->key) == 0))
+ status = ts_config_add_string (&data->host, child,
+ /* may be empty = */ 0);
+ else if (strcasecmp ("Plugin", child->key) == 0)
+ status = ts_config_add_string (&data->plugin, child,
+ /* may be empty = */ 0);
+ else if (strcasecmp ("PluginInstance", child->key) == 0)
+ status = ts_config_add_string (&data->plugin_instance, child,
+ /* may be empty = */ 1);
+#if 0
+ else if (strcasecmp ("Type", child->key) == 0)
+ status = ts_config_add_string (&data->type, child,
+ /* may be empty = */ 0);
+#endif
+ else if (strcasecmp ("TypeInstance", child->key) == 0)
+ status = ts_config_add_string (&data->type_instance, child,
+ /* may be empty = */ 1);
+ else
+ {
+ ERROR ("Target `set': The `%s' configuration option is not understood "
+ "and will be ignored.", child->key);
+ status = 0;
+ }
+
+ if (status != 0)
+ break;
+ }
+
+ /* Additional sanity-checking */
+ while (status == 0)
+ {
+ if ((data->host == NULL)
+ && (data->plugin == NULL)
+ && (data->plugin_instance == NULL)
+ /* && (data->type == NULL) */
+ && (data->type_instance == NULL))
+ {
+ ERROR ("Target `set': You need to set at lease one of `Host', "
+ "`Plugin', `PluginInstance', `Type', or `TypeInstance'.");
+ status = -1;
+ }
+
+ break;
+ }
+
+ if (status != 0)
+ {
+ ts_destroy ((void *) &data);
+ return (status);
+ }
+
+ *user_data = data;
+ return (0);
+} /* }}} int ts_create */
+
+static int ts_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */
+ notification_meta_t **meta, void **user_data)
+{
+ ts_data_t *data;
+
+ if ((ds == NULL) || (vl == NULL) || (user_data == NULL))
+ return (-EINVAL);
+
+ data = *user_data;
+ if (data == NULL)
+ {
+ ERROR ("Target `set': Invoke: `data' is NULL.");
+ return (-EINVAL);
+ }
+
+#define SET_FIELD(f) if (data->f != NULL) { sstrncpy (vl->f, data->f, sizeof (vl->f)); }
+ SET_FIELD (host);
+ SET_FIELD (plugin);
+ SET_FIELD (plugin_instance);
+ /* SET_FIELD (type); */
+ SET_FIELD (type_instance);
+
+ return (FC_TARGET_CONTINUE);
+} /* }}} int ts_invoke */
+
+void module_register (void)
+{
+ target_proc_t tproc;
+
+ memset (&tproc, 0, sizeof (tproc));
+ tproc.create = ts_create;
+ tproc.destroy = ts_destroy;
+ tproc.invoke = ts_invoke;
+ fc_register_target ("set", tproc);
+} /* module_register */
+
+/* vim: set sw=2 sts=2 tw=78 et fdm=marker : */
+
nfs_procedure value:COUNTER:0:4294967295
nginx_connections value:GAUGE:0:U
nginx_requests value:COUNTER:0:134217728
+operations value:COUNTER:0:4294967295
percent percent:GAUGE:0:100.1
pg_blks value:COUNTER:0:U
pg_db_size value:GAUGE:0:U
ps_pagefaults minflt:COUNTER:0:9223372036854775807, majflt:COUNTER:0:9223372036854775807
ps_rss value:GAUGE:0:9223372036854775807
ps_state value:GAUGE:0:65535
+queue_length value:GAUGE:0:U
serial_octets rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
signal_noise value:GAUGE:U:0
signal_power value:GAUGE:U:0
=head1 FILES
The location of the types.db file is defined by the B<TypesDB> configuration
-option (see L<collectd.conf(5)>). If you want to specify custom data-sets, you
-should do so by using a custom file specified as an additional argument to the
-B<TypesDB> option.
+option (see L<collectd.conf(5)>). It defaults to collectd's shared data
+directory, i.E<nbsp>e. F<I<prefix>/share/collectd/>. If you want to specify
+custom data-sets, you should do so by using a custom file specified as an
+additional argument to the B<TypesDB> option.
=head1 SEE ALSO
#ifndef UTILS_CMD_FLUSH_H
#define UTILS_CMD_FLUSH_H 1
+#include <stdio.h>
+
int handle_flush (FILE *fh, char *buffer);
#endif /* UTILS_CMD_FLUSH_H */
#ifndef UTILS_CMD_GETVAL_H
#define UTILS_CMD_GETVAL_H 1
+#include <stdio.h>
+
int handle_getval (FILE *fh, char *buffer);
#endif /* UTILS_CMD_GETVAL_H */
#ifndef UTILS_CMD_LISTVAL_H
#define UTILS_CMD_LISTVAL_H 1
+#include <stdio.h>
+
int handle_listval (FILE *fh, char *buffer);
#endif /* UTILS_CMD_LISTVAL_H */
#ifndef UTILS_CMD_PUTNOTIF_H
#define UTILS_CMD_PUTNOTIF_H 1
+#include <stdio.h>
+
int handle_putnotif (FILE *fh, char *buffer);
/* vim: set shiftwidth=2 softtabstop=2 tabstop=8 : */
#ifndef UTILS_CMD_PUTVAL_H
#define UTILS_CMD_PUTVAL_H 1
+#include <stdio.h>
+
int handle_putval (FILE *fh, char *buffer);
#endif /* UTILS_CMD_PUTVAL_H */
int interval;
} c_complain_t;
-#define C_COMPLAIN_INIT { 0, 0 }
+#define C_COMPLAIN_INIT_STATIC { 0, 0 }
+#define C_COMPLAIN_INIT(c) do { (c)->last = 0; (c)->interval = 0; } while (0)
/*
* NAME
#include "config.h"
#include <arpa/nameser.h>
+#include <stdint.h>
#if HAVE_PCAP_H
# include <pcap.h>
--- /dev/null
+/**
+ * collectd - src/utils_rrdcreate.c
+ * 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
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "utils_rrdcreate.h"
+
+#include <rrd.h>
+
+/*
+ * Private variables
+ */
+static int rra_timespans[] =
+{
+ 3600,
+ 86400,
+ 604800,
+ 2678400,
+ 31622400
+};
+static int rra_timespans_num = STATIC_ARRAY_SIZE (rra_timespans);
+
+static char *rra_types[] =
+{
+ "AVERAGE",
+ "MIN",
+ "MAX"
+};
+static int rra_types_num = STATIC_ARRAY_SIZE (rra_types);
+
+/*
+ * Private functions
+ */
+static void rra_free (int rra_num, char **rra_def) /* {{{ */
+{
+ int i;
+
+ for (i = 0; i < rra_num; i++)
+ {
+ sfree (rra_def[i]);
+ }
+ sfree (rra_def);
+} /* }}} void rra_free */
+
+/* * * * * * * * * *
+ * WARNING: Magic *
+ * * * * * * * * * */
+static int rra_get (char ***ret, const value_list_t *vl, /* {{{ */
+ const rrdcreate_config_t *cfg)
+{
+ char **rra_def;
+ int rra_num;
+
+ int *rts;
+ int rts_num;
+
+ int rra_max;
+
+ int span;
+
+ int cdp_num;
+ int cdp_len;
+ int i, j;
+
+ char buffer[128];
+
+ /* The stepsize we use here: If it is user-set, use it. If not, use the
+ * interval of the value-list. */
+ int ss;
+
+ if (cfg->rrarows <= 0)
+ {
+ *ret = NULL;
+ return (-1);
+ }
+
+ if ((cfg->xff < 0) || (cfg->xff >= 1.0))
+ {
+ *ret = NULL;
+ return (-1);
+ }
+
+ ss = (cfg->stepsize > 0) ? cfg->stepsize : vl->interval;
+ if (ss <= 0)
+ {
+ *ret = NULL;
+ return (-1);
+ }
+
+ /* Use the configured timespans or fall back to the built-in defaults */
+ if (cfg->timespans_num != 0)
+ {
+ rts = cfg->timespans;
+ rts_num = cfg->timespans_num;
+ }
+ else
+ {
+ rts = rra_timespans;
+ rts_num = rra_timespans_num;
+ }
+
+ rra_max = rts_num * rra_types_num;
+
+ if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
+ return (-1);
+ memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
+ rra_num = 0;
+
+ cdp_len = 0;
+ for (i = 0; i < rts_num; i++)
+ {
+ span = rts[i];
+
+ if ((span / ss) < cfg->rrarows)
+ span = ss * cfg->rrarows;
+
+ if (cdp_len == 0)
+ cdp_len = 1;
+ else
+ cdp_len = (int) floor (((double) span)
+ / ((double) (cfg->rrarows * ss)));
+
+ cdp_num = (int) ceil (((double) span)
+ / ((double) (cdp_len * ss)));
+
+ for (j = 0; j < rra_types_num; j++)
+ {
+ if (rra_num >= rra_max)
+ break;
+
+ if (ssnprintf (buffer, sizeof (buffer), "RRA:%s:%3.1f:%u:%u",
+ rra_types[j], cfg->xff,
+ cdp_len, cdp_num) >= sizeof (buffer))
+ {
+ ERROR ("rra_get: Buffer would have been truncated.");
+ continue;
+ }
+
+ rra_def[rra_num++] = sstrdup (buffer);
+ }
+ }
+
+ *ret = rra_def;
+ return (rra_num);
+} /* }}} int rra_get */
+
+static void ds_free (int ds_num, char **ds_def) /* {{{ */
+{
+ int i;
+
+ for (i = 0; i < ds_num; i++)
+ if (ds_def[i] != NULL)
+ free (ds_def[i]);
+ free (ds_def);
+} /* }}} void ds_free */
+
+static int ds_get (char ***ret, /* {{{ */
+ const data_set_t *ds, const value_list_t *vl,
+ const rrdcreate_config_t *cfg)
+{
+ char **ds_def;
+ int ds_num;
+
+ char min[32];
+ char max[32];
+ char buffer[128];
+
+ ds_def = (char **) malloc (ds->ds_num * sizeof (char *));
+ if (ds_def == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("rrdtool plugin: malloc failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+ memset (ds_def, '\0', ds->ds_num * sizeof (char *));
+
+ for (ds_num = 0; ds_num < ds->ds_num; ds_num++)
+ {
+ data_source_t *d = ds->ds + ds_num;
+ char *type;
+ int status;
+
+ ds_def[ds_num] = NULL;
+
+ if (d->type == DS_TYPE_COUNTER)
+ type = "COUNTER";
+ else if (d->type == DS_TYPE_GAUGE)
+ type = "GAUGE";
+ else
+ {
+ ERROR ("rrdtool plugin: Unknown DS type: %i",
+ d->type);
+ break;
+ }
+
+ if (isnan (d->min))
+ {
+ sstrncpy (min, "U", sizeof (min));
+ }
+ else
+ ssnprintf (min, sizeof (min), "%lf", d->min);
+
+ if (isnan (d->max))
+ {
+ sstrncpy (max, "U", sizeof (max));
+ }
+ else
+ ssnprintf (max, sizeof (max), "%lf", d->max);
+
+ status = ssnprintf (buffer, sizeof (buffer),
+ "DS:%s:%s:%i:%s:%s",
+ d->name, type,
+ (cfg->heartbeat > 0) ? cfg->heartbeat : (2 * vl->interval),
+ min, max);
+ if ((status < 1) || (status >= sizeof (buffer)))
+ break;
+
+ ds_def[ds_num] = sstrdup (buffer);
+ } /* for ds_num = 0 .. ds->ds_num */
+
+ if (ds_num != ds->ds_num)
+ {
+ ds_free (ds_num, ds_def);
+ return (-1);
+ }
+
+ *ret = ds_def;
+ return (ds_num);
+} /* }}} int ds_get */
+
+#if HAVE_THREADSAFE_LIBRRD
+static int srrd_create (const char *filename, /* {{{ */
+ unsigned long pdp_step, time_t last_up,
+ int argc, const char **argv)
+{
+ int status;
+ char *filename_copy;
+
+ if ((filename == NULL) || (argv == NULL))
+ return (-EINVAL);
+
+ /* Some versions of librrd don't have the `const' qualifier for the first
+ * argument, so we have to copy the pointer here to avoid warnings. It sucks,
+ * but what else can we do? :( -octo */
+ filename_copy = strdup (filename);
+ if (filename_copy == NULL)
+ {
+ ERROR ("srrd_create: strdup failed.");
+ return (-ENOMEM);
+ }
+
+ optind = 0; /* bug in librrd? */
+ rrd_clear_error ();
+
+ status = rrd_create_r (filename_copy, pdp_step, last_up,
+ argc, (void *) argv);
+
+ if (status != 0)
+ {
+ WARNING ("rrdtool plugin: rrd_create_r (%s) failed: %s",
+ filename, rrd_get_error ());
+ }
+
+ sfree (filename_copy);
+
+ return (status);
+} /* }}} int srrd_create */
+/* #endif HAVE_THREADSAFE_LIBRRD */
+
+#else /* !HAVE_THREADSAFE_LIBRRD */
+static int srrd_create (const char *filename, /* {{{ */
+ unsigned long pdp_step, time_t last_up,
+ int argc, const char **argv)
+{
+ int status;
+
+ int new_argc;
+ char **new_argv;
+
+ char pdp_step_str[16];
+ char last_up_str[16];
+
+ new_argc = 6 + argc;
+ new_argv = (char **) malloc ((new_argc + 1) * sizeof (char *));
+ if (new_argv == NULL)
+ {
+ ERROR ("rrdtool plugin: malloc failed.");
+ return (-1);
+ }
+
+ if (last_up == 0)
+ last_up = time (NULL) - 10;
+
+ 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;
+ new_argv[2] = "-s";
+ new_argv[3] = pdp_step_str;
+ new_argv[4] = "-b";
+ new_argv[5] = last_up_str;
+
+ memcpy (new_argv + 6, argv, argc * sizeof (char *));
+ new_argv[new_argc] = NULL;
+
+ pthread_mutex_lock (&librrd_lock);
+ optind = 0; /* bug in librrd? */
+ rrd_clear_error ();
+
+ status = rrd_create (new_argc, new_argv);
+ pthread_mutex_unlock (&librrd_lock);
+
+ if (status != 0)
+ {
+ WARNING ("rrdtool plugin: rrd_create (%s) failed: %s",
+ filename, rrd_get_error ());
+ }
+
+ sfree (new_argv);
+
+ return (status);
+} /* }}} int srrd_create */
+#endif /* !HAVE_THREADSAFE_LIBRRD */
+
+/*
+ * Public functions
+ */
+int cu_rrd_create_file (const char *filename, /* {{{ */
+ const data_set_t *ds, const value_list_t *vl,
+ const rrdcreate_config_t *cfg)
+{
+ char **argv;
+ int argc;
+ char **rra_def;
+ int rra_num;
+ char **ds_def;
+ int ds_num;
+ int status = 0;
+
+ if (check_create_dir (filename))
+ return (-1);
+
+ if ((rra_num = rra_get (&rra_def, vl, cfg)) < 1)
+ {
+ ERROR ("cu_rrd_create_file failed: Could not calculate RRAs");
+ return (-1);
+ }
+
+ if ((ds_num = ds_get (&ds_def, ds, vl, cfg)) < 1)
+ {
+ ERROR ("cu_rrd_create_file failed: Could not calculate DSes");
+ return (-1);
+ }
+
+ argc = ds_num + rra_num;
+
+ if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("cu_rrd_create_file failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ memcpy (argv, ds_def, ds_num * sizeof (char *));
+ memcpy (argv + ds_num, rra_def, rra_num * sizeof (char *));
+ argv[ds_num + rra_num] = NULL;
+
+ assert (vl->time > 10);
+ status = srrd_create (filename,
+ (cfg->stepsize > 0) ? cfg->stepsize : vl->interval,
+ vl->time - 10,
+ argc, (const char **) argv);
+
+ free (argv);
+ ds_free (ds_num, ds_def);
+ rra_free (rra_num, rra_def);
+
+ if (status != 0)
+ {
+ WARNING ("cu_rrd_create_file: srrd_create (%s) returned status %i.",
+ filename, status);
+ }
+ else
+ {
+ DEBUG ("cu_rrd_create_file: Successfully created RRD file \"%s\".",
+ filename);
+ }
+
+ return (status);
+} /* }}} int cu_rrd_create_file */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
--- /dev/null
+/**
+ * collectd - src/utils_rrdcreate.h
+ * 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 verplant.org>
+ **/
+
+#ifndef UTILS_RRDCREATE_H
+#define UTILS_RRDCREATE_H 1
+
+#include "plugin.h"
+
+#include <stddef.h>
+
+struct rrdcreate_config_s
+{
+ int stepsize;
+ int heartbeat;
+ int rrarows;
+ double xff;
+
+ int *timespans;
+ size_t timespans_num;
+
+ char **consolidation_functions;
+ size_t consolidation_functions_num;
+};
+typedef struct rrdcreate_config_s rrdcreate_config_t;
+
+int cu_rrd_create_file (const char *filename,
+ const data_set_t *ds, const value_list_t *vl,
+ const rrdcreate_config_t *cfg);
+
+#endif /* UTILS_RRDCREATE_H */
+
+/* vim: set sw=2 sts=2 et : */
--- /dev/null
+/**
+ * collectd - src/utils_subst.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
+ *
+ * Authors:
+ * Sebastian "tokkee" Harl <sh at tokkee.org>
+ **/
+
+/*
+ * This module provides functions for string substitution.
+ */
+
+#include "collectd.h"
+#include "common.h"
+
+char *subst (char *buf, size_t buflen, const char *string, int off1, int off2,
+ const char *replacement)
+{
+ char *buf_ptr = buf;
+ size_t len = buflen;
+
+ if ((NULL == buf) || (0 >= buflen) || (NULL == string)
+ || (0 > off1) || (0 > off2) || (off1 > off2)
+ || (NULL == replacement))
+ return NULL;
+
+ sstrncpy (buf_ptr, string, (off1 + 1 > buflen) ? buflen : off1 + 1);
+ buf_ptr += off1;
+ len -= off1;
+
+ if (0 >= len)
+ return buf;
+
+ sstrncpy (buf_ptr, replacement, len);
+ buf_ptr += strlen (replacement);
+ len -= strlen (replacement);
+
+ if (0 >= len)
+ return buf;
+
+ sstrncpy (buf_ptr, string + off2, len);
+ return buf;
+} /* subst */
+
+char *asubst (const char *string, int off1, int off2, const char *replacement)
+{
+ char *buf;
+ int len;
+
+ char *ret;
+
+ if ((NULL == string) || (0 > off1) || (0 > off2) || (off1 > off2)
+ || (NULL ==replacement))
+ return NULL;
+
+ len = off1 + strlen (replacement) + strlen (string) - off2 + 1;
+
+ buf = (char *)malloc (len);
+ if (NULL == buf)
+ return NULL;
+
+ ret = subst (buf, len, string, off1, off2, replacement);
+ if (NULL == ret)
+ free (buf);
+ return ret;
+} /* asubst */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
+
--- /dev/null
+/**
+ * collectd - src/utils_subst.h
+ * 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
+ *
+ * Authors:
+ * Sebastian "tokkee" Harl <sh at tokkee.org>
+ **/
+
+/*
+ * This module provides functions for string substitution.
+ */
+
+#ifndef UTILS_SUBST_H
+#define UTILS_SUBST_H 1
+
+#include <stddef.h>
+
+/*
+ * subst:
+ *
+ * Replace a substring of a string with the specified replacement text. The
+ * resulting string is stored in the buffer pointed to by 'buf' of length
+ * 'buflen'. Upon success, the buffer will always be null-terminated. The
+ * result may be truncated if the buffer is too small.
+ *
+ * The substring to be replaces is identified by the two offsets 'off1' and
+ * 'off2' where 'off1' specifies the offset to the beginning of the substring
+ * and 'off2' specifies the offset to the first byte after the substring.
+ *
+ * The minimum buffer size to store the complete return value (including the
+ * terminating '\0' character) thus has to be:
+ * off1 + strlen(replacement) + strlen(string) - off2 + 1
+ *
+ * Example:
+ *
+ * 01234567890
+ * string = "foo_____bar"
+ * ^ ^
+ * | |
+ * off1 off2
+ *
+ * off1 = 3
+ * off2 = 8
+ *
+ * replacement = " - "
+ *
+ * -> "foo - bar"
+ *
+ * The function returns 'buf' on success, NULL else.
+ */
+char *subst (char *buf, size_t buflen, const char *string, int off1, int off2,
+ const char *replacement);
+
+/*
+ * asubst:
+ *
+ * This function is very similar to subst(). It differs in that it
+ * automatically allocates the memory required for the return value which the
+ * user then has to free himself.
+ *
+ * Returns the newly allocated result string on success, NULL else.
+ */
+char *asubst (const char *string, int off1, int off2, const char *replacement);
+
+#endif /* UTILS_SUBST_H */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
+