libtool
src/.deps
src/Makefile
+src/collectd.conf
src/config.h
src/libconfig/Makefile
src/liboping/Makefile
src/*.lo
src/*.o
src/collectd
-src/collectd.1
-src/collectd.conf.5
+src/collectd*.1
+src/collectd*.5
src/config.h.in~
-src/libconfig/.libs
-src/libconfig/*.la
-src/libconfig/*.lo
+src/liboconfig/.libs
+src/liboconfig/*.la
+src/liboconfig/*.lo
src/liboping/.libs
src/liboping/*.la
src/liboping/*.lo
+# lex / yacc stuff:
+ylwrap
+src/liboconfig/parser.c
+src/liboconfig/parser.h
+src/liboconfig/scanner.c
+
# make dist stuff:
collectd-*.tar.gz
collectd-*.tar.bz2
+2007-09-01, Version 4.1.0
+ * Build system: The build system has been changed to automatically
+ disable all plugins, which are missing dependencies. The dependency
+ checking has been removed from the plugins themselves to remove
+ redundancy.
+ * Flexible interval: The interval of collected data is now sent along
+ with the data itself over the network, so that the interval-settings
+ of server and clients no longer needs to match.
+ * netlink plugin: The new `netlink' plugin connects to the Linux
+ kernel using a netlink socket and uses it to query information about
+ interfaces, qdiscs and classes.
+ * rrdtool plugin: The cache is now dumped to disk in an extra thread
+ to not block data collection.
+ * snmp plugin: The new `snmp' plugin can read values from SNMP enabled
+ network devices, such as switches, routers, thermometers, rack
+ monitoring servers, etc. The collectd-snmp(5) manpage documents this
+ plugin.
+ * unixsock plugin: Added the `LISTVAL' command.
+ * xmms plugin: The new `xmms' plugin graphs the bitrate and frequency
+ of music played with xmms.
+
2007-08-26, Version 4.0.7
* documentation: Some typos have been fixed and some information has
been improved.
MySQL server statistics: Commands issued, handlers triggered, thread
usage, query cache utilization and traffic/octets sent and received.
+ - netlink
+ Very detailed Linux network interface and routing statistics. You can get
+ (detailed) information on interfaces, qdiscs, classes, and, if you can
+ make use of it, filters.
+
- network
Receive values that were collected by other hosts. Large setups will
want to collect the data on one dedicated machine, and this is the
- serial
RX and TX of serial interfaces. Linux only; needs root privileges.
+ - snmp
+ Read values from SNMP (Simple Network Management Protocol) enabled
+ network devices such as switches, routers, thermometers, rack monitoring
+ servers, etc. See collectd-snmp(5).
+
- swap
Pages swapped out onto harddisk or whatever is called `swap' by the OS..
- wireless
Link quality of wireless cards. Linux only.
+ - xmms
+ Bitrate and frequency of music played with XMMS.
+
* Output can be written or send to various destinations by the following
plugins:
* libmysqlclient (optional)
+ * libnetlink (optional)
+
+ * libnetsnmp (optional)
+
* liboping (optional, if not found a version shipped with this distribution
can be used)
Used by the `ping' plugin to send and receive ICMP packets.
* libupsclient/nut (optional)
For the `nut' plugin which queries nut's `upsd'.
+ * libxmms (optional)
+
* librt, libsocket, libkstat, libdevinfo
Various standard Solaris libraries which provide system functions.
dnl Process this file with autoconf to produce a configure script.
-AC_INIT(collectd, 4.0.7)
+AC_INIT(collectd, m4_esyscmd(./version-gen.sh))
AC_CONFIG_SRCDIR(src/collectd.c)
AC_CONFIG_HEADERS(src/config.h)
AM_INIT_AUTOMAKE(dist-bzip2)
AC_PROG_YACC
AC_CONFIG_SUBDIRS(libltdl)
+AC_MSG_CHECKING([for kernel type ($host_os)])
+case $host_os in
+ *linux*)
+ AC_DEFINE([KERNEL_LINUX], 1, [True if program is to be compiled for a Linux kernel])
+ ac_system="Linux"
+ ;;
+ *solaris*)
+ AC_DEFINE([KERNEL_SOLARIS], 1, [True if program is to be compiled for a Solaris kernel])
+ ac_system="Solaris"
+ ;;
+ *darwin*)
+ ac_system="Darwin"
+ ;;
+ *)
+ ac_system="unknown"
+esac
+AC_MSG_RESULT([$ac_system])
+
#
# Checks for header files.
#
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_HEADER_DIRENT
-AC_CHECK_HEADERS(stdint.h)
-AC_CHECK_HEADERS(stdio.h)
-AC_CHECK_HEADERS(errno.h)
-AC_CHECK_HEADERS(math.h)
-AC_CHECK_HEADERS(syslog.h)
-AC_CHECK_HEADERS(fcntl.h)
-AC_CHECK_HEADERS(signal.h)
-AC_CHECK_HEADERS(assert.h)
-AC_CHECK_HEADERS(sys/types.h)
-AC_CHECK_HEADERS(sys/socket.h)
-AC_CHECK_HEADERS(sys/select.h)
-AC_CHECK_HEADERS(poll.h)
-AC_CHECK_HEADERS(netdb.h)
-AC_CHECK_HEADERS(arpa/inet.h)
-AC_CHECK_HEADERS(sys/resource.h)
-AC_CHECK_HEADERS(sys/param.h)
-AC_CHECK_HEADERS(kstat.h)
+
+AC_CHECK_HEADERS(stdint.h stdio.h errno.h math.h stdarg.h syslog.h fcntl.h signal.h assert.h sys/types.h sys/socket.h sys/select.h poll.h netdb.h arpa/inet.h sys/resource.h sys/param.h kstat.h regex.h sys/ioctl.h)
# For ping library
AC_CHECK_HEADERS(netinet/in_systm.h, [], [],
])
# For cpu modules
+AC_CHECK_HEADERS(sys/dkstat.h)
+if test "x$ac_system" = "xDarwin"
+then
+ AC_CHECK_HEADERS(mach/mach_init.h mach/host_priv.h mach/mach_error.h mach/mach_host.h mach/mach_port.h mach/mach_types.h mach/message.h mach/processor_set.h mach/processor.h mach/processor_info.h mach/task.h mach/thread_act.h mach/vm_region.h mach/vm_map.h mach/vm_prot.h mach/vm_statistics.h mach/kern_return.h)
+ AC_CHECK_HEADERS(CoreFoundation/CoreFoundation.h IOKit/IOKitLib.h IOKit/IOTypes.h IOKit/ps/IOPSKeys.h IOKit/IOBSD.h IOKit/storage/IOBlockStorageDriver.h)
+fi
AC_CHECK_HEADERS(sys/sysctl.h, [], [],
[
#if HAVE_SYS_TYPES_H
# include <sys/param.h>
#endif
])
-AC_CHECK_HEADERS(sys/dkstat.h)
-AC_CHECK_HEADERS(mach/mach_init.h)
-AC_CHECK_HEADERS(mach/host_priv.h)
-AC_CHECK_HEADERS(mach/mach_error.h)
-AC_CHECK_HEADERS(mach/mach_host.h)
-AC_CHECK_HEADERS(mach/mach_port.h)
-AC_CHECK_HEADERS(mach/mach_types.h)
-AC_CHECK_HEADERS(mach/message.h)
-AC_CHECK_HEADERS(mach/processor_set.h)
-AC_CHECK_HEADERS(mach/processor.h)
-AC_CHECK_HEADERS(mach/processor_info.h)
-AC_CHECK_HEADERS(mach/task.h)
-AC_CHECK_HEADERS(mach/thread_act.h)
-AC_CHECK_HEADERS(mach/vm_region.h)
-AC_CHECK_HEADERS(mach/vm_map.h)
-AC_CHECK_HEADERS(mach/vm_prot.h)
-AC_CHECK_HEADERS(mach/vm_statistics.h)
-AC_CHECK_HEADERS(mach/kern_return.h)
# For hddtemp module
-AC_CHECK_HEADERS(linux/major.h)
-AC_CHECK_HEADERS(libgen.h)
-
-# For the apple_sensors module
-AC_CHECK_HEADERS(CoreFoundation/CoreFoundation.h)
-AC_CHECK_HEADERS(IOKit/IOKitLib.h)
-AC_CHECK_HEADERS(IOKit/IOTypes.h)
+AC_CHECK_HEADERS(linux/major.h libgen.h)
# For the battery plugin
AC_CHECK_HEADERS(IOKit/ps/IOPowerSources.h, [], [],
# include <IOKit/IOTypes.h>
#endif
])
-AC_CHECK_HEADERS(IOKit/ps/IOPSKeys.h)
-
-# For the `disk' plugin
-AC_CHECK_HEADERS(IOKit/IOBSD.h)
-AC_CHECK_HEADERS(IOKit/storage/IOBlockStorageDriver.h)
-
-# For load module
-AC_CHECK_HEADERS(sys/loadavg.h)
-
-# For the processes plugin
-AC_CHECK_HEADERS(linux/config.h)
# For the swap module
AC_CHECK_HEADERS(sys/swap.h, [], [],
#endif
])
+# For load module
+# For the processes plugin
# For users module
-AC_CHECK_HEADERS(utmp.h)
-AC_CHECK_HEADERS(utmpx.h)
+AC_CHECK_HEADERS(sys/loadavg.h linux/config.h utmp.h utmpx.h)
# For interface plugin
AC_CHECK_HEADERS(ifaddrs.h)
#endif
])
-# For apache plugin
-AC_CHECK_HEADERS(curl/curl.h)
-
# For quota module
-AC_CHECK_HEADERS(pwd.h)
AC_CHECK_HEADERS(sys/ucred.h, [], [],
[
#if HAVE_SYS_TYPES_H
# include <sys/param.h>
#endif
])
-AC_CHECK_HEADERS(ctype.h)
-AC_CHECK_HEADERS(limits.h)
-AC_CHECK_HEADERS(sys/quota.h)
-AC_CHECK_HEADERS(xfs/xqm.h)
# For mount interface
-AC_CHECK_HEADERS(fs_info.h)
-AC_CHECK_HEADERS(fshelp.h)
-AC_CHECK_HEADERS(paths.h)
-AC_CHECK_HEADERS(mntent.h)
-AC_CHECK_HEADERS(mnttab.h)
-AC_CHECK_HEADERS(sys/fstyp.h)
-AC_CHECK_HEADERS(sys/fs_types.h)
-AC_CHECK_HEADERS(sys/mntent.h)
-AC_CHECK_HEADERS(sys/mnttab.h)
AC_CHECK_HEADERS(sys/mount.h, [], [],
[
#if HAVE_SYS_TYPES_H
# include <sys/param.h>
#endif
])
-AC_CHECK_HEADERS(sys/statfs.h)
-AC_CHECK_HEADERS(sys/statvfs.h)
-AC_CHECK_HEADERS(sys/vfs.h)
-AC_CHECK_HEADERS(sys/vfstab.h)
-
-# For the swap plugin, FreeBSD
-AC_CHECK_HEADERS(kvm.h)
# For the email plugin
AC_CHECK_HEADERS(linux/un.h, [], [],
# include <sys/socket.h>
#endif
])
-AC_CHECK_HEADERS(sys/un.h)
-AC_CHECK_HEADERS(grp.h)
-# For debugging interface (variable number of arguments)
-AC_CHECK_HEADERS(stdarg.h)
-
-# Regular expressions for the ignorelist.
-AC_CHECK_HEADERS(regex.h)
+AC_CHECK_HEADERS(pwd.h grp.h sys/un.h ctype.h limits.h sys/quota.h xfs/xqm.h fs_info.h fshelp.h paths.h mntent.h mnttab.h sys/fstyp.h sys/fs_types.h sys/mntent.h sys/mnttab.h sys/statfs.h sys/statvfs.h sys/vfs.h sys/vfstab.h kvm.h)
# For the dns plugin
AC_CHECK_HEADERS(arpa/nameser.h)
])
# For the multimeter plugin
-AC_CHECK_HEADERS(termios.h)
-AC_CHECK_HEADERS(sys/ioctl.h)
+have_termios_h="no"
+AC_CHECK_HEADERS(termios.h, [have_termios_h="yes"])
#
# Checking for libraries
# Checks for library functions.
#
AC_PROG_GCC_TRADITIONAL
-AC_CHECK_FUNCS(gettimeofday select strdup strtol)
-AC_CHECK_FUNCS(getaddrinfo getnameinfo)
-AC_CHECK_FUNCS(strchr memcpy strstr strcmp strncmp strncpy strlen)
-AC_CHECK_FUNCS(strncasecmp strcasecmp)
-AC_CHECK_FUNCS(openlog syslog closelog)
+AC_CHECK_FUNCS(gettimeofday select strdup strtol getaddrinfo getnameinfo strchr memcpy strstr strcmp strncmp strncpy strlen strncasecmp strcasecmp openlog closelog)
AC_FUNC_STRERROR_R
AC_CHECK_FUNCS(nanosleep, [], AC_CHECK_LIB(rt, nanosleep, [nanosleep_needs_rt="yes"], AC_MSG_ERROR(cannot find nanosleep)))
AM_CONDITIONAL(BUILD_WITH_LIBRT, test "x$nanosleep_needs_rt" = "xyes")
-# Regular expressions for the ignorelist.
AC_CHECK_FUNCS(regcomp regerror regexec regfree)
-# For cpu module
AC_CHECK_FUNCS(sysctlbyname, [have_sysctlbyname="yes"], [have_sysctlbyname="no"])
-
-# For df module
-AC_CHECK_FUNCS(statfs statvfs)
+AC_CHECK_FUNCS(host_statistics, [have_host_statistics="yes"], [have_host_statistics="no"])
+AC_CHECK_FUNCS(processor_info, [have_processor_info="yes"], [have_processor_info="no"])
+AC_CHECK_FUNCS(thread_info, [have_thread_info="yes"], [have_thread_info="no"])
+AC_CHECK_FUNCS(statfs, [have_statfs="yes"], [have_statfs="no"])
+AC_CHECK_FUNCS(statvfs, [have_statvfs="yes"], [have_statvfs="no"])
+AC_CHECK_FUNCS(getifaddrs, [have_getifaddrs="yes"], [have_getifaddrs="no"])
+AC_CHECK_FUNCS(syslog, [have_syslog="yes"], [have_syslog="no"])
+AC_CHECK_FUNCS(getutent, [have_getutent="yes"], [have_getutent="no"])
+AC_CHECK_FUNCS(getutxent, [have_getutxent="yes"], [have_getutxent="no"])
# For load module
AC_CHECK_FUNCS(getloadavg, [have_getloadavg="yes"], [have_getloadavg="no"])
-# For the `processes' plugin
-AC_CHECK_FUNCS(thread_info)
-
-# For users module
-AC_CHECK_FUNCS(getutent getutxent)
-
-# For interface module
-AC_CHECK_FUNCS(getifaddrs)
-
# Check for NAN
AC_ARG_WITH(nan-emulation, [AS_HELP_STRING([--with-nan-emulation], [use emulated NAN. For crosscompiling only.])],
[
#endif
])
-AC_MSG_CHECKING([for kernel type ($host_os)])
-case $host_os in
- *linux*)
- AC_DEFINE([KERNEL_LINUX], 1, [True if program is to be compiled for a Linux kernel])
- ac_system="Linux"
- ;;
- *solaris*)
- AC_DEFINE([KERNEL_SOLARIS], 1, [True if program is to be compiled for a Solaris kernel])
- ac_system="Solaris"
- ;;
- *)
- ac_system="unknown"
-esac
-AC_MSG_RESULT([$ac_system])
-
with_libresolv="yes"
AC_CHECK_LIB(resolv, res_search,
[
[Wether or not to use pthread (POSIX threads) library])
AM_CONDITIONAL(BUILD_WITH_LIBPTHREAD, test "x$with_libpthread" = "xyes")
-if test "$ac_system" = "Solaris"
+if test "x$ac_system" = "xSolaris"
then
with_kstat="yes"
with_devinfo="yes"
then
with_lm_sensors="yes"
else
- with_lm_sensors="no"
+ with_lm_sensors="no (Linux only library)"
fi
])
if test "x$with_lm_sensors" = "xyes"
fi
AM_CONDITIONAL(BUILD_WITH_LIBOPING, test "x$with_liboping" = "xyes")
AM_CONDITIONAL(BUILD_WITH_OWN_LIBOPING, test "x$with_own_liboping" = "xyes")
-if test "x$with_liboping" = "xyes" -a "x$with_own_liboping" = "xyes"
-then
- with_liboping="yes (shipped version)"
-fi
AC_ARG_WITH(libpcap, [AS_HELP_STRING([--with-libpcap@<:@=PREFIX@:>@], [Path to libpcap.])],
[
fi
AM_CONDITIONAL(BUILD_WITH_LIBIPTC, test "x$with_libiptc" = "xyes")
-# TODO: Use `libupsclient-config' here.
-AC_ARG_WITH(libupsclient, [AS_HELP_STRING([--with-libupsclient@<:@=PREFIX@:>@], [Path to libupsclient.])],
+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
LDFLAGS="$LDFLAGS -L$withval/lib"
CPPFLAGS="$CPPFLAGS -I$withval/include"
+ with_libnetsnmp="yes"
+ fi
+],
+[with_libnetsnmp="yes"])
+if test "x$with_libnetsnmp" = "xyes"
+then
+ AC_CHECK_LIB(netsnmp, init_snmp,
+ [
+ AC_DEFINE(HAVE_LIBSNMP, 1, [Define to 1 if you have the Net-SNMP library (-lnetsnmp).])
+ ], [with_libnetsnmp="no (libnetsnmp not found)"])
+fi
+if test "x$with_libnetsnmp" = "xyes"
+then
+ AC_CHECK_HEADERS(net-snmp/net-snmp-config.h,
+ [
+ AC_DEFINE(HAVE_NET_SNMP_NET_SNMP_CONFIG_H, 1, [Define to 1 if you have the <net-snmp/net-snmp-config.h> header file.])
+ ], [with_libnetsnmp="no (net-snmp/net-snmp-config.h not found)"])
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBNETSNMP, test "x$with_libnetsnmp" = "xyes")
+
+with_upsclient_config="libupsclient-config"
+with_upsclient_cflags=""
+with_upsclient_libs=""
+AC_ARG_WITH(libupsclient, [AS_HELP_STRING([--with-libupsclient@<:@=PREFIX@:>@], [Path to libupsclient.])],
+[
+ if test "x$withval" = "xno"
+ then
+ with_libupsclient="no"
+ else
with_libupsclient="yes"
+ if "x$withval" != "xyes"
+ then
+ with_upsclient_config="$withval/bin/libupsclient-config"
+ fi
fi
],
[
])
if test "x$with_libupsclient" = "xyes"
then
+ with_upsclient_cflags=`$with_upsclient_config --cflags 2>/dev/null`
+ upsclient_config_status=$?
+
+ if test $upsclient_config_status -ne 0
+ then
+ with_libupsclient="no"
+ fi
+fi
+if test "x$with_libupsclient" = "xyes"
+then
+ with_upsclient_libs=`$with_upsclient_config --libs 2>/dev/null`
+ upsclient_config_status=$?
+
+ if test $upsclient_config_status -ne 0
+ then
+ with_libupsclient="no"
+ fi
+fi
+if test "x$with_libupsclient" = "xyes"
+then
+ CFLAGS_ORIG=$CFLAGS
+ CFLAGS="$CFLAGS $with_upsclient_cflags"
+ LDFLAGS_ORIG=$LDFLAGS
+ LDFLAGS="$LDFLAGS $with_upsclient_libs"
AC_CHECK_LIB(upsclient, upscli_connect,
[
- AC_DEFINE(HAVE_LIBUPSCLIENT, 1, [Define to 1 if you have the upsclient library (-lupsclient).])
- ], [with_libupsclient="no (libupsclient not found)"])
+ BUILD_WITH_LIBUPSCLIENT_CFLAGS="$with_upsclient_cflags"
+ BUILD_WITH_LIBUPSCLIENT_LIBS="$with_upsclient_libs"
+ AC_SUBST(BUILD_WITH_LIBUPSCLIENT_CFLAGS)
+ AC_SUBST(BUILD_WITH_LIBUPSCLIENT_LIBS)
+ ],
+ [
+ with_libupsclient="no"
+ ])
+ CFLAGS=$CFLAGS_ORIG
+ LDFLAGS=$LDFLAGS_ORIG
fi
if test "x$with_libupsclient" = "xyes"
then
- AC_CHECK_HEADERS(upsclient.h,
- [
- AC_DEFINE(HAVE_UPSCLIENT_H, 1, [Define to 1 if you have the <upsclient.h> header file.])
- ], [with_libupsclient="no (upsclient.h not found)"])
+ AC_DEFINE(HAVE_LIBUPSCLIENT, 1, [Define to 1 if you have the upsclient library (-lupsclient).])
fi
if test "x$with_libupsclient" = "xyes"
then
fi
AM_CONDITIONAL(BUILD_WITH_LIBUPSCLIENT, test "x$with_libupsclient" = "xyes")
+### BEGIN of check for libxmms ###
+with_xmms_config="xmms-config"
+with_xmms_cflags=""
+with_xmms_libs=""
+AC_ARG_WITH(libxmms, [AS_HELP_STRING([--with-libxmms@<:@=PREFIX@:>@], [Path to libxmms.])],
+[
+ if test "x$withval" != "xno" -a "x$withval" != "xyes"
+ then
+ if test -x "$withval/bin/xmms-config"
+ then
+ with_xmms_config="$withval/bin/xmms-config"
+ fi
+ fi
+ if test "x$withval" = "xno"
+ then
+ with_libxmms="no"
+ else
+ with_libxmms="yes"
+ fi
+],
+[
+ with_libxmms="yes"
+])
+if test "x$with_libxmms" = "xyes"
+then
+ with_xmms_cflags=`$with_xmms_config --cflags 2>/dev/null`
+ xmms_config_status=$?
+
+ if test $xmms_config_status -ne 0
+ then
+ with_libxmms="no"
+ fi
+fi
+if test "x$with_libxmms" = "xyes"
+then
+ with_xmms_libs=`$with_xmms_config --libs 2>/dev/null`
+ xmms_config_status=$?
+
+ if test $xmms_config_status -ne 0
+ then
+ with_libxmms="no"
+ fi
+fi
+if test "x$with_libxmms" = "xyes"
+then
+ AC_CHECK_LIB(xmms, xmms_remote_get_info,
+ [
+ BUILD_WITH_LIBXMMS_CFLAGS="$with_xmms_cflags"
+ BUILD_WITH_LIBXMMS_LIBS="$with_xmms_libs"
+ AC_SUBST(BUILD_WITH_LIBXMMS_CFLAGS)
+ AC_SUBST(BUILD_WITH_LIBXMMS_LIBS)
+ ],
+ [
+ with_libxmms="no"
+ ],
+ [$with_xmms_libs])
+fi
+with_libxmms_numeric=0
+if test "x$with_libxmms" = "xyes"
+then
+ with_libxmms_numeric=1
+fi
+AC_DEFINE_UNQUOTED(HAVE_LIBXMMS, [$with_libxmms_numeric], [Define to 1 if you have the 'xmms' library (-lxmms).])
+AM_CONDITIONAL(BUILD_WITH_LIBXMMS, test "x$with_libxmms" = "xyes")
+### END of check for libxmms ###
+
+with_libnetlink_cflags=""
+with_libnetlink_libs="-lnetlink"
+AC_ARG_WITH(libnetlink, [AS_HELP_STRING([--with-libnetlink@<:@=PREFIX@:>@], [Path to libnetlink.])],
+[
+ echo "libnetlink: withval = $withval"
+ if test "x$withval" = "xyes"
+ then
+ with_libnetlink="yes"
+ else if test "x$withval" = "xno"
+ then
+ with_libnetlink="no"
+ else
+ if test -d "$withval/include"
+ then
+ with_libnetlink_cflags="-I$withval/include"
+ with_libnetlink_libs="-L$withval/lib -lnetlink"
+ with_libnetlink="yes"
+ else
+ AC_MSG_ERROR("no such directory: $withval/include")
+ fi
+ fi; fi
+],
+[
+ if test "x$ac_system" = "xLinux"
+ then
+ with_libnetlink="yes"
+ else
+ with_libnetlink="no (Linux only library)"
+ fi
+])
+if test "x$with_libnetlink" = "xyes"
+then
+ SAVE_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS $with_libnetlink_cflags"
+
+ AC_CHECK_HEADERS(iproute/libnetlink.h, [], [with_libnetlink="no (iproute/libnetlink.h not found)"],
+[#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>])
+
+ CFLAGS="$SAVE_CFLAGS"
+fi
+if test "x$with_libnetlink" = "xyes"
+then
+ AC_CHECK_LIB(netlink, rtnl_open,
+ [with_libnetlink="yes"],
+ [with_libnetlink="no (symbol 'rtnl_open' not found)"],
+ [$with_libnetlink_libs])
+fi
+if test "x$with_libnetlink" = "xyes"
+then
+ BUILD_WITH_LIBNETLINK_CFLAGS="$with_libnetlink_cflags"
+ BUILD_WITH_LIBNETLINK_LIBS="$with_libnetlink_libs"
+ AC_SUBST(BUILD_WITH_LIBNETLINK_CFLAGS)
+ AC_SUBST(BUILD_WITH_LIBNETLINK_LIBS)
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBNETLINK, test "x$with_libnetlink" = "xyes")
+
# Check for enabled/disabled features
#
]dnl
)# AC_COLLECTD(name, enable/disable, info-text, feature/module)
+# AC_PLUGIN(name, default, info)
+# ------------------------------------------------------------
+dnl
+AC_DEFUN(
+ [AC_PLUGIN],
+ [
+ enable_plugin="no"
+ AC_ARG_ENABLE([$1], AC_HELP_STRING([--enable-$1], [$3]),
+ [
+ if test "x$enableval" = "xyes"
+ then
+ enable_plugin="yes"
+ else
+ enable_plugin="no"
+ fi
+ ],
+ [
+ if test "x$2" = "xyes"
+ then
+ enable_plugin="yes"
+ else
+ enable_plugin="no"
+ fi
+ ])
+ if test "x$enable_plugin" = "xyes"
+ then
+ AC_DEFINE([HAVE_PLUGIN_]my_toupper([$1]), 1, [Define to 1 if the $1 plugin is enabled.])
+ fi
+ AM_CONDITIONAL([BUILD_PLUGIN_]my_toupper([$1]), test "x$enable_plugin" = "xyes")
+ enable_$1="$enable_plugin"
+ ]
+)# AC_PLUGIN(name, default, info)
+
m4_divert_once([HELP_ENABLE], [
collectd features:])
+# FIXME: Remove these calls to `AC_COLLECTD' and then remove that macro.
AC_COLLECTD([debug], [enable], [feature], [debugging])
AC_COLLECTD([daemon], [disable], [feature], [daemon mode])
AC_COLLECTD([getifaddrs],[enable], [feature], [getifaddrs under Linux])
+plugin_battery="no"
+plugin_cpu="no"
+plugin_cpufreq="no"
+plugin_df="no"
+plugin_disk="no"
+plugin_entropy="no"
+plugin_interface="no"
+plugin_irq="no"
+plugin_load="no"
+plugin_memory="no"
+plugin_multimeter="no"
+plugin_nfs="no"
+plugin_processes="no"
+plugin_serial="no"
+plugin_swap="no"
+plugin_tape="no"
+plugin_users="no"
+plugin_vserver="no"
+plugin_wireless="no"
+
+# Linux
+if test "x$ac_system" = "xLinux"
+then
+ plugin_battery="yes"
+ plugin_cpu="yes"
+ plugin_cpufreq="yes"
+ plugin_disk="yes"
+ plugin_entropy="yes"
+ plugin_interface="yes"
+ plugin_irq="yes"
+ plugin_load="yes"
+ plugin_memory="yes"
+ plugin_nfs="yes"
+ plugin_processes="yes"
+ plugin_serial="yes"
+ plugin_swap="yes"
+ plugin_vserver="yes"
+ plugin_wireless="yes"
+fi
+
+# Mac OS X devices
+if test "x$with_libiokit" = "xyes"
+then
+ plugin_battery="yes"
+ plugin_disk="yes"
+fi
+
+# Solaris
+if test "x$with_devinfo$with_kstat" = "xyesyes"
+then
+ plugin_cpu="yes"
+ plugin_disk="yes"
+ plugin_interface="yes"
+ plugin_memory="yes"
+ plugin_swap="yes"
+ plugin_tape="yes"
+fi
+
+# libstatgrab
+if test "x$with_libstatgrab" = "xyes"
+then
+ plugin_interface="yes"
+ plugin_load="yes"
+ plugin_memory="yes"
+ plugin_swap="yes"
+fi
+
+if test "x$have_processor_info" = "xyes"
+then
+ plugin_cpu="yes"
+fi
+if test "x$have_sysctlbyname" = "xyes"
+then
+ plugin_cpu="yes"
+ plugin_memory="yes"
+fi
+
+if test "x$have_statfs" = "xyes"
+then
+ plugin_df="yes"
+fi
+if test "x$have_statvfs" = "xyes"
+then
+ plugin_df="yes"
+fi
+
+if test "x$have_getifaddrs" = "xyes"
+then
+ plugin_interface="yes"
+fi
+
+if test "x$have_getloadavg" = "xyes"
+then
+ plugin_load="yes"
+fi
+
+# Mac OS X memory interface
+if test "x$have_host_statistics" = "xyes"
+then
+ plugin_memory="yes"
+fi
+
+if test "x$have_termios_h" = "xyes"
+then
+ plugin_multimeter="yes"
+fi
+
+if test "x$have_thread_info" = "xyes"
+then
+ plugin_processes="yes"
+fi
+
+if test "x$with_libkvm" = "xyes"
+then
+ plugin_swap="yes"
+fi
+
+if test "x$have_getutent" = "xyes"
+then
+ plugin_users="yes"
+fi
+if test "x$have_getutxent" = "xyes"
+then
+ plugin_users="yes"
+fi
+
+# FIXME: sysctl for swap plugin
+
m4_divert_once([HELP_ENABLE], [
-collectd modules:])
-AC_COLLECTD([apache], [disable], [module], [Apache httpd statistics])
-AC_COLLECTD([apcups], [disable], [module], [Statistics of UPSes by APC])
-AC_COLLECTD([apple_sensors], [disable], [module], [Apple's hardware sensors])
-AC_COLLECTD([battery], [disable], [module], [battery statistics])
-AC_COLLECTD([cpu], [disable], [module], [cpu usage statistics])
-AC_COLLECTD([cpufreq], [disable], [module], [system cpu frequency statistics])
-AC_COLLECTD([disk], [disable], [module], [disk/partition statistics])
-AC_COLLECTD([csv], [disable], [module], [csv output plugin])
-AC_COLLECTD([df], [disable], [module], [df statistics])
-AC_COLLECTD([dns], [disable], [module], [dns statistics])
-AC_COLLECTD([email], [disable], [module], [email statistics])
-AC_COLLECTD([entropy], [disable], [module], [entropy statistics])
-AC_COLLECTD([exec], [disable], [module], [exec of external programs])
-AC_COLLECTD([hddtemp], [disable], [module], [hdd temperature statistics])
-AC_COLLECTD([interface], [disable], [module], [interface statistics])
-AC_COLLECTD([iptables], [disable], [module], [IPtables statistics])
-AC_COLLECTD([irq], [disable], [module], [irq statistics])
-AC_COLLECTD([load], [disable], [module], [system load statistics])
-AC_COLLECTD([mbmon], [disable], [module], [motherboard monitor statistics])
-AC_COLLECTD([memory], [disable], [module], [memory statistics])
-AC_COLLECTD([multimeter],[disable], [module], [multimeter statistics])
-AC_COLLECTD([mysql], [disable], [module], [mysql statistics])
-AC_COLLECTD([network], [disable], [module], [network functionality])
-AC_COLLECTD([nfs], [disable], [module], [nfs statistics])
-AC_COLLECTD([ntpd], [disable], [module], [ntpd statistics])
-AC_COLLECTD([nut], [disable], [module], [network UPS tools statistics])
-AC_COLLECTD([perl], [disable], [module], [embedded perl interpreter])
-AC_COLLECTD([ping], [disable], [module], [ping statistics])
-AC_COLLECTD([processes], [disable], [module], [processes statistics])
-AC_COLLECTD([sensors], [disable], [module], [lm_sensors statistics])
-AC_COLLECTD([serial], [disable], [module], [serial statistics])
-AC_COLLECTD([logfile], [disable], [module], [logfile log facility])
-AC_COLLECTD([swap], [disable], [module], [swap statistics])
-AC_COLLECTD([syslog], [disable], [module], [syslog log facility])
-AC_COLLECTD([tape], [disable], [module], [tape statistics])
-AC_COLLECTD([unixsock], [disable], [module], [UNIX socket plugin])
-AC_COLLECTD([users], [disable], [module], [user count statistics])
-AC_COLLECTD([vserver], [disable], [module], [vserver statistics])
-AC_COLLECTD([wireless], [disable], [module], [wireless link statistics])
+collectd plugins:])
+
+AC_PLUGIN([apache], [$with_libcurl], [Apache httpd statistics])
+AC_PLUGIN([apcups], [yes], [Statistics of UPSes by APC])
+AC_PLUGIN([apple_sensors], [$with_libiokit], [Apple's hardware sensors])
+AC_PLUGIN([battery], [$plugin_battery], [Battery statistics])
+AC_PLUGIN([cpu], [$plugin_cpu], [CPU usage statistics])
+AC_PLUGIN([cpufreq], [$plugin_cpufreq], [CPU frequency statistics])
+AC_PLUGIN([csv], [yes], [CSV output plugin])
+AC_PLUGIN([df], [$plugin_df], [Filesystem usage statistics])
+AC_PLUGIN([disk], [$plugin_disk], [Disk usage statistics])
+AC_PLUGIN([dns], [$with_libpcap], [DNS traffic analysis])
+AC_PLUGIN([email], [yes], [EMail statistics])
+AC_PLUGIN([entropy], [$plugin_entropy], [Entropy statistics])
+AC_PLUGIN([exec], [yes], [Execution of external programs])
+AC_PLUGIN([hddtemp], [yes], [Query hddtempd])
+AC_PLUGIN([interface], [$plugin_interface], [Interface traffic statistics])
+AC_PLUGIN([iptables], [$with_libiptc], [IPTables rule counters])
+AC_PLUGIN([irq], [$plugin_irq], [IRQ statistics])
+AC_PLUGIN([load], [$plugin_load], [System load])
+AC_PLUGIN([logfile], [yes], [File logging plugin])
+AC_PLUGIN([mbmon], [yes], [Query mbmond])
+AC_PLUGIN([memory], [$plugin_memory], [Memory usage])
+AC_PLUGIN([multimeter], [$plugin_multimeter], [Read multimeter values])
+AC_PLUGIN([mysql], [$with_libmysql], [MySQL statistics])
+AC_PLUGIN([netlink], [$with_libnetlink], [Enhanced Linux network statistics])
+AC_PLUGIN([network], [yes], [Network communication plugin])
+AC_PLUGIN([nfs], [$plugin_nfs], [NFS statistics])
+AC_PLUGIN([ntpd], [yes], [NTPd statistics])
+AC_PLUGIN([nut], [$with_libupsclient], [Network UPS tools statistics])
+AC_PLUGIN([perl], [$with_libperl], [Embed a Perl interpreter])
+AC_PLUGIN([ping], [$with_liboping], [Network latency statistics])
+AC_PLUGIN([processes], [$plugin_processes], [Process statistics])
+AC_PLUGIN([rrdtool], [$with_rrdtool], [RRDTool output plugin])
+AC_PLUGIN([sensors], [$with_lm_sensors], [lm_sensors statistics])
+AC_PLUGIN([serial], [$plugin_serial], [serial port traffic])
+AC_PLUGIN([snmp], [$with_libnetsnmp], [SNMP querying plugin])
+AC_PLUGIN([swap], [$plugin_swap], [Swap usage statistics])
+AC_PLUGIN([syslog], [$have_syslog], [Syslog logging plugin])
+AC_PLUGIN([tape], [$plugin_tape], [Tape drive statistics])
+AC_PLUGIN([unixsock], [yes], [Unixsock communication plugin])
+AC_PLUGIN([users], [$plugin_users], [User statistics])
+AC_PLUGIN([vserver], [$plugin_vserver], [Linux VServer statistics])
+AC_PLUGIN([wireless], [$plugin_wireless], [Wireless statistics])
+AC_PLUGIN([xmms], [$with_libxmms], [XMMS statistics])
AC_OUTPUT(Makefile src/Makefile src/collectd.conf src/liboconfig/Makefile src/liboping/Makefile)
+if test "x$with_liboping" = "xyes" -a "x$with_own_liboping" = "xyes"
+then
+ with_liboping="yes (shipped version)"
+fi
+
if test "x$with_libperl" = "xyes"
then
with_libperl="yes (version `perl -MConfig -e 'print $Config{version};'`)"
libiokit . . . . . $with_libiokit
libiptc . . . . . . $with_libiptc
libkstat . . . . . $with_kstat
+ libkvm . . . . . . $with_libkvm
libmysql . . . . . $with_libmysql
+ libnetlink . . . . $with_libnetlink
+ libnetsnmp . . . . $with_libnetsnmp
liboconfig . . . . $with_liboconfig
liboping . . . . . $with_liboping
libpcap . . . . . . $with_libpcap
libsensors . . . . $with_lm_sensors
libstatgrab . . . . $with_libstatgrab
libupsclient . . . $with_libupsclient
+ libxmms . . . . . . $with_libxmms
Features:
daemon mode . . . . $enable_daemon
memory . . . . . . $enable_memory
multimeter . . . . $enable_multimeter
mysql . . . . . . . $enable_mysql
+ netlink . . . . . . $enable_netlink
network . . . . . . $enable_network
nfs . . . . . . . . $enable_nfs
ntpd . . . . . . . $enable_ntpd
processes . . . . . $enable_processes
sensors . . . . . . $enable_sensors
serial . . . . . . $enable_serial
+ snmp . . . . . . . $enable_snmp
swap . . . . . . . $enable_swap
syslog . . . . . . $enable_syslog
tape . . . . . . . $enable_tape
users . . . . . . . $enable_users
vserver . . . . . . $enable_vserver
wireless . . . . . $enable_wireless
+ xmms . . . . . . . $enable_xmms
EOF
Exporter::export_ok_tags('all');
-bootstrap Collectd "4.0.7";
+bootstrap Collectd "4.1.0";
1;
return ("$host/$plugin/$type");
} # _create_identifier
+sub _parse_identifier
+{
+ my $string = shift;
+ my $host;
+ my $plugin;
+ my $plugin_instance;
+ my $type;
+ my $type_instance;
+ my $ident;
+
+ ($host, $plugin, $type) = split ('/', $string);
+
+ ($plugin, $plugin_instance) = split ('-', $plugin, 2);
+ ($type, $type_instance) = split ('-', $type, 2);
+
+ $ident =
+ {
+ host => $host,
+ plugin => $plugin,
+ type => $type
+ };
+ $ident->{'plugin_instance'} = $plugin_instance if (defined ($plugin_instance));
+ $ident->{'type_instance'} = $type_instance if (defined ($type_instance));
+
+ return ($ident);
+} # _parse_identifier
+
=head1 PUBLIC METHODS
=over 4
return;
} # putval
+=item I<$res> = I<$obj>-E<gt>B<listval> ()
+
+Queries a list of values from the daemon. The list is returned as an array of
+hash references, where each hash reference is a valid identifier. The C<time>
+member of each hash holds the epoch value of the last update of that value.
+
+=cut
+
+sub listval
+{
+ my $obj = shift;
+ my $msg;
+ my @ret = ();
+ my $status;
+ my $fh = $obj->{'sock'} or confess;
+
+ $msg = "LISTVAL\n";
+ send ($fh, $msg, 0) or confess ("send: $!");
+
+ $msg = <$fh>;
+ ($status, $msg) = split (' ', $msg, 2);
+ if ($status < 0)
+ {
+ $obj->{'error'} = $msg;
+ return;
+ }
+
+ for (my $i = 0; $i < $status; $i++)
+ {
+ my $time;
+ my $ident;
+
+ $msg = <$fh>;
+ chomp ($msg);
+
+ ($time, $ident) = split (' ', $msg, 2);
+
+ $ident = _parse_identifier ($ident);
+ $ident->{'time'} = int ($time);
+
+ push (@ret, $ident);
+ } # for (i = 0 .. $status)
+
+ return (@ret);
+} # listval
+
=item I<$obj>-E<gt>destroy ();
Closes the socket before the object is destroyed. This function is also
collection.cgi
--------------
- Sample CGI script that creates graphs on the fly. The Perl module `RRDs' is
-needed (Debian package `librrds-perl').
+ Sample CGI script that creates graphs on the fly. The Perl modules `RRDs'
+(Debian package `librrds-perl'), `URI:Escape' (package liburi-perl),
+`HTML::Entities' (package libhtml-parser-perl) and a CGI capable web server
+(e.g. apache2 or boa) are needed. Simply install the script to a place where
+the webserver will treat it as a CGI script (/usr/lib/cgi-bin/ by default) and
+visit that page in a browser (http://localhost/cgi-bin/collection.cgi by
+default). Please refer to your webserver's documentation for more details.
+
+ Starting with version 4, collection.cgi requires a small config file, which
+should look something like this:
+
+ datadir: "/var/lib/collectd/rrd/"
+ libdir: "/usr/lib/collectd/"
extractDS.px
------------
=over 4
-=item collectd_socket [ socket path ] (default: /tmp/.collectd-email)
+=item collectd_socket [ socket path ] (default: /var/run/collectd-email)
Where the collectd socket is
push (@cmds, {
setting => 'collectd_socket',
- default => '/tmp/.collectd-email',
+ default => '/var/run/collectd-email',
type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING,
});
collectd_buffersize 256
-collectd_socket /tmp/.collectd-email
+collectd_socket /var/run/collectd-email
collectd_timeout 2
collectd_retries 3
--- /dev/null
+datadir: "/opt/collectd/var/lib/collectd/rrd/"
+libdir: "/opt/collectd/lib/collectd/"
+
--- /dev/null
+#!/usr/bin/perl
+#
+# collectd - contrib/cussh.pl
+# Copyright (C) 2007 Sebastian Harl
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; only version 2 of the License is applicable.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Author:
+# Sebastian Harl <sh at tokkee.org>
+#
+
+=head1 NAME
+
+cussh - collectd UNIX socket shell
+
+=head1 SYNOPSIS
+
+B<cussh> [I<E<lt>pathE<gt>>]
+
+=head1 DESCRIPTION
+
+B<collectd>'s unixsock plugin allows external programs to access the values it
+has collected or received and to submit own values. This is a little
+interactive frontend for this plugin.
+
+=head1 OPTIONS
+
+=over 4
+
+=item I<E<lt>pathE<gt>>
+
+The path to the UNIX socket provided by collectd's unixsock plugin. (Default:
+F</var/run/collectd-unixsock>)
+
+=back
+
+=cut
+
+use strict;
+use warnings;
+
+use Collectd::Unixsock();
+
+{ # main
+ my $path = $ARGV[0] || "/var/run/collectd-unixsock";
+ my $sock = Collectd::Unixsock->new($path);
+
+ if (! $sock) {
+ print STDERR "Unable to connect to $path!\n";
+ exit 1;
+ }
+
+ print "cussh version 0.1, Copyright (C) 2007 Sebastian Harl\n"
+ . "cussh comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
+ . "and you are welcome to redistribute it under certain conditions.\n"
+ . "See the GNU General Public License 2 for more details.\n\n";
+
+ while (1) {
+ print "cussh> ";
+ my $line = <STDIN>;
+
+ last if ((! $line) || ($line =~ m/^quit$/i));
+
+ my ($cmd) = $line =~ m/^(\w+)\s+/;
+ $line = $';
+
+ next if (! $cmd);
+ $cmd = uc $cmd;
+
+ my $f = undef;
+ if ($cmd eq "PUTVAL") {
+ $f = \&putval;
+ }
+ elsif ($cmd eq "GETVAL") {
+ $f = \&getval;
+ }
+ else {
+ print STDERR "ERROR: Unknown command $cmd!\n";
+ next;
+ }
+
+ if (! $f->($sock, $line)) {
+ print STDERR "ERROR: Command failed!\n";
+ next;
+ }
+ }
+
+ $sock->destroy();
+ exit 0;
+}
+
+sub getid {
+ my $string = shift || return;
+
+ print $$string . $/;
+ my ($h, $p, $pi, $t, $ti) =
+ $$string =~ m/^(\w+)\/(\w+)(?:-(\w+))?\/(\w+)(?:-(\w+))?\s+/;
+ $$string = $';
+
+ return if ((! $h) || (! $p) || (! $t));
+
+ my %id = ();
+
+ ($id{'host'}, $id{'plugin'}, $id{'type'}) = ($h, $p, $t);
+
+ $id{'plugin_instance'} = $pi if ($pi);
+ $id{'type_instance'} = $ti if ($ti);
+ return \%id;
+}
+
+=head1 COMMANDS
+
+=over 4
+
+=item B<GETVAL> I<Identifier>
+
+=item B<PUTVAL> I<Identifier> I<Valuelist>
+
+These commands follow the exact same syntax as described in
+L<collectd-unixsock(5)>.
+
+=cut
+
+sub putval {
+ my $sock = shift || return;
+ my $line = shift || return;
+
+ my $id = getid(\$line);
+
+ return if (! $id);
+
+ my ($time, @values) = split m/:/, $line;
+ return $sock->putval(%$id, $time, \@values);
+}
+
+sub getval {
+ my $sock = shift || return;
+ my $line = shift || return;
+
+ my $id = getid(\$line);
+
+ return if (! $id);
+
+ my $vals = $sock->getval(%$id);
+
+ return if (! $vals);
+
+ foreach my $key (keys %$vals) {
+ print "\t$key: $vals->{$key}\n";
+ }
+ return 1;
+}
+
+=head1 SEE ALSO
+
+L<collectd(1)>, L<collectd-unisock(5)>
+
+=head1 AUTHOR
+
+Written by Sebastian Harl E<lt>sh@tokkee.orgE<gt>.
+
+B<collectd> has been written by Florian Forster and others.
+
+=head1 COPYRIGHT
+
+Copyright (C) 2007 Sebastian Harl.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; only version 2 of the License is applicable.
+
+=cut
+
+# vim: set sw=4 ts=4 tw=78 noexpandtab :
collectd_CPPFLAGS = $(LTDLINCL)
collectd_CPPFLAGS += -DPREFIX='"${prefix}"'
collectd_CPPFLAGS += -DCONFIGFILE='"${sysconfdir}/${PACKAGE_NAME}.conf"'
+collectd_CPPFLAGS += -DLOCALSTATEDIR='"${localstatedir}"'
collectd_CPPFLAGS += -DPKGLOCALSTATEDIR='"${localstatedir}/lib/${PACKAGE_NAME}"'
if BUILD_FEATURE_DAEMON
collectd_CPPFLAGS += -DPIDFILE='"${localstatedir}/run/${PACKAGE_NAME}.pid"'
pkglib_LTLIBRARIES =
-if BUILD_MODULE_APACHE
+if BUILD_PLUGIN_APACHE
pkglib_LTLIBRARIES += apache.la
apache_la_SOURCES = apache.c
apache_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += apache.la
endif
-if BUILD_MODULE_APCUPS
+if BUILD_PLUGIN_APCUPS
pkglib_LTLIBRARIES += apcups.la
apcups_la_SOURCES = apcups.c
apcups_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += apcups.la
endif
-if BUILD_MODULE_APPLE_SENSORS
+if BUILD_PLUGIN_APPLE_SENSORS
pkglib_LTLIBRARIES += apple_sensors.la
apple_sensors_la_SOURCES = apple_sensors.c
-apple_sensors_la_LDFLAGS = -module -avoid-version
-if BUILD_WITH_LIBIOKIT
-apple_sensors_la_LDFLAGS += -lIOKit
-endif
+apple_sensors_la_LDFLAGS = -module -avoid-version -lIOKit
collectd_LDADD += "-dlopen" apple_sensors.la
collectd_DEPENDENCIES += apple_sensors.la
endif
-if BUILD_MODULE_BATTERY
+if BUILD_PLUGIN_BATTERY
pkglib_LTLIBRARIES += battery.la
battery_la_SOURCES = battery.c
battery_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += battery.la
endif
-if BUILD_MODULE_CPU
+if BUILD_PLUGIN_CPU
pkglib_LTLIBRARIES += cpu.la
cpu_la_SOURCES = cpu.c
cpu_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += cpu.la
endif
-if BUILD_MODULE_CPUFREQ
+if BUILD_PLUGIN_CPUFREQ
pkglib_LTLIBRARIES += cpufreq.la
cpufreq_la_SOURCES = cpufreq.c
cpufreq_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += cpufreq.la
endif
-if BUILD_MODULE_CSV
+if BUILD_PLUGIN_CSV
pkglib_LTLIBRARIES += csv.la
csv_la_SOURCES = csv.c
csv_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += csv.la
endif
-if BUILD_MODULE_DF
+if BUILD_PLUGIN_DF
pkglib_LTLIBRARIES += df.la
df_la_SOURCES = df.c
df_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += df.la
endif
-if BUILD_MODULE_DISK
+if BUILD_PLUGIN_DISK
pkglib_LTLIBRARIES += disk.la
disk_la_SOURCES = disk.c
disk_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += disk.la
endif
-if BUILD_MODULE_DNS
+if BUILD_PLUGIN_DNS
pkglib_LTLIBRARIES += dns.la
-dns_la_SOURCES = dns.c
-if BUILD_WITH_LIBPCAP
-if BUILD_WITH_LIBPTHREAD
-dns_la_SOURCES += utils_dns.c utils_dns.h
-endif
-endif
-dns_la_LDFLAGS = -module -avoid-version
-if BUILD_WITH_LIBPCAP
-dns_la_LDFLAGS += -lpcap
-endif
-if BUILD_WITH_LIBPTHREAD
-dns_la_LDFLAGS += -lpthread
-endif
+dns_la_SOURCES = dns.c utils_dns.c utils_dns.h
+dns_la_LDFLAGS = -module -avoid-version -lpcap -lpthread
collectd_LDADD += "-dlopen" dns.la
collectd_DEPENDENCIES += dns.la
endif
-if BUILD_MODULE_EMAIL
+if BUILD_PLUGIN_EMAIL
pkglib_LTLIBRARIES += email.la
email_la_SOURCES = email.c
email_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += email.la
endif
-if BUILD_MODULE_ENTROPY
+if BUILD_PLUGIN_ENTROPY
pkglib_LTLIBRARIES += entropy.la
entropy_la_SOURCES = entropy.c
entropy_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += entropy.la
endif
-if BUILD_MODULE_EXEC
+if BUILD_PLUGIN_EXEC
pkglib_LTLIBRARIES += exec.la
-exec_la_SOURCES = exec.c
+exec_la_SOURCES = exec.c utils_cmd_putval.c utils_cmd_putval.h
exec_la_LDFLAGS = -module -avoid-version
if BUILD_WITH_LIBPTHREAD
exec_la_LDFLAGS += -lpthread
collectd_DEPENDENCIES += exec.la
endif
-if BUILD_MODULE_HDDTEMP
+if BUILD_PLUGIN_HDDTEMP
pkglib_LTLIBRARIES += hddtemp.la
hddtemp_la_SOURCES = hddtemp.c
hddtemp_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += hddtemp.la
endif
-if BUILD_MODULE_INTERFACE
+if BUILD_PLUGIN_INTERFACE
pkglib_LTLIBRARIES += interface.la
interface_la_SOURCES = interface.c
interface_la_LDFLAGS = -module -avoid-version
endif
endif
-if BUILD_MODULE_IPTABLES
+if BUILD_PLUGIN_IPTABLES
pkglib_LTLIBRARIES += iptables.la
iptables_la_SOURCES = iptables.c
-iptables_la_LDFLAGS = -module -avoid-version
-if BUILD_WITH_LIBIPTC
-iptables_la_LDFLAGS += -liptc
-endif
+iptables_la_LDFLAGS = -module -avoid-version -liptc
collectd_LDADD += "-dlopen" iptables.la
collectd_DEPENDENCIES += iptables.la
endif
-if BUILD_MODULE_IRQ
+if BUILD_PLUGIN_IRQ
pkglib_LTLIBRARIES += irq.la
irq_la_SOURCES = irq.c
irq_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += irq.la
endif
-if BUILD_MODULE_LOAD
+if BUILD_PLUGIN_LOAD
pkglib_LTLIBRARIES += load.la
load_la_SOURCES = load.c
load_la_LDFLAGS = -module -avoid-version
endif
endif
-if BUILD_MODULE_LOGFILE
+if BUILD_PLUGIN_LOGFILE
pkglib_LTLIBRARIES += logfile.la
logfile_la_SOURCES = logfile.c
logfile_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += logfile.la
endif
-if BUILD_MODULE_MBMON
+if BUILD_PLUGIN_MBMON
pkglib_LTLIBRARIES += mbmon.la
mbmon_la_SOURCES = mbmon.c
mbmon_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += mbmon.la
endif
-if BUILD_MODULE_MEMORY
+if BUILD_PLUGIN_MEMORY
pkglib_LTLIBRARIES += memory.la
memory_la_SOURCES = memory.c
memory_la_LDFLAGS = -module -avoid-version
endif
endif
-if BUILD_MODULE_MULTIMETER
+if BUILD_PLUGIN_MULTIMETER
pkglib_LTLIBRARIES += multimeter.la
multimeter_la_SOURCES = multimeter.c
multimeter_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += multimeter.la
endif
-if BUILD_MODULE_MYSQL
+if BUILD_PLUGIN_MYSQL
pkglib_LTLIBRARIES += mysql.la
mysql_la_SOURCES = mysql.c
mysql_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += mysql.la
endif
-if BUILD_MODULE_NETWORK
+if BUILD_PLUGIN_NETLINK
+pkglib_LTLIBRARIES += netlink.la
+netlink_la_SOURCES = netlink.c
+netlink_la_LDFLAGS = -module -avoid-version
+netlink_la_CFLAGS = $(BUILD_WITH_LIBNETLINK_CFLAGS)
+netlink_la_LIBADD = $(BUILD_WITH_LIBNETLINK_LIBS)
+collectd_LDADD += "-dlopen" netlink.la
+collectd_DEPENDENCIES += netlink.la
+endif
+
+if BUILD_PLUGIN_NETWORK
pkglib_LTLIBRARIES += network.la
network_la_SOURCES = network.c network.h
network_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += network.la
endif
-if BUILD_MODULE_NFS
+if BUILD_PLUGIN_NFS
pkglib_LTLIBRARIES += nfs.la
nfs_la_SOURCES = nfs.c
nfs_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += nfs.la
endif
-if BUILD_MODULE_NTPD
+if BUILD_PLUGIN_NTPD
pkglib_LTLIBRARIES += ntpd.la
ntpd_la_SOURCES = ntpd.c
ntpd_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += ntpd.la
endif
-if BUILD_MODULE_NUT
+if BUILD_PLUGIN_NUT
pkglib_LTLIBRARIES += nut.la
nut_la_SOURCES = nut.c
-nut_la_LDFLAGS = -module -avoid-version
-if BUILD_WITH_LIBUPSCLIENT
-nut_la_LDFLAGS += -lupsclient
-if BUILD_WITH_LIBPTHREAD
-nut_la_LDFLAGS += -lpthread
-endif
-endif
+nut_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBUPSCLIENT_CFLAGS)
+nut_la_LDFLAGS = -module -avoid-version -lpthread $(BUILD_WITH_LIBUPSCLIENT_LIBS)
collectd_LDADD += "-dlopen" nut.la
collectd_DEPENDENCIES += nut.la
endif
-if BUILD_WITH_LIBPERL
-if BUILD_MODULE_PERL
+if BUILD_PLUGIN_PERL
pkglib_LTLIBRARIES += perl.la
perl_la_SOURCES = perl.c
perl_la_CFLAGS = $(AM_CFLAGS) \
collectd_LDADD += "-dlopen" perl.la
collectd_DEPENDENCIES += perl.la
endif
-endif
-if BUILD_MODULE_PING
+if BUILD_PLUGIN_PING
pkglib_LTLIBRARIES += ping.la
ping_la_SOURCES = ping.c
ping_la_LDFLAGS = -module -avoid-version
-if BUILD_WITH_LIBOPING
if BUILD_WITH_OWN_LIBOPING
ping_la_LIBADD = liboping/liboping.la
ping_la_DEPENDENCIES = liboping/liboping.la
else
ping_la_LDFLAGS += -loping
endif
-endif
collectd_LDADD += "-dlopen" ping.la
collectd_DEPENDENCIES += ping.la
endif
-if BUILD_MODULE_PROCESSES
+if BUILD_PLUGIN_PROCESSES
pkglib_LTLIBRARIES += processes.la
processes_la_SOURCES = processes.c
processes_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += processes.la
endif
-if BUILD_WITH_RRDTOOL
+if BUILD_PLUGIN_RRDTOOL
pkglib_LTLIBRARIES += rrdtool.la
rrdtool_la_SOURCES = rrdtool.c
rrdtool_la_LDFLAGS = -module -avoid-version -lrrd
collectd_DEPENDENCIES += rrdtool.la
endif
-if BUILD_MODULE_SENSORS
+if BUILD_PLUGIN_SENSORS
pkglib_LTLIBRARIES += sensors.la
sensors_la_SOURCES = sensors.c
sensors_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += sensors.la
endif
-if BUILD_MODULE_SERIAL
+if BUILD_PLUGIN_SERIAL
pkglib_LTLIBRARIES += serial.la
serial_la_SOURCES = serial.c
serial_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += serial.la
endif
-if BUILD_MODULE_SWAP
+if BUILD_PLUGIN_SNMP
+pkglib_LTLIBRARIES += snmp.la
+snmp_la_SOURCES = snmp.c
+snmp_la_LDFLAGS = -module -avoid-version
+if BUILD_WITH_LIBNETSNMP
+snmp_la_LDFLAGS += -lnetsnmp
+endif
+if BUILD_WITH_LIBPTHREAD
+snmp_la_LDFLAGS += -lpthread
+endif
+collectd_LDADD += "-dlopen" snmp.la
+collectd_DEPENDENCIES += snmp.la
+endif
+
+if BUILD_PLUGIN_SWAP
pkglib_LTLIBRARIES += swap.la
swap_la_SOURCES = swap.c
swap_la_LDFLAGS = -module -avoid-version
endif
endif
-if BUILD_MODULE_SYSLOG
+if BUILD_PLUGIN_SYSLOG
pkglib_LTLIBRARIES += syslog.la
syslog_la_SOURCES = syslog.c
syslog_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += syslog.la
endif
-if BUILD_MODULE_TAPE
+if BUILD_PLUGIN_TAPE
pkglib_LTLIBRARIES += tape.la
tape_la_SOURCES = tape.c
-tape_la_LDFLAGS = -module -avoid-version
-if BUILD_WITH_LIBKSTAT
-tape_la_LDFLAGS += -lkstat
-endif
-if BUILD_WITH_LIBDEVINFO
-tape_la_LDFLAGS += -ldevinfo
-endif
+tape_la_LDFLAGS = -module -avoid-version -lkstat -ldevinfo
collectd_LDADD += "-dlopen" tape.la
collectd_DEPENDENCIES += tape.la
endif
-if BUILD_MODULE_UNIXSOCK
+if BUILD_PLUGIN_UNIXSOCK
pkglib_LTLIBRARIES += unixsock.la
-unixsock_la_SOURCES = unixsock.c
-unixsock_la_CPPFLAGS = -DPREFIX='"${prefix}"'
+unixsock_la_SOURCES = unixsock.c utils_cmd_putval.h utils_cmd_putval.c
+unixsock_la_CPPFLAGS = -DLOCALSTATEDIR='"${localstatedir}"'
unixsock_la_LDFLAGS = -module -avoid-version -lpthread
collectd_LDADD += "-dlopen" unixsock.la
collectd_DEPENDENCIES += unixsock.la
endif
-if BUILD_MODULE_USERS
+if BUILD_PLUGIN_USERS
pkglib_LTLIBRARIES += users.la
users_la_SOURCES = users.c
users_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += users.la
endif
-if BUILD_MODULE_VSERVER
+if BUILD_PLUGIN_VSERVER
pkglib_LTLIBRARIES += vserver.la
vserver_la_SOURCES = vserver.c
vserver_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += vserver.la
endif
-if BUILD_MODULE_WIRELESS
+if BUILD_PLUGIN_WIRELESS
pkglib_LTLIBRARIES += wireless.la
wireless_la_SOURCES = wireless.c
wireless_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += wireless.la
endif
+if BUILD_PLUGIN_XMMS
+pkglib_LTLIBRARIES += xmms.la
+xmms_la_SOURCES = xmms.c
+xmms_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBXMMS_CFLAGS)
+xmms_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBXMMS_LIBS)
+collectd_LDADD += "-dlopen" xmms.la
+collectd_DEPENDENCIES += xmms.la
+endif
+
+
dist_man_MANS = collectd.1 collectd-nagios.1 collectd.conf.5 \
collectd-email.5 collectd-exec.5 collectd-perl.5 \
- collectd-unixsock.5
+ collectd-snmp.5 collectd-unixsock.5
#collectd_1_SOURCES = collectd.pod
/**
* collectd - src/apache.c
- * Copyright (C) 2006 Florian octo Forster
+ * Copyright (C) 2006,2007 Florian octo Forster
* Copyright (C) 2007 Florent EppO Monbillard
*
* This program is free software; you can redistribute it and/or modify it
#include "plugin.h"
#include "configfile.h"
-#if HAVE_LIBCURL && HAVE_CURL_CURL_H
-# define APACHE_HAVE_READ 1
-# include <curl/curl.h>
-#else
-# define APACHE_HAVE_READ 0
-#endif
+#include <curl/curl.h>
-#if APACHE_HAVE_READ
static char *url = NULL;
static char *user = NULL;
static char *pass = NULL;
return (0);
} /* int apache_read */
-#endif /* APACHE_HAVE_READ */
void module_register (void)
{
-#if APACHE_HAVE_READ
plugin_register_config ("apache", config,
config_keys, config_keys_num);
plugin_register_init ("apache", init);
plugin_register_read ("apache", apache_read);
-#endif
} /* void module_register */
/*
* collectd - src/apcups.c
+ * Copyright (C) 2007 Florian octo Forster
* Copyright (C) 2006 Anthony Gialluca <tonyabg at charter.net>
* Copyright (C) 2000-2004 Kern Sibbald
* Copyright (C) 1996-99 Andre M. Hedrick <andre at suse.com>
*
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General
* Public License as published by the Free Software Foundation.
# include <IOKit/IOTypes.h>
#endif
-#if HAVE_IOKIT_IOKITLIB_H
-# define IOKIT_HAVE_READ 1
-#else
-# define IOKIT_HAVE_READ 0
-#endif
-
-#if HAVE_IOKIT_IOKITLIB_H
static mach_port_t io_master_port = MACH_PORT_NULL;
-#endif
-#if IOKIT_HAVE_READ
static int as_init (void)
{
kern_return_t status;
return (0);
} /* int as_read */
-#endif /* IOKIT_HAVE_READ */
void module_register (void)
{
-#if IOKIT_HAVE_READ
plugin_register_init ("apple_sensors", as_init);
plugin_register_read ("apple_sensors", as_read);
-#endif /* IOKIT_HAVE_READ */
} /* void module_register */
# include <IOKit/ps/IOPSKeys.h>
#endif
-#if HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H || KERNEL_LINUX
-# define BATTERY_HAVE_READ 1
-#else
-# define BATTERY_HAVE_READ 0
+#if !HAVE_IOKIT_IOKITLIB_H && !HAVE_IOKIT_PS_IOPOWERSOURCES_H && !KERNEL_LINUX
+# error "No applicable input method."
#endif
#define INVALID_VALUE 47841.29
-#if BATTERY_HAVE_READ
#if HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H
/* No global variables */
/* #endif HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H */
return (0);
}
-#endif /* BATTERY_HAVE_READ */
void module_register (void)
{
-#if BATTERY_HAVE_READ
plugin_register_init ("battery", battery_init);
plugin_register_read ("battery", battery_read);
-#endif /* BATTERY_HAVE_READ */
} /* void module_register */
=item
-Other lines must consist of an I<Identifier> and a I<Value-List>, separated by
-a space. A description of these two parts follows:
+Other lines must consist of an I<Identifier>, an optional I<Option-List> and a
+I<Value-List>, separated by a spaces. A description of these two parts follows:
An I<Identifier> is of the form
C<I<host>B</>I<plugin>B<->I<instance>B</>I<type>B<->I<instance>> with both
I<instance>-parts being optional. If they're omitted the hyphen must be
omitted, too.
-A I<Value-List> is a colon-separated list of values, prepended by the time
-stamp in epoch, i.E<nbsp>e. the same format RRDTool uses, see L<rrdupdate(1)>.
-As with the argument passed to RRDTool you can use B<N> as the current time and
-B<U> for undefined values. However, undefined values can only passed for
-B<GAUGE> values. When setting B<U> for a B<COUNTER> data source the behavior is
-undefined.
+The I<OptionList> is an optional list of I<Options>, where each option if a
+key-value-pair. A list of currently understood options can be found below, all
+other options will be ignored.
+
+I<Valuelist> is a colon-seperated list of the time and the values, each either
+an integer if the data-source is a counter, of a double if the data-source if
+of type "gauge". You can submit an undefined gauge-value by using B<U>. When
+submitting B<U> to a counter the behavior is undefined. The time is given as
+epoch (i.E<nbsp>e. standard UNIX time).
+
+You can mix options and values, but the order is important: Options only
+effect following values, so specifying an option as last field is allowed, but
+useless. Also, an option applies to B<all> following values, so you don't need
+to re-set an option over and over again.
+
+The currently defined B<Options> are:
+
+=over 4
+
+=item B<interval=>I<seconds>
+
+Gives the interval in which the data identified by I<Identifier> is being
+collected.
+
+=back
+
+Please note that this is the same format as used in the B<unixsock plugin>, see
+L<collectd-unixsock(5)>. There's also a bit more information on identifiers in
+case you're confused.
Since examples usually let one understand a lot better, here are some:
leeloo/cpu-0/cpu-idle N:2299366
- alice/interface/if_octets-eth0 1180647081:421465:479194
+ alice/interface/if_octets-eth0 interval=10 1180647081:421465:479194
=back
num_okay++;
}
- if ((num_critical != 0) || (values_num == 0))
+ printf ("%i critical, %i warning, %i okay",
+ num_critical, num_warning, num_okay);
+ if (values_num > 0)
{
- printf ("CRITICAL: %i critical, %i warning, %i okay\n",
- num_critical, num_warning, num_okay);
- return (RET_CRITICAL);
+ printf (" |");
+ for (i = 0; i < values_num; i++)
+ printf (" %s=%lf;;;;", values_names[i], values[i]);
}
+ printf ("\n");
+
+ if ((num_critical != 0) || (values_num == 0))
+ return (RET_CRITICAL);
else if (num_warning != 0)
- {
- printf ("WARNING: %i warning, %i okay\n",
- num_warning, num_okay);
return (RET_WARNING);
- }
- else
- {
- printf ("OKAY: %i okay\n", num_okay);
- return (RET_OKAY);
- }
- return (RET_UNKNOWN);
+ return (RET_OKAY);
} /* int do_check_con_none */
int do_check_con_average (int values_num, double *values, char **values_names)
int i;
double total;
int total_num;
+ double average;
total = 0.0;
total_num = 0;
}
if (total_num == 0)
- {
- printf ("WARNING: No defined values found\n");
+ average = NAN;
+ else
+ average = total / total_num;
+ printf ("%lf average |", average);
+ for (i = 0; i < values_num; i++)
+ printf (" %s=%lf;;;;", values_names[i], values[i]);
+
+ if (total_num == 0)
return (RET_WARNING);
- }
- if (match_range (&range_critical_g, total / total_num) != 0)
- {
- printf ("CRITICAL: Average = %lf\n",
- (double) (total / total_num));
+ if (isnan (average)
+ || match_range (&range_critical_g, average))
return (RET_CRITICAL);
- }
- else if (match_range (&range_warning_g, total / total_num) != 0)
- {
- printf ("WARNING: Average = %lf\n",
- (double) (total / total_num));
+ else if (match_range (&range_warning_g, average) != 0)
return (RET_WARNING);
- }
- else
- {
- printf ("OKAY: Average = %lf\n",
- (double) (total / total_num));
- return (RET_OKAY);
- }
- return (RET_UNKNOWN);
+ return (RET_OKAY);
} /* int do_check_con_average */
int do_check_con_sum (int values_num, double *values, char **values_names)
return (do_check_con_sum (values_num, values, values_names));
free (values);
- free (values_names);
+ free (values_names); /* FIXME? */
return (RET_UNKNOWN);
}
--- /dev/null
+=head1 NAME
+
+collectd-snmp - Documentation of collectd's C<snmp plugin>
+
+=head1 SYNOPSIS
+
+ LoadPlugin snmp
+ # ...
+ <Plugin snmp>
+ <Data "powerplus_voltge_input">
+ Type "voltage"
+ Table false
+ Instance "input_line1"
+ Values "SNMPv2-SMI::enterprises.6050.5.4.1.1.2.1"
+ </Data>
+ <Data "hr_users">
+ Type "users"
+ Table false
+ Instance ""
+ Values "HOST-RESOURCES-MIB::hrSystemNumUsers.0"
+ </Data>
+ <Data "std_traffic">
+ Type "if_octets"
+ Table true
+ Instance "IF-MIB::ifDescr"
+ Values "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets"
+ </Data>
+
+ <Host "some.switch.mydomain.org">
+ Address "192.168.0.2"
+ Version 1
+ Community "community_string"
+ Collect "std_traffic"
+ Inverval 120
+ </Host>
+ <Host "some.server.mydomain.org">
+ Address "192.168.0.42"
+ Version 2
+ Community "another_string"
+ Collect "std_traffic" "hr_users"
+ </Host>
+ <Host "some.ups.mydomain.org">
+ Address "192.168.0.3"
+ Version 1
+ Community "more_communities"
+ Collect "powerplus_voltge_input"
+ Interval 300
+ </Host>
+ </Plugin>
+
+=head1 DESCRIPTION
+
+The C<snmp plugin> queries other hosts using SNMP, the simple network
+management protocol, and translates the value it receives to collectd's
+internal format and dispatches them. Depending on the write plugins you have
+loaded they may be written to disk or submitted to another instance or
+whatever you configured.
+
+Because querying a host via SNMP may produce a timeout multiple threads are
+used to query hosts in parallel. Depending on the number of hosts between one
+and ten threads are used.
+
+=head1 CONFIGURATION
+
+Since the aim of the C<snmp plugin> is to provide a generic interface to SNMP,
+it's configuration is not trivial and may take some time.
+
+There are two types of blocks that can be contained in the
+C<E<lt>PluginE<nbsp>snmpE<gt>> block: B<Data> and B<Host>:
+
+=head2 The B<Data> block
+
+The B<Data> block defines a list of values or a table of values that are to be
+queried. The following options can be set:
+
+=over 4
+
+=item B<Type> I<type>
+
+collectd's type that is to be used, e.E<nbsp>g. "if_octets" for interface
+traffic or "users" for a user count. The types are read from the B<TypesDB>
+(see L<collectd.conf(5)>), so you may want to check for which types are
+defined.
+
+=item B<Table> I<true|false>
+
+Define if this is a single list of values or a table of values. The difference
+is the following:
+
+When B<Table> is set to B<false>, the OIDs given to B<Values> (see below) are
+queried using the C<GET> SNMP command (see L<snmpget(1)>) and transmitted to
+collectd. B<One> value list is dispatched and, eventually, one file will be
+written.
+
+When B<Table> is set to B<true>, the OIDs given to B<Values> (see below) are
+queried using the C<GETNEXT> SNMP command until the subtree is left. After all
+the lists (think: all columns of the table) have been read B<several> values
+sets will be dispatches and, eventually, several files will be written. If you
+configure a B<Type> (see above) which needs more than one data source (for
+example C<if_octets> which needs C<rx> and C<tx>) you will need to specify more
+than one (two, in the example case) OIDs with the B<Values> option. This has
+nothing to do with the B<Table> setting.
+
+For example, if you want to query the number of users on a system, you can use
+C<HOST-RESOURCES-MIB::hrSystemNumUsers.0>. This is one value and belongs to one
+value list, therefore B<Table> must be set to B<false>. Please note that, in
+this case, you have to include the sequence number (zero in this case) in the
+OID.
+
+Counter example: If you want to query the interface table provided by the
+C<IF-MIB>, e.E<nbsp>g. the bytes transmitted. There are potentially many
+interfaces, so you will want to set B<Table> to B<true>. Because the
+C<if_octets> type needs two values, received and transmitted bytes, you need to
+specify two OIDs in the B<Values> setting, in this case likely
+C<IF-MIB::ifHCInOctets> and C<IF-MIB::ifHCOutOctets>. But, this is because of
+the B<Type> setting, not the B<Table> setting.
+
+Since the semantic of B<Instance> and B<Values> depends on this setting you
+need to set it before setting them. Doing vice verse will result in undefined
+behavior.
+
+=item B<Instance> I<Instance>
+
+Sets the type-instance of the values that are dispatched. The meaning of this
+setting depends on whether B<Table> is set to I<true> or I<false>:
+
+If B<Table> is set to I<true>, I<Instance> is interpreted as an SNMP-prefix
+that will return a list of strings. Those strings are then used as the actual
+type-instance. An example would be the C<IF-MIB::ifDescr> subtree.
+L<variables(5)> from the SNMP distribution describes the format of OIDs.
+
+If B<Table> is set to I<false> the actual string configured for I<Instance> is
+copied into the value-list. In this case I<Instance> may be empty, i.E<nbsp>e.
+"".
+
+=item B<Values> I<OID> [I<OID> ...]
+
+Configures the values to be queried from the SNMP host. The meaning slightly
+changes with the B<Table> setting. L<variables(5)> from the SNMP distribution
+describes the format of OIDs.
+
+If B<Table> is set to I<true>, each I<OID> must be the prefix of all the
+values to query, e.E<nbsp>g. C<IF-MIB::ifInOctets> for all the counters of
+incoming traffic. This subtree is walked (using C<GETNEXT>) until a value from
+outside the subtree is returned.
+
+If B<Table> is set to I<false>, each I<OID> must be the OID of exactly one
+value, e.E<nbsp>g. C<IF-MIB::ifInOctets.3> for the third counter of incoming
+traffic.
+
+=back
+
+=head2 The Host block
+
+The B<Host> block defines which hosts to query, which SNMP community and
+version to use and which of the defined B<Data> to query.
+
+The argument passed to the B<Host> block is used as the hostname in the data
+stored by collectd.
+
+=over 4
+
+=item B<Address> I<IP-Address>|I<Hostname>
+
+Set the address to connect to.
+
+=item B<Version> B<1>|B<2>
+
+Set the SNMP version to use. When giving B<2> version 2c is actually used.
+Version 3 is not supported by this plugin.
+
+=item B<Community> I<Community>
+
+Pass I<Community> to the host.
+
+=item B<Collect> I<Data> [I<Data> ...]
+
+Defines which values to collect. I<Data> refers to one of the B<Data> block
+above. Since the config file is read top-down you need to define the data
+before using it here.
+
+=item B<Interval> I<Seconds>
+
+Collect data from this host every I<Seconds> seconds. This value needs to be a
+multiple of the global B<Interval> setting and, if it is not, will be rounded
+B<down> to one and a warning is logged in this case. So if your global
+B<Interval> is set to I<10> and you configure I<25> here, it's rounded down to
+I<20>. By default the global B<Interval> setting will be used.
+
+This option is meant for devices with not much CPU power, e.E<nbsp>g. network
+equipment such as switches, embedded devices, rack monitoring systems and so
+on. Since the B<Step> of generated RRD files depends on this setting it's
+wise to select a reasonable value once and never change it.
+
+=back
+
+=head1 SEE ALSO
+
+L<collectd(1)>,
+L<collectd.conf(5)>,
+L<snmpget(1)>,
+L<snmpgetnext(1)>,
+L<variables(5)>,
+L<unix(7)>
+
+=head1 AUTHOR
+
+Florian Forster E<lt>octo@verplant.orgE<gt>
+
+=cut
-> | GETVAL myhost/cpu-0/cpu-user
<- | 1 value=1.260000e+00
-=item B<PUTVAL> I<Identifier> I<Valuelist>
+=item B<LISTVAL>
-Submits a value (identified by I<Identifier>, see below) to the daemon which
-will dispatch it to all it's write-plugins. The I<Valuelist> is a
-colon-separated list of the time and the values, each either an integer if the
-data-source is a counter, of a double if the data-source if of type "gauge".
-You can submit an undefined gauge-value by using B<U>. When submitting B<U> to
-a counter the behavior is undefined. The time is given as epoch (i.E<nbsp>e.
-standard UNIX time).
+Returnes a list of the values available in the value cache together with the
+time of the last update, so that querying applications can issue a B<GETVAL>
+command for the values that have changed.
+
+The first line's status number is the number of identifiers returned or less
+than zero if an error occured. Each of the following lines containes the
+update time as an epoch value and the identifier, seperated by a space.
+
+Example:
+ -> | LISTVAL
+ <- | 69 Values found
+ <- | 1182204284 leeloo/cpu-0/cpu-idle
+ <- | 1182204284 leeloo/cpu-0/cpu-nice
+ <- | 1182204284 leeloo/cpu-0/cpu-system
+ <- | 1182204284 leeloo/cpu-0/cpu-user
+ ...
+
+=item B<PUTVAL> I<Identifier> [I<OptionList>] I<Valuelist>
+
+Submits one or more values (identified by I<Identifier>, see below) to the
+daemon which will dispatch it to all it's write-plugins.
+
+An I<Identifier> is of the form
+C<I<host>B</>I<plugin>B<->I<instance>B</>I<type>B<->I<instance>> with both
+I<instance>-parts being optional. If they're omitted the hyphen must be
+omitted, too.
+
+The I<OptionList> is an optional list of I<Options>, where each option if a
+key-value-pair. A list of currently understood options can be found below, all
+other options will be ignored.
+
+I<Valuelist> is a colon-seperated list of the time and the values, each either
+an integer if the data-source is a counter, of a double if the data-source if
+of type "gauge". You can submit an undefined gauge-value by using B<U>. When
+submitting B<U> to a counter the behavior is undefined. The time is given as
+epoch (i.E<nbsp>e. standard UNIX time).
+
+You can mix options and values, but the order is important: Options only
+effect following values, so specifying an option as last field is allowed, but
+useless. Also, an option applies to B<all> following values, so you don't need
+to re-set an option over and over again.
+
+The currently defined B<Options> are:
+
+=over 4
+
+=item B<interval=>I<seconds>
+
+Gives the interval in which the data identified by I<Identifier> is being
+collected.
+
+=back
+
+Please note that this is the same format as used in the B<exec plugin>, see
+L<collectd-exec(5)>.
Example:
- -> | PUTVAL testhost/interface/if_octets-test0 1179574444:123:456
+ -> | PUTVAL testhost/interface/if_octets-test0 interval=10 1179574444:123:456
<- | 0 Success
=back
#Interval 10
#ReadThreads 5
-@BUILD_MODULE_APACHE_TRUE@LoadPlugin apache
-@BUILD_MODULE_APCUPS_TRUE@LoadPlugin apcups
-@BUILD_MODULE_APPLE_SENSORS_TRUE@LoadPlugin apple_sensors
-@BUILD_MODULE_BATTERY_TRUE@LoadPlugin battery
-@BUILD_MODULE_CPU_TRUE@LoadPlugin cpu
-@BUILD_MODULE_CPUFREQ_TRUE@LoadPlugin cpufreq
-@BUILD_MODULE_CSV_TRUE@LoadPlugin csv
-@BUILD_MODULE_DF_TRUE@LoadPlugin df
-@BUILD_MODULE_DISK_TRUE@LoadPlugin disk
-@BUILD_MODULE_DNS_TRUE@LoadPlugin dns
-@BUILD_MODULE_EMAIL_TRUE@LoadPlugin email
-@BUILD_MODULE_ENTROPY_TRUE@LoadPlugin entropy
-@BUILD_MODULE_EXEC_TRUE@LoadPlugin exec
-@BUILD_MODULE_HDDTEMP_TRUE@LoadPlugin hddtemp
-@BUILD_MODULE_INTERFACE_TRUE@LoadPlugin interface
-@BUILD_MODULE_IPTABLES_TRUE@LoadPlugin iptables
-@BUILD_MODULE_IRQ_TRUE@LoadPlugin irq
-@BUILD_MODULE_LOAD_TRUE@LoadPlugin load
-@BUILD_MODULE_LOGFILE_TRUE@LoadPlugin logfile
-@BUILD_MODULE_MBMON_TRUE@LoadPlugin mbmon
-@BUILD_MODULE_MEMORY_TRUE@LoadPlugin memory
-@BUILD_MODULE_MULTIMETER_TRUE@LoadPlugin multimeter
-@BUILD_MODULE_MYSQL_TRUE@LoadPlugin mysql
-@BUILD_MODULE_NETWORK_TRUE@LoadPlugin network
-@BUILD_MODULE_NFS_TRUE@LoadPlugin nfs
-@BUILD_MODULE_NTPD_TRUE@LoadPlugin ntpd
-@BUILD_MODULE_NUT_TRUE@LoadPlugin nut
-@BUILD_MODULE_PERL_TRUE@LoadPlugin perl
-@BUILD_MODULE_PING_TRUE@LoadPlugin ping
-@BUILD_MODULE_PROCESSES_TRUE@LoadPlugin processes
-@BUILD_WITH_RRDTOOL_TRUE@LoadPlugin rrdtool
-@BUILD_MODULE_SENSORS_TRUE@LoadPlugin sensors
-@BUILD_MODULE_SERIAL_TRUE@LoadPlugin serial
-@BUILD_MODULE_SWAP_TRUE@LoadPlugin swap
-@BUILD_MODULE_SYSLOG_TRUE@LoadPlugin syslog
-@BUILD_MODULE_TAPE_TRUE@LoadPlugin tape
-@BUILD_MODULE_UNIXSOCK_TRUE@LoadPlugin unixsock
-@BUILD_MODULE_USERS_TRUE@LoadPlugin users
-@BUILD_MODULE_VSERVER_TRUE@LoadPlugin vserver
-@BUILD_MODULE_WIRELESS_TRUE@LoadPlugin wireless
+@BUILD_PLUGIN_APACHE_TRUE@LoadPlugin apache
+@BUILD_PLUGIN_APCUPS_TRUE@LoadPlugin apcups
+@BUILD_PLUGIN_APPLE_SENSORS_TRUE@LoadPlugin apple_sensors
+@BUILD_PLUGIN_BATTERY_TRUE@LoadPlugin battery
+@BUILD_PLUGIN_CPU_TRUE@LoadPlugin cpu
+@BUILD_PLUGIN_CPUFREQ_TRUE@LoadPlugin cpufreq
+@BUILD_PLUGIN_CSV_TRUE@LoadPlugin csv
+@BUILD_PLUGIN_DF_TRUE@LoadPlugin df
+@BUILD_PLUGIN_DISK_TRUE@LoadPlugin disk
+@BUILD_PLUGIN_DNS_TRUE@LoadPlugin dns
+@BUILD_PLUGIN_EMAIL_TRUE@LoadPlugin email
+@BUILD_PLUGIN_ENTROPY_TRUE@LoadPlugin entropy
+@BUILD_PLUGIN_EXEC_TRUE@LoadPlugin exec
+@BUILD_PLUGIN_HDDTEMP_TRUE@LoadPlugin hddtemp
+@BUILD_PLUGIN_INTERFACE_TRUE@LoadPlugin interface
+@BUILD_PLUGIN_IPTABLES_TRUE@LoadPlugin iptables
+@BUILD_PLUGIN_IRQ_TRUE@LoadPlugin irq
+@BUILD_PLUGIN_LOAD_TRUE@LoadPlugin load
+@BUILD_PLUGIN_LOGFILE_TRUE@LoadPlugin logfile
+@BUILD_PLUGIN_MBMON_TRUE@LoadPlugin mbmon
+@BUILD_PLUGIN_MEMORY_TRUE@LoadPlugin memory
+@BUILD_PLUGIN_MULTIMETER_TRUE@LoadPlugin multimeter
+@BUILD_PLUGIN_MYSQL_TRUE@LoadPlugin mysql
+@BUILD_PLUGIN_NETLINK_TRUE@LoadPlugin netlink
+@BUILD_PLUGIN_NETWORK_TRUE@LoadPlugin network
+@BUILD_PLUGIN_NFS_TRUE@LoadPlugin nfs
+@BUILD_PLUGIN_NTPD_TRUE@LoadPlugin ntpd
+@BUILD_PLUGIN_NUT_TRUE@LoadPlugin nut
+@BUILD_PLUGIN_PERL_TRUE@LoadPlugin perl
+@BUILD_PLUGIN_PING_TRUE@LoadPlugin ping
+@BUILD_PLUGIN_PROCESSES_TRUE@LoadPlugin processes
+@BUILD_PLUGIN_RRDTOOL_TRUE@LoadPlugin rrdtool
+@BUILD_PLUGIN_SENSORS_TRUE@LoadPlugin sensors
+@BUILD_PLUGIN_SERIAL_TRUE@LoadPlugin serial
+@BUILD_PLUGIN_SNMP_TRUE@LoadPlugin snmp
+@BUILD_PLUGIN_SWAP_TRUE@LoadPlugin swap
+@BUILD_PLUGIN_SYSLOG_TRUE@LoadPlugin syslog
+@BUILD_PLUGIN_TAPE_TRUE@LoadPlugin tape
+@BUILD_PLUGIN_UNIXSOCK_TRUE@LoadPlugin unixsock
+@BUILD_PLUGIN_USERS_TRUE@LoadPlugin users
+@BUILD_PLUGIN_VSERVER_TRUE@LoadPlugin vserver
+@BUILD_PLUGIN_WIRELESS_TRUE@LoadPlugin wireless
+@BUILD_PLUGIN_XMMS_TRUE@LoadPlugin xmms
#<Plugin apache>
# URL "http://localhost/status?auto"
# Database "db_name"
#</Plugin>
+#<Plugin netlink>
+# Interface "All"
+# VerboseInterface "All"
+# QDisc "eth0" "pfifo_fast-1:0"
+# Class "ppp0" "htb-1:10"
+# Filter "ppp0" "u32-1:0"
+#</Plugin>
+
#<Plugin network>
# Server "ff18::efc0:4a42" "25826"
# Server "239.192.74.66" "25826"
# IgnoreSelected false
#</Plugin>
+#<Plugin snmp>
+# <Data "powerplus_voltge_input">
+# Type "voltage"
+# Table false
+# Instance "input_line1"
+# Values "SNMPv2-SMI::enterprises.6050.5.4.1.1.2.1"
+# </Data>
+# <Data "hr_users">
+# Type "users"
+# Table false
+# Instance ""
+# Values "HOST-RESOURCES-MIB::hrSystemNumUsers.0"
+# </Data>
+# <Data "std_traffic">
+# Type "if_octets"
+# Table true
+# Instance "IF-MIB::ifDescr"
+# Values "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets"
+# </Data>
+#
+# <Host "some.switch.mydomain.org">
+# Address "192.168.0.2"
+# Version 1
+# Community "community_string"
+# Collect "std_traffic"
+# Inverval 120
+# </Host>
+# <Host "some.server.mydomain.org">
+# Address "192.168.0.42"
+# Version 2
+# Community "another_string"
+# Collect "std_traffic" "hr_users"
+# </Host>
+# <Host "some.ups.mydomain.org">
+# Address "192.168.0.3"
+# Version 1
+# Community "more_communities"
+# Collect "powerplus_voltge_input"
+# Interval 300
+# </Host>
+#</Plugin>
+
#<Plugin syslog>
# LogLevel info
#</Plugin>
=item B<PIDFile> I<File>
Sets where to write the PID file to. This file is overwritten when it exists
-and deleted when the program ist stopped. Some init-scripts might override this
-setting using the B<-P> commandline option.
+and deleted when the program is stopped. Some init-scripts might override this
+setting using the B<-P> command-line option.
=item B<PluginDir> I<Directory>
=head1 PLUGIN OPTIONS
-Some Plugins may register own options. These options must be enclosed in a
+Some plugins may register own options. These options must be enclosed in a
C<Plugin>-Section. Which options exist depends on the plugin used. Some plugins
require external configuration, too. The C<apache plugin>, for example,
required C<mod_status> to be configured in the webserver you're going to
=over 4
+=item B<SocketFile> I<Path>
+
+Sets the socket-file which is to be created.
+
=item B<SocketGroup> I<Group>
If running as root change the group of the UNIX-socket after it has been
=over 4
-=item B<Exec> I<User> I<Executable>
+=item B<Exec> I<User>[:[I<Group>]] I<Executable>
-Execute the executable I<Executable> as user I<User>.
+Execute the executable I<Executable> as user I<User>. If the user name is
+followed by a colon and a group name, the program is executed as the specified
+group. If only the colon follows the user name the group defaults to the
+user's login group.
=back
=back
+=head2 Plugin C<netlink>
+
+The C<netlink> plugin uses a netlink socket to query the Linux kernel about
+statistics of various interface and routing aspects.
+
+=over 4
+
+=item B<Interface> I<Interface>
+
+=item B<VerboseInterface> I<Interface>
+
+Instruct the plugin to collect interface statistics. This is basically the same
+as the statistics provided by the C<interface> plugin (see above) but
+potentially much more detailed.
+
+When configuring with B<Interface> only the basic statistics will be collected,
+namely octets, packets, and errors. These statistics are collected by
+the C<interface> plugin, too, so using both at the same time is no benefit.
+
+When configured with B<VerboseInterface> all counters B<except> the basic ones,
+so that no data needs to be collected twice if you use the C<interface> plugin.
+This includes dropped packets, received multicast packets, collisions and a
+whole zoo of differentiated RX and TX errors. You can try the following command
+to get an idea of what awaits you:
+
+ ip -s -s link list
+
+If I<Interface> is B<All>, all interfaces will be selected.
+
+=item B<QDisc> I<Interface> [I<QDisc>]
+
+=item B<Class> I<Interface> [I<Class>]
+
+=item B<Filter> I<Interface> [I<Filter>]
+
+Collect the octets and packets that pass a certain qdisc, class or filter.
+
+QDiscs and classes are identified by their type and handle (or classid).
+Filters don't necessarily have a handle, therefore the parent's handle is used.
+The notation used in collectd differs from that used in tc(1) in that it
+doesn't skip the major or minor number if it's zero and doesn't print special
+ids by their name. So, for example, a qdisc may be identified by
+C<pfifo_fast-1:0> even though the minor number of B<all> qdiscs is zero and
+thus not displayed by tc(1).
+
+If B<QDisc>, B<Class>, or B<Filter> is given without the second argument,
+i.E<nbsp>.e. without an identifier, all qdiscs, classes, or filters that are
+associated with that interface will be collected.
+
+Since a filter itself doesn't necessarily have a handle, the parent's handle is
+used. This may lead to problems when more than one filter is attached to a
+qdisc or class. This isn't nice, but we don't know how this could be done any
+better. If you have a idea, please don't hesitate to tell us.
+
+As with the B<Interface> option you can specify B<All> as the interface,
+meaning all interfaces.
+
+Here are some examples to help you understand the above text more easily:
+
+ <Plugin netlink>
+ VerboseInterface "All"
+ QDisc "eth0" "pfifo_fast-1:0"
+ QDisc "ppp0"
+ Class "ppp0" "htb-1:10"
+ Filter "ppp0" "u32-1:0"
+ </Plugin>
+
+=item B<IgnoreSelected>
+
+The behaviour is the same as with all other similar plugins: If nothing is
+selected at all, everything is collected. If some things are selected using the
+options described above, only these statistics are collected. If you set
+B<IgnoreSelected> to B<true>, this behavior is inversed, i.E<nbsp>e. the
+specified statistics will not be collected.
+
+=back
+
=head2 Plugin C<network>
=over 4
=head2 Plugin C<rrdtool>
You can use the settings B<StepSize>, B<HeartBeat>, B<RRARows>, and B<XFF> to
-finetune your RRD-files. Please read L<rrdcreate(1)> if you encounter problems
+fine-tune your RRD-files. Please read L<rrdcreate(1)> if you encounter problems
using these settings. If you don't want to dive into the depths of RRDTool, you
can safely ignore these settings.
If this option is set to a value greater than zero, the C<rrdtool plugin> will
save values in a cache, as described above. Writing multiple values at once
reduces IO-operations and thus lessens the load produced by updating the files.
-The tradeoff is that the graphs kind of "drag behind" and that more memory is
+The trade off is that the graphs kind of "drag behind" and that more memory is
used.
=back
=back
+=head2 Plugin C<snmp>
+
+Since the configuration of the C<snmp plugin> is a little more complicated than
+other plugins, its documentation has been moved to an own manpage,
+L<collectd-snmp(5)>. Please see there for details.
+
=head2 Plugin C<syslog>
=over 4
#define CONFIGFILE SYSCONFDIR"/collectd.conf"
#endif
+#ifndef LOCALSTATEDIR
+#define LOCALSTATEDIR PREFIX "/var"
+#endif
+
#ifndef PKGLOCALSTATEDIR
#define PKGLOCALSTATEDIR PREFIX "/var/lib/" PACKAGE_NAME
#endif
Please note that some plugins, that provide other means of communicating with
the daemon, have manpages of their own to describe their functionality in more
detail. In particular those are L<collectd-email(5)>, L<collectd-exec(5)>,
-L<collectd-perl(5)>, and L<collectd-unixsock(5)>
+L<collectd-perl(5)>, L<collectd-snmp(5)>, and L<collectd-unixsock(5)>
=head1 SEE ALSO
L<collectd-email(5)>,
L<collectd-exec(5)>,
L<collectd-perl(5)>,
+L<collectd-snmp(5)>,
L<collectd-unixsock(5)>,
L<http://collectd.org/>
struct cf_callback *next;
} cf_callback_t;
+typedef struct cf_complex_callback_s
+{
+ char *type;
+ int (*callback) (oconfig_item_t *);
+ struct cf_complex_callback_s *next;
+} cf_complex_callback_t;
+
typedef struct cf_value_map_s
{
char *key;
* Private variables
*/
static cf_callback_t *first_callback = NULL;
+static cf_complex_callback_t *complex_callback_head = NULL;
static cf_value_map_t cf_value_map[] =
{
int i;
char *name;
+ cf_complex_callback_t *cb;
+
if (strcasecmp (ci->key, "Plugin") != 0)
return (-1);
- if (ci->values_num != 1)
+ if (ci->values_num < 1)
return (-1);
if (ci->values[0].type != OCONFIG_TYPE_STRING)
return (-1);
name = ci->values[0].value.string;
+ /* Check for a complex callback first */
+ for (cb = complex_callback_head; cb != NULL; cb = cb->next)
+ if (strcasecmp (name, cb->type) == 0)
+ return (cb->callback (ci));
+
+ /* Hm, no complex plugin found. Dispatch the values one by one */
for (i = 0; i < ci->children_num; i++)
{
if (ci->children[i].children == NULL)
dispatch_value_plugin (name, ci->children + i);
else
- {DEBUG ("No nested config blocks allow for plugins. Yet.");}
+ {DEBUG ("No nested config blocks allow for this plugin.");}
}
return (0);
}
} /* void cf_unregister */
+void cf_unregister_complex (const char *type)
+{
+ cf_complex_callback_t *this, *prev;
+
+ for (prev = NULL, this = complex_callback_head;
+ this != NULL;
+ prev = this, this = this->next)
+ if (strcasecmp (this->type, type) == 0)
+ {
+ if (prev == NULL)
+ complex_callback_head = this->next;
+ else
+ prev->next = this->next;
+
+ sfree (this->type);
+ sfree (this);
+ break;
+ }
+} /* void cf_unregister */
+
void cf_register (const char *type,
int (*callback) (const char *, const char *),
const char **keys, int keys_num)
first_callback = cf_cb;
} /* void cf_register */
+int cf_register_complex (const char *type, int (*callback) (oconfig_item_t *))
+{
+ cf_complex_callback_t *new;
+
+ new = (cf_complex_callback_t *) malloc (sizeof (cf_complex_callback_t));
+ if (new == NULL)
+ return (-1);
+
+ new->type = strdup (type);
+ if (new->type == NULL)
+ {
+ sfree (new);
+ return (-1);
+ }
+
+ new->callback = callback;
+ new->next = NULL;
+
+ if (complex_callback_head == NULL)
+ {
+ complex_callback_head = new;
+ }
+ else
+ {
+ cf_complex_callback_t *last = complex_callback_head;
+ while (last->next != NULL)
+ last = last->next;
+ last->next = new;
+ }
+
+ return (0);
+} /* int cf_register_complex */
+
int cf_read (char *filename)
{
oconfig_item_t *conf;
+#ifndef CONFIGFILE_H
+#define CONFIGFILE_H
/**
* collectd - src/configfile.h
* Copyright (C) 2005,2006 Florian octo Forster
* Florian octo Forster <octo at verplant.org>
**/
-#ifndef CONFIGFILE_H
-#define CONFIGFILE_H
+#include "collectd.h"
+#include "liboconfig/oconfig.h"
/*
* DESCRIPTION
* `plugin_register'
*/
void cf_unregister (const char *type);
+void cf_unregister_complex (const char *type);
/*
* DESCRIPTION
int (*callback) (const char *, const char *),
const char **keys, int keys_num);
+int cf_register_complex (const char *type, int (*callback) (oconfig_item_t *));
+
/*
* DESCRIPTION
* `cf_read' reads the config file `filename' and dispatches the read
# endif
#endif /* HAVE_SYSCTLBYNAME */
-#if defined(PROCESSOR_CPU_LOAD_INFO) || defined(KERNEL_LINUX) || defined(HAVE_LIBKSTAT) || defined(HAVE_SYSCTLBYNAME)
-# define CPU_HAVE_READ 1
-#else
-# define CPU_HAVE_READ 0
+#if !PROCESSOR_CPU_LOAD_INFO && !KERNEL_LINUX && !HAVE_LIBKSTAT && !HAVE_SYSCTLBYNAME
+# error "No applicable input method."
#endif
-#if CPU_HAVE_READ
#ifdef PROCESSOR_CPU_LOAD_INFO
static mach_port_t port_host;
static processor_port_array_t cpu_list;
return (0);
}
-#endif /* CPU_HAVE_READ */
void module_register (void)
{
-#if CPU_HAVE_READ
plugin_register_init ("cpu", init);
plugin_register_read ("cpu", cpu_read);
-#endif /* CPU_HAVE_READ */
} /* void module_register */
#define MODULE_NAME "cpufreq"
-#if defined(KERNEL_LINUX)
-# define CPUFREQ_HAVE_READ 1
-#else
-# define CPUFREQ_HAVE_READ 0
-#endif
-
-#if CPUFREQ_HAVE_READ
-#ifdef KERNEL_LINUX
static int num_cpu = 0;
-#endif
static int cpufreq_init (void)
{
-#ifdef KERNEL_LINUX
int status;
char filename[256];
if (num_cpu == 0)
plugin_unregister_read ("cpufreq");
-#endif /* defined(KERNEL_LINUX) */
return (0);
} /* int cpufreq_init */
static int cpufreq_read (void)
{
-#ifdef KERNEL_LINUX
int status;
unsigned long long val;
int i = 0;
cpufreq_submit (i, val);
}
-#endif /* defined(KERNEL_LINUX) */
return (0);
} /* int cpufreq_read */
-#endif /* CPUFREQ_HAVE_READ */
-#undef BUFSIZE
void module_register (void)
{
-#if CPUFREQ_HAVE_READ
plugin_register_init ("cpufreq", cpufreq_init);
plugin_register_read ("cpufreq", cpufreq_read);
-#endif /* CPUFREQ_HAVE_READ */
}
#include "utils_mount.h"
#include "utils_ignorelist.h"
-#if HAVE_STATFS || HAVE_STATVFS
-# define DF_HAVE_READ 1
-#else
-# define DF_HAVE_READ 0
-#endif
-
#if HAVE_STATVFS
# if HAVE_SYS_STATVFS_H
# include <sys/statvfs.h>
# endif
# define STATANYFS statfs
# define BLOCKSIZE(s) (s).f_bsize
+#else
+# error "No applicable input method."
#endif
-#if DF_HAVE_READ
static const char *config_keys[] =
{
"Device",
return (0);
} /* int df_read */
-#endif /* DF_HAVE_READ */
void module_register (void)
{
-#if DF_HAVE_READ
plugin_register_config ("df", df_config,
config_keys, config_keys_num);
plugin_register_init ("df", df_init);
plugin_register_read ("df", df_read);
-#endif
} /* void module_register */
# define UINT_MAX 4294967295U
#endif
-#if HAVE_IOKIT_IOKITLIB_H || KERNEL_LINUX || HAVE_LIBKSTAT
-# define DISK_HAVE_READ 1
-#else
-# define DISK_HAVE_READ 0
-#endif
-
-#if DISK_HAVE_READ
#if HAVE_IOKIT_IOKITLIB_H
static mach_port_t io_master_port = MACH_PORT_NULL;
/* #endif HAVE_IOKIT_IOKITLIB_H */
extern kstat_ctl_t *kc;
static kstat_t *ksp[MAX_NUMDISK];
static int numdisk = 0;
-#endif /* HAVE_LIBKSTAT */
+/* #endif HAVE_LIBKSTAT */
+
+#else
+# error "No applicable input method."
+#endif
static int disk_init (void)
{
return (0);
} /* int disk_read */
-#endif /* DISK_HAVE_READ */
void module_register (void)
{
-#if DISK_HAVE_READ
plugin_register_init ("disk", disk_init);
plugin_register_read ("disk", disk_read);
-#endif /* DISK_HAVE_READ */
} /* void module_register */
#include "plugin.h"
#include "configfile.h"
-#if HAVE_LIBPCAP && HAVE_LIBPTHREAD
-# include "utils_dns.h"
-# include <pthread.h>
-# include <pcap.h>
-# include <poll.h>
-# define DNS_HAVE_READ 1
-#else
-# define DNS_HAVE_READ 0
-#endif
+#include "utils_dns.h"
+#include <pthread.h>
+#include <pcap.h>
+#include <poll.h>
/*
* Private data types
*/
-#if DNS_HAVE_READ
struct counter_list_s
{
unsigned int key;
struct counter_list_s *next;
};
typedef struct counter_list_s counter_list_t;
-#endif
/*
* Private variables
*/
-#if DNS_HAVE_READ
static const char *config_keys[] =
{
"Interface",
static pthread_mutex_t qtype_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t opcode_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t rcode_mutex = PTHREAD_MUTEX_INITIALIZER;
-#endif /* DNS_HAVE_READ */
/*
* Private functions
*/
-#if DNS_HAVE_READ
static counter_list_t *counter_list_search (counter_list_t **list, unsigned int key)
{
counter_list_t *entry;
return (0);
} /* int dns_read */
-#endif
void module_register (void)
{
-#if DNS_HAVE_READ
plugin_register_config ("dns", dns_config, config_keys, config_keys_num);
plugin_register_init ("dns", dns_init);
plugin_register_read ("dns", dns_read);
-#endif
} /* void module_register */
/* 256 bytes ought to be enough for anybody ;-) */
#define BUFSIZE 256
-#ifndef COLLECTD_SOCKET_PREFIX
-# define COLLECTD_SOCKET_PREFIX "/tmp/.collectd-"
-#endif /* COLLECTD_SOCKET_PREFIX */
-
-#define SOCK_PATH COLLECTD_SOCKET_PREFIX"email"
+#define SOCK_PATH LOCALSTATEDIR"/run/"PACKAGE_NAME"-email"
#define MAX_CONNS 5
#define MAX_CONNS_LIMIT 16384
/* valid configuration file keys */
static const char *config_keys[] =
{
+ "SocketFile",
"SocketGroup",
"SocketPerms",
"MaxConns"
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
/* socket configuration */
+static char *sock_file = SOCK_PATH;
static char *sock_group = COLLECTD_GRP_NAME;
static int sock_perms = S_IRWXU | S_IRWXG;
static int max_conns = MAX_CONNS;
*/
static int email_config (const char *key, const char *value)
{
- if (0 == strcasecmp (key, "SocketGroup")) {
+ if (0 == strcasecmp (key, "SocketFile")) {
+ sock_file = sstrdup (value);
+ }
+ else if (0 == strcasecmp (key, "SocketGroup")) {
sock_group = sstrdup (value);
}
else if (0 == strcasecmp (key, "SocketPerms")) {
addr.sun_family = AF_UNIX;
- strncpy (addr.sun_path, SOCK_PATH, (size_t)(UNIX_PATH_MAX - 1));
+ strncpy (addr.sun_path, sock_file, (size_t)(UNIX_PATH_MAX - 1));
addr.sun_path[UNIX_PATH_MAX - 1] = '\0';
unlink (addr.sun_path);
}
else
{
- status = chown (SOCK_PATH, (uid_t) -1, grp->gr_gid);
+ status = chown (sock_file, (uid_t) -1, grp->gr_gid);
if (status != 0)
{
char errbuf[1024];
log_warn ("chown (%s, -1, %i) failed: %s",
- SOCK_PATH, (int) grp->gr_gid,
+ sock_file, (int) grp->gr_gid,
sstrerror (errno, errbuf, sizeof (errbuf)));
}
}
}
errno = 0;
- if (0 != chmod (SOCK_PATH, sock_perms)) {
+ if (0 != chmod (sock_file, sock_perms)) {
char errbuf[1024];
log_warn ("chmod() failed: %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
pthread_mutex_unlock (&conns_mutex);
- unlink (SOCK_PATH);
+ unlink (sock_file);
errno = 0;
return (0);
/**
* collectd - src/entropy.c
- * Copyright (C) 2005,2006 Florian octo Forster
+ * Copyright (C) 2007 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
#include "common.h"
#include "plugin.h"
-#if KERNEL_LINUX
-# define ENTROPY_HAVE_READ 1
-#else
-# define ENTROPY_HAVE_READ 0
+#if !KERNEL_LINUX
+# error "No applicable input method."
#endif
#define ENTROPY_FILE "/proc/sys/kernel/random/entropy_avail"
-#if ENTROPY_HAVE_READ
static void entropy_submit (double entropy)
{
value_t values[1];
static int entropy_read (void)
{
-#if KERNEL_LINUX
double entropy;
FILE *fh;
char buffer[64];
if (entropy > 0.0)
entropy_submit (entropy);
-#endif /* KERNEL_LINUX */
return (0);
}
-#endif /* ENTROPY_HAVE_READ */
void module_register (void)
{
-#if ENTROPY_HAVE_READ
plugin_register_read ("entropy", entropy_read);
-#endif
} /* void module_register */
#include "collectd.h"
#include "common.h"
#include "plugin.h"
+#include "utils_cmd_putval.h"
#include <sys/types.h>
#include <pwd.h>
+#include <grp.h>
#include <signal.h>
#include <pthread.h>
struct program_list_s
{
char *user;
+ char *group;
char *exec;
int pid;
program_list_t *next;
pl->next = pl_head;
pl_head = pl;
+
+ pl->group = strchr (pl->user, ':');
+ if (NULL != pl->group) {
+ *pl->group = '\0';
+ pl->group++;
+ }
}
else
{
{
int status;
int uid;
+ int gid;
char *arg0;
struct passwd *sp_ptr;
struct passwd sp;
- char pwnambuf[2048];
+ char nambuf[2048];
char errbuf[1024];
sp_ptr = NULL;
- status = getpwnam_r (pl->user, &sp, pwnambuf, sizeof (pwnambuf), &sp_ptr);
+ status = getpwnam_r (pl->user, &sp, nambuf, sizeof (nambuf), &sp_ptr);
if (status != 0)
{
ERROR ("exec plugin: getpwnam_r failed: %s",
exit (-1);
}
+ if (NULL != pl->group)
+ {
+ if ('\0' != *pl->group) {
+ struct group *gr_ptr = NULL;
+ struct group gr;
+
+ status = getgrnam_r (pl->group, &gr, nambuf, sizeof (nambuf), &gr_ptr);
+ if (0 != status)
+ {
+ ERROR ("exec plugin: getgrnam_r failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ exit (-1);
+ }
+ if (NULL == gr_ptr)
+ {
+ ERROR ("exec plugin: No such group: `%s'", pl->group);
+ exit (-1);
+ }
+
+ gid = gr.gr_gid;
+ }
+ else
+ {
+ gid = sp.pw_gid;
+ }
+
+ status = setgid (gid);
+ if (0 != status)
+ {
+ ERROR ("exec plugin: setgid failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ exit (-1);
+ }
+ }
+
arg0 = strrchr (pl->exec, '/');
if (arg0 != NULL)
arg0++;
static int parse_line (char *buffer)
{
- char *fields[4];
+ char *fields[256];
int fields_num;
- char *hostname;
- char *plugin;
- char *plugin_instance;
- char *type;
- char *type_instance;
-
- const data_set_t *ds;
- value_list_t vl = VALUE_LIST_INIT;
-
- int status;
-
- fields_num = strsplit (buffer, fields, 4);
- if (fields_num != 2)
- {
- WARNING ("exec plugin: Number of fields is not 2.");
- return (-1);
- }
-
- status = parse_identifier (fields[0], &hostname,
- &plugin, &plugin_instance,
- &type, &type_instance);
- if (status != 0)
- {
- WARNING ("exec plugin: Cannot parse `%s'", fields[0]);
- return (-1);
- }
-
- if ((strlen (hostname) >= sizeof (vl.host))
- || (strlen (plugin) >= sizeof (vl.plugin))
- || ((plugin_instance != NULL)
- && (strlen (plugin_instance) >= sizeof (vl.plugin_instance)))
- || ((type_instance != NULL)
- && (strlen (type_instance) >= sizeof (vl.type_instance))))
- {
- WARNING ("exec plugin: An identifier is too long.");
- return (-1);
- }
-
- strcpy (vl.host, hostname);
- strcpy (vl.plugin, plugin);
- if (plugin_instance != NULL)
- strcpy (vl.plugin_instance, plugin_instance);
- if (type_instance != NULL)
- strcpy (vl.type_instance, type_instance);
-
- ds = plugin_get_ds (type);
- if (ds == NULL)
- {
- WARNING ("exec plugin: No such type: `%s'", type);
- return (-1);
- }
-
- vl.values_len = ds->ds_num;
- vl.values = (value_t *) malloc (sizeof (value_t) * vl.values_len);
- if (vl.values == NULL)
- return (-1);
-
- /* Sets vl.values and vl.time */
- status = parse_values (fields[1], &vl, ds);
- if (status != 0)
- {
- WARNING ("exec plugin: Cannot parse `%s'", fields[1]);
- sfree (vl.values);
- return (-1);
- }
-
- plugin_dispatch_values (type, &vl);
+ fields[0] = "PUTVAL";
+ fields_num = strsplit (buffer, &fields[1], STATIC_ARRAY_SIZE(fields) - 1);
- sfree (vl.values);
-
+ handle_putval (stdout, fields, fields_num + 1);
return (0);
} /* int parse_line */
#include "plugin.h"
#include "configfile.h"
-#if HAVE_NETDB_H && HAVE_SYS_SOCKET_H && HAVE_NETINET_IN_H \
- && HAVE_NETINET_TCP_H && HAVE_LIBGEN_H
# include <netdb.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <netinet/tcp.h>
# include <libgen.h> /* for basename */
-# define HDDTEMP_HAVE_READ 1
-#else
-# define HDDTEMP_HAVE_READ 0
-#endif
#if HAVE_LINUX_MAJOR_H
# include <linux/major.h>
#define HDDTEMP_DEF_HOST "127.0.0.1"
#define HDDTEMP_DEF_PORT "7634"
-#if HDDTEMP_HAVE_READ
static const char *config_keys[] =
{
"Host",
return (0);
} /* int hddtemp_read */
-#endif /* HDDTEMP_HAVE_READ */
/* module_register
Register collectd plugin. */
void module_register (void)
{
-#if HDDTEMP_HAVE_READ
plugin_register_config ("hddtemp", hddtemp_config,
config_keys, config_keys_num);
plugin_register_init ("hddtemp", hddtemp_init);
plugin_register_read ("hddtemp", hddtemp_read);
-#endif /* HDDTEMP_HAVE_READ */
}
# endif /* !COLLECT_GETIFADDRS */
#endif /* KERNEL_LINUX */
-#if HAVE_GETIFADDRS || KERNEL_LINUX || HAVE_LIBKSTAT || HAVE_LIBSTATGRAB
-# define INTERFACE_HAVE_READ 1
-#else
-# define INTERFACE_HAVE_READ 0
+#if !HAVE_GETIFADDRS && !KERNEL_LINUX && !HAVE_LIBKSTAT && !HAVE_LIBSTATGRAB
+# error "No applicable input method."
#endif
/*
#if HAVE_LIBKSTAT
static int interface_init (void)
{
-#if HAVE_LIBKSTAT
kstat_t *ksp_chain;
unsigned long long val;
continue;
ksp[numif++] = ksp_chain;
}
-#endif /* HAVE_LIBKSTAT */
return (0);
} /* int interface_init */
return (1 - if_list_action);
} /* int check_ignore_if */
-#if INTERFACE_HAVE_READ
static void if_submit (const char *dev, const char *type,
unsigned long long rx,
unsigned long long tx)
return (0);
} /* int interface_read */
-#endif /* INTERFACE_HAVE_READ */
void module_register (void)
{
#if HAVE_LIBKSTAT
plugin_register_init ("interface", interface_init);
#endif
-#if INTERFACE_HAVE_READ
plugin_register_read ("interface", interface_read);
-#endif
} /* void module_register */
# include <libiptc/libiptc.h>
#endif
-#if HAVE_LIBIPTC_LIBIPTC_H
-# define IPTABLES_HAVE_READ 1
-#else
-# define IPTABLES_HAVE_READ 0
-#endif
-
-#define MODULE_NAME "iptables"
-#define BUFSIZE 512
-
/*
* (Module-)Global variables
*/
/*
- * Removed packet count for now, should have config option if you want to save
- * them Although other collectd models don't seem to care much for options
- * eitherway for what to log
- */
-#if IPTABLES_HAVE_READ
-/*
* Config format should be `Chain table chainname',
* e. g. `Chain mangle incoming'
*/
return (0);
} /* int iptables_config */
-#endif /* IPTABLES_HAVE_READ */
-#if IPTABLES_HAVE_READ
/* This needs to return `int' for IPT_MATCH_ITERATE to work. */
static int submit_match (const struct ipt_entry_match *match,
const struct ipt_entry *entry,
return (0);
} /* int iptables_shutdown */
-#endif /* IPTABLES_HAVE_READ */
void module_register (void)
{
-#if IPTABLES_HAVE_READ
plugin_register_config ("iptables", iptables_config,
config_keys, config_keys_num);
plugin_register_read ("iptables", iptables_read);
plugin_register_shutdown ("iptables", iptables_shutdown);
-#endif
} /* void module_register */
-#undef BUFSIZE
-#undef MODULE_NAME
-
/*
* vim:shiftwidth=4:softtabstop=4:tabstop=8
*/
#include "plugin.h"
#include "configfile.h"
-#if KERNEL_LINUX
-# define IRQ_HAVE_READ 1
-#else
-# define IRQ_HAVE_READ 0
+#if !KERNEL_LINUX
+# error "No applicable input method."
#endif
#define BUFSIZE 128
/*
* (Module-)Global variables
*/
-#if IRQ_HAVE_READ
static const char *config_keys[] =
{
"Irq",
static int irq_read (void)
{
-#if KERNEL_LINUX
-
#undef BUFSIZE
#define BUFSIZE 256
irq_submit (irq, irq_value);
}
fclose (fh);
-#endif /* KERNEL_LINUX */
return (0);
} /* int irq_read */
-#endif /* IRQ_HAVE_READ */
void module_register (void)
{
-#if IRQ_HAVE_READ
plugin_register_config ("irq", irq_config,
config_keys, config_keys_num);
plugin_register_read ("irq", irq_read);
-#endif /* IRQ_HAVE_READ */
} /* void module_register */
#undef BUFSIZE
/**
* collectd - src/load.c
- * Copyright (C) 2005,2006 Florian octo Forster
+ * Copyright (C) 2005-2007 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
#include "common.h"
#include "plugin.h"
-#if defined(HAVE_GETLOADAVG) || defined(KERNEL_LINUX) || defined(HAVE_LIBSTATGRAB)
-# define LOAD_HAVE_READ 1
-#else
-# define LOAD_HAVE_READ 0
-#endif
-
#ifdef HAVE_SYS_LOADAVG_H
#include <sys/loadavg.h>
#endif
#endif
#endif /* defined(HAVE_GETLOADAVG) */
-#if LOAD_HAVE_READ
static void load_submit (gauge_t snum, gauge_t mnum, gauge_t lnum)
{
value_t values[3];
lnum = ls->min15;
load_submit (snum, mnum, lnum);
-#endif /* HAVE_LIBSTATGRAB */
+/* #endif HAVE_LIBSTATGRAB */
+
+#else
+# error "No applicable input method."
+#endif
return (0);
}
-#endif /* LOAD_HAVE_READ */
void module_register (void)
{
-#if LOAD_HAVE_READ
plugin_register_read ("load", load_read);
-#endif
} /* void module_register */
#include "plugin.h"
#include "configfile.h"
-#if HAVE_NETDB_H && HAVE_SYS_SOCKET_H && HAVE_NETINET_IN_H && HAVE_NETINET_TCP_H
-# include <netdb.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <netinet/tcp.h>
-# define MBMON_HAVE_READ 1
-#else
-# define MBMON_HAVE_READ 0
-#endif
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
#define MBMON_DEF_HOST "127.0.0.1"
#define MBMON_DEF_PORT "411" /* the default for Debian */
};
static int config_keys_num = 2;
-#if MBMON_HAVE_READ
static char *mbmon_host = NULL;
static char *mbmon_port = NULL;
return (0);
} /* void mbmon_read */
-#endif /* MBMON_HAVE_READ */
/* module_register
Register collectd plugin. */
void module_register (void)
{
-#if MBMON_HAVE_READ
plugin_register_config ("mbmon", mbmon_config, config_keys, config_keys_num);
plugin_register_read ("mbmon", mbmon_read);
-#endif /* MBMON_HAVE_READ */
} /* void module_register */
# include <mach/vm_statistics.h>
#endif
-#if defined (HOST_VM_INFO) || HAVE_SYSCTLBYNAME || KERNEL_LINUX || HAVE_LIBKSTAT
-# define MEMORY_HAVE_READ 1
-#else
-# define MEMORY_HAVE_READ 0
-#endif
-
/* vm_statistics_data_t */
-#if defined(HOST_VM_INFO)
+#if HAVE_HOST_STATISTICS
static mach_port_t port_host;
static vm_size_t pagesize;
-/* #endif HOST_VM_INFO */
+/* #endif HAVE_HOST_STATISTICS */
#elif HAVE_SYSCTLBYNAME
/* no global variables */
#elif HAVE_LIBKSTAT
static int pagesize;
static kstat_t *ksp;
-#endif /* HAVE_LIBKSTAT */
+/* #endif HAVE_LIBKSTAT */
+
+#else
+# error "No applicable input method."
+#endif
-#if MEMORY_HAVE_READ
static int memory_init (void)
{
-#if defined(HOST_VM_INFO)
+#if HAVE_HOST_STATISTICS
port_host = mach_host_self ();
host_page_size (port_host, &pagesize);
-/* #endif HOST_VM_INFO */
+/* #endif HAVE_HOST_STATISTICS */
#elif HAVE_SYSCTLBYNAME
/* no init stuff */
static int memory_read (void)
{
-#if defined(HOST_VM_INFO)
+#if HAVE_HOST_STATISTICS
kern_return_t status;
vm_statistics_data_t vm_data;
mach_msg_type_number_t vm_data_len;
memory_submit ("active", active);
memory_submit ("inactive", inactive);
memory_submit ("free", free);
-/* #endif HOST_VM_INFO */
+/* #endif HAVE_HOST_STATISTICS */
#elif HAVE_SYSCTLBYNAME
/*
return (0);
}
-#endif /* MEMORY_HAVE_READ */
void module_register (void)
{
-#if MEMORY_HAVE_READ
plugin_register_init ("memory", memory_init);
plugin_register_read ("memory", memory_read);
-#endif /* MEMORY_HAVE_READ */
} /* void module_register */
# include <termios.h>
# include <sys/ioctl.h>
# include <math.h>
-# define MULTIMETER_HAVE_READ 1
#else
-# define MULTIMETER_HAVE_READ 0
-# error "multimeter cannot read!"
+# error "No applicable input method."
#endif
-#if MULTIMETER_HAVE_READ
static int fd = -1;
static int multimeter_timeval_sub (struct timeval *tv1, struct timeval *tv2,
}
return (0);
}
+
#define LINE_LENGTH 14
static int multimeter_read_value(double *value)
{
return (0);
}
-#endif /* MULTIMETER_HAVE_READ */
void module_register (void)
{
-#if MULTIMETER_HAVE_READ
plugin_register_init ("multimeter", multimeter_init);
plugin_register_read ("multimeter", multimeter_read);
plugin_register_shutdown ("multimeter", multimeter_shutdown);
-#endif /* MULTIMETER_HAVE_READ */
} /* void module_register */
#include <mysql/mysql.h>
#endif
-#if HAVE_LIBMYSQLCLIENT
-# define MYSQL_HAVE_READ 1
-#else
-# define MYSQL_HAVE_READ 0
-#endif
-
/* TODO: Understand `Select_*' and possibly do that stuff as well.. */
-#if MYSQL_HAVE_READ
static const char *config_keys[] =
{
"Host",
return (0);
} /* int mysql_read */
-#endif /* MYSQL_HAVE_READ */
void module_register (void)
{
-#if MYSQL_HAVE_READ
plugin_register_config ("mysql", config, config_keys, config_keys_num);
plugin_register_read ("mysql", mysql_read);
-#endif /* MYSQL_HAVE_READ */
} /* void module_register */
--- /dev/null
+/**
+ * collectd - src/netlink.c
+ * Copyright (C) 2007 Florian octo Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+
+#include <asm/types.h>
+#include <sys/socket.h>
+#include <iproute/libnetlink.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/gen_stats.h>
+
+#include <iproute/ll_map.h>
+
+typedef struct ir_ignorelist_s
+{
+ char *device;
+ char *type;
+ char *inst;
+ struct ir_ignorelist_s *next;
+} ir_ignorelist_t;
+
+static int ir_ignorelist_invert = 1;
+static ir_ignorelist_t *ir_ignorelist_head = NULL;
+
+static struct rtnl_handle rth;
+
+static char **iflist = NULL;
+static size_t iflist_len = 0;
+
+static const char *config_keys[] =
+{
+ "Interface",
+ "VerboseInterface",
+ "QDisc",
+ "Class",
+ "Filter",
+ "IgnoreSelected"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static int add_ignorelist (const char *dev, const char *type,
+ const char *inst)
+{
+ ir_ignorelist_t *entry;
+
+ entry = (ir_ignorelist_t *) malloc (sizeof (ir_ignorelist_t));
+ if (entry == NULL)
+ return (-1);
+
+ memset (entry, '\0', sizeof (ir_ignorelist_t));
+
+ if (strcasecmp (dev, "All") != 0)
+ {
+ entry->device = strdup (dev);
+ if (entry->device == NULL)
+ {
+ sfree (entry);
+ return (-1);
+ }
+ }
+
+ entry->type = strdup (type);
+ if (entry->type == NULL)
+ {
+ sfree (entry->device);
+ sfree (entry);
+ return (-1);
+ }
+
+ if (inst != NULL)
+ {
+ entry->inst = strdup (inst);
+ if (entry->inst == NULL)
+ {
+ sfree (entry->type);
+ sfree (entry->device);
+ sfree (entry);
+ return (-1);
+ }
+ }
+
+ entry->next = ir_ignorelist_head;
+ ir_ignorelist_head = entry;
+
+ return (0);
+} /* int add_ignorelist */
+
+/*
+ * Checks wether a data set should be ignored. Returns `true' is the value
+ * should be ignored, `false' otherwise.
+ */
+static int check_ignorelist (const char *dev,
+ const char *type, const char *type_instance)
+{
+ ir_ignorelist_t *i;
+
+ assert ((dev != NULL) && (type != NULL));
+
+ if (ir_ignorelist_head == NULL)
+ return (ir_ignorelist_invert ? 0 : 1);
+
+ for (i = ir_ignorelist_head; i != NULL; i = i->next)
+ {
+ /* i->device == NULL => match all devices */
+ if ((i->device != NULL)
+ && (strcasecmp (i->device, dev) != 0))
+ continue;
+
+ if (strcasecmp (i->type, type) != 0)
+ continue;
+
+ if ((i->inst != NULL) && (type_instance != NULL)
+ && (strcasecmp (i->inst, type_instance) != 0))
+ continue;
+
+ DEBUG ("netlink plugin: check_ignorelist: "
+ "(dev = %s; type = %s; inst = %s) matched "
+ "(dev = %s; type = %s; inst = %s)",
+ dev, type,
+ type_instance == NULL ? "(nil)" : type_instance,
+ i->device == NULL ? "(nil)" : i->device,
+ i->type,
+ i->inst == NULL ? "(nil)" : i->inst);
+
+ return (ir_ignorelist_invert ? 0 : 1);
+ } /* for i */
+
+ return (ir_ignorelist_invert);
+} /* int check_ignorelist */
+
+static void submit_one (const char *dev, const char *type,
+ const char *type_instance, counter_t value)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].counter = value;
+
+ vl.values = values;
+ vl.values_len = 1;
+ vl.time = time (NULL);
+ strcpy (vl.host, hostname_g);
+ strcpy (vl.plugin, "netlink");
+ strncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
+
+ if (type_instance != NULL)
+ strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+ plugin_dispatch_values (type, &vl);
+} /* void submit_one */
+
+static void submit_two (const char *dev, const char *type,
+ const char *type_instance,
+ counter_t rx, counter_t tx)
+{
+ value_t values[2];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].counter = rx;
+ values[1].counter = tx;
+
+ vl.values = values;
+ vl.values_len = 2;
+ vl.time = time (NULL);
+ strcpy (vl.host, hostname_g);
+ strcpy (vl.plugin, "netlink");
+ strncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
+
+ if (type_instance != NULL)
+ strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+ plugin_dispatch_values (type, &vl);
+} /* void submit_two */
+
+static int link_filter (const struct sockaddr_nl *sa, struct nlmsghdr *nmh,
+ void *args)
+{
+ struct ifinfomsg *msg;
+ int msg_len;
+ struct rtattr *attrs[IFLA_MAX + 1];
+ struct rtnl_link_stats *stats;
+
+ const char *dev;
+
+ if (nmh->nlmsg_type != RTM_NEWLINK)
+ {
+ ERROR ("netlink plugin: link_filter: Don't know how to handle type %i.",
+ nmh->nlmsg_type);
+ return (-1);
+ }
+
+ msg = NLMSG_DATA (nmh);
+
+ msg_len = nmh->nlmsg_len - sizeof (struct ifinfomsg);
+ if (msg_len < 0)
+ {
+ ERROR ("netlink plugin: link_filter: msg_len = %i < 0;", msg_len);
+ return (-1);
+ }
+
+ memset (attrs, '\0', sizeof (attrs));
+ if (parse_rtattr (attrs, IFLA_MAX, IFLA_RTA (msg), msg_len) != 0)
+ {
+ ERROR ("netlink plugin: link_filter: parse_rtattr failed.");
+ return (-1);
+ }
+
+ if (attrs[IFLA_STATS] == NULL)
+ return (-1);
+ stats = RTA_DATA (attrs[IFLA_STATS]);
+
+ if (attrs[IFLA_IFNAME] == NULL)
+ {
+ ERROR ("netlink plugin: link_filter: attrs[IFLA_IFNAME] == NULL");
+ return (-1);
+ }
+ dev = RTA_DATA (attrs[IFLA_IFNAME]);
+
+ /* Update the `iflist'. It's used to know which interfaces exist and query
+ * them later for qdiscs and classes. */
+ if (msg->ifi_index >= iflist_len)
+ {
+ char **temp;
+
+ temp = (char **) realloc (iflist, (msg->ifi_index + 1) * sizeof (char *));
+ if (temp == NULL)
+ {
+ ERROR ("netlink plugin: link_filter: realloc failed.");
+ return (-1);
+ }
+
+ memset (temp + iflist_len, '\0',
+ (msg->ifi_index + 1 - iflist_len) * sizeof (char *));
+ iflist = temp;
+ iflist_len = msg->ifi_index + 1;
+ }
+ if ((iflist[msg->ifi_index] == NULL)
+ || (strcmp (iflist[msg->ifi_index], dev) != 0))
+ {
+ sfree (iflist[msg->ifi_index]);
+ iflist[msg->ifi_index] = strdup (dev);
+ }
+
+ if (check_ignorelist (dev, "interface", NULL) == 0)
+ {
+ submit_two (dev, "if_octets", NULL, stats->rx_bytes, stats->tx_bytes);
+ submit_two (dev, "if_packets", NULL, stats->rx_packets, stats->tx_packets);
+ submit_two (dev, "if_errors", NULL, stats->rx_errors, stats->tx_errors);
+ }
+ else
+ {
+ DEBUG ("netlink plugin: Ignoring %s/interface.", dev);
+ }
+
+ if (check_ignorelist (dev, "if_detail", NULL) == 0)
+ {
+ submit_two (dev, "if_dropped", NULL, stats->rx_dropped, stats->tx_dropped);
+ submit_one (dev, "if_multicast", NULL, stats->multicast);
+ submit_one (dev, "if_collisions", NULL, stats->collisions);
+
+ submit_one (dev, "if_rx_errors", "length", stats->rx_length_errors);
+ submit_one (dev, "if_rx_errors", "over", stats->rx_over_errors);
+ submit_one (dev, "if_rx_errors", "crc", stats->rx_crc_errors);
+ submit_one (dev, "if_rx_errors", "frame", stats->rx_frame_errors);
+ submit_one (dev, "if_rx_errors", "fifo", stats->rx_fifo_errors);
+ submit_one (dev, "if_rx_errors", "missed", stats->rx_missed_errors);
+
+ submit_one (dev, "if_tx_errors", "aborted", stats->tx_aborted_errors);
+ submit_one (dev, "if_tx_errors", "carrier", stats->tx_carrier_errors);
+ submit_one (dev, "if_tx_errors", "fifo", stats->tx_fifo_errors);
+ submit_one (dev, "if_tx_errors", "heartbeat", stats->tx_heartbeat_errors);
+ submit_one (dev, "if_tx_errors", "window", stats->tx_window_errors);
+ }
+ else
+ {
+ DEBUG ("netlink plugin: Ignoring %s/if_detail.", dev);
+ }
+
+ return (0);
+} /* int link_filter */
+
+static int qos_filter (const struct sockaddr_nl *sa, struct nlmsghdr *nmh,
+ void *args)
+{
+ struct tcmsg *msg;
+ int msg_len;
+ struct rtattr *attrs[TCA_MAX + 1];
+
+ int wanted_ifindex = *((int *) args);
+
+ const char *dev;
+
+ /* char *type_instance; */
+ char *tc_type;
+ char tc_inst[DATA_MAX_NAME_LEN];
+
+ if (nmh->nlmsg_type == RTM_NEWQDISC)
+ tc_type = "qdisc";
+ else if (nmh->nlmsg_type == RTM_NEWTCLASS)
+ tc_type = "class";
+ else if (nmh->nlmsg_type == RTM_NEWTFILTER)
+ tc_type = "filter";
+ else
+ {
+ ERROR ("netlink plugin: qos_filter: Don't know how to handle type %i.",
+ nmh->nlmsg_type);
+ return (-1);
+ }
+
+ msg = NLMSG_DATA (nmh);
+
+ msg_len = nmh->nlmsg_len - sizeof (struct tcmsg);
+ if (msg_len < 0)
+ {
+ ERROR ("netlink plugin: qos_filter: msg_len = %i < 0;", msg_len);
+ return (-1);
+ }
+
+ if (msg->tcm_ifindex != wanted_ifindex)
+ {
+ DEBUG ("netlink plugin: qos_filter: Got %s for interface #%i, "
+ "but expected #%i.",
+ tc_type, msg->tcm_ifindex, wanted_ifindex);
+ return (0);
+ }
+
+ if (msg->tcm_ifindex >= iflist_len)
+ {
+ ERROR ("netlink plugin: qos_filter: msg->tcm_ifindex = %i "
+ ">= iflist_len = %i",
+ msg->tcm_ifindex, iflist_len);
+ return (-1);
+ }
+
+ dev = iflist[msg->tcm_ifindex];
+ if (dev == NULL)
+ {
+ ERROR ("netlink plugin: qos_filter: iflist[%i] == NULL",
+ msg->tcm_ifindex);
+ return (-1);
+ }
+
+ memset (attrs, '\0', sizeof (attrs));
+ if (parse_rtattr (attrs, TCA_MAX, TCA_RTA (msg), msg_len) != 0)
+ {
+ ERROR ("netlink plugin: qos_filter: parse_rtattr failed.");
+ return (-1);
+ }
+
+ if (attrs[TCA_KIND] == NULL)
+ {
+ ERROR ("netlink plugin: qos_filter: attrs[TCA_KIND] == NULL");
+ return (-1);
+ }
+
+ { /* The the ID */
+ uint32_t numberic_id;
+
+ numberic_id = msg->tcm_handle;
+ if (strcmp (tc_type, "filter") == 0)
+ numberic_id = msg->tcm_parent;
+
+ snprintf (tc_inst, sizeof (tc_inst), "%s-%x:%x",
+ (const char *) RTA_DATA (attrs[TCA_KIND]),
+ numberic_id >> 16,
+ numberic_id & 0x0000FFFF);
+ tc_inst[sizeof (tc_inst) - 1] = '\0';
+ }
+
+ DEBUG ("netlink plugin: qos_filter: got %s for %s (%i).",
+ tc_type, dev, msg->tcm_ifindex);
+
+ if (check_ignorelist (dev, tc_type, tc_inst))
+ return (0);
+
+ if (attrs[TCA_STATS2])
+ {
+ struct rtattr *attrs_stats[TCA_STATS_MAX + 1];
+
+ memset (attrs_stats, '\0', sizeof (attrs_stats));
+ parse_rtattr_nested (attrs_stats, TCA_STATS_MAX, attrs[TCA_STATS2]);
+
+ if (attrs_stats[TCA_STATS_BASIC])
+ {
+ struct gnet_stats_basic bs;
+ char type_instance[DATA_MAX_NAME_LEN];
+
+ snprintf (type_instance, sizeof (type_instance), "%s-%s",
+ tc_type, tc_inst);
+ type_instance[sizeof (type_instance) - 1] = '\0';
+
+ memset (&bs, '\0', sizeof (bs));
+ memcpy (&bs, RTA_DATA (attrs_stats[TCA_STATS_BASIC]),
+ MIN (RTA_PAYLOAD (attrs_stats[TCA_STATS_BASIC]), sizeof(bs)));
+
+ submit_one (dev, "ipt_bytes", type_instance, bs.bytes);
+ submit_one (dev, "ipt_packets", type_instance, bs.packets);
+ }
+ }
+
+ return (0);
+} /* int qos_filter */
+
+static int ir_config (const char *key, const char *value)
+{
+ char *new_val;
+ char *fields[8];
+ int fields_num;
+ int status = 1;
+
+ new_val = strdup (value);
+ if (new_val == NULL)
+ return (-1);
+
+ fields_num = strsplit (new_val, fields, STATIC_ARRAY_SIZE (fields));
+ if ((fields_num < 1) || (fields_num > 8))
+ {
+ sfree (new_val);
+ return (-1);
+ }
+
+ if ((strcasecmp (key, "Interface") == 0)
+ || (strcasecmp (key, "VerboseInterface") == 0))
+ {
+ if (fields_num != 1)
+ {
+ ERROR ("netlink plugin: Invalid number of fields for option "
+ "`%s'. Got %i, expected 1.", key, fields_num);
+ status = -1;
+ }
+ else
+ {
+ add_ignorelist (fields[0], "interface", NULL);
+ if (strcasecmp (key, "VerboseInterface") == 0)
+ add_ignorelist (fields[0], "if_detail", NULL);
+ status = 0;
+ }
+ }
+ else if ((strcasecmp (key, "QDisc") == 0)
+ || (strcasecmp (key, "Class") == 0)
+ || (strcasecmp (key, "Filter") == 0))
+ {
+ if ((fields_num < 1) || (fields_num > 2))
+ {
+ ERROR ("netlink plugin: Invalid number of fields for option "
+ "`%s'. Got %i, expected 1 or 2.", key, fields_num);
+ return (-1);
+ }
+ else
+ {
+ add_ignorelist (fields[0], key,
+ (fields_num == 2) ? fields[1] : NULL);
+ status = 0;
+ }
+ }
+ else if (strcasecmp (key, "IgnoreSelected") == 0)
+ {
+ if (fields_num != 1)
+ {
+ ERROR ("netlink plugin: Invalid number of fields for option "
+ "`IgnoreSelected'. Got %i, expected 1.", fields_num);
+ status = -1;
+ }
+ else
+ {
+ if ((strcasecmp (fields[0], "yes") == 0)
+ || (strcasecmp (fields[0], "true") == 0)
+ || (strcasecmp (fields[0], "on") == 0))
+ ir_ignorelist_invert = 0;
+ else
+ ir_ignorelist_invert = 1;
+ status = 0;
+ }
+ }
+
+ sfree (new_val);
+
+ return (status);
+} /* int ir_config */
+
+static int ir_init (void)
+{
+ memset (&rth, '\0', sizeof (rth));
+
+ if (rtnl_open (&rth, 0) != 0)
+ {
+ ERROR ("netlink plugin: ir_read: rtnl_open failed.");
+ return (-1);
+ }
+
+ if (ll_init_map (&rth) != 0)
+ {
+ ERROR ("netlink plugin: ir_read: ll_init_map failed.");
+ return (-1);
+ }
+
+ return (0);
+} /* int ir_init */
+
+static int ir_read (void)
+{
+ struct ifinfomsg im;
+ struct tcmsg tm;
+ int ifindex;
+
+ static const int type_id[] = { RTM_GETQDISC, RTM_GETTCLASS, RTM_GETTFILTER };
+ static const char *type_name[] = { "qdisc", "class", "filter" };
+
+ memset (&im, '\0', sizeof (im));
+ im.ifi_type = AF_UNSPEC;
+
+ if (rtnl_dump_request (&rth, RTM_GETLINK, &im, sizeof (im)) < 0)
+ {
+ ERROR ("netlink plugin: ir_read: rtnl_dump_request failed.");
+ return (-1);
+ }
+
+ if (rtnl_dump_filter (&rth, link_filter, /* arg1 = */ NULL,
+ NULL, NULL) != 0)
+ {
+ ERROR ("netlink plugin: ir_read: rtnl_dump_filter failed.");
+ return (-1);
+ }
+
+ /* `link_filter' will update `iflist' which is used here to iterate over all
+ * interfaces. */
+ for (ifindex = 0; ifindex < iflist_len; ifindex++)
+ {
+ int type_index;
+
+ if (iflist[ifindex] == NULL)
+ continue;
+
+ for (type_index = 0; type_index < STATIC_ARRAY_SIZE (type_id); type_index++)
+ {
+ if (check_ignorelist (iflist[ifindex], type_name[type_index], NULL))
+ {
+ DEBUG ("netlink plugin: ir_read: check_ignorelist (%s, %s, (nil)) "
+ "== TRUE", iflist[ifindex], type_name[type_index]);
+ continue;
+ }
+
+ DEBUG ("netlink plugin: ir_read: querying %s from %s (%i).",
+ type_name[type_index], iflist[ifindex], ifindex);
+
+ memset (&tm, '\0', sizeof (tm));
+ tm.tcm_family = AF_UNSPEC;
+ tm.tcm_ifindex = ifindex;
+
+ if (rtnl_dump_request (&rth, type_id[type_index], &tm, sizeof (tm)) < 0)
+ {
+ ERROR ("netlink plugin: ir_read: rtnl_dump_request failed.");
+ continue;
+ }
+
+ if (rtnl_dump_filter (&rth, qos_filter, (void *) &ifindex,
+ NULL, NULL) != 0)
+ {
+ ERROR ("netlink plugin: ir_read: rtnl_dump_filter failed.");
+ continue;
+ }
+ } /* for (type_index) */
+ } /* for (if_index) */
+
+ return (0);
+} /* int ir_read */
+
+static int ir_shutdown (void)
+{
+ if ((rth.fd != 0) || (rth.seq != 0) || (rth.dump != 0))
+ {
+ rtnl_close(&rth);
+ memset (&rth, '\0', sizeof (rth));
+ }
+
+ return (0);
+} /* int ir_shutdown */
+
+void module_register (void)
+{
+ plugin_register_config ("netlink", ir_config, config_keys, config_keys_num);
+ plugin_register_init ("netlink", ir_init);
+ plugin_register_read ("netlink", ir_read);
+ plugin_register_shutdown ("netlink", ir_shutdown);
+} /* void module_register */
+
+/*
+ * vim: set shiftwidth=2 softtabstop=2 tabstop=8 :
+ */
static char send_buffer[BUFF_SIZE];
static char *send_buffer_ptr;
static int send_buffer_fill;
-static value_list_t send_buffer_vl = VALUE_LIST_INIT;
+static value_list_t send_buffer_vl = VALUE_LIST_STATIC;
static char send_buffer_type[DATA_MAX_NAME_LEN];
static pthread_mutex_t send_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
if (status == 0)
vl.time = (time_t) tmp;
}
+ else if (ntohs (header->type) == TYPE_INTERVAL)
+ {
+ uint64_t tmp = 0;
+ status = parse_part_number (&buffer, &buffer_len, &tmp);
+ if (status == 0)
+ vl.interval = (int) tmp;
+ }
else if (ntohs (header->type) == TYPE_HOST)
{
status = parse_part_string (&buffer, &buffer_len,
(unsigned int) vl->time);
}
+ if (vl_def->interval != vl->interval)
+ {
+ if (write_part_number (&buffer, &buffer_size, TYPE_INTERVAL,
+ (uint64_t) vl->interval))
+ return (-1);
+ vl_def->interval = vl->interval;
+ DEBUG ("network plugin: add_to_buffer: interval = %i",
+ (int) vl->interval);
+ }
+
if (strcmp (vl_def->plugin, vl->plugin) != 0)
{
if (write_part_string (&buffer, &buffer_size, TYPE_PLUGIN,
#define TYPE_TYPE 0x0004
#define TYPE_TYPE_INSTANCE 0x0005
#define TYPE_VALUES 0x0006
+#define TYPE_INTERVAL 0x0007
#endif /* NETWORK_H */
#include "common.h"
#include "plugin.h"
-/* #if defined(KERNEL_LINUX) || defined(HAVE_LIBKSTAT) */
-#if KERNEL_LINUX
-# define NFS_HAVE_READ 1
-#else
-# define NFS_HAVE_READ 0
+#if !KERNEL_LINUX
+# error "No applicable input method."
#endif
/*
21 commit
*/
-#if NFS_HAVE_READ
static const char *nfs2_procedures_names[] =
{
"null",
}
} /* void nfs_procedures_submit */
-#if KERNEL_LINUX
static void nfs_read_stats_file (FILE *fh, char *inst)
{
char buffer[BUFSIZE];
}
} /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
} /* void nfs_read_stats_file */
-#endif /* defined(KERNEL_LINUX) */
#undef BUFSIZE
#if HAVE_LIBKSTAT && 0
static int nfs_read (void)
{
-#if KERNEL_LINUX
FILE *fh;
if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
fclose (fh);
}
-/* #endif defined(KERNEL_LINUX) */
-
-#elif HAVE_LIBKSTAT && 0
+#if HAVE_LIBKSTAT && 0
if (nfs2_ksp_client != NULL)
nfs2_read_kstat (nfs2_ksp_client, "client");
if (nfs2_ksp_server != NULL)
return (0);
}
-#endif /* NFS_HAVE_READ */
void module_register (void)
{
-#if NFS_HAVE_READ
plugin_register_read ("nfs", nfs_read);
-#endif
} /* void module_register */
#include "plugin.h"
#include "configfile.h"
-#if HAVE_SYS_SOCKET_H
-# define NTPD_HAVE_READ 1
-#else
-# define NTPD_HAVE_READ 0
-#endif
-
#if HAVE_STDINT_H
# include <stdint.h>
#endif
};
static int config_keys_num = 2;
-#if NTPD_HAVE_READ
# define NTPD_DEFAULT_HOST "localhost"
# define NTPD_DEFAULT_PORT "123"
static int sock_descr = -1;
return (0);
} /* int ntpd_read */
-#endif /* NTPD_HAVE_READ */
void module_register (void)
{
-#if NTPD_HAVE_READ
plugin_register_config ("ntpd", ntpd_config,
config_keys, config_keys_num);
plugin_register_read ("ntpd", ntpd_read);
-#endif /* NTPD_HAVE_READ */
} /* void module_register */
#include "common.h"
#include "plugin.h"
-#if HAVE_PTHREAD_H
-# include <pthread.h>
-#endif
-
-#if HAVE_UPSCLIENT_H
-# include <upsclient.h>
-# define NUT_HAVE_READ 1
-#else
-# define NUT_HAVE_READ 0
-#endif
+#include <pthread.h>
+#include <upsclient.h>
#if HAVE_UPSCONN_T
typedef UPSCONN_t collectd_upsconn_t;
# error "Unable to determine the UPS connection type."
#endif
-
-#if NUT_HAVE_READ
struct nut_ups_s;
typedef struct nut_ups_s nut_ups_t;
struct nut_ups_s
return (0);
} /* int nut_shutdown */
-#endif /* NUT_HAVE_READ */
void module_register (void)
{
-#if NUT_HAVE_READ
plugin_register_config ("nut", nut_config, config_keys, config_keys_num);
plugin_register_read ("nut", nut_read);
plugin_register_shutdown ("nut", nut_shutdown);
-#endif
} /* void module_register */
/* vim: set sw=2 ts=8 sts=2 tw=78 : */
rf->wait_time = 86400;
NOTICE ("read-function of plugin `%s' "
- "failed. Will syspend it for %i "
+ "failed. Will suspend it for %i "
"seconds.", le->key, rf->wait_left);
}
else
return (0);
} /* int plugin_register_config */
+int plugin_register_complex_config (const char *type,
+ int (*callback) (oconfig_item_t *))
+{
+ return (cf_register_complex (type, callback));
+} /* int plugin_register_complex_config */
+
int plugin_register_init (const char *name,
int (*callback) (void))
{
return (0);
} /* int plugin_unregister_config */
+int plugin_unregister_complex_config (const char *name)
+{
+ cf_unregister_complex (name);
+ return (0);
+} /* int plugin_unregister_complex_config */
+
int plugin_unregister_init (const char *name)
{
return (plugin_unregister (list_init, name));
#ifndef PLUGIN_H
#define PLUGIN_H
-
/**
* collectd - src/plugin.h
- * Copyright (C) 2005,2006 Florian octo Forster
+ * Copyright (C) 2005-2007 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Florian octo Forster <octo at verplant.org>
**/
+#include "collectd.h"
+#include "configfile.h"
+
#define DATA_MAX_NAME_LEN 64
#define DS_TYPE_COUNTER 0
value_t *values;
int values_len;
time_t time;
+ int interval;
char host[DATA_MAX_NAME_LEN];
char plugin[DATA_MAX_NAME_LEN];
char plugin_instance[DATA_MAX_NAME_LEN];
};
typedef struct value_list_s value_list_t;
-#define VALUE_LIST_INIT { NULL, 0, 0, "localhost", "", "", "" }
+#define VALUE_LIST_INIT { NULL, 0, 0, interval_g, "localhost", "", "", "" }
+#define VALUE_LIST_STATIC { NULL, 0, 0, 0, "localhost", "", "", "" }
struct data_source_s
{
int plugin_register_config (const char *name,
int (*callback) (const char *key, const char *val),
const char **keys, int keys_num);
+int plugin_register_complex_config (const char *type,
+ int (*callback) (oconfig_item_t *));
int plugin_register_init (const char *name,
int (*callback) (void));
int plugin_register_read (const char *name,
void (*callback) (int, const char *));
int plugin_unregister_config (const char *name);
+int plugin_unregister_complex_config (const char *name);
int plugin_unregister_init (const char *name);
int plugin_unregister_read (const char *name);
int plugin_unregister_write (const char *name);
int plugin_unregister_data_set (const char *name);
int plugin_unregister_log (const char *name);
+
/*
* NAME
* plugin_dispatch_values
# ifndef CONFIG_HZ
# define CONFIG_HZ 100
# endif
-#endif /* KERNEL_LINUX */
-
-#define MODULE_NAME "processes"
+/* #endif KERNEL_LINUX */
-#if HAVE_THREAD_INFO || KERNEL_LINUX
-# define PROCESSES_HAVE_READ 1
#else
-# define PROCESSES_HAVE_READ 0
+# error "No applicable input method."
#endif
#define BUFSIZE 256
-#if PROCESSES_HAVE_READ
-#if HAVE_THREAD_INFO | KERNEL_LINUX
static const char *config_keys[] =
{
"Process",
NULL
};
static int config_keys_num = 1;
-#endif
typedef struct procstat_entry_s
{
struct procstat_entry_s *instances;
} procstat_t;
-#if HAVE_THREAD_INFO | KERNEL_LINUX
static procstat_t *list_head_g = NULL;
-#endif
#if HAVE_THREAD_INFO
static mach_port_t port_host_self;
static long pagesize_g;
#endif /* KERNEL_LINUX */
-#if HAVE_THREAD_INFO | KERNEL_LINUX
static void ps_list_register (const char *name)
{
procstat_t *new;
return (0);
}
-#endif /* HAVE_THREAD_INFO | KERNEL_LINUX */
static int ps_init (void)
{
return (0);
} /* int ps_read */
-#endif /* PROCESSES_HAVE_READ */
void module_register (void)
{
-#if PROCESSES_HAVE_READ
-#if HAVE_THREAD_INFO | KERNEL_LINUX
plugin_register_config ("processes", ps_config,
config_keys, config_keys_num);
-#endif
plugin_register_init ("processes", ps_init);
plugin_register_read ("processes", ps_read);
-#endif /* PROCESSES_HAVE_READ */
} /* void module_register */
char **values;
time_t first_value;
time_t last_value;
+ enum
+ {
+ FLAG_NONE = 0x00,
+ FLAG_QUEUED = 0x01
+ } flags;
};
typedef struct rrd_cache_s rrd_cache_t;
+struct rrd_queue_s
+{
+ char *filename;
+ struct rrd_queue_s *next;
+};
+typedef struct rrd_queue_s rrd_queue_t;
+
/*
* Private variables
*/
};
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+/* If datadir is zero, the daemon's basedir is used. If stepsize or heartbeat
+ * is zero a default, depending on the `interval' member of the value list is
+ * being used. */
static char *datadir = NULL;
static int stepsize = 0;
static int heartbeat = 0;
static int rrarows = 1200;
static double xff = 0.1;
+/* XXX: If you need to lock both, cache_lock and queue_lock, at the same time,
+ * ALWAYS lock `cache_lock' first! */
static int cache_timeout = 0;
static int cache_flush_timeout = 0;
static time_t cache_flush_last;
static avl_tree_t *cache = NULL;
static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
+static rrd_queue_t *queue_head = NULL;
+static rrd_queue_t *queue_tail = NULL;
+static pthread_t queue_thread = 0;
+static pthread_mutex_t queue_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t queue_cond = PTHREAD_COND_INITIALIZER;
+
+static int do_shutdown = 0;
+
/* * * * * * * * * *
* WARNING: Magic *
* * * * * * * * * */
-static int rra_get (char ***ret)
+
+static void rra_free (int rra_num, char **rra_def)
+{
+ int i;
+
+ for (i = 0; i < rra_num; i++)
+ {
+ sfree (rra_def[i]);
+ }
+ sfree (rra_def);
+} /* void rra_free */
+
+static int rra_get (char ***ret, const value_list_t *vl)
{
- static char **rra_def = NULL;
- static int rra_num = 0;
+ char **rra_def;
+ int rra_num;
int *rts;
int rts_num;
char buffer[64];
- if ((rra_num != 0) && (rra_def != NULL))
+ /* The stepsize we use here: If it is user-set, use it. If not, use the
+ * interval of the value-list. */
+ int ss;
+
+ if (rrarows <= 0)
+ {
+ *ret = NULL;
+ return (-1);
+ }
+
+ ss = (stepsize > 0) ? stepsize : vl->interval;
+ if (ss <= 0)
{
- *ret = rra_def;
- return (rra_num);
+ *ret = NULL;
+ return (-1);
}
/* Use the configured timespans or fall back to the built-in defaults */
if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
return (-1);
memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
-
- if ((stepsize <= 0) || (rrarows <= 0))
- {
- *ret = NULL;
- return (-1);
- }
+ rra_num = 0;
cdp_len = 0;
for (i = 0; i < rts_num; i++)
{
span = rts[i];
- if ((span / stepsize) < rrarows)
+ if ((span / ss) < rrarows)
continue;
if (cdp_len == 0)
cdp_len = 1;
else
cdp_len = (int) floor (((double) span)
- / ((double) (rrarows * stepsize)));
+ / ((double) (rrarows * ss)));
cdp_num = (int) ceil (((double) span)
- / ((double) (cdp_len * stepsize)));
+ / ((double) (cdp_len * ss)));
for (j = 0; j < rra_types_num; j++)
{
*ret = rra_def;
return (rra_num);
-}
+} /* int rra_get */
static void ds_free (int ds_num, char **ds_def)
{
free (ds_def);
}
-static int ds_get (char ***ret, const data_set_t *ds)
+static int ds_get (char ***ret, const data_set_t *ds, const value_list_t *vl)
{
char **ds_def;
int ds_num;
status = snprintf (buffer, sizeof (buffer),
"DS:%s:%s:%i:%s:%s",
- d->name, type, heartbeat,
+ d->name, type,
+ (heartbeat > 0) ? heartbeat : (2 * vl->interval),
min, max);
if ((status < 1) || (status >= sizeof (buffer)))
break;
return (ds_num);
}
-static int rrd_create_file (char *filename, const data_set_t *ds)
+static int rrd_create_file (char *filename, const data_set_t *ds, const value_list_t *vl)
{
char **argv;
int argc;
if (check_create_dir (filename))
return (-1);
- if ((rra_num = rra_get (&rra_def)) < 1)
+ if ((rra_num = rra_get (&rra_def, vl)) < 1)
{
ERROR ("rrd_create_file failed: Could not calculate RRAs");
return (-1);
}
- if ((ds_num = ds_get (&ds_def, ds)) < 1)
+ if ((ds_num = ds_get (&ds_def, ds, vl)) < 1)
{
ERROR ("rrd_create_file failed: Could not calculate DSes");
return (-1);
}
status = snprintf (stepsize_str, sizeof (stepsize_str),
- "%i", stepsize);
+ "%i", (stepsize > 0) ? stepsize : vl->interval);
if ((status < 1) || (status >= sizeof (stepsize_str)))
{
ERROR ("rrdtool plugin: snprintf failed.");
+ free (argv);
+ ds_free (ds_num, ds_def);
+ rra_free (rra_num, rra_def);
return (-1);
}
free (argv);
ds_free (ds_num, ds_def);
+ rra_free (rra_num, rra_def);
return (status);
}
return (0);
} /* int value_list_to_filename */
-static rrd_cache_t *rrd_cache_insert (const char *filename,
- const char *value, time_t value_time)
+static int rrd_write_to_file (char *filename, char **values, int values_num)
{
- rrd_cache_t *rc = NULL;
- int new_rc = 0;
+ char **argv;
+ int argc;
+ int status;
- if (cache != NULL)
- avl_get (cache, filename, (void *) &rc);
+ if (values_num < 1)
+ return (0);
- if (rc == NULL)
- {
- rc = (rrd_cache_t *) malloc (sizeof (rrd_cache_t));
- if (rc == NULL)
- return (NULL);
- rc->values_num = 0;
- rc->values = NULL;
- rc->first_value = 0;
- rc->last_value = 0;
- new_rc = 1;
- }
+ argc = values_num + 2;
+ argv = (char **) malloc ((argc + 1) * sizeof (char *));
+ if (argv == NULL)
+ return (-1);
- if (rc->last_value >= value_time)
+ argv[0] = "update";
+ argv[1] = filename;
+ memcpy (argv + 2, values, values_num * sizeof (char *));
+ argv[argc] = NULL;
+
+ DEBUG ("rrd_update (argc = %i, argv = %p)", argc, (void *) argv);
+
+ optind = 0; /* bug in librrd? */
+ rrd_clear_error ();
+ status = rrd_update (argc, argv);
+ if (status != 0)
{
- WARNING ("rrdtool plugin: (rc->last_value = %u) >= (value_time = %u)",
- (unsigned int) rc->last_value,
- (unsigned int) value_time);
- return (NULL);
+ WARNING ("rrd_update failed: %s: %s",
+ filename, rrd_get_error ());
+ status = -1;
}
- rc->values = (char **) realloc ((void *) rc->values,
- (rc->values_num + 1) * sizeof (char *));
- if (rc->values == NULL)
+ sfree (argv);
+
+ return (status);
+} /* int rrd_write_cache_entry */
+
+static void *rrd_queue_thread (void *data)
+{
+ while (42)
{
- char errbuf[1024];
- ERROR ("rrdtool plugin: realloc failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- if (cache != NULL)
+ rrd_queue_t *queue_entry;
+ rrd_cache_t *cache_entry;
+ char **values;
+ int values_num;
+ int i;
+
+ /* XXX: If you need to lock both, cache_lock and queue_lock, at
+ * the same time, ALWAYS lock `cache_lock' first! */
+
+ /* wait until an entry is available */
+ pthread_mutex_lock (&queue_lock);
+ while ((queue_head == NULL) && (do_shutdown == 0))
+ pthread_cond_wait (&queue_cond, &queue_lock);
+
+ /* We're in the shutdown phase */
+ if (queue_head == NULL)
{
- void *cache_key = NULL;
- avl_remove (cache, filename, &cache_key, NULL);
- sfree (cache_key);
+ pthread_mutex_unlock (&queue_lock);
+ break;
}
- free (rc);
- return (NULL);
- }
- rc->values[rc->values_num] = strdup (value);
- if (rc->values[rc->values_num] != NULL)
- rc->values_num++;
+ /* Dequeue the first entry */
+ queue_entry = queue_head;
+ if (queue_head == queue_tail)
+ queue_head = queue_tail = NULL;
+ else
+ queue_head = queue_head->next;
- if (rc->values_num == 1)
- rc->first_value = value_time;
- rc->last_value = value_time;
+ /* Unlock the queue again */
+ pthread_mutex_unlock (&queue_lock);
- /* Insert if this is the first value */
- if ((cache != NULL) && (new_rc == 1))
- {
- void *cache_key = strdup (filename);
+ /* We now need the cache lock so the entry isn't updated while
+ * we make a copy of it's values */
+ pthread_mutex_lock (&cache_lock);
- if (cache_key == NULL)
- {
- char errbuf[1024];
- ERROR ("rrdtool plugin: strdup failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- sfree (rc->values[0]);
- sfree (rc->values);
- sfree (rc);
- return (NULL);
- }
+ avl_get (cache, queue_entry->filename, (void *) &cache_entry);
- avl_insert (cache, cache_key, rc);
- }
+ values = cache_entry->values;
+ values_num = cache_entry->values_num;
- DEBUG ("rrd_cache_insert (%s, %s, %u) = %p", filename, value,
- (unsigned int) value_time, (void *) rc);
+ cache_entry->values = NULL;
+ cache_entry->values_num = 0;
+ cache_entry->flags = FLAG_NONE;
- return (rc);
-} /* rrd_cache_t *rrd_cache_insert */
+ pthread_mutex_unlock (&cache_lock);
-static int rrd_write_cache_entry (const char *filename, rrd_cache_t *rc)
-{
- char **argv;
- int argc;
+ /* Write the values to the RRD-file */
+ rrd_write_to_file (queue_entry->filename, values, values_num);
- char *fn;
- int status;
+ for (i = 0; i < values_num; i++)
+ {
+ sfree (values[i]);
+ }
+ sfree (values);
+ sfree (queue_entry->filename);
+ sfree (queue_entry);
+ } /* while (42) */
- int i;
+ pthread_mutex_lock (&cache_lock);
+ avl_destroy (cache);
+ cache = NULL;
+ pthread_mutex_unlock (&cache_lock);
- if (rc->values_num < 1)
- return (0);
+ pthread_exit ((void *) 0);
+ return ((void *) 0);
+} /* void *rrd_queue_thread */
- argc = rc->values_num + 2;
- argv = (char **) malloc ((argc + 1) * sizeof (char *));
- if (argv == NULL)
+static int rrd_queue_cache_entry (const char *filename)
+{
+ rrd_queue_t *queue_entry;
+
+ queue_entry = (rrd_queue_t *) malloc (sizeof (rrd_queue_t));
+ if (queue_entry == NULL)
return (-1);
- fn = strdup (filename);
- if (fn == NULL)
+ queue_entry->filename = strdup (filename);
+ if (queue_entry->filename == NULL)
{
- free (argv);
+ free (queue_entry);
return (-1);
}
- argv[0] = "update";
- argv[1] = fn;
- memcpy (argv + 2, rc->values, rc->values_num * sizeof (char *));
- argv[argc] = NULL;
-
- DEBUG ("rrd_update (argc = %i, argv = %p)", argc, (void *) argv);
+ queue_entry->next = NULL;
- optind = 0; /* bug in librrd? */
- rrd_clear_error ();
- status = rrd_update (argc, argv);
- if (status != 0)
- {
- WARNING ("rrd_update failed: %s: %s",
- filename, rrd_get_error ());
- status = -1;
- }
+ pthread_mutex_lock (&queue_lock);
+ if (queue_tail == NULL)
+ queue_head = queue_entry;
+ else
+ queue_tail->next = queue_entry;
+ queue_tail = queue_entry;
+ pthread_cond_signal (&queue_cond);
+ pthread_mutex_unlock (&queue_lock);
- free (argv);
- free (fn);
- /* Free the value list of `rc' */
- for (i = 0; i < rc->values_num; i++)
- free (rc->values[i]);
- free (rc->values);
- rc->values = NULL;
- rc->values_num = 0;
+ DEBUG ("rrdtool plugin: Put `%s' into the update queue", filename);
- return (status);
-} /* int rrd_write_cache_entry */
+ return (0);
+} /* int rrd_queue_cache_entry */
static void rrd_cache_flush (int timeout)
{
avl_iterator_t *iter;
int i;
- if (cache == NULL)
- return;
-
DEBUG ("Flushing cache, timeout = %i", timeout);
now = time (NULL);
while (avl_iterator_next (iter, (void *) &key, (void *) &rc) == 0)
{
DEBUG ("key = %s; age = %i;", key, now - rc->first_value);
- if ((now - rc->first_value) >= timeout)
+
+ if (rc->flags == FLAG_QUEUED)
+ continue;
+ else if ((now - rc->first_value) < timeout)
+ continue;
+ else if (rc->values_num > 0)
+ {
+ if (rrd_queue_cache_entry (key) == 0)
+ rc->flags = FLAG_QUEUED;
+ }
+ else /* ancient and no values -> waste of memory */
{
keys = (char **) realloc ((void *) keys,
(keys_num + 1) * sizeof (char *));
continue;
}
- rrd_write_cache_entry (keys[i], rc);
- /* rc's value-list is free's by `rrd_write_cache_entry' */
+ assert (rc->values == NULL);
+ assert (rc->values_num == 0);
+
sfree (rc);
sfree (key);
keys[i] = NULL;
cache_flush_last = now;
} /* void rrd_cache_flush */
+static int rrd_cache_insert (const char *filename,
+ const char *value, time_t value_time)
+{
+ rrd_cache_t *rc = NULL;
+ int new_rc = 0;
+ char **values_new;
+
+ pthread_mutex_lock (&cache_lock);
+
+ avl_get (cache, filename, (void *) &rc);
+
+ if (rc == NULL)
+ {
+ rc = (rrd_cache_t *) malloc (sizeof (rrd_cache_t));
+ if (rc == NULL)
+ return (-1);
+ rc->values_num = 0;
+ rc->values = NULL;
+ rc->first_value = 0;
+ rc->last_value = 0;
+ rc->flags = FLAG_NONE;
+ new_rc = 1;
+ }
+
+ if (rc->last_value >= value_time)
+ {
+ pthread_mutex_unlock (&cache_lock);
+ WARNING ("rrdtool plugin: (rc->last_value = %u) >= (value_time = %u)",
+ (unsigned int) rc->last_value,
+ (unsigned int) value_time);
+ return (-1);
+ }
+
+ values_new = (char **) realloc ((void *) rc->values,
+ (rc->values_num + 1) * sizeof (char *));
+ if (values_new == NULL)
+ {
+ char errbuf[1024];
+ void *cache_key = NULL;
+
+ sstrerror (errno, errbuf, sizeof (errbuf));
+
+ avl_remove (cache, filename, &cache_key, NULL);
+ pthread_mutex_unlock (&cache_lock);
+
+ ERROR ("rrdtool plugin: realloc failed: %s", errbuf);
+
+ sfree (cache_key);
+ sfree (rc->values);
+ sfree (rc);
+ return (-1);
+ }
+ rc->values = values_new;
+
+ rc->values[rc->values_num] = strdup (value);
+ if (rc->values[rc->values_num] != NULL)
+ rc->values_num++;
+
+ if (rc->values_num == 1)
+ rc->first_value = value_time;
+ rc->last_value = value_time;
+
+ /* Insert if this is the first value */
+ if (new_rc == 1)
+ {
+ void *cache_key = strdup (filename);
+
+ if (cache_key == NULL)
+ {
+ char errbuf[1024];
+ sstrerror (errno, errbuf, sizeof (errbuf));
+
+ pthread_mutex_unlock (&cache_lock);
+
+ ERROR ("rrdtool plugin: strdup failed: %s", errbuf);
+
+ sfree (rc->values[0]);
+ sfree (rc->values);
+ sfree (rc);
+ return (-1);
+ }
+
+ avl_insert (cache, cache_key, rc);
+ }
+
+ DEBUG ("rrd_cache_insert (%s, %s, %u) = %p", filename, value,
+ (unsigned int) value_time, (void *) rc);
+
+ if ((rc->last_value - rc->first_value) >= cache_timeout)
+ {
+ /* XXX: If you need to lock both, cache_lock and queue_lock, at
+ * the same time, ALWAYS lock `cache_lock' first! */
+ if (rc->flags != FLAG_QUEUED)
+ {
+ if (rrd_queue_cache_entry (filename) == 0)
+ rc->flags = FLAG_QUEUED;
+ }
+ else
+ {
+ DEBUG ("rrdtool plugin: `%s' is already queued.", filename);
+ }
+ }
+
+ if ((cache_timeout > 0) &&
+ ((time (NULL) - cache_flush_last) > cache_flush_timeout))
+ rrd_cache_flush (cache_flush_timeout);
+
+
+ pthread_mutex_unlock (&cache_lock);
+
+ return (0);
+} /* int rrd_cache_insert */
+
static int rrd_write (const data_set_t *ds, const value_list_t *vl)
{
struct stat statbuf;
char filename[512];
char values[512];
- rrd_cache_t *rc;
- time_t now;
+ int status;
if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
return (-1);
{
if (errno == ENOENT)
{
- if (rrd_create_file (filename, ds))
+ if (rrd_create_file (filename, ds, vl))
return (-1);
}
else
return (-1);
}
- pthread_mutex_lock (&cache_lock);
- rc = rrd_cache_insert (filename, values, vl->time);
- if (rc == NULL)
- {
- pthread_mutex_unlock (&cache_lock);
- return (-1);
- }
-
- if (cache == NULL)
- {
- rrd_write_cache_entry (filename, rc);
- /* rc's value-list is free's by `rrd_write_cache_entry' */
- sfree (rc);
- pthread_mutex_unlock (&cache_lock);
- return (0);
- }
-
- now = time (NULL);
-
- DEBUG ("age (%s) = %i", filename, now - rc->first_value);
+ status = rrd_cache_insert (filename, values, vl->time);
- /* `rc' is not free'd here, because we'll likely reuse it. If not, then
- * the next flush will remove this entry. */
- if ((now - rc->first_value) >= cache_timeout)
- rrd_write_cache_entry (filename, rc);
-
- if ((now - cache_flush_last) >= cache_flush_timeout)
- rrd_cache_flush (cache_flush_timeout);
-
- pthread_mutex_unlock (&cache_lock);
- return (0);
+ return (status);
} /* int rrd_write */
static int rrd_config (const char *key, const char *value)
}
else if (strcasecmp ("StepSize", key) == 0)
{
- int tmp = atoi (value);
- if (tmp <= 0)
- {
- fprintf (stderr, "rrdtool: `StepSize' must "
- "be greater than 0.\n");
- return (1);
- }
- stepsize = tmp;
+ stepsize = atoi (value);
+ if (stepsize < 0)
+ stepsize = 0;
}
else if (strcasecmp ("HeartBeat", key) == 0)
{
- int tmp = atoi (value);
- if (tmp <= 0)
- {
- fprintf (stderr, "rrdtool: `HeartBeat' must "
- "be greater than 0.\n");
- return (1);
- }
- heartbeat = tmp;
+ heartbeat = atoi (value);
+ if (heartbeat < 0)
+ heartbeat = 0;
}
else if (strcasecmp ("RRARows", key) == 0)
{
{
pthread_mutex_lock (&cache_lock);
rrd_cache_flush (-1);
- if (cache != NULL)
- avl_destroy (cache);
- cache = NULL;
pthread_mutex_unlock (&cache_lock);
+ pthread_mutex_lock (&queue_lock);
+ do_shutdown = 1;
+ pthread_cond_signal (&queue_cond);
+ pthread_mutex_unlock (&queue_lock);
+
return (0);
} /* int rrd_shutdown */
static int rrd_init (void)
{
- if (stepsize <= 0)
- stepsize = interval_g;
+ int status;
+
+ if (stepsize < 0)
+ stepsize = 0;
if (heartbeat <= 0)
- heartbeat = 2 * interval_g;
+ {
+ if (stepsize > 0)
+ heartbeat = 2 * stepsize;
+ else
+ heartbeat = 0;
+ }
- if (heartbeat < interval_g)
+ if ((heartbeat > 0) && (heartbeat < interval_g))
WARNING ("rrdtool plugin: Your `heartbeat' is "
"smaller than your `interval'. This will "
"likely cause problems.");
- else if (stepsize < interval_g)
+ else if ((stepsize > 0) && (stepsize < interval_g))
WARNING ("rrdtool plugin: Your `stepsize' is "
"smaller than your `interval'. This will "
"create needlessly big RRD-files.");
+ /* Set the cache up */
pthread_mutex_lock (&cache_lock);
+
+ cache = avl_create ((int (*) (const void *, const void *)) strcmp);
+ if (cache == NULL)
+ {
+ ERROR ("rrdtool plugin: avl_create failed.");
+ return (-1);
+ }
+
+ cache_flush_last = time (NULL);
if (cache_timeout < 2)
{
cache_timeout = 0;
cache_flush_timeout = 0;
}
- else
- {
- if (cache_flush_timeout < cache_timeout)
- cache_flush_timeout = 10 * cache_timeout;
+ else if (cache_flush_timeout < cache_timeout)
+ cache_flush_timeout = 10 * cache_timeout;
- cache = avl_create ((int (*) (const void *, const void *)) strcmp);
- cache_flush_last = time (NULL);
- plugin_register_shutdown ("rrdtool", rrd_shutdown);
- }
pthread_mutex_unlock (&cache_lock);
+ status = pthread_create (&queue_thread, NULL, rrd_queue_thread, NULL);
+ if (status != 0)
+ {
+ ERROR ("rrdtool plugin: Cannot create queue-thread.");
+ return (-1);
+ }
+
DEBUG ("rrdtool plugin: rrd_init: datadir = %s; stepsize = %i;"
" heartbeat = %i; rrarows = %i; xff = %lf;",
(datadir == NULL) ? "(null)" : datadir,
config_keys, config_keys_num);
plugin_register_init ("rrdtool", rrd_init);
plugin_register_write ("rrdtool", rrd_write);
+ plugin_register_shutdown ("rrdtool", rrd_shutdown);
}
#if defined(HAVE_SENSORS_SENSORS_H)
# include <sensors/sensors.h>
-#else
-# undef HAVE_LIBSENSORS
#endif
-#if defined(HAVE_LIBSENSORS)
-# define SENSORS_HAVE_READ 1
-#else
-# define SENSORS_HAVE_READ 0
-#endif
-
-#if SENSORS_HAVE_READ
#define SENSOR_TYPE_VOLTAGE 0
#define SENSOR_TYPE_FANSPEED 1
#define SENSOR_TYPE_TEMPERATURE 2
return (0);
} /* int sensors_read */
-#endif /* SENSORS_HAVE_READ */
void module_register (void)
{
-#if SENSORS_HAVE_READ
plugin_register_config ("sensors", sensors_config,
config_keys, config_keys_num);
plugin_register_read ("sensors", sensors_read);
plugin_register_shutdown ("sensors", sensors_shutdown);
-#endif
} /* void module_register */
#include "common.h"
#include "plugin.h"
-#if defined(KERNEL_LINUX)
-# define SERIAL_HAVE_READ 1
-#else
-# define SERIAL_HAVE_READ 0
+#if !KERNEL_LINUX
+# error "No applicable input method."
#endif
-#if SERIAL_HAVE_READ
static void serial_submit (const char *type_instance,
counter_t rx, counter_t tx)
{
static int serial_read (void)
{
-#ifdef KERNEL_LINUX
FILE *fh;
char buffer[1024];
fclose (fh);
return (0);
-#endif /* KERNEL_LINUX */
} /* int serial_read */
-#endif /* SERIAL_HAVE_READ */
void module_register (void)
{
-#if SERIAL_HAVE_READ
plugin_register_read ("serial", serial_read);
-#endif /* SERIAL_HAVE_READ */
} /* void module_register */
--- /dev/null
+/**
+ * collectd - src/snmp.c
+ * Copyright (C) 2007 Florian octo Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#include <pthread.h>
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+
+/*
+ * Private data structes
+ */
+struct oid_s
+{
+ oid oid[MAX_OID_LEN];
+ size_t oid_len;
+};
+typedef struct oid_s oid_t;
+
+union instance_u
+{
+ char string[DATA_MAX_NAME_LEN];
+ oid_t oid;
+};
+typedef union instance_u instance_t;
+
+struct data_definition_s
+{
+ char *name; /* used to reference this from the `Collect' option */
+ char *type; /* used to find the data_set */
+ int is_table;
+ instance_t instance;
+ oid_t *values;
+ int values_len;
+ struct data_definition_s *next;
+};
+typedef struct data_definition_s data_definition_t;
+
+struct host_definition_s
+{
+ char *name;
+ char *address;
+ char *community;
+ int version;
+ void *sess_handle;
+ int16_t skip_num;
+ int16_t skip_left;
+ data_definition_t **data_list;
+ int data_list_len;
+ enum /****************************************************/
+ { /* This host.. */
+ STATE_IDLE, /* - just sits there until `skip_left < interval_g' */
+ STATE_WAIT, /* - waits to be queried. */
+ STATE_BUSY /* - is currently being queried. */
+ } state; /****************************************************/
+ struct host_definition_s *next;
+};
+typedef struct host_definition_s host_definition_t;
+
+/* These two types are used to cache values in `csnmp_read_table' to handle
+ * gaps in tables. */
+struct csnmp_list_instances_s
+{
+ oid subid;
+ char instance[DATA_MAX_NAME_LEN];
+ struct csnmp_list_instances_s *next;
+};
+typedef struct csnmp_list_instances_s csnmp_list_instances_t;
+
+struct csnmp_table_values_s
+{
+ oid subid;
+ value_t value;
+ struct csnmp_table_values_s *next;
+};
+typedef struct csnmp_table_values_s csnmp_table_values_t;
+
+/*
+ * Private variables
+ */
+static int do_shutdown = 0;
+
+pthread_t *threads = NULL;
+int threads_num = 0;
+
+static data_definition_t *data_head = NULL;
+static host_definition_t *host_head = NULL;
+
+static pthread_mutex_t host_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t host_cond = PTHREAD_COND_INITIALIZER;
+
+/*
+ * Private functions
+ */
+/* First there are many functions which do configuration stuff. It's a big
+ * bloated and messy, I'm afraid. */
+
+/*
+ * Callgraph for the config stuff:
+ * csnmp_config
+ * +-> call_snmp_init_once
+ * +-> csnmp_config_add_data
+ * ! +-> csnmp_config_add_data_type
+ * ! +-> csnmp_config_add_data_table
+ * ! +-> csnmp_config_add_data_instance
+ * ! +-> csnmp_config_add_data_values
+ * +-> csnmp_config_add_host
+ * +-> csnmp_config_add_host_address
+ * +-> csnmp_config_add_host_community
+ * +-> csnmp_config_add_host_version
+ * +-> csnmp_config_add_host_collect
+ * +-> csnmp_config_add_host_interval
+ */
+static void call_snmp_init_once (void)
+{
+ static int have_init = 0;
+
+ if (have_init == 0)
+ init_snmp (PACKAGE_NAME);
+ have_init = 1;
+} /* void call_snmp_init_once */
+
+static int csnmp_config_add_data_type (data_definition_t *dd, oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("snmp plugin: `Type' needs exactly one string argument.");
+ return (-1);
+ }
+
+ if (dd->type != NULL)
+ free (dd->type);
+
+ dd->type = strdup (ci->values[0].value.string);
+ if (dd->type == NULL)
+ return (-1);
+
+ return (0);
+} /* int csnmp_config_add_data_type */
+
+static int csnmp_config_add_data_table (data_definition_t *dd, oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
+ {
+ WARNING ("snmp plugin: `Table' needs exactly one boolean argument.");
+ return (-1);
+ }
+
+ dd->is_table = ci->values[0].value.boolean ? 1 : 0;
+
+ return (0);
+} /* int csnmp_config_add_data_table */
+
+static int csnmp_config_add_data_instance (data_definition_t *dd, oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("snmp plugin: `Instance' needs exactly one string argument.");
+ return (-1);
+ }
+
+ if (dd->is_table)
+ {
+ /* Instance is an OID */
+ dd->instance.oid.oid_len = MAX_OID_LEN;
+
+ if (!read_objid (ci->values[0].value.string,
+ dd->instance.oid.oid, &dd->instance.oid.oid_len))
+ {
+ ERROR ("snmp plugin: read_objid (%s) failed.",
+ ci->values[0].value.string);
+ return (-1);
+ }
+ }
+ else
+ {
+ /* Instance is a simple string */
+ strncpy (dd->instance.string, ci->values[0].value.string, DATA_MAX_NAME_LEN - 1);
+ }
+
+ return (0);
+} /* int csnmp_config_add_data_instance */
+
+static int csnmp_config_add_data_values (data_definition_t *dd, oconfig_item_t *ci)
+{
+ int i;
+
+ if (ci->values_num < 1)
+ {
+ WARNING ("snmp plugin: `Values' needs at least one argument.");
+ return (-1);
+ }
+
+ for (i = 0; i < ci->values_num; i++)
+ if (ci->values[i].type != OCONFIG_TYPE_STRING)
+ {
+ WARNING ("snmp plugin: `Values' needs only string argument.");
+ return (-1);
+ }
+
+ if (dd->values != NULL)
+ free (dd->values);
+ dd->values = (oid_t *) malloc (sizeof (oid_t) * ci->values_num);
+ if (dd->values == NULL)
+ return (-1);
+ dd->values_len = ci->values_num;
+
+ for (i = 0; i < ci->values_num; i++)
+ {
+ dd->values[i].oid_len = MAX_OID_LEN;
+
+ if (NULL == snmp_parse_oid (ci->values[i].value.string,
+ dd->values[i].oid, &dd->values[i].oid_len))
+ {
+ ERROR ("snmp plugin: snmp_parse_oid (%s) failed.",
+ ci->values[i].value.string);
+ free (dd->values);
+ dd->values = NULL;
+ dd->values_len = 0;
+ return (-1);
+ }
+ }
+
+ return (0);
+} /* int csnmp_config_add_data_instance */
+
+static int csnmp_config_add_data (oconfig_item_t *ci)
+{
+ data_definition_t *dd;
+ int status = 0;
+ int i;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("snmp plugin: The `Data' config option needs exactly one string argument.");
+ return (-1);
+ }
+
+ dd = (data_definition_t *) malloc (sizeof (data_definition_t));
+ if (dd == NULL)
+ return (-1);
+ memset (dd, '\0', sizeof (data_definition_t));
+
+ dd->name = strdup (ci->values[0].value.string);
+ if (dd->name == NULL)
+ {
+ free (dd);
+ return (-1);
+ }
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *option = ci->children + i;
+ status = 0;
+
+ if (strcasecmp ("Type", option->key) == 0)
+ status = csnmp_config_add_data_type (dd, option);
+ else if (strcasecmp ("Table", option->key) == 0)
+ status = csnmp_config_add_data_table (dd, option);
+ else if (strcasecmp ("Instance", option->key) == 0)
+ status = csnmp_config_add_data_instance (dd, option);
+ else if (strcasecmp ("Values", option->key) == 0)
+ status = csnmp_config_add_data_values (dd, option);
+ else
+ {
+ WARNING ("snmp plugin: Option `%s' not allowed here.", option->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ } /* for (ci->children) */
+
+ while (status == 0)
+ {
+ if (dd->type == NULL)
+ {
+ WARNING ("snmp plugin: `Type' not given for data `%s'", dd->name);
+ status = -1;
+ break;
+ }
+ if (dd->values == NULL)
+ {
+ WARNING ("snmp plugin: No `Value' given for data `%s'", dd->name);
+ status = -1;
+ break;
+ }
+
+ break;
+ } /* while (status == 0) */
+
+ if (status != 0)
+ {
+ sfree (dd->name);
+ sfree (dd->values);
+ sfree (dd);
+ return (-1);
+ }
+
+ DEBUG ("snmp plugin: dd = { name = %s, type = %s, is_table = %s, values_len = %i }",
+ dd->name, dd->type, (dd->is_table != 0) ? "true" : "false", dd->values_len);
+
+ if (data_head == NULL)
+ data_head = dd;
+ else
+ {
+ data_definition_t *last;
+ last = data_head;
+ while (last->next != NULL)
+ last = last->next;
+ last->next = dd;
+ }
+
+ return (0);
+} /* int csnmp_config_add_data */
+
+static int csnmp_config_add_host_address (host_definition_t *hd, oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("snmp plugin: The `Address' config option needs exactly one string argument.");
+ return (-1);
+ }
+
+ if (hd->address == NULL)
+ free (hd->address);
+
+ hd->address = strdup (ci->values[0].value.string);
+ if (hd->address == NULL)
+ return (-1);
+
+ DEBUG ("snmp plugin: host = %s; host->address = %s;",
+ hd->name, hd->address);
+
+ return (0);
+} /* int csnmp_config_add_host_address */
+
+static int csnmp_config_add_host_community (host_definition_t *hd, oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("snmp plugin: The `Community' config option needs exactly one string argument.");
+ return (-1);
+ }
+
+ if (hd->community == NULL)
+ free (hd->community);
+
+ hd->community = strdup (ci->values[0].value.string);
+ if (hd->community == NULL)
+ return (-1);
+
+ DEBUG ("snmp plugin: host = %s; host->community = %s;",
+ hd->name, hd->community);
+
+ return (0);
+} /* int csnmp_config_add_host_community */
+
+static int csnmp_config_add_host_version (host_definition_t *hd, oconfig_item_t *ci)
+{
+ int version;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+ {
+ WARNING ("snmp plugin: The `Version' config option needs exactly one number argument.");
+ return (-1);
+ }
+
+ version = (int) ci->values[0].value.number;
+ if ((version != 1) && (version != 2))
+ {
+ WARNING ("snmp plugin: `Version' must either be `1' or `2'.");
+ return (-1);
+ }
+
+ hd->version = version;
+
+ return (0);
+} /* int csnmp_config_add_host_address */
+
+static int csnmp_config_add_host_collect (host_definition_t *host,
+ oconfig_item_t *ci)
+{
+ data_definition_t *data;
+ data_definition_t **data_list;
+ int data_list_len;
+ int i;
+
+ if (ci->values_num < 1)
+ {
+ WARNING ("snmp plugin: `Collect' needs at least one argument.");
+ return (-1);
+ }
+
+ for (i = 0; i < ci->values_num; i++)
+ if (ci->values[i].type != OCONFIG_TYPE_STRING)
+ {
+ WARNING ("snmp plugin: All arguments to `Collect' must be strings.");
+ return (-1);
+ }
+
+ data_list_len = host->data_list_len + ci->values_num;
+ data_list = (data_definition_t **) realloc (host->data_list,
+ sizeof (data_definition_t *) * data_list_len);
+ if (data_list == NULL)
+ return (-1);
+ host->data_list = data_list;
+
+ for (i = 0; i < ci->values_num; i++)
+ {
+ for (data = data_head; data != NULL; data = data->next)
+ if (strcasecmp (ci->values[i].value.string, data->name) == 0)
+ break;
+
+ if (data == NULL)
+ {
+ WARNING ("snmp plugin: No such data configured: `%s'",
+ ci->values[i].value.string);
+ continue;
+ }
+
+ DEBUG ("snmp plugin: Collect: host = %s, data[%i] = %s;",
+ host->name, host->data_list_len, data->name);
+
+ host->data_list[host->data_list_len] = data;
+ host->data_list_len++;
+ } /* for (values_num) */
+
+ return (0);
+} /* int csnmp_config_add_host_collect */
+
+static int csnmp_config_add_host_interval (host_definition_t *hd, oconfig_item_t *ci)
+{
+ int interval;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+ {
+ WARNING ("snmp plugin: The `Interval' config option needs exactly one number argument.");
+ return (-1);
+ }
+
+ interval = (int) ci->values[0].value.number;
+ hd->skip_num = interval;
+ if (hd->skip_num < 0)
+ hd->skip_num = 0;
+
+ return (0);
+} /* int csnmp_config_add_host_interval */
+
+static int csnmp_config_add_host (oconfig_item_t *ci)
+{
+ host_definition_t *hd;
+ int status = 0;
+ int i;
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("snmp plugin: `Host' needs exactly one string argument.");
+ return (-1);
+ }
+
+ hd = (host_definition_t *) malloc (sizeof (host_definition_t));
+ if (hd == NULL)
+ return (-1);
+ memset (hd, '\0', sizeof (host_definition_t));
+ hd->version = 2;
+
+ hd->name = strdup (ci->values[0].value.string);
+ if (hd->name == NULL)
+ {
+ free (hd);
+ return (-1);
+ }
+
+ hd->sess_handle = NULL;
+ hd->skip_num = 0;
+ hd->skip_left = 0;
+ hd->state = STATE_IDLE;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *option = ci->children + i;
+ status = 0;
+
+ if (strcasecmp ("Address", option->key) == 0)
+ status = csnmp_config_add_host_address (hd, option);
+ else if (strcasecmp ("Community", option->key) == 0)
+ status = csnmp_config_add_host_community (hd, option);
+ else if (strcasecmp ("Version", option->key) == 0)
+ status = csnmp_config_add_host_version (hd, option);
+ else if (strcasecmp ("Collect", option->key) == 0)
+ csnmp_config_add_host_collect (hd, option);
+ else if (strcasecmp ("Interval", option->key) == 0)
+ csnmp_config_add_host_interval (hd, option);
+ else
+ {
+ WARNING ("snmp plugin: csnmp_config_add_host: Option `%s' not allowed here.", option->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ } /* for (ci->children) */
+
+ while (status == 0)
+ {
+ if (hd->address == NULL)
+ {
+ WARNING ("snmp plugin: `Address' not given for host `%s'", hd->name);
+ status = -1;
+ break;
+ }
+ if (hd->community == NULL)
+ {
+ WARNING ("snmp plugin: `Community' not given for host `%s'", hd->name);
+ status = -1;
+ break;
+ }
+
+ break;
+ } /* while (status == 0) */
+
+ if (status != 0)
+ {
+ sfree (hd->name);
+ sfree (hd);
+ return (-1);
+ }
+
+ DEBUG ("snmp plugin: hd = { name = %s, address = %s, community = %s, version = %i }",
+ hd->name, hd->address, hd->community, hd->version);
+
+ if (host_head == NULL)
+ host_head = hd;
+ else
+ {
+ host_definition_t *last;
+ last = host_head;
+ while (last->next != NULL)
+ last = last->next;
+ last->next = hd;
+ }
+
+ return (0);
+} /* int csnmp_config_add_host */
+
+static int csnmp_config (oconfig_item_t *ci)
+{
+ int i;
+
+ call_snmp_init_once ();
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+ if (strcasecmp ("Data", child->key) == 0)
+ csnmp_config_add_data (child);
+ else if (strcasecmp ("Host", child->key) == 0)
+ csnmp_config_add_host (child);
+ else
+ {
+ WARNING ("snmp plugin: Ignoring unknown config option `%s'.", child->key);
+ }
+ } /* for (ci->children) */
+
+ return (0);
+} /* int csnmp_config */
+
+/* End of the config stuff. Now the interesting part begins */
+
+static void csnmp_host_close_session (host_definition_t *host)
+{
+ int status;
+
+ if (host->sess_handle == NULL)
+ return;
+
+ status = snmp_sess_close (host->sess_handle);
+
+ if (status != 0)
+ {
+ char *errstr = NULL;
+
+ snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
+
+ ERROR ("snmp plugin: snmp_sess_close failed: %s",
+ (errstr == NULL) ? "Unknown problem" : errstr);
+ sfree (errstr);
+ }
+
+ host->sess_handle = NULL;
+} /* void csnmp_host_close_session */
+
+static void csnmp_host_open_session (host_definition_t *host)
+{
+ struct snmp_session sess;
+
+ if (host->sess_handle != NULL)
+ csnmp_host_close_session (host);
+
+ snmp_sess_init (&sess);
+ sess.peername = host->address;
+ sess.community = (u_char *) host->community;
+ sess.community_len = strlen (host->community);
+ sess.version = (host->version == 1) ? SNMP_VERSION_1 : SNMP_VERSION_2c;
+
+ /* snmp_sess_open will copy the `struct snmp_session *'. */
+ host->sess_handle = snmp_sess_open (&sess);
+
+ if (host->sess_handle == NULL)
+ {
+ char *errstr = NULL;
+
+ snmp_error (&sess, NULL, NULL, &errstr);
+
+ ERROR ("snmp plugin: snmp_sess_open failed: %s",
+ (errstr == NULL) ? "Unknown problem" : errstr);
+ sfree (errstr);
+ }
+} /* void csnmp_host_open_session */
+
+static value_t csnmp_value_list_to_value (struct variable_list *vl, int type)
+{
+ value_t ret;
+ uint64_t temp = 0;
+ int defined = 1;
+
+ if ((vl->type == ASN_INTEGER)
+ || (vl->type == ASN_UINTEGER)
+ || (vl->type == ASN_COUNTER)
+ || (vl->type == ASN_GAUGE))
+ {
+ temp = (uint32_t) *vl->val.integer;
+ DEBUG ("snmp plugin: Parsed int32 value is %llu.", temp);
+ }
+ else if (vl->type == ASN_COUNTER64)
+ {
+ temp = (uint32_t) vl->val.counter64->high;
+ temp = temp << 32;
+ temp += (uint32_t) vl->val.counter64->low;
+ DEBUG ("snmp plugin: Parsed int64 value is %llu.", temp);
+ }
+ else
+ {
+ WARNING ("snmp plugin: I don't know the ASN type `%i'", (int) vl->type);
+ defined = 0;
+ }
+
+ if (type == DS_TYPE_COUNTER)
+ {
+ ret.counter = temp;
+ }
+ else if (type == DS_TYPE_GAUGE)
+ {
+ ret.gauge = NAN;
+ if (defined != 0)
+ ret.gauge = temp;
+ }
+
+ return (ret);
+} /* value_t csnmp_value_list_to_value */
+
+static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *data,
+ csnmp_list_instances_t *instance_list,
+ csnmp_table_values_t **value_table)
+{
+ const data_set_t *ds;
+ value_list_t vl = VALUE_LIST_INIT;
+
+ csnmp_list_instances_t *instance_list_ptr;
+ csnmp_table_values_t **value_table_ptr;
+
+ int i;
+
+ ds = plugin_get_ds (data->type);
+ if (!ds)
+ {
+ ERROR ("snmp plugin: DataSet `%s' not defined.", data->type);
+ return (-1);
+ }
+ assert (ds->ds_num == data->values_len);
+
+ value_table_ptr = (csnmp_table_values_t **) malloc (sizeof (csnmp_table_values_t *)
+ * data->values_len);
+ if (value_table_ptr == NULL)
+ return (-1);
+ for (i = 0; i < data->values_len; i++)
+ value_table_ptr[i] = value_table[i];
+
+ vl.values_len = ds->ds_num;
+ vl.values = (value_t *) malloc (sizeof (value_t) * vl.values_len);
+ if (vl.values == NULL)
+ {
+ sfree (value_table_ptr);
+ return (-1);
+ }
+
+ strncpy (vl.host, host->name, sizeof (vl.host));
+ vl.host[sizeof (vl.host) - 1] = '\0';
+ strcpy (vl.plugin, "snmp");
+
+ vl.interval = host->skip_num;
+ vl.time = time (NULL);
+
+ for (instance_list_ptr = instance_list;
+ instance_list_ptr != NULL;
+ instance_list_ptr = instance_list_ptr->next)
+ {
+ strncpy (vl.type_instance, instance_list_ptr->instance, sizeof (vl.type_instance));
+ vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+
+ for (i = 0; i < data->values_len; i++)
+ {
+ while ((value_table_ptr[i] != NULL)
+ && (value_table_ptr[i]->subid < instance_list_ptr->subid))
+ value_table_ptr[i] = value_table_ptr[i]->next;
+ if ((value_table_ptr[i] == NULL)
+ || (value_table_ptr[i]->subid != instance_list_ptr->subid))
+ break;
+ vl.values[i] = value_table_ptr[i]->value;
+ } /* for (data->values_len) */
+
+ /* If the for-loop was aborted early, not all subid's match. */
+ if (i < data->values_len)
+ {
+ DEBUG ("snmp plugin: host = %s; data = %s; i = %i; "
+ "Skipping SUBID %i",
+ host->name, data->name, i, instance_list_ptr->subid);
+ continue;
+ }
+
+ /* If we get here `vl.type_instance' and all `vl.values' have been set */
+ plugin_dispatch_values (data->type, &vl);
+ } /* for (instance_list) */
+
+ sfree (vl.values);
+ sfree (value_table_ptr);
+
+ return (0);
+} /* int csnmp_dispatch_table */
+
+static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
+{
+ struct snmp_pdu *req;
+ struct snmp_pdu *res;
+ struct variable_list *vb;
+
+ const data_set_t *ds;
+ oid_t *oid_list;
+ uint32_t oid_list_len;
+
+ int status;
+ int i;
+
+ /* `value_table' and `value_table_ptr' implement a linked list for each
+ * value. `instance_list' and `instance_list_ptr' implement a linked list of
+ * instance names. This is used to jump gaps in the table. */
+ csnmp_list_instances_t *instance_list;
+ csnmp_list_instances_t *instance_list_ptr;
+ csnmp_table_values_t **value_table;
+ csnmp_table_values_t **value_table_ptr;
+
+ DEBUG ("snmp plugin: csnmp_read_table (host = %s, data = %s)",
+ host->name, data->name);
+
+ ds = plugin_get_ds (data->type);
+ if (!ds)
+ {
+ ERROR ("snmp plugin: DataSet `%s' not defined.", data->type);
+ return (-1);
+ }
+
+ if (ds->ds_num != data->values_len)
+ {
+ ERROR ("snmp plugin: DataSet `%s' requires %i values, but config talks about %i",
+ data->type, ds->ds_num, data->values_len);
+ return (-1);
+ }
+
+ /* We need a copy of all the OIDs, because GETNEXT will destroy them. */
+ oid_list_len = data->values_len + 1;
+ oid_list = (oid_t *) malloc (sizeof (oid_t) * (oid_list_len));
+ if (oid_list == NULL)
+ return (-1);
+ memcpy (oid_list, &data->instance.oid, sizeof (oid_t));
+ for (i = 0; i < data->values_len; i++)
+ memcpy (oid_list + (i + 1), data->values + i, sizeof (oid_t));
+
+ /* Allocate the `value_table' */
+ value_table = (csnmp_table_values_t **) malloc (sizeof (csnmp_table_values_t *)
+ * 2 * data->values_len);
+ if (value_table == NULL)
+ {
+ sfree (oid_list);
+ return (-1);
+ }
+ memset (value_table, '\0', sizeof (csnmp_table_values_t *) * 2 * data->values_len);
+ value_table_ptr = value_table + data->values_len;
+
+ instance_list = NULL;
+ instance_list_ptr = NULL;
+
+ status = 0;
+ while (status == 0)
+ {
+ csnmp_list_instances_t *il;
+
+ req = snmp_pdu_create (SNMP_MSG_GETNEXT);
+ if (req == NULL)
+ {
+ ERROR ("snmp plugin: snmp_pdu_create failed.");
+ status = -1;
+ break;
+ }
+
+ for (i = 0; i < oid_list_len; i++)
+ snmp_add_null_var (req, oid_list[i].oid, oid_list[i].oid_len);
+
+ status = snmp_sess_synch_response (host->sess_handle, req, &res);
+
+ if (status != STAT_SUCCESS)
+ {
+ char *errstr = NULL;
+
+ snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
+ ERROR ("snmp plugin: snmp_sess_synch_response failed: %s",
+ (errstr == NULL) ? "Unknown problem" : errstr);
+ csnmp_host_close_session (host);
+
+ status = -1;
+ break;
+ }
+ status = 0;
+ assert (res != NULL);
+
+ vb = res->variables;
+ if (vb == NULL)
+ {
+ status = -1;
+ break;
+ }
+
+ /* Check if we left the subtree */
+ if (snmp_oid_ncompare (data->instance.oid.oid, data->instance.oid.oid_len,
+ vb->name, vb->name_length,
+ data->instance.oid.oid_len) != 0)
+ break;
+
+ /* Allocate a new `csnmp_list_instances_t', insert the instance name and
+ * add it to the list */
+ il = (csnmp_list_instances_t *) malloc (sizeof (csnmp_list_instances_t));
+ if (il == NULL)
+ {
+ status = -1;
+ break;
+ }
+ il->subid = vb->name[vb->name_length - 1];
+ il->next = NULL;
+
+ /* Get instance name */
+ if ((vb->type == ASN_OCTET_STR) || (vb->type == ASN_BIT_STR))
+ {
+ char *ptr;
+ size_t instance_len;
+
+ instance_len = sizeof (il->instance) - 1;
+ if (instance_len > vb->val_len)
+ instance_len = vb->val_len;
+
+ strncpy (il->instance, (char *) ((vb->type == ASN_OCTET_STR)
+ ? vb->val.string
+ : vb->val.bitstring),
+ instance_len);
+ il->instance[instance_len] = '\0';
+
+ for (ptr = il->instance; *ptr != '\0'; ptr++)
+ {
+ if ((*ptr > 0) && (*ptr < 32))
+ *ptr = ' ';
+ else if (*ptr == '/')
+ *ptr = '_';
+ }
+ DEBUG ("snmp plugin: il->instance = `%s';", il->instance);
+ }
+ else
+ {
+ value_t val = csnmp_value_list_to_value (vb, DS_TYPE_COUNTER);
+ snprintf (il->instance, sizeof (il->instance),
+ "%llu", val.counter);
+ }
+ il->instance[sizeof (il->instance) - 1] = '\0';
+ DEBUG ("snmp plugin: data = `%s'; il->instance = `%s';",
+ data->name, il->instance);
+
+ if (instance_list_ptr == NULL)
+ instance_list = il;
+ else
+ instance_list_ptr->next = il;
+ instance_list_ptr = il;
+
+ /* Copy OID to oid_list[0] */
+ memcpy (oid_list[0].oid, vb->name, sizeof (oid) * vb->name_length);
+ oid_list[0].oid_len = vb->name_length;
+
+ for (i = 0; i < data->values_len; i++)
+ {
+ csnmp_table_values_t *vt;
+
+ vb = vb->next_variable;
+ if (vb == NULL)
+ {
+ status = -1;
+ break;
+ }
+
+ /* Check if we left the subtree */
+ if (snmp_oid_ncompare (data->values[i].oid,
+ data->values[i].oid_len,
+ vb->name, vb->name_length,
+ data->values[i].oid_len) != 0)
+ {
+ DEBUG ("snmp plugin: host = %s; data = %s; Value %i left its subtree.",
+ host->name, data->name, i);
+ continue;
+ }
+
+ if ((value_table_ptr[i] != NULL)
+ && (vb->name[vb->name_length - 1] <= value_table_ptr[i]->subid))
+ {
+ DEBUG ("snmp plugin: host = %s; data = %s; i = %i; SUBID is not increasing.",
+ host->name, data->name, i);
+ continue;
+ }
+
+ vt = (csnmp_table_values_t *) malloc (sizeof (csnmp_table_values_t));
+ if (vt != NULL)
+ {
+ vt->subid = vb->name[vb->name_length - 1];
+ vt->value = csnmp_value_list_to_value (vb, ds->ds[i].type);
+ vt->next = NULL;
+
+ if (value_table_ptr[i] == NULL)
+ value_table[i] = vt;
+ else
+ value_table_ptr[i]->next = vt;
+ value_table_ptr[i] = vt;
+ }
+
+ /* Copy OID to oid_list[i + 1] */
+ memcpy (oid_list[i + 1].oid, vb->name, sizeof (oid) * vb->name_length);
+ oid_list[i + 1].oid_len = vb->name_length;
+ } /* for (i = data->values_len) */
+
+ if (res != NULL)
+ snmp_free_pdu (res);
+ res = NULL;
+ } /* while (status == 0) */
+
+ if (status == 0)
+ csnmp_dispatch_table (host, data, instance_list, value_table);
+
+ /* Free all allocated variables here */
+ while (instance_list != NULL)
+ {
+ instance_list_ptr = instance_list->next;
+ sfree (instance_list);
+ instance_list = instance_list_ptr;
+ }
+
+ for (i = 0; i < data->values_len; i++)
+ {
+ csnmp_table_values_t *tmp;
+ while (value_table[i] != NULL)
+ {
+ tmp = value_table[i]->next;
+ sfree (value_table[i]);
+ value_table[i] = tmp;
+ }
+ }
+
+ sfree (value_table);
+ sfree (oid_list);
+
+ return (0);
+} /* int csnmp_read_table */
+
+static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
+{
+ struct snmp_pdu *req;
+ struct snmp_pdu *res;
+ struct variable_list *vb;
+
+ const data_set_t *ds;
+ value_list_t vl = VALUE_LIST_INIT;
+
+ int status;
+ int i;
+
+ DEBUG ("snmp plugin: csnmp_read_value (host = %s, data = %s)",
+ host->name, data->name);
+
+ ds = plugin_get_ds (data->type);
+ if (!ds)
+ {
+ ERROR ("snmp plugin: DataSet `%s' not defined.", data->type);
+ return (-1);
+ }
+
+ if (ds->ds_num != data->values_len)
+ {
+ ERROR ("snmp plugin: DataSet `%s' requires %i values, but config talks about %i",
+ data->type, ds->ds_num, data->values_len);
+ return (-1);
+ }
+
+ vl.values_len = ds->ds_num;
+ vl.values = (value_t *) malloc (sizeof (value_t) * vl.values_len);
+ if (vl.values == NULL)
+ return (-1);
+ for (i = 0; i < vl.values_len; i++)
+ {
+ if (ds->ds[i].type == DS_TYPE_COUNTER)
+ vl.values[i].counter = 0;
+ else
+ vl.values[i].gauge = NAN;
+ }
+
+ strncpy (vl.host, host->name, sizeof (vl.host));
+ vl.host[sizeof (vl.host) - 1] = '\0';
+ strcpy (vl.plugin, "snmp");
+ strncpy (vl.type_instance, data->instance.string, sizeof (vl.type_instance));
+ vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+
+ vl.interval = host->skip_num;
+
+ req = snmp_pdu_create (SNMP_MSG_GET);
+ if (req == NULL)
+ {
+ ERROR ("snmp plugin: snmp_pdu_create failed.");
+ sfree (vl.values);
+ return (-1);
+ }
+
+ for (i = 0; i < data->values_len; i++)
+ snmp_add_null_var (req, data->values[i].oid, data->values[i].oid_len);
+ status = snmp_sess_synch_response (host->sess_handle, req, &res);
+
+ if (status != STAT_SUCCESS)
+ {
+ char *errstr = NULL;
+
+ snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
+ ERROR ("snmp plugin: snmp_sess_synch_response failed: %s",
+ (errstr == NULL) ? "Unknown problem" : errstr);
+ csnmp_host_close_session (host);
+ sfree (errstr);
+
+ return (-1);
+ }
+
+ vl.time = time (NULL);
+
+ for (vb = res->variables; vb != NULL; vb = vb->next_variable)
+ {
+ char buffer[1024];
+ snprint_variable (buffer, sizeof (buffer),
+ vb->name, vb->name_length, vb);
+ DEBUG ("snmp plugin: Got this variable: %s", buffer);
+
+ for (i = 0; i < data->values_len; i++)
+ if (snmp_oid_compare (data->values[i].oid, data->values[i].oid_len,
+ vb->name, vb->name_length) == 0)
+ vl.values[i] = csnmp_value_list_to_value (vb, ds->ds[i].type);
+ } /* for (res->variables) */
+
+ snmp_free_pdu (res);
+
+ DEBUG ("snmp plugin: -> plugin_dispatch_values (%s, &vl);", data->type);
+ plugin_dispatch_values (data->type, &vl);
+ sfree (vl.values);
+
+ return (0);
+} /* int csnmp_read_value */
+
+static int csnmp_read_host (host_definition_t *host)
+{
+ int i;
+
+ DEBUG ("snmp plugin: csnmp_read_host (%s);", host->name);
+
+ if (host->sess_handle == NULL)
+ csnmp_host_open_session (host);
+
+ if (host->sess_handle == NULL)
+ return (-1);
+
+ for (i = 0; i < host->data_list_len; i++)
+ {
+ data_definition_t *data = host->data_list[i];
+
+ if (data->is_table)
+ csnmp_read_table (host, data);
+ else
+ csnmp_read_value (host, data);
+ }
+
+ return (0);
+} /* int csnmp_read_host */
+
+static void *csnmp_read_thread (void *data)
+{
+ host_definition_t *host;
+
+ pthread_mutex_lock (&host_lock);
+ while (do_shutdown == 0)
+ {
+ pthread_cond_wait (&host_cond, &host_lock);
+
+ for (host = host_head; host != NULL; host = host->next)
+ {
+ if (do_shutdown != 0)
+ break;
+ if (host->state != STATE_WAIT)
+ continue;
+
+ host->state = STATE_BUSY;
+ pthread_mutex_unlock (&host_lock);
+ csnmp_read_host (host);
+ pthread_mutex_lock (&host_lock);
+ host->state = STATE_IDLE;
+ } /* for (host) */
+ } /* while (do_shutdown == 0) */
+ pthread_mutex_unlock (&host_lock);
+
+ pthread_exit ((void *) 0);
+ return ((void *) 0);
+} /* void *csnmp_read_thread */
+
+static int csnmp_init (void)
+{
+ host_definition_t *host;
+ int i;
+
+ if (host_head == NULL)
+ return (-1);
+
+ call_snmp_init_once ();
+
+ threads_num = 0;
+ for (host = host_head; host != NULL; host = host->next)
+ {
+ threads_num++;
+ /* We need to initialize `skip_num' here, because `interval_g' isn't
+ * initialized during `configure'. */
+ host->skip_left = interval_g;
+ if (host->skip_num == 0)
+ {
+ host->skip_num = interval_g;
+ }
+ else if (host->skip_num < interval_g)
+ {
+ host->skip_num = interval_g;
+ WARNING ("snmp plugin: Data for host `%s' will be collected every %i seconds.",
+ host->name, host->skip_num);
+ }
+
+ csnmp_host_open_session (host);
+ } /* for (host) */
+
+ /* Now start the reading threads */
+ if (threads_num > 3)
+ {
+ threads_num = 3 + ((threads_num - 3) / 10);
+ if (threads_num > 10)
+ threads_num = 10;
+ }
+
+ threads = (pthread_t *) malloc (threads_num * sizeof (pthread_t));
+ if (threads == NULL)
+ return (-1);
+ memset (threads, '\0', threads_num * sizeof (pthread_t));
+
+ for (i = 0; i < threads_num; i++)
+ pthread_create (threads + i, NULL, csnmp_read_thread, (void *) 0);
+
+ return (0);
+} /* int csnmp_init */
+
+static int csnmp_read (void)
+{
+ host_definition_t *host;
+ time_t now;
+
+ if (host_head == NULL)
+ {
+ INFO ("snmp plugin: No hosts configured.");
+ return (-1);
+ }
+
+ now = time (NULL);
+
+ pthread_mutex_lock (&host_lock);
+ for (host = host_head; host != NULL; host = host->next)
+ {
+ if (host->state != STATE_IDLE)
+ continue;
+
+ host->skip_left -= interval_g;
+ if (host->skip_left >= interval_g)
+ continue;
+
+ host->state = STATE_WAIT;
+
+ host->skip_left = host->skip_num;
+ } /* for (host) */
+
+ pthread_cond_broadcast (&host_cond);
+ pthread_mutex_unlock (&host_lock);
+
+ return (0);
+} /* int csnmp_read */
+
+static int csnmp_shutdown (void)
+{
+ host_definition_t *host_this;
+ host_definition_t *host_next;
+
+ data_definition_t *data_this;
+ data_definition_t *data_next;
+
+ int i;
+
+ pthread_mutex_lock (&host_lock);
+ do_shutdown = 1;
+ pthread_cond_broadcast (&host_cond);
+ pthread_mutex_unlock (&host_lock);
+
+ for (i = 0; i < threads_num; i++)
+ pthread_join (threads[i], NULL);
+
+ /* Now that all the threads have exited, let's free all the global variables.
+ * This isn't really neccessary, I guess, but I think it's good stile to do
+ * so anyway. */
+ host_this = host_head;
+ host_head = NULL;
+ while (host_this != NULL)
+ {
+ host_next = host_this->next;
+
+ csnmp_host_close_session (host_this);
+
+ sfree (host_this->name);
+ sfree (host_this->address);
+ sfree (host_this->community);
+ sfree (host_this->data_list);
+ sfree (host_this);
+
+ host_this = host_next;
+ }
+
+ data_this = data_head;
+ data_head = NULL;
+ while (data_this != NULL)
+ {
+ data_next = data_this->next;
+
+ sfree (data_this->name);
+ sfree (data_this->type);
+ sfree (data_this->values);
+ sfree (data_this);
+
+ data_this = data_next;
+ }
+
+ return (0);
+} /* int csnmp_shutdown */
+
+void module_register (void)
+{
+ plugin_register_complex_config ("snmp", csnmp_config);
+ plugin_register_init ("snmp", csnmp_init);
+ plugin_register_read ("snmp", csnmp_read);
+ plugin_register_shutdown ("snmp", csnmp_shutdown);
+} /* void module_register */
+
+/*
+ * vim: shiftwidth=2 softtabstop=2 tabstop=8
+ */
# include <kvm.h>
#endif
-#if KERNEL_LINUX || HAVE_LIBKSTAT || defined(VM_SWAPUSAGE) || HAVE_LIBKVM || HAVE_LIBSTATGRAB
-# define SWAP_HAVE_READ 1
-#else
-# define SWAP_HAVE_READ 0
-#endif
-
#undef MAX
#define MAX(x,y) ((x) > (y) ? (x) : (y))
-#if SWAP_HAVE_READ
#if KERNEL_LINUX
/* No global variables */
/* #endif KERNEL_LINUX */
#elif HAVE_LIBSTATGRAB
/* No global variables */
+/* #endif HAVE_LIBSTATGRAB */
+
+#else
+# error "No applicable input method."
#endif /* HAVE_LIBSTATGRAB */
static int swap_init (void)
return (0);
} /* int swap_read */
-#endif /* SWAP_HAVE_READ */
void module_register (void)
{
-#if SWAP_HAVE_READ
plugin_register_init ("swap", swap_init);
plugin_register_read ("swap", swap_read);
-#endif /* SWAP_HAVE_READ */
} /* void module_register */
#include "common.h"
#include "plugin.h"
-#if defined(HAVE_LIBKSTAT)
-# define TAPE_HAVE_READ 1
-#else
-# define TAPE_HAVE_READ 0
+#if !HAVE_LIBKSTAT
+# error "No applicable input method."
#endif
-#if TAPE_HAVE_READ
-#if defined(HAVE_LIBKSTAT)
#define MAX_NUMTAPE 256
extern kstat_ctl_t *kc;
static kstat_t *ksp[MAX_NUMTAPE];
static int numtape = 0;
-#endif /* HAVE_LIBKSTAT */
static int tape_init (void)
{
-#ifdef HAVE_LIBKSTAT
kstat_t *ksp_chain;
numtape = 0;
continue;
ksp[numtape++] = ksp_chain;
}
-#endif
return (0);
-}
+} /* int tape_init */
static void tape_submit (const char *plugin_instance,
const char *type,
static int tape_read (void)
{
-#if defined(HAVE_LIBKSTAT)
-# if HAVE_KSTAT_IO_T_WRITES && HAVE_KSTAT_IO_T_NWRITES && HAVE_KSTAT_IO_T_WTIME
-# define KIO_ROCTETS reads
-# define KIO_WOCTETS writes
-# define KIO_ROPS nreads
-# define KIO_WOPS nwrites
-# define KIO_RTIME rtime
-# define KIO_WTIME wtime
-# elif HAVE_KSTAT_IO_T_NWRITTEN && HAVE_KSTAT_IO_T_WRITES && HAVE_KSTAT_IO_T_WTIME
-# define KIO_ROCTETS nread
-# define KIO_WOCTETS nwritten
-# define KIO_ROPS reads
-# define KIO_WOPS writes
-# define KIO_RTIME rtime
-# define KIO_WTIME wtime
-# else
-# error "kstat_io_t does not have the required members"
-# endif
+#if HAVE_KSTAT_IO_T_WRITES && HAVE_KSTAT_IO_T_NWRITES && HAVE_KSTAT_IO_T_WTIME
+# define KIO_ROCTETS reads
+# define KIO_WOCTETS writes
+# define KIO_ROPS nreads
+# define KIO_WOPS nwrites
+# define KIO_RTIME rtime
+# define KIO_WTIME wtime
+#elif HAVE_KSTAT_IO_T_NWRITTEN && HAVE_KSTAT_IO_T_WRITES && HAVE_KSTAT_IO_T_WTIME
+# define KIO_ROCTETS nread
+# define KIO_WOCTETS nwritten
+# define KIO_ROPS reads
+# define KIO_WOPS writes
+# define KIO_RTIME rtime
+# define KIO_WTIME wtime
+#else
+# error "kstat_io_t does not have the required members"
+#endif
static kstat_io_t kio;
int i;
kio.KIO_RTIME, kio.KIO_WTIME);
}
}
-#endif /* defined(HAVE_LIBKSTAT) */
return (0);
}
-#endif /* TAPE_HAVE_READ */
void module_register (void)
{
-#if TAPE_HAVE_READ
plugin_register_init ("tape", tape_init);
plugin_register_read ("tape", tape_read);
-#endif /* TAPE_HAVE_READ */
}
apache_connections count:GAUGE:0:65535
apache_requests count:COUNTER:0:134217728
apache_scoreboard count:GAUGE:0:65535
+bitrate value:GAUGE:0:4294967295
charge value:GAUGE:0:U
counter value:COUNTER:U:U
cpu value:COUNTER:0:4294967295
frequency_offset ppm:GAUGE:-1000000:1000000
gauge value:GAUGE:U:U
humitidy value:GAUGE:0:100
+if_collisions value:COUNTER:0:4294967295
+if_dropped rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
if_errors rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
+if_multicast value:COUNTER:0:4294967295
if_octets rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
if_packets rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
+if_rx_errors value:COUNTER:0:4294967295
+if_tx_errors value:COUNTER:0:4294967295
ipt_bytes value:COUNTER:0:134217728
ipt_packets value:COUNTER:0:134217728
irq value:COUNTER:U:65535
#include "common.h"
#include "plugin.h"
#include "configfile.h"
+#include "utils_cmd_putval.h"
/* Folks without pthread will need to disable this plugin. */
#include <pthread.h>
# define UNIX_PATH_MAX sizeof (((struct sockaddr_un *)0)->sun_path)
#endif
-#define US_DEFAULT_PATH PREFIX"/var/run/"PACKAGE_NAME"-unixsock"
+#define US_DEFAULT_PATH LOCALSTATEDIR"/run/"PACKAGE_NAME"-unixsock"
/*
* Private data structures
} /* while (this != NULL) */
pthread_mutex_unlock (&cache_lock);
-} /* int cache_flush */
+} /* void cache_flush */
static int us_open_socket (void)
{
return (0);
} /* int us_handle_getval */
-static int us_handle_putval (FILE *fh, char **fields, int fields_num)
+static int us_handle_listval (FILE *fh, char **fields, int fields_num)
{
- char *hostname;
- char *plugin;
- char *plugin_instance;
- char *type;
- char *type_instance;
- int status;
- int i;
-
- const data_set_t *ds;
- value_list_t vl = VALUE_LIST_INIT;
-
- char **value_ptr;
+ char buffer[1024];
+ char **value_list = NULL;
+ int value_list_len = 0;
+ value_cache_t *entry;
+ int i;
- if (fields_num != 3)
+ if (fields_num != 1)
{
- DEBUG ("unixsock plugin: Wrong number of fields: %i", fields_num);
- fprintf (fh, "-1 Wrong number of fields: Got %i, expected 3.\n",
+ DEBUG ("unixsock plugin: us_handle_listval: "
+ "Wrong number of fields: %i", fields_num);
+ fprintf (fh, "-1 Wrong number of fields: Got %i, expected 1.\n",
fields_num);
fflush (fh);
return (-1);
}
- status = parse_identifier (fields[1], &hostname,
- &plugin, &plugin_instance,
- &type, &type_instance);
- if (status != 0)
- {
- DEBUG ("unixsock plugin: Cannot parse `%s'", fields[1]);
- fprintf (fh, "-1 Cannot parse identifier.\n");
- fflush (fh);
- return (-1);
- }
-
- if ((strlen (hostname) >= sizeof (vl.host))
- || (strlen (plugin) >= sizeof (vl.plugin))
- || ((plugin_instance != NULL)
- && (strlen (plugin_instance) >= sizeof (vl.plugin_instance)))
- || ((type_instance != NULL)
- && (strlen (type_instance) >= sizeof (vl.type_instance))))
- {
- fprintf (fh, "-1 Identifier too long.");
- return (-1);
- }
-
- strcpy (vl.host, hostname);
- strcpy (vl.plugin, plugin);
- if (plugin_instance != NULL)
- strcpy (vl.plugin_instance, plugin_instance);
- if (type_instance != NULL)
- strcpy (vl.type_instance, type_instance);
-
- { /* parse the time */
- char *t = fields[2];
- char *v = strchr (t, ':');
- if (v == NULL)
- {
- fprintf (fh, "-1 No time found.");
- return (-1);
- }
- *v = '\0'; v++;
-
- vl.time = (time_t) atoi (t);
- if (vl.time == 0)
- vl.time = time (NULL);
-
- fields[2] = v;
- }
-
- ds = plugin_get_ds (type);
- if (ds == NULL)
- return (-1);
-
- value_ptr = (char **) calloc (ds->ds_num, sizeof (char *));
- if (value_ptr == NULL)
- {
- fprintf (fh, "-1 calloc failed.");
- return (-1);
- }
-
- { /* parse the value-list. It's colon-separated. */
- char *dummy;
- char *ptr;
- char *saveptr;
-
- i = 0;
- dummy = fields[2];
- saveptr = NULL;
- while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL)
- {
- dummy = NULL;
- if (i >= ds->ds_num)
- {
- i = ds->ds_num + 1;
- break;
- }
- value_ptr[i] = ptr;
- i++;
- }
-
- if (i != ds->ds_num)
- {
- sfree (value_ptr);
- fprintf (fh, "-1 Number of values incorrect: Got %i, "
- "expected %i.", i, ds->ds_num);
- return (-1);
- }
- } /* done parsing the value-list */
+ pthread_mutex_lock (&cache_lock);
- vl.values_len = ds->ds_num;
- vl.values = (value_t *) malloc (vl.values_len * sizeof (value_t));
- if (vl.values == NULL)
+ for (entry = cache_head; entry != NULL; entry = entry->next)
{
- sfree (value_ptr);
- fprintf (fh, "-1 malloc failed.");
- return (-1);
- }
- DEBUG ("value_ptr = 0x%p; vl.values = 0x%p;", (void *) value_ptr, (void *) vl.values);
+ char **tmp;
- for (i = 0; i < ds->ds_num; i++)
- {
- if (strcmp (value_ptr[i], "U") == 0)
- vl.values[i].gauge = NAN;
- else if (ds->ds[i].type == DS_TYPE_COUNTER)
- vl.values[i].counter = atoll (value_ptr[i]);
- else if (ds->ds[i].type == DS_TYPE_GAUGE)
- vl.values[i].gauge = atof (value_ptr[i]);
- } /* for (i = 2 .. fields_num) */
+ snprintf (buffer, sizeof (buffer), "%u %s\n",
+ (unsigned int) entry->time, entry->name);
+ buffer[sizeof (buffer) - 1] = '\0';
+
+ tmp = realloc (value_list, sizeof (char *) * (value_list_len + 1));
+ if (tmp == NULL)
+ continue;
+ value_list = tmp;
- plugin_dispatch_values (type, &vl);
+ value_list[value_list_len] = strdup (buffer);
- DEBUG ("value_ptr = 0x%p; vl.values = 0x%p;", (void *) value_ptr, (void *) vl.values);
+ if (value_list[value_list_len] != NULL)
+ value_list_len++;
+ } /* for (entry) */
- sfree (value_ptr);
- sfree (vl.values);
+ pthread_mutex_unlock (&cache_lock);
- fprintf (fh, "0 Success\n");
+ DEBUG ("unixsock plugin: us_handle_listval: value_list_len = %i", value_list_len);
+ fprintf (fh, "%i Values found\n", value_list_len);
+ for (i = 0; i < value_list_len; i++)
+ fputs (value_list[i], fh);
fflush (fh);
return (0);
-} /* int us_handle_putval */
+} /* int us_handle_listval */
static void *us_handle_client (void *arg)
{
}
else if (strcasecmp (fields[0], "putval") == 0)
{
- us_handle_putval (fh, fields, fields_num);
+ handle_putval (fh, fields, fields_num);
+ }
+ else if (strcasecmp (fields[0], "listval") == 0)
+ {
+ us_handle_listval (fh, fields, fields_num);
}
else
{
#if HAVE_UTMPX_H
# include <utmpx.h>
-#else /* !HAVE_UTMPX_H */
-# if HAVE_UTMP_H
-# include <utmp.h>
-# endif /* HAVE_UTMP_H */
-#endif /* HAVE_UTMPX_H */
+/* #endif HAVE_UTMPX_H */
-#define MODULE_NAME "users"
+#elif HAVE_UTMP_H
+# include <utmp.h>
+/* #endif HAVE_UTMP_H */
-#if HAVE_GETUTXENT || HAVE_GETUTENT
-# define USERS_HAVE_READ 1
#else
-# define USERS_HAVE_READ 0
+# error "No applicable input method."
#endif
-#if USERS_HAVE_READ
static void users_submit (gauge_t value)
{
value_t values[1];
endutent();
users_submit (users);
-#endif /* HAVE_GETUTENT */
+/* #endif HAVE_GETUTENT */
+
+#else
+# error "No applicable input method."
+#endif
return (0);
} /* int users_read */
-#endif /* USERS_HAVE_READ */
void module_register (void)
{
-#if USERS_HAVE_READ
plugin_register_read ("users", users_read);
-#endif
} /* void module_register(void) */
--- /dev/null
+/**
+ * collectd - src/utils_cms_putval.c
+ * Copyright (C) 2007 Florian octo Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+static int parse_value (const data_set_t *ds, value_list_t *vl,
+ const char *type,
+ FILE *fh, char *buffer)
+{
+ char *dummy;
+ char *ptr;
+ char *saveptr;
+ int i;
+
+ char *time_str = buffer;
+ char *value_str = strchr (time_str, ':');
+ if (value_str == NULL)
+ {
+ fprintf (fh, "-1 No time found.");
+ return (-1);
+ }
+ *value_str = '\0'; value_str++;
+
+ vl->time = (time_t) atoi (time_str);
+ if (vl->time == 0)
+ vl->time = time (NULL);
+
+ i = 0;
+ dummy = value_str;
+ saveptr = NULL;
+ while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL)
+ {
+ dummy = NULL;
+
+ if (i >= vl->values_len)
+ {
+ i = vl->values_len + 1;
+ break;
+ }
+
+ if (strcmp (ptr, "U") == 0)
+ vl->values[i].gauge = NAN;
+ else if (ds->ds[i].type == DS_TYPE_COUNTER)
+ vl->values[i].counter = atoll (ptr);
+ else if (ds->ds[i].type == DS_TYPE_GAUGE)
+ vl->values[i].gauge = atof (ptr);
+
+ i++;
+ } /* while (strtok_r) */
+
+ if (i != vl->values_len)
+ {
+ char identifier[128];
+ FORMAT_VL (identifier, sizeof (identifier), vl, ds);
+ ERROR ("cmd putval: parse_value: "
+ "Number of values incorrect: "
+ "Got %i, expected %i. Identifier is `%s'.",
+ i, vl->values_len, identifier);
+ fprintf (fh, "-1 Number of values incorrect: "
+ "Got %i, expected %i.\n",
+ i, vl->values_len);
+ return (-1);
+ }
+
+ plugin_dispatch_values (type, vl);
+ return (0);
+} /* int parse_value */
+
+static int parse_option (value_list_t *vl, char *buffer)
+{
+ char *option = buffer;
+ char *value;
+
+ if ((vl == NULL) || (option == NULL))
+ return (-1);
+
+ value = strchr (option, '=');
+ if (value == NULL)
+ return (-1);
+ *value = '\0'; value++;
+
+ if (strcasecmp ("interval", option) == 0)
+ {
+ vl->interval = atoi (value);
+ if (vl->interval <= 0)
+ vl->interval = interval_g;
+ }
+ else
+ return (1);
+
+ return (0);
+} /* int parse_option */
+
+int handle_putval (FILE *fh, char **fields, int fields_num)
+{
+ char *hostname;
+ char *plugin;
+ char *plugin_instance;
+ char *type;
+ char *type_instance;
+ int status;
+ int i;
+
+ const data_set_t *ds;
+ value_list_t vl = VALUE_LIST_INIT;
+
+ if (fields_num < 3)
+ {
+ DEBUG ("cmd putval: Wrong number of fields: %i",
+ fields_num);
+ fprintf (fh, "-1 Wrong number of fields: Got %i, "
+ "expected at least 3.\n",
+ fields_num);
+ fflush (fh);
+ return (-1);
+ }
+
+ status = parse_identifier (fields[1], &hostname,
+ &plugin, &plugin_instance,
+ &type, &type_instance);
+ if (status != 0)
+ {
+ DEBUG ("cmd putval: Cannot parse `%s'", fields[1]);
+ fprintf (fh, "-1 Cannot parse identifier.\n");
+ fflush (fh);
+ return (-1);
+ }
+
+ if ((strlen (hostname) >= sizeof (vl.host))
+ || (strlen (plugin) >= sizeof (vl.plugin))
+ || ((plugin_instance != NULL)
+ && (strlen (plugin_instance) >= sizeof (vl.plugin_instance)))
+ || ((type_instance != NULL)
+ && (strlen (type_instance) >= sizeof (vl.type_instance))))
+ {
+ fprintf (fh, "-1 Identifier too long.");
+ return (-1);
+ }
+
+ strcpy (vl.host, hostname);
+ strcpy (vl.plugin, plugin);
+ if (plugin_instance != NULL)
+ strcpy (vl.plugin_instance, plugin_instance);
+ if (type_instance != NULL)
+ strcpy (vl.type_instance, type_instance);
+
+ ds = plugin_get_ds (type);
+ if (ds == NULL)
+ return (-1);
+
+ vl.values_len = ds->ds_num;
+ vl.values = (value_t *) malloc (vl.values_len * sizeof (value_t));
+ if (vl.values == NULL)
+ {
+ fprintf (fh, "-1 malloc failed.");
+ return (-1);
+ }
+
+ /* All the remaining fields are part of the optionlist. */
+ for (i = 2; i < fields_num; i++)
+ {
+ if (strchr (fields[i], ':') != NULL)
+ {
+ /* It's parse_value's job to write an error to `fh'.
+ * This is not the case with `parse_option below.
+ * Neither will write an success message. */
+ if (parse_value (ds, &vl, type, fh, fields[i]) != 0)
+ break;
+ }
+ else if (strchr (fields[i], '=') != NULL)
+ {
+ if (parse_option (&vl, fields[i]) != 0)
+ {
+ fprintf (fh, "-1 Error parsing option `%s'",
+ fields[i]);
+ break;
+ }
+ }
+ else
+ {
+ WARNING ("cmd putval: handle_putval: "
+ "Cannot parse field #%i `%s'; "
+ "Ignoring it.\n",
+ i, fields[i]);
+ }
+ }
+ /* Done parsing the options. */
+
+ if (i == fields_num)
+ fprintf (fh, "0 Success\n");
+ fflush (fh);
+
+ sfree (vl.values);
+
+ return (0);
+} /* int handle_putval */
+
--- /dev/null
+/**
+ * collectd - src/utils_cms_putval.h
+ * Copyright (C) 2007 Florian octo Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#ifndef UTILS_CMD_PUTVAL_H
+#define UTILS_CMD_PUTVAL_H 1
+
+#include "plugin.h"
+
+int handle_putval (FILE *fh, char **fields, int fields_num);
+
+#endif /* UTILS_CMD_PUTVAL_H */
#define BUFSIZE 512
-#define MODULE_NAME "vserver"
#define PROCDIR "/proc/virtual"
-#if defined(KERNEL_LINUX)
-# define VSERVER_HAVE_READ 1
-#else
-# define VSERVER_HAVE_READ 0
-#endif /* defined(KERNEL_LINUX) */
+#if !KERNEL_LINUX
+# error "No applicable input method."
+#endif
-#if VSERVER_HAVE_READ
static int pagesize = 0;
static int vserver_init (void)
return (0);
} /* int vserver_read */
-#endif /* VSERVER_HAVE_READ */
void module_register (void)
{
-#if VSERVER_HAVE_READ
plugin_register_init ("vserver", vserver_init);
plugin_register_read ("vserver", vserver_read);
-#endif /* VSERVER_HAVE_READ */
} /* void module_register(void) */
/* vim: set ts=4 sw=4 noexpandtab : */
#include "common.h"
#include "plugin.h"
-#if defined(KERNEL_LINUX)
-# define WIRELESS_HAVE_READ 1
-#else
-# define WIRELESS_HAVE_READ 0
+#if !KERNEL_LINUX
+# error "No applicable input method."
#endif
#define WIRELESS_PROC_FILE "/proc/net/wireless"
-#if WIRELESS_HAVE_READ
#if 0
static double wireless_dbm_to_watt (double dbm)
{
return (0);
} /* int wireless_read */
-#endif /* WIRELESS_HAVE_READ */
void module_register (void)
{
-#if WIRELESS_HAVE_READ
plugin_register_read ("wireless", wireless_read);
-#endif /* WIRELESS_HAVE_READ */
} /* void module_register */
--- /dev/null
+/**
+ * collectd - src/xmms.c
+ * Copyright (C) 2007 Florian octo Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+
+#include <xmms/xmmsctrl.h>
+
+static gint xmms_session;
+
+static void cxmms_submit (const char *type, gauge_t value)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].gauge = value;
+
+ vl.values = values;
+ vl.values_len = 1;
+ vl.time = time (NULL);
+ strcpy (vl.host, hostname_g);
+ strcpy (vl.plugin, "xmms");
+
+ plugin_dispatch_values (type, &vl);
+} /* void cxmms_submit */
+
+int cxmms_read (void)
+{
+ gint rate;
+ gint freq;
+ gint nch;
+
+ if (!xmms_remote_is_running (xmms_session))
+ return (0);
+
+ xmms_remote_get_info (xmms_session, &rate, &freq, &nch);
+
+ if ((freq == 0) || (nch == 0))
+ return (0);
+
+ cxmms_submit ("bitrate", rate);
+ cxmms_submit ("frequency", freq);
+
+ return (0);
+} /* int read */
+
+void module_register (void)
+{
+ plugin_register_read ("xmms", cxmms_read);
+} /* void module_register */
+
+/*
+ * vim: shiftwidth=2:softtabstop=2:textwidth=78
+ */
--- /dev/null
+#!/bin/sh
+
+DEFAULT_VERSION="4.1.0.git"
+
+VERSION="$( git describe 2> /dev/null | sed -e 's/^collectd-//' )"
+
+if test -z "$VERSION"; then
+ VERSION="$DEFAULT_VERSION"
+fi
+
+VERSION=$( echo "$VERSION" | sed -e 's/-/./g' )
+
+echo -n $VERSION
+