From: Florian Forster Date: Fri, 10 Oct 2008 07:02:33 +0000 (+0200) Subject: Merge branch 'collectd-4.5' X-Git-Tag: collectd-4.6.0~178 X-Git-Url: https://git.octo.it/?p=collectd.git;a=commitdiff_plain;h=332cf199806de625661fa3a9bf9555f7a47ba9f9;hp=2c2e9a297f59c110ddd4adef6293fe80f39f15b7 Merge branch 'collectd-4.5' Conflicts: configure.in --- diff --git a/.mailmap b/.mailmap new file mode 100644 index 00000000..9bb4399e --- /dev/null +++ b/.mailmap @@ -0,0 +1,8 @@ +Anthony +Florian Forster +Florian Forster +Luboš Staněk +Luboš Staněk +Niki W. Waibel +Sebastian Harl + diff --git a/README b/README index e698786a..b6bdb413 100644 --- a/README +++ b/README @@ -40,6 +40,10 @@ Features - 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) @@ -76,6 +80,9 @@ Features 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). @@ -152,9 +159,15 @@ Features 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. @@ -180,6 +193,12 @@ Features - 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. @@ -214,6 +233,11 @@ Features 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 @@ -279,7 +303,7 @@ Features 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. @@ -339,76 +363,101 @@ Prerequisites * CoreFoundation.framework and IOKit.framework (optional) For compiling on Darwin in general and the `apple_sensors' plugin in particular. + * libcurl (optional) If you want to use the `apache', `ascent', or `nginx' plugin. + + + * libdbi (optional) + Used by the `dbi' plugin to connect to various databases. + * libesmtp (optional) For the `notify_email' plugin. + * libhal (optional) If present, the uuid plugin will check for UUID from HAL. + - * 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. + * libmysqlclient (optional) Unsurprisingly used by the `mysql' plugin. + * libnetlink (optional) Used, obviously, for the `netlink' plugin. + * libnetsnmp (optional) For the `snmp' plugin. + * libnotify (optional) For the `notify_desktop' plugin. + * liboping (optional, if not found a version shipped with this distribution can be used) Used by the `ping' plugin to send and receive ICMP packets. + * libowcapi (optional) Used by the `onewire' plugin to read values from onewire sensors (or the owserver(1) daemon). + * libpcap (optional) Used to capture packets by the `dns' plugin. + * libperl (optional) Obviously used by the `perl' plugin. The library has to be compiled with ithread support (introduced in Perl 5.6.0). + * libpq (optional) The PostgreSQL C client library used by the `postgresql' plugin. + - * librrd (optional; headers and library; rrdtool 1.0 and 1.2 both work fine) - If built without `librrd' the resulting binary will be `client only', i.e. - will send its values via multicast and not create any RRD files itself. - Alternatively you can chose to write CSV-files (Comma Separated Values) - instead. + * 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. + * librt, libsocket, libkstat, libdevinfo (optional) Various standard Solaris libraries which provide system functions. + * libsensors (optional) To read from `lm_sensors', see the `sensors' plugin. + - * libstatgrab (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.. - + * libstatgrab (optional) + Used by various plugins to collect statistics on systems other than Linux + and/or Solaris. + * libupsclient/nut (optional) For the `nut' plugin which queries nut's `upsd'. + * libvirt (optional) Collect statistics from virtual machines. + * libxml2 (optional) Parse XML data. This is needed for the `ascent' and `libvirt' plugins. + * libxmms (optional) + Configuring / Compiling / Installing @@ -418,7 +467,7 @@ 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 diff --git a/configure.in b/configure.in index c71cfa4e..d416e696 100644 --- a/configure.in +++ b/configure.in @@ -922,102 +922,6 @@ fi 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" @@ -1044,7 +948,45 @@ fi 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") + +# --with-libcurl {{{ with_curl_config="curl-config" with_curl_cflags="" with_curl_libs="" @@ -1112,221 +1054,166 @@ then 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" +if test "x$with_libdbi" = "xyes" 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 + SAVE_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $with_libdbi_cppflags" -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 + AC_CHECK_HEADERS(dbi/dbi.h, [with_libdbi="yes"], [with_libdbi="no (dbi/dbi.h not found)"]) -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]) + CPPFLAGS="$SAVE_CPPFLAGS" 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" + SAVE_LDFLAGS="$LDFLAGS" + CPPFLAGS="$CPPFLAGS $with_libdbi_cppflags" + LDFLAGS="$LDFLAGS $with_libdbi_ldflags" - AC_CHECK_HEADERS(statgrab.h, - [with_libstatgrab="yes"], - [with_libstatgrab="no (statgrab.h not found)"]) + AC_CHECK_LIB(dbi, dbi_initialize, [with_libdbi="yes"], [with_libdbi="no (Symbol 'dbi_initialize' not found)"]) - CPPFLAGS="$SAVE_CPPFLAGS" + CPPFLAGS="$SAVE_CPPFLAGS" + LDFLAGS="$SAVE_LDFLAGS" 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" - - AC_CHECK_LIB(statgrab, sg_init, - [with_libstatgrab="yes"], - [with_libstatgrab="no (symbol sg_init not found)"]) - - CFLAGS="$SAVE_CFLAGS" - LDFLAGS="$SAVE_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") +# }}} -AM_CONDITIONAL(BUILD_WITH_LIBSTATGRAB, test "x$with_libstatgrab" = "xyes") -if test "x$with_libstatgrab" = "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_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) + 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 - -with_libkvm="no" -AC_CHECK_LIB(kvm, kvm_getprocs, [with_kvm_getprocs="yes"], [with_kvm_getprocs="no"]) -if test "x$with_kvm_getprocs" = "xyes" +if test "x$with_libesmtp" = "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" + AC_CHECK_HEADERS(libesmtp.h, + [ + AC_DEFINE(HAVE_LIBESMTP_H, 1, [Define to 1 if you have the header file.]) + ], [with_libesmtp="no (libesmtp.h 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" + collect_libesmtp=1 +else + collect_libesmtp=0 fi -AM_CONDITIONAL(BUILD_WITH_LIBKVM_NLIST, test "x$with_kvm_nlist" = "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 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 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="" @@ -1392,75 +1279,250 @@ then 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.])], +# --with-libnetlink {{{ +with_libnetlink_cflags="" +with_libnetlink_libs="-lnetlink" +AC_ARG_WITH(libnetlink, [AS_HELP_STRING([--with-libnetlink@<:@=PREFIX@:>@], [Path to libnetlink.])], [ - 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 + 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" + if test "x$ac_system" = "xLinux" + then + with_libnetlink="yes" + else + with_libnetlink="no (Linux only library)" + fi ]) +if test "x$with_libnetlink" = "xyes" +then + SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $with_libnetlink_cflags" -save_LDFLAGS="$LDFLAGS" -save_CPPFLAGS="$CPPFLAGS" -LDFLAGS="$liboconfig_LDFLAGS" -CPPFLAGS="$liboconfig_CPPFLAGS" -AC_CHECK_LIB(oconfig, oconfig_parse_fh, -[ - with_liboconfig="yes" - with_own_liboconfig="no" -], -[ - with_liboconfig="yes" - with_own_liboconfig="yes" - LDFLAGS="$save_LDFLAGS" - CPPFLAGS="$save_CPPFLAGS" -]) + with_libnetlink="no (libnetlink.h not found)" -AM_CONDITIONAL(BUILD_WITH_OWN_LIBOCONFIG, test "x$with_own_liboconfig" = "xyes") -if test "x$with_own_liboconfig" = "xyes" + AC_CHECK_HEADERS(libnetlink.h iproute/libnetlink.h linux/libnetlink.h, + [ + with_libnetlink="yes" + break + ], [], +[#include +#include +#include +#include +#include +#include ]) + AC_CHECK_HEADERS(linux/gen_stats.h linux/pkt_sched.h, [], [], +[#include +#include +#include +#include ]) + + AC_COMPILE_IFELSE( +[#include +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include + +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 - with_liboconfig="yes (shipped version)" + 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_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.])], +# --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" - 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" + with_libnetsnmp="no" + else if test "x$withval" = "xyes" + then + with_libnetsnmp="yes" + else + if test -x "$withval" + then + with_snmp_config="$withval" + with_libnetsnmp="yes" + else + with_snmp_config="$withval/bin/net-snmp-config" + with_libnetsnmp="yes" + fi + fi; fi +], +[with_libnetsnmp="yes"]) +if test "x$with_libnetsnmp" = "xyes" +then + with_snmp_cflags=`$with_snmp_config --cflags 2>/dev/null` + snmp_config_status=$? + + if test $snmp_config_status -ne 0 + then + with_libnetsnmp="no ($with_snmp_config failed)" + else + SAVE_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_libnetsnmp" = "xyes" +then + with_snmp_libs=`$with_snmp_config --libs 2>/dev/null` + snmp_config_status=$? + + if test $snmp_config_status -ne 0 + then + with_libnetsnmp="no ($with_snmp_config failed)" + else + AC_CHECK_LIB(netsnmp, init_snmp, + [with_libnetsnmp="yes"], + [with_libnetsnmp="no (libnetsnmp not found)"], + [$with_snmp_libs]) + fi +fi +if test "x$with_libnetsnmp" = "xyes" +then + BUILD_WITH_LIBSNMP_CFLAGS="$with_snmp_cflags" + BUILD_WITH_LIBSNMP_LIBS="$with_snmp_libs" + AC_SUBST(BUILD_WITH_LIBSNMP_CFLAGS) + AC_SUBST(BUILD_WITH_LIBSNMP_LIBS) +fi +AM_CONDITIONAL(BUILD_WITH_LIBNETSNMP, test "x$with_libnetsnmp" = "xyes") +# }}} + +# --with-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 + 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_liboconfig="yes" + with_own_liboconfig="no" +], +[ + with_liboconfig="yes" + with_own_liboconfig="yes" + LDFLAGS="$save_LDFLAGS" + CPPFLAGS="$save_CPPFLAGS" +]) + +AM_CONDITIONAL(BUILD_WITH_OWN_LIBOCONFIG, test "x$with_own_liboconfig" = "xyes") +if test "x$with_own_liboconfig" = "xyes" +then + with_liboconfig="yes (shipped version)" +fi +# }}} + +# --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" @@ -1490,7 +1552,9 @@ then 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 {{{ with_libowcapi_cppflags="" with_libowcapi_libs="-lowcapi" AC_ARG_WITH(libowcapi, [AS_HELP_STRING([--with-libowcapi@<:@=PREFIX@:>@], [Path to libowcapi.])], @@ -1535,8 +1599,9 @@ then 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" @@ -1574,45 +1639,9 @@ 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") +# }}} -AC_ARG_WITH(libesmtp, [AS_HELP_STRING([--with-libesmtp@<:@=PREFIX@:>@], [Path to libesmtp.])], -[ - if test "x$withval" != "xno" && test "x$withval" != "xyes" - then - LDFLAGS="$LDFLAGS -L$withval/lib" - CPPFLAGS="$CPPFLAGS -I$withval/include -D_THREAD_SAFE" - with_libesmtp="yes" - else - with_libesmtp="$withval" - fi -], -[ - with_libesmtp="yes" -]) -if test "x$with_libesmtp" = "xyes" -then - AC_CHECK_LIB(esmtp, smtp_create_session, - [ - AC_DEFINE(HAVE_LIBESMTP, 1, [Define to 1 if you have the esmtp library (-lesmtp).]) - ], [with_libesmtp="no (libesmtp not found)"]) -fi -if test "x$with_libesmtp" = "xyes" -then - AC_CHECK_HEADERS(libesmtp.h, - [ - AC_DEFINE(HAVE_LIBESMTP_H, 1, [Define to 1 if you have the 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") - +# --with-libperl {{{ perl_interpreter="perl" AC_ARG_WITH(libperl, [AS_HELP_STRING([--with-libperl@<:@=PREFIX@:>@], [Path to libperl.])], [ @@ -1728,551 +1757,526 @@ then 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" + with_libpq="no" + else if test "x$withval" = "xyes" + then + with_libpq="yes" else - with_libiptc="$withval" - fi + if test -f "$withval" && test -x "$withval"; + then + with_pg_config="$withval" + else if test -x "$withval/bin/pg_config" + then + with_pg_config="$withval/bin/pg_config" + fi; fi + with_libpq="yes" + fi; fi ], [ - if test "x$ac_system" = "xLinux" + with_libpq="yes" +]) +if test "x$with_libpq" = "xyes" +then + with_libpq_includedir=`$with_pg_config --includedir 2> /dev/null` + pg_config_status=$? + + if test $pg_config_status -eq 0 then - with_libiptc="yes" + 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 - with_libiptc="no (Linux only)" + AC_MSG_WARN([$with_pg_config returned with status $pg_config_status]) 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 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" - ]) + SAVE_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $with_libpq_cppflags" - CFLAGS=$SAVE_CFLAGS + AC_CHECK_HEADERS(libpq-fe.h, [], + [with_libpq="no (libpq-fe.h not found)"], []) + + CPPFLAGS="$SAVE_CPPFLAGS" 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" +if test "x$with_libpq" = "xyes" then - AC_DEFINE(OWN_LIBIPTC, 1, [Define to 1 if we use the shipped iptc library.]) -fi + with_libpq_libdir=`$with_pg_config --libdir 2> /dev/null` + pg_config_status=$? -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" + if test $pg_config_status -eq 0 then - with_libnetsnmp="yes" - else - if test -x "$withval" - then - with_snmp_config="$withval" - with_libnetsnmp="yes" - else - with_snmp_config="$withval/bin/net-snmp-config" - with_libnetsnmp="yes" + if test -n "$with_libpq_libdir"; then + for dir in $with_libpq_libdir; do + with_libpq_ldflags="$with_libpq_ldflags -L$dir" + done fi - fi; fi -], -[with_libnetsnmp="yes"]) -if test "x$with_libnetsnmp" = "xyes" -then - with_snmp_cflags=`$with_snmp_config --cflags 2>/dev/null` - snmp_config_status=$? - - if test $snmp_config_status -ne 0 - then - with_libnetsnmp="no ($with_snmp_config failed)" else - SAVE_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_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 - with_snmp_libs=`$with_snmp_config --libs 2>/dev/null` - snmp_config_status=$? + BUILD_WITH_LIBPQ_CPPFLAGS="$with_libpq_cppflags" + BUILD_WITH_LIBPQ_LDFLAGS="$with_libpq_ldflags" + AC_SUBST(BUILD_WITH_LIBPQ_CPPFLAGS) + AC_SUBST(BUILD_WITH_LIBPQ_LDFLAGS) +fi +AM_CONDITIONAL(BUILD_WITH_LIBPQ, test "x$with_libpq" = "xyes") +# }}} - if test $snmp_config_status -ne 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_libnetsnmp="no ($with_snmp_config failed)" + LDFLAGS="$LDFLAGS -L$withval/lib" + CPPFLAGS="$CPPFLAGS -I$withval/include" + with_libpthread="yes" else - AC_CHECK_LIB(netsnmp, init_snmp, - [with_libnetsnmp="yes"], - [with_libnetsnmp="no (libnetsnmp not found)"], - [$with_snmp_libs]) + if test "x$withval" = "xno" + then + with_libpthread="no (disabled)" + fi fi -fi -if test "x$with_libnetsnmp" = "xyes" +], [with_libpthread="yes"]) +if test "x$with_libpthread" = "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) + AC_CHECK_LIB(pthread, pthread_create, [with_libpthread="yes"], [with_libpthread="no (libpthread not found)"], []) fi -AM_CONDITIONAL(BUILD_WITH_LIBNETSNMP, test "x$with_libnetsnmp" = "xyes") - -PKG_CHECK_MODULES([LIBNOTIFY], [libnotify], - [with_libnotify="yes"], - [with_libnotify="no ($LIBNOTIFY_PKG_ERRORS)"]) - -with_libupsclient="no (pkg-config isn't available)" -with_libupsclient_cflags="" -with_libupsclient_libs="" -if test "x$PKG_CONFIG" != "x" +if test "x$with_libpthread" = "xyes" then - pkg-config --exists 'libupsclient' 2>/dev/null - if test "$?" = "0" - then - with_libupsclient="yes" - else - with_libupsclient="no (pkg-config doesn't know library)" - 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 - 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 + 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") +# }}} + +# --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 - with_libupsclient="no" + librrd_cflags="-I$withval/include" + librrd_ldflags="-L$withval/lib" + with_librrd="yes" + else + with_librrd="$withval" fi -fi -if test "x$with_libupsclient" = "xyes" +], [with_librrd="yes"]) +if test "x$with_librrd" = "xyes" then SAVE_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $with_libupsclient_cflags" + SAVE_LDFLAGS="$LDFLAGS" - AC_CHECK_HEADERS(upsclient.h, [], [with_libupsclient="no (upsclient.h not found)"]) + CPPFLAGS="$CPPFLAGS $librrd_cflags" + LDFLAGS="$LDFLAGS $librrd_ldflags" + + 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" 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_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 - SAVE_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $with_libupsclient_cflags" - - AC_CHECK_TYPES([UPSCONN_t, UPSCONN], [], [], -[#include -#include -#include ]) - - CPPFLAGS="$SAVE_CPPFLAGS" + 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$with_libupsclient" = "xyes" +if test "x$librrd_threadsafe" = "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) + AC_DEFINE(HAVE_THREADSAFE_LIBRRD, 1, [Define to 1 if you have the threadsafe rrd library (-lrrd_th).]) 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.])], +# --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 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 -#include -#include -#include -#include -#include ]) - AC_CHECK_HEADERS(linux/gen_stats.h linux/pkt_sched.h, [], [], -[#include -#include -#include -#include ]) - - AC_COMPILE_IFELSE( -[#include -#include -#include -#include -#include -#include - -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 -#include -#include -#include -#include -#include - -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 -#include -#include -#include -]) + 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 +#include +#include ]) + + 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="" @@ -2387,8 +2391,92 @@ if test "x$with_libvirt" = "xyes"; then 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 +#include +#include +#include +]) + + 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 # @@ -2695,6 +2783,7 @@ AC_PLUGIN([cpu], [$plugin_cpu], [CPU usage statistics]) AC_PLUGIN([cpufreq], [$plugin_cpufreq], [CPU frequency statistics]) AC_PLUGIN([csv], [yes], [CSV output plugin]) AC_PLUGIN([notify_desktop], [$with_libnotify], [Desktop notifications]) +AC_PLUGIN([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]) @@ -2729,8 +2818,9 @@ 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]) @@ -2787,10 +2877,10 @@ AC_SUBST(PERL_BINDINGS_OPTIONS) AC_OUTPUT(Makefile src/Makefile src/collectd.conf src/libiptc/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" \ @@ -2822,6 +2912,7 @@ cat < +# +# +# Statement "SELECT 'customers' AS c_key, COUNT(*) AS c_value FROM customers_tbl" +# Type "gauge" +# InstancesFrom "c_key" +# ValuesFrom "c_value" +# +# +# Driver "mysql" +# DriverOption "host" "localhost" +# DriverOption "username" "collectd" +# DriverOption "password" "AeXohy0O" +# DriverOption "dbname" "custdb0" +# #SelectDB "custdb0" +# Query "num_of_customers" +# #Query "..." +# +# + # # Device "/dev/hda1" # Device "192.168.0.2:/mnt/nfs" @@ -313,6 +334,13 @@ FQDNLookup true # Process "name" # +# +# DaemonAddress "unix:/tmp/rrdcached.sock" +# DataDir "@prefix@/var/lib/@PACKAGE_NAME@/rrd" +# CreateFiles true +# CollectStatistics true +# + # # DataDir "@prefix@/var/lib/@PACKAGE_NAME@/rrd" # CacheTimeout 120 diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index 0df5c3b7..5d07ee52 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -282,6 +282,161 @@ number. =back +=head2 Plugin C + +This plugin uses the "B" library (L) 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: + + + + Statement "SELECT category, COUNT(*) AS value FROM products WHERE in_stock = 0 GROUP BY category" + Type "gauge" + InstancesFrom "category" + ValuesFrom "value" + + + Driver "mysql" + DriverOption "host" "localhost" + DriverOption "username" "collectd" + DriverOption "password" "aZo6daiw" + DriverOption "dbname" "prod_info" + SelectDB "prod_info" + Query "out_of_stock" + + + +The configuration above defines one query and one database. The query is then +linked to the database with the B option I the +BDatabaseE> block. You can have any number of queries and databases +and you can also use the B statement to split up the configuration +file in multiple, smaller files. However, the BQueryE> block I +precede the BDatabaseE> blocks, because the file is interpreted from +top to bottom! + +The following is a complete list of options: + +=head3 B 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 I + +Sets the statement that should be executed on the server. This is B +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 I + +The B that's used for each line returned. See L 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 +setting below. + +=item B I [I ...] + +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 I [I ...] + +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 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 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- 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 I + +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", +BataBase Briver, and some distributions ship them in separate +packages. Drivers for the "dbi" library are developed by the B +project at L. + +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 I I + +Sets driver-specific options. What option a driver supports can be found in the +documentation for each driver, somewhere at +L. However, the options "host", +"username", "password", and "dbname" seem to be deEfacto 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/ +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 I + +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 I + +Associates the query named I with this database connection. The +query needs to be defined I this statement, i.Ee. 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 =over 4 @@ -1500,6 +1655,56 @@ and minor and major pagefaults. =back +=head2 Plugin C + +The C plugin uses the RRDTool accelerator daemon, L, +to store values to RRD files in an efficient manner. The combination of the +C B and the C B is very similar to the +way the C plugin works (see below). The added abstraction layer +provides a number of benefits, though: Because the cache is not within +C anymore, it does not need to be flushed when C is to be +restarted. This results in much shorter (if any) gaps in graphs, especially +under heavy load. Also, the C 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 to create the appropriate RRD files +anymore. And even if C 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 is to let C and C run +on the same host, communicating via a UNIX domain socket. The B +setting should be set to an absolute path, so that a changed base directory +does not result in RRD files being createdE/ expected in the wrong place. + +=over 4 + +=item B I
+ +Address of the daemon as understood by the C function of the RRD +library. See L for details. Example: + + + DaemonAddress "unix:/var/run/rrdcached.sock" + + +=item B I + +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 daemon! +Use of an absolute path is recommended. + +=item B B|B + +Enables or disables the creation of RRD files. If the daemon is not running +locally, or B is set to a relative path, this will not work as +expected. Default is B. + +=back + =head2 Plugin C You can use the settings B, B, B, and B to diff --git a/src/dbi.c b/src/dbi.c new file mode 100644 index 00000000..484c604c --- /dev/null +++ b/src/dbi.c @@ -0,0 +1,1059 @@ +/** + * 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 + **/ + +#include "collectd.h" +#include "common.h" +#include "plugin.h" +#include "configfile.h" + +#include + +/* + * 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_flag (connection) != 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 {{{ + * + * + * + * Statement "SELECT name, value FROM table" + * Type "gauge" + * InstancesFrom "name" + * ValuesFrom "value" + * + * + * + * Driver "mysql" + * DriverOption "hostname" "localhost" + * ... + * Query "plugin_instance0" + * + * + */ + +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 block comes before " + "the 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 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 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_flag (db->connection) != 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_flag (db->connection) != 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 + */ diff --git a/src/interface.c b/src/interface.c index 806a336d..7512c4ee 100644 --- a/src/interface.c +++ b/src/interface.c @@ -24,6 +24,7 @@ #include "common.h" #include "plugin.h" #include "configfile.h" +#include "utils_ignorelist.h" #if HAVE_SYS_TYPES_H # include @@ -77,14 +78,7 @@ static const char *config_keys[] = }; 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 @@ -95,33 +89,21 @@ static int numif = 0; 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 { @@ -161,26 +143,6 @@ static int interface_init (void) } /* 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) @@ -188,7 +150,7 @@ static void if_submit (const char *dev, const char *type, 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; diff --git a/src/libiptc/Makefile.am b/src/libiptc/Makefile.am index 338aecb9..3a6ef675 100644 --- a/src/libiptc/Makefile.am +++ b/src/libiptc/Makefile.am @@ -1,6 +1,6 @@ AUTOMAKE_OPTIONS = foreign no-dependencies -EXTRA_DIST = libiptc.c +EXTRA_DIST = libiptc.c README.collectd if COMPILER_IS_GCC AM_CFLAGS = -Wall -Werror @@ -8,7 +8,7 @@ endif 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 diff --git a/src/libiptc/README.collectd b/src/libiptc/README.collectd new file mode 100644 index 00000000..adb53b0b --- /dev/null +++ b/src/libiptc/README.collectd @@ -0,0 +1,25 @@ + 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. + diff --git a/src/libiptc/libip6tc.c b/src/libiptc/libip6tc.c index b30bb28b..276b7af8 100644 --- a/src/libiptc/libip6tc.c +++ b/src/libiptc/libip6tc.c @@ -131,7 +131,7 @@ typedef unsigned int socklen_t; #include "libiptc.c" #define BIT6(a, l) \ - ((ntohl(a->in6_u.u6_addr32[(l) / 32]) >> (31 - ((l) & 31))) & 1) + ((ntohl(a->s6_addr32[(l) / 32]) >> (31 - ((l) & 31))) & 1) int ipv6_prefix_length(const struct in6_addr *a) diff --git a/src/libiptc/libip6tc.h b/src/libiptc/libip6tc.h index 103267b7..9253e11f 100644 --- a/src/libiptc/libip6tc.h +++ b/src/libiptc/libip6tc.h @@ -162,7 +162,7 @@ int ip6tc_set_counter(const ip6t_chainlabel chain, 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); @@ -170,4 +170,6 @@ 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 */ diff --git a/src/libiptc/libiptc.c b/src/libiptc/libiptc.c index f8e88b28..f7a6640f 100644 --- a/src/libiptc/libiptc.c +++ b/src/libiptc/libiptc.c @@ -44,6 +44,7 @@ */ #include #include +#include "xtables.h" #include "linux_list.h" @@ -58,8 +59,10 @@ #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; @@ -150,6 +153,11 @@ STRUCT_TC_HANDLE 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; }; @@ -184,7 +192,7 @@ static struct rule_head *iptcc_alloc_rule(struct chain_head *c, unsigned int siz } /* 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; @@ -282,11 +290,307 @@ iptcb_ent_is_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h) /********************************************************************** + * 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); } @@ -338,21 +642,81 @@ iptcc_find_chain_by_offset(TC_HANDLE_T handle, unsigned int offset) 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; } @@ -413,14 +777,37 @@ static int __iptcc_p_del_policy(TC_HANDLE_T h, unsigned int num) 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; + } } } @@ -493,6 +880,7 @@ static int cache_add_entry(STRUCT_ENTRY *e, errno = -ENOMEM; return -1; } + h->num_chains++; /* New user defined chain */ __iptcc_p_add_chain(h, c, offset, num); @@ -580,22 +968,27 @@ static int parse_table(TC_HANDLE_T h) 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++; } } @@ -848,7 +1241,7 @@ TC_INIT(const char *tablename) return NULL; } sockfd_use++; - +retry: s = sizeof(info); strcpy(info.name, tablename); @@ -901,6 +1294,9 @@ TC_INIT(const char *tablename) return h; error: TC_FREE(&h); + /* A different process changed the ruleset size, retry */ + if (errno == EAGAIN) + goto retry; return NULL; } @@ -925,6 +1321,8 @@ TC_FREE(TC_HANDLE_T *h) free(c); } + iptcc_chain_index_free(*h); + free((*h)->entries); free(*h); @@ -947,7 +1345,7 @@ TC_DUMP_ENTRIES(const TC_HANDLE_T handle) 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], @@ -1091,7 +1489,7 @@ TC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle) } /* 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; @@ -1107,9 +1505,8 @@ TC_NUM_RULES(const char *chain, TC_HANDLE_T *handle) 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; @@ -1791,6 +2188,8 @@ int 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; @@ -1819,10 +2218,25 @@ TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) 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; @@ -1885,11 +2299,14 @@ TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle) } /* 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); @@ -1997,16 +2414,14 @@ subtract_counters(STRUCT_COUNTERS *answer, } -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. @@ -2016,15 +2431,13 @@ static void counters_normal_map(STRUCT_COUNTERS_INFO *newcounters, * => 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. @@ -2033,19 +2446,18 @@ static void counters_map_zeroed(STRUCT_COUNTERS_INFO *newcounters, * => 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"); diff --git a/src/libiptc/libiptc.h b/src/libiptc/libiptc.h index d9f7423c..3fc25b6f 100644 --- a/src/libiptc/libiptc.h +++ b/src/libiptc/libiptc.h @@ -172,11 +172,13 @@ int iptc_set_counter(const ipt_chainlabel chain, 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 diff --git a/src/libiptc/libxtc.h b/src/libiptc/libxtc.h new file mode 100644 index 00000000..2ed03f4c --- /dev/null +++ b/src/libiptc/libxtc.h @@ -0,0 +1,53 @@ +/** + * 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 + +#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 */ diff --git a/src/libiptc/xtables.h b/src/libiptc/xtables.h new file mode 100644 index 00000000..47e47dc7 --- /dev/null +++ b/src/libiptc/xtables.h @@ -0,0 +1,239 @@ +/** + * 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 +#include +#include +#include "libxtc.h" +#include + +#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 +#endif + +#endif /* _XTABLES_H */ diff --git a/src/perl.c b/src/perl.c index bb62267e..d3e8c29e 100644 --- a/src/perl.c +++ b/src/perl.c @@ -1806,7 +1806,10 @@ static int perl_config (oconfig_item_t *ci) 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) { diff --git a/src/plugin.c b/src/plugin.c index 1ec25441..0ae6e44a 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -718,7 +718,7 @@ void plugin_shutdown_all (void) 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; diff --git a/src/postgresql.c b/src/postgresql.c index 9438c576..43f5af56 100644 --- a/src/postgresql.c +++ b/src/postgresql.c @@ -217,8 +217,7 @@ static c_psql_database_t *c_psql_database_new (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; diff --git a/src/rrdcached.c b/src/rrdcached.c new file mode 100644 index 00000000..f9d65ca5 --- /dev/null +++ b/src/rrdcached.c @@ -0,0 +1,415 @@ +/** + * 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 + **/ + +#include "collectd.h" +#include "plugin.h" +#include "common.h" +#include "utils_rrdcreate.h" + +#include + +/* + * 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 : + */ diff --git a/src/rrdtool.c b/src/rrdtool.c index 2e1727a8..9b236cb8 100644 --- a/src/rrdtool.c +++ b/src/rrdtool.c @@ -23,6 +23,7 @@ #include "plugin.h" #include "common.h" #include "utils_avltree.h" +#include "utils_rrdcreate.h" #include @@ -65,27 +66,6 @@ typedef struct rrd_queue_s rrd_queue_t; /* * 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", @@ -103,12 +83,21 @@ static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); /* If datadir is zero, the daemon's basedir is used. If stepsize or heartbeat * is zero a default, depending on the `interval' member of the value list is * being used. */ -static char *datadir = NULL; -static int stepsize = 0; -static int heartbeat = 0; -static int rrarows = 1200; -static double xff = 0.1; -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! */ @@ -132,233 +121,7 @@ static pthread_mutex_t librrd_lock = PTHREAD_MUTEX_INITIALIZER; 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) { @@ -380,59 +143,6 @@ static int srrd_update (char *filename, char *template, /* #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) { @@ -476,58 +186,6 @@ static int srrd_update (char *filename, char *template, } /* 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) { @@ -1111,7 +769,9 @@ static int rrd_write (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 @@ -1196,15 +856,15 @@ static int rrd_config (const char *key, const char *value) } 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) { @@ -1215,7 +875,7 @@ static int rrd_config (const char *key, const char *value) "be greater than 0.\n"); return (1); } - rrarows = tmp; + rrdcreate_config.rrarows = tmp; } else if (strcasecmp ("RRATimespan", key) == 0) { @@ -1234,23 +894,23 @@ static int rrd_config (const char *key, const char *value) { 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); @@ -1264,7 +924,7 @@ static int rrd_config (const char *key, const char *value) "be in the range 0 to 1 (exclusive)."); return (1); } - xff = tmp; + rrdcreate_config.xff = tmp; } else if (strcasecmp ("WritesPerSecond", key) == 0) { @@ -1318,16 +978,18 @@ static int rrd_init (void) { 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."); @@ -1363,7 +1025,10 @@ static int rrd_init (void) 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 */ diff --git a/src/snmp.c b/src/snmp.c index 4d6e7694..3ba93fe8 100644 --- a/src/snmp.c +++ b/src/snmp.c @@ -22,6 +22,7 @@ #include "collectd.h" #include "common.h" #include "plugin.h" +#include "utils_complain.h" #include @@ -67,6 +68,7 @@ struct host_definition_s char *community; int version; void *sess_handle; + c_complain_t complaint; uint32_t interval; time_t next_update; data_definition_t **data_list; @@ -116,6 +118,7 @@ static pthread_cond_t host_cond = PTHREAD_COND_INITIALIZER; /* * 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. */ @@ -551,6 +554,7 @@ static int csnmp_config_add_host (oconfig_item_t *ci) 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) @@ -653,7 +657,7 @@ static int csnmp_config (oconfig_item_t *ci) 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) { @@ -1146,7 +1150,9 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) 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) @@ -1161,6 +1167,9 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) } 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) @@ -1626,5 +1635,5 @@ void module_register (void) } /* void module_register */ /* - * vim: shiftwidth=2 softtabstop=2 tabstop=8 + * vim: shiftwidth=2 softtabstop=2 tabstop=8 fdm=marker */ diff --git a/src/types.db b/src/types.db index c8d2f8a1..21d15d64 100644 --- a/src/types.db +++ b/src/types.db @@ -64,6 +64,7 @@ mysql_threads running:GAUGE:0:U, connected:GAUGE:0:U, cached:GAUGE:0:U, created 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 @@ -80,6 +81,7 @@ ps_cputime user:COUNTER:0:16000000, syst:COUNTER:0:16000000 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 diff --git a/src/utils_complain.h b/src/utils_complain.h index e93d823e..b51a81c6 100644 --- a/src/utils_complain.h +++ b/src/utils_complain.h @@ -39,7 +39,8 @@ typedef struct 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 diff --git a/src/utils_rrdcreate.c b/src/utils_rrdcreate.c new file mode 100644 index 00000000..99feda25 --- /dev/null +++ b/src/utils_rrdcreate.c @@ -0,0 +1,396 @@ +/** + * 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 + **/ + +#include "collectd.h" +#include "common.h" +#include "utils_rrdcreate.h" + +#include + +/* + * 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; + + 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 */ +/* #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 : */ diff --git a/src/utils_rrdcreate.h b/src/utils_rrdcreate.h new file mode 100644 index 00000000..6208a6fc --- /dev/null +++ b/src/utils_rrdcreate.h @@ -0,0 +1,46 @@ +/** + * 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 + **/ + +#ifndef UTILS_RRDCREATE_H +#define UTILS_RRDCREATE_H 1 + +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 : */