summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 2578c91)
raw | patch | inline | side by side (parent: 2578c91)
author | Florian Forster <octo@collectd.org> | |
Sat, 20 Sep 2014 04:49:01 +0000 (06:49 +0200) | ||
committer | Florian Forster <octo@collectd.org> | |
Sat, 20 Sep 2014 04:49:01 +0000 (06:49 +0200) |
84 files changed:
diff --git a/configure.ac b/configure.ac
index 65e535a66e159d129343571e94e32478a8f5158c..9dd30c78993ca9c74c285b6a2f31bb45505436c7 100644 (file)
--- a/configure.ac
+++ b/configure.ac
dnl Process this file with autoconf to produce a configure script.
AC_INIT([collectd],[m4_esyscmd(./version-gen.sh)])
-AC_CONFIG_SRCDIR(src/collectd.c)
+AC_CONFIG_SRCDIR(src/)
AC_CONFIG_HEADERS(src/config.h)
AC_CONFIG_AUX_DIR([libltdl/config])
AC_CONFIG_FILES(src/libcollectdclient/collectd/lcc_features.h)
-AC_CONFIG_FILES([Makefile src/Makefile src/collectd.conf src/libcollectdclient/Makefile src/libcollectdclient/libcollectdclient.pc src/liboconfig/Makefile bindings/Makefile bindings/java/Makefile])
+AC_CONFIG_FILES([Makefile src/Makefile src/daemon/Makefile src/collectd.conf src/libcollectdclient/Makefile src/libcollectdclient/libcollectdclient.pc src/liboconfig/Makefile bindings/Makefile bindings/java/Makefile])
AC_OUTPUT
if test "x$with_librrd" = "xyes" \
diff --git a/src/Makefile.am b/src/Makefile.am
index 340c79289f3f52b9e9e943d5d80aa8b7ed912111..b3bd26ed6e172b42a22de56de6eb4e06795adf7a 100644 (file)
--- a/src/Makefile.am
+++ b/src/Makefile.am
if BUILD_WITH_OWN_LIBOCONFIG
SUBDIRS += liboconfig
endif
+SUBDIRS += daemon
if COMPILER_IS_GCC
AM_CFLAGS = -Wall -Werror
endif
-AM_CPPFLAGS = -DPREFIX='"${prefix}"'
+AM_CPPFLAGS = -I$(srcdir)/daemon
+AM_CPPFLAGS += -DPREFIX='"${prefix}"'
AM_CPPFLAGS += -DCONFIGFILE='"${sysconfdir}/${PACKAGE_NAME}.conf"'
AM_CPPFLAGS += -DLOCALSTATEDIR='"${localstatedir}"'
AM_CPPFLAGS += -DPKGLOCALSTATEDIR='"${localstatedir}/lib/${PACKAGE_NAME}"'
AUTOMAKE_OPTIONS = subdir-objects
-sbin_PROGRAMS = collectd collectdmon
+sbin_PROGRAMS = collectdmon
bin_PROGRAMS = collectd-nagios collectdctl collectd-tg
-collectd_SOURCES = collectd.c collectd.h \
- common.c common.h \
- configfile.c configfile.h \
- filter_chain.c filter_chain.h \
- meta_data.c meta_data.h \
- plugin.c plugin.h \
- utils_avltree.c utils_avltree.h \
- utils_cache.c utils_cache.h \
- utils_complain.c utils_complain.h \
- utils_heap.c utils_heap.h \
- utils_ignorelist.c utils_ignorelist.h \
- utils_llist.c utils_llist.h \
- utils_parse_option.c utils_parse_option.h \
- utils_random.c utils_random.h \
- utils_tail_match.c utils_tail_match.h \
- utils_match.c utils_match.h \
- utils_subst.c utils_subst.h \
- utils_tail.c utils_tail.h \
- utils_time.c utils_time.h \
- types_list.c types_list.h \
- utils_threshold.c utils_threshold.h
-
-
-collectd_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL)
-collectd_CFLAGS = $(AM_CFLAGS)
-collectd_LDFLAGS = -export-dynamic
-collectd_LDADD = -lm
-collectd_DEPENDENCIES =
-
-# Link to these libraries..
-if BUILD_WITH_LIBRT
-collectd_LDADD += -lrt
-endif
-if BUILD_WITH_LIBPOSIX4
-collectd_LDADD += -lposix4
-endif
-if BUILD_WITH_LIBSOCKET
-collectd_LDADD += -lsocket
-endif
-if BUILD_WITH_LIBRESOLV
-collectd_LDADD += -lresolv
-endif
-if BUILD_WITH_LIBPTHREAD
-collectd_LDADD += -lpthread
-endif
-if BUILD_WITH_LIBKSTAT
-collectd_LDADD += -lkstat
-endif
-if BUILD_WITH_LIBDEVINFO
-collectd_LDADD += -ldevinfo
-endif
-if BUILD_AIX
-collectd_LDFLAGS += -Wl,-bexpall,-brtllib
-endif
-
-# The daemon needs to call sg_init, so we need to link it against libstatgrab,
-# too. -octo
-if BUILD_WITH_LIBSTATGRAB
-collectd_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
-collectd_LDADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
-endif
-
-if BUILD_WITH_OWN_LIBOCONFIG
-collectd_LDADD += $(LIBLTDL) liboconfig/liboconfig.la
-collectd_DEPENDENCIES += liboconfig/liboconfig.la
-else
-collectd_LDADD += -loconfig
-endif
-
collectdmon_SOURCES = collectdmon.c
collectdmon_CPPFLAGS = $(AM_CPPFLAGS)
collectdctl_DEPENDENCIES = libcollectdclient/libcollectdclient.la
collectd_tg_SOURCES = collectd-tg.c \
- utils_heap.c utils_heap.h
+ daemon/utils_heap.c daemon/utils_heap.h
collectd_tg_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/src/libcollectdclient/collectd
collectd_tg_LDADD =
if BUILD_WITH_LIBSOCKET
utils_vl_lookup.c utils_vl_lookup.h
aggregation_la_LDFLAGS = -module -avoid-version
aggregation_la_LIBADD =
-collectd_LDADD += "-dlopen" aggregation.la
-collectd_DEPENDENCIES += aggregation.la
endif
if BUILD_PLUGIN_AMQP
amqp_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBRABBITMQ_LDFLAGS)
amqp_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBRABBITMQ_CPPFLAGS)
amqp_la_LIBADD = $(BUILD_WITH_LIBRABBITMQ_LIBS)
-collectd_LDADD += "-dlopen" amqp.la
-collectd_DEPENDENCIES += amqp.la
endif
if BUILD_PLUGIN_APACHE
apache_la_LDFLAGS = -module -avoid-version
apache_la_CFLAGS = $(AM_CFLAGS)
apache_la_LIBADD =
-collectd_LDADD += "-dlopen" apache.la
if BUILD_WITH_LIBCURL
apache_la_CFLAGS += $(BUILD_WITH_LIBCURL_CFLAGS)
apache_la_LIBADD += $(BUILD_WITH_LIBCURL_LIBS)
endif
-collectd_DEPENDENCIES += apache.la
endif
if BUILD_PLUGIN_APCUPS
if BUILD_WITH_LIBSOCKET
apcups_la_LIBADD += -lsocket
endif
-collectd_LDADD += "-dlopen" apcups.la
-collectd_DEPENDENCIES += apcups.la
endif
if BUILD_PLUGIN_APPLE_SENSORS
apple_sensors_la_SOURCES = apple_sensors.c
apple_sensors_la_LDFLAGS = -module -avoid-version
apple_sensors_la_LDFLAGS += -framework IOKit
-collectd_LDADD += "-dlopen" apple_sensors.la
-collectd_DEPENDENCIES += apple_sensors.la
endif
if BUILD_PLUGIN_AQUAERO
aquaero_la_LDFLAGS = -module -avoid-version
aquaero_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBAQUAERO5_CFLAGS)
aquaero_la_LIBADD = $(BUILD_WITH_LIBAQUAERO5_LDFLAGS) -laquaero5
-collectd_LDADD += "-dlopen" aquaero.la
-collectd_DEPENDENCIES += aquaero.la
endif
if BUILD_PLUGIN_ASCENT
ascent_la_CFLAGS = $(AM_CFLAGS) \
$(BUILD_WITH_LIBCURL_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
ascent_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
-collectd_LDADD += "-dlopen" ascent.la
-collectd_DEPENDENCIES += ascent.la
endif
if BUILD_PLUGIN_BAROMETER
barometer_la_SOURCES = barometer.c
barometer_la_LDFLAGS = -module -avoid-version
barometer_la_LIBADD = -lm
-collectd_LDADD += "-dlopen" barometer.la
-collectd_DEPENDENCIES += barometer.la
endif
if BUILD_PLUGIN_BATTERY
if BUILD_WITH_LIBIOKIT
battery_la_LDFLAGS += -framework IOKit
endif
-collectd_LDADD += "-dlopen" battery.la
-collectd_DEPENDENCIES += battery.la
endif
if BUILD_PLUGIN_BIND
bind_la_SOURCES = bind.c
bind_la_LDFLAGS = -module -avoid-version
bind_la_CFLAGS = $(AM_CFLAGS) \
- $(BUILD_WITH_LIBCURL_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
+ $(BUILD_WITH_LIBCURL_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
bind_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
-collectd_LDADD += "-dlopen" bind.la
-collectd_DEPENDENCIES += bind.la
endif
if BUILD_PLUGIN_CGROUPS
pkglib_LTLIBRARIES += cgroups.la
-cgroups_la_SOURCES = cgroups.c utils_mount.c utils_mount.h
+cgroups_la_SOURCES = cgroups.c \
+ utils_ignorelist.c utils_ignorelist.h \
+ utils_mount.c utils_mount.h
cgroups_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" cgroups.la
-collectd_DEPENDENCIES += cgroups.la
endif
if BUILD_PLUGIN_CONNTRACK
pkglib_LTLIBRARIES += conntrack.la
conntrack_la_SOURCES = conntrack.c
conntrack_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" conntrack.la
-collectd_DEPENDENCIES += conntrack.la
endif
if BUILD_PLUGIN_CONTEXTSWITCH
if BUILD_WITH_PERFSTAT
contextswitch_la_LIBADD += -lperfstat
endif
-collectd_LDADD += "-dlopen" contextswitch.la
-collectd_DEPENDENCIES += contextswitch.la
endif
if BUILD_PLUGIN_CPU
if BUILD_WITH_PERFSTAT
cpu_la_LIBADD += -lperfstat
endif
-collectd_LDADD += "-dlopen" cpu.la
-collectd_DEPENDENCIES += cpu.la
endif
if BUILD_PLUGIN_CPUFREQ
pkglib_LTLIBRARIES += cpufreq.la
cpufreq_la_SOURCES = cpufreq.c
cpufreq_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" cpufreq.la
-collectd_DEPENDENCIES += cpufreq.la
endif
if BUILD_PLUGIN_CSV
pkglib_LTLIBRARIES += csv.la
csv_la_SOURCES = csv.c
csv_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" csv.la
-collectd_DEPENDENCIES += csv.la
endif
if BUILD_PLUGIN_CURL
curl_la_LDFLAGS = -module -avoid-version
curl_la_CFLAGS = $(AM_CFLAGS)
curl_la_LIBADD =
-collectd_LDADD += "-dlopen" curl.la
if BUILD_WITH_LIBCURL
curl_la_CFLAGS += $(BUILD_WITH_LIBCURL_CFLAGS)
curl_la_LIBADD += $(BUILD_WITH_LIBCURL_LIBS)
endif
-collectd_DEPENDENCIES += curl.la
endif
if BUILD_PLUGIN_CURL_JSON
curl_json_la_SOURCES = curl_json.c
curl_json_la_CFLAGS = $(AM_CFLAGS)
curl_json_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBYAJL_LDFLAGS)
-curl_json_la_CPPFLAGS = $(BUILD_WITH_LIBYAJL_CPPFLAGS)
+curl_json_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
curl_json_la_LIBADD = $(BUILD_WITH_LIBYAJL_LIBS)
if BUILD_WITH_LIBCURL
curl_json_la_CFLAGS += $(BUILD_WITH_LIBCURL_CFLAGS)
curl_json_la_LIBADD += $(BUILD_WITH_LIBCURL_LIBS)
endif
-collectd_LDADD += "-dlopen" curl_json.la
-collectd_DEPENDENCIES += curl_json.la
endif
if BUILD_PLUGIN_CURL_XML
curl_xml_la_CFLAGS = $(AM_CFLAGS) \
$(BUILD_WITH_LIBCURL_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
curl_xml_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
-collectd_LDADD += "-dlopen" curl_xml.la
-collectd_DEPENDENCIES += curl_xml.la
endif
if BUILD_PLUGIN_DBI
dbi_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBDBI_CPPFLAGS)
dbi_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBDBI_LDFLAGS)
dbi_la_LIBADD = $(BUILD_WITH_LIBDBI_LIBS)
-collectd_LDADD += "-dlopen" dbi.la
-collectd_DEPENDENCIES += dbi.la
endif
if BUILD_PLUGIN_DF
pkglib_LTLIBRARIES += df.la
-df_la_SOURCES = df.c utils_mount.c utils_mount.h
+df_la_SOURCES = df.c \
+ utils_ignorelist.c utils_ignorelist.h \
+ utils_mount.c utils_mount.h
df_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" df.la
-collectd_DEPENDENCIES += df.la
endif
if BUILD_PLUGIN_DISK
pkglib_LTLIBRARIES += disk.la
-disk_la_SOURCES = disk.c
+disk_la_SOURCES = disk.c \
+ utils_ignorelist.c utils_ignorelist.h
disk_la_CFLAGS = $(AM_CFLAGS)
disk_la_LDFLAGS = -module -avoid-version
disk_la_LIBADD =
if BUILD_WITH_PERFSTAT
disk_la_LIBADD += -lperfstat
endif
-collectd_LDADD += "-dlopen" disk.la
-collectd_DEPENDENCIES += disk.la
endif
if BUILD_PLUGIN_DNS
dns_la_SOURCES = dns.c utils_dns.c utils_dns.h
dns_la_LDFLAGS = -module -avoid-version
dns_la_LIBADD = -lpcap -lpthread
-collectd_LDADD += "-dlopen" dns.la
-collectd_DEPENDENCIES += dns.la
endif
if BUILD_PLUGIN_DRBD
drbd_la_SOURCES = drbd.c
drbd_la_LDFLAGS = -module -avoid-version
drbd_la_LIBADD = -lpthread
-collectd_LDADD += "-dlopen" drbd.la
-collectd_DEPENDENCIES += drbd.la
endif
if BUILD_PLUGIN_EMAIL
email_la_SOURCES = email.c
email_la_LDFLAGS = -module -avoid-version
email_la_LIBADD = -lpthread
-collectd_LDADD += "-dlopen" email.la
-collectd_DEPENDENCIES += email.la
endif
if BUILD_PLUGIN_ENTROPY
pkglib_LTLIBRARIES += entropy.la
entropy_la_SOURCES = entropy.c
entropy_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" entropy.la
-collectd_DEPENDENCIES += entropy.la
endif
if BUILD_PLUGIN_EXEC
utils_cmd_putval.c utils_cmd_putval.h
exec_la_LDFLAGS = -module -avoid-version
exec_la_LIBADD = -lpthread
-collectd_LDADD += "-dlopen" exec.la
-collectd_DEPENDENCIES += exec.la
endif
if BUILD_PLUGIN_ETHSTAT
pkglib_LTLIBRARIES += ethstat.la
ethstat_la_SOURCES = ethstat.c
ethstat_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" ethstat.la
-collectd_DEPENDENCIES += ethstat.la
endif
if BUILD_PLUGIN_FILECOUNT
pkglib_LTLIBRARIES += filecount.la
filecount_la_SOURCES = filecount.c
filecount_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" filecount.la
-collectd_DEPENDENCIES += filecount.la
endif
if BUILD_PLUGIN_GMOND
gmond_la_CPPFLAGS = $(AM_CPPFLAGS) $(GANGLIA_CPPFLAGS)
gmond_la_LDFLAGS = -module -avoid-version $(GANGLIA_LDFLAGS)
gmond_la_LIBADD = $(GANGLIA_LIBS)
-collectd_LDADD += "-dlopen" gmond.la
-collectd_DEPENDENCIES += gmond.la
endif
if BUILD_PLUGIN_HDDTEMP
if BUILD_WITH_LIBSOCKET
hddtemp_la_LIBADD += -lsocket
endif
-collectd_LDADD += "-dlopen" hddtemp.la
-collectd_DEPENDENCIES += hddtemp.la
endif
if BUILD_PLUGIN_INTERFACE
pkglib_LTLIBRARIES += interface.la
-interface_la_SOURCES = interface.c
+interface_la_SOURCES = interface.c \
+ utils_ignorelist.c utils_ignorelist.h
interface_la_CFLAGS = $(AM_CFLAGS)
interface_la_LDFLAGS = -module -avoid-version
interface_la_LIBADD =
-collectd_LDADD += "-dlopen" interface.la
-collectd_DEPENDENCIES += interface.la
if BUILD_WITH_LIBSTATGRAB
interface_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
interface_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
iptables_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBIPTC_CPPFLAGS)
iptables_la_LDFLAGS = -module -avoid-version
iptables_la_LIBADD = $(BUILD_WITH_LIBIPTC_LDFLAGS)
-collectd_LDADD += "-dlopen" iptables.la
-collectd_DEPENDENCIES += iptables.la
endif
if BUILD_PLUGIN_IPMI
pkglib_LTLIBRARIES += ipmi.la
-ipmi_la_SOURCES = ipmi.c
+ipmi_la_SOURCES = ipmi.c \
+ utils_ignorelist.c utils_ignorelist.h
ipmi_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_OPENIPMI_CFLAGS)
ipmi_la_LDFLAGS = -module -avoid-version
ipmi_la_LIBADD = $(BUILD_WITH_OPENIPMI_LIBS)
-collectd_LDADD += "-dlopen" ipmi.la
-collectd_DEPENDENCIES += ipmi.la
endif
if BUILD_PLUGIN_IPVS
ipvs_la_CFLAGS = $(AM_CFLAGS) $(KERNEL_CFLAGS)
endif
ipvs_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" ipvs.la
-collectd_DEPENDENCIES += ipvs.la
endif
if BUILD_PLUGIN_IRQ
pkglib_LTLIBRARIES += irq.la
-irq_la_SOURCES = irq.c
+irq_la_SOURCES = irq.c \
+ utils_ignorelist.c utils_ignorelist.h
irq_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" irq.la
-collectd_DEPENDENCIES += irq.la
endif
if BUILD_PLUGIN_JAVA
java_la_CFLAGS = $(AM_CFLAGS) $(JAVA_CFLAGS)
java_la_LDFLAGS = -module -avoid-version $(JAVA_LDFLAGS)
java_la_LIBADD = $(JAVA_LIBS)
-collectd_LDADD += "-dlopen" java.la
-collectd_DEPENDENCIES += java.la
endif
if BUILD_PLUGIN_LOAD
load_la_CFLAGS = $(AM_CFLAGS)
load_la_LDFLAGS = -module -avoid-version
load_la_LIBADD =
-collectd_LDADD += "-dlopen" load.la
-collectd_DEPENDENCIES += load.la
if BUILD_WITH_LIBSTATGRAB
load_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
load_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
pkglib_LTLIBRARIES += logfile.la
logfile_la_SOURCES = logfile.c
logfile_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" logfile.la
-collectd_DEPENDENCIES += logfile.la
endif
if BUILD_PLUGIN_LOG_LOGSTASH
log_logstash_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBYAJL_LDFLAGS)
log_logstash_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
log_logstash_la_LIBADD = $(BUILD_WITH_LIBYAJL_LIBS)
-collectd_LDADD += "-dlopen" log_logstash.la
-collectd_DEPENDENCIES += log_logstash.la
endif
if BUILD_PLUGIN_LPAR
pkglib_LTLIBRARIES += lpar.la
lpar_la_SOURCES = lpar.c
lpar_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" lpar.la
-collectd_DEPENDENCIES += lpar.la
lpar_la_LIBADD = -lperfstat
endif
lvm_la_SOURCES = lvm.c
lvm_la_LDFLAGS = -module -avoid-version
lvm_la_LIBADD = $(BUILD_WITH_LIBLVM2APP_LIBS)
-collectd_LDADD += "-dlopen" lvm.la
-collectd_DEPENDENCIES += lvm.la
endif
if BUILD_PLUGIN_MADWIFI
pkglib_LTLIBRARIES += madwifi.la
-madwifi_la_SOURCES = madwifi.c madwifi.h
+madwifi_la_SOURCES = madwifi.c madwifi.h \
+ utils_ignorelist.c utils_ignorelist.h
madwifi_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" madwifi.la
-collectd_DEPENDENCIES += madwifi.la
endif
if BUILD_PLUGIN_MATCH_EMPTY_COUNTER
pkglib_LTLIBRARIES += match_empty_counter.la
match_empty_counter_la_SOURCES = match_empty_counter.c
match_empty_counter_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" match_empty_counter.la
-collectd_DEPENDENCIES += match_empty_counter.la
endif
if BUILD_PLUGIN_MATCH_HASHED
pkglib_LTLIBRARIES += match_hashed.la
match_hashed_la_SOURCES = match_hashed.c
match_hashed_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" match_hashed.la
-collectd_DEPENDENCIES += match_hashed.la
endif
if BUILD_PLUGIN_MATCH_REGEX
pkglib_LTLIBRARIES += match_regex.la
match_regex_la_SOURCES = match_regex.c
match_regex_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" match_regex.la
-collectd_DEPENDENCIES += match_regex.la
endif
if BUILD_PLUGIN_MATCH_TIMEDIFF
pkglib_LTLIBRARIES += match_timediff.la
match_timediff_la_SOURCES = match_timediff.c
match_timediff_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" match_timediff.la
-collectd_DEPENDENCIES += match_timediff.la
endif
if BUILD_PLUGIN_MATCH_VALUE
pkglib_LTLIBRARIES += match_value.la
match_value_la_SOURCES = match_value.c
match_value_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" match_value.la
-collectd_DEPENDENCIES += match_value.la
endif
if BUILD_PLUGIN_MBMON
if BUILD_WITH_LIBSOCKET
mbmon_la_LIBADD += -lsocket
endif
-collectd_LDADD += "-dlopen" mbmon.la
-collectd_DEPENDENCIES += mbmon.la
endif
if BUILD_PLUGIN_MD
pkglib_LTLIBRARIES += md.la
-md_la_SOURCES = md.c
+md_la_SOURCES = md.c \
+ utils_ignorelist.c utils_ignorelist.h
md_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" md.la
-collectd_DEPENDENCIES += md.la
endif
if BUILD_PLUGIN_MEMCACHEC
pkglib_LTLIBRARIES += memcachec.la
memcachec_la_SOURCES = memcachec.c
memcachec_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBMEMCACHED_LDFLAGS)
-memcachec_la_CPPFLAGS = $(BUILD_WITH_LIBMEMCACHED_CPPFLAGS)
+memcachec_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBMEMCACHED_CPPFLAGS)
memcachec_la_LIBADD = $(BUILD_WITH_LIBMEMCACHED_LIBS)
-collectd_LDADD += "-dlopen" memcachec.la
-collectd_DEPENDENCIES += memcachec.la
endif
if BUILD_PLUGIN_MEMCACHED
if BUILD_WITH_LIBSOCKET
memcached_la_LIBADD += -lsocket
endif
-collectd_LDADD += "-dlopen" memcached.la
-collectd_DEPENDENCIES += memcached.la
endif
if BUILD_PLUGIN_MEMORY
memory_la_CFLAGS = $(AM_CFLAGS)
memory_la_LDFLAGS = -module -avoid-version
memory_la_LIBADD =
-collectd_LDADD += "-dlopen" memory.la
-collectd_DEPENDENCIES += memory.la
if BUILD_WITH_LIBKSTAT
memory_la_LIBADD += -lkstat
endif
endif
endif
+if BUILD_PLUGIN_MIC
+pkglib_LTLIBRARIES += mic.la
+mic_la_SOURCES = mic.c \
+ utils_ignorelist.c utils_ignorelist.h
+mic_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_MIC_LIBPATH)
+mic_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_MIC_CPPFLAGS)
+mic_la_LIBADD = $(BUILD_WITH_MIC_LDADD)
+endif
+
if BUILD_PLUGIN_MODBUS
pkglib_LTLIBRARIES += modbus.la
modbus_la_SOURCES = modbus.c
modbus_la_LDFLAGS = -module -avoid-version
modbus_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBMODBUS_CFLAGS)
modbus_la_LIBADD = $(BUILD_WITH_LIBMODBUS_LIBS)
-collectd_LDADD += "-dlopen" modbus.la
-collectd_DEPENDENCIES += modbus.la
endif
if BUILD_PLUGIN_MULTIMETER
pkglib_LTLIBRARIES += multimeter.la
multimeter_la_SOURCES = multimeter.c
multimeter_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" multimeter.la
-collectd_DEPENDENCIES += multimeter.la
endif
if BUILD_PLUGIN_MYSQL
mysql_la_LDFLAGS = -module -avoid-version
mysql_la_CFLAGS = $(AM_CFLAGS)
mysql_la_LIBADD =
-collectd_LDADD += "-dlopen" mysql.la
if BUILD_WITH_LIBMYSQL
mysql_la_CFLAGS += $(BUILD_WITH_LIBMYSQL_CFLAGS)
mysql_la_LIBADD += $(BUILD_WITH_LIBMYSQL_LIBS)
endif
-collectd_DEPENDENCIES += mysql.la
endif
if BUILD_PLUGIN_NETAPP
pkglib_LTLIBRARIES += netapp.la
-netapp_la_SOURCES = netapp.c
+netapp_la_SOURCES = netapp.c \
+ utils_ignorelist.c utils_ignorelist.h
netapp_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBNETAPP_CPPFLAGS)
netapp_la_LDFLAGS = -module -avoid-version $(LIBNETAPP_LDFLAGS)
netapp_la_LIBADD = $(LIBNETAPP_LIBS)
-collectd_LDADD += "-dlopen" netapp.la
-collectd_DEPENDENCIES += netapp.la
endif
if BUILD_PLUGIN_NETLINK
netlink_la_LDFLAGS = -module -avoid-version
netlink_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBMNL_CFLAGS)
netlink_la_LIBADD = $(BUILD_WITH_LIBMNL_LIBS)
-collectd_LDADD += "-dlopen" netlink.la
-collectd_DEPENDENCIES += netlink.la
endif
if BUILD_PLUGIN_NETWORK
network_la_LDFLAGS += $(GCRYPT_LDFLAGS)
network_la_LIBADD += $(GCRYPT_LIBS)
endif
-collectd_LDADD += "-dlopen" network.la
-collectd_DEPENDENCIES += network.la
endif
if BUILD_PLUGIN_NFS
pkglib_LTLIBRARIES += nfs.la
nfs_la_SOURCES = nfs.c
nfs_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" nfs.la
-collectd_DEPENDENCIES += nfs.la
endif
if BUILD_PLUGIN_FSCACHE
pkglib_LTLIBRARIES += fscache.la
fscache_la_SOURCES = fscache.c
fscache_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" fscache.la
-collectd_DEPENDENCIES += fscache.la
endif
if BUILD_PLUGIN_NGINX
nginx_la_CFLAGS += $(BUILD_WITH_LIBCURL_CFLAGS)
nginx_la_LIBADD += $(BUILD_WITH_LIBCURL_LIBS)
endif
-collectd_LDADD += "-dlopen" nginx.la
-collectd_DEPENDENCIES += nginx.la
endif
if BUILD_PLUGIN_NOTIFY_DESKTOP
notify_desktop_la_CFLAGS = $(AM_CFLAGS) $(LIBNOTIFY_CFLAGS)
notify_desktop_la_LDFLAGS = -module -avoid-version
notify_desktop_la_LIBADD = $(LIBNOTIFY_LIBS)
-collectd_LDADD += "-dlopen" notify_desktop.la
-collectd_DEPENDENCIES += notify_desktop.la
endif
if BUILD_PLUGIN_NOTIFY_EMAIL
notify_email_la_SOURCES = notify_email.c
notify_email_la_LDFLAGS = -module -avoid-version
notify_email_la_LIBADD = -lesmtp -lssl -lcrypto -lpthread -ldl
-collectd_LDADD += "-dlopen" notify_email.la
-collectd_DEPENDENCIES += notify_email.la
endif
if BUILD_PLUGIN_NTPD
if BUILD_WITH_LIBSOCKET
ntpd_la_LIBADD += -lsocket
endif
-collectd_LDADD += "-dlopen" ntpd.la
-collectd_DEPENDENCIES += ntpd.la
endif
if BUILD_PLUGIN_NUMA
pkglib_LTLIBRARIES += numa.la
numa_la_SOURCES = numa.c
numa_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" numa.la
-collectd_DEPENDENCIES += numa.la
endif
if BUILD_PLUGIN_NUT
nut_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBUPSCLIENT_CFLAGS)
nut_la_LDFLAGS = -module -avoid-version
nut_la_LIBADD = -lpthread $(BUILD_WITH_LIBUPSCLIENT_LIBS)
-collectd_LDADD += "-dlopen" nut.la
-collectd_DEPENDENCIES += nut.la
endif
if BUILD_PLUGIN_OLSRD
if BUILD_WITH_LIBSOCKET
olsrd_la_LIBADD += -lsocket
endif
-collectd_LDADD += "-dlopen" olsrd.la
-collectd_DEPENDENCIES += olsrd.la
endif
if BUILD_PLUGIN_ONEWIRE
pkglib_LTLIBRARIES += onewire.la
-onewire_la_SOURCES = onewire.c
+onewire_la_SOURCES = onewire.c \
+ utils_ignorelist.c utils_ignorelist.h
onewire_la_CFLAGS = $(AM_CFLAGS)
-onewire_la_CPPFLAGS = $(BUILD_WITH_LIBOWCAPI_CPPFLAGS)
+onewire_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBOWCAPI_CPPFLAGS)
onewire_la_LIBADD = $(BUILD_WITH_LIBOWCAPI_LIBS)
onewire_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" onewire.la
-collectd_DEPENDENCIES += onewire.la
endif
if BUILD_PLUGIN_OPENVPN
openvpn_la_SOURCES = openvpn.c
openvpn_la_CFLAGS = $(AM_CFLAGS)
openvpn_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" openvpn.la
-collectd_DEPENDENCIES += openvpn.la
endif
if BUILD_PLUGIN_ORACLE
oracle_la_SOURCES = oracle.c \
utils_db_query.c utils_db_query.h
oracle_la_CFLAGS = $(AM_CFLAGS)
-oracle_la_CPPFLAGS = $(BUILD_WITH_ORACLE_CFLAGS)
+oracle_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_ORACLE_CFLAGS)
oracle_la_LIBADD = $(BUILD_WITH_ORACLE_LIBS)
oracle_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" oracle.la
-collectd_DEPENDENCIES += oracle.la
endif
if BUILD_PLUGIN_PERL
endif
perl_la_LDFLAGS = -module -avoid-version \
$(PERL_LDFLAGS)
-collectd_LDADD += "-dlopen" perl.la
-collectd_DEPENDENCIES += perl.la
endif
if BUILD_PLUGIN_PF
pkglib_LTLIBRARIES += pf.la
pf_la_SOURCES = pf.c
pf_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" pf.la
-collectd_DEPENDENCIES += pf.la
endif
if BUILD_PLUGIN_PINBA
nodist_pinba_la_SOURCES = pinba.pb-c.c pinba.pb-c.h
pinba_la_LDFLAGS = -module -avoid-version
pinba_la_LIBADD = -lprotobuf-c
-collectd_LDADD += "-dlopen" pinba.la
-collectd_DEPENDENCIES += pinba.la
endif
if BUILD_PLUGIN_PING
ping_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBOPING_CPPFLAGS)
ping_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBOPING_LDFLAGS)
ping_la_LIBADD = -loping -lm
-collectd_LDADD += "-dlopen" ping.la
-collectd_DEPENDENCIES += ping.la
endif
if BUILD_PLUGIN_POSTGRESQL
postgresql_la_LDFLAGS = -module -avoid-version \
$(BUILD_WITH_LIBPQ_LDFLAGS)
postgresql_la_LIBADD = -lpq
-collectd_LDADD += "-dlopen" postgresql.la
-collectd_DEPENDENCIES += postgresql.la
endif
if BUILD_PLUGIN_POWERDNS
pkglib_LTLIBRARIES += powerdns.la
powerdns_la_SOURCES = powerdns.c
powerdns_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" powerdns.la
-collectd_DEPENDENCIES += powerdns.la
endif
if BUILD_PLUGIN_PYTHON
endif
python_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_PYTHON_LDFLAGS)
python_la_LIBADD = $(BUILD_WITH_PYTHON_LIBS)
-collectd_LDADD += "-dlopen" python.la
-collectd_DEPENDENCIES += python.la
endif
if BUILD_PLUGIN_PROCESSES
processes_la_SOURCES = processes.c
processes_la_LDFLAGS = -module -avoid-version
processes_la_LIBADD =
-collectd_LDADD += "-dlopen" processes.la
-collectd_DEPENDENCIES += processes.la
if BUILD_WITH_LIBKVM_GETPROCS
processes_la_LIBADD += -lkvm
endif
if BUILD_PLUGIN_PROTOCOLS
pkglib_LTLIBRARIES += protocols.la
-protocols_la_SOURCES = protocols.c
+protocols_la_SOURCES = protocols.c \
+ utils_ignorelist.c utils_ignorelist.h
protocols_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" protocols.la
-collectd_DEPENDENCIES += protocols.la
endif
if BUILD_PLUGIN_REDIS
redis_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBCREDIS_LDFLAGS)
redis_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCREDIS_CPPFLAGS)
redis_la_LIBADD = -lcredis
-collectd_LDADD += "-dlopen" redis.la
-collectd_DEPENDENCIES += redis.la
endif
if BUILD_PLUGIN_ROUTEROS
pkglib_LTLIBRARIES += routeros.la
routeros_la_SOURCES = routeros.c
-routeros_la_CPPFLAGS = $(BUILD_WITH_LIBROUTEROS_CPPFLAGS)
+routeros_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBROUTEROS_CPPFLAGS)
routeros_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBROUTEROS_LDFLAGS)
routeros_la_LIBADD = -lrouteros
-collectd_LDADD += "-dlopen" routeros.la
-collectd_DEPENDENCIES += routeros.la
endif
if BUILD_PLUGIN_RRDCACHED
rrdcached_la_LDFLAGS = -module -avoid-version
rrdcached_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBRRD_CFLAGS)
rrdcached_la_LIBADD = $(BUILD_WITH_LIBRRD_LDFLAGS)
-collectd_LDADD += "-dlopen" rrdcached.la
-collectd_DEPENDENCIES += rrdcached.la
endif
if BUILD_PLUGIN_RRDTOOL
rrdtool_la_LDFLAGS = -module -avoid-version
rrdtool_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBRRD_CFLAGS)
rrdtool_la_LIBADD = $(BUILD_WITH_LIBRRD_LDFLAGS)
-collectd_LDADD += "-dlopen" rrdtool.la
-collectd_DEPENDENCIES += rrdtool.la
endif
if BUILD_PLUGIN_SENSORS
pkglib_LTLIBRARIES += sensors.la
-sensors_la_SOURCES = sensors.c
+sensors_la_SOURCES = sensors.c \
+ utils_ignorelist.c utils_ignorelist.h
sensors_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBSENSORS_CFLAGS)
sensors_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBSENSORS_LDFLAGS)
sensors_la_LIBADD = -lsensors
-collectd_LDADD += "-dlopen" sensors.la
-collectd_DEPENDENCIES += sensors.la
endif
if BUILD_PLUGIN_SERIAL
pkglib_LTLIBRARIES += serial.la
serial_la_SOURCES = serial.c
serial_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" serial.la
-collectd_DEPENDENCIES += serial.la
endif
if BUILD_PLUGIN_SIGROK
sigrok_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBSIGROK_CFLAGS)
sigrok_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBSIGROK_LDFLAGS)
sigrok_la_LIBADD = -lsigrok
-collectd_LDADD += "-dlopen" sigrok.la
-collectd_DEPENDENCIES += sigrok.la
endif
if BUILD_PLUGIN_SNMP
if BUILD_WITH_LIBPTHREAD
snmp_la_LIBADD += -lpthread
endif
-collectd_LDADD += "-dlopen" snmp.la
-collectd_DEPENDENCIES += snmp.la
endif
if BUILD_PLUGIN_STATSD
utils_latency.h utils_latency.c
statsd_la_LDFLAGS = -module -avoid-version
statsd_la_LIBADD = -lpthread
-collectd_LDADD += "-dlopen" statsd.la
-collectd_DEPENDENCIES += statsd.la
endif
if BUILD_PLUGIN_SWAP
swap_la_CFLAGS = $(AM_CFLAGS)
swap_la_LDFLAGS = -module -avoid-version
swap_la_LIBADD =
-collectd_LDADD += "-dlopen" swap.la
-collectd_DEPENDENCIES += swap.la
if BUILD_WITH_LIBKSTAT
swap_la_LIBADD += -lkstat
endif
pkglib_LTLIBRARIES += syslog.la
syslog_la_SOURCES = syslog.c
syslog_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" syslog.la
-collectd_DEPENDENCIES += syslog.la
endif
if BUILD_PLUGIN_TABLE
pkglib_LTLIBRARIES += table.la
table_la_SOURCES = table.c
table_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" table.la
-collectd_DEPENDENCIES += table.la
endif
if BUILD_PLUGIN_TAIL
pkglib_LTLIBRARIES += tail.la
tail_la_SOURCES = tail.c
tail_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" tail.la
-collectd_DEPENDENCIES += tail.la
endif
if BUILD_PLUGIN_TAIL_CSV
pkglib_LTLIBRARIES += tail_csv.la
tail_csv_la_SOURCES = tail_csv.c
tail_csv_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" tail_csv.la
-collectd_DEPENDENCIES += tail_csv.la
endif
if BUILD_PLUGIN_TAPE
tape_la_SOURCES = tape.c
tape_la_LDFLAGS = -module -avoid-version
tape_la_LIBADD = -lkstat -ldevinfo
-collectd_LDADD += "-dlopen" tape.la
-collectd_DEPENDENCIES += tape.la
endif
if BUILD_PLUGIN_TARGET_NOTIFICATION
pkglib_LTLIBRARIES += target_notification.la
target_notification_la_SOURCES = target_notification.c
target_notification_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" target_notification.la
-collectd_DEPENDENCIES += target_notification.la
endif
if BUILD_PLUGIN_TARGET_REPLACE
pkglib_LTLIBRARIES += target_replace.la
target_replace_la_SOURCES = target_replace.c
target_replace_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" target_replace.la
-collectd_DEPENDENCIES += target_replace.la
endif
if BUILD_PLUGIN_TARGET_SCALE
pkglib_LTLIBRARIES += target_scale.la
target_scale_la_SOURCES = target_scale.c
target_scale_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" target_scale.la
-collectd_DEPENDENCIES += target_scale.la
endif
if BUILD_PLUGIN_TARGET_SET
pkglib_LTLIBRARIES += target_set.la
target_set_la_SOURCES = target_set.c
target_set_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" target_set.la
-collectd_DEPENDENCIES += target_set.la
endif
if BUILD_PLUGIN_TARGET_V5UPGRADE
pkglib_LTLIBRARIES += target_v5upgrade.la
target_v5upgrade_la_SOURCES = target_v5upgrade.c
target_v5upgrade_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" target_v5upgrade.la
-collectd_DEPENDENCIES += target_v5upgrade.la
endif
if BUILD_PLUGIN_TCPCONNS
tcpconns_la_SOURCES = tcpconns.c
tcpconns_la_LDFLAGS = -module -avoid-version
tcpconns_la_LIBADD =
-collectd_LDADD += "-dlopen" tcpconns.la
-collectd_DEPENDENCIES += tcpconns.la
if BUILD_WITH_LIBKVM_NLIST
tcpconns_la_LIBADD += -lkvm
endif
pkglib_LTLIBRARIES += teamspeak2.la
teamspeak2_la_SOURCES = teamspeak2.c
teamspeak2_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" teamspeak2.la
-collectd_DEPENDENCIES += teamspeak2.la
endif
if BUILD_PLUGIN_TED
pkglib_LTLIBRARIES += ted.la
ted_la_SOURCES = ted.c
ted_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" ted.la
-collectd_DEPENDENCIES += ted.la
endif
if BUILD_PLUGIN_THERMAL
pkglib_LTLIBRARIES += thermal.la
-thermal_la_SOURCES = thermal.c
+thermal_la_SOURCES = thermal.c \
+ utils_ignorelist.c utils_ignorelist.h
thermal_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" thermal.la
-collectd_DEPENDENCIES += thermal.la
endif
if BUILD_PLUGIN_THRESHOLD
pkglib_LTLIBRARIES += threshold.la
threshold_la_SOURCES = threshold.c
threshold_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" threshold.la
-collectd_DEPENDENCIES += threshold.la
endif
if BUILD_PLUGIN_TOKYOTYRANT
if BUILD_WITH_LIBSOCKET
tokyotyrant_la_LIBADD += -lsocket
endif
-collectd_LDADD += "-dlopen" tokyotyrant.la
-collectd_DEPENDENCIES += tokyotyrant.la
endif
if BUILD_PLUGIN_UNIXSOCK
utils_cmd_putnotif.h utils_cmd_putnotif.c
unixsock_la_LDFLAGS = -module -avoid-version
unixsock_la_LIBADD = -lpthread
-collectd_LDADD += "-dlopen" unixsock.la
-collectd_DEPENDENCIES += unixsock.la
endif
if BUILD_PLUGIN_UPTIME
if BUILD_WITH_PERFSTAT
uptime_la_LIBADD += -lperfstat
endif
-collectd_LDADD += "-dlopen" uptime.la
-collectd_DEPENDENCIES += uptime.la
endif
if BUILD_PLUGIN_USERS
users_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
users_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
endif
-collectd_LDADD += "-dlopen" users.la
-collectd_DEPENDENCIES += users.la
endif
if BUILD_PLUGIN_UUID
uuid_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBHAL_CFLAGS)
uuid_la_LIBADD = $(BUILD_WITH_LIBHAL_LIBS)
uuid_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" uuid.la
-collectd_DEPENDENCIES += uuid.la
-endif
-
-if BUILD_PLUGIN_MIC
-pkglib_LTLIBRARIES += mic.la
-mic_la_SOURCES = mic.c
-mic_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_MIC_LIBPATH)
-mic_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_MIC_CPPFLAGS)
-mic_la_LIBADD = $(BUILD_WITH_MIC_LDADD)
-collectd_LDADD += "-dlopen" mic.la
-collectd_DEPENDENCIES += mic.la
endif
if BUILD_PLUGIN_VARNISH
varnish_la_LDFLAGS = -module -avoid-version
varnish_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBVARNISH_CFLAGS)
varnish_la_LIBADD = $(BUILD_WITH_LIBVARNISH_LIBS)
-collectd_LDADD += "-dlopen" varnish.la
-collectd_DEPENDENCIES += varnish.la
endif
if BUILD_PLUGIN_VIRT
pkglib_LTLIBRARIES += virt.la
-virt_la_SOURCES = virt.c
+virt_la_SOURCES = virt.c \
+ utils_ignorelist.c utils_ignorelist.h
virt_la_CFLAGS = $(AM_CFLAGS) \
$(BUILD_WITH_LIBVIRT_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
virt_la_LIBADD = $(BUILD_WITH_LIBVIRT_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
virt_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" virt.la
-collectd_DEPENDENCIES += virt.la
endif
if BUILD_PLUGIN_VMEM
pkglib_LTLIBRARIES += vmem.la
vmem_la_SOURCES = vmem.c
vmem_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" vmem.la
-collectd_DEPENDENCIES += vmem.la
endif
if BUILD_PLUGIN_VSERVER
pkglib_LTLIBRARIES += vserver.la
vserver_la_SOURCES = vserver.c
vserver_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" vserver.la
-collectd_DEPENDENCIES += vserver.la
endif
if BUILD_PLUGIN_WIRELESS
pkglib_LTLIBRARIES += wireless.la
wireless_la_SOURCES = wireless.c
wireless_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" wireless.la
-collectd_DEPENDENCIES += wireless.la
endif
if BUILD_PLUGIN_WRITE_GRAPHITE
utils_format_graphite.c utils_format_graphite.h \
utils_format_json.c utils_format_json.h
write_graphite_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" write_graphite.la
-collectd_DEPENDENCIES += write_graphite.la
endif
if BUILD_PLUGIN_WRITE_HTTP
write_http_la_LDFLAGS = -module -avoid-version
write_http_la_CFLAGS = $(AM_CFLAGS)
write_http_la_LIBADD =
-collectd_LDADD += "-dlopen" write_http.la
if BUILD_WITH_LIBCURL
write_http_la_CFLAGS += $(BUILD_WITH_LIBCURL_CFLAGS)
write_http_la_LIBADD += $(BUILD_WITH_LIBCURL_LIBS)
endif
-collectd_DEPENDENCIES += write_http.la
endif
if BUILD_PLUGIN_WRITE_KAFKA
utils_crc32.c utils_crc32.h
write_kafka_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBRDKAFKA_LDFLAGS)
write_kafka_la_LIBADD = $(BUILD_WITH_LIBRDKAFKA_LIBS)
-collectd_LDADD += "-dlopen" write_kafka.la
-collectd_DEPENDENCIES += write_kafka.la
endif
if BUILD_PLUGIN_WRITE_MONGODB
write_mongodb_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBMONGOC_CPPFLAGS)
write_mongodb_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBMONGOC_LDFLAGS)
write_mongodb_la_LIBADD = -lmongoc
-collectd_LDADD += "-dlopen" write_mongodb.la
-collectd_DEPENDENCIES += write_mongodb.la
endif
if BUILD_PLUGIN_WRITE_REDIS
write_redis_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBCREDIS_LDFLAGS)
write_redis_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCREDIS_CPPFLAGS)
write_redis_la_LIBADD = -lcredis
-collectd_LDADD += "-dlopen" write_redis.la
-collectd_DEPENDENCIES += write_redis.la
endif
if BUILD_PLUGIN_WRITE_RIEMANN
nodist_write_riemann_la_SOURCES = riemann.pb-c.c riemann.pb-c.h
write_riemann_la_LDFLAGS = -module -avoid-version
write_riemann_la_LIBADD = -lprotobuf-c
-collectd_LDADD += "-dlopen" write_riemann.la
-collectd_DEPENDENCIES += write_riemann.la
endif
if BUILD_PLUGIN_WRITE_TSDB
pkglib_LTLIBRARIES += write_tsdb.la
write_tsdb_la_SOURCES = write_tsdb.c
write_tsdb_la_LDFLAGS = -module -avoid-version
-collectd_LDADD += "-dlopen" write_tsdb.la
-collectd_DEPENDENCIES += write_tsdb.la
endif
if BUILD_PLUGIN_XMMS
xmms_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBXMMS_CFLAGS)
xmms_la_LDFLAGS = -module -avoid-version
xmms_la_LIBADD = $(BUILD_WITH_LIBXMMS_LIBS)
-collectd_LDADD += "-dlopen" xmms.la
-collectd_DEPENDENCIES += xmms.la
endif
if BUILD_PLUGIN_ZFS_ARC
zfs_arc_la_LIBADD = -lkstat
endif
endif
-collectd_LDADD += "-dlopen" zfs_arc.la
-collectd_DEPENDENCIES += zfs_arc.la
endif
BUILT_SOURCES += $(dist_man_MANS)
diff --git a/src/collectd.c b/src/collectd.c
--- a/src/collectd.c
+++ /dev/null
@@ -1,637 +0,0 @@
-/**
- * collectd - src/collectd.c
- * Copyright (C) 2005-2007 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- * Alvaro Barcellos <alvaro.barcellos at gmail.com>
- **/
-
-#include "collectd.h"
-#include "common.h"
-
-#include "plugin.h"
-#include "configfile.h"
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-
-#include <pthread.h>
-
-#if HAVE_LOCALE_H
-# include <locale.h>
-#endif
-
-#if HAVE_STATGRAB_H
-# include <statgrab.h>
-#endif
-
-#ifndef COLLECTD_LOCALE
-# define COLLECTD_LOCALE "C"
-#endif
-
-/*
- * Global variables
- */
-char hostname_g[DATA_MAX_NAME_LEN];
-cdtime_t interval_g;
-int pidfile_from_cli = 0;
-int timeout_g;
-#if HAVE_LIBKSTAT
-kstat_ctl_t *kc;
-#endif /* HAVE_LIBKSTAT */
-
-static int loop = 0;
-
-static void *do_flush (void __attribute__((unused)) *arg)
-{
- INFO ("Flushing all data.");
- plugin_flush (/* plugin = */ NULL,
- /* timeout = */ 0,
- /* ident = */ NULL);
- INFO ("Finished flushing all data.");
- pthread_exit (NULL);
- return NULL;
-}
-
-static void sig_int_handler (int __attribute__((unused)) signal)
-{
- loop++;
-}
-
-static void sig_term_handler (int __attribute__((unused)) signal)
-{
- loop++;
-}
-
-static void sig_usr1_handler (int __attribute__((unused)) signal)
-{
- pthread_t thread;
- pthread_attr_t attr;
-
- /* flushing the data might take a while,
- * so it should be done asynchronously */
- pthread_attr_init (&attr);
- pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
- pthread_create (&thread, &attr, do_flush, NULL);
- pthread_attr_destroy (&attr);
-}
-
-static int init_hostname (void)
-{
- const char *str;
-
- struct addrinfo ai_hints;
- struct addrinfo *ai_list;
- struct addrinfo *ai_ptr;
- int status;
-
- str = global_option_get ("Hostname");
- if (str != NULL)
- {
- sstrncpy (hostname_g, str, sizeof (hostname_g));
- return (0);
- }
-
- if (gethostname (hostname_g, sizeof (hostname_g)) != 0)
- {
- fprintf (stderr, "`gethostname' failed and no "
- "hostname was configured.\n");
- return (-1);
- }
-
- str = global_option_get ("FQDNLookup");
- if (IS_FALSE (str))
- return (0);
-
- memset (&ai_hints, '\0', sizeof (ai_hints));
- ai_hints.ai_flags = AI_CANONNAME;
-
- status = getaddrinfo (hostname_g, NULL, &ai_hints, &ai_list);
- if (status != 0)
- {
- ERROR ("Looking up \"%s\" failed. You have set the "
- "\"FQDNLookup\" option, but I cannot resolve "
- "my hostname to a fully qualified domain "
- "name. Please fix the network "
- "configuration.", hostname_g);
- return (-1);
- }
-
- for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
- {
- if (ai_ptr->ai_canonname == NULL)
- continue;
-
- sstrncpy (hostname_g, ai_ptr->ai_canonname, sizeof (hostname_g));
- break;
- }
-
- freeaddrinfo (ai_list);
- return (0);
-} /* int init_hostname */
-
-static int init_global_variables (void)
-{
- char const *str;
-
- interval_g = cf_get_default_interval ();
- assert (interval_g > 0);
- DEBUG ("interval_g = %.3f;", CDTIME_T_TO_DOUBLE (interval_g));
-
- str = global_option_get ("Timeout");
- if (str == NULL)
- str = "2";
- timeout_g = atoi (str);
- if (timeout_g <= 1)
- {
- fprintf (stderr, "Cannot set the timeout to a correct value.\n"
- "Please check your settings.\n");
- return (-1);
- }
- DEBUG ("timeout_g = %i;", timeout_g);
-
- if (init_hostname () != 0)
- return (-1);
- DEBUG ("hostname_g = %s;", hostname_g);
-
- return (0);
-} /* int init_global_variables */
-
-static int change_basedir (const char *orig_dir)
-{
- char *dir;
- size_t dirlen;
- int status;
-
- dir = strdup (orig_dir);
- if (dir == NULL)
- {
- char errbuf[1024];
- ERROR ("strdup failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (-1);
- }
-
- dirlen = strlen (dir);
- while ((dirlen > 0) && (dir[dirlen - 1] == '/'))
- dir[--dirlen] = '\0';
-
- if (dirlen <= 0)
- return (-1);
-
- status = chdir (dir);
- if (status == 0)
- {
- free (dir);
- return (0);
- }
- else if (errno != ENOENT)
- {
- char errbuf[1024];
- ERROR ("change_basedir: chdir (%s): %s", dir,
- sstrerror (errno, errbuf, sizeof (errbuf)));
- free (dir);
- return (-1);
- }
-
- status = mkdir (dir, S_IRWXU | S_IRWXG | S_IRWXO);
- if (status != 0)
- {
- char errbuf[1024];
- ERROR ("change_basedir: mkdir (%s): %s", dir,
- sstrerror (errno, errbuf, sizeof (errbuf)));
- free (dir);
- return (-1);
- }
-
- status = chdir (dir);
- if (status != 0)
- {
- char errbuf[1024];
- ERROR ("change_basedir: chdir (%s): %s", dir,
- sstrerror (errno, errbuf, sizeof (errbuf)));
- free (dir);
- return (-1);
- }
-
- free (dir);
- return (0);
-} /* static int change_basedir (char *dir) */
-
-#if HAVE_LIBKSTAT
-static void update_kstat (void)
-{
- if (kc == NULL)
- {
- if ((kc = kstat_open ()) == NULL)
- ERROR ("Unable to open kstat control structure");
- }
- else
- {
- kid_t kid;
- kid = kstat_chain_update (kc);
- if (kid > 0)
- {
- INFO ("kstat chain has been updated");
- plugin_init_all ();
- }
- else if (kid < 0)
- ERROR ("kstat chain update failed");
- /* else: everything works as expected */
- }
-
- return;
-} /* static void update_kstat (void) */
-#endif /* HAVE_LIBKSTAT */
-
-/* TODO
- * Remove all settings but `-f' and `-C'
- */
-static void exit_usage (int status)
-{
- printf ("Usage: "PACKAGE" [OPTIONS]\n\n"
-
- "Available options:\n"
- " General:\n"
- " -C <file> Configuration file.\n"
- " Default: "CONFIGFILE"\n"
- " -t Test config and exit.\n"
- " -T Test plugin read and exit.\n"
- " -P <file> PID-file.\n"
- " Default: "PIDFILE"\n"
-#if COLLECT_DAEMON
- " -f Don't fork to the background.\n"
-#endif
- " -h Display help (this message)\n"
- "\nBuiltin defaults:\n"
- " Config file "CONFIGFILE"\n"
- " PID file "PIDFILE"\n"
- " Plugin directory "PLUGINDIR"\n"
- " Data directory "PKGLOCALSTATEDIR"\n"
- "\n"PACKAGE" "VERSION", http://collectd.org/\n"
- "by Florian octo Forster <octo@collectd.org>\n"
- "for contributions see `AUTHORS'\n");
- exit (status);
-} /* static void exit_usage (int status) */
-
-static int do_init (void)
-{
-#if HAVE_SETLOCALE
- if (setlocale (LC_NUMERIC, COLLECTD_LOCALE) == NULL)
- WARNING ("setlocale (\"%s\") failed.", COLLECTD_LOCALE);
-#endif
-
-#if HAVE_LIBKSTAT
- kc = NULL;
- update_kstat ();
-#endif
-
-#if HAVE_LIBSTATGRAB
- if (sg_init ())
- {
- ERROR ("sg_init: %s", sg_str_error (sg_get_error ()));
- return (-1);
- }
-
- if (sg_drop_privileges ())
- {
- ERROR ("sg_drop_privileges: %s", sg_str_error (sg_get_error ()));
- return (-1);
- }
-#endif
-
- plugin_init_all ();
-
- return (0);
-} /* int do_init () */
-
-
-static int do_loop (void)
-{
- cdtime_t interval = cf_get_default_interval ();
- cdtime_t wait_until;
-
- wait_until = cdtime () + interval;
-
- while (loop == 0)
- {
- struct timespec ts_wait = { 0, 0 };
- cdtime_t now;
-
-#if HAVE_LIBKSTAT
- update_kstat ();
-#endif
-
- /* Issue all plugins */
- plugin_read_all ();
-
- now = cdtime ();
- if (now >= wait_until)
- {
- WARNING ("Not sleeping because the next interval is "
- "%.3f seconds in the past!",
- CDTIME_T_TO_DOUBLE (now - wait_until));
- wait_until = now + interval;
- continue;
- }
-
- CDTIME_T_TO_TIMESPEC (wait_until - now, &ts_wait);
- wait_until = wait_until + interval;
-
- while ((loop == 0) && (nanosleep (&ts_wait, &ts_wait) != 0))
- {
- if (errno != EINTR)
- {
- char errbuf[1024];
- ERROR ("nanosleep failed: %s",
- sstrerror (errno, errbuf,
- sizeof (errbuf)));
- return (-1);
- }
- }
- } /* while (loop == 0) */
-
- return (0);
-} /* int do_loop */
-
-static int do_shutdown (void)
-{
- plugin_shutdown_all ();
- return (0);
-} /* int do_shutdown */
-
-#if COLLECT_DAEMON
-static int pidfile_create (void)
-{
- FILE *fh;
- const char *file = global_option_get ("PIDFile");
-
- if ((fh = fopen (file, "w")) == NULL)
- {
- char errbuf[1024];
- ERROR ("fopen (%s): %s", file,
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (1);
- }
-
- fprintf (fh, "%i\n", (int) getpid ());
- fclose(fh);
-
- return (0);
-} /* static int pidfile_create (const char *file) */
-
-static int pidfile_remove (void)
-{
- const char *file = global_option_get ("PIDFile");
-
- DEBUG ("unlink (%s)", (file != NULL) ? file : "<null>");
- return (unlink (file));
-} /* static int pidfile_remove (const char *file) */
-#endif /* COLLECT_DAEMON */
-
-int main (int argc, char **argv)
-{
- struct sigaction sig_int_action;
- struct sigaction sig_term_action;
- struct sigaction sig_usr1_action;
- struct sigaction sig_pipe_action;
- char *configfile = CONFIGFILE;
- int test_config = 0;
- int test_readall = 0;
- const char *basedir;
-#if COLLECT_DAEMON
- struct sigaction sig_chld_action;
- pid_t pid;
- int daemonize = 1;
-#endif
- int exit_status = 0;
-
- /* read options */
- while (1)
- {
- int c;
-
- c = getopt (argc, argv, "htTC:"
-#if COLLECT_DAEMON
- "fP:"
-#endif
- );
-
- if (c == -1)
- break;
-
- switch (c)
- {
- case 'C':
- configfile = optarg;
- break;
- case 't':
- test_config = 1;
- break;
- case 'T':
- test_readall = 1;
- global_option_set ("ReadThreads", "-1");
-#if COLLECT_DAEMON
- daemonize = 0;
-#endif /* COLLECT_DAEMON */
- break;
-#if COLLECT_DAEMON
- case 'P':
- global_option_set ("PIDFile", optarg);
- pidfile_from_cli = 1;
- break;
- case 'f':
- daemonize = 0;
- break;
-#endif /* COLLECT_DAEMON */
- case 'h':
- exit_usage (0);
- break;
- default:
- exit_usage (1);
- } /* switch (c) */
- } /* while (1) */
-
- if (optind < argc)
- exit_usage (1);
-
- plugin_init_ctx ();
-
- /*
- * Read options from the config file, the environment and the command
- * line (in that order, with later options overwriting previous ones in
- * general).
- * Also, this will automatically load modules.
- */
- if (cf_read (configfile))
- {
- fprintf (stderr, "Error: Reading the config file failed!\n"
- "Read the syslog for details.\n");
- return (1);
- }
-
- /*
- * Change directory. We do this _after_ reading the config and loading
- * modules to relative paths work as expected.
- */
- if ((basedir = global_option_get ("BaseDir")) == NULL)
- {
- fprintf (stderr, "Don't have a basedir to use. This should not happen. Ever.");
- return (1);
- }
- else if (change_basedir (basedir))
- {
- fprintf (stderr, "Error: Unable to change to directory `%s'.\n", basedir);
- return (1);
- }
-
- /*
- * Set global variables or, if that failes, exit. We cannot run with
- * them being uninitialized. If nothing is configured, then defaults
- * are being used. So this means that the user has actually done
- * something wrong.
- */
- if (init_global_variables () != 0)
- return (1);
-
- if (test_config)
- return (0);
-
-#if COLLECT_DAEMON
- /*
- * fork off child
- */
- memset (&sig_chld_action, '\0', sizeof (sig_chld_action));
- sig_chld_action.sa_handler = SIG_IGN;
- sigaction (SIGCHLD, &sig_chld_action, NULL);
-
- if (daemonize)
- {
- if ((pid = fork ()) == -1)
- {
- /* error */
- char errbuf[1024];
- fprintf (stderr, "fork: %s",
- sstrerror (errno, errbuf,
- sizeof (errbuf)));
- return (1);
- }
- else if (pid != 0)
- {
- /* parent */
- /* printf ("Running (PID %i)\n", pid); */
- return (0);
- }
-
- /* Detach from session */
- setsid ();
-
- /* Write pidfile */
- if (pidfile_create ())
- exit (2);
-
- /* close standard descriptors */
- close (2);
- close (1);
- close (0);
-
- if (open ("/dev/null", O_RDWR) != 0)
- {
- ERROR ("Error: Could not connect `STDIN' to `/dev/null'");
- return (1);
- }
- if (dup (0) != 1)
- {
- ERROR ("Error: Could not connect `STDOUT' to `/dev/null'");
- return (1);
- }
- if (dup (0) != 2)
- {
- ERROR ("Error: Could not connect `STDERR' to `/dev/null'");
- return (1);
- }
- } /* if (daemonize) */
-#endif /* COLLECT_DAEMON */
-
- memset (&sig_pipe_action, '\0', sizeof (sig_pipe_action));
- sig_pipe_action.sa_handler = SIG_IGN;
- sigaction (SIGPIPE, &sig_pipe_action, NULL);
-
- /*
- * install signal handlers
- */
- memset (&sig_int_action, '\0', sizeof (sig_int_action));
- sig_int_action.sa_handler = sig_int_handler;
- if (0 != sigaction (SIGINT, &sig_int_action, NULL)) {
- char errbuf[1024];
- ERROR ("Error: Failed to install a signal handler for signal INT: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (1);
- }
-
- memset (&sig_term_action, '\0', sizeof (sig_term_action));
- sig_term_action.sa_handler = sig_term_handler;
- if (0 != sigaction (SIGTERM, &sig_term_action, NULL)) {
- char errbuf[1024];
- ERROR ("Error: Failed to install a signal handler for signal TERM: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (1);
- }
-
- memset (&sig_usr1_action, '\0', sizeof (sig_usr1_action));
- sig_usr1_action.sa_handler = sig_usr1_handler;
- if (0 != sigaction (SIGUSR1, &sig_usr1_action, NULL)) {
- char errbuf[1024];
- ERROR ("Error: Failed to install a signal handler for signal USR1: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (1);
- }
-
- /*
- * run the actual loops
- */
- do_init ();
-
- if (test_readall)
- {
- if (plugin_read_all_once () != 0)
- exit_status = 1;
- }
- else
- {
- INFO ("Initialization complete, entering read-loop.");
- do_loop ();
- }
-
- /* close syslog */
- INFO ("Exiting normally.");
-
- do_shutdown ();
-
-#if COLLECT_DAEMON
- if (daemonize)
- pidfile_remove ();
-#endif /* COLLECT_DAEMON */
-
- return (exit_status);
-} /* int main */
diff --git a/src/collectd.h b/src/collectd.h
--- a/src/collectd.h
+++ /dev/null
@@ -1,315 +0,0 @@
-/**
- * collectd - src/collectd.h
- * Copyright (C) 2005,2006 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#ifndef COLLECTD_H
-#define COLLECTD_H
-
-#if HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <stdio.h>
-#if HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-#if HAVE_SYS_STAT_H
-# include <sys/stat.h>
-#endif
-#if STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# if HAVE_STDLIB_H
-# include <stdlib.h>
-# endif
-#endif
-#if HAVE_STRING_H
-# if !STDC_HEADERS && HAVE_MEMORY_H
-# include <memory.h>
-# endif
-# include <string.h>
-#endif
-#if HAVE_STRINGS_H
-# include <strings.h>
-#endif
-#if HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
-#if HAVE_STDINT_H
-# include <stdint.h>
-#endif
-#if HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#if HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-#ifndef WEXITSTATUS
-# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8)
-#endif
-#ifndef WIFEXITED
-# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
-#endif
-#if HAVE_SIGNAL_H
-# include <signal.h>
-#endif
-#if HAVE_FCNTL_H
-# include <fcntl.h>
-#endif
-#if HAVE_ERRNO_H
-# include <errno.h>
-#endif
-#if HAVE_LIMITS_H
-# include <limits.h>
-#endif
-#if TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-#endif
-
-#if HAVE_ASSERT_H
-# include <assert.h>
-#else
-# define assert(...) /* nop */
-#endif
-
-#if !defined(HAVE__BOOL) || !HAVE__BOOL
-typedef int _Bool;
-# undef HAVE__BOOL
-# define HAVE__BOOL 1
-#endif
-
-#if NAN_STATIC_DEFAULT
-# include <math.h>
-/* #endif NAN_STATIC_DEFAULT*/
-#elif NAN_STATIC_ISOC
-# ifndef __USE_ISOC99
-# define DISABLE_ISOC99 1
-# define __USE_ISOC99 1
-# endif /* !defined(__USE_ISOC99) */
-# include <math.h>
-# if DISABLE_ISOC99
-# undef DISABLE_ISOC99
-# undef __USE_ISOC99
-# endif /* DISABLE_ISOC99 */
-/* #endif NAN_STATIC_ISOC */
-#elif NAN_ZERO_ZERO
-# include <math.h>
-# ifdef NAN
-# undef NAN
-# endif
-# define NAN (0.0 / 0.0)
-# ifndef isnan
-# define isnan(f) ((f) != (f))
-# endif /* !defined(isnan) */
-# ifndef isfinite
-# define isfinite(f) (((f) - (f)) == 0.0)
-# endif
-# ifndef isinf
-# define isinf(f) (!isfinite(f) && !isnan(f))
-# endif
-#endif /* NAN_ZERO_ZERO */
-
-/* Try really, really hard to determine endianess. Under NexentaStor 1.0.2 this
- * information is in <sys/isa_defs.h>, possibly some other Solaris versions do
- * this too.. */
-#if HAVE_ENDIAN_H
-# include <endian.h>
-#elif HAVE_SYS_ISA_DEFS_H
-# include <sys/isa_defs.h>
-#endif
-
-#ifndef BYTE_ORDER
-# if defined(_BYTE_ORDER)
-# define BYTE_ORDER _BYTE_ORDER
-# elif defined(__BYTE_ORDER)
-# define BYTE_ORDER __BYTE_ORDER
-# elif defined(__DARWIN_BYTE_ORDER)
-# define BYTE_ORDER __DARWIN_BYTE_ORDER
-# endif
-#endif
-#ifndef BIG_ENDIAN
-# if defined(_BIG_ENDIAN)
-# define BIG_ENDIAN _BIG_ENDIAN
-# elif defined(__BIG_ENDIAN)
-# define BIG_ENDIAN __BIG_ENDIAN
-# elif defined(__DARWIN_BIG_ENDIAN)
-# define BIG_ENDIAN __DARWIN_BIG_ENDIAN
-# endif
-#endif
-#ifndef LITTLE_ENDIAN
-# if defined(_LITTLE_ENDIAN)
-# define LITTLE_ENDIAN _LITTLE_ENDIAN
-# elif defined(__LITTLE_ENDIAN)
-# define LITTLE_ENDIAN __LITTLE_ENDIAN
-# elif defined(__DARWIN_LITTLE_ENDIAN)
-# define LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN
-# endif
-#endif
-#ifndef BYTE_ORDER
-# if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)
-# undef BIG_ENDIAN
-# define BIG_ENDIAN 4321
-# define LITTLE_ENDIAN 1234
-# define BYTE_ORDER BIG_ENDIAN
-# elif !defined(BIG_ENDIAN) && defined(LITTLE_ENDIAN)
-# undef LITTLE_ENDIAN
-# define BIG_ENDIAN 4321
-# define LITTLE_ENDIAN 1234
-# define BYTE_ORDER LITTLE_ENDIAN
-# endif
-#endif
-#if !defined(BYTE_ORDER) || !defined(BIG_ENDIAN)
-# error "Cannot determine byte order"
-#endif
-
-#if HAVE_DIRENT_H
-# include <dirent.h>
-# define NAMLEN(dirent) strlen((dirent)->d_name)
-#else
-# define dirent direct
-# define NAMLEN(dirent) (dirent)->d_namlen
-# if HAVE_SYS_NDIR_H
-# include <sys/ndir.h>
-# endif
-# if HAVE_SYS_DIR_H
-# include <sys/dir.h>
-# endif
-# if HAVE_NDIR_H
-# include <ndir.h>
-# endif
-#endif
-
-#if HAVE_STDARG_H
-# include <stdarg.h>
-#endif
-#if HAVE_CTYPE_H
-# include <ctype.h>
-#endif
-#if HAVE_SYS_PARAM_H
-# include <sys/param.h>
-#endif
-
-#if HAVE_KSTAT_H
-# include <kstat.h>
-#endif
-
-#ifndef PACKAGE_NAME
-#define PACKAGE_NAME "collectd"
-#endif
-
-#ifndef PREFIX
-#define PREFIX "/opt/" PACKAGE_NAME
-#endif
-
-#ifndef SYSCONFDIR
-#define SYSCONFDIR PREFIX "/etc"
-#endif
-
-#ifndef CONFIGFILE
-#define CONFIGFILE SYSCONFDIR"/collectd.conf"
-#endif
-
-#ifndef LOCALSTATEDIR
-#define LOCALSTATEDIR PREFIX "/var"
-#endif
-
-#ifndef PKGLOCALSTATEDIR
-#define PKGLOCALSTATEDIR PREFIX "/var/lib/" PACKAGE_NAME
-#endif
-
-#ifndef PIDFILE
-#define PIDFILE PREFIX "/var/run/" PACKAGE_NAME ".pid"
-#endif
-
-#ifndef PLUGINDIR
-#define PLUGINDIR PREFIX "/lib/" PACKAGE_NAME
-#endif
-
-#ifndef PKGDATADIR
-#define PKGDATADIR PREFIX "/share/" PACKAGE_NAME
-#endif
-
-#ifndef COLLECTD_GRP_NAME
-# define COLLECTD_GRP_NAME "collectd"
-#endif
-
-#ifndef COLLECTD_DEFAULT_INTERVAL
-# define COLLECTD_DEFAULT_INTERVAL 10.0
-#endif
-
- #ifndef COLLECTD_USERAGENT
- # define COLLECTD_USERAGENT PACKAGE_NAME"/"PACKAGE_VERSION
- #endif
-
-/* Only enable __attribute__() for compilers known to support it. */
-#if defined(__clang__)
-# define clang_attr(x) __attribute__(x)
-# define gcc_attr(x) /**/
-#elif __GNUC__
-# define clang_attr(x) /**/
-# define gcc_attr(x) __attribute__(x)
-#else
-# define clang_attr(x) /**/
-# define gcc_attr(x) /**/
-# define __attribute__(x) /**/
-#endif
-
-#if defined(COLLECT_DEBUG) && COLLECT_DEBUG && defined(__GNUC__) && __GNUC__
-# undef strcpy
-# undef strcat
-# undef strtok
-# pragma GCC poison strcpy strcat strtok
-#endif
-
-/*
- * Special hack for the perl plugin: Because the later included perl.h defines
- * a macro which is never used, but contains `sprintf', we cannot poison that
- * identifies just yet. The parl plugin will do that itself once perl.h is
- * included.
- */
-#ifndef DONT_POISON_SPRINTF_YET
-# if defined(COLLECT_DEBUG) && COLLECT_DEBUG && defined(__GNUC__) && __GNUC__
-# undef sprintf
-# pragma GCC poison sprintf
-# endif
-#endif
-
-/* Type for time as used by "utils_time.h" */
-typedef uint64_t cdtime_t;
-
-extern char hostname_g[];
-extern cdtime_t interval_g;
-extern int pidfile_from_cli;
-extern int timeout_g;
-
-#endif /* COLLECTD_H */
diff --git a/src/common.c b/src/common.c
--- a/src/common.c
+++ /dev/null
@@ -1,1596 +0,0 @@
-/**
- * collectd - src/common.c
- * Copyright (C) 2005-2014 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- * Niki W. Waibel <niki.waibel@gmx.net>
- * Sebastian Harl <sh at tokkee.org>
- * Michał Mirosław <mirq-linux at rere.qmqm.pl>
-**/
-
-#if HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "collectd.h"
-#include "common.h"
-#include "plugin.h"
-#include "utils_cache.h"
-
-#if HAVE_PTHREAD_H
-# include <pthread.h>
-#endif
-
-#ifdef HAVE_MATH_H
-# include <math.h>
-#endif
-
-/* for getaddrinfo */
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-
-#if HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-
-/* for ntohl and htonl */
-#if HAVE_ARPA_INET_H
-# include <arpa/inet.h>
-#endif
-
-#ifdef HAVE_LIBKSTAT
-extern kstat_ctl_t *kc;
-#endif
-
-#if !HAVE_GETPWNAM_R
-static pthread_mutex_t getpwnam_r_lock = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
-#if !HAVE_STRERROR_R
-static pthread_mutex_t strerror_r_lock = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
-char *sstrncpy (char *dest, const char *src, size_t n)
-{
- strncpy (dest, src, n);
- dest[n - 1] = '\0';
-
- return (dest);
-} /* char *sstrncpy */
-
-int ssnprintf (char *dest, size_t n, const char *format, ...)
-{
- int ret = 0;
- va_list ap;
-
- va_start (ap, format);
- ret = vsnprintf (dest, n, format, ap);
- dest[n - 1] = '\0';
- va_end (ap);
-
- return (ret);
-} /* int ssnprintf */
-
-char *ssnprintf_alloc (char const *format, ...) /* {{{ */
-{
- char static_buffer[1024] = "";
- char *alloc_buffer;
- size_t alloc_buffer_size;
- int status;
- va_list ap;
-
- /* Try printing into the static buffer. In many cases it will be
- * sufficiently large and we can simply return a strdup() of this
- * buffer. */
- va_start (ap, format);
- status = vsnprintf (static_buffer, sizeof (static_buffer), format, ap);
- va_end (ap);
- if (status < 0)
- return (NULL);
-
- /* "status" does not include the null byte. */
- alloc_buffer_size = (size_t) (status + 1);
- if (alloc_buffer_size <= sizeof (static_buffer))
- return (strdup (static_buffer));
-
- /* Allocate a buffer large enough to hold the string. */
- alloc_buffer = malloc (alloc_buffer_size);
- if (alloc_buffer == NULL)
- return (NULL);
- memset (alloc_buffer, 0, alloc_buffer_size);
-
- /* Print again into this new buffer. */
- va_start (ap, format);
- status = vsnprintf (alloc_buffer, alloc_buffer_size, format, ap);
- va_end (ap);
- if (status < 0)
- {
- sfree (alloc_buffer);
- return (NULL);
- }
-
- return (alloc_buffer);
-} /* }}} char *ssnprintf_alloc */
-
-char *sstrdup (const char *s)
-{
- char *r;
- size_t sz;
-
- if (s == NULL)
- return (NULL);
-
- /* Do not use `strdup' here, because it's not specified in POSIX. It's
- * ``only'' an XSI extension. */
- sz = strlen (s) + 1;
- r = (char *) malloc (sizeof (char) * sz);
- if (r == NULL)
- {
- ERROR ("sstrdup: Out of memory.");
- exit (3);
- }
- memcpy (r, s, sizeof (char) * sz);
-
- return (r);
-} /* char *sstrdup */
-
-/* Even though Posix requires "strerror_r" to return an "int",
- * some systems (e.g. the GNU libc) return a "char *" _and_
- * ignore the second argument ... -tokkee */
-char *sstrerror (int errnum, char *buf, size_t buflen)
-{
- buf[0] = '\0';
-
-#if !HAVE_STRERROR_R
- {
- char *temp;
-
- pthread_mutex_lock (&strerror_r_lock);
-
- temp = strerror (errnum);
- sstrncpy (buf, temp, buflen);
-
- pthread_mutex_unlock (&strerror_r_lock);
- }
-/* #endif !HAVE_STRERROR_R */
-
-#elif STRERROR_R_CHAR_P
- {
- char *temp;
- temp = strerror_r (errnum, buf, buflen);
- if (buf[0] == '\0')
- {
- if ((temp != NULL) && (temp != buf) && (temp[0] != '\0'))
- sstrncpy (buf, temp, buflen);
- else
- sstrncpy (buf, "strerror_r did not return "
- "an error message", buflen);
- }
- }
-/* #endif STRERROR_R_CHAR_P */
-
-#else
- if (strerror_r (errnum, buf, buflen) != 0)
- {
- ssnprintf (buf, buflen, "Error #%i; "
- "Additionally, strerror_r failed.",
- errnum);
- }
-#endif /* STRERROR_R_CHAR_P */
-
- return (buf);
-} /* char *sstrerror */
-
-void *smalloc (size_t size)
-{
- void *r;
-
- if ((r = malloc (size)) == NULL)
- {
- ERROR ("Not enough memory.");
- exit (3);
- }
-
- return (r);
-} /* void *smalloc */
-
-#if 0
-void sfree (void **ptr)
-{
- if (ptr == NULL)
- return;
-
- if (*ptr != NULL)
- free (*ptr);
-
- *ptr = NULL;
-}
-#endif
-
-ssize_t sread (int fd, void *buf, size_t count)
-{
- char *ptr;
- size_t nleft;
- ssize_t status;
-
- ptr = (char *) buf;
- nleft = count;
-
- while (nleft > 0)
- {
- status = read (fd, (void *) ptr, nleft);
-
- if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
- continue;
-
- if (status < 0)
- return (status);
-
- if (status == 0)
- {
- DEBUG ("Received EOF from fd %i. "
- "Closing fd and returning error.",
- fd);
- close (fd);
- return (-1);
- }
-
- assert ((0 > status) || (nleft >= (size_t)status));
-
- nleft = nleft - status;
- ptr = ptr + status;
- }
-
- return (0);
-}
-
-
-ssize_t swrite (int fd, const void *buf, size_t count)
-{
- const char *ptr;
- size_t nleft;
- ssize_t status;
-
- ptr = (const char *) buf;
- nleft = count;
-
- while (nleft > 0)
- {
- status = write (fd, (const void *) ptr, nleft);
-
- if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
- continue;
-
- if (status < 0)
- return (status);
-
- nleft = nleft - status;
- ptr = ptr + status;
- }
-
- return (0);
-}
-
-int strsplit (char *string, char **fields, size_t size)
-{
- size_t i;
- char *ptr;
- char *saveptr;
-
- i = 0;
- ptr = string;
- saveptr = NULL;
- while ((fields[i] = strtok_r (ptr, " \t\r\n", &saveptr)) != NULL)
- {
- ptr = NULL;
- i++;
-
- if (i >= size)
- break;
- }
-
- return ((int) i);
-}
-
-int strjoin (char *dst, size_t dst_len,
- char **fields, size_t fields_num,
- const char *sep)
-{
- size_t field_len;
- size_t sep_len;
- int i;
-
- memset (dst, '\0', dst_len);
-
- if (fields_num <= 0)
- return (-1);
-
- sep_len = 0;
- if (sep != NULL)
- sep_len = strlen (sep);
-
- for (i = 0; i < (int)fields_num; i++)
- {
- if ((i > 0) && (sep_len > 0))
- {
- if (dst_len <= sep_len)
- return (-1);
-
- strncat (dst, sep, dst_len);
- dst_len -= sep_len;
- }
-
- field_len = strlen (fields[i]);
-
- if (dst_len <= field_len)
- return (-1);
-
- strncat (dst, fields[i], dst_len);
- dst_len -= field_len;
- }
-
- return (strlen (dst));
-}
-
-int strsubstitute (char *str, char c_from, char c_to)
-{
- int ret;
-
- if (str == NULL)
- return (-1);
-
- ret = 0;
- while (*str != '\0')
- {
- if (*str == c_from)
- {
- *str = c_to;
- ret++;
- }
- str++;
- }
-
- return (ret);
-} /* int strsubstitute */
-
-int strunescape (char *buf, size_t buf_len)
-{
- size_t i;
-
- for (i = 0; (i < buf_len) && (buf[i] != '\0'); ++i)
- {
- if (buf[i] != '\\')
- continue;
-
- if (((i + 1) >= buf_len) || (buf[i + 1] == 0)) {
- ERROR ("string unescape: backslash found at end of string.");
- /* Ensure null-byte at the end of the buffer. */
- buf[i] = 0;
- return (-1);
- }
-
- switch (buf[i + 1]) {
- case 't':
- buf[i] = '\t';
- break;
- case 'n':
- buf[i] = '\n';
- break;
- case 'r':
- buf[i] = '\r';
- break;
- default:
- buf[i] = buf[i + 1];
- break;
- }
-
- /* Move everything after the position one position to the left.
- * Add a null-byte as last character in the buffer. */
- memmove (buf + i + 1, buf + i + 2, buf_len - i - 2);
- buf[buf_len - 1] = 0;
- }
- return (0);
-} /* int strunescape */
-
-size_t strstripnewline (char *buffer)
-{
- size_t buffer_len = strlen (buffer);
-
- while (buffer_len > 0)
- {
- if ((buffer[buffer_len - 1] != '\n')
- && (buffer[buffer_len - 1] != '\r'))
- break;
- buffer[buffer_len] = 0;
- buffer_len--;
- }
-
- return (buffer_len);
-} /* size_t strstripnewline */
-
-int escape_slashes (char *buffer, size_t buffer_size)
-{
- int i;
- size_t buffer_len;
-
- buffer_len = strlen (buffer);
-
- if (buffer_len <= 1)
- {
- if (strcmp ("/", buffer) == 0)
- {
- if (buffer_size < 5)
- return (-1);
- sstrncpy (buffer, "root", buffer_size);
- }
- return (0);
- }
-
- /* Move one to the left */
- if (buffer[0] == '/')
- {
- memmove (buffer, buffer + 1, buffer_len);
- buffer_len--;
- }
-
- for (i = 0; i < buffer_len - 1; i++)
- {
- if (buffer[i] == '/')
- buffer[i] = '_';
- }
-
- return (0);
-} /* int escape_slashes */
-
-void replace_special (char *buffer, size_t buffer_size)
-{
- size_t i;
-
- for (i = 0; i < buffer_size; i++)
- {
- if (buffer[i] == 0)
- return;
- if ((!isalnum ((int) buffer[i])) && (buffer[i] != '-'))
- buffer[i] = '_';
- }
-} /* void replace_special */
-
-int timeval_cmp (struct timeval tv0, struct timeval tv1, struct timeval *delta)
-{
- struct timeval *larger;
- struct timeval *smaller;
-
- int status;
-
- NORMALIZE_TIMEVAL (tv0);
- NORMALIZE_TIMEVAL (tv1);
-
- if ((tv0.tv_sec == tv1.tv_sec) && (tv0.tv_usec == tv1.tv_usec))
- {
- if (delta != NULL) {
- delta->tv_sec = 0;
- delta->tv_usec = 0;
- }
- return (0);
- }
-
- if ((tv0.tv_sec < tv1.tv_sec)
- || ((tv0.tv_sec == tv1.tv_sec) && (tv0.tv_usec < tv1.tv_usec)))
- {
- larger = &tv1;
- smaller = &tv0;
- status = -1;
- }
- else
- {
- larger = &tv0;
- smaller = &tv1;
- status = 1;
- }
-
- if (delta != NULL) {
- delta->tv_sec = larger->tv_sec - smaller->tv_sec;
-
- if (smaller->tv_usec <= larger->tv_usec)
- delta->tv_usec = larger->tv_usec - smaller->tv_usec;
- else
- {
- --delta->tv_sec;
- delta->tv_usec = 1000000 + larger->tv_usec - smaller->tv_usec;
- }
- }
-
- assert ((delta == NULL)
- || ((0 <= delta->tv_usec) && (delta->tv_usec < 1000000)));
-
- return (status);
-} /* int timeval_cmp */
-
-int check_create_dir (const char *file_orig)
-{
- struct stat statbuf;
-
- char file_copy[512];
- char dir[512];
- int dir_len = 512;
- char *fields[16];
- int fields_num;
- char *ptr;
- char *saveptr;
- int last_is_file = 1;
- int path_is_absolute = 0;
- size_t len;
- int i;
-
- /*
- * Sanity checks first
- */
- if (file_orig == NULL)
- return (-1);
-
- if ((len = strlen (file_orig)) < 1)
- return (-1);
- else if (len >= sizeof (file_copy))
- return (-1);
-
- /*
- * If `file_orig' ends in a slash the last component is a directory,
- * otherwise it's a file. Act accordingly..
- */
- if (file_orig[len - 1] == '/')
- last_is_file = 0;
- if (file_orig[0] == '/')
- path_is_absolute = 1;
-
- /*
- * Create a copy for `strtok_r' to destroy
- */
- sstrncpy (file_copy, file_orig, sizeof (file_copy));
-
- /*
- * Break into components. This will eat up several slashes in a row and
- * remove leading and trailing slashes..
- */
- ptr = file_copy;
- saveptr = NULL;
- fields_num = 0;
- while ((fields[fields_num] = strtok_r (ptr, "/", &saveptr)) != NULL)
- {
- ptr = NULL;
- fields_num++;
-
- if (fields_num >= 16)
- break;
- }
-
- /*
- * For each component, do..
- */
- for (i = 0; i < (fields_num - last_is_file); i++)
- {
- /*
- * Do not create directories that start with a dot. This
- * prevents `../../' attacks and other likely malicious
- * behavior.
- */
- if (fields[i][0] == '.')
- {
- ERROR ("Cowardly refusing to create a directory that "
- "begins with a `.' (dot): `%s'", file_orig);
- return (-2);
- }
-
- /*
- * Join the components together again
- */
- dir[0] = '/';
- if (strjoin (dir + path_is_absolute, dir_len - path_is_absolute,
- fields, i + 1, "/") < 0)
- {
- ERROR ("strjoin failed: `%s', component #%i", file_orig, i);
- return (-1);
- }
-
- while (42) {
- if ((stat (dir, &statbuf) == -1)
- && (lstat (dir, &statbuf) == -1))
- {
- if (errno == ENOENT)
- {
- if (mkdir (dir, S_IRWXU | S_IRWXG | S_IRWXO) == 0)
- break;
-
- /* this might happen, if a different thread created
- * the directory in the meantime
- * => call stat() again to check for S_ISDIR() */
- if (EEXIST == errno)
- continue;
-
- char errbuf[1024];
- ERROR ("check_create_dir: mkdir (%s): %s", dir,
- sstrerror (errno,
- errbuf, sizeof (errbuf)));
- return (-1);
- }
- else
- {
- char errbuf[1024];
- ERROR ("check_create_dir: stat (%s): %s", dir,
- sstrerror (errno, errbuf,
- sizeof (errbuf)));
- return (-1);
- }
- }
- else if (!S_ISDIR (statbuf.st_mode))
- {
- ERROR ("check_create_dir: `%s' exists but is not "
- "a directory!", dir);
- return (-1);
- }
- break;
- }
- }
-
- return (0);
-} /* check_create_dir */
-
-#ifdef HAVE_LIBKSTAT
-int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
-{
- char ident[128];
-
- *ksp_ptr = NULL;
-
- if (kc == NULL)
- return (-1);
-
- ssnprintf (ident, sizeof (ident), "%s,%i,%s", module, instance, name);
-
- *ksp_ptr = kstat_lookup (kc, module, instance, name);
- if (*ksp_ptr == NULL)
- {
- ERROR ("get_kstat: Cound not find kstat %s", ident);
- return (-1);
- }
-
- if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
- {
- ERROR ("get_kstat: kstat %s has wrong type", ident);
- *ksp_ptr = NULL;
- return (-1);
- }
-
-#ifdef assert
- assert (*ksp_ptr != NULL);
- assert ((*ksp_ptr)->ks_type == KSTAT_TYPE_NAMED);
-#endif
-
- if (kstat_read (kc, *ksp_ptr, NULL) == -1)
- {
- ERROR ("get_kstat: kstat %s could not be read", ident);
- return (-1);
- }
-
- if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
- {
- ERROR ("get_kstat: kstat %s has wrong type", ident);
- return (-1);
- }
-
- return (0);
-}
-
-long long get_kstat_value (kstat_t *ksp, char *name)
-{
- kstat_named_t *kn;
- long long retval = -1LL;
-
- if (ksp == NULL)
- {
- ERROR ("get_kstat_value (\"%s\"): ksp is NULL.", name);
- return (-1LL);
- }
- else if (ksp->ks_type != KSTAT_TYPE_NAMED)
- {
- ERROR ("get_kstat_value (\"%s\"): ksp->ks_type (%#x) "
- "is not KSTAT_TYPE_NAMED (%#x).",
- name,
- (unsigned int) ksp->ks_type,
- (unsigned int) KSTAT_TYPE_NAMED);
- return (-1LL);
- }
-
- if ((kn = (kstat_named_t *) kstat_data_lookup (ksp, name)) == NULL)
- return (-1LL);
-
- if (kn->data_type == KSTAT_DATA_INT32)
- retval = (long long) kn->value.i32;
- else if (kn->data_type == KSTAT_DATA_UINT32)
- retval = (long long) kn->value.ui32;
- else if (kn->data_type == KSTAT_DATA_INT64)
- retval = (long long) kn->value.i64; /* According to ANSI C99 `long long' must hold at least 64 bits */
- else if (kn->data_type == KSTAT_DATA_UINT64)
- retval = (long long) kn->value.ui64; /* XXX: Might overflow! */
- else
- WARNING ("get_kstat_value: Not a numeric value: %s", name);
-
- return (retval);
-}
-#endif /* HAVE_LIBKSTAT */
-
-#ifndef HAVE_HTONLL
-unsigned long long ntohll (unsigned long long n)
-{
-#if BYTE_ORDER == BIG_ENDIAN
- return (n);
-#else
- return (((unsigned long long) ntohl (n)) << 32) + ntohl (n >> 32);
-#endif
-} /* unsigned long long ntohll */
-
-unsigned long long htonll (unsigned long long n)
-{
-#if BYTE_ORDER == BIG_ENDIAN
- return (n);
-#else
- return (((unsigned long long) htonl (n)) << 32) + htonl (n >> 32);
-#endif
-} /* unsigned long long htonll */
-#endif /* HAVE_HTONLL */
-
-#if FP_LAYOUT_NEED_NOTHING
-/* Well, we need nothing.. */
-/* #endif FP_LAYOUT_NEED_NOTHING */
-
-#elif FP_LAYOUT_NEED_ENDIANFLIP || FP_LAYOUT_NEED_INTSWAP
-# if FP_LAYOUT_NEED_ENDIANFLIP
-# define FP_CONVERT(A) ((((uint64_t)(A) & 0xff00000000000000LL) >> 56) | \
- (((uint64_t)(A) & 0x00ff000000000000LL) >> 40) | \
- (((uint64_t)(A) & 0x0000ff0000000000LL) >> 24) | \
- (((uint64_t)(A) & 0x000000ff00000000LL) >> 8) | \
- (((uint64_t)(A) & 0x00000000ff000000LL) << 8) | \
- (((uint64_t)(A) & 0x0000000000ff0000LL) << 24) | \
- (((uint64_t)(A) & 0x000000000000ff00LL) << 40) | \
- (((uint64_t)(A) & 0x00000000000000ffLL) << 56))
-# else
-# define FP_CONVERT(A) ((((uint64_t)(A) & 0xffffffff00000000LL) >> 32) | \
- (((uint64_t)(A) & 0x00000000ffffffffLL) << 32))
-# endif
-
-double ntohd (double d)
-{
- union
- {
- uint8_t byte[8];
- uint64_t integer;
- double floating;
- } ret;
-
- ret.floating = d;
-
- /* NAN in x86 byte order */
- if ((ret.byte[0] == 0x00) && (ret.byte[1] == 0x00)
- && (ret.byte[2] == 0x00) && (ret.byte[3] == 0x00)
- && (ret.byte[4] == 0x00) && (ret.byte[5] == 0x00)
- && (ret.byte[6] == 0xf8) && (ret.byte[7] == 0x7f))
- {
- return (NAN);
- }
- else
- {
- uint64_t tmp;
-
- tmp = ret.integer;
- ret.integer = FP_CONVERT (tmp);
- return (ret.floating);
- }
-} /* double ntohd */
-
-double htond (double d)
-{
- union
- {
- uint8_t byte[8];
- uint64_t integer;
- double floating;
- } ret;
-
- if (isnan (d))
- {
- ret.byte[0] = ret.byte[1] = ret.byte[2] = ret.byte[3] = 0x00;
- ret.byte[4] = ret.byte[5] = 0x00;
- ret.byte[6] = 0xf8;
- ret.byte[7] = 0x7f;
- return (ret.floating);
- }
- else
- {
- uint64_t tmp;
-
- ret.floating = d;
- tmp = FP_CONVERT (ret.integer);
- ret.integer = tmp;
- return (ret.floating);
- }
-} /* double htond */
-#endif /* FP_LAYOUT_NEED_ENDIANFLIP || FP_LAYOUT_NEED_INTSWAP */
-
-int format_name (char *ret, int ret_len,
- const char *hostname,
- const char *plugin, const char *plugin_instance,
- const char *type, const char *type_instance)
-{
- char *buffer;
- size_t buffer_size;
-
- buffer = ret;
- buffer_size = (size_t) ret_len;
-
-#define APPEND(str) do { \
- size_t l = strlen (str); \
- if (l >= buffer_size) \
- return (ENOBUFS); \
- memcpy (buffer, (str), l); \
- buffer += l; buffer_size -= l; \
-} while (0)
-
- assert (plugin != NULL);
- assert (type != NULL);
-
- APPEND (hostname);
- APPEND ("/");
- APPEND (plugin);
- if ((plugin_instance != NULL) && (plugin_instance[0] != 0))
- {
- APPEND ("-");
- APPEND (plugin_instance);
- }
- APPEND ("/");
- APPEND (type);
- if ((type_instance != NULL) && (type_instance[0] != 0))
- {
- APPEND ("-");
- APPEND (type_instance);
- }
- assert (buffer_size > 0);
- buffer[0] = 0;
-
-#undef APPEND
- return (0);
-} /* int format_name */
-
-int format_values (char *ret, size_t ret_len, /* {{{ */
- const data_set_t *ds, const value_list_t *vl,
- _Bool store_rates)
-{
- size_t offset = 0;
- int status;
- int i;
- gauge_t *rates = NULL;
-
- assert (0 == strcmp (ds->type, vl->type));
-
- memset (ret, 0, ret_len);
-
-#define BUFFER_ADD(...) do { \
- status = ssnprintf (ret + offset, ret_len - offset, \
- __VA_ARGS__); \
- if (status < 1) \
- { \
- sfree (rates); \
- return (-1); \
- } \
- else if (((size_t) status) >= (ret_len - offset)) \
- { \
- sfree (rates); \
- return (-1); \
- } \
- else \
- offset += ((size_t) status); \
-} while (0)
-
- BUFFER_ADD ("%.3f", CDTIME_T_TO_DOUBLE (vl->time));
-
- for (i = 0; i < ds->ds_num; i++)
- {
- if (ds->ds[i].type == DS_TYPE_GAUGE)
- BUFFER_ADD (":%f", vl->values[i].gauge);
- else if (store_rates)
- {
- if (rates == NULL)
- rates = uc_get_rate (ds, vl);
- if (rates == NULL)
- {
- WARNING ("format_values: "
- "uc_get_rate failed.");
- return (-1);
- }
- BUFFER_ADD (":%g", rates[i]);
- }
- else if (ds->ds[i].type == DS_TYPE_COUNTER)
- BUFFER_ADD (":%llu", vl->values[i].counter);
- else if (ds->ds[i].type == DS_TYPE_DERIVE)
- BUFFER_ADD (":%"PRIi64, vl->values[i].derive);
- else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
- BUFFER_ADD (":%"PRIu64, vl->values[i].absolute);
- else
- {
- ERROR ("format_values plugin: Unknown data source type: %i",
- ds->ds[i].type);
- sfree (rates);
- return (-1);
- }
- } /* for ds->ds_num */
-
-#undef BUFFER_ADD
-
- sfree (rates);
- return (0);
-} /* }}} int format_values */
-
-int parse_identifier (char *str, char **ret_host,
- char **ret_plugin, char **ret_plugin_instance,
- char **ret_type, char **ret_type_instance)
-{
- char *hostname = NULL;
- char *plugin = NULL;
- char *plugin_instance = NULL;
- char *type = NULL;
- char *type_instance = NULL;
-
- hostname = str;
- if (hostname == NULL)
- return (-1);
-
- plugin = strchr (hostname, '/');
- if (plugin == NULL)
- return (-1);
- *plugin = '\0'; plugin++;
-
- type = strchr (plugin, '/');
- if (type == NULL)
- return (-1);
- *type = '\0'; type++;
-
- plugin_instance = strchr (plugin, '-');
- if (plugin_instance != NULL)
- {
- *plugin_instance = '\0';
- plugin_instance++;
- }
-
- type_instance = strchr (type, '-');
- if (type_instance != NULL)
- {
- *type_instance = '\0';
- type_instance++;
- }
-
- *ret_host = hostname;
- *ret_plugin = plugin;
- *ret_plugin_instance = plugin_instance;
- *ret_type = type;
- *ret_type_instance = type_instance;
- return (0);
-} /* int parse_identifier */
-
-int parse_identifier_vl (const char *str, value_list_t *vl) /* {{{ */
-{
- char str_copy[6 * DATA_MAX_NAME_LEN];
- char *host = NULL;
- char *plugin = NULL;
- char *plugin_instance = NULL;
- char *type = NULL;
- char *type_instance = NULL;
- int status;
-
- if ((str == NULL) || (vl == NULL))
- return (EINVAL);
-
- sstrncpy (str_copy, str, sizeof (str_copy));
-
- status = parse_identifier (str_copy, &host,
- &plugin, &plugin_instance,
- &type, &type_instance);
- if (status != 0)
- return (status);
-
- sstrncpy (vl->host, host, sizeof (vl->host));
- sstrncpy (vl->plugin, plugin, sizeof (vl->plugin));
- sstrncpy (vl->plugin_instance,
- (plugin_instance != NULL) ? plugin_instance : "",
- sizeof (vl->plugin_instance));
- sstrncpy (vl->type, type, sizeof (vl->type));
- sstrncpy (vl->type_instance,
- (type_instance != NULL) ? type_instance : "",
- sizeof (vl->type_instance));
-
- return (0);
-} /* }}} int parse_identifier_vl */
-
-int parse_value (const char *value_orig, value_t *ret_value, int ds_type)
-{
- char *value;
- char *endptr = NULL;
- size_t value_len;
-
- if (value_orig == NULL)
- return (EINVAL);
-
- value = strdup (value_orig);
- if (value == NULL)
- return (ENOMEM);
- value_len = strlen (value);
-
- while ((value_len > 0) && isspace ((int) value[value_len - 1]))
- {
- value[value_len - 1] = 0;
- value_len--;
- }
-
- switch (ds_type)
- {
- case DS_TYPE_COUNTER:
- ret_value->counter = (counter_t) strtoull (value, &endptr, 0);
- break;
-
- case DS_TYPE_GAUGE:
- ret_value->gauge = (gauge_t) strtod (value, &endptr);
- break;
-
- case DS_TYPE_DERIVE:
- ret_value->derive = (derive_t) strtoll (value, &endptr, 0);
- break;
-
- case DS_TYPE_ABSOLUTE:
- ret_value->absolute = (absolute_t) strtoull (value, &endptr, 0);
- break;
-
- default:
- sfree (value);
- ERROR ("parse_value: Invalid data source type: %i.", ds_type);
- return -1;
- }
-
- if (value == endptr) {
- ERROR ("parse_value: Failed to parse string as %s: %s.",
- DS_TYPE_TO_STRING (ds_type), value);
- sfree (value);
- return -1;
- }
- else if ((NULL != endptr) && ('\0' != *endptr))
- INFO ("parse_value: Ignoring trailing garbage \"%s\" after %s value. "
- "Input string was \"%s\".",
- endptr, DS_TYPE_TO_STRING (ds_type), value_orig);
-
- sfree (value);
- return 0;
-} /* int parse_value */
-
-int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
-{
- int i;
- char *dummy;
- char *ptr;
- char *saveptr;
-
- i = -1;
- dummy = buffer;
- saveptr = NULL;
- while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL)
- {
- dummy = NULL;
-
- if (i >= vl->values_len)
- {
- /* Make sure i is invalid. */
- i = vl->values_len + 1;
- break;
- }
-
- if (i == -1)
- {
- if (strcmp ("N", ptr) == 0)
- vl->time = cdtime ();
- else
- {
- char *endptr = NULL;
- double tmp;
-
- errno = 0;
- tmp = strtod (ptr, &endptr);
- if ((errno != 0) /* Overflow */
- || (endptr == ptr) /* Invalid string */
- || (endptr == NULL) /* This should not happen */
- || (*endptr != 0)) /* Trailing chars */
- return (-1);
-
- vl->time = DOUBLE_TO_CDTIME_T (tmp);
- }
- }
- else
- {
- if ((strcmp ("U", ptr) == 0) && (ds->ds[i].type == DS_TYPE_GAUGE))
- vl->values[i].gauge = NAN;
- else if (0 != parse_value (ptr, &vl->values[i], ds->ds[i].type))
- return -1;
- }
-
- i++;
- } /* while (strtok_r) */
-
- if ((ptr != NULL) || (i != vl->values_len))
- return (-1);
- return (0);
-} /* int parse_values */
-
-#if !HAVE_GETPWNAM_R
-int getpwnam_r (const char *name, struct passwd *pwbuf, char *buf,
- size_t buflen, struct passwd **pwbufp)
-{
- int status = 0;
- struct passwd *pw;
-
- memset (pwbuf, '\0', sizeof (struct passwd));
-
- pthread_mutex_lock (&getpwnam_r_lock);
-
- do
- {
- pw = getpwnam (name);
- if (pw == NULL)
- {
- status = (errno != 0) ? errno : ENOENT;
- break;
- }
-
-#define GETPWNAM_COPY_MEMBER(member) \
- if (pw->member != NULL) \
- { \
- int len = strlen (pw->member); \
- if (len >= buflen) \
- { \
- status = ENOMEM; \
- break; \
- } \
- sstrncpy (buf, pw->member, buflen); \
- pwbuf->member = buf; \
- buf += (len + 1); \
- buflen -= (len + 1); \
- }
- GETPWNAM_COPY_MEMBER(pw_name);
- GETPWNAM_COPY_MEMBER(pw_passwd);
- GETPWNAM_COPY_MEMBER(pw_gecos);
- GETPWNAM_COPY_MEMBER(pw_dir);
- GETPWNAM_COPY_MEMBER(pw_shell);
-
- pwbuf->pw_uid = pw->pw_uid;
- pwbuf->pw_gid = pw->pw_gid;
-
- if (pwbufp != NULL)
- *pwbufp = pwbuf;
- } while (0);
-
- pthread_mutex_unlock (&getpwnam_r_lock);
-
- return (status);
-} /* int getpwnam_r */
-#endif /* !HAVE_GETPWNAM_R */
-
-int notification_init (notification_t *n, int severity, const char *message,
- const char *host,
- const char *plugin, const char *plugin_instance,
- const char *type, const char *type_instance)
-{
- memset (n, '\0', sizeof (notification_t));
-
- n->severity = severity;
-
- if (message != NULL)
- sstrncpy (n->message, message, sizeof (n->message));
- if (host != NULL)
- sstrncpy (n->host, host, sizeof (n->host));
- if (plugin != NULL)
- sstrncpy (n->plugin, plugin, sizeof (n->plugin));
- if (plugin_instance != NULL)
- sstrncpy (n->plugin_instance, plugin_instance,
- sizeof (n->plugin_instance));
- if (type != NULL)
- sstrncpy (n->type, type, sizeof (n->type));
- if (type_instance != NULL)
- sstrncpy (n->type_instance, type_instance,
- sizeof (n->type_instance));
-
- return (0);
-} /* int notification_init */
-
-int walk_directory (const char *dir, dirwalk_callback_f callback,
- void *user_data, int include_hidden)
-{
- struct dirent *ent;
- DIR *dh;
- int success;
- int failure;
-
- success = 0;
- failure = 0;
-
- if ((dh = opendir (dir)) == NULL)
- {
- char errbuf[1024];
- ERROR ("walk_directory: Cannot open '%s': %s", dir,
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return -1;
- }
-
- while ((ent = readdir (dh)) != NULL)
- {
- int status;
-
- if (include_hidden)
- {
- if ((strcmp (".", ent->d_name) == 0)
- || (strcmp ("..", ent->d_name) == 0))
- continue;
- }
- else /* if (!include_hidden) */
- {
- if (ent->d_name[0]=='.')
- continue;
- }
-
- status = (*callback) (dir, ent->d_name, user_data);
- if (status != 0)
- failure++;
- else
- success++;
- }
-
- closedir (dh);
-
- if ((success == 0) && (failure > 0))
- return (-1);
- return (0);
-}
-
-ssize_t read_file_contents (const char *filename, char *buf, size_t bufsize)
-{
- FILE *fh;
- ssize_t ret;
-
- fh = fopen (filename, "r");
- if (fh == NULL)
- return (-1);
-
- ret = (ssize_t) fread (buf, 1, bufsize, fh);
- if ((ret == 0) && (ferror (fh) != 0))
- {
- ERROR ("read_file_contents: Reading file \"%s\" failed.",
- filename);
- ret = -1;
- }
-
- fclose(fh);
- return (ret);
-}
-
-counter_t counter_diff (counter_t old_value, counter_t new_value)
-{
- counter_t diff;
-
- if (old_value > new_value)
- {
- if (old_value <= 4294967295U)
- diff = (4294967295U - old_value) + new_value;
- else
- diff = (18446744073709551615ULL - old_value)
- + new_value;
- }
- else
- {
- diff = new_value - old_value;
- }
-
- return (diff);
-} /* counter_t counter_diff */
-
-int rate_to_value (value_t *ret_value, gauge_t rate, /* {{{ */
- rate_to_value_state_t *state,
- int ds_type, cdtime_t t)
-{
- gauge_t delta_gauge;
- cdtime_t delta_t;
-
- if (ds_type == DS_TYPE_GAUGE)
- {
- state->last_value.gauge = rate;
- state->last_time = t;
-
- *ret_value = state->last_value;
- return (0);
- }
-
- /* Counter and absolute can't handle negative rates. Reset "last time"
- * to zero, so that the next valid rate will re-initialize the
- * structure. */
- if ((rate < 0.0)
- && ((ds_type == DS_TYPE_COUNTER)
- || (ds_type == DS_TYPE_ABSOLUTE)))
- {
- memset (state, 0, sizeof (*state));
- return (EINVAL);
- }
-
- /* Another invalid state: The time is not increasing. */
- if (t <= state->last_time)
- {
- memset (state, 0, sizeof (*state));
- return (EINVAL);
- }
-
- delta_t = t - state->last_time;
- delta_gauge = (rate * CDTIME_T_TO_DOUBLE (delta_t)) + state->residual;
-
- /* Previous value is invalid. */
- if (state->last_time == 0) /* {{{ */
- {
- if (ds_type == DS_TYPE_DERIVE)
- {
- state->last_value.derive = (derive_t) rate;
- state->residual = rate - ((gauge_t) state->last_value.derive);
- }
- else if (ds_type == DS_TYPE_COUNTER)
- {
- state->last_value.counter = (counter_t) rate;
- state->residual = rate - ((gauge_t) state->last_value.counter);
- }
- else if (ds_type == DS_TYPE_ABSOLUTE)
- {
- state->last_value.absolute = (absolute_t) rate;
- state->residual = rate - ((gauge_t) state->last_value.absolute);
- }
- else
- {
- assert (23 == 42);
- }
-
- state->last_time = t;
- return (EAGAIN);
- } /* }}} */
-
- if (ds_type == DS_TYPE_DERIVE)
- {
- derive_t delta_derive = (derive_t) delta_gauge;
-
- state->last_value.derive += delta_derive;
- state->residual = delta_gauge - ((gauge_t) delta_derive);
- }
- else if (ds_type == DS_TYPE_COUNTER)
- {
- counter_t delta_counter = (counter_t) delta_gauge;
-
- state->last_value.counter += delta_counter;
- state->residual = delta_gauge - ((gauge_t) delta_counter);
- }
- else if (ds_type == DS_TYPE_ABSOLUTE)
- {
- absolute_t delta_absolute = (absolute_t) delta_gauge;
-
- state->last_value.absolute = delta_absolute;
- state->residual = delta_gauge - ((gauge_t) delta_absolute);
- }
- else
- {
- assert (23 == 42);
- }
-
- state->last_time = t;
- *ret_value = state->last_value;
- return (0);
-} /* }}} value_t rate_to_value */
-
-int value_to_rate (value_t *ret_rate, derive_t value, /* {{{ */
- value_to_rate_state_t *state,
- int ds_type, cdtime_t t)
-{
- double interval;
-
- /* Another invalid state: The time is not increasing. */
- if (t <= state->last_time)
- {
- memset (state, 0, sizeof (*state));
- return (EINVAL);
- }
-
- interval = CDTIME_T_TO_DOUBLE(t - state->last_time);
-
- /* Previous value is invalid. */
- if (state->last_time == 0) /* {{{ */
- {
- if (ds_type == DS_TYPE_DERIVE)
- {
- state->last_value.derive = value;
- }
- else if (ds_type == DS_TYPE_COUNTER)
- {
- state->last_value.counter = (counter_t) value;
- }
- else if (ds_type == DS_TYPE_ABSOLUTE)
- {
- state->last_value.absolute = (absolute_t) value;
- }
- else
- {
- assert (23 == 42);
- }
-
- state->last_time = t;
- return (EAGAIN);
- } /* }}} */
-
- if (ds_type == DS_TYPE_DERIVE)
- {
- ret_rate->gauge = (value - state->last_value.derive) / interval;
- state->last_value.derive = value;
- }
- else if (ds_type == DS_TYPE_COUNTER)
- {
- ret_rate->gauge = (((counter_t)value) - state->last_value.counter) / interval;
- state->last_value.counter = (counter_t) value;
- }
- else if (ds_type == DS_TYPE_ABSOLUTE)
- {
- ret_rate->gauge = (((absolute_t)value) - state->last_value.absolute) / interval;
- state->last_value.absolute = (absolute_t) value;
- }
- else
- {
- assert (23 == 42);
- }
-
- state->last_time = t;
- return (0);
-} /* }}} value_t rate_to_value */
-
-int service_name_to_port_number (const char *service_name)
-{
- struct addrinfo *ai_list;
- struct addrinfo *ai_ptr;
- struct addrinfo ai_hints;
- int status;
- int service_number;
-
- if (service_name == NULL)
- return (-1);
-
- ai_list = NULL;
- memset (&ai_hints, 0, sizeof (ai_hints));
- ai_hints.ai_family = AF_UNSPEC;
-
- status = getaddrinfo (/* node = */ NULL, service_name,
- &ai_hints, &ai_list);
- if (status != 0)
- {
- ERROR ("service_name_to_port_number: getaddrinfo failed: %s",
- gai_strerror (status));
- return (-1);
- }
-
- service_number = -1;
- for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
- {
- if (ai_ptr->ai_family == AF_INET)
- {
- struct sockaddr_in *sa;
-
- sa = (void *) ai_ptr->ai_addr;
- service_number = (int) ntohs (sa->sin_port);
- }
- else if (ai_ptr->ai_family == AF_INET6)
- {
- struct sockaddr_in6 *sa;
-
- sa = (void *) ai_ptr->ai_addr;
- service_number = (int) ntohs (sa->sin6_port);
- }
-
- if ((service_number > 0) && (service_number <= 65535))
- break;
- }
-
- freeaddrinfo (ai_list);
-
- if ((service_number > 0) && (service_number <= 65535))
- return (service_number);
- return (-1);
-} /* int service_name_to_port_number */
-
-int strtoderive (const char *string, derive_t *ret_value) /* {{{ */
-{
- derive_t tmp;
- char *endptr;
-
- if ((string == NULL) || (ret_value == NULL))
- return (EINVAL);
-
- errno = 0;
- endptr = NULL;
- tmp = (derive_t) strtoll (string, &endptr, /* base = */ 0);
- if ((endptr == string) || (errno != 0))
- return (-1);
-
- *ret_value = tmp;
- return (0);
-} /* }}} int strtoderive */
-
-int strtogauge (const char *string, gauge_t *ret_value) /* {{{ */
-{
- gauge_t tmp;
- char *endptr = NULL;
-
- if ((string == NULL) || (ret_value == NULL))
- return (EINVAL);
-
- errno = 0;
- endptr = NULL;
- tmp = (gauge_t) strtod (string, &endptr);
- if (errno != 0)
- return (errno);
- else if ((endptr == NULL) || (*endptr != 0))
- return (EINVAL);
-
- *ret_value = tmp;
- return (0);
-} /* }}} int strtogauge */
-
-int strarray_add (char ***ret_array, size_t *ret_array_len, char const *str) /* {{{ */
-{
- char **array;
- size_t array_len = *ret_array_len;
-
- if (str == NULL)
- return (EINVAL);
-
- array = realloc (*ret_array,
- (array_len + 1) * sizeof (*array));
- if (array == NULL)
- return (ENOMEM);
- *ret_array = array;
-
- array[array_len] = strdup (str);
- if (array[array_len] == NULL)
- return (ENOMEM);
-
- array_len++;
- *ret_array_len = array_len;
- return (0);
-} /* }}} int strarray_add */
-
-void strarray_free (char **array, size_t array_len) /* {{{ */
-{
- size_t i;
-
- for (i = 0; i < array_len; i++)
- sfree (array[i]);
- sfree (array);
-} /* }}} void strarray_free */
diff --git a/src/common.h b/src/common.h
--- a/src/common.h
+++ /dev/null
@@ -1,357 +0,0 @@
-/**
- * collectd - src/common.h
- * Copyright (C) 2005-2014 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- * Niki W. Waibel <niki.waibel@gmx.net>
-**/
-
-#ifndef COMMON_H
-#define COMMON_H
-
-#include "collectd.h"
-#include "plugin.h"
-
-#if HAVE_PWD_H
-# include <pwd.h>
-#endif
-
-#define sfree(ptr) \
- do { \
- if((ptr) != NULL) { \
- free(ptr); \
- } \
- (ptr) = NULL; \
- } while (0)
-
-#define STATIC_ARRAY_SIZE(a) (sizeof (a) / sizeof (*(a)))
-
-#define IS_TRUE(s) ((strcasecmp ("true", (s)) == 0) \
- || (strcasecmp ("yes", (s)) == 0) \
- || (strcasecmp ("on", (s)) == 0))
-#define IS_FALSE(s) ((strcasecmp ("false", (s)) == 0) \
- || (strcasecmp ("no", (s)) == 0) \
- || (strcasecmp ("off", (s)) == 0))
-
-struct rate_to_value_state_s
-{
- value_t last_value;
- cdtime_t last_time;
- gauge_t residual;
-};
-typedef struct rate_to_value_state_s rate_to_value_state_t;
-
-struct value_to_rate_state_s
-{
- value_t last_value;
- cdtime_t last_time;
-};
-typedef struct value_to_rate_state_s value_to_rate_state_t;
-
-char *sstrncpy (char *dest, const char *src, size_t n);
-
-__attribute__ ((format(printf,3,4)))
-int ssnprintf (char *dest, size_t n, const char *format, ...);
-
-__attribute__ ((format(printf,1,2)))
-char *ssnprintf_alloc (char const *format, ...);
-
-char *sstrdup(const char *s);
-void *smalloc(size_t size);
-char *sstrerror (int errnum, char *buf, size_t buflen);
-
-/*
- * NAME
- * sread
- *
- * DESCRIPTION
- * Reads exactly `n' bytes or fails. Syntax and other behavior is analogous
- * to `read(2)'. If EOF is received the file descriptor is closed and an
- * error is returned.
- *
- * PARAMETERS
- * `fd' File descriptor to write to.
- * `buf' Buffer that is to be written.
- * `count' Number of bytes in the buffer.
- *
- * RETURN VALUE
- * Zero upon success or non-zero if an error occurred. `errno' is set in this
- * case.
- */
-ssize_t sread (int fd, void *buf, size_t count);
-
-/*
- * NAME
- * swrite
- *
- * DESCRIPTION
- * Writes exactly `n' bytes or fails. Syntax and other behavior is analogous
- * to `write(2)'.
- *
- * PARAMETERS
- * `fd' File descriptor to write to.
- * `buf' Buffer that is to be written.
- * `count' Number of bytes in the buffer.
- *
- * RETURN VALUE
- * Zero upon success or non-zero if an error occurred. `errno' is set in this
- * case.
- */
-ssize_t swrite (int fd, const void *buf, size_t count);
-
-/*
- * NAME
- * strsplit
- *
- * DESCRIPTION
- * Splits a string into parts and stores pointers to the parts in `fields'.
- * The characters split at are: " ", "\t", "\r", and "\n".
- *
- * PARAMETERS
- * `string' String to split. This string will be modified. `fields' will
- * contain pointers to parts of this string, so free'ing it
- * will destroy `fields' as well.
- * `fields' Array of strings where pointers to the parts will be stored.
- * `size' Number of elements in the array. No more than `size'
- * pointers will be stored in `fields'.
- *
- * RETURN VALUE
- * Returns the number of parts stored in `fields'.
- */
-int strsplit (char *string, char **fields, size_t size);
-
-/*
- * NAME
- * strjoin
- *
- * DESCRIPTION
- * Joins together several parts of a string using `sep' as a separator. This
- * is equivalent to the Perl built-in `join'.
- *
- * PARAMETERS
- * `dst' Buffer where the result is stored.
- * `dst_len' Length of the destination buffer. No more than this many
- * bytes will be written to the memory pointed to by `dst',
- * including the trailing null-byte.
- * `fields' Array of strings to be joined.
- * `fields_num' Number of elements in the `fields' array.
- * `sep' String to be inserted between any two elements of `fields'.
- * This string is neither prepended nor appended to the result.
- * Instead of passing "" (empty string) one can pass NULL.
- *
- * RETURN VALUE
- * Returns the number of characters in `dst', NOT including the trailing
- * null-byte. If an error occurred (empty array or `dst' too small) a value
- * smaller than zero will be returned.
- */
-int strjoin (char *dst, size_t dst_len, char **fields, size_t fields_num, const char *sep);
-
-/*
- * NAME
- * escape_slashes
- *
- * DESCRIPTION
- * Removes slashes ("/") from "buffer". If buffer contains a single slash,
- * the result will be "root". Leading slashes are removed. All other slashes
- * are replaced with underscores ("_").
- * This function is used by plugin_dispatch_values() to escape all parts of
- * the identifier.
- *
- * PARAMETERS
- * `buffer' String to be escaped.
- * `buffer_size' Size of the buffer. No more then this many bytes will be
- * written to `buffer', including the trailing null-byte.
- *
- * RETURN VALUE
- * Returns zero upon success and a value smaller than zero upon failure.
- */
-int escape_slashes (char *buffer, size_t buffer_size);
-
-/*
- * NAME
- * replace_special
- *
- * DESCRIPTION
- * Replaces any special characters (anything that's not alpha-numeric or a
- * dash) with an underscore.
- *
- * E.g. "foo$bar&" would become "foo_bar_".
- *
- * PARAMETERS
- * `buffer' String to be handled.
- * `buffer_size' Length of the string. The function returns after
- * encountering a null-byte or reading this many bytes.
- */
-void replace_special (char *buffer, size_t buffer_size);
-
-int strsubstitute (char *str, char c_from, char c_to);
-
-/*
- * NAME
- * strunescape
- *
- * DESCRIPTION
- * Replaces any escaped characters in a string with the appropriate special
- * characters. The following escaped characters are recognized:
- *
- * \t -> <tab>
- * \n -> <newline>
- * \r -> <carriage return>
- *
- * For all other escacped characters only the backslash will be removed.
- *
- * PARAMETERS
- * `buf' String to be unescaped.
- * `buf_len' Length of the string, including the terminating null-byte.
- *
- * RETURN VALUE
- * Returns zero upon success, a value less than zero else.
- */
-int strunescape (char *buf, size_t buf_len);
-
-/**
- * Removed trailing newline characters (CR and LF) from buffer, which must be
- * null terminated. Returns the length of the resulting string.
- */
-__attribute__((nonnull (1)))
-size_t strstripnewline (char *buffer);
-
-/*
- * NAME
- * timeval_cmp
- *
- * DESCRIPTION
- * Compare the two time values `tv0' and `tv1' and store the absolut value
- * of the difference in the time value pointed to by `delta' if it does not
- * equal NULL.
- *
- * RETURN VALUE
- * Returns an integer less than, equal to, or greater than zero if `tv0' is
- * less than, equal to, or greater than `tv1' respectively.
- */
-int timeval_cmp (struct timeval tv0, struct timeval tv1, struct timeval *delta);
-
-/* make sure tv_usec stores less than a second */
-#define NORMALIZE_TIMEVAL(tv) \
- do { \
- (tv).tv_sec += (tv).tv_usec / 1000000; \
- (tv).tv_usec = (tv).tv_usec % 1000000; \
- } while (0)
-
-/* make sure tv_sec stores less than a second */
-#define NORMALIZE_TIMESPEC(tv) \
- do { \
- (tv).tv_sec += (tv).tv_nsec / 1000000000; \
- (tv).tv_nsec = (tv).tv_nsec % 1000000000; \
- } while (0)
-
-int check_create_dir (const char *file_orig);
-
-#ifdef HAVE_LIBKSTAT
-int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name);
-long long get_kstat_value (kstat_t *ksp, char *name);
-#endif
-
-#ifndef HAVE_HTONLL
-unsigned long long ntohll (unsigned long long n);
-unsigned long long htonll (unsigned long long n);
-#endif
-
-#if FP_LAYOUT_NEED_NOTHING
-# define ntohd(d) (d)
-# define htond(d) (d)
-#elif FP_LAYOUT_NEED_ENDIANFLIP || FP_LAYOUT_NEED_INTSWAP
-double ntohd (double d);
-double htond (double d);
-#else
-# error "Don't know how to convert between host and network representation of doubles."
-#endif
-
-int format_name (char *ret, int ret_len,
- const char *hostname,
- const char *plugin, const char *plugin_instance,
- const char *type, const char *type_instance);
-#define FORMAT_VL(ret, ret_len, vl) \
- format_name (ret, ret_len, (vl)->host, (vl)->plugin, (vl)->plugin_instance, \
- (vl)->type, (vl)->type_instance)
-int format_values (char *ret, size_t ret_len,
- const data_set_t *ds, const value_list_t *vl,
- _Bool store_rates);
-
-int parse_identifier (char *str, char **ret_host,
- char **ret_plugin, char **ret_plugin_instance,
- char **ret_type, char **ret_type_instance);
-int parse_identifier_vl (const char *str, value_list_t *vl);
-int parse_value (const char *value, value_t *ret_value, int ds_type);
-int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds);
-
-#if !HAVE_GETPWNAM_R
-int getpwnam_r (const char *name, struct passwd *pwbuf, char *buf,
- size_t buflen, struct passwd **pwbufp);
-#endif
-
-int notification_init (notification_t *n, int severity, const char *message,
- const char *host,
- const char *plugin, const char *plugin_instance,
- const char *type, const char *type_instance);
-#define NOTIFICATION_INIT_VL(n, vl) \
- notification_init (n, NOTIF_FAILURE, NULL, \
- (vl)->host, (vl)->plugin, (vl)->plugin_instance, \
- (vl)->type, (vl)->type_instance)
-
-typedef int (*dirwalk_callback_f)(const char *dirname, const char *filename,
- void *user_data);
-int walk_directory (const char *dir, dirwalk_callback_f callback,
- void *user_data, int hidden);
-/* Returns the number of bytes read or negative on error. */
-ssize_t read_file_contents (char const *filename, char *buf, size_t bufsize);
-
-counter_t counter_diff (counter_t old_value, counter_t new_value);
-
-/* Convert a rate back to a value_t. When converting to a derive_t, counter_t
- * or absoltue_t, take fractional residuals into account. This is important
- * when scaling counters, for example.
- * Returns zero on success. Returns EAGAIN when called for the first time; in
- * this case the value_t is invalid and the next call should succeed. Other
- * return values indicate an error. */
-int rate_to_value (value_t *ret_value, gauge_t rate,
- rate_to_value_state_t *state, int ds_type, cdtime_t t);
-
-int value_to_rate (value_t *ret_rate, derive_t value,
- value_to_rate_state_t *state, int ds_type, cdtime_t t);
-
-/* Converts a service name (a string) to a port number
- * (in the range [1-65535]). Returns less than zero on error. */
-int service_name_to_port_number (const char *service_name);
-
-/** Parse a string to a derive_t value. Returns zero on success or non-zero on
- * failure. If failure is returned, ret_value is not touched. */
-int strtoderive (const char *string, derive_t *ret_value);
-
-/** Parse a string to a gauge_t value. Returns zero on success or non-zero on
- * failure. If failure is returned, ret_value is not touched. */
-int strtogauge (const char *string, gauge_t *ret_value);
-
-int strarray_add (char ***ret_array, size_t *ret_array_len, char const *str);
-void strarray_free (char **array, size_t array_len);
-
-#endif /* COMMON_H */
diff --git a/src/configfile.c b/src/configfile.c
--- a/src/configfile.c
+++ /dev/null
@@ -1,1353 +0,0 @@
-/**
- * collectd - src/configfile.c
- * Copyright (C) 2005-2011 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- * Sebastian tokkee Harl <sh at tokkee.org>
- **/
-
-#include "collectd.h"
-
-#include "liboconfig/oconfig.h"
-
-#include "common.h"
-#include "plugin.h"
-#include "configfile.h"
-#include "types_list.h"
-#include "filter_chain.h"
-
-#if HAVE_WORDEXP_H
-# include <wordexp.h>
-#endif /* HAVE_WORDEXP_H */
-
-#if HAVE_FNMATCH_H
-# include <fnmatch.h>
-#endif /* HAVE_FNMATCH_H */
-
-#if HAVE_LIBGEN_H
-# include <libgen.h>
-#endif /* HAVE_LIBGEN_H */
-
-#define ESCAPE_NULL(str) ((str) == NULL ? "(null)" : (str))
-
-/*
- * Private types
- */
-typedef struct cf_callback
-{
- const char *type;
- int (*callback) (const char *, const char *);
- const char **keys;
- int keys_num;
- plugin_ctx_t ctx;
- struct cf_callback *next;
-} cf_callback_t;
-
-typedef struct cf_complex_callback_s
-{
- char *type;
- int (*callback) (oconfig_item_t *);
- plugin_ctx_t ctx;
- struct cf_complex_callback_s *next;
-} cf_complex_callback_t;
-
-typedef struct cf_value_map_s
-{
- char *key;
- int (*func) (const oconfig_item_t *);
-} cf_value_map_t;
-
-typedef struct cf_global_option_s
-{
- char *key;
- char *value;
- char *def;
-} cf_global_option_t;
-
-/*
- * Prototypes of callback functions
- */
-static int dispatch_value_typesdb (const oconfig_item_t *ci);
-static int dispatch_value_plugindir (const oconfig_item_t *ci);
-static int dispatch_loadplugin (const oconfig_item_t *ci);
-
-/*
- * Private variables
- */
-static cf_callback_t *first_callback = NULL;
-static cf_complex_callback_t *complex_callback_head = NULL;
-
-static cf_value_map_t cf_value_map[] =
-{
- {"TypesDB", dispatch_value_typesdb},
- {"PluginDir", dispatch_value_plugindir},
- {"LoadPlugin", dispatch_loadplugin}
-};
-static int cf_value_map_num = STATIC_ARRAY_SIZE (cf_value_map);
-
-static cf_global_option_t cf_global_options[] =
-{
- {"BaseDir", NULL, PKGLOCALSTATEDIR},
- {"PIDFile", NULL, PIDFILE},
- {"Hostname", NULL, NULL},
- {"FQDNLookup", NULL, "true"},
- {"Interval", NULL, NULL},
- {"ReadThreads", NULL, "5"},
- {"WriteThreads", NULL, "5"},
- {"WriteQueueLimitHigh", NULL, NULL},
- {"WriteQueueLimitLow", NULL, NULL},
- {"Timeout", NULL, "2"},
- {"AutoLoadPlugin", NULL, "false"},
- {"CollectInternalStats", NULL, "false"},
- {"PreCacheChain", NULL, "PreCache"},
- {"PostCacheChain", NULL, "PostCache"},
- {"MaxReadInterval", NULL, "86400"}
-};
-static int cf_global_options_num = STATIC_ARRAY_SIZE (cf_global_options);
-
-static int cf_default_typesdb = 1;
-
-/*
- * Functions to handle register/unregister, search, and other plugin related
- * stuff
- */
-static cf_callback_t *cf_search (const char *type)
-{
- cf_callback_t *cf_cb;
-
- if (type == NULL)
- return (NULL);
-
- for (cf_cb = first_callback; cf_cb != NULL; cf_cb = cf_cb->next)
- if (strcasecmp (cf_cb->type, type) == 0)
- break;
-
- return (cf_cb);
-}
-
-static int cf_dispatch (const char *type, const char *orig_key,
- const char *orig_value)
-{
- cf_callback_t *cf_cb;
- plugin_ctx_t old_ctx;
- char *key;
- char *value;
- int ret;
- int i;
-
- DEBUG ("type = %s, key = %s, value = %s",
- ESCAPE_NULL(type),
- ESCAPE_NULL(orig_key),
- ESCAPE_NULL(orig_value));
-
- if ((cf_cb = cf_search (type)) == NULL)
- {
- WARNING ("Found a configuration for the `%s' plugin, but "
- "the plugin isn't loaded or didn't register "
- "a configuration callback.", type);
- return (-1);
- }
-
- if ((key = strdup (orig_key)) == NULL)
- return (1);
- if ((value = strdup (orig_value)) == NULL)
- {
- free (key);
- return (2);
- }
-
- ret = -1;
-
- old_ctx = plugin_set_ctx (cf_cb->ctx);
-
- for (i = 0; i < cf_cb->keys_num; i++)
- {
- if ((cf_cb->keys[i] != NULL)
- && (strcasecmp (cf_cb->keys[i], key) == 0))
- {
- ret = (*cf_cb->callback) (key, value);
- break;
- }
- }
-
- plugin_set_ctx (old_ctx);
-
- if (i >= cf_cb->keys_num)
- WARNING ("Plugin `%s' did not register for value `%s'.", type, key);
-
- free (key);
- free (value);
-
- DEBUG ("cf_dispatch: return (%i)", ret);
-
- return (ret);
-} /* int cf_dispatch */
-
-static int dispatch_global_option (const oconfig_item_t *ci)
-{
- if (ci->values_num != 1)
- return (-1);
- if (ci->values[0].type == OCONFIG_TYPE_STRING)
- return (global_option_set (ci->key, ci->values[0].value.string));
- else if (ci->values[0].type == OCONFIG_TYPE_NUMBER)
- {
- char tmp[128];
- ssnprintf (tmp, sizeof (tmp), "%lf", ci->values[0].value.number);
- return (global_option_set (ci->key, tmp));
- }
- else if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN)
- {
- if (ci->values[0].value.boolean)
- return (global_option_set (ci->key, "true"));
- else
- return (global_option_set (ci->key, "false"));
- }
-
- return (-1);
-} /* int dispatch_global_option */
-
-static int dispatch_value_typesdb (const oconfig_item_t *ci)
-{
- int i = 0;
-
- assert (strcasecmp (ci->key, "TypesDB") == 0);
-
- cf_default_typesdb = 0;
-
- if (ci->values_num < 1) {
- ERROR ("configfile: `TypesDB' needs at least one argument.");
- return (-1);
- }
-
- for (i = 0; i < ci->values_num; ++i)
- {
- if (OCONFIG_TYPE_STRING != ci->values[i].type) {
- WARNING ("configfile: TypesDB: Skipping %i. argument which "
- "is not a string.", i + 1);
- continue;
- }
-
- read_types_list (ci->values[i].value.string);
- }
- return (0);
-} /* int dispatch_value_typesdb */
-
-static int dispatch_value_plugindir (const oconfig_item_t *ci)
-{
- assert (strcasecmp (ci->key, "PluginDir") == 0);
-
- if (ci->values_num != 1)
- return (-1);
- if (ci->values[0].type != OCONFIG_TYPE_STRING)
- return (-1);
-
- plugin_set_dir (ci->values[0].value.string);
- return (0);
-}
-
-static int dispatch_loadplugin (const oconfig_item_t *ci)
-{
- int i;
- const char *name;
- unsigned int flags = 0;
- plugin_ctx_t ctx;
- plugin_ctx_t old_ctx;
- int ret_val;
-
- assert (strcasecmp (ci->key, "LoadPlugin") == 0);
-
- if (ci->values_num != 1)
- return (-1);
- if (ci->values[0].type != OCONFIG_TYPE_STRING)
- return (-1);
-
- name = ci->values[0].value.string;
- if (strcmp ("libvirt", name) == 0)
- name = "virt";
-
- /* default to the global interval set before loading this plugin */
- memset (&ctx, 0, sizeof (ctx));
- ctx.interval = cf_get_default_interval ();
-
- for (i = 0; i < ci->children_num; ++i) {
- if (strcasecmp("Globals", ci->children[i].key) == 0)
- cf_util_get_flag (ci->children + i, &flags, PLUGIN_FLAGS_GLOBAL);
- else if (strcasecmp ("Interval", ci->children[i].key) == 0) {
- if (cf_util_get_cdtime (ci->children + i, &ctx.interval) != 0) {
- /* cf_util_get_cdtime will log an error */
- continue;
- }
- }
- else {
- WARNING("Ignoring unknown LoadPlugin option \"%s\" "
- "for plugin \"%s\"",
- ci->children[i].key, ci->values[0].value.string);
- }
- }
-
- old_ctx = plugin_set_ctx (ctx);
- ret_val = plugin_load (name, (uint32_t) flags);
- /* reset to the "global" context */
- plugin_set_ctx (old_ctx);
-
- return (ret_val);
-} /* int dispatch_value_loadplugin */
-
-static int dispatch_value_plugin (const char *plugin, oconfig_item_t *ci)
-{
- char buffer[4096];
- char *buffer_ptr;
- int buffer_free;
- int i;
-
- buffer_ptr = buffer;
- buffer_free = sizeof (buffer);
-
- for (i = 0; i < ci->values_num; i++)
- {
- int status = -1;
-
- if (ci->values[i].type == OCONFIG_TYPE_STRING)
- status = ssnprintf (buffer_ptr, buffer_free, " %s",
- ci->values[i].value.string);
- else if (ci->values[i].type == OCONFIG_TYPE_NUMBER)
- status = ssnprintf (buffer_ptr, buffer_free, " %lf",
- ci->values[i].value.number);
- else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN)
- status = ssnprintf (buffer_ptr, buffer_free, " %s",
- ci->values[i].value.boolean
- ? "true" : "false");
-
- if ((status < 0) || (status >= buffer_free))
- return (-1);
- buffer_free -= status;
- buffer_ptr += status;
- }
- /* skip the initial space */
- buffer_ptr = buffer + 1;
-
- return (cf_dispatch (plugin, ci->key, buffer_ptr));
-} /* int dispatch_value_plugin */
-
-static int dispatch_value (const oconfig_item_t *ci)
-{
- int ret = -2;
- int i;
-
- for (i = 0; i < cf_value_map_num; i++)
- if (strcasecmp (cf_value_map[i].key, ci->key) == 0)
- {
- ret = cf_value_map[i].func (ci);
- break;
- }
-
- for (i = 0; i < cf_global_options_num; i++)
- if (strcasecmp (cf_global_options[i].key, ci->key) == 0)
- {
- ret = dispatch_global_option (ci);
- break;
- }
-
- return (ret);
-} /* int dispatch_value */
-
-static int dispatch_block_plugin (oconfig_item_t *ci)
-{
- int i;
- char *name;
-
- cf_complex_callback_t *cb;
-
- if (strcasecmp (ci->key, "Plugin") != 0)
- return (-1);
- if (ci->values_num < 1)
- return (-1);
- if (ci->values[0].type != OCONFIG_TYPE_STRING)
- return (-1);
-
- name = ci->values[0].value.string;
- if (strcmp ("libvirt", name) == 0)
- {
- /* TODO(octo): Remove this legacy. */
- WARNING ("The \"libvirt\" plugin has been renamed to \"virt\" to avoid problems with the build system. "
- "Your configuration is still using the old name. "
- "Please change it to use \"virt\" as soon as possible. "
- "This compatibility code will go away eventually.");
- name = "virt";
- }
-
- if (IS_TRUE (global_option_get ("AutoLoadPlugin")))
- {
- int status;
-
- status = plugin_load (name, /* flags = */ 0);
- if (status != 0)
- {
- ERROR ("Automatically loading plugin \"%s\" failed "
- "with status %i.", name, status);
- return (status);
- }
- }
-
- /* Check for a complex callback first */
- for (cb = complex_callback_head; cb != NULL; cb = cb->next)
- {
- if (strcasecmp (name, cb->type) == 0)
- {
- plugin_ctx_t old_ctx;
- int ret_val;
-
- old_ctx = plugin_set_ctx (cb->ctx);
- ret_val = (cb->callback (ci));
- plugin_set_ctx (old_ctx);
- return (ret_val);
- }
- }
-
- /* 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
- {
- WARNING ("There is a `%s' block within the "
- "configuration for the %s plugin. "
- "The plugin either only expects "
- "\"simple\" configuration statements "
- "or wasn't loaded using `LoadPlugin'."
- " Please check your configuration.",
- ci->children[i].key, name);
- }
- }
-
- return (0);
-}
-
-
-static int dispatch_block (oconfig_item_t *ci)
-{
- if (strcasecmp (ci->key, "LoadPlugin") == 0)
- return (dispatch_loadplugin (ci));
- else if (strcasecmp (ci->key, "Plugin") == 0)
- return (dispatch_block_plugin (ci));
- else if (strcasecmp (ci->key, "Chain") == 0)
- return (fc_configure (ci));
-
- return (0);
-}
-
-static int cf_ci_replace_child (oconfig_item_t *dst, oconfig_item_t *src,
- int offset)
-{
- oconfig_item_t *temp;
- int i;
-
- assert (offset >= 0);
- assert (dst->children_num > offset);
-
- /* Free the memory used by the replaced child. Usually that's the
- * `Include "blah"' statement. */
- temp = dst->children + offset;
- for (i = 0; i < temp->values_num; i++)
- {
- if (temp->values[i].type == OCONFIG_TYPE_STRING)
- {
- sfree (temp->values[i].value.string);
- }
- }
- sfree (temp->values);
- temp = NULL;
-
- /* If (src->children_num == 0) the array size is decreased. If offset
- * is _not_ the last element, (offset < (dst->children_num - 1)), then
- * we need to move the trailing elements before resizing the array. */
- if ((src->children_num == 0) && (offset < (dst->children_num - 1)))
- {
- int nmemb = dst->children_num - (offset + 1);
- memmove (dst->children + offset, dst->children + offset + 1,
- sizeof (oconfig_item_t) * nmemb);
- }
-
- /* Resize the memory containing the children to be big enough to hold
- * all children. */
- if (dst->children_num + src->children_num - 1 == 0)
- {
- dst->children_num = 0;
- return (0);
- }
-
- temp = (oconfig_item_t *) realloc (dst->children,
- sizeof (oconfig_item_t)
- * (dst->children_num + src->children_num - 1));
- if (temp == NULL)
- {
- ERROR ("configfile: realloc failed.");
- return (-1);
- }
- dst->children = temp;
-
- /* If there are children behind the include statement, and they have
- * not yet been moved because (src->children_num == 0), then move them
- * to the end of the list, so that the new children have room before
- * them. */
- if ((src->children_num > 0)
- && ((dst->children_num - (offset + 1)) > 0))
- {
- int nmemb = dst->children_num - (offset + 1);
- int old_offset = offset + 1;
- int new_offset = offset + src->children_num;
-
- memmove (dst->children + new_offset,
- dst->children + old_offset,
- sizeof (oconfig_item_t) * nmemb);
- }
-
- /* Last but not least: If there are new children, copy them to the
- * memory reserved for them. */
- if (src->children_num > 0)
- {
- memcpy (dst->children + offset,
- src->children,
- sizeof (oconfig_item_t) * src->children_num);
- }
-
- /* Update the number of children. */
- dst->children_num += (src->children_num - 1);
-
- return (0);
-} /* int cf_ci_replace_child */
-
-static int cf_ci_append_children (oconfig_item_t *dst, oconfig_item_t *src)
-{
- oconfig_item_t *temp;
-
- if ((src == NULL) || (src->children_num == 0))
- return (0);
-
- temp = (oconfig_item_t *) realloc (dst->children,
- sizeof (oconfig_item_t)
- * (dst->children_num + src->children_num));
- if (temp == NULL)
- {
- ERROR ("configfile: realloc failed.");
- return (-1);
- }
- dst->children = temp;
-
- memcpy (dst->children + dst->children_num,
- src->children,
- sizeof (oconfig_item_t)
- * src->children_num);
- dst->children_num += src->children_num;
-
- return (0);
-} /* int cf_ci_append_children */
-
-#define CF_MAX_DEPTH 8
-static oconfig_item_t *cf_read_generic (const char *path,
- const char *pattern, int depth);
-
-static int cf_include_all (oconfig_item_t *root, int depth)
-{
- int i;
-
- for (i = 0; i < root->children_num; i++)
- {
- oconfig_item_t *new;
- oconfig_item_t *old;
-
- char *pattern = NULL;
-
- int j;
-
- if (strcasecmp (root->children[i].key, "Include") != 0)
- continue;
-
- old = root->children + i;
-
- if ((old->values_num != 1)
- || (old->values[0].type != OCONFIG_TYPE_STRING))
- {
- ERROR ("configfile: `Include' needs exactly one string argument.");
- continue;
- }
-
- for (j = 0; j < old->children_num; ++j)
- {
- oconfig_item_t *child = old->children + j;
-
- if (strcasecmp (child->key, "Filter") == 0)
- cf_util_get_string (child, &pattern);
- else
- ERROR ("configfile: Option `%s' not allowed in <Include> block.",
- child->key);
- }
-
- new = cf_read_generic (old->values[0].value.string, pattern, depth + 1);
- sfree (pattern);
-
- if (new == NULL)
- return (-1);
-
- /* Now replace the i'th child in `root' with `new'. */
- if (cf_ci_replace_child (root, new, i) < 0)
- return (-1);
-
- /* ... and go back to the new i'th child. */
- --i;
-
- sfree (new->values);
- sfree (new);
- } /* for (i = 0; i < root->children_num; i++) */
-
- return (0);
-} /* int cf_include_all */
-
-static oconfig_item_t *cf_read_file (const char *file,
- const char *pattern, int depth)
-{
- oconfig_item_t *root;
- int status;
-
- assert (depth < CF_MAX_DEPTH);
-
- if (pattern != NULL) {
-#if HAVE_FNMATCH_H && HAVE_LIBGEN_H
- char *tmp = sstrdup (file);
- char *filename = basename (tmp);
-
- if ((filename != NULL) && (fnmatch (pattern, filename, 0) != 0)) {
- DEBUG ("configfile: Not including `%s' because it "
- "does not match pattern `%s'.",
- filename, pattern);
- free (tmp);
- return (NULL);
- }
-
- free (tmp);
-#else
- ERROR ("configfile: Cannot apply pattern filter '%s' "
- "to file '%s': functions basename() and / or "
- "fnmatch() not available.", pattern, file);
-#endif /* HAVE_FNMATCH_H && HAVE_LIBGEN_H */
- }
-
- root = oconfig_parse_file (file);
- if (root == NULL)
- {
- ERROR ("configfile: Cannot read file `%s'.", file);
- return (NULL);
- }
-
- status = cf_include_all (root, depth);
- if (status != 0)
- {
- oconfig_free (root);
- return (NULL);
- }
-
- return (root);
-} /* oconfig_item_t *cf_read_file */
-
-static int cf_compare_string (const void *p1, const void *p2)
-{
- return strcmp (*(const char **) p1, *(const char **) p2);
-}
-
-static oconfig_item_t *cf_read_dir (const char *dir,
- const char *pattern, int depth)
-{
- oconfig_item_t *root = NULL;
- DIR *dh;
- struct dirent *de;
- char **filenames = NULL;
- int filenames_num = 0;
- int status;
- int i;
-
- assert (depth < CF_MAX_DEPTH);
-
- dh = opendir (dir);
- if (dh == NULL)
- {
- char errbuf[1024];
- ERROR ("configfile: opendir failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (NULL);
- }
-
- root = (oconfig_item_t *) malloc (sizeof (oconfig_item_t));
- if (root == NULL)
- {
- ERROR ("configfile: malloc failed.");
- return (NULL);
- }
- memset (root, 0, sizeof (oconfig_item_t));
-
- while ((de = readdir (dh)) != NULL)
- {
- char name[1024];
- char **tmp;
-
- if ((de->d_name[0] == '.') || (de->d_name[0] == 0))
- continue;
-
- status = ssnprintf (name, sizeof (name), "%s/%s",
- dir, de->d_name);
- if ((status < 0) || ((size_t) status >= sizeof (name)))
- {
- ERROR ("configfile: Not including `%s/%s' because its"
- " name is too long.",
- dir, de->d_name);
- for (i = 0; i < filenames_num; ++i)
- free (filenames[i]);
- free (filenames);
- free (root);
- return (NULL);
- }
-
- ++filenames_num;
- tmp = (char **) realloc (filenames,
- filenames_num * sizeof (*filenames));
- if (tmp == NULL) {
- ERROR ("configfile: realloc failed.");
- for (i = 0; i < filenames_num - 1; ++i)
- free (filenames[i]);
- free (filenames);
- free (root);
- return (NULL);
- }
- filenames = tmp;
-
- filenames[filenames_num - 1] = sstrdup (name);
- }
-
- qsort ((void *) filenames, filenames_num, sizeof (*filenames),
- cf_compare_string);
-
- for (i = 0; i < filenames_num; ++i)
- {
- oconfig_item_t *temp;
- char *name = filenames[i];
-
- temp = cf_read_generic (name, pattern, depth);
- if (temp == NULL)
- {
- /* An error should already have been reported. */
- sfree (name);
- continue;
- }
-
- cf_ci_append_children (root, temp);
- sfree (temp->children);
- sfree (temp);
-
- free (name);
- }
-
- free(filenames);
- return (root);
-} /* oconfig_item_t *cf_read_dir */
-
-/*
- * cf_read_generic
- *
- * Path is stat'ed and either cf_read_file or cf_read_dir is called
- * accordingly.
- *
- * There are two versions of this function: If `wordexp' exists shell wildcards
- * will be expanded and the function will include all matches found. If
- * `wordexp' (or, more precisely, it's header file) is not available the
- * simpler function is used which does not do any such expansion.
- */
-#if HAVE_WORDEXP_H
-static oconfig_item_t *cf_read_generic (const char *path,
- const char *pattern, int depth)
-{
- oconfig_item_t *root = NULL;
- int status;
- const char *path_ptr;
- wordexp_t we;
- size_t i;
-
- if (depth >= CF_MAX_DEPTH)
- {
- ERROR ("configfile: Not including `%s' because the maximum "
- "nesting depth has been reached.", path);
- return (NULL);
- }
-
- status = wordexp (path, &we, WRDE_NOCMD);
- if (status != 0)
- {
- ERROR ("configfile: wordexp (%s) failed.", path);
- return (NULL);
- }
-
- root = (oconfig_item_t *) malloc (sizeof (oconfig_item_t));
- if (root == NULL)
- {
- ERROR ("configfile: malloc failed.");
- return (NULL);
- }
- memset (root, '\0', sizeof (oconfig_item_t));
-
- /* wordexp() might return a sorted list already. That's not
- * documented though, so let's make sure we get what we want. */
- qsort ((void *) we.we_wordv, we.we_wordc, sizeof (*we.we_wordv),
- cf_compare_string);
-
- for (i = 0; i < we.we_wordc; i++)
- {
- oconfig_item_t *temp;
- struct stat statbuf;
-
- path_ptr = we.we_wordv[i];
-
- status = stat (path_ptr, &statbuf);
- if (status != 0)
- {
- char errbuf[1024];
- WARNING ("configfile: stat (%s) failed: %s",
- path_ptr,
- sstrerror (errno, errbuf, sizeof (errbuf)));
- continue;
- }
-
- if (S_ISREG (statbuf.st_mode))
- temp = cf_read_file (path_ptr, pattern, depth);
- else if (S_ISDIR (statbuf.st_mode))
- temp = cf_read_dir (path_ptr, pattern, depth);
- else
- {
- WARNING ("configfile: %s is neither a file nor a "
- "directory.", path);
- continue;
- }
-
- if (temp == NULL) {
- oconfig_free (root);
- return (NULL);
- }
-
- cf_ci_append_children (root, temp);
- sfree (temp->children);
- sfree (temp);
- }
-
- wordfree (&we);
-
- return (root);
-} /* oconfig_item_t *cf_read_generic */
-/* #endif HAVE_WORDEXP_H */
-
-#else /* if !HAVE_WORDEXP_H */
-static oconfig_item_t *cf_read_generic (const char *path,
- const char *pattern, int depth)
-{
- struct stat statbuf;
- int status;
-
- if (depth >= CF_MAX_DEPTH)
- {
- ERROR ("configfile: Not including `%s' because the maximum "
- "nesting depth has been reached.", path);
- return (NULL);
- }
-
- status = stat (path, &statbuf);
- if (status != 0)
- {
- char errbuf[1024];
- ERROR ("configfile: stat (%s) failed: %s",
- path,
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (NULL);
- }
-
- if (S_ISREG (statbuf.st_mode))
- return (cf_read_file (path, pattern, depth));
- else if (S_ISDIR (statbuf.st_mode))
- return (cf_read_dir (path, pattern, depth));
-
- ERROR ("configfile: %s is neither a file nor a directory.", path);
- return (NULL);
-} /* oconfig_item_t *cf_read_generic */
-#endif /* !HAVE_WORDEXP_H */
-
-/*
- * Public functions
- */
-int global_option_set (const char *option, const char *value)
-{
- int i;
-
- DEBUG ("option = %s; value = %s;", option, value);
-
- for (i = 0; i < cf_global_options_num; i++)
- if (strcasecmp (cf_global_options[i].key, option) == 0)
- break;
-
- if (i >= cf_global_options_num)
- return (-1);
-
- if (strcasecmp (option, "PIDFile") == 0 && pidfile_from_cli == 1)
- {
- DEBUG ("Configfile: Ignoring `PIDFILE' option because "
- "command-line option `-P' take precedence.");
- return (0);
- }
-
- sfree (cf_global_options[i].value);
-
- if (value != NULL)
- cf_global_options[i].value = strdup (value);
- else
- cf_global_options[i].value = NULL;
-
- return (0);
-}
-
-const char *global_option_get (const char *option)
-{
- int i;
-
- for (i = 0; i < cf_global_options_num; i++)
- if (strcasecmp (cf_global_options[i].key, option) == 0)
- break;
-
- if (i >= cf_global_options_num)
- return (NULL);
-
- return ((cf_global_options[i].value != NULL)
- ? cf_global_options[i].value
- : cf_global_options[i].def);
-} /* char *global_option_get */
-
-long global_option_get_long (const char *option, long default_value)
-{
- const char *str;
- long value;
-
- str = global_option_get (option);
- if (NULL == str)
- return (default_value);
-
- errno = 0;
- value = strtol (str, /* endptr = */ NULL, /* base = */ 0);
- if (errno != 0)
- return (default_value);
-
- return (value);
-} /* char *global_option_get_long */
-
-cdtime_t global_option_get_time (const char *name, cdtime_t def) /* {{{ */
-{
- char const *optstr;
- char *endptr = NULL;
- double v;
-
- optstr = global_option_get (name);
- if (optstr == NULL)
- return (def);
-
- errno = 0;
- v = strtod (optstr, &endptr);
- if ((endptr == NULL) || (*endptr != 0) || (errno != 0))
- return (def);
- else if (v <= 0.0)
- return (def);
-
- return (DOUBLE_TO_CDTIME_T (v));
-} /* }}} cdtime_t global_option_get_time */
-
-cdtime_t cf_get_default_interval (void)
-{
- return (global_option_get_time ("Interval",
- DOUBLE_TO_CDTIME_T (COLLECTD_DEFAULT_INTERVAL)));
-}
-
-void cf_unregister (const char *type)
-{
- cf_callback_t *this, *prev;
-
- for (prev = NULL, this = first_callback;
- this != NULL;
- prev = this, this = this->next)
- if (strcasecmp (this->type, type) == 0)
- {
- if (prev == NULL)
- first_callback = this->next;
- else
- prev->next = this->next;
-
- free (this);
- break;
- }
-} /* 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)
-{
- cf_callback_t *cf_cb;
-
- /* Remove this module from the list, if it already exists */
- cf_unregister (type);
-
- /* This pointer will be free'd in `cf_unregister' */
- if ((cf_cb = (cf_callback_t *) malloc (sizeof (cf_callback_t))) == NULL)
- return;
-
- cf_cb->type = type;
- cf_cb->callback = callback;
- cf_cb->keys = keys;
- cf_cb->keys_num = keys_num;
- cf_cb->ctx = plugin_get_ctx ();
-
- cf_cb->next = first_callback;
- 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;
-
- new->ctx = plugin_get_ctx ();
-
- 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;
- int i;
-
- conf = cf_read_generic (filename, /* pattern = */ NULL, /* depth = */ 0);
- if (conf == NULL)
- {
- ERROR ("Unable to read config file %s.", filename);
- return (-1);
- }
- else if (conf->children_num == 0)
- {
- ERROR ("Configuration file %s is empty.", filename);
- oconfig_free (conf);
- return (-1);
- }
-
- for (i = 0; i < conf->children_num; i++)
- {
- if (conf->children[i].children == NULL)
- dispatch_value (conf->children + i);
- else
- dispatch_block (conf->children + i);
- }
-
- oconfig_free (conf);
-
- /* Read the default types.db if no `TypesDB' option was given. */
- if (cf_default_typesdb)
- read_types_list (PKGDATADIR"/types.db");
-
- return (0);
-} /* int cf_read */
-
-/* Assures the config option is a string, duplicates it and returns the copy in
- * "ret_string". If necessary "*ret_string" is freed first. Returns zero upon
- * success. */
-int cf_util_get_string (const oconfig_item_t *ci, char **ret_string) /* {{{ */
-{
- char *string;
-
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
- {
- ERROR ("cf_util_get_string: The %s option requires "
- "exactly one string argument.", ci->key);
- return (-1);
- }
-
- string = strdup (ci->values[0].value.string);
- if (string == NULL)
- return (-1);
-
- if (*ret_string != NULL)
- sfree (*ret_string);
- *ret_string = string;
-
- return (0);
-} /* }}} int cf_util_get_string */
-
-/* Assures the config option is a string and copies it to the provided buffer.
- * Assures null-termination. */
-int cf_util_get_string_buffer (const oconfig_item_t *ci, char *buffer, /* {{{ */
- size_t buffer_size)
-{
- if ((ci == NULL) || (buffer == NULL) || (buffer_size < 1))
- return (EINVAL);
-
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
- {
- ERROR ("cf_util_get_string_buffer: The %s option requires "
- "exactly one string argument.", ci->key);
- return (-1);
- }
-
- strncpy (buffer, ci->values[0].value.string, buffer_size);
- buffer[buffer_size - 1] = 0;
-
- return (0);
-} /* }}} int cf_util_get_string_buffer */
-
-/* Assures the config option is a number and returns it as an int. */
-int cf_util_get_int (const oconfig_item_t *ci, int *ret_value) /* {{{ */
-{
- if ((ci == NULL) || (ret_value == NULL))
- return (EINVAL);
-
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
- {
- ERROR ("cf_util_get_int: The %s option requires "
- "exactly one numeric argument.", ci->key);
- return (-1);
- }
-
- *ret_value = (int) ci->values[0].value.number;
-
- return (0);
-} /* }}} int cf_util_get_int */
-
-int cf_util_get_double (const oconfig_item_t *ci, double *ret_value) /* {{{ */
-{
- if ((ci == NULL) || (ret_value == NULL))
- return (EINVAL);
-
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
- {
- ERROR ("cf_util_get_double: The %s option requires "
- "exactly one numeric argument.", ci->key);
- return (-1);
- }
-
- *ret_value = ci->values[0].value.number;
-
- return (0);
-} /* }}} int cf_util_get_double */
-
-int cf_util_get_boolean (const oconfig_item_t *ci, _Bool *ret_bool) /* {{{ */
-{
- if ((ci == NULL) || (ret_bool == NULL))
- return (EINVAL);
-
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
- {
- ERROR ("cf_util_get_boolean: The %s option requires "
- "exactly one boolean argument.", ci->key);
- return (-1);
- }
-
- *ret_bool = ci->values[0].value.boolean ? 1 : 0;
-
- return (0);
-} /* }}} int cf_util_get_boolean */
-
-int cf_util_get_flag (const oconfig_item_t *ci, /* {{{ */
- unsigned int *ret_value, unsigned int flag)
-{
- int status;
- _Bool b;
-
- if (ret_value == NULL)
- return (EINVAL);
-
- b = 0;
- status = cf_util_get_boolean (ci, &b);
- if (status != 0)
- return (status);
-
- if (b)
- {
- *ret_value |= flag;
- }
- else
- {
- *ret_value &= ~flag;
- }
-
- return (0);
-} /* }}} int cf_util_get_flag */
-
-/* Assures that the config option is a string or a number if the correct range
- * of 1-65535. The string is then converted to a port number using
- * `service_name_to_port_number' and returned.
- * Returns the port number in the range [1-65535] or less than zero upon
- * failure. */
-int cf_util_get_port_number (const oconfig_item_t *ci) /* {{{ */
-{
- int tmp;
-
- if ((ci->values_num != 1)
- || ((ci->values[0].type != OCONFIG_TYPE_STRING)
- && (ci->values[0].type != OCONFIG_TYPE_NUMBER)))
- {
- ERROR ("cf_util_get_port_number: The \"%s\" option requires "
- "exactly one string argument.", ci->key);
- return (-1);
- }
-
- if (ci->values[0].type == OCONFIG_TYPE_STRING)
- return (service_name_to_port_number (ci->values[0].value.string));
-
- assert (ci->values[0].type == OCONFIG_TYPE_NUMBER);
- tmp = (int) (ci->values[0].value.number + 0.5);
- if ((tmp < 1) || (tmp > 65535))
- {
- ERROR ("cf_util_get_port_number: The \"%s\" option requires "
- "a service name or a port number. The number "
- "you specified, %i, is not in the valid "
- "range of 1-65535.",
- ci->key, tmp);
- return (-1);
- }
-
- return (tmp);
-} /* }}} int cf_util_get_port_number */
-
-int cf_util_get_service (const oconfig_item_t *ci, char **ret_string) /* {{{ */
-{
- int port;
- char *service;
- int status;
-
- if (ci->values_num != 1)
- {
- ERROR ("cf_util_get_service: The %s option requires exactly "
- "one argument.", ci->key);
- return (-1);
- }
-
- if (ci->values[0].type == OCONFIG_TYPE_STRING)
- return (cf_util_get_string (ci, ret_string));
- if (ci->values[0].type != OCONFIG_TYPE_NUMBER)
- {
- ERROR ("cf_util_get_service: The %s option requires "
- "exactly one string or numeric argument.",
- ci->key);
- }
-
- port = 0;
- status = cf_util_get_int (ci, &port);
- if (status != 0)
- return (status);
- else if ((port < 1) || (port > 65535))
- {
- ERROR ("cf_util_get_service: The port number given "
- "for the %s option is out of "
- "range (%i).", ci->key, port);
- return (-1);
- }
-
- service = malloc (6);
- if (service == NULL)
- {
- ERROR ("cf_util_get_service: Out of memory.");
- return (-1);
- }
- ssnprintf (service, 6, "%i", port);
-
- sfree (*ret_string);
- *ret_string = service;
-
- return (0);
-} /* }}} int cf_util_get_service */
-
-int cf_util_get_cdtime (const oconfig_item_t *ci, cdtime_t *ret_value) /* {{{ */
-{
- if ((ci == NULL) || (ret_value == NULL))
- return (EINVAL);
-
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
- {
- ERROR ("cf_util_get_cdtime: The %s option requires "
- "exactly one numeric argument.", ci->key);
- return (-1);
- }
-
- if (ci->values[0].value.number < 0.0)
- {
- ERROR ("cf_util_get_cdtime: The numeric argument of the %s "
- "option must not be negative.", ci->key);
- return (-1);
- }
-
- *ret_value = DOUBLE_TO_CDTIME_T (ci->values[0].value.number);
-
- return (0);
-} /* }}} int cf_util_get_cdtime */
-
diff --git a/src/configfile.h b/src/configfile.h
--- a/src/configfile.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/**
- * collectd - src/configfile.h
- * Copyright (C) 2005-2011 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#ifndef CONFIGFILE_H
-#define CONFIGFILE_H
-
-#include "collectd.h"
-#include "utils_time.h"
-#include "liboconfig/oconfig.h"
-
-/*
- * DESCRIPTION
- * Remove a registered plugin from the internal data structures.
- *
- * PARAMETERS
- * `type' Name of the plugin (must be the same as passed to
- * `plugin_register'
- */
-void cf_unregister (const char *type);
-void cf_unregister_complex (const char *type);
-
-/*
- * DESCRIPTION
- * `cf_register' is called by plugins that wish to receive config keys. The
- * plugin will then receive all keys it registered for if they're found in a
- * `<Plugin $type>' section.
- *
- * PARAMETERS
- * `type' Name of the plugin (must be the same as passed to
- * `plugin_register'
- * `callback' Pointer to the callback function. The callback must return zero
- * upon success, a value smaller than zero if it doesn't know how
- * to handle the `key' passed to it (the first argument) or a
- * value greater than zero if it knows how to handle the key but
- * failed.
- * `keys' Array of key values this plugin wished to receive. The last
- * element must be a NULL-pointer.
- * `keys_num' Number of elements in the array (not counting the last NULL-
- * pointer.
- *
- * NOTES
- * `cf_unregister' will be called for `type' to make sure only one record
- * exists for each `type' at any time. This means that `cf_register' may be
- * called multiple times, but only the last call will have an effect.
- */
-void cf_register (const char *type,
- int (*callback) (const char *, const char *),
- const char **keys, int keys_num);
-
-int cf_register_complex (const char *type, int (*callback) (oconfig_item_t *));
-
-/*
- * DESCRIPTION
- * `cf_read' reads the config file `filename' and dispatches the read
- * information to functions/variables. Most important: Is calls `plugin_load'
- * to load specific plugins, depending on the current mode of operation.
- *
- * PARAMETERS
- * `filename' An additional filename to look for. This function calls
- * `lc_process' which already searches many standard locations..
- * If set to NULL will use the `CONFIGFILE' define.
- *
- * RETURN VALUE
- * Returns zero upon success and non-zero otherwise. A error-message will have
- * been printed in this case.
- */
-int cf_read (char *filename);
-
-int global_option_set (const char *option, const char *value);
-const char *global_option_get (const char *option);
-long global_option_get_long (const char *option, long default_value);
-long global_option_get_long_in_range (const char *option, long default_value, long min, long max);
-
-cdtime_t global_option_get_time (char const *option, cdtime_t default_value);
-
-cdtime_t cf_get_default_interval (void);
-
-/* Assures the config option is a string, duplicates it and returns the copy in
- * "ret_string". If necessary "*ret_string" is freed first. Returns zero upon
- * success. */
-int cf_util_get_string (const oconfig_item_t *ci, char **ret_string);
-
-/* Assures the config option is a string and copies it to the provided buffer.
- * Assures null-termination. */
-int cf_util_get_string_buffer (const oconfig_item_t *ci, char *buffer,
- size_t buffer_size);
-
-/* Assures the config option is a number and returns it as an int. */
-int cf_util_get_int (const oconfig_item_t *ci, int *ret_value);
-
-/* Assures the config option is a number and returns it as a double. */
-int cf_util_get_double (const oconfig_item_t *ci, double *ret_value);
-
-/* Assures the config option is a boolean and assignes it to `ret_bool'.
- * Otherwise, `ret_bool' is not changed and non-zero is returned. */
-int cf_util_get_boolean (const oconfig_item_t *ci, _Bool *ret_bool);
-
-/* Assures the config option is a boolean and set or unset the given flag in
- * `ret_value' as appropriate. Returns non-zero on error. */
-int cf_util_get_flag (const oconfig_item_t *ci,
- unsigned int *ret_value, unsigned int flag);
-
-/* Assures that the config option is a string or a number if the correct range
- * of 1-65535. The string is then converted to a port number using
- * `service_name_to_port_number' and returned.
- * Returns the port number in the range [1-65535] or less than zero upon
- * failure. */
-int cf_util_get_port_number (const oconfig_item_t *ci);
-
-/* Assures that the config option is either a service name (a string) or a port
- * number (an integer in the appropriate range) and returns a newly allocated
- * string. If ret_string points to a non-NULL pointer, it is freed before
- * assigning a new value. */
-int cf_util_get_service (const oconfig_item_t *ci, char **ret_string);
-
-int cf_util_get_cdtime (const oconfig_item_t *ci, cdtime_t *ret_value);
-
-#endif /* defined(CONFIGFILE_H) */
diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am
--- /dev/null
+++ b/src/daemon/Makefile.am
@@ -0,0 +1,85 @@
+if COMPILER_IS_GCC
+AM_CFLAGS = -Wall -Werror
+endif
+
+AM_CPPFLAGS = -DPREFIX='"${prefix}"'
+AM_CPPFLAGS += -DCONFIGFILE='"${sysconfdir}/${PACKAGE_NAME}.conf"'
+AM_CPPFLAGS += -DLOCALSTATEDIR='"${localstatedir}"'
+AM_CPPFLAGS += -DPKGLOCALSTATEDIR='"${localstatedir}/lib/${PACKAGE_NAME}"'
+if BUILD_FEATURE_DAEMON
+AM_CPPFLAGS += -DPIDFILE='"${localstatedir}/run/${PACKAGE_NAME}.pid"'
+endif
+AM_CPPFLAGS += -DPLUGINDIR='"${pkglibdir}"'
+AM_CPPFLAGS += -DPKGDATADIR='"${pkgdatadir}"'
+
+AUTOMAKE_OPTIONS = subdir-objects
+
+sbin_PROGRAMS = collectd
+
+collectd_SOURCES = collectd.c collectd.h \
+ common.c common.h \
+ configfile.c configfile.h \
+ filter_chain.c filter_chain.h \
+ meta_data.c meta_data.h \
+ plugin.c plugin.h \
+ utils_avltree.c utils_avltree.h \
+ utils_cache.c utils_cache.h \
+ utils_complain.c utils_complain.h \
+ utils_heap.c utils_heap.h \
+ utils_llist.c utils_llist.h \
+ utils_parse_option.c utils_parse_option.h \
+ utils_random.c utils_random.h \
+ utils_tail_match.c utils_tail_match.h \
+ utils_match.c utils_match.h \
+ utils_subst.c utils_subst.h \
+ utils_tail.c utils_tail.h \
+ utils_time.c utils_time.h \
+ types_list.c types_list.h \
+ utils_threshold.c utils_threshold.h
+
+
+collectd_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL)
+collectd_CFLAGS = $(AM_CFLAGS)
+collectd_LDFLAGS = -export-dynamic
+collectd_LDADD = -lm
+collectd_DEPENDENCIES =
+
+# Link to these libraries..
+if BUILD_WITH_LIBRT
+collectd_LDADD += -lrt
+endif
+if BUILD_WITH_LIBPOSIX4
+collectd_LDADD += -lposix4
+endif
+if BUILD_WITH_LIBSOCKET
+collectd_LDADD += -lsocket
+endif
+if BUILD_WITH_LIBRESOLV
+collectd_LDADD += -lresolv
+endif
+if BUILD_WITH_LIBPTHREAD
+collectd_LDADD += -lpthread
+endif
+if BUILD_WITH_LIBKSTAT
+collectd_LDADD += -lkstat
+endif
+if BUILD_WITH_LIBDEVINFO
+collectd_LDADD += -ldevinfo
+endif
+if BUILD_AIX
+collectd_LDFLAGS += -Wl,-bexpall,-brtllib
+endif
+
+# The daemon needs to call sg_init, so we need to link it against libstatgrab,
+# too. -octo
+if BUILD_WITH_LIBSTATGRAB
+collectd_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
+collectd_LDADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
+endif
+
+if BUILD_WITH_OWN_LIBOCONFIG
+collectd_LDADD += $(LIBLTDL) $(top_builddir)/src/liboconfig/liboconfig.la
+collectd_DEPENDENCIES += $(top_builddir)/src/liboconfig/liboconfig.la
+else
+collectd_LDADD += -loconfig
+endif
diff --git a/src/daemon/collectd.c b/src/daemon/collectd.c
--- /dev/null
+++ b/src/daemon/collectd.c
@@ -0,0 +1,637 @@
+/**
+ * collectd - src/collectd.c
+ * Copyright (C) 2005-2007 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ * Alvaro Barcellos <alvaro.barcellos at gmail.com>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+
+#include "plugin.h"
+#include "configfile.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include <pthread.h>
+
+#if HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#if HAVE_STATGRAB_H
+# include <statgrab.h>
+#endif
+
+#ifndef COLLECTD_LOCALE
+# define COLLECTD_LOCALE "C"
+#endif
+
+/*
+ * Global variables
+ */
+char hostname_g[DATA_MAX_NAME_LEN];
+cdtime_t interval_g;
+int pidfile_from_cli = 0;
+int timeout_g;
+#if HAVE_LIBKSTAT
+kstat_ctl_t *kc;
+#endif /* HAVE_LIBKSTAT */
+
+static int loop = 0;
+
+static void *do_flush (void __attribute__((unused)) *arg)
+{
+ INFO ("Flushing all data.");
+ plugin_flush (/* plugin = */ NULL,
+ /* timeout = */ 0,
+ /* ident = */ NULL);
+ INFO ("Finished flushing all data.");
+ pthread_exit (NULL);
+ return NULL;
+}
+
+static void sig_int_handler (int __attribute__((unused)) signal)
+{
+ loop++;
+}
+
+static void sig_term_handler (int __attribute__((unused)) signal)
+{
+ loop++;
+}
+
+static void sig_usr1_handler (int __attribute__((unused)) signal)
+{
+ pthread_t thread;
+ pthread_attr_t attr;
+
+ /* flushing the data might take a while,
+ * so it should be done asynchronously */
+ pthread_attr_init (&attr);
+ pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+ pthread_create (&thread, &attr, do_flush, NULL);
+ pthread_attr_destroy (&attr);
+}
+
+static int init_hostname (void)
+{
+ const char *str;
+
+ struct addrinfo ai_hints;
+ struct addrinfo *ai_list;
+ struct addrinfo *ai_ptr;
+ int status;
+
+ str = global_option_get ("Hostname");
+ if (str != NULL)
+ {
+ sstrncpy (hostname_g, str, sizeof (hostname_g));
+ return (0);
+ }
+
+ if (gethostname (hostname_g, sizeof (hostname_g)) != 0)
+ {
+ fprintf (stderr, "`gethostname' failed and no "
+ "hostname was configured.\n");
+ return (-1);
+ }
+
+ str = global_option_get ("FQDNLookup");
+ if (IS_FALSE (str))
+ return (0);
+
+ memset (&ai_hints, '\0', sizeof (ai_hints));
+ ai_hints.ai_flags = AI_CANONNAME;
+
+ status = getaddrinfo (hostname_g, NULL, &ai_hints, &ai_list);
+ if (status != 0)
+ {
+ ERROR ("Looking up \"%s\" failed. You have set the "
+ "\"FQDNLookup\" option, but I cannot resolve "
+ "my hostname to a fully qualified domain "
+ "name. Please fix the network "
+ "configuration.", hostname_g);
+ return (-1);
+ }
+
+ for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
+ {
+ if (ai_ptr->ai_canonname == NULL)
+ continue;
+
+ sstrncpy (hostname_g, ai_ptr->ai_canonname, sizeof (hostname_g));
+ break;
+ }
+
+ freeaddrinfo (ai_list);
+ return (0);
+} /* int init_hostname */
+
+static int init_global_variables (void)
+{
+ char const *str;
+
+ interval_g = cf_get_default_interval ();
+ assert (interval_g > 0);
+ DEBUG ("interval_g = %.3f;", CDTIME_T_TO_DOUBLE (interval_g));
+
+ str = global_option_get ("Timeout");
+ if (str == NULL)
+ str = "2";
+ timeout_g = atoi (str);
+ if (timeout_g <= 1)
+ {
+ fprintf (stderr, "Cannot set the timeout to a correct value.\n"
+ "Please check your settings.\n");
+ return (-1);
+ }
+ DEBUG ("timeout_g = %i;", timeout_g);
+
+ if (init_hostname () != 0)
+ return (-1);
+ DEBUG ("hostname_g = %s;", hostname_g);
+
+ return (0);
+} /* int init_global_variables */
+
+static int change_basedir (const char *orig_dir)
+{
+ char *dir;
+ size_t dirlen;
+ int status;
+
+ dir = strdup (orig_dir);
+ if (dir == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("strdup failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ dirlen = strlen (dir);
+ while ((dirlen > 0) && (dir[dirlen - 1] == '/'))
+ dir[--dirlen] = '\0';
+
+ if (dirlen <= 0)
+ return (-1);
+
+ status = chdir (dir);
+ if (status == 0)
+ {
+ free (dir);
+ return (0);
+ }
+ else if (errno != ENOENT)
+ {
+ char errbuf[1024];
+ ERROR ("change_basedir: chdir (%s): %s", dir,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ free (dir);
+ return (-1);
+ }
+
+ status = mkdir (dir, S_IRWXU | S_IRWXG | S_IRWXO);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("change_basedir: mkdir (%s): %s", dir,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ free (dir);
+ return (-1);
+ }
+
+ status = chdir (dir);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("change_basedir: chdir (%s): %s", dir,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ free (dir);
+ return (-1);
+ }
+
+ free (dir);
+ return (0);
+} /* static int change_basedir (char *dir) */
+
+#if HAVE_LIBKSTAT
+static void update_kstat (void)
+{
+ if (kc == NULL)
+ {
+ if ((kc = kstat_open ()) == NULL)
+ ERROR ("Unable to open kstat control structure");
+ }
+ else
+ {
+ kid_t kid;
+ kid = kstat_chain_update (kc);
+ if (kid > 0)
+ {
+ INFO ("kstat chain has been updated");
+ plugin_init_all ();
+ }
+ else if (kid < 0)
+ ERROR ("kstat chain update failed");
+ /* else: everything works as expected */
+ }
+
+ return;
+} /* static void update_kstat (void) */
+#endif /* HAVE_LIBKSTAT */
+
+/* TODO
+ * Remove all settings but `-f' and `-C'
+ */
+static void exit_usage (int status)
+{
+ printf ("Usage: "PACKAGE" [OPTIONS]\n\n"
+
+ "Available options:\n"
+ " General:\n"
+ " -C <file> Configuration file.\n"
+ " Default: "CONFIGFILE"\n"
+ " -t Test config and exit.\n"
+ " -T Test plugin read and exit.\n"
+ " -P <file> PID-file.\n"
+ " Default: "PIDFILE"\n"
+#if COLLECT_DAEMON
+ " -f Don't fork to the background.\n"
+#endif
+ " -h Display help (this message)\n"
+ "\nBuiltin defaults:\n"
+ " Config file "CONFIGFILE"\n"
+ " PID file "PIDFILE"\n"
+ " Plugin directory "PLUGINDIR"\n"
+ " Data directory "PKGLOCALSTATEDIR"\n"
+ "\n"PACKAGE" "VERSION", http://collectd.org/\n"
+ "by Florian octo Forster <octo@collectd.org>\n"
+ "for contributions see `AUTHORS'\n");
+ exit (status);
+} /* static void exit_usage (int status) */
+
+static int do_init (void)
+{
+#if HAVE_SETLOCALE
+ if (setlocale (LC_NUMERIC, COLLECTD_LOCALE) == NULL)
+ WARNING ("setlocale (\"%s\") failed.", COLLECTD_LOCALE);
+#endif
+
+#if HAVE_LIBKSTAT
+ kc = NULL;
+ update_kstat ();
+#endif
+
+#if HAVE_LIBSTATGRAB
+ if (sg_init ())
+ {
+ ERROR ("sg_init: %s", sg_str_error (sg_get_error ()));
+ return (-1);
+ }
+
+ if (sg_drop_privileges ())
+ {
+ ERROR ("sg_drop_privileges: %s", sg_str_error (sg_get_error ()));
+ return (-1);
+ }
+#endif
+
+ plugin_init_all ();
+
+ return (0);
+} /* int do_init () */
+
+
+static int do_loop (void)
+{
+ cdtime_t interval = cf_get_default_interval ();
+ cdtime_t wait_until;
+
+ wait_until = cdtime () + interval;
+
+ while (loop == 0)
+ {
+ struct timespec ts_wait = { 0, 0 };
+ cdtime_t now;
+
+#if HAVE_LIBKSTAT
+ update_kstat ();
+#endif
+
+ /* Issue all plugins */
+ plugin_read_all ();
+
+ now = cdtime ();
+ if (now >= wait_until)
+ {
+ WARNING ("Not sleeping because the next interval is "
+ "%.3f seconds in the past!",
+ CDTIME_T_TO_DOUBLE (now - wait_until));
+ wait_until = now + interval;
+ continue;
+ }
+
+ CDTIME_T_TO_TIMESPEC (wait_until - now, &ts_wait);
+ wait_until = wait_until + interval;
+
+ while ((loop == 0) && (nanosleep (&ts_wait, &ts_wait) != 0))
+ {
+ if (errno != EINTR)
+ {
+ char errbuf[1024];
+ ERROR ("nanosleep failed: %s",
+ sstrerror (errno, errbuf,
+ sizeof (errbuf)));
+ return (-1);
+ }
+ }
+ } /* while (loop == 0) */
+
+ return (0);
+} /* int do_loop */
+
+static int do_shutdown (void)
+{
+ plugin_shutdown_all ();
+ return (0);
+} /* int do_shutdown */
+
+#if COLLECT_DAEMON
+static int pidfile_create (void)
+{
+ FILE *fh;
+ const char *file = global_option_get ("PIDFile");
+
+ if ((fh = fopen (file, "w")) == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("fopen (%s): %s", file,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (1);
+ }
+
+ fprintf (fh, "%i\n", (int) getpid ());
+ fclose(fh);
+
+ return (0);
+} /* static int pidfile_create (const char *file) */
+
+static int pidfile_remove (void)
+{
+ const char *file = global_option_get ("PIDFile");
+
+ DEBUG ("unlink (%s)", (file != NULL) ? file : "<null>");
+ return (unlink (file));
+} /* static int pidfile_remove (const char *file) */
+#endif /* COLLECT_DAEMON */
+
+int main (int argc, char **argv)
+{
+ struct sigaction sig_int_action;
+ struct sigaction sig_term_action;
+ struct sigaction sig_usr1_action;
+ struct sigaction sig_pipe_action;
+ char *configfile = CONFIGFILE;
+ int test_config = 0;
+ int test_readall = 0;
+ const char *basedir;
+#if COLLECT_DAEMON
+ struct sigaction sig_chld_action;
+ pid_t pid;
+ int daemonize = 1;
+#endif
+ int exit_status = 0;
+
+ /* read options */
+ while (1)
+ {
+ int c;
+
+ c = getopt (argc, argv, "htTC:"
+#if COLLECT_DAEMON
+ "fP:"
+#endif
+ );
+
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case 'C':
+ configfile = optarg;
+ break;
+ case 't':
+ test_config = 1;
+ break;
+ case 'T':
+ test_readall = 1;
+ global_option_set ("ReadThreads", "-1");
+#if COLLECT_DAEMON
+ daemonize = 0;
+#endif /* COLLECT_DAEMON */
+ break;
+#if COLLECT_DAEMON
+ case 'P':
+ global_option_set ("PIDFile", optarg);
+ pidfile_from_cli = 1;
+ break;
+ case 'f':
+ daemonize = 0;
+ break;
+#endif /* COLLECT_DAEMON */
+ case 'h':
+ exit_usage (0);
+ break;
+ default:
+ exit_usage (1);
+ } /* switch (c) */
+ } /* while (1) */
+
+ if (optind < argc)
+ exit_usage (1);
+
+ plugin_init_ctx ();
+
+ /*
+ * Read options from the config file, the environment and the command
+ * line (in that order, with later options overwriting previous ones in
+ * general).
+ * Also, this will automatically load modules.
+ */
+ if (cf_read (configfile))
+ {
+ fprintf (stderr, "Error: Reading the config file failed!\n"
+ "Read the syslog for details.\n");
+ return (1);
+ }
+
+ /*
+ * Change directory. We do this _after_ reading the config and loading
+ * modules to relative paths work as expected.
+ */
+ if ((basedir = global_option_get ("BaseDir")) == NULL)
+ {
+ fprintf (stderr, "Don't have a basedir to use. This should not happen. Ever.");
+ return (1);
+ }
+ else if (change_basedir (basedir))
+ {
+ fprintf (stderr, "Error: Unable to change to directory `%s'.\n", basedir);
+ return (1);
+ }
+
+ /*
+ * Set global variables or, if that failes, exit. We cannot run with
+ * them being uninitialized. If nothing is configured, then defaults
+ * are being used. So this means that the user has actually done
+ * something wrong.
+ */
+ if (init_global_variables () != 0)
+ return (1);
+
+ if (test_config)
+ return (0);
+
+#if COLLECT_DAEMON
+ /*
+ * fork off child
+ */
+ memset (&sig_chld_action, '\0', sizeof (sig_chld_action));
+ sig_chld_action.sa_handler = SIG_IGN;
+ sigaction (SIGCHLD, &sig_chld_action, NULL);
+
+ if (daemonize)
+ {
+ if ((pid = fork ()) == -1)
+ {
+ /* error */
+ char errbuf[1024];
+ fprintf (stderr, "fork: %s",
+ sstrerror (errno, errbuf,
+ sizeof (errbuf)));
+ return (1);
+ }
+ else if (pid != 0)
+ {
+ /* parent */
+ /* printf ("Running (PID %i)\n", pid); */
+ return (0);
+ }
+
+ /* Detach from session */
+ setsid ();
+
+ /* Write pidfile */
+ if (pidfile_create ())
+ exit (2);
+
+ /* close standard descriptors */
+ close (2);
+ close (1);
+ close (0);
+
+ if (open ("/dev/null", O_RDWR) != 0)
+ {
+ ERROR ("Error: Could not connect `STDIN' to `/dev/null'");
+ return (1);
+ }
+ if (dup (0) != 1)
+ {
+ ERROR ("Error: Could not connect `STDOUT' to `/dev/null'");
+ return (1);
+ }
+ if (dup (0) != 2)
+ {
+ ERROR ("Error: Could not connect `STDERR' to `/dev/null'");
+ return (1);
+ }
+ } /* if (daemonize) */
+#endif /* COLLECT_DAEMON */
+
+ memset (&sig_pipe_action, '\0', sizeof (sig_pipe_action));
+ sig_pipe_action.sa_handler = SIG_IGN;
+ sigaction (SIGPIPE, &sig_pipe_action, NULL);
+
+ /*
+ * install signal handlers
+ */
+ memset (&sig_int_action, '\0', sizeof (sig_int_action));
+ sig_int_action.sa_handler = sig_int_handler;
+ if (0 != sigaction (SIGINT, &sig_int_action, NULL)) {
+ char errbuf[1024];
+ ERROR ("Error: Failed to install a signal handler for signal INT: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (1);
+ }
+
+ memset (&sig_term_action, '\0', sizeof (sig_term_action));
+ sig_term_action.sa_handler = sig_term_handler;
+ if (0 != sigaction (SIGTERM, &sig_term_action, NULL)) {
+ char errbuf[1024];
+ ERROR ("Error: Failed to install a signal handler for signal TERM: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (1);
+ }
+
+ memset (&sig_usr1_action, '\0', sizeof (sig_usr1_action));
+ sig_usr1_action.sa_handler = sig_usr1_handler;
+ if (0 != sigaction (SIGUSR1, &sig_usr1_action, NULL)) {
+ char errbuf[1024];
+ ERROR ("Error: Failed to install a signal handler for signal USR1: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (1);
+ }
+
+ /*
+ * run the actual loops
+ */
+ do_init ();
+
+ if (test_readall)
+ {
+ if (plugin_read_all_once () != 0)
+ exit_status = 1;
+ }
+ else
+ {
+ INFO ("Initialization complete, entering read-loop.");
+ do_loop ();
+ }
+
+ /* close syslog */
+ INFO ("Exiting normally.");
+
+ do_shutdown ();
+
+#if COLLECT_DAEMON
+ if (daemonize)
+ pidfile_remove ();
+#endif /* COLLECT_DAEMON */
+
+ return (exit_status);
+} /* int main */
diff --git a/src/daemon/collectd.h b/src/daemon/collectd.h
--- /dev/null
+++ b/src/daemon/collectd.h
@@ -0,0 +1,315 @@
+/**
+ * collectd - src/collectd.h
+ * Copyright (C) 2005,2006 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#ifndef COLLECTD_H
+#define COLLECTD_H
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+#if HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#if HAVE_ERRNO_H
+# include <errno.h>
+#endif
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#if HAVE_ASSERT_H
+# include <assert.h>
+#else
+# define assert(...) /* nop */
+#endif
+
+#if !defined(HAVE__BOOL) || !HAVE__BOOL
+typedef int _Bool;
+# undef HAVE__BOOL
+# define HAVE__BOOL 1
+#endif
+
+#if NAN_STATIC_DEFAULT
+# include <math.h>
+/* #endif NAN_STATIC_DEFAULT*/
+#elif NAN_STATIC_ISOC
+# ifndef __USE_ISOC99
+# define DISABLE_ISOC99 1
+# define __USE_ISOC99 1
+# endif /* !defined(__USE_ISOC99) */
+# include <math.h>
+# if DISABLE_ISOC99
+# undef DISABLE_ISOC99
+# undef __USE_ISOC99
+# endif /* DISABLE_ISOC99 */
+/* #endif NAN_STATIC_ISOC */
+#elif NAN_ZERO_ZERO
+# include <math.h>
+# ifdef NAN
+# undef NAN
+# endif
+# define NAN (0.0 / 0.0)
+# ifndef isnan
+# define isnan(f) ((f) != (f))
+# endif /* !defined(isnan) */
+# ifndef isfinite
+# define isfinite(f) (((f) - (f)) == 0.0)
+# endif
+# ifndef isinf
+# define isinf(f) (!isfinite(f) && !isnan(f))
+# endif
+#endif /* NAN_ZERO_ZERO */
+
+/* Try really, really hard to determine endianess. Under NexentaStor 1.0.2 this
+ * information is in <sys/isa_defs.h>, possibly some other Solaris versions do
+ * this too.. */
+#if HAVE_ENDIAN_H
+# include <endian.h>
+#elif HAVE_SYS_ISA_DEFS_H
+# include <sys/isa_defs.h>
+#endif
+
+#ifndef BYTE_ORDER
+# if defined(_BYTE_ORDER)
+# define BYTE_ORDER _BYTE_ORDER
+# elif defined(__BYTE_ORDER)
+# define BYTE_ORDER __BYTE_ORDER
+# elif defined(__DARWIN_BYTE_ORDER)
+# define BYTE_ORDER __DARWIN_BYTE_ORDER
+# endif
+#endif
+#ifndef BIG_ENDIAN
+# if defined(_BIG_ENDIAN)
+# define BIG_ENDIAN _BIG_ENDIAN
+# elif defined(__BIG_ENDIAN)
+# define BIG_ENDIAN __BIG_ENDIAN
+# elif defined(__DARWIN_BIG_ENDIAN)
+# define BIG_ENDIAN __DARWIN_BIG_ENDIAN
+# endif
+#endif
+#ifndef LITTLE_ENDIAN
+# if defined(_LITTLE_ENDIAN)
+# define LITTLE_ENDIAN _LITTLE_ENDIAN
+# elif defined(__LITTLE_ENDIAN)
+# define LITTLE_ENDIAN __LITTLE_ENDIAN
+# elif defined(__DARWIN_LITTLE_ENDIAN)
+# define LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN
+# endif
+#endif
+#ifndef BYTE_ORDER
+# if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)
+# undef BIG_ENDIAN
+# define BIG_ENDIAN 4321
+# define LITTLE_ENDIAN 1234
+# define BYTE_ORDER BIG_ENDIAN
+# elif !defined(BIG_ENDIAN) && defined(LITTLE_ENDIAN)
+# undef LITTLE_ENDIAN
+# define BIG_ENDIAN 4321
+# define LITTLE_ENDIAN 1234
+# define BYTE_ORDER LITTLE_ENDIAN
+# endif
+#endif
+#if !defined(BYTE_ORDER) || !defined(BIG_ENDIAN)
+# error "Cannot determine byte order"
+#endif
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#if HAVE_STDARG_H
+# include <stdarg.h>
+#endif
+#if HAVE_CTYPE_H
+# include <ctype.h>
+#endif
+#if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
+#if HAVE_KSTAT_H
+# include <kstat.h>
+#endif
+
+#ifndef PACKAGE_NAME
+#define PACKAGE_NAME "collectd"
+#endif
+
+#ifndef PREFIX
+#define PREFIX "/opt/" PACKAGE_NAME
+#endif
+
+#ifndef SYSCONFDIR
+#define SYSCONFDIR PREFIX "/etc"
+#endif
+
+#ifndef CONFIGFILE
+#define CONFIGFILE SYSCONFDIR"/collectd.conf"
+#endif
+
+#ifndef LOCALSTATEDIR
+#define LOCALSTATEDIR PREFIX "/var"
+#endif
+
+#ifndef PKGLOCALSTATEDIR
+#define PKGLOCALSTATEDIR PREFIX "/var/lib/" PACKAGE_NAME
+#endif
+
+#ifndef PIDFILE
+#define PIDFILE PREFIX "/var/run/" PACKAGE_NAME ".pid"
+#endif
+
+#ifndef PLUGINDIR
+#define PLUGINDIR PREFIX "/lib/" PACKAGE_NAME
+#endif
+
+#ifndef PKGDATADIR
+#define PKGDATADIR PREFIX "/share/" PACKAGE_NAME
+#endif
+
+#ifndef COLLECTD_GRP_NAME
+# define COLLECTD_GRP_NAME "collectd"
+#endif
+
+#ifndef COLLECTD_DEFAULT_INTERVAL
+# define COLLECTD_DEFAULT_INTERVAL 10.0
+#endif
+
+ #ifndef COLLECTD_USERAGENT
+ # define COLLECTD_USERAGENT PACKAGE_NAME"/"PACKAGE_VERSION
+ #endif
+
+/* Only enable __attribute__() for compilers known to support it. */
+#if defined(__clang__)
+# define clang_attr(x) __attribute__(x)
+# define gcc_attr(x) /**/
+#elif __GNUC__
+# define clang_attr(x) /**/
+# define gcc_attr(x) __attribute__(x)
+#else
+# define clang_attr(x) /**/
+# define gcc_attr(x) /**/
+# define __attribute__(x) /**/
+#endif
+
+#if defined(COLLECT_DEBUG) && COLLECT_DEBUG && defined(__GNUC__) && __GNUC__
+# undef strcpy
+# undef strcat
+# undef strtok
+# pragma GCC poison strcpy strcat strtok
+#endif
+
+/*
+ * Special hack for the perl plugin: Because the later included perl.h defines
+ * a macro which is never used, but contains `sprintf', we cannot poison that
+ * identifies just yet. The parl plugin will do that itself once perl.h is
+ * included.
+ */
+#ifndef DONT_POISON_SPRINTF_YET
+# if defined(COLLECT_DEBUG) && COLLECT_DEBUG && defined(__GNUC__) && __GNUC__
+# undef sprintf
+# pragma GCC poison sprintf
+# endif
+#endif
+
+/* Type for time as used by "utils_time.h" */
+typedef uint64_t cdtime_t;
+
+extern char hostname_g[];
+extern cdtime_t interval_g;
+extern int pidfile_from_cli;
+extern int timeout_g;
+
+#endif /* COLLECTD_H */
diff --git a/src/daemon/common.c b/src/daemon/common.c
--- /dev/null
+++ b/src/daemon/common.c
@@ -0,0 +1,1596 @@
+/**
+ * collectd - src/common.c
+ * Copyright (C) 2005-2014 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ * Niki W. Waibel <niki.waibel@gmx.net>
+ * Sebastian Harl <sh at tokkee.org>
+ * Michał Mirosław <mirq-linux at rere.qmqm.pl>
+**/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "utils_cache.h"
+
+#if HAVE_PTHREAD_H
+# include <pthread.h>
+#endif
+
+#ifdef HAVE_MATH_H
+# include <math.h>
+#endif
+
+/* for getaddrinfo */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+/* for ntohl and htonl */
+#if HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_LIBKSTAT
+extern kstat_ctl_t *kc;
+#endif
+
+#if !HAVE_GETPWNAM_R
+static pthread_mutex_t getpwnam_r_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+#if !HAVE_STRERROR_R
+static pthread_mutex_t strerror_r_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+char *sstrncpy (char *dest, const char *src, size_t n)
+{
+ strncpy (dest, src, n);
+ dest[n - 1] = '\0';
+
+ return (dest);
+} /* char *sstrncpy */
+
+int ssnprintf (char *dest, size_t n, const char *format, ...)
+{
+ int ret = 0;
+ va_list ap;
+
+ va_start (ap, format);
+ ret = vsnprintf (dest, n, format, ap);
+ dest[n - 1] = '\0';
+ va_end (ap);
+
+ return (ret);
+} /* int ssnprintf */
+
+char *ssnprintf_alloc (char const *format, ...) /* {{{ */
+{
+ char static_buffer[1024] = "";
+ char *alloc_buffer;
+ size_t alloc_buffer_size;
+ int status;
+ va_list ap;
+
+ /* Try printing into the static buffer. In many cases it will be
+ * sufficiently large and we can simply return a strdup() of this
+ * buffer. */
+ va_start (ap, format);
+ status = vsnprintf (static_buffer, sizeof (static_buffer), format, ap);
+ va_end (ap);
+ if (status < 0)
+ return (NULL);
+
+ /* "status" does not include the null byte. */
+ alloc_buffer_size = (size_t) (status + 1);
+ if (alloc_buffer_size <= sizeof (static_buffer))
+ return (strdup (static_buffer));
+
+ /* Allocate a buffer large enough to hold the string. */
+ alloc_buffer = malloc (alloc_buffer_size);
+ if (alloc_buffer == NULL)
+ return (NULL);
+ memset (alloc_buffer, 0, alloc_buffer_size);
+
+ /* Print again into this new buffer. */
+ va_start (ap, format);
+ status = vsnprintf (alloc_buffer, alloc_buffer_size, format, ap);
+ va_end (ap);
+ if (status < 0)
+ {
+ sfree (alloc_buffer);
+ return (NULL);
+ }
+
+ return (alloc_buffer);
+} /* }}} char *ssnprintf_alloc */
+
+char *sstrdup (const char *s)
+{
+ char *r;
+ size_t sz;
+
+ if (s == NULL)
+ return (NULL);
+
+ /* Do not use `strdup' here, because it's not specified in POSIX. It's
+ * ``only'' an XSI extension. */
+ sz = strlen (s) + 1;
+ r = (char *) malloc (sizeof (char) * sz);
+ if (r == NULL)
+ {
+ ERROR ("sstrdup: Out of memory.");
+ exit (3);
+ }
+ memcpy (r, s, sizeof (char) * sz);
+
+ return (r);
+} /* char *sstrdup */
+
+/* Even though Posix requires "strerror_r" to return an "int",
+ * some systems (e.g. the GNU libc) return a "char *" _and_
+ * ignore the second argument ... -tokkee */
+char *sstrerror (int errnum, char *buf, size_t buflen)
+{
+ buf[0] = '\0';
+
+#if !HAVE_STRERROR_R
+ {
+ char *temp;
+
+ pthread_mutex_lock (&strerror_r_lock);
+
+ temp = strerror (errnum);
+ sstrncpy (buf, temp, buflen);
+
+ pthread_mutex_unlock (&strerror_r_lock);
+ }
+/* #endif !HAVE_STRERROR_R */
+
+#elif STRERROR_R_CHAR_P
+ {
+ char *temp;
+ temp = strerror_r (errnum, buf, buflen);
+ if (buf[0] == '\0')
+ {
+ if ((temp != NULL) && (temp != buf) && (temp[0] != '\0'))
+ sstrncpy (buf, temp, buflen);
+ else
+ sstrncpy (buf, "strerror_r did not return "
+ "an error message", buflen);
+ }
+ }
+/* #endif STRERROR_R_CHAR_P */
+
+#else
+ if (strerror_r (errnum, buf, buflen) != 0)
+ {
+ ssnprintf (buf, buflen, "Error #%i; "
+ "Additionally, strerror_r failed.",
+ errnum);
+ }
+#endif /* STRERROR_R_CHAR_P */
+
+ return (buf);
+} /* char *sstrerror */
+
+void *smalloc (size_t size)
+{
+ void *r;
+
+ if ((r = malloc (size)) == NULL)
+ {
+ ERROR ("Not enough memory.");
+ exit (3);
+ }
+
+ return (r);
+} /* void *smalloc */
+
+#if 0
+void sfree (void **ptr)
+{
+ if (ptr == NULL)
+ return;
+
+ if (*ptr != NULL)
+ free (*ptr);
+
+ *ptr = NULL;
+}
+#endif
+
+ssize_t sread (int fd, void *buf, size_t count)
+{
+ char *ptr;
+ size_t nleft;
+ ssize_t status;
+
+ ptr = (char *) buf;
+ nleft = count;
+
+ while (nleft > 0)
+ {
+ status = read (fd, (void *) ptr, nleft);
+
+ if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+ continue;
+
+ if (status < 0)
+ return (status);
+
+ if (status == 0)
+ {
+ DEBUG ("Received EOF from fd %i. "
+ "Closing fd and returning error.",
+ fd);
+ close (fd);
+ return (-1);
+ }
+
+ assert ((0 > status) || (nleft >= (size_t)status));
+
+ nleft = nleft - status;
+ ptr = ptr + status;
+ }
+
+ return (0);
+}
+
+
+ssize_t swrite (int fd, const void *buf, size_t count)
+{
+ const char *ptr;
+ size_t nleft;
+ ssize_t status;
+
+ ptr = (const char *) buf;
+ nleft = count;
+
+ while (nleft > 0)
+ {
+ status = write (fd, (const void *) ptr, nleft);
+
+ if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+ continue;
+
+ if (status < 0)
+ return (status);
+
+ nleft = nleft - status;
+ ptr = ptr + status;
+ }
+
+ return (0);
+}
+
+int strsplit (char *string, char **fields, size_t size)
+{
+ size_t i;
+ char *ptr;
+ char *saveptr;
+
+ i = 0;
+ ptr = string;
+ saveptr = NULL;
+ while ((fields[i] = strtok_r (ptr, " \t\r\n", &saveptr)) != NULL)
+ {
+ ptr = NULL;
+ i++;
+
+ if (i >= size)
+ break;
+ }
+
+ return ((int) i);
+}
+
+int strjoin (char *dst, size_t dst_len,
+ char **fields, size_t fields_num,
+ const char *sep)
+{
+ size_t field_len;
+ size_t sep_len;
+ int i;
+
+ memset (dst, '\0', dst_len);
+
+ if (fields_num <= 0)
+ return (-1);
+
+ sep_len = 0;
+ if (sep != NULL)
+ sep_len = strlen (sep);
+
+ for (i = 0; i < (int)fields_num; i++)
+ {
+ if ((i > 0) && (sep_len > 0))
+ {
+ if (dst_len <= sep_len)
+ return (-1);
+
+ strncat (dst, sep, dst_len);
+ dst_len -= sep_len;
+ }
+
+ field_len = strlen (fields[i]);
+
+ if (dst_len <= field_len)
+ return (-1);
+
+ strncat (dst, fields[i], dst_len);
+ dst_len -= field_len;
+ }
+
+ return (strlen (dst));
+}
+
+int strsubstitute (char *str, char c_from, char c_to)
+{
+ int ret;
+
+ if (str == NULL)
+ return (-1);
+
+ ret = 0;
+ while (*str != '\0')
+ {
+ if (*str == c_from)
+ {
+ *str = c_to;
+ ret++;
+ }
+ str++;
+ }
+
+ return (ret);
+} /* int strsubstitute */
+
+int strunescape (char *buf, size_t buf_len)
+{
+ size_t i;
+
+ for (i = 0; (i < buf_len) && (buf[i] != '\0'); ++i)
+ {
+ if (buf[i] != '\\')
+ continue;
+
+ if (((i + 1) >= buf_len) || (buf[i + 1] == 0)) {
+ ERROR ("string unescape: backslash found at end of string.");
+ /* Ensure null-byte at the end of the buffer. */
+ buf[i] = 0;
+ return (-1);
+ }
+
+ switch (buf[i + 1]) {
+ case 't':
+ buf[i] = '\t';
+ break;
+ case 'n':
+ buf[i] = '\n';
+ break;
+ case 'r':
+ buf[i] = '\r';
+ break;
+ default:
+ buf[i] = buf[i + 1];
+ break;
+ }
+
+ /* Move everything after the position one position to the left.
+ * Add a null-byte as last character in the buffer. */
+ memmove (buf + i + 1, buf + i + 2, buf_len - i - 2);
+ buf[buf_len - 1] = 0;
+ }
+ return (0);
+} /* int strunescape */
+
+size_t strstripnewline (char *buffer)
+{
+ size_t buffer_len = strlen (buffer);
+
+ while (buffer_len > 0)
+ {
+ if ((buffer[buffer_len - 1] != '\n')
+ && (buffer[buffer_len - 1] != '\r'))
+ break;
+ buffer[buffer_len] = 0;
+ buffer_len--;
+ }
+
+ return (buffer_len);
+} /* size_t strstripnewline */
+
+int escape_slashes (char *buffer, size_t buffer_size)
+{
+ int i;
+ size_t buffer_len;
+
+ buffer_len = strlen (buffer);
+
+ if (buffer_len <= 1)
+ {
+ if (strcmp ("/", buffer) == 0)
+ {
+ if (buffer_size < 5)
+ return (-1);
+ sstrncpy (buffer, "root", buffer_size);
+ }
+ return (0);
+ }
+
+ /* Move one to the left */
+ if (buffer[0] == '/')
+ {
+ memmove (buffer, buffer + 1, buffer_len);
+ buffer_len--;
+ }
+
+ for (i = 0; i < buffer_len - 1; i++)
+ {
+ if (buffer[i] == '/')
+ buffer[i] = '_';
+ }
+
+ return (0);
+} /* int escape_slashes */
+
+void replace_special (char *buffer, size_t buffer_size)
+{
+ size_t i;
+
+ for (i = 0; i < buffer_size; i++)
+ {
+ if (buffer[i] == 0)
+ return;
+ if ((!isalnum ((int) buffer[i])) && (buffer[i] != '-'))
+ buffer[i] = '_';
+ }
+} /* void replace_special */
+
+int timeval_cmp (struct timeval tv0, struct timeval tv1, struct timeval *delta)
+{
+ struct timeval *larger;
+ struct timeval *smaller;
+
+ int status;
+
+ NORMALIZE_TIMEVAL (tv0);
+ NORMALIZE_TIMEVAL (tv1);
+
+ if ((tv0.tv_sec == tv1.tv_sec) && (tv0.tv_usec == tv1.tv_usec))
+ {
+ if (delta != NULL) {
+ delta->tv_sec = 0;
+ delta->tv_usec = 0;
+ }
+ return (0);
+ }
+
+ if ((tv0.tv_sec < tv1.tv_sec)
+ || ((tv0.tv_sec == tv1.tv_sec) && (tv0.tv_usec < tv1.tv_usec)))
+ {
+ larger = &tv1;
+ smaller = &tv0;
+ status = -1;
+ }
+ else
+ {
+ larger = &tv0;
+ smaller = &tv1;
+ status = 1;
+ }
+
+ if (delta != NULL) {
+ delta->tv_sec = larger->tv_sec - smaller->tv_sec;
+
+ if (smaller->tv_usec <= larger->tv_usec)
+ delta->tv_usec = larger->tv_usec - smaller->tv_usec;
+ else
+ {
+ --delta->tv_sec;
+ delta->tv_usec = 1000000 + larger->tv_usec - smaller->tv_usec;
+ }
+ }
+
+ assert ((delta == NULL)
+ || ((0 <= delta->tv_usec) && (delta->tv_usec < 1000000)));
+
+ return (status);
+} /* int timeval_cmp */
+
+int check_create_dir (const char *file_orig)
+{
+ struct stat statbuf;
+
+ char file_copy[512];
+ char dir[512];
+ int dir_len = 512;
+ char *fields[16];
+ int fields_num;
+ char *ptr;
+ char *saveptr;
+ int last_is_file = 1;
+ int path_is_absolute = 0;
+ size_t len;
+ int i;
+
+ /*
+ * Sanity checks first
+ */
+ if (file_orig == NULL)
+ return (-1);
+
+ if ((len = strlen (file_orig)) < 1)
+ return (-1);
+ else if (len >= sizeof (file_copy))
+ return (-1);
+
+ /*
+ * If `file_orig' ends in a slash the last component is a directory,
+ * otherwise it's a file. Act accordingly..
+ */
+ if (file_orig[len - 1] == '/')
+ last_is_file = 0;
+ if (file_orig[0] == '/')
+ path_is_absolute = 1;
+
+ /*
+ * Create a copy for `strtok_r' to destroy
+ */
+ sstrncpy (file_copy, file_orig, sizeof (file_copy));
+
+ /*
+ * Break into components. This will eat up several slashes in a row and
+ * remove leading and trailing slashes..
+ */
+ ptr = file_copy;
+ saveptr = NULL;
+ fields_num = 0;
+ while ((fields[fields_num] = strtok_r (ptr, "/", &saveptr)) != NULL)
+ {
+ ptr = NULL;
+ fields_num++;
+
+ if (fields_num >= 16)
+ break;
+ }
+
+ /*
+ * For each component, do..
+ */
+ for (i = 0; i < (fields_num - last_is_file); i++)
+ {
+ /*
+ * Do not create directories that start with a dot. This
+ * prevents `../../' attacks and other likely malicious
+ * behavior.
+ */
+ if (fields[i][0] == '.')
+ {
+ ERROR ("Cowardly refusing to create a directory that "
+ "begins with a `.' (dot): `%s'", file_orig);
+ return (-2);
+ }
+
+ /*
+ * Join the components together again
+ */
+ dir[0] = '/';
+ if (strjoin (dir + path_is_absolute, dir_len - path_is_absolute,
+ fields, i + 1, "/") < 0)
+ {
+ ERROR ("strjoin failed: `%s', component #%i", file_orig, i);
+ return (-1);
+ }
+
+ while (42) {
+ if ((stat (dir, &statbuf) == -1)
+ && (lstat (dir, &statbuf) == -1))
+ {
+ if (errno == ENOENT)
+ {
+ if (mkdir (dir, S_IRWXU | S_IRWXG | S_IRWXO) == 0)
+ break;
+
+ /* this might happen, if a different thread created
+ * the directory in the meantime
+ * => call stat() again to check for S_ISDIR() */
+ if (EEXIST == errno)
+ continue;
+
+ char errbuf[1024];
+ ERROR ("check_create_dir: mkdir (%s): %s", dir,
+ sstrerror (errno,
+ errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+ else
+ {
+ char errbuf[1024];
+ ERROR ("check_create_dir: stat (%s): %s", dir,
+ sstrerror (errno, errbuf,
+ sizeof (errbuf)));
+ return (-1);
+ }
+ }
+ else if (!S_ISDIR (statbuf.st_mode))
+ {
+ ERROR ("check_create_dir: `%s' exists but is not "
+ "a directory!", dir);
+ return (-1);
+ }
+ break;
+ }
+ }
+
+ return (0);
+} /* check_create_dir */
+
+#ifdef HAVE_LIBKSTAT
+int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
+{
+ char ident[128];
+
+ *ksp_ptr = NULL;
+
+ if (kc == NULL)
+ return (-1);
+
+ ssnprintf (ident, sizeof (ident), "%s,%i,%s", module, instance, name);
+
+ *ksp_ptr = kstat_lookup (kc, module, instance, name);
+ if (*ksp_ptr == NULL)
+ {
+ ERROR ("get_kstat: Cound not find kstat %s", ident);
+ return (-1);
+ }
+
+ if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
+ {
+ ERROR ("get_kstat: kstat %s has wrong type", ident);
+ *ksp_ptr = NULL;
+ return (-1);
+ }
+
+#ifdef assert
+ assert (*ksp_ptr != NULL);
+ assert ((*ksp_ptr)->ks_type == KSTAT_TYPE_NAMED);
+#endif
+
+ if (kstat_read (kc, *ksp_ptr, NULL) == -1)
+ {
+ ERROR ("get_kstat: kstat %s could not be read", ident);
+ return (-1);
+ }
+
+ if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
+ {
+ ERROR ("get_kstat: kstat %s has wrong type", ident);
+ return (-1);
+ }
+
+ return (0);
+}
+
+long long get_kstat_value (kstat_t *ksp, char *name)
+{
+ kstat_named_t *kn;
+ long long retval = -1LL;
+
+ if (ksp == NULL)
+ {
+ ERROR ("get_kstat_value (\"%s\"): ksp is NULL.", name);
+ return (-1LL);
+ }
+ else if (ksp->ks_type != KSTAT_TYPE_NAMED)
+ {
+ ERROR ("get_kstat_value (\"%s\"): ksp->ks_type (%#x) "
+ "is not KSTAT_TYPE_NAMED (%#x).",
+ name,
+ (unsigned int) ksp->ks_type,
+ (unsigned int) KSTAT_TYPE_NAMED);
+ return (-1LL);
+ }
+
+ if ((kn = (kstat_named_t *) kstat_data_lookup (ksp, name)) == NULL)
+ return (-1LL);
+
+ if (kn->data_type == KSTAT_DATA_INT32)
+ retval = (long long) kn->value.i32;
+ else if (kn->data_type == KSTAT_DATA_UINT32)
+ retval = (long long) kn->value.ui32;
+ else if (kn->data_type == KSTAT_DATA_INT64)
+ retval = (long long) kn->value.i64; /* According to ANSI C99 `long long' must hold at least 64 bits */
+ else if (kn->data_type == KSTAT_DATA_UINT64)
+ retval = (long long) kn->value.ui64; /* XXX: Might overflow! */
+ else
+ WARNING ("get_kstat_value: Not a numeric value: %s", name);
+
+ return (retval);
+}
+#endif /* HAVE_LIBKSTAT */
+
+#ifndef HAVE_HTONLL
+unsigned long long ntohll (unsigned long long n)
+{
+#if BYTE_ORDER == BIG_ENDIAN
+ return (n);
+#else
+ return (((unsigned long long) ntohl (n)) << 32) + ntohl (n >> 32);
+#endif
+} /* unsigned long long ntohll */
+
+unsigned long long htonll (unsigned long long n)
+{
+#if BYTE_ORDER == BIG_ENDIAN
+ return (n);
+#else
+ return (((unsigned long long) htonl (n)) << 32) + htonl (n >> 32);
+#endif
+} /* unsigned long long htonll */
+#endif /* HAVE_HTONLL */
+
+#if FP_LAYOUT_NEED_NOTHING
+/* Well, we need nothing.. */
+/* #endif FP_LAYOUT_NEED_NOTHING */
+
+#elif FP_LAYOUT_NEED_ENDIANFLIP || FP_LAYOUT_NEED_INTSWAP
+# if FP_LAYOUT_NEED_ENDIANFLIP
+# define FP_CONVERT(A) ((((uint64_t)(A) & 0xff00000000000000LL) >> 56) | \
+ (((uint64_t)(A) & 0x00ff000000000000LL) >> 40) | \
+ (((uint64_t)(A) & 0x0000ff0000000000LL) >> 24) | \
+ (((uint64_t)(A) & 0x000000ff00000000LL) >> 8) | \
+ (((uint64_t)(A) & 0x00000000ff000000LL) << 8) | \
+ (((uint64_t)(A) & 0x0000000000ff0000LL) << 24) | \
+ (((uint64_t)(A) & 0x000000000000ff00LL) << 40) | \
+ (((uint64_t)(A) & 0x00000000000000ffLL) << 56))
+# else
+# define FP_CONVERT(A) ((((uint64_t)(A) & 0xffffffff00000000LL) >> 32) | \
+ (((uint64_t)(A) & 0x00000000ffffffffLL) << 32))
+# endif
+
+double ntohd (double d)
+{
+ union
+ {
+ uint8_t byte[8];
+ uint64_t integer;
+ double floating;
+ } ret;
+
+ ret.floating = d;
+
+ /* NAN in x86 byte order */
+ if ((ret.byte[0] == 0x00) && (ret.byte[1] == 0x00)
+ && (ret.byte[2] == 0x00) && (ret.byte[3] == 0x00)
+ && (ret.byte[4] == 0x00) && (ret.byte[5] == 0x00)
+ && (ret.byte[6] == 0xf8) && (ret.byte[7] == 0x7f))
+ {
+ return (NAN);
+ }
+ else
+ {
+ uint64_t tmp;
+
+ tmp = ret.integer;
+ ret.integer = FP_CONVERT (tmp);
+ return (ret.floating);
+ }
+} /* double ntohd */
+
+double htond (double d)
+{
+ union
+ {
+ uint8_t byte[8];
+ uint64_t integer;
+ double floating;
+ } ret;
+
+ if (isnan (d))
+ {
+ ret.byte[0] = ret.byte[1] = ret.byte[2] = ret.byte[3] = 0x00;
+ ret.byte[4] = ret.byte[5] = 0x00;
+ ret.byte[6] = 0xf8;
+ ret.byte[7] = 0x7f;
+ return (ret.floating);
+ }
+ else
+ {
+ uint64_t tmp;
+
+ ret.floating = d;
+ tmp = FP_CONVERT (ret.integer);
+ ret.integer = tmp;
+ return (ret.floating);
+ }
+} /* double htond */
+#endif /* FP_LAYOUT_NEED_ENDIANFLIP || FP_LAYOUT_NEED_INTSWAP */
+
+int format_name (char *ret, int ret_len,
+ const char *hostname,
+ const char *plugin, const char *plugin_instance,
+ const char *type, const char *type_instance)
+{
+ char *buffer;
+ size_t buffer_size;
+
+ buffer = ret;
+ buffer_size = (size_t) ret_len;
+
+#define APPEND(str) do { \
+ size_t l = strlen (str); \
+ if (l >= buffer_size) \
+ return (ENOBUFS); \
+ memcpy (buffer, (str), l); \
+ buffer += l; buffer_size -= l; \
+} while (0)
+
+ assert (plugin != NULL);
+ assert (type != NULL);
+
+ APPEND (hostname);
+ APPEND ("/");
+ APPEND (plugin);
+ if ((plugin_instance != NULL) && (plugin_instance[0] != 0))
+ {
+ APPEND ("-");
+ APPEND (plugin_instance);
+ }
+ APPEND ("/");
+ APPEND (type);
+ if ((type_instance != NULL) && (type_instance[0] != 0))
+ {
+ APPEND ("-");
+ APPEND (type_instance);
+ }
+ assert (buffer_size > 0);
+ buffer[0] = 0;
+
+#undef APPEND
+ return (0);
+} /* int format_name */
+
+int format_values (char *ret, size_t ret_len, /* {{{ */
+ const data_set_t *ds, const value_list_t *vl,
+ _Bool store_rates)
+{
+ size_t offset = 0;
+ int status;
+ int i;
+ gauge_t *rates = NULL;
+
+ assert (0 == strcmp (ds->type, vl->type));
+
+ memset (ret, 0, ret_len);
+
+#define BUFFER_ADD(...) do { \
+ status = ssnprintf (ret + offset, ret_len - offset, \
+ __VA_ARGS__); \
+ if (status < 1) \
+ { \
+ sfree (rates); \
+ return (-1); \
+ } \
+ else if (((size_t) status) >= (ret_len - offset)) \
+ { \
+ sfree (rates); \
+ return (-1); \
+ } \
+ else \
+ offset += ((size_t) status); \
+} while (0)
+
+ BUFFER_ADD ("%.3f", CDTIME_T_TO_DOUBLE (vl->time));
+
+ for (i = 0; i < ds->ds_num; i++)
+ {
+ if (ds->ds[i].type == DS_TYPE_GAUGE)
+ BUFFER_ADD (":%f", vl->values[i].gauge);
+ else if (store_rates)
+ {
+ if (rates == NULL)
+ rates = uc_get_rate (ds, vl);
+ if (rates == NULL)
+ {
+ WARNING ("format_values: "
+ "uc_get_rate failed.");
+ return (-1);
+ }
+ BUFFER_ADD (":%g", rates[i]);
+ }
+ else if (ds->ds[i].type == DS_TYPE_COUNTER)
+ BUFFER_ADD (":%llu", vl->values[i].counter);
+ else if (ds->ds[i].type == DS_TYPE_DERIVE)
+ BUFFER_ADD (":%"PRIi64, vl->values[i].derive);
+ else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
+ BUFFER_ADD (":%"PRIu64, vl->values[i].absolute);
+ else
+ {
+ ERROR ("format_values plugin: Unknown data source type: %i",
+ ds->ds[i].type);
+ sfree (rates);
+ return (-1);
+ }
+ } /* for ds->ds_num */
+
+#undef BUFFER_ADD
+
+ sfree (rates);
+ return (0);
+} /* }}} int format_values */
+
+int parse_identifier (char *str, char **ret_host,
+ char **ret_plugin, char **ret_plugin_instance,
+ char **ret_type, char **ret_type_instance)
+{
+ char *hostname = NULL;
+ char *plugin = NULL;
+ char *plugin_instance = NULL;
+ char *type = NULL;
+ char *type_instance = NULL;
+
+ hostname = str;
+ if (hostname == NULL)
+ return (-1);
+
+ plugin = strchr (hostname, '/');
+ if (plugin == NULL)
+ return (-1);
+ *plugin = '\0'; plugin++;
+
+ type = strchr (plugin, '/');
+ if (type == NULL)
+ return (-1);
+ *type = '\0'; type++;
+
+ plugin_instance = strchr (plugin, '-');
+ if (plugin_instance != NULL)
+ {
+ *plugin_instance = '\0';
+ plugin_instance++;
+ }
+
+ type_instance = strchr (type, '-');
+ if (type_instance != NULL)
+ {
+ *type_instance = '\0';
+ type_instance++;
+ }
+
+ *ret_host = hostname;
+ *ret_plugin = plugin;
+ *ret_plugin_instance = plugin_instance;
+ *ret_type = type;
+ *ret_type_instance = type_instance;
+ return (0);
+} /* int parse_identifier */
+
+int parse_identifier_vl (const char *str, value_list_t *vl) /* {{{ */
+{
+ char str_copy[6 * DATA_MAX_NAME_LEN];
+ char *host = NULL;
+ char *plugin = NULL;
+ char *plugin_instance = NULL;
+ char *type = NULL;
+ char *type_instance = NULL;
+ int status;
+
+ if ((str == NULL) || (vl == NULL))
+ return (EINVAL);
+
+ sstrncpy (str_copy, str, sizeof (str_copy));
+
+ status = parse_identifier (str_copy, &host,
+ &plugin, &plugin_instance,
+ &type, &type_instance);
+ if (status != 0)
+ return (status);
+
+ sstrncpy (vl->host, host, sizeof (vl->host));
+ sstrncpy (vl->plugin, plugin, sizeof (vl->plugin));
+ sstrncpy (vl->plugin_instance,
+ (plugin_instance != NULL) ? plugin_instance : "",
+ sizeof (vl->plugin_instance));
+ sstrncpy (vl->type, type, sizeof (vl->type));
+ sstrncpy (vl->type_instance,
+ (type_instance != NULL) ? type_instance : "",
+ sizeof (vl->type_instance));
+
+ return (0);
+} /* }}} int parse_identifier_vl */
+
+int parse_value (const char *value_orig, value_t *ret_value, int ds_type)
+{
+ char *value;
+ char *endptr = NULL;
+ size_t value_len;
+
+ if (value_orig == NULL)
+ return (EINVAL);
+
+ value = strdup (value_orig);
+ if (value == NULL)
+ return (ENOMEM);
+ value_len = strlen (value);
+
+ while ((value_len > 0) && isspace ((int) value[value_len - 1]))
+ {
+ value[value_len - 1] = 0;
+ value_len--;
+ }
+
+ switch (ds_type)
+ {
+ case DS_TYPE_COUNTER:
+ ret_value->counter = (counter_t) strtoull (value, &endptr, 0);
+ break;
+
+ case DS_TYPE_GAUGE:
+ ret_value->gauge = (gauge_t) strtod (value, &endptr);
+ break;
+
+ case DS_TYPE_DERIVE:
+ ret_value->derive = (derive_t) strtoll (value, &endptr, 0);
+ break;
+
+ case DS_TYPE_ABSOLUTE:
+ ret_value->absolute = (absolute_t) strtoull (value, &endptr, 0);
+ break;
+
+ default:
+ sfree (value);
+ ERROR ("parse_value: Invalid data source type: %i.", ds_type);
+ return -1;
+ }
+
+ if (value == endptr) {
+ ERROR ("parse_value: Failed to parse string as %s: %s.",
+ DS_TYPE_TO_STRING (ds_type), value);
+ sfree (value);
+ return -1;
+ }
+ else if ((NULL != endptr) && ('\0' != *endptr))
+ INFO ("parse_value: Ignoring trailing garbage \"%s\" after %s value. "
+ "Input string was \"%s\".",
+ endptr, DS_TYPE_TO_STRING (ds_type), value_orig);
+
+ sfree (value);
+ return 0;
+} /* int parse_value */
+
+int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
+{
+ int i;
+ char *dummy;
+ char *ptr;
+ char *saveptr;
+
+ i = -1;
+ dummy = buffer;
+ saveptr = NULL;
+ while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL)
+ {
+ dummy = NULL;
+
+ if (i >= vl->values_len)
+ {
+ /* Make sure i is invalid. */
+ i = vl->values_len + 1;
+ break;
+ }
+
+ if (i == -1)
+ {
+ if (strcmp ("N", ptr) == 0)
+ vl->time = cdtime ();
+ else
+ {
+ char *endptr = NULL;
+ double tmp;
+
+ errno = 0;
+ tmp = strtod (ptr, &endptr);
+ if ((errno != 0) /* Overflow */
+ || (endptr == ptr) /* Invalid string */
+ || (endptr == NULL) /* This should not happen */
+ || (*endptr != 0)) /* Trailing chars */
+ return (-1);
+
+ vl->time = DOUBLE_TO_CDTIME_T (tmp);
+ }
+ }
+ else
+ {
+ if ((strcmp ("U", ptr) == 0) && (ds->ds[i].type == DS_TYPE_GAUGE))
+ vl->values[i].gauge = NAN;
+ else if (0 != parse_value (ptr, &vl->values[i], ds->ds[i].type))
+ return -1;
+ }
+
+ i++;
+ } /* while (strtok_r) */
+
+ if ((ptr != NULL) || (i != vl->values_len))
+ return (-1);
+ return (0);
+} /* int parse_values */
+
+#if !HAVE_GETPWNAM_R
+int getpwnam_r (const char *name, struct passwd *pwbuf, char *buf,
+ size_t buflen, struct passwd **pwbufp)
+{
+ int status = 0;
+ struct passwd *pw;
+
+ memset (pwbuf, '\0', sizeof (struct passwd));
+
+ pthread_mutex_lock (&getpwnam_r_lock);
+
+ do
+ {
+ pw = getpwnam (name);
+ if (pw == NULL)
+ {
+ status = (errno != 0) ? errno : ENOENT;
+ break;
+ }
+
+#define GETPWNAM_COPY_MEMBER(member) \
+ if (pw->member != NULL) \
+ { \
+ int len = strlen (pw->member); \
+ if (len >= buflen) \
+ { \
+ status = ENOMEM; \
+ break; \
+ } \
+ sstrncpy (buf, pw->member, buflen); \
+ pwbuf->member = buf; \
+ buf += (len + 1); \
+ buflen -= (len + 1); \
+ }
+ GETPWNAM_COPY_MEMBER(pw_name);
+ GETPWNAM_COPY_MEMBER(pw_passwd);
+ GETPWNAM_COPY_MEMBER(pw_gecos);
+ GETPWNAM_COPY_MEMBER(pw_dir);
+ GETPWNAM_COPY_MEMBER(pw_shell);
+
+ pwbuf->pw_uid = pw->pw_uid;
+ pwbuf->pw_gid = pw->pw_gid;
+
+ if (pwbufp != NULL)
+ *pwbufp = pwbuf;
+ } while (0);
+
+ pthread_mutex_unlock (&getpwnam_r_lock);
+
+ return (status);
+} /* int getpwnam_r */
+#endif /* !HAVE_GETPWNAM_R */
+
+int notification_init (notification_t *n, int severity, const char *message,
+ const char *host,
+ const char *plugin, const char *plugin_instance,
+ const char *type, const char *type_instance)
+{
+ memset (n, '\0', sizeof (notification_t));
+
+ n->severity = severity;
+
+ if (message != NULL)
+ sstrncpy (n->message, message, sizeof (n->message));
+ if (host != NULL)
+ sstrncpy (n->host, host, sizeof (n->host));
+ if (plugin != NULL)
+ sstrncpy (n->plugin, plugin, sizeof (n->plugin));
+ if (plugin_instance != NULL)
+ sstrncpy (n->plugin_instance, plugin_instance,
+ sizeof (n->plugin_instance));
+ if (type != NULL)
+ sstrncpy (n->type, type, sizeof (n->type));
+ if (type_instance != NULL)
+ sstrncpy (n->type_instance, type_instance,
+ sizeof (n->type_instance));
+
+ return (0);
+} /* int notification_init */
+
+int walk_directory (const char *dir, dirwalk_callback_f callback,
+ void *user_data, int include_hidden)
+{
+ struct dirent *ent;
+ DIR *dh;
+ int success;
+ int failure;
+
+ success = 0;
+ failure = 0;
+
+ if ((dh = opendir (dir)) == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("walk_directory: Cannot open '%s': %s", dir,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return -1;
+ }
+
+ while ((ent = readdir (dh)) != NULL)
+ {
+ int status;
+
+ if (include_hidden)
+ {
+ if ((strcmp (".", ent->d_name) == 0)
+ || (strcmp ("..", ent->d_name) == 0))
+ continue;
+ }
+ else /* if (!include_hidden) */
+ {
+ if (ent->d_name[0]=='.')
+ continue;
+ }
+
+ status = (*callback) (dir, ent->d_name, user_data);
+ if (status != 0)
+ failure++;
+ else
+ success++;
+ }
+
+ closedir (dh);
+
+ if ((success == 0) && (failure > 0))
+ return (-1);
+ return (0);
+}
+
+ssize_t read_file_contents (const char *filename, char *buf, size_t bufsize)
+{
+ FILE *fh;
+ ssize_t ret;
+
+ fh = fopen (filename, "r");
+ if (fh == NULL)
+ return (-1);
+
+ ret = (ssize_t) fread (buf, 1, bufsize, fh);
+ if ((ret == 0) && (ferror (fh) != 0))
+ {
+ ERROR ("read_file_contents: Reading file \"%s\" failed.",
+ filename);
+ ret = -1;
+ }
+
+ fclose(fh);
+ return (ret);
+}
+
+counter_t counter_diff (counter_t old_value, counter_t new_value)
+{
+ counter_t diff;
+
+ if (old_value > new_value)
+ {
+ if (old_value <= 4294967295U)
+ diff = (4294967295U - old_value) + new_value;
+ else
+ diff = (18446744073709551615ULL - old_value)
+ + new_value;
+ }
+ else
+ {
+ diff = new_value - old_value;
+ }
+
+ return (diff);
+} /* counter_t counter_diff */
+
+int rate_to_value (value_t *ret_value, gauge_t rate, /* {{{ */
+ rate_to_value_state_t *state,
+ int ds_type, cdtime_t t)
+{
+ gauge_t delta_gauge;
+ cdtime_t delta_t;
+
+ if (ds_type == DS_TYPE_GAUGE)
+ {
+ state->last_value.gauge = rate;
+ state->last_time = t;
+
+ *ret_value = state->last_value;
+ return (0);
+ }
+
+ /* Counter and absolute can't handle negative rates. Reset "last time"
+ * to zero, so that the next valid rate will re-initialize the
+ * structure. */
+ if ((rate < 0.0)
+ && ((ds_type == DS_TYPE_COUNTER)
+ || (ds_type == DS_TYPE_ABSOLUTE)))
+ {
+ memset (state, 0, sizeof (*state));
+ return (EINVAL);
+ }
+
+ /* Another invalid state: The time is not increasing. */
+ if (t <= state->last_time)
+ {
+ memset (state, 0, sizeof (*state));
+ return (EINVAL);
+ }
+
+ delta_t = t - state->last_time;
+ delta_gauge = (rate * CDTIME_T_TO_DOUBLE (delta_t)) + state->residual;
+
+ /* Previous value is invalid. */
+ if (state->last_time == 0) /* {{{ */
+ {
+ if (ds_type == DS_TYPE_DERIVE)
+ {
+ state->last_value.derive = (derive_t) rate;
+ state->residual = rate - ((gauge_t) state->last_value.derive);
+ }
+ else if (ds_type == DS_TYPE_COUNTER)
+ {
+ state->last_value.counter = (counter_t) rate;
+ state->residual = rate - ((gauge_t) state->last_value.counter);
+ }
+ else if (ds_type == DS_TYPE_ABSOLUTE)
+ {
+ state->last_value.absolute = (absolute_t) rate;
+ state->residual = rate - ((gauge_t) state->last_value.absolute);
+ }
+ else
+ {
+ assert (23 == 42);
+ }
+
+ state->last_time = t;
+ return (EAGAIN);
+ } /* }}} */
+
+ if (ds_type == DS_TYPE_DERIVE)
+ {
+ derive_t delta_derive = (derive_t) delta_gauge;
+
+ state->last_value.derive += delta_derive;
+ state->residual = delta_gauge - ((gauge_t) delta_derive);
+ }
+ else if (ds_type == DS_TYPE_COUNTER)
+ {
+ counter_t delta_counter = (counter_t) delta_gauge;
+
+ state->last_value.counter += delta_counter;
+ state->residual = delta_gauge - ((gauge_t) delta_counter);
+ }
+ else if (ds_type == DS_TYPE_ABSOLUTE)
+ {
+ absolute_t delta_absolute = (absolute_t) delta_gauge;
+
+ state->last_value.absolute = delta_absolute;
+ state->residual = delta_gauge - ((gauge_t) delta_absolute);
+ }
+ else
+ {
+ assert (23 == 42);
+ }
+
+ state->last_time = t;
+ *ret_value = state->last_value;
+ return (0);
+} /* }}} value_t rate_to_value */
+
+int value_to_rate (value_t *ret_rate, derive_t value, /* {{{ */
+ value_to_rate_state_t *state,
+ int ds_type, cdtime_t t)
+{
+ double interval;
+
+ /* Another invalid state: The time is not increasing. */
+ if (t <= state->last_time)
+ {
+ memset (state, 0, sizeof (*state));
+ return (EINVAL);
+ }
+
+ interval = CDTIME_T_TO_DOUBLE(t - state->last_time);
+
+ /* Previous value is invalid. */
+ if (state->last_time == 0) /* {{{ */
+ {
+ if (ds_type == DS_TYPE_DERIVE)
+ {
+ state->last_value.derive = value;
+ }
+ else if (ds_type == DS_TYPE_COUNTER)
+ {
+ state->last_value.counter = (counter_t) value;
+ }
+ else if (ds_type == DS_TYPE_ABSOLUTE)
+ {
+ state->last_value.absolute = (absolute_t) value;
+ }
+ else
+ {
+ assert (23 == 42);
+ }
+
+ state->last_time = t;
+ return (EAGAIN);
+ } /* }}} */
+
+ if (ds_type == DS_TYPE_DERIVE)
+ {
+ ret_rate->gauge = (value - state->last_value.derive) / interval;
+ state->last_value.derive = value;
+ }
+ else if (ds_type == DS_TYPE_COUNTER)
+ {
+ ret_rate->gauge = (((counter_t)value) - state->last_value.counter) / interval;
+ state->last_value.counter = (counter_t) value;
+ }
+ else if (ds_type == DS_TYPE_ABSOLUTE)
+ {
+ ret_rate->gauge = (((absolute_t)value) - state->last_value.absolute) / interval;
+ state->last_value.absolute = (absolute_t) value;
+ }
+ else
+ {
+ assert (23 == 42);
+ }
+
+ state->last_time = t;
+ return (0);
+} /* }}} value_t rate_to_value */
+
+int service_name_to_port_number (const char *service_name)
+{
+ struct addrinfo *ai_list;
+ struct addrinfo *ai_ptr;
+ struct addrinfo ai_hints;
+ int status;
+ int service_number;
+
+ if (service_name == NULL)
+ return (-1);
+
+ ai_list = NULL;
+ memset (&ai_hints, 0, sizeof (ai_hints));
+ ai_hints.ai_family = AF_UNSPEC;
+
+ status = getaddrinfo (/* node = */ NULL, service_name,
+ &ai_hints, &ai_list);
+ if (status != 0)
+ {
+ ERROR ("service_name_to_port_number: getaddrinfo failed: %s",
+ gai_strerror (status));
+ return (-1);
+ }
+
+ service_number = -1;
+ for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
+ {
+ if (ai_ptr->ai_family == AF_INET)
+ {
+ struct sockaddr_in *sa;
+
+ sa = (void *) ai_ptr->ai_addr;
+ service_number = (int) ntohs (sa->sin_port);
+ }
+ else if (ai_ptr->ai_family == AF_INET6)
+ {
+ struct sockaddr_in6 *sa;
+
+ sa = (void *) ai_ptr->ai_addr;
+ service_number = (int) ntohs (sa->sin6_port);
+ }
+
+ if ((service_number > 0) && (service_number <= 65535))
+ break;
+ }
+
+ freeaddrinfo (ai_list);
+
+ if ((service_number > 0) && (service_number <= 65535))
+ return (service_number);
+ return (-1);
+} /* int service_name_to_port_number */
+
+int strtoderive (const char *string, derive_t *ret_value) /* {{{ */
+{
+ derive_t tmp;
+ char *endptr;
+
+ if ((string == NULL) || (ret_value == NULL))
+ return (EINVAL);
+
+ errno = 0;
+ endptr = NULL;
+ tmp = (derive_t) strtoll (string, &endptr, /* base = */ 0);
+ if ((endptr == string) || (errno != 0))
+ return (-1);
+
+ *ret_value = tmp;
+ return (0);
+} /* }}} int strtoderive */
+
+int strtogauge (const char *string, gauge_t *ret_value) /* {{{ */
+{
+ gauge_t tmp;
+ char *endptr = NULL;
+
+ if ((string == NULL) || (ret_value == NULL))
+ return (EINVAL);
+
+ errno = 0;
+ endptr = NULL;
+ tmp = (gauge_t) strtod (string, &endptr);
+ if (errno != 0)
+ return (errno);
+ else if ((endptr == NULL) || (*endptr != 0))
+ return (EINVAL);
+
+ *ret_value = tmp;
+ return (0);
+} /* }}} int strtogauge */
+
+int strarray_add (char ***ret_array, size_t *ret_array_len, char const *str) /* {{{ */
+{
+ char **array;
+ size_t array_len = *ret_array_len;
+
+ if (str == NULL)
+ return (EINVAL);
+
+ array = realloc (*ret_array,
+ (array_len + 1) * sizeof (*array));
+ if (array == NULL)
+ return (ENOMEM);
+ *ret_array = array;
+
+ array[array_len] = strdup (str);
+ if (array[array_len] == NULL)
+ return (ENOMEM);
+
+ array_len++;
+ *ret_array_len = array_len;
+ return (0);
+} /* }}} int strarray_add */
+
+void strarray_free (char **array, size_t array_len) /* {{{ */
+{
+ size_t i;
+
+ for (i = 0; i < array_len; i++)
+ sfree (array[i]);
+ sfree (array);
+} /* }}} void strarray_free */
diff --git a/src/daemon/common.h b/src/daemon/common.h
--- /dev/null
+++ b/src/daemon/common.h
@@ -0,0 +1,357 @@
+/**
+ * collectd - src/common.h
+ * Copyright (C) 2005-2014 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ * Niki W. Waibel <niki.waibel@gmx.net>
+**/
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include "collectd.h"
+#include "plugin.h"
+
+#if HAVE_PWD_H
+# include <pwd.h>
+#endif
+
+#define sfree(ptr) \
+ do { \
+ if((ptr) != NULL) { \
+ free(ptr); \
+ } \
+ (ptr) = NULL; \
+ } while (0)
+
+#define STATIC_ARRAY_SIZE(a) (sizeof (a) / sizeof (*(a)))
+
+#define IS_TRUE(s) ((strcasecmp ("true", (s)) == 0) \
+ || (strcasecmp ("yes", (s)) == 0) \
+ || (strcasecmp ("on", (s)) == 0))
+#define IS_FALSE(s) ((strcasecmp ("false", (s)) == 0) \
+ || (strcasecmp ("no", (s)) == 0) \
+ || (strcasecmp ("off", (s)) == 0))
+
+struct rate_to_value_state_s
+{
+ value_t last_value;
+ cdtime_t last_time;
+ gauge_t residual;
+};
+typedef struct rate_to_value_state_s rate_to_value_state_t;
+
+struct value_to_rate_state_s
+{
+ value_t last_value;
+ cdtime_t last_time;
+};
+typedef struct value_to_rate_state_s value_to_rate_state_t;
+
+char *sstrncpy (char *dest, const char *src, size_t n);
+
+__attribute__ ((format(printf,3,4)))
+int ssnprintf (char *dest, size_t n, const char *format, ...);
+
+__attribute__ ((format(printf,1,2)))
+char *ssnprintf_alloc (char const *format, ...);
+
+char *sstrdup(const char *s);
+void *smalloc(size_t size);
+char *sstrerror (int errnum, char *buf, size_t buflen);
+
+/*
+ * NAME
+ * sread
+ *
+ * DESCRIPTION
+ * Reads exactly `n' bytes or fails. Syntax and other behavior is analogous
+ * to `read(2)'. If EOF is received the file descriptor is closed and an
+ * error is returned.
+ *
+ * PARAMETERS
+ * `fd' File descriptor to write to.
+ * `buf' Buffer that is to be written.
+ * `count' Number of bytes in the buffer.
+ *
+ * RETURN VALUE
+ * Zero upon success or non-zero if an error occurred. `errno' is set in this
+ * case.
+ */
+ssize_t sread (int fd, void *buf, size_t count);
+
+/*
+ * NAME
+ * swrite
+ *
+ * DESCRIPTION
+ * Writes exactly `n' bytes or fails. Syntax and other behavior is analogous
+ * to `write(2)'.
+ *
+ * PARAMETERS
+ * `fd' File descriptor to write to.
+ * `buf' Buffer that is to be written.
+ * `count' Number of bytes in the buffer.
+ *
+ * RETURN VALUE
+ * Zero upon success or non-zero if an error occurred. `errno' is set in this
+ * case.
+ */
+ssize_t swrite (int fd, const void *buf, size_t count);
+
+/*
+ * NAME
+ * strsplit
+ *
+ * DESCRIPTION
+ * Splits a string into parts and stores pointers to the parts in `fields'.
+ * The characters split at are: " ", "\t", "\r", and "\n".
+ *
+ * PARAMETERS
+ * `string' String to split. This string will be modified. `fields' will
+ * contain pointers to parts of this string, so free'ing it
+ * will destroy `fields' as well.
+ * `fields' Array of strings where pointers to the parts will be stored.
+ * `size' Number of elements in the array. No more than `size'
+ * pointers will be stored in `fields'.
+ *
+ * RETURN VALUE
+ * Returns the number of parts stored in `fields'.
+ */
+int strsplit (char *string, char **fields, size_t size);
+
+/*
+ * NAME
+ * strjoin
+ *
+ * DESCRIPTION
+ * Joins together several parts of a string using `sep' as a separator. This
+ * is equivalent to the Perl built-in `join'.
+ *
+ * PARAMETERS
+ * `dst' Buffer where the result is stored.
+ * `dst_len' Length of the destination buffer. No more than this many
+ * bytes will be written to the memory pointed to by `dst',
+ * including the trailing null-byte.
+ * `fields' Array of strings to be joined.
+ * `fields_num' Number of elements in the `fields' array.
+ * `sep' String to be inserted between any two elements of `fields'.
+ * This string is neither prepended nor appended to the result.
+ * Instead of passing "" (empty string) one can pass NULL.
+ *
+ * RETURN VALUE
+ * Returns the number of characters in `dst', NOT including the trailing
+ * null-byte. If an error occurred (empty array or `dst' too small) a value
+ * smaller than zero will be returned.
+ */
+int strjoin (char *dst, size_t dst_len, char **fields, size_t fields_num, const char *sep);
+
+/*
+ * NAME
+ * escape_slashes
+ *
+ * DESCRIPTION
+ * Removes slashes ("/") from "buffer". If buffer contains a single slash,
+ * the result will be "root". Leading slashes are removed. All other slashes
+ * are replaced with underscores ("_").
+ * This function is used by plugin_dispatch_values() to escape all parts of
+ * the identifier.
+ *
+ * PARAMETERS
+ * `buffer' String to be escaped.
+ * `buffer_size' Size of the buffer. No more then this many bytes will be
+ * written to `buffer', including the trailing null-byte.
+ *
+ * RETURN VALUE
+ * Returns zero upon success and a value smaller than zero upon failure.
+ */
+int escape_slashes (char *buffer, size_t buffer_size);
+
+/*
+ * NAME
+ * replace_special
+ *
+ * DESCRIPTION
+ * Replaces any special characters (anything that's not alpha-numeric or a
+ * dash) with an underscore.
+ *
+ * E.g. "foo$bar&" would become "foo_bar_".
+ *
+ * PARAMETERS
+ * `buffer' String to be handled.
+ * `buffer_size' Length of the string. The function returns after
+ * encountering a null-byte or reading this many bytes.
+ */
+void replace_special (char *buffer, size_t buffer_size);
+
+int strsubstitute (char *str, char c_from, char c_to);
+
+/*
+ * NAME
+ * strunescape
+ *
+ * DESCRIPTION
+ * Replaces any escaped characters in a string with the appropriate special
+ * characters. The following escaped characters are recognized:
+ *
+ * \t -> <tab>
+ * \n -> <newline>
+ * \r -> <carriage return>
+ *
+ * For all other escacped characters only the backslash will be removed.
+ *
+ * PARAMETERS
+ * `buf' String to be unescaped.
+ * `buf_len' Length of the string, including the terminating null-byte.
+ *
+ * RETURN VALUE
+ * Returns zero upon success, a value less than zero else.
+ */
+int strunescape (char *buf, size_t buf_len);
+
+/**
+ * Removed trailing newline characters (CR and LF) from buffer, which must be
+ * null terminated. Returns the length of the resulting string.
+ */
+__attribute__((nonnull (1)))
+size_t strstripnewline (char *buffer);
+
+/*
+ * NAME
+ * timeval_cmp
+ *
+ * DESCRIPTION
+ * Compare the two time values `tv0' and `tv1' and store the absolut value
+ * of the difference in the time value pointed to by `delta' if it does not
+ * equal NULL.
+ *
+ * RETURN VALUE
+ * Returns an integer less than, equal to, or greater than zero if `tv0' is
+ * less than, equal to, or greater than `tv1' respectively.
+ */
+int timeval_cmp (struct timeval tv0, struct timeval tv1, struct timeval *delta);
+
+/* make sure tv_usec stores less than a second */
+#define NORMALIZE_TIMEVAL(tv) \
+ do { \
+ (tv).tv_sec += (tv).tv_usec / 1000000; \
+ (tv).tv_usec = (tv).tv_usec % 1000000; \
+ } while (0)
+
+/* make sure tv_sec stores less than a second */
+#define NORMALIZE_TIMESPEC(tv) \
+ do { \
+ (tv).tv_sec += (tv).tv_nsec / 1000000000; \
+ (tv).tv_nsec = (tv).tv_nsec % 1000000000; \
+ } while (0)
+
+int check_create_dir (const char *file_orig);
+
+#ifdef HAVE_LIBKSTAT
+int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name);
+long long get_kstat_value (kstat_t *ksp, char *name);
+#endif
+
+#ifndef HAVE_HTONLL
+unsigned long long ntohll (unsigned long long n);
+unsigned long long htonll (unsigned long long n);
+#endif
+
+#if FP_LAYOUT_NEED_NOTHING
+# define ntohd(d) (d)
+# define htond(d) (d)
+#elif FP_LAYOUT_NEED_ENDIANFLIP || FP_LAYOUT_NEED_INTSWAP
+double ntohd (double d);
+double htond (double d);
+#else
+# error "Don't know how to convert between host and network representation of doubles."
+#endif
+
+int format_name (char *ret, int ret_len,
+ const char *hostname,
+ const char *plugin, const char *plugin_instance,
+ const char *type, const char *type_instance);
+#define FORMAT_VL(ret, ret_len, vl) \
+ format_name (ret, ret_len, (vl)->host, (vl)->plugin, (vl)->plugin_instance, \
+ (vl)->type, (vl)->type_instance)
+int format_values (char *ret, size_t ret_len,
+ const data_set_t *ds, const value_list_t *vl,
+ _Bool store_rates);
+
+int parse_identifier (char *str, char **ret_host,
+ char **ret_plugin, char **ret_plugin_instance,
+ char **ret_type, char **ret_type_instance);
+int parse_identifier_vl (const char *str, value_list_t *vl);
+int parse_value (const char *value, value_t *ret_value, int ds_type);
+int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds);
+
+#if !HAVE_GETPWNAM_R
+int getpwnam_r (const char *name, struct passwd *pwbuf, char *buf,
+ size_t buflen, struct passwd **pwbufp);
+#endif
+
+int notification_init (notification_t *n, int severity, const char *message,
+ const char *host,
+ const char *plugin, const char *plugin_instance,
+ const char *type, const char *type_instance);
+#define NOTIFICATION_INIT_VL(n, vl) \
+ notification_init (n, NOTIF_FAILURE, NULL, \
+ (vl)->host, (vl)->plugin, (vl)->plugin_instance, \
+ (vl)->type, (vl)->type_instance)
+
+typedef int (*dirwalk_callback_f)(const char *dirname, const char *filename,
+ void *user_data);
+int walk_directory (const char *dir, dirwalk_callback_f callback,
+ void *user_data, int hidden);
+/* Returns the number of bytes read or negative on error. */
+ssize_t read_file_contents (char const *filename, char *buf, size_t bufsize);
+
+counter_t counter_diff (counter_t old_value, counter_t new_value);
+
+/* Convert a rate back to a value_t. When converting to a derive_t, counter_t
+ * or absoltue_t, take fractional residuals into account. This is important
+ * when scaling counters, for example.
+ * Returns zero on success. Returns EAGAIN when called for the first time; in
+ * this case the value_t is invalid and the next call should succeed. Other
+ * return values indicate an error. */
+int rate_to_value (value_t *ret_value, gauge_t rate,
+ rate_to_value_state_t *state, int ds_type, cdtime_t t);
+
+int value_to_rate (value_t *ret_rate, derive_t value,
+ value_to_rate_state_t *state, int ds_type, cdtime_t t);
+
+/* Converts a service name (a string) to a port number
+ * (in the range [1-65535]). Returns less than zero on error. */
+int service_name_to_port_number (const char *service_name);
+
+/** Parse a string to a derive_t value. Returns zero on success or non-zero on
+ * failure. If failure is returned, ret_value is not touched. */
+int strtoderive (const char *string, derive_t *ret_value);
+
+/** Parse a string to a gauge_t value. Returns zero on success or non-zero on
+ * failure. If failure is returned, ret_value is not touched. */
+int strtogauge (const char *string, gauge_t *ret_value);
+
+int strarray_add (char ***ret_array, size_t *ret_array_len, char const *str);
+void strarray_free (char **array, size_t array_len);
+
+#endif /* COMMON_H */
diff --git a/src/daemon/configfile.c b/src/daemon/configfile.c
--- /dev/null
+++ b/src/daemon/configfile.c
@@ -0,0 +1,1353 @@
+/**
+ * collectd - src/configfile.c
+ * Copyright (C) 2005-2011 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ * Sebastian tokkee Harl <sh at tokkee.org>
+ **/
+
+#include "collectd.h"
+
+#include "liboconfig/oconfig.h"
+
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+#include "types_list.h"
+#include "filter_chain.h"
+
+#if HAVE_WORDEXP_H
+# include <wordexp.h>
+#endif /* HAVE_WORDEXP_H */
+
+#if HAVE_FNMATCH_H
+# include <fnmatch.h>
+#endif /* HAVE_FNMATCH_H */
+
+#if HAVE_LIBGEN_H
+# include <libgen.h>
+#endif /* HAVE_LIBGEN_H */
+
+#define ESCAPE_NULL(str) ((str) == NULL ? "(null)" : (str))
+
+/*
+ * Private types
+ */
+typedef struct cf_callback
+{
+ const char *type;
+ int (*callback) (const char *, const char *);
+ const char **keys;
+ int keys_num;
+ plugin_ctx_t ctx;
+ struct cf_callback *next;
+} cf_callback_t;
+
+typedef struct cf_complex_callback_s
+{
+ char *type;
+ int (*callback) (oconfig_item_t *);
+ plugin_ctx_t ctx;
+ struct cf_complex_callback_s *next;
+} cf_complex_callback_t;
+
+typedef struct cf_value_map_s
+{
+ char *key;
+ int (*func) (const oconfig_item_t *);
+} cf_value_map_t;
+
+typedef struct cf_global_option_s
+{
+ char *key;
+ char *value;
+ char *def;
+} cf_global_option_t;
+
+/*
+ * Prototypes of callback functions
+ */
+static int dispatch_value_typesdb (const oconfig_item_t *ci);
+static int dispatch_value_plugindir (const oconfig_item_t *ci);
+static int dispatch_loadplugin (const oconfig_item_t *ci);
+
+/*
+ * Private variables
+ */
+static cf_callback_t *first_callback = NULL;
+static cf_complex_callback_t *complex_callback_head = NULL;
+
+static cf_value_map_t cf_value_map[] =
+{
+ {"TypesDB", dispatch_value_typesdb},
+ {"PluginDir", dispatch_value_plugindir},
+ {"LoadPlugin", dispatch_loadplugin}
+};
+static int cf_value_map_num = STATIC_ARRAY_SIZE (cf_value_map);
+
+static cf_global_option_t cf_global_options[] =
+{
+ {"BaseDir", NULL, PKGLOCALSTATEDIR},
+ {"PIDFile", NULL, PIDFILE},
+ {"Hostname", NULL, NULL},
+ {"FQDNLookup", NULL, "true"},
+ {"Interval", NULL, NULL},
+ {"ReadThreads", NULL, "5"},
+ {"WriteThreads", NULL, "5"},
+ {"WriteQueueLimitHigh", NULL, NULL},
+ {"WriteQueueLimitLow", NULL, NULL},
+ {"Timeout", NULL, "2"},
+ {"AutoLoadPlugin", NULL, "false"},
+ {"CollectInternalStats", NULL, "false"},
+ {"PreCacheChain", NULL, "PreCache"},
+ {"PostCacheChain", NULL, "PostCache"},
+ {"MaxReadInterval", NULL, "86400"}
+};
+static int cf_global_options_num = STATIC_ARRAY_SIZE (cf_global_options);
+
+static int cf_default_typesdb = 1;
+
+/*
+ * Functions to handle register/unregister, search, and other plugin related
+ * stuff
+ */
+static cf_callback_t *cf_search (const char *type)
+{
+ cf_callback_t *cf_cb;
+
+ if (type == NULL)
+ return (NULL);
+
+ for (cf_cb = first_callback; cf_cb != NULL; cf_cb = cf_cb->next)
+ if (strcasecmp (cf_cb->type, type) == 0)
+ break;
+
+ return (cf_cb);
+}
+
+static int cf_dispatch (const char *type, const char *orig_key,
+ const char *orig_value)
+{
+ cf_callback_t *cf_cb;
+ plugin_ctx_t old_ctx;
+ char *key;
+ char *value;
+ int ret;
+ int i;
+
+ DEBUG ("type = %s, key = %s, value = %s",
+ ESCAPE_NULL(type),
+ ESCAPE_NULL(orig_key),
+ ESCAPE_NULL(orig_value));
+
+ if ((cf_cb = cf_search (type)) == NULL)
+ {
+ WARNING ("Found a configuration for the `%s' plugin, but "
+ "the plugin isn't loaded or didn't register "
+ "a configuration callback.", type);
+ return (-1);
+ }
+
+ if ((key = strdup (orig_key)) == NULL)
+ return (1);
+ if ((value = strdup (orig_value)) == NULL)
+ {
+ free (key);
+ return (2);
+ }
+
+ ret = -1;
+
+ old_ctx = plugin_set_ctx (cf_cb->ctx);
+
+ for (i = 0; i < cf_cb->keys_num; i++)
+ {
+ if ((cf_cb->keys[i] != NULL)
+ && (strcasecmp (cf_cb->keys[i], key) == 0))
+ {
+ ret = (*cf_cb->callback) (key, value);
+ break;
+ }
+ }
+
+ plugin_set_ctx (old_ctx);
+
+ if (i >= cf_cb->keys_num)
+ WARNING ("Plugin `%s' did not register for value `%s'.", type, key);
+
+ free (key);
+ free (value);
+
+ DEBUG ("cf_dispatch: return (%i)", ret);
+
+ return (ret);
+} /* int cf_dispatch */
+
+static int dispatch_global_option (const oconfig_item_t *ci)
+{
+ if (ci->values_num != 1)
+ return (-1);
+ if (ci->values[0].type == OCONFIG_TYPE_STRING)
+ return (global_option_set (ci->key, ci->values[0].value.string));
+ else if (ci->values[0].type == OCONFIG_TYPE_NUMBER)
+ {
+ char tmp[128];
+ ssnprintf (tmp, sizeof (tmp), "%lf", ci->values[0].value.number);
+ return (global_option_set (ci->key, tmp));
+ }
+ else if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN)
+ {
+ if (ci->values[0].value.boolean)
+ return (global_option_set (ci->key, "true"));
+ else
+ return (global_option_set (ci->key, "false"));
+ }
+
+ return (-1);
+} /* int dispatch_global_option */
+
+static int dispatch_value_typesdb (const oconfig_item_t *ci)
+{
+ int i = 0;
+
+ assert (strcasecmp (ci->key, "TypesDB") == 0);
+
+ cf_default_typesdb = 0;
+
+ if (ci->values_num < 1) {
+ ERROR ("configfile: `TypesDB' needs at least one argument.");
+ return (-1);
+ }
+
+ for (i = 0; i < ci->values_num; ++i)
+ {
+ if (OCONFIG_TYPE_STRING != ci->values[i].type) {
+ WARNING ("configfile: TypesDB: Skipping %i. argument which "
+ "is not a string.", i + 1);
+ continue;
+ }
+
+ read_types_list (ci->values[i].value.string);
+ }
+ return (0);
+} /* int dispatch_value_typesdb */
+
+static int dispatch_value_plugindir (const oconfig_item_t *ci)
+{
+ assert (strcasecmp (ci->key, "PluginDir") == 0);
+
+ if (ci->values_num != 1)
+ return (-1);
+ if (ci->values[0].type != OCONFIG_TYPE_STRING)
+ return (-1);
+
+ plugin_set_dir (ci->values[0].value.string);
+ return (0);
+}
+
+static int dispatch_loadplugin (const oconfig_item_t *ci)
+{
+ int i;
+ const char *name;
+ unsigned int flags = 0;
+ plugin_ctx_t ctx;
+ plugin_ctx_t old_ctx;
+ int ret_val;
+
+ assert (strcasecmp (ci->key, "LoadPlugin") == 0);
+
+ if (ci->values_num != 1)
+ return (-1);
+ if (ci->values[0].type != OCONFIG_TYPE_STRING)
+ return (-1);
+
+ name = ci->values[0].value.string;
+ if (strcmp ("libvirt", name) == 0)
+ name = "virt";
+
+ /* default to the global interval set before loading this plugin */
+ memset (&ctx, 0, sizeof (ctx));
+ ctx.interval = cf_get_default_interval ();
+
+ for (i = 0; i < ci->children_num; ++i) {
+ if (strcasecmp("Globals", ci->children[i].key) == 0)
+ cf_util_get_flag (ci->children + i, &flags, PLUGIN_FLAGS_GLOBAL);
+ else if (strcasecmp ("Interval", ci->children[i].key) == 0) {
+ if (cf_util_get_cdtime (ci->children + i, &ctx.interval) != 0) {
+ /* cf_util_get_cdtime will log an error */
+ continue;
+ }
+ }
+ else {
+ WARNING("Ignoring unknown LoadPlugin option \"%s\" "
+ "for plugin \"%s\"",
+ ci->children[i].key, ci->values[0].value.string);
+ }
+ }
+
+ old_ctx = plugin_set_ctx (ctx);
+ ret_val = plugin_load (name, (uint32_t) flags);
+ /* reset to the "global" context */
+ plugin_set_ctx (old_ctx);
+
+ return (ret_val);
+} /* int dispatch_value_loadplugin */
+
+static int dispatch_value_plugin (const char *plugin, oconfig_item_t *ci)
+{
+ char buffer[4096];
+ char *buffer_ptr;
+ int buffer_free;
+ int i;
+
+ buffer_ptr = buffer;
+ buffer_free = sizeof (buffer);
+
+ for (i = 0; i < ci->values_num; i++)
+ {
+ int status = -1;
+
+ if (ci->values[i].type == OCONFIG_TYPE_STRING)
+ status = ssnprintf (buffer_ptr, buffer_free, " %s",
+ ci->values[i].value.string);
+ else if (ci->values[i].type == OCONFIG_TYPE_NUMBER)
+ status = ssnprintf (buffer_ptr, buffer_free, " %lf",
+ ci->values[i].value.number);
+ else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN)
+ status = ssnprintf (buffer_ptr, buffer_free, " %s",
+ ci->values[i].value.boolean
+ ? "true" : "false");
+
+ if ((status < 0) || (status >= buffer_free))
+ return (-1);
+ buffer_free -= status;
+ buffer_ptr += status;
+ }
+ /* skip the initial space */
+ buffer_ptr = buffer + 1;
+
+ return (cf_dispatch (plugin, ci->key, buffer_ptr));
+} /* int dispatch_value_plugin */
+
+static int dispatch_value (const oconfig_item_t *ci)
+{
+ int ret = -2;
+ int i;
+
+ for (i = 0; i < cf_value_map_num; i++)
+ if (strcasecmp (cf_value_map[i].key, ci->key) == 0)
+ {
+ ret = cf_value_map[i].func (ci);
+ break;
+ }
+
+ for (i = 0; i < cf_global_options_num; i++)
+ if (strcasecmp (cf_global_options[i].key, ci->key) == 0)
+ {
+ ret = dispatch_global_option (ci);
+ break;
+ }
+
+ return (ret);
+} /* int dispatch_value */
+
+static int dispatch_block_plugin (oconfig_item_t *ci)
+{
+ int i;
+ char *name;
+
+ cf_complex_callback_t *cb;
+
+ if (strcasecmp (ci->key, "Plugin") != 0)
+ return (-1);
+ if (ci->values_num < 1)
+ return (-1);
+ if (ci->values[0].type != OCONFIG_TYPE_STRING)
+ return (-1);
+
+ name = ci->values[0].value.string;
+ if (strcmp ("libvirt", name) == 0)
+ {
+ /* TODO(octo): Remove this legacy. */
+ WARNING ("The \"libvirt\" plugin has been renamed to \"virt\" to avoid problems with the build system. "
+ "Your configuration is still using the old name. "
+ "Please change it to use \"virt\" as soon as possible. "
+ "This compatibility code will go away eventually.");
+ name = "virt";
+ }
+
+ if (IS_TRUE (global_option_get ("AutoLoadPlugin")))
+ {
+ int status;
+
+ status = plugin_load (name, /* flags = */ 0);
+ if (status != 0)
+ {
+ ERROR ("Automatically loading plugin \"%s\" failed "
+ "with status %i.", name, status);
+ return (status);
+ }
+ }
+
+ /* Check for a complex callback first */
+ for (cb = complex_callback_head; cb != NULL; cb = cb->next)
+ {
+ if (strcasecmp (name, cb->type) == 0)
+ {
+ plugin_ctx_t old_ctx;
+ int ret_val;
+
+ old_ctx = plugin_set_ctx (cb->ctx);
+ ret_val = (cb->callback (ci));
+ plugin_set_ctx (old_ctx);
+ return (ret_val);
+ }
+ }
+
+ /* 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
+ {
+ WARNING ("There is a `%s' block within the "
+ "configuration for the %s plugin. "
+ "The plugin either only expects "
+ "\"simple\" configuration statements "
+ "or wasn't loaded using `LoadPlugin'."
+ " Please check your configuration.",
+ ci->children[i].key, name);
+ }
+ }
+
+ return (0);
+}
+
+
+static int dispatch_block (oconfig_item_t *ci)
+{
+ if (strcasecmp (ci->key, "LoadPlugin") == 0)
+ return (dispatch_loadplugin (ci));
+ else if (strcasecmp (ci->key, "Plugin") == 0)
+ return (dispatch_block_plugin (ci));
+ else if (strcasecmp (ci->key, "Chain") == 0)
+ return (fc_configure (ci));
+
+ return (0);
+}
+
+static int cf_ci_replace_child (oconfig_item_t *dst, oconfig_item_t *src,
+ int offset)
+{
+ oconfig_item_t *temp;
+ int i;
+
+ assert (offset >= 0);
+ assert (dst->children_num > offset);
+
+ /* Free the memory used by the replaced child. Usually that's the
+ * `Include "blah"' statement. */
+ temp = dst->children + offset;
+ for (i = 0; i < temp->values_num; i++)
+ {
+ if (temp->values[i].type == OCONFIG_TYPE_STRING)
+ {
+ sfree (temp->values[i].value.string);
+ }
+ }
+ sfree (temp->values);
+ temp = NULL;
+
+ /* If (src->children_num == 0) the array size is decreased. If offset
+ * is _not_ the last element, (offset < (dst->children_num - 1)), then
+ * we need to move the trailing elements before resizing the array. */
+ if ((src->children_num == 0) && (offset < (dst->children_num - 1)))
+ {
+ int nmemb = dst->children_num - (offset + 1);
+ memmove (dst->children + offset, dst->children + offset + 1,
+ sizeof (oconfig_item_t) * nmemb);
+ }
+
+ /* Resize the memory containing the children to be big enough to hold
+ * all children. */
+ if (dst->children_num + src->children_num - 1 == 0)
+ {
+ dst->children_num = 0;
+ return (0);
+ }
+
+ temp = (oconfig_item_t *) realloc (dst->children,
+ sizeof (oconfig_item_t)
+ * (dst->children_num + src->children_num - 1));
+ if (temp == NULL)
+ {
+ ERROR ("configfile: realloc failed.");
+ return (-1);
+ }
+ dst->children = temp;
+
+ /* If there are children behind the include statement, and they have
+ * not yet been moved because (src->children_num == 0), then move them
+ * to the end of the list, so that the new children have room before
+ * them. */
+ if ((src->children_num > 0)
+ && ((dst->children_num - (offset + 1)) > 0))
+ {
+ int nmemb = dst->children_num - (offset + 1);
+ int old_offset = offset + 1;
+ int new_offset = offset + src->children_num;
+
+ memmove (dst->children + new_offset,
+ dst->children + old_offset,
+ sizeof (oconfig_item_t) * nmemb);
+ }
+
+ /* Last but not least: If there are new children, copy them to the
+ * memory reserved for them. */
+ if (src->children_num > 0)
+ {
+ memcpy (dst->children + offset,
+ src->children,
+ sizeof (oconfig_item_t) * src->children_num);
+ }
+
+ /* Update the number of children. */
+ dst->children_num += (src->children_num - 1);
+
+ return (0);
+} /* int cf_ci_replace_child */
+
+static int cf_ci_append_children (oconfig_item_t *dst, oconfig_item_t *src)
+{
+ oconfig_item_t *temp;
+
+ if ((src == NULL) || (src->children_num == 0))
+ return (0);
+
+ temp = (oconfig_item_t *) realloc (dst->children,
+ sizeof (oconfig_item_t)
+ * (dst->children_num + src->children_num));
+ if (temp == NULL)
+ {
+ ERROR ("configfile: realloc failed.");
+ return (-1);
+ }
+ dst->children = temp;
+
+ memcpy (dst->children + dst->children_num,
+ src->children,
+ sizeof (oconfig_item_t)
+ * src->children_num);
+ dst->children_num += src->children_num;
+
+ return (0);
+} /* int cf_ci_append_children */
+
+#define CF_MAX_DEPTH 8
+static oconfig_item_t *cf_read_generic (const char *path,
+ const char *pattern, int depth);
+
+static int cf_include_all (oconfig_item_t *root, int depth)
+{
+ int i;
+
+ for (i = 0; i < root->children_num; i++)
+ {
+ oconfig_item_t *new;
+ oconfig_item_t *old;
+
+ char *pattern = NULL;
+
+ int j;
+
+ if (strcasecmp (root->children[i].key, "Include") != 0)
+ continue;
+
+ old = root->children + i;
+
+ if ((old->values_num != 1)
+ || (old->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ ERROR ("configfile: `Include' needs exactly one string argument.");
+ continue;
+ }
+
+ for (j = 0; j < old->children_num; ++j)
+ {
+ oconfig_item_t *child = old->children + j;
+
+ if (strcasecmp (child->key, "Filter") == 0)
+ cf_util_get_string (child, &pattern);
+ else
+ ERROR ("configfile: Option `%s' not allowed in <Include> block.",
+ child->key);
+ }
+
+ new = cf_read_generic (old->values[0].value.string, pattern, depth + 1);
+ sfree (pattern);
+
+ if (new == NULL)
+ return (-1);
+
+ /* Now replace the i'th child in `root' with `new'. */
+ if (cf_ci_replace_child (root, new, i) < 0)
+ return (-1);
+
+ /* ... and go back to the new i'th child. */
+ --i;
+
+ sfree (new->values);
+ sfree (new);
+ } /* for (i = 0; i < root->children_num; i++) */
+
+ return (0);
+} /* int cf_include_all */
+
+static oconfig_item_t *cf_read_file (const char *file,
+ const char *pattern, int depth)
+{
+ oconfig_item_t *root;
+ int status;
+
+ assert (depth < CF_MAX_DEPTH);
+
+ if (pattern != NULL) {
+#if HAVE_FNMATCH_H && HAVE_LIBGEN_H
+ char *tmp = sstrdup (file);
+ char *filename = basename (tmp);
+
+ if ((filename != NULL) && (fnmatch (pattern, filename, 0) != 0)) {
+ DEBUG ("configfile: Not including `%s' because it "
+ "does not match pattern `%s'.",
+ filename, pattern);
+ free (tmp);
+ return (NULL);
+ }
+
+ free (tmp);
+#else
+ ERROR ("configfile: Cannot apply pattern filter '%s' "
+ "to file '%s': functions basename() and / or "
+ "fnmatch() not available.", pattern, file);
+#endif /* HAVE_FNMATCH_H && HAVE_LIBGEN_H */
+ }
+
+ root = oconfig_parse_file (file);
+ if (root == NULL)
+ {
+ ERROR ("configfile: Cannot read file `%s'.", file);
+ return (NULL);
+ }
+
+ status = cf_include_all (root, depth);
+ if (status != 0)
+ {
+ oconfig_free (root);
+ return (NULL);
+ }
+
+ return (root);
+} /* oconfig_item_t *cf_read_file */
+
+static int cf_compare_string (const void *p1, const void *p2)
+{
+ return strcmp (*(const char **) p1, *(const char **) p2);
+}
+
+static oconfig_item_t *cf_read_dir (const char *dir,
+ const char *pattern, int depth)
+{
+ oconfig_item_t *root = NULL;
+ DIR *dh;
+ struct dirent *de;
+ char **filenames = NULL;
+ int filenames_num = 0;
+ int status;
+ int i;
+
+ assert (depth < CF_MAX_DEPTH);
+
+ dh = opendir (dir);
+ if (dh == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("configfile: opendir failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (NULL);
+ }
+
+ root = (oconfig_item_t *) malloc (sizeof (oconfig_item_t));
+ if (root == NULL)
+ {
+ ERROR ("configfile: malloc failed.");
+ return (NULL);
+ }
+ memset (root, 0, sizeof (oconfig_item_t));
+
+ while ((de = readdir (dh)) != NULL)
+ {
+ char name[1024];
+ char **tmp;
+
+ if ((de->d_name[0] == '.') || (de->d_name[0] == 0))
+ continue;
+
+ status = ssnprintf (name, sizeof (name), "%s/%s",
+ dir, de->d_name);
+ if ((status < 0) || ((size_t) status >= sizeof (name)))
+ {
+ ERROR ("configfile: Not including `%s/%s' because its"
+ " name is too long.",
+ dir, de->d_name);
+ for (i = 0; i < filenames_num; ++i)
+ free (filenames[i]);
+ free (filenames);
+ free (root);
+ return (NULL);
+ }
+
+ ++filenames_num;
+ tmp = (char **) realloc (filenames,
+ filenames_num * sizeof (*filenames));
+ if (tmp == NULL) {
+ ERROR ("configfile: realloc failed.");
+ for (i = 0; i < filenames_num - 1; ++i)
+ free (filenames[i]);
+ free (filenames);
+ free (root);
+ return (NULL);
+ }
+ filenames = tmp;
+
+ filenames[filenames_num - 1] = sstrdup (name);
+ }
+
+ qsort ((void *) filenames, filenames_num, sizeof (*filenames),
+ cf_compare_string);
+
+ for (i = 0; i < filenames_num; ++i)
+ {
+ oconfig_item_t *temp;
+ char *name = filenames[i];
+
+ temp = cf_read_generic (name, pattern, depth);
+ if (temp == NULL)
+ {
+ /* An error should already have been reported. */
+ sfree (name);
+ continue;
+ }
+
+ cf_ci_append_children (root, temp);
+ sfree (temp->children);
+ sfree (temp);
+
+ free (name);
+ }
+
+ free(filenames);
+ return (root);
+} /* oconfig_item_t *cf_read_dir */
+
+/*
+ * cf_read_generic
+ *
+ * Path is stat'ed and either cf_read_file or cf_read_dir is called
+ * accordingly.
+ *
+ * There are two versions of this function: If `wordexp' exists shell wildcards
+ * will be expanded and the function will include all matches found. If
+ * `wordexp' (or, more precisely, it's header file) is not available the
+ * simpler function is used which does not do any such expansion.
+ */
+#if HAVE_WORDEXP_H
+static oconfig_item_t *cf_read_generic (const char *path,
+ const char *pattern, int depth)
+{
+ oconfig_item_t *root = NULL;
+ int status;
+ const char *path_ptr;
+ wordexp_t we;
+ size_t i;
+
+ if (depth >= CF_MAX_DEPTH)
+ {
+ ERROR ("configfile: Not including `%s' because the maximum "
+ "nesting depth has been reached.", path);
+ return (NULL);
+ }
+
+ status = wordexp (path, &we, WRDE_NOCMD);
+ if (status != 0)
+ {
+ ERROR ("configfile: wordexp (%s) failed.", path);
+ return (NULL);
+ }
+
+ root = (oconfig_item_t *) malloc (sizeof (oconfig_item_t));
+ if (root == NULL)
+ {
+ ERROR ("configfile: malloc failed.");
+ return (NULL);
+ }
+ memset (root, '\0', sizeof (oconfig_item_t));
+
+ /* wordexp() might return a sorted list already. That's not
+ * documented though, so let's make sure we get what we want. */
+ qsort ((void *) we.we_wordv, we.we_wordc, sizeof (*we.we_wordv),
+ cf_compare_string);
+
+ for (i = 0; i < we.we_wordc; i++)
+ {
+ oconfig_item_t *temp;
+ struct stat statbuf;
+
+ path_ptr = we.we_wordv[i];
+
+ status = stat (path_ptr, &statbuf);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ WARNING ("configfile: stat (%s) failed: %s",
+ path_ptr,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ continue;
+ }
+
+ if (S_ISREG (statbuf.st_mode))
+ temp = cf_read_file (path_ptr, pattern, depth);
+ else if (S_ISDIR (statbuf.st_mode))
+ temp = cf_read_dir (path_ptr, pattern, depth);
+ else
+ {
+ WARNING ("configfile: %s is neither a file nor a "
+ "directory.", path);
+ continue;
+ }
+
+ if (temp == NULL) {
+ oconfig_free (root);
+ return (NULL);
+ }
+
+ cf_ci_append_children (root, temp);
+ sfree (temp->children);
+ sfree (temp);
+ }
+
+ wordfree (&we);
+
+ return (root);
+} /* oconfig_item_t *cf_read_generic */
+/* #endif HAVE_WORDEXP_H */
+
+#else /* if !HAVE_WORDEXP_H */
+static oconfig_item_t *cf_read_generic (const char *path,
+ const char *pattern, int depth)
+{
+ struct stat statbuf;
+ int status;
+
+ if (depth >= CF_MAX_DEPTH)
+ {
+ ERROR ("configfile: Not including `%s' because the maximum "
+ "nesting depth has been reached.", path);
+ return (NULL);
+ }
+
+ status = stat (path, &statbuf);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("configfile: stat (%s) failed: %s",
+ path,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (NULL);
+ }
+
+ if (S_ISREG (statbuf.st_mode))
+ return (cf_read_file (path, pattern, depth));
+ else if (S_ISDIR (statbuf.st_mode))
+ return (cf_read_dir (path, pattern, depth));
+
+ ERROR ("configfile: %s is neither a file nor a directory.", path);
+ return (NULL);
+} /* oconfig_item_t *cf_read_generic */
+#endif /* !HAVE_WORDEXP_H */
+
+/*
+ * Public functions
+ */
+int global_option_set (const char *option, const char *value)
+{
+ int i;
+
+ DEBUG ("option = %s; value = %s;", option, value);
+
+ for (i = 0; i < cf_global_options_num; i++)
+ if (strcasecmp (cf_global_options[i].key, option) == 0)
+ break;
+
+ if (i >= cf_global_options_num)
+ return (-1);
+
+ if (strcasecmp (option, "PIDFile") == 0 && pidfile_from_cli == 1)
+ {
+ DEBUG ("Configfile: Ignoring `PIDFILE' option because "
+ "command-line option `-P' take precedence.");
+ return (0);
+ }
+
+ sfree (cf_global_options[i].value);
+
+ if (value != NULL)
+ cf_global_options[i].value = strdup (value);
+ else
+ cf_global_options[i].value = NULL;
+
+ return (0);
+}
+
+const char *global_option_get (const char *option)
+{
+ int i;
+
+ for (i = 0; i < cf_global_options_num; i++)
+ if (strcasecmp (cf_global_options[i].key, option) == 0)
+ break;
+
+ if (i >= cf_global_options_num)
+ return (NULL);
+
+ return ((cf_global_options[i].value != NULL)
+ ? cf_global_options[i].value
+ : cf_global_options[i].def);
+} /* char *global_option_get */
+
+long global_option_get_long (const char *option, long default_value)
+{
+ const char *str;
+ long value;
+
+ str = global_option_get (option);
+ if (NULL == str)
+ return (default_value);
+
+ errno = 0;
+ value = strtol (str, /* endptr = */ NULL, /* base = */ 0);
+ if (errno != 0)
+ return (default_value);
+
+ return (value);
+} /* char *global_option_get_long */
+
+cdtime_t global_option_get_time (const char *name, cdtime_t def) /* {{{ */
+{
+ char const *optstr;
+ char *endptr = NULL;
+ double v;
+
+ optstr = global_option_get (name);
+ if (optstr == NULL)
+ return (def);
+
+ errno = 0;
+ v = strtod (optstr, &endptr);
+ if ((endptr == NULL) || (*endptr != 0) || (errno != 0))
+ return (def);
+ else if (v <= 0.0)
+ return (def);
+
+ return (DOUBLE_TO_CDTIME_T (v));
+} /* }}} cdtime_t global_option_get_time */
+
+cdtime_t cf_get_default_interval (void)
+{
+ return (global_option_get_time ("Interval",
+ DOUBLE_TO_CDTIME_T (COLLECTD_DEFAULT_INTERVAL)));
+}
+
+void cf_unregister (const char *type)
+{
+ cf_callback_t *this, *prev;
+
+ for (prev = NULL, this = first_callback;
+ this != NULL;
+ prev = this, this = this->next)
+ if (strcasecmp (this->type, type) == 0)
+ {
+ if (prev == NULL)
+ first_callback = this->next;
+ else
+ prev->next = this->next;
+
+ free (this);
+ break;
+ }
+} /* 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)
+{
+ cf_callback_t *cf_cb;
+
+ /* Remove this module from the list, if it already exists */
+ cf_unregister (type);
+
+ /* This pointer will be free'd in `cf_unregister' */
+ if ((cf_cb = (cf_callback_t *) malloc (sizeof (cf_callback_t))) == NULL)
+ return;
+
+ cf_cb->type = type;
+ cf_cb->callback = callback;
+ cf_cb->keys = keys;
+ cf_cb->keys_num = keys_num;
+ cf_cb->ctx = plugin_get_ctx ();
+
+ cf_cb->next = first_callback;
+ 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;
+
+ new->ctx = plugin_get_ctx ();
+
+ 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;
+ int i;
+
+ conf = cf_read_generic (filename, /* pattern = */ NULL, /* depth = */ 0);
+ if (conf == NULL)
+ {
+ ERROR ("Unable to read config file %s.", filename);
+ return (-1);
+ }
+ else if (conf->children_num == 0)
+ {
+ ERROR ("Configuration file %s is empty.", filename);
+ oconfig_free (conf);
+ return (-1);
+ }
+
+ for (i = 0; i < conf->children_num; i++)
+ {
+ if (conf->children[i].children == NULL)
+ dispatch_value (conf->children + i);
+ else
+ dispatch_block (conf->children + i);
+ }
+
+ oconfig_free (conf);
+
+ /* Read the default types.db if no `TypesDB' option was given. */
+ if (cf_default_typesdb)
+ read_types_list (PKGDATADIR"/types.db");
+
+ return (0);
+} /* int cf_read */
+
+/* Assures the config option is a string, duplicates it and returns the copy in
+ * "ret_string". If necessary "*ret_string" is freed first. Returns zero upon
+ * success. */
+int cf_util_get_string (const oconfig_item_t *ci, char **ret_string) /* {{{ */
+{
+ char *string;
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ ERROR ("cf_util_get_string: The %s option requires "
+ "exactly one string argument.", ci->key);
+ return (-1);
+ }
+
+ string = strdup (ci->values[0].value.string);
+ if (string == NULL)
+ return (-1);
+
+ if (*ret_string != NULL)
+ sfree (*ret_string);
+ *ret_string = string;
+
+ return (0);
+} /* }}} int cf_util_get_string */
+
+/* Assures the config option is a string and copies it to the provided buffer.
+ * Assures null-termination. */
+int cf_util_get_string_buffer (const oconfig_item_t *ci, char *buffer, /* {{{ */
+ size_t buffer_size)
+{
+ if ((ci == NULL) || (buffer == NULL) || (buffer_size < 1))
+ return (EINVAL);
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ ERROR ("cf_util_get_string_buffer: The %s option requires "
+ "exactly one string argument.", ci->key);
+ return (-1);
+ }
+
+ strncpy (buffer, ci->values[0].value.string, buffer_size);
+ buffer[buffer_size - 1] = 0;
+
+ return (0);
+} /* }}} int cf_util_get_string_buffer */
+
+/* Assures the config option is a number and returns it as an int. */
+int cf_util_get_int (const oconfig_item_t *ci, int *ret_value) /* {{{ */
+{
+ if ((ci == NULL) || (ret_value == NULL))
+ return (EINVAL);
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+ {
+ ERROR ("cf_util_get_int: The %s option requires "
+ "exactly one numeric argument.", ci->key);
+ return (-1);
+ }
+
+ *ret_value = (int) ci->values[0].value.number;
+
+ return (0);
+} /* }}} int cf_util_get_int */
+
+int cf_util_get_double (const oconfig_item_t *ci, double *ret_value) /* {{{ */
+{
+ if ((ci == NULL) || (ret_value == NULL))
+ return (EINVAL);
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+ {
+ ERROR ("cf_util_get_double: The %s option requires "
+ "exactly one numeric argument.", ci->key);
+ return (-1);
+ }
+
+ *ret_value = ci->values[0].value.number;
+
+ return (0);
+} /* }}} int cf_util_get_double */
+
+int cf_util_get_boolean (const oconfig_item_t *ci, _Bool *ret_bool) /* {{{ */
+{
+ if ((ci == NULL) || (ret_bool == NULL))
+ return (EINVAL);
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
+ {
+ ERROR ("cf_util_get_boolean: The %s option requires "
+ "exactly one boolean argument.", ci->key);
+ return (-1);
+ }
+
+ *ret_bool = ci->values[0].value.boolean ? 1 : 0;
+
+ return (0);
+} /* }}} int cf_util_get_boolean */
+
+int cf_util_get_flag (const oconfig_item_t *ci, /* {{{ */
+ unsigned int *ret_value, unsigned int flag)
+{
+ int status;
+ _Bool b;
+
+ if (ret_value == NULL)
+ return (EINVAL);
+
+ b = 0;
+ status = cf_util_get_boolean (ci, &b);
+ if (status != 0)
+ return (status);
+
+ if (b)
+ {
+ *ret_value |= flag;
+ }
+ else
+ {
+ *ret_value &= ~flag;
+ }
+
+ return (0);
+} /* }}} int cf_util_get_flag */
+
+/* Assures that the config option is a string or a number if the correct range
+ * of 1-65535. The string is then converted to a port number using
+ * `service_name_to_port_number' and returned.
+ * Returns the port number in the range [1-65535] or less than zero upon
+ * failure. */
+int cf_util_get_port_number (const oconfig_item_t *ci) /* {{{ */
+{
+ int tmp;
+
+ if ((ci->values_num != 1)
+ || ((ci->values[0].type != OCONFIG_TYPE_STRING)
+ && (ci->values[0].type != OCONFIG_TYPE_NUMBER)))
+ {
+ ERROR ("cf_util_get_port_number: The \"%s\" option requires "
+ "exactly one string argument.", ci->key);
+ return (-1);
+ }
+
+ if (ci->values[0].type == OCONFIG_TYPE_STRING)
+ return (service_name_to_port_number (ci->values[0].value.string));
+
+ assert (ci->values[0].type == OCONFIG_TYPE_NUMBER);
+ tmp = (int) (ci->values[0].value.number + 0.5);
+ if ((tmp < 1) || (tmp > 65535))
+ {
+ ERROR ("cf_util_get_port_number: The \"%s\" option requires "
+ "a service name or a port number. The number "
+ "you specified, %i, is not in the valid "
+ "range of 1-65535.",
+ ci->key, tmp);
+ return (-1);
+ }
+
+ return (tmp);
+} /* }}} int cf_util_get_port_number */
+
+int cf_util_get_service (const oconfig_item_t *ci, char **ret_string) /* {{{ */
+{
+ int port;
+ char *service;
+ int status;
+
+ if (ci->values_num != 1)
+ {
+ ERROR ("cf_util_get_service: The %s option requires exactly "
+ "one argument.", ci->key);
+ return (-1);
+ }
+
+ if (ci->values[0].type == OCONFIG_TYPE_STRING)
+ return (cf_util_get_string (ci, ret_string));
+ if (ci->values[0].type != OCONFIG_TYPE_NUMBER)
+ {
+ ERROR ("cf_util_get_service: The %s option requires "
+ "exactly one string or numeric argument.",
+ ci->key);
+ }
+
+ port = 0;
+ status = cf_util_get_int (ci, &port);
+ if (status != 0)
+ return (status);
+ else if ((port < 1) || (port > 65535))
+ {
+ ERROR ("cf_util_get_service: The port number given "
+ "for the %s option is out of "
+ "range (%i).", ci->key, port);
+ return (-1);
+ }
+
+ service = malloc (6);
+ if (service == NULL)
+ {
+ ERROR ("cf_util_get_service: Out of memory.");
+ return (-1);
+ }
+ ssnprintf (service, 6, "%i", port);
+
+ sfree (*ret_string);
+ *ret_string = service;
+
+ return (0);
+} /* }}} int cf_util_get_service */
+
+int cf_util_get_cdtime (const oconfig_item_t *ci, cdtime_t *ret_value) /* {{{ */
+{
+ if ((ci == NULL) || (ret_value == NULL))
+ return (EINVAL);
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+ {
+ ERROR ("cf_util_get_cdtime: The %s option requires "
+ "exactly one numeric argument.", ci->key);
+ return (-1);
+ }
+
+ if (ci->values[0].value.number < 0.0)
+ {
+ ERROR ("cf_util_get_cdtime: The numeric argument of the %s "
+ "option must not be negative.", ci->key);
+ return (-1);
+ }
+
+ *ret_value = DOUBLE_TO_CDTIME_T (ci->values[0].value.number);
+
+ return (0);
+} /* }}} int cf_util_get_cdtime */
+
diff --git a/src/daemon/configfile.h b/src/daemon/configfile.h
--- /dev/null
+++ b/src/daemon/configfile.h
@@ -0,0 +1,141 @@
+/**
+ * collectd - src/configfile.h
+ * Copyright (C) 2005-2011 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#ifndef CONFIGFILE_H
+#define CONFIGFILE_H
+
+#include "collectd.h"
+#include "utils_time.h"
+#include "liboconfig/oconfig.h"
+
+/*
+ * DESCRIPTION
+ * Remove a registered plugin from the internal data structures.
+ *
+ * PARAMETERS
+ * `type' Name of the plugin (must be the same as passed to
+ * `plugin_register'
+ */
+void cf_unregister (const char *type);
+void cf_unregister_complex (const char *type);
+
+/*
+ * DESCRIPTION
+ * `cf_register' is called by plugins that wish to receive config keys. The
+ * plugin will then receive all keys it registered for if they're found in a
+ * `<Plugin $type>' section.
+ *
+ * PARAMETERS
+ * `type' Name of the plugin (must be the same as passed to
+ * `plugin_register'
+ * `callback' Pointer to the callback function. The callback must return zero
+ * upon success, a value smaller than zero if it doesn't know how
+ * to handle the `key' passed to it (the first argument) or a
+ * value greater than zero if it knows how to handle the key but
+ * failed.
+ * `keys' Array of key values this plugin wished to receive. The last
+ * element must be a NULL-pointer.
+ * `keys_num' Number of elements in the array (not counting the last NULL-
+ * pointer.
+ *
+ * NOTES
+ * `cf_unregister' will be called for `type' to make sure only one record
+ * exists for each `type' at any time. This means that `cf_register' may be
+ * called multiple times, but only the last call will have an effect.
+ */
+void cf_register (const char *type,
+ int (*callback) (const char *, const char *),
+ const char **keys, int keys_num);
+
+int cf_register_complex (const char *type, int (*callback) (oconfig_item_t *));
+
+/*
+ * DESCRIPTION
+ * `cf_read' reads the config file `filename' and dispatches the read
+ * information to functions/variables. Most important: Is calls `plugin_load'
+ * to load specific plugins, depending on the current mode of operation.
+ *
+ * PARAMETERS
+ * `filename' An additional filename to look for. This function calls
+ * `lc_process' which already searches many standard locations..
+ * If set to NULL will use the `CONFIGFILE' define.
+ *
+ * RETURN VALUE
+ * Returns zero upon success and non-zero otherwise. A error-message will have
+ * been printed in this case.
+ */
+int cf_read (char *filename);
+
+int global_option_set (const char *option, const char *value);
+const char *global_option_get (const char *option);
+long global_option_get_long (const char *option, long default_value);
+long global_option_get_long_in_range (const char *option, long default_value, long min, long max);
+
+cdtime_t global_option_get_time (char const *option, cdtime_t default_value);
+
+cdtime_t cf_get_default_interval (void);
+
+/* Assures the config option is a string, duplicates it and returns the copy in
+ * "ret_string". If necessary "*ret_string" is freed first. Returns zero upon
+ * success. */
+int cf_util_get_string (const oconfig_item_t *ci, char **ret_string);
+
+/* Assures the config option is a string and copies it to the provided buffer.
+ * Assures null-termination. */
+int cf_util_get_string_buffer (const oconfig_item_t *ci, char *buffer,
+ size_t buffer_size);
+
+/* Assures the config option is a number and returns it as an int. */
+int cf_util_get_int (const oconfig_item_t *ci, int *ret_value);
+
+/* Assures the config option is a number and returns it as a double. */
+int cf_util_get_double (const oconfig_item_t *ci, double *ret_value);
+
+/* Assures the config option is a boolean and assignes it to `ret_bool'.
+ * Otherwise, `ret_bool' is not changed and non-zero is returned. */
+int cf_util_get_boolean (const oconfig_item_t *ci, _Bool *ret_bool);
+
+/* Assures the config option is a boolean and set or unset the given flag in
+ * `ret_value' as appropriate. Returns non-zero on error. */
+int cf_util_get_flag (const oconfig_item_t *ci,
+ unsigned int *ret_value, unsigned int flag);
+
+/* Assures that the config option is a string or a number if the correct range
+ * of 1-65535. The string is then converted to a port number using
+ * `service_name_to_port_number' and returned.
+ * Returns the port number in the range [1-65535] or less than zero upon
+ * failure. */
+int cf_util_get_port_number (const oconfig_item_t *ci);
+
+/* Assures that the config option is either a service name (a string) or a port
+ * number (an integer in the appropriate range) and returns a newly allocated
+ * string. If ret_string points to a non-NULL pointer, it is freed before
+ * assigning a new value. */
+int cf_util_get_service (const oconfig_item_t *ci, char **ret_string);
+
+int cf_util_get_cdtime (const oconfig_item_t *ci, cdtime_t *ret_value);
+
+#endif /* defined(CONFIGFILE_H) */
diff --git a/src/daemon/filter_chain.c b/src/daemon/filter_chain.c
--- /dev/null
@@ -0,0 +1,1058 @@
+/**
+ * collectd - src/filter_chain.c
+ * Copyright (C) 2008-2010 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#include "collectd.h"
+#include "configfile.h"
+#include "plugin.h"
+#include "utils_complain.h"
+#include "common.h"
+#include "filter_chain.h"
+
+/*
+ * Data types
+ */
+/* List of matches, used in fc_rule_t and for the global `match_list_head'
+ * variable. */
+struct fc_match_s;
+typedef struct fc_match_s fc_match_t; /* {{{ */
+struct fc_match_s
+{
+ char name[DATA_MAX_NAME_LEN];
+ match_proc_t proc;
+ void *user_data;
+ fc_match_t *next;
+}; /* }}} */
+
+/* List of targets, used in fc_rule_t and for the global `target_list_head'
+ * variable. */
+struct fc_target_s;
+typedef struct fc_target_s fc_target_t; /* {{{ */
+struct fc_target_s
+{
+ char name[DATA_MAX_NAME_LEN];
+ void *user_data;
+ target_proc_t proc;
+ fc_target_t *next;
+}; /* }}} */
+
+/* List of rules, used in fc_chain_t */
+struct fc_rule_s;
+typedef struct fc_rule_s fc_rule_t; /* {{{ */
+struct fc_rule_s
+{
+ char name[DATA_MAX_NAME_LEN];
+ fc_match_t *matches;
+ fc_target_t *targets;
+ fc_rule_t *next;
+}; /* }}} */
+
+/* List of chains, used for `chain_list_head' */
+struct fc_chain_s /* {{{ */
+{
+ char name[DATA_MAX_NAME_LEN];
+ fc_rule_t *rules;
+ fc_target_t *targets;
+ fc_chain_t *next;
+}; /* }}} */
+
+/*
+ * Global variables
+ */
+static fc_match_t *match_list_head;
+static fc_target_t *target_list_head;
+static fc_chain_t *chain_list_head;
+
+/*
+ * Private functions
+ */
+static void fc_free_matches (fc_match_t *m) /* {{{ */
+{
+ if (m == NULL)
+ return;
+
+ if (m->proc.destroy != NULL)
+ (*m->proc.destroy) (&m->user_data);
+ else if (m->user_data != NULL)
+ {
+ ERROR ("Filter subsystem: fc_free_matches: There is user data, but no "
+ "destroy functions has been specified. "
+ "Memory will probably be lost!");
+ }
+
+ if (m->next != NULL)
+ fc_free_matches (m->next);
+
+ free (m);
+} /* }}} void fc_free_matches */
+
+static void fc_free_targets (fc_target_t *t) /* {{{ */
+{
+ if (t == NULL)
+ return;
+
+ if (t->proc.destroy != NULL)
+ (*t->proc.destroy) (&t->user_data);
+ else if (t->user_data != NULL)
+ {
+ ERROR ("Filter subsystem: fc_free_targets: There is user data, but no "
+ "destroy functions has been specified. "
+ "Memory will probably be lost!");
+ }
+
+ if (t->next != NULL)
+ fc_free_targets (t->next);
+
+ free (t);
+} /* }}} void fc_free_targets */
+
+static void fc_free_rules (fc_rule_t *r) /* {{{ */
+{
+ if (r == NULL)
+ return;
+
+ fc_free_matches (r->matches);
+ fc_free_targets (r->targets);
+
+ if (r->next != NULL)
+ fc_free_rules (r->next);
+
+ free (r);
+} /* }}} void fc_free_rules */
+
+static void fc_free_chains (fc_chain_t *c) /* {{{ */
+{
+ if (c == NULL)
+ return;
+
+ fc_free_rules (c->rules);
+ fc_free_targets (c->targets);
+
+ if (c->next != NULL)
+ fc_free_chains (c->next);
+
+ free (c);
+} /* }}} void fc_free_chains */
+
+static char *fc_strdup (const char *orig) /* {{{ */
+{
+ size_t sz;
+ char *dest;
+
+ if (orig == NULL)
+ return (NULL);
+
+ sz = strlen (orig) + 1;
+ dest = (char *) malloc (sz);
+ if (dest == NULL)
+ return (NULL);
+
+ memcpy (dest, orig, sz);
+
+ return (dest);
+} /* }}} char *fc_strdup */
+
+/*
+ * Configuration.
+ *
+ * The configuration looks somewhat like this:
+ *
+ * <Chain "PreCache">
+ * <Rule>
+ * <Match "regex">
+ * Plugin "^mysql$"
+ * Type "^mysql_command$"
+ * TypeInstance "^show_"
+ * </Match>
+ * <Target "drop">
+ * </Target>
+ * </Rule>
+ *
+ * <Target "write">
+ * Plugin "rrdtool"
+ * </Target>
+ * </Chain>
+ */
+static int fc_config_add_match (fc_match_t **matches_head, /* {{{ */
+ oconfig_item_t *ci)
+{
+ fc_match_t *m;
+ fc_match_t *ptr;
+ int status;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("Filter subsystem: `Match' blocks require "
+ "exactly one string argument.");
+ return (-1);
+ }
+
+ ptr = match_list_head;
+ while (ptr != NULL)
+ {
+ if (strcasecmp (ptr->name, ci->values[0].value.string) == 0)
+ break;
+ ptr = ptr->next;
+ }
+
+ if (ptr == NULL)
+ {
+ WARNING ("Filter subsystem: Cannot find a \"%s\" match. "
+ "Did you load the appropriate plugin?",
+ ci->values[0].value.string);
+ return (-1);
+ }
+
+ m = (fc_match_t *) malloc (sizeof (*m));
+ if (m == NULL)
+ {
+ ERROR ("fc_config_add_match: malloc failed.");
+ return (-1);
+ }
+ memset (m, 0, sizeof (*m));
+
+ sstrncpy (m->name, ptr->name, sizeof (m->name));
+ memcpy (&m->proc, &ptr->proc, sizeof (m->proc));
+ m->user_data = NULL;
+ m->next = NULL;
+
+ if (m->proc.create != NULL)
+ {
+ status = (*m->proc.create) (ci, &m->user_data);
+ if (status != 0)
+ {
+ WARNING ("Filter subsystem: Failed to create a %s match.",
+ m->name);
+ fc_free_matches (m);
+ return (-1);
+ }
+ }
+
+ if (*matches_head != NULL)
+ {
+ ptr = *matches_head;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = m;
+ }
+ else
+ {
+ *matches_head = m;
+ }
+
+ return (0);
+} /* }}} int fc_config_add_match */
+
+static int fc_config_add_target (fc_target_t **targets_head, /* {{{ */
+ oconfig_item_t *ci)
+{
+ fc_target_t *t;
+ fc_target_t *ptr;
+ int status;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("Filter subsystem: `Target' blocks require "
+ "exactly one string argument.");
+ return (-1);
+ }
+
+ ptr = target_list_head;
+ while (ptr != NULL)
+ {
+ if (strcasecmp (ptr->name, ci->values[0].value.string) == 0)
+ break;
+ ptr = ptr->next;
+ }
+
+ if (ptr == NULL)
+ {
+ WARNING ("Filter subsystem: Cannot find a \"%s\" target. "
+ "Did you load the appropriate plugin?",
+ ci->values[0].value.string);
+ return (-1);
+ }
+
+ t = (fc_target_t *) malloc (sizeof (*t));
+ if (t == NULL)
+ {
+ ERROR ("fc_config_add_target: malloc failed.");
+ return (-1);
+ }
+ memset (t, 0, sizeof (*t));
+
+ sstrncpy (t->name, ptr->name, sizeof (t->name));
+ memcpy (&t->proc, &ptr->proc, sizeof (t->proc));
+ t->user_data = NULL;
+ t->next = NULL;
+
+ if (t->proc.create != NULL)
+ {
+ status = (*t->proc.create) (ci, &t->user_data);
+ if (status != 0)
+ {
+ WARNING ("Filter subsystem: Failed to create a %s target.",
+ t->name);
+ fc_free_targets (t);
+ return (-1);
+ }
+ }
+ else
+ {
+ t->user_data = NULL;
+ }
+
+ if (*targets_head != NULL)
+ {
+ ptr = *targets_head;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = t;
+ }
+ else
+ {
+ *targets_head = t;
+ }
+
+ return (0);
+} /* }}} int fc_config_add_target */
+
+static int fc_config_add_rule (fc_chain_t *chain, /* {{{ */
+ oconfig_item_t *ci)
+{
+ fc_rule_t *rule;
+ char rule_name[2*DATA_MAX_NAME_LEN] = "Unnamed rule";
+ int status = 0;
+ int i;
+
+ if (ci->values_num > 1)
+ {
+ WARNING ("Filter subsystem: `Rule' blocks have at most one argument.");
+ return (-1);
+ }
+ else if ((ci->values_num == 1)
+ && (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("Filter subsystem: `Rule' blocks expect one string argument "
+ "or no argument at all.");
+ return (-1);
+ }
+
+ rule = (fc_rule_t *) malloc (sizeof (*rule));
+ if (rule == NULL)
+ {
+ ERROR ("fc_config_add_rule: malloc failed.");
+ return (-1);
+ }
+ memset (rule, 0, sizeof (*rule));
+ rule->next = NULL;
+
+ if (ci->values_num == 1)
+ {
+ sstrncpy (rule->name, ci->values[0].value.string, sizeof (rule->name));
+ ssnprintf (rule_name, sizeof (rule_name), "Rule \"%s\"",
+ ci->values[0].value.string);
+ }
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *option = ci->children + i;
+ status = 0;
+
+ if (strcasecmp ("Match", option->key) == 0)
+ status = fc_config_add_match (&rule->matches, option);
+ else if (strcasecmp ("Target", option->key) == 0)
+ status = fc_config_add_target (&rule->targets, option);
+ else
+ {
+ WARNING ("Filter subsystem: %s: Option `%s' not allowed "
+ "inside a <Rule> block.", rule_name, option->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ } /* for (ci->children) */
+
+ /* Additional sanity checking. */
+ while (status == 0)
+ {
+ if (rule->targets == NULL)
+ {
+ WARNING ("Filter subsystem: %s: No target has been specified.",
+ rule_name);
+ status = -1;
+ break;
+ }
+
+ break;
+ } /* while (status == 0) */
+
+ if (status != 0)
+ {
+ fc_free_rules (rule);
+ return (-1);
+ }
+
+ if (chain->rules != NULL)
+ {
+ fc_rule_t *ptr;
+
+ ptr = chain->rules;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = rule;
+ }
+ else
+ {
+ chain->rules = rule;
+ }
+
+ return (0);
+} /* }}} int fc_config_add_rule */
+
+static int fc_config_add_chain (const oconfig_item_t *ci) /* {{{ */
+{
+ fc_chain_t *chain = NULL;
+ int status = 0;
+ int i;
+ int new_chain = 1;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("Filter subsystem: <Chain> blocks require exactly one "
+ "string argument.");
+ return (-1);
+ }
+
+ if (chain_list_head != NULL)
+ {
+ if ((chain = fc_chain_get_by_name (ci->values[0].value.string)) != NULL)
+ new_chain = 0;
+ }
+
+ if (chain == NULL)
+ {
+ chain = (fc_chain_t *) malloc (sizeof (*chain));
+ if (chain == NULL)
+ {
+ ERROR ("fc_config_add_chain: malloc failed.");
+ return (-1);
+ }
+ memset (chain, 0, sizeof (*chain));
+ sstrncpy (chain->name, ci->values[0].value.string, sizeof (chain->name));
+ chain->rules = NULL;
+ chain->targets = NULL;
+ chain->next = NULL;
+ }
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *option = ci->children + i;
+ status = 0;
+
+ if (strcasecmp ("Rule", option->key) == 0)
+ status = fc_config_add_rule (chain, option);
+ else if (strcasecmp ("Target", option->key) == 0)
+ status = fc_config_add_target (&chain->targets, option);
+ else
+ {
+ WARNING ("Filter subsystem: Chain %s: Option `%s' not allowed "
+ "inside a <Chain> block.", chain->name, option->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ } /* for (ci->children) */
+
+ if (status != 0)
+ {
+ fc_free_chains (chain);
+ return (-1);
+ }
+
+ if (chain_list_head != NULL)
+ {
+ if (!new_chain)
+ return (0);
+
+ fc_chain_t *ptr;
+
+ ptr = chain_list_head;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = chain;
+ }
+ else
+ {
+ chain_list_head = chain;
+ }
+
+ return (0);
+} /* }}} int fc_config_add_chain */
+
+/*
+ * Built-in target "jump"
+ *
+ * Prefix `bit' like `_b_uilt-_i_n _t_arget'
+ */
+static int fc_bit_jump_create (const oconfig_item_t *ci, /* {{{ */
+ void **user_data)
+{
+ oconfig_item_t *ci_chain;
+
+ if (ci->children_num != 1)
+ {
+ ERROR ("Filter subsystem: The built-in target `jump' needs exactly "
+ "one `Chain' argument!");
+ return (-1);
+ }
+
+ ci_chain = ci->children;
+ if (strcasecmp ("Chain", ci_chain->key) != 0)
+ {
+ ERROR ("Filter subsystem: The built-in target `jump' does not "
+ "support the configuration option `%s'.",
+ ci_chain->key);
+ return (-1);
+ }
+
+ if ((ci_chain->values_num != 1)
+ || (ci_chain->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ ERROR ("Filter subsystem: Built-in target `jump': The `Chain' option "
+ "needs exactly one string argument.");
+ return (-1);
+ }
+
+ *user_data = fc_strdup (ci_chain->values[0].value.string);
+ if (*user_data == NULL)
+ {
+ ERROR ("fc_bit_jump_create: fc_strdup failed.");
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int fc_bit_jump_create */
+
+static int fc_bit_jump_destroy (void **user_data) /* {{{ */
+{
+ if (user_data != NULL)
+ {
+ free (*user_data);
+ *user_data = NULL;
+ }
+
+ return (0);
+} /* }}} int fc_bit_jump_destroy */
+
+static int fc_bit_jump_invoke (const data_set_t *ds, /* {{{ */
+ value_list_t *vl, notification_meta_t __attribute__((unused)) **meta,
+ void **user_data)
+{
+ char *chain_name;
+ fc_chain_t *chain;
+ int status;
+
+ chain_name = *user_data;
+
+ for (chain = chain_list_head; chain != NULL; chain = chain->next)
+ if (strcasecmp (chain_name, chain->name) == 0)
+ break;
+
+ if (chain == NULL)
+ {
+ ERROR ("Filter subsystem: Built-in target `jump': There is no chain "
+ "named `%s'.", chain_name);
+ return (-1);
+ }
+
+ status = fc_process_chain (ds, vl, chain);
+ if (status < 0)
+ return (status);
+ else if (status == FC_TARGET_STOP)
+ return (FC_TARGET_STOP);
+ else
+ return (FC_TARGET_CONTINUE);
+} /* }}} int fc_bit_jump_invoke */
+
+static int fc_bit_stop_invoke (const data_set_t __attribute__((unused)) *ds, /* {{{ */
+ value_list_t __attribute__((unused)) *vl,
+ notification_meta_t __attribute__((unused)) **meta,
+ void __attribute__((unused)) **user_data)
+{
+ return (FC_TARGET_STOP);
+} /* }}} int fc_bit_stop_invoke */
+
+static int fc_bit_return_invoke (const data_set_t __attribute__((unused)) *ds, /* {{{ */
+ value_list_t __attribute__((unused)) *vl,
+ notification_meta_t __attribute__((unused)) **meta,
+ void __attribute__((unused)) **user_data)
+{
+ return (FC_TARGET_RETURN);
+} /* }}} int fc_bit_return_invoke */
+
+static int fc_bit_write_create (const oconfig_item_t *ci, /* {{{ */
+ void **user_data)
+{
+ int i;
+
+ char **plugin_list;
+ size_t plugin_list_len;
+
+ plugin_list = NULL;
+ plugin_list_len = 0;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+ char **temp;
+ int j;
+
+ if (strcasecmp ("Plugin", child->key) != 0)
+ {
+ ERROR ("Filter subsystem: The built-in target `write' does not "
+ "support the configuration option `%s'.",
+ child->key);
+ continue;
+ }
+
+ for (j = 0; j < child->values_num; j++)
+ {
+ if (child->values[j].type != OCONFIG_TYPE_STRING)
+ {
+ ERROR ("Filter subsystem: Built-in target `write': "
+ "The `Plugin' option accepts only string arguments.");
+ continue;
+ }
+
+ temp = (char **) realloc (plugin_list, (plugin_list_len + 2)
+ * (sizeof (*plugin_list)));
+ if (temp == NULL)
+ {
+ ERROR ("fc_bit_write_create: realloc failed.");
+ continue;
+ }
+ plugin_list = temp;
+
+ plugin_list[plugin_list_len] = fc_strdup (child->values[j].value.string);
+ if (plugin_list[plugin_list_len] == NULL)
+ {
+ ERROR ("fc_bit_write_create: fc_strdup failed.");
+ continue;
+ }
+ plugin_list_len++;
+ plugin_list[plugin_list_len] = NULL;
+ } /* for (j = 0; j < child->values_num; j++) */
+ } /* for (i = 0; i < ci->children_num; i++) */
+
+ *user_data = plugin_list;
+
+ return (0);
+} /* }}} int fc_bit_write_create */
+
+static int fc_bit_write_destroy (void **user_data) /* {{{ */
+{
+ char **plugin_list;
+ size_t i;
+
+ if ((user_data == NULL) || (*user_data == NULL))
+ return (0);
+
+ plugin_list = *user_data;
+
+ for (i = 0; plugin_list[i] != NULL; i++)
+ free (plugin_list[i]);
+ free (plugin_list);
+
+ return (0);
+} /* }}} int fc_bit_write_destroy */
+
+static int fc_bit_write_invoke (const data_set_t *ds, /* {{{ */
+ value_list_t *vl, notification_meta_t __attribute__((unused)) **meta,
+ void **user_data)
+{
+ char **plugin_list;
+ int status;
+
+ plugin_list = NULL;
+ if (user_data != NULL)
+ plugin_list = *user_data;
+
+ if ((plugin_list == NULL) || (plugin_list[0] == NULL))
+ {
+ static c_complain_t enoent_complaint = C_COMPLAIN_INIT_STATIC;
+
+ status = plugin_write (/* plugin = */ NULL, ds, vl);
+ if (status == ENOENT)
+ {
+ /* in most cases this is a permanent error, so use the complain
+ * mechanism rather than spamming the logs */
+ c_complain (LOG_INFO, &enoent_complaint,
+ "Filter subsystem: Built-in target `write': Dispatching value to "
+ "all write plugins failed with status %i (ENOENT). "
+ "Most likely this means you didn't load any write plugins.",
+ status);
+ }
+ else if (status != 0)
+ {
+ INFO ("Filter subsystem: Built-in target `write': Dispatching value to "
+ "all write plugins failed with status %i.", status);
+ }
+ else
+ {
+ assert (status == 0);
+ c_release (LOG_INFO, &enoent_complaint, "Filter subsystem: "
+ "Built-in target `write': Some write plugin is back to normal "
+ "operation. `write' succeeded.");
+ }
+ }
+ else
+ {
+ size_t i;
+
+ for (i = 0; plugin_list[i] != NULL; i++)
+ {
+ status = plugin_write (plugin_list[i], ds, vl);
+ if (status != 0)
+ {
+ INFO ("Filter subsystem: Built-in target `write': Dispatching value to "
+ "the `%s' plugin failed with status %i.", plugin_list[i], status);
+ }
+ } /* for (i = 0; plugin_list[i] != NULL; i++) */
+ }
+
+ return (FC_TARGET_CONTINUE);
+} /* }}} int fc_bit_write_invoke */
+
+static int fc_init_once (void) /* {{{ */
+{
+ static int done = 0;
+ target_proc_t tproc;
+
+ if (done != 0)
+ return (0);
+
+ memset (&tproc, 0, sizeof (tproc));
+ tproc.create = fc_bit_jump_create;
+ tproc.destroy = fc_bit_jump_destroy;
+ tproc.invoke = fc_bit_jump_invoke;
+ fc_register_target ("jump", tproc);
+
+ memset (&tproc, 0, sizeof (tproc));
+ tproc.create = NULL;
+ tproc.destroy = NULL;
+ tproc.invoke = fc_bit_stop_invoke;
+ fc_register_target ("stop", tproc);
+
+ memset (&tproc, 0, sizeof (tproc));
+ tproc.create = NULL;
+ tproc.destroy = NULL;
+ tproc.invoke = fc_bit_return_invoke;
+ fc_register_target ("return", tproc);
+
+ memset (&tproc, 0, sizeof (tproc));
+ tproc.create = fc_bit_write_create;
+ tproc.destroy = fc_bit_write_destroy;
+ tproc.invoke = fc_bit_write_invoke;
+ fc_register_target ("write", tproc);
+
+ done++;
+ return (0);
+} /* }}} int fc_init_once */
+
+/*
+ * Public functions
+ */
+/* Add a match to list of available matches. */
+int fc_register_match (const char *name, match_proc_t proc) /* {{{ */
+{
+ fc_match_t *m;
+
+ DEBUG ("fc_register_match (%s);", name);
+
+ m = (fc_match_t *) malloc (sizeof (*m));
+ if (m == NULL)
+ return (-ENOMEM);
+ memset (m, 0, sizeof (*m));
+
+ sstrncpy (m->name, name, sizeof (m->name));
+ memcpy (&m->proc, &proc, sizeof (m->proc));
+ m->next = NULL;
+
+ if (match_list_head == NULL)
+ {
+ match_list_head = m;
+ }
+ else
+ {
+ fc_match_t *ptr;
+
+ ptr = match_list_head;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = m;
+ }
+
+ return (0);
+} /* }}} int fc_register_match */
+
+/* Add a target to list of available targets. */
+int fc_register_target (const char *name, target_proc_t proc) /* {{{ */
+{
+ fc_target_t *t;
+
+ DEBUG ("fc_register_target (%s);", name);
+
+ t = (fc_target_t *) malloc (sizeof (*t));
+ if (t == NULL)
+ return (-ENOMEM);
+ memset (t, 0, sizeof (*t));
+
+ sstrncpy (t->name, name, sizeof (t->name));
+ memcpy (&t->proc, &proc, sizeof (t->proc));
+ t->next = NULL;
+
+ if (target_list_head == NULL)
+ {
+ target_list_head = t;
+ }
+ else
+ {
+ fc_target_t *ptr;
+
+ ptr = target_list_head;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = t;
+ }
+
+ return (0);
+} /* }}} int fc_register_target */
+
+fc_chain_t *fc_chain_get_by_name (const char *chain_name) /* {{{ */
+{
+ fc_chain_t *chain;
+
+ if (chain_name == NULL)
+ return (NULL);
+
+ for (chain = chain_list_head; chain != NULL; chain = chain->next)
+ if (strcasecmp (chain_name, chain->name) == 0)
+ return (chain);
+
+ return (NULL);
+} /* }}} int fc_chain_get_by_name */
+
+int fc_process_chain (const data_set_t *ds, value_list_t *vl, /* {{{ */
+ fc_chain_t *chain)
+{
+ fc_rule_t *rule;
+ fc_target_t *target;
+ int status;
+
+ if (chain == NULL)
+ return (-1);
+
+ DEBUG ("fc_process_chain (chain = %s);", chain->name);
+
+ status = FC_TARGET_CONTINUE;
+ for (rule = chain->rules; rule != NULL; rule = rule->next)
+ {
+ fc_match_t *match;
+
+ if (rule->name[0] != 0)
+ {
+ DEBUG ("fc_process_chain (%s): Testing the `%s' rule.",
+ chain->name, rule->name);
+ }
+
+ /* N. B.: rule->matches may be NULL. */
+ for (match = rule->matches; match != NULL; match = match->next)
+ {
+ /* FIXME: Pass the meta-data to match targets here (when implemented). */
+ status = (*match->proc.match) (ds, vl, /* meta = */ NULL,
+ &match->user_data);
+ if (status < 0)
+ {
+ WARNING ("fc_process_chain (%s): A match failed.", chain->name);
+ break;
+ }
+ else if (status != FC_MATCH_MATCHES)
+ break;
+ }
+
+ /* for-loop has been aborted: Either error or no match. */
+ if (match != NULL)
+ {
+ status = FC_TARGET_CONTINUE;
+ continue;
+ }
+
+ if (rule->name[0] != 0)
+ {
+ DEBUG ("fc_process_chain (%s): Rule `%s' matches.",
+ chain->name, rule->name);
+ }
+
+ for (target = rule->targets; target != NULL; target = target->next)
+ {
+ /* If we get here, all matches have matched the value. Execute the
+ * target. */
+ /* FIXME: Pass the meta-data to match targets here (when implemented). */
+ status = (*target->proc.invoke) (ds, vl, /* meta = */ NULL,
+ &target->user_data);
+ if (status < 0)
+ {
+ WARNING ("fc_process_chain (%s): A target failed.", chain->name);
+ continue;
+ }
+ else if (status == FC_TARGET_CONTINUE)
+ continue;
+ else if (status == FC_TARGET_STOP)
+ break;
+ else if (status == FC_TARGET_RETURN)
+ break;
+ else
+ {
+ WARNING ("fc_process_chain (%s): Unknown return value "
+ "from target `%s': %i",
+ chain->name, target->name, status);
+ }
+ }
+
+ if ((status == FC_TARGET_STOP)
+ || (status == FC_TARGET_RETURN))
+ {
+ if (rule->name[0] != 0)
+ {
+ DEBUG ("fc_process_chain (%s): Rule `%s' signaled "
+ "the %s condition.",
+ chain->name, rule->name,
+ (status == FC_TARGET_STOP) ? "stop" : "return");
+ }
+ break;
+ }
+ else
+ {
+ status = FC_TARGET_CONTINUE;
+ }
+ } /* for (rule) */
+
+ if (status == FC_TARGET_STOP)
+ return (FC_TARGET_STOP);
+ else if (status == FC_TARGET_RETURN)
+ return (FC_TARGET_CONTINUE);
+
+ /* for-loop has been aborted: A target returned `FC_TARGET_STOP' */
+ if (rule != NULL)
+ return (FC_TARGET_CONTINUE);
+
+ DEBUG ("fc_process_chain (%s): Executing the default targets.",
+ chain->name);
+
+ status = FC_TARGET_CONTINUE;
+ for (target = chain->targets; target != NULL; target = target->next)
+ {
+ /* If we get here, all matches have matched the value. Execute the
+ * target. */
+ /* FIXME: Pass the meta-data to match targets here (when implemented). */
+ status = (*target->proc.invoke) (ds, vl, /* meta = */ NULL,
+ &target->user_data);
+ if (status < 0)
+ {
+ WARNING ("fc_process_chain (%s): The default target failed.",
+ chain->name);
+ }
+ else if (status == FC_TARGET_CONTINUE)
+ continue;
+ else if (status == FC_TARGET_STOP)
+ break;
+ else if (status == FC_TARGET_RETURN)
+ break;
+ else
+ {
+ WARNING ("fc_process_chain (%s): Unknown return value "
+ "from target `%s': %i",
+ chain->name, target->name, status);
+ }
+ }
+
+ if ((status == FC_TARGET_STOP)
+ || (status == FC_TARGET_RETURN))
+ {
+ assert (target != NULL);
+ DEBUG ("fc_process_chain (%s): Default target `%s' signaled "
+ "the %s condition.",
+ chain->name, target->name,
+ (status == FC_TARGET_STOP) ? "stop" : "return");
+ if (status == FC_TARGET_STOP)
+ return (FC_TARGET_STOP);
+ else
+ return (FC_TARGET_CONTINUE);
+ }
+
+ DEBUG ("fc_process_chain (%s): Signaling `continue' at end of chain.",
+ chain->name);
+
+ return (FC_TARGET_CONTINUE);
+} /* }}} int fc_process_chain */
+
+/* Iterate over all rules in the chain and execute all targets for which all
+ * matches match. */
+int fc_default_action (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+ /* FIXME: Pass the meta-data to match targets here (when implemented). */
+ return (fc_bit_write_invoke (ds, vl,
+ /* meta = */ NULL, /* user_data = */ NULL));
+} /* }}} int fc_default_action */
+
+int fc_configure (const oconfig_item_t *ci) /* {{{ */
+{
+ fc_init_once ();
+
+ if (ci == NULL)
+ return (-EINVAL);
+
+ if (strcasecmp ("Chain", ci->key) == 0)
+ return (fc_config_add_chain (ci));
+
+ WARNING ("Filter subsystem: Unknown top level config option `%s'.",
+ ci->key);
+
+ return (-1);
+} /* }}} int fc_configure */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/daemon/filter_chain.h b/src/daemon/filter_chain.h
--- /dev/null
@@ -0,0 +1,106 @@
+/**
+ * collectd - src/filter_chain.h
+ * Copyright (C) 2008,2009 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#ifndef FILTER_CHAIN_H
+#define FILTER_CHAIN_H 1
+
+#include "collectd.h"
+#include "plugin.h"
+
+#define FC_MATCH_NO_MATCH 0
+#define FC_MATCH_MATCHES 1
+
+#define FC_TARGET_CONTINUE 0
+#define FC_TARGET_STOP 1
+#define FC_TARGET_RETURN 2
+
+/*
+ * Match functions
+ */
+struct match_proc_s
+{
+ int (*create) (const oconfig_item_t *ci, void **user_data);
+ int (*destroy) (void **user_data);
+ int (*match) (const data_set_t *ds, const value_list_t *vl,
+ notification_meta_t **meta, void **user_data);
+};
+typedef struct match_proc_s match_proc_t;
+
+int fc_register_match (const char *name, match_proc_t proc);
+
+/*
+ * Target functions
+ */
+struct target_proc_s
+{
+ int (*create) (const oconfig_item_t *ci, void **user_data);
+ int (*destroy) (void **user_data);
+ int (*invoke) (const data_set_t *ds, value_list_t *vl,
+ notification_meta_t **meta, void **user_data);
+};
+typedef struct target_proc_s target_proc_t;
+
+struct fc_chain_s;
+typedef struct fc_chain_s fc_chain_t;
+
+int fc_register_target (const char *name, target_proc_t proc);
+
+/*
+ * TODO: Chain management
+ */
+#if 0
+int fc_chain_add (const char *chain_name,
+ const char *target_name, int target_argc, char **target_argv);
+int fc_chain_delete (const char *chain_name);
+#endif
+
+/*
+ * TODO: Rule management
+ */
+#if 0
+int fc_rule_add (const char *chain_name, int position,
+ int match_num, const char **match_name, int *match_argc, char ***match_argv,
+ const char *target_name, int target_argc, char **target_argv);
+int fc_rule_delete (const char *chain_name, int position);
+#endif
+
+/*
+ * Processing function
+ */
+fc_chain_t *fc_chain_get_by_name (const char *chain_name);
+
+int fc_process_chain (const data_set_t *ds, value_list_t *vl,
+ fc_chain_t *chain);
+
+int fc_default_action (const data_set_t *ds, value_list_t *vl);
+
+/*
+ * Shortcut for global configuration
+ */
+int fc_configure (const oconfig_item_t *ci);
+
+#endif /* FILTER_CHAIN_H */
+/* vim: set sw=2 sts=2 et : */
diff --git a/src/daemon/meta_data.c b/src/daemon/meta_data.c
--- /dev/null
+++ b/src/daemon/meta_data.c
@@ -0,0 +1,637 @@
+/**
+ * collectd - src/meta_data.c
+ * Copyright (C) 2008-2011 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "meta_data.h"
+
+#include <pthread.h>
+
+/*
+ * Data types
+ */
+union meta_value_u
+{
+ char *mv_string;
+ int64_t mv_signed_int;
+ uint64_t mv_unsigned_int;
+ double mv_double;
+ _Bool mv_boolean;
+};
+typedef union meta_value_u meta_value_t;
+
+struct meta_entry_s;
+typedef struct meta_entry_s meta_entry_t;
+struct meta_entry_s
+{
+ char *key;
+ meta_value_t value;
+ int type;
+ meta_entry_t *next;
+};
+
+struct meta_data_s
+{
+ meta_entry_t *head;
+ pthread_mutex_t lock;
+};
+
+/*
+ * Private functions
+ */
+static char *md_strdup (const char *orig) /* {{{ */
+{
+ size_t sz;
+ char *dest;
+
+ if (orig == NULL)
+ return (NULL);
+
+ sz = strlen (orig) + 1;
+ dest = (char *) malloc (sz);
+ if (dest == NULL)
+ return (NULL);
+
+ memcpy (dest, orig, sz);
+
+ return (dest);
+} /* }}} char *md_strdup */
+
+static meta_entry_t *md_entry_alloc (const char *key) /* {{{ */
+{
+ meta_entry_t *e;
+
+ e = (meta_entry_t *) malloc (sizeof (*e));
+ if (e == NULL)
+ {
+ ERROR ("md_entry_alloc: malloc failed.");
+ return (NULL);
+ }
+ memset (e, 0, sizeof (*e));
+
+ e->key = md_strdup (key);
+ if (e->key == NULL)
+ {
+ free (e);
+ ERROR ("md_entry_alloc: md_strdup failed.");
+ return (NULL);
+ }
+
+ e->type = 0;
+ e->next = NULL;
+
+ return (e);
+} /* }}} meta_entry_t *md_entry_alloc */
+
+static meta_entry_t *md_entry_clone (const meta_entry_t *orig) /* {{{ */
+{
+ meta_entry_t *copy;
+
+ if (orig == NULL)
+ return (NULL);
+
+ copy = md_entry_alloc (orig->key);
+ copy->type = orig->type;
+ if (copy->type == MD_TYPE_STRING)
+ copy->value.mv_string = strdup (orig->value.mv_string);
+ else
+ copy->value = orig->value;
+
+ copy->next = md_entry_clone (orig->next);
+ return (copy);
+} /* }}} meta_entry_t *md_entry_clone */
+
+static void md_entry_free (meta_entry_t *e) /* {{{ */
+{
+ if (e == NULL)
+ return;
+
+ free (e->key);
+
+ if (e->type == MD_TYPE_STRING)
+ free (e->value.mv_string);
+
+ if (e->next != NULL)
+ md_entry_free (e->next);
+
+ free (e);
+} /* }}} void md_entry_free */
+
+static int md_entry_insert (meta_data_t *md, meta_entry_t *e) /* {{{ */
+{
+ meta_entry_t *this;
+ meta_entry_t *prev;
+
+ if ((md == NULL) || (e == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ prev = NULL;
+ this = md->head;
+ while (this != NULL)
+ {
+ if (strcasecmp (e->key, this->key) == 0)
+ break;
+
+ prev = this;
+ this = this->next;
+ }
+
+ if (this == NULL)
+ {
+ /* This key does not exist yet. */
+ if (md->head == NULL)
+ md->head = e;
+ else
+ {
+ assert (prev != NULL);
+ prev->next = e;
+ }
+
+ e->next = NULL;
+ }
+ else /* (this != NULL) */
+ {
+ if (prev == NULL)
+ md->head = e;
+ else
+ prev->next = e;
+
+ e->next = this->next;
+ }
+
+ pthread_mutex_unlock (&md->lock);
+
+ if (this != NULL)
+ {
+ this->next = NULL;
+ md_entry_free (this);
+ }
+
+ return (0);
+} /* }}} int md_entry_insert */
+
+/* XXX: The lock on md must be held while calling this function! */
+static meta_entry_t *md_entry_lookup (meta_data_t *md, /* {{{ */
+ const char *key)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL))
+ return (NULL);
+
+ for (e = md->head; e != NULL; e = e->next)
+ if (strcasecmp (key, e->key) == 0)
+ break;
+
+ return (e);
+} /* }}} meta_entry_t *md_entry_lookup */
+
+/*
+ * Public functions
+ */
+meta_data_t *meta_data_create (void) /* {{{ */
+{
+ meta_data_t *md;
+
+ md = (meta_data_t *) malloc (sizeof (*md));
+ if (md == NULL)
+ {
+ ERROR ("meta_data_create: malloc failed.");
+ return (NULL);
+ }
+ memset (md, 0, sizeof (*md));
+
+ md->head = NULL;
+ pthread_mutex_init (&md->lock, /* attr = */ NULL);
+
+ return (md);
+} /* }}} meta_data_t *meta_data_create */
+
+meta_data_t *meta_data_clone (meta_data_t *orig) /* {{{ */
+{
+ meta_data_t *copy;
+
+ if (orig == NULL)
+ return (NULL);
+
+ copy = meta_data_create ();
+ if (copy == NULL)
+ return (NULL);
+
+ pthread_mutex_lock (&orig->lock);
+ copy->head = md_entry_clone (orig->head);
+ pthread_mutex_unlock (&orig->lock);
+
+ return (copy);
+} /* }}} meta_data_t *meta_data_clone */
+
+void meta_data_destroy (meta_data_t *md) /* {{{ */
+{
+ if (md == NULL)
+ return;
+
+ pthread_mutex_destroy(&md->lock);
+ md_entry_free (md->head);
+ pthread_mutex_destroy (&md->lock);
+ free (md);
+} /* }}} void meta_data_destroy */
+
+int meta_data_exists (meta_data_t *md, const char *key) /* {{{ */
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ for (e = md->head; e != NULL; e = e->next)
+ {
+ if (strcasecmp (key, e->key) == 0)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return (1);
+ }
+ }
+
+ pthread_mutex_unlock (&md->lock);
+ return (0);
+} /* }}} int meta_data_exists */
+
+int meta_data_type (meta_data_t *md, const char *key) /* {{{ */
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL))
+ return -EINVAL;
+
+ pthread_mutex_lock (&md->lock);
+
+ for (e = md->head; e != NULL; e = e->next)
+ {
+ if (strcasecmp (key, e->key) == 0)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return e->type;
+ }
+ }
+
+ pthread_mutex_unlock (&md->lock);
+ return 0;
+} /* }}} int meta_data_type */
+
+int meta_data_toc (meta_data_t *md, char ***toc) /* {{{ */
+{
+ int i = 0, count = 0;
+ meta_entry_t *e;
+
+ if ((md == NULL) || (toc == NULL))
+ return -EINVAL;
+
+ pthread_mutex_lock (&md->lock);
+
+ for (e = md->head; e != NULL; e = e->next)
+ ++count;
+
+ if (count == 0)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return (count);
+ }
+
+ *toc = calloc(count, sizeof(**toc));
+ for (e = md->head; e != NULL; e = e->next)
+ (*toc)[i++] = strdup(e->key);
+
+ pthread_mutex_unlock (&md->lock);
+ return count;
+} /* }}} int meta_data_toc */
+
+int meta_data_delete (meta_data_t *md, const char *key) /* {{{ */
+{
+ meta_entry_t *this;
+ meta_entry_t *prev;
+
+ if ((md == NULL) || (key == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ prev = NULL;
+ this = md->head;
+ while (this != NULL)
+ {
+ if (strcasecmp (key, this->key) == 0)
+ break;
+
+ prev = this;
+ this = this->next;
+ }
+
+ if (this == NULL)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ if (prev == NULL)
+ md->head = this->next;
+ else
+ prev->next = this->next;
+
+ pthread_mutex_unlock (&md->lock);
+
+ this->next = NULL;
+ md_entry_free (this);
+
+ return (0);
+} /* }}} int meta_data_delete */
+
+/*
+ * Add functions
+ */
+int meta_data_add_string (meta_data_t *md, /* {{{ */
+ const char *key, const char *value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL) || (value == NULL))
+ return (-EINVAL);
+
+ e = md_entry_alloc (key);
+ if (e == NULL)
+ return (-ENOMEM);
+
+ e->value.mv_string = md_strdup (value);
+ if (e->value.mv_string == NULL)
+ {
+ ERROR ("meta_data_add_string: md_strdup failed.");
+ md_entry_free (e);
+ return (-ENOMEM);
+ }
+ e->type = MD_TYPE_STRING;
+
+ return (md_entry_insert (md, e));
+} /* }}} int meta_data_add_string */
+
+int meta_data_add_signed_int (meta_data_t *md, /* {{{ */
+ const char *key, int64_t value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL))
+ return (-EINVAL);
+
+ e = md_entry_alloc (key);
+ if (e == NULL)
+ return (-ENOMEM);
+
+ e->value.mv_signed_int = value;
+ e->type = MD_TYPE_SIGNED_INT;
+
+ return (md_entry_insert (md, e));
+} /* }}} int meta_data_add_signed_int */
+
+int meta_data_add_unsigned_int (meta_data_t *md, /* {{{ */
+ const char *key, uint64_t value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL))
+ return (-EINVAL);
+
+ e = md_entry_alloc (key);
+ if (e == NULL)
+ return (-ENOMEM);
+
+ e->value.mv_unsigned_int = value;
+ e->type = MD_TYPE_UNSIGNED_INT;
+
+ return (md_entry_insert (md, e));
+} /* }}} int meta_data_add_unsigned_int */
+
+int meta_data_add_double (meta_data_t *md, /* {{{ */
+ const char *key, double value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL))
+ return (-EINVAL);
+
+ e = md_entry_alloc (key);
+ if (e == NULL)
+ return (-ENOMEM);
+
+ e->value.mv_double = value;
+ e->type = MD_TYPE_DOUBLE;
+
+ return (md_entry_insert (md, e));
+} /* }}} int meta_data_add_double */
+
+int meta_data_add_boolean (meta_data_t *md, /* {{{ */
+ const char *key, _Bool value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL))
+ return (-EINVAL);
+
+ e = md_entry_alloc (key);
+ if (e == NULL)
+ return (-ENOMEM);
+
+ e->value.mv_boolean = value;
+ e->type = MD_TYPE_BOOLEAN;
+
+ return (md_entry_insert (md, e));
+} /* }}} int meta_data_add_boolean */
+
+/*
+ * Get functions
+ */
+int meta_data_get_string (meta_data_t *md, /* {{{ */
+ const char *key, char **value)
+{
+ meta_entry_t *e;
+ char *temp;
+
+ if ((md == NULL) || (key == NULL) || (value == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ e = md_entry_lookup (md, key);
+ if (e == NULL)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ if (e->type != MD_TYPE_STRING)
+ {
+ ERROR ("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ temp = md_strdup (e->value.mv_string);
+ if (temp == NULL)
+ {
+ pthread_mutex_unlock (&md->lock);
+ ERROR ("meta_data_get_string: md_strdup failed.");
+ return (-ENOMEM);
+ }
+
+ pthread_mutex_unlock (&md->lock);
+
+ *value = temp;
+
+ return (0);
+} /* }}} int meta_data_get_string */
+
+int meta_data_get_signed_int (meta_data_t *md, /* {{{ */
+ const char *key, int64_t *value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL) || (value == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ e = md_entry_lookup (md, key);
+ if (e == NULL)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ if (e->type != MD_TYPE_SIGNED_INT)
+ {
+ ERROR ("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ *value = e->value.mv_signed_int;
+
+ pthread_mutex_unlock (&md->lock);
+ return (0);
+} /* }}} int meta_data_get_signed_int */
+
+int meta_data_get_unsigned_int (meta_data_t *md, /* {{{ */
+ const char *key, uint64_t *value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL) || (value == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ e = md_entry_lookup (md, key);
+ if (e == NULL)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ if (e->type != MD_TYPE_UNSIGNED_INT)
+ {
+ ERROR ("meta_data_get_unsigned_int: Type mismatch for key `%s'", e->key);
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ *value = e->value.mv_unsigned_int;
+
+ pthread_mutex_unlock (&md->lock);
+ return (0);
+} /* }}} int meta_data_get_unsigned_int */
+
+int meta_data_get_double (meta_data_t *md, /* {{{ */
+ const char *key, double *value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL) || (value == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ e = md_entry_lookup (md, key);
+ if (e == NULL)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ if (e->type != MD_TYPE_DOUBLE)
+ {
+ ERROR ("meta_data_get_double: Type mismatch for key `%s'", e->key);
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ *value = e->value.mv_double;
+
+ pthread_mutex_unlock (&md->lock);
+ return (0);
+} /* }}} int meta_data_get_double */
+
+int meta_data_get_boolean (meta_data_t *md, /* {{{ */
+ const char *key, _Bool *value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL) || (value == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ e = md_entry_lookup (md, key);
+ if (e == NULL)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ if (e->type != MD_TYPE_BOOLEAN)
+ {
+ ERROR ("meta_data_get_boolean: Type mismatch for key `%s'", e->key);
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ *value = e->value.mv_boolean;
+
+ pthread_mutex_unlock (&md->lock);
+ return (0);
+} /* }}} int meta_data_get_boolean */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/daemon/meta_data.h b/src/daemon/meta_data.h
--- /dev/null
+++ b/src/daemon/meta_data.h
@@ -0,0 +1,86 @@
+/**
+ * collectd - src/meta_data.h
+ * Copyright (C) 2008-2011 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#ifndef META_DATA_H
+#define META_DATA_H
+
+#include "collectd.h"
+
+/*
+ * Defines
+ */
+#define MD_TYPE_STRING 1
+#define MD_TYPE_SIGNED_INT 2
+#define MD_TYPE_UNSIGNED_INT 3
+#define MD_TYPE_DOUBLE 4
+#define MD_TYPE_BOOLEAN 5
+
+struct meta_data_s;
+typedef struct meta_data_s meta_data_t;
+
+meta_data_t *meta_data_create (void);
+meta_data_t *meta_data_clone (meta_data_t *orig);
+void meta_data_destroy (meta_data_t *md);
+
+int meta_data_exists (meta_data_t *md, const char *key);
+int meta_data_type (meta_data_t *md, const char *key);
+int meta_data_toc (meta_data_t *md, char ***toc);
+int meta_data_delete (meta_data_t *md, const char *key);
+
+int meta_data_add_string (meta_data_t *md,
+ const char *key,
+ const char *value);
+int meta_data_add_signed_int (meta_data_t *md,
+ const char *key,
+ int64_t value);
+int meta_data_add_unsigned_int (meta_data_t *md,
+ const char *key,
+ uint64_t value);
+int meta_data_add_double (meta_data_t *md,
+ const char *key,
+ double value);
+int meta_data_add_boolean (meta_data_t *md,
+ const char *key,
+ _Bool value);
+
+int meta_data_get_string (meta_data_t *md,
+ const char *key,
+ char **value);
+int meta_data_get_signed_int (meta_data_t *md,
+ const char *key,
+ int64_t *value);
+int meta_data_get_unsigned_int (meta_data_t *md,
+ const char *key,
+ uint64_t *value);
+int meta_data_get_double (meta_data_t *md,
+ const char *key,
+ double *value);
+int meta_data_get_boolean (meta_data_t *md,
+ const char *key,
+ _Bool *value);
+
+#endif /* META_DATA_H */
+/* vim: set sw=2 sts=2 et : */
diff --git a/src/daemon/plugin.c b/src/daemon/plugin.c
--- /dev/null
+++ b/src/daemon/plugin.c
@@ -0,0 +1,2656 @@
+/**
+ * collectd - src/plugin.c
+ * Copyright (C) 2005-2014 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ * Sebastian Harl <sh at tokkee.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+#include "filter_chain.h"
+#include "utils_avltree.h"
+#include "utils_cache.h"
+#include "utils_complain.h"
+#include "utils_llist.h"
+#include "utils_heap.h"
+#include "utils_time.h"
+#include "utils_random.h"
+
+#if HAVE_PTHREAD_H
+# include <pthread.h>
+#endif
+
+#include <ltdl.h>
+
+/*
+ * Private structures
+ */
+struct callback_func_s
+{
+ void *cf_callback;
+ user_data_t cf_udata;
+ plugin_ctx_t cf_ctx;
+};
+typedef struct callback_func_s callback_func_t;
+
+#define RF_SIMPLE 0
+#define RF_COMPLEX 1
+#define RF_REMOVE 65535
+struct read_func_s
+{
+ /* `read_func_t' "inherits" from `callback_func_t'.
+ * The `rf_super' member MUST be the first one in this structure! */
+#define rf_callback rf_super.cf_callback
+#define rf_udata rf_super.cf_udata
+#define rf_ctx rf_super.cf_ctx
+ callback_func_t rf_super;
+ char rf_group[DATA_MAX_NAME_LEN];
+ char *rf_name;
+ int rf_type;
+ cdtime_t rf_interval;
+ cdtime_t rf_effective_interval;
+ cdtime_t rf_next_read;
+};
+typedef struct read_func_s read_func_t;
+
+struct write_queue_s;
+typedef struct write_queue_s write_queue_t;
+struct write_queue_s
+{
+ value_list_t *vl;
+ plugin_ctx_t ctx;
+ write_queue_t *next;
+};
+
+/*
+ * Private variables
+ */
+static c_avl_tree_t *plugins_loaded = NULL;
+
+static llist_t *list_init;
+static llist_t *list_write;
+static llist_t *list_flush;
+static llist_t *list_missing;
+static llist_t *list_shutdown;
+static llist_t *list_log;
+static llist_t *list_notification;
+
+static fc_chain_t *pre_cache_chain = NULL;
+static fc_chain_t *post_cache_chain = NULL;
+
+static c_avl_tree_t *data_sets;
+
+static char *plugindir = NULL;
+
+#ifndef DEFAULT_MAX_READ_INTERVAL
+# define DEFAULT_MAX_READ_INTERVAL TIME_T_TO_CDTIME_T (86400)
+#endif
+static c_heap_t *read_heap = NULL;
+static llist_t *read_list;
+static int read_loop = 1;
+static pthread_mutex_t read_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t read_cond = PTHREAD_COND_INITIALIZER;
+static pthread_t *read_threads = NULL;
+static int read_threads_num = 0;
+static cdtime_t max_read_interval = DEFAULT_MAX_READ_INTERVAL;
+
+static write_queue_t *write_queue_head;
+static write_queue_t *write_queue_tail;
+static long write_queue_length = 0;
+static _Bool write_loop = 1;
+static pthread_mutex_t write_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t write_cond = PTHREAD_COND_INITIALIZER;
+static pthread_t *write_threads = NULL;
+static size_t write_threads_num = 0;
+
+static pthread_key_t plugin_ctx_key;
+static _Bool plugin_ctx_key_initialized = 0;
+
+static long write_limit_high = 0;
+static long write_limit_low = 0;
+
+static derive_t stats_values_dropped = 0;
+static _Bool record_statistics = 0;
+
+/*
+ * Static functions
+ */
+static int plugin_dispatch_values_internal (value_list_t *vl);
+
+static const char *plugin_get_dir (void)
+{
+ if (plugindir == NULL)
+ return (PLUGINDIR);
+ else
+ return (plugindir);
+}
+
+static void plugin_update_internal_statistics (void) { /* {{{ */
+ derive_t copy_write_queue_length;
+ value_list_t vl = VALUE_LIST_INIT;
+ value_t values[2];
+
+ copy_write_queue_length = write_queue_length;
+
+ /* Initialize `vl' */
+ vl.values = values;
+ vl.values_len = 2;
+ vl.time = 0;
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "collectd", sizeof (vl.plugin));
+
+ vl.type_instance[0] = 0;
+ vl.values_len = 1;
+
+ /* Write queue */
+ sstrncpy (vl.plugin_instance, "write_queue",
+ sizeof (vl.plugin_instance));
+
+ /* Write queue : queue length */
+ vl.values[0].gauge = (gauge_t) copy_write_queue_length;
+ sstrncpy (vl.type, "queue_length", sizeof (vl.type));
+ vl.type_instance[0] = 0;
+ plugin_dispatch_values (&vl);
+
+ /* Write queue : Values dropped (queue length > low limit) */
+ vl.values[0].derive = (derive_t) stats_values_dropped;
+ sstrncpy (vl.type, "derive", sizeof (vl.type));
+ sstrncpy (vl.type_instance, "dropped", sizeof (vl.type_instance));
+ plugin_dispatch_values (&vl);
+
+ /* Cache */
+ sstrncpy (vl.plugin_instance, "cache",
+ sizeof (vl.plugin_instance));
+
+ /* Cache : Nb entry in cache tree */
+ vl.values[0].gauge = (gauge_t) uc_get_size();
+ sstrncpy (vl.type, "cache_size", sizeof (vl.type));
+ vl.type_instance[0] = 0;
+ plugin_dispatch_values (&vl);
+
+ return;
+} /* }}} void plugin_update_internal_statistics */
+
+static void destroy_callback (callback_func_t *cf) /* {{{ */
+{
+ if (cf == NULL)
+ return;
+
+ if ((cf->cf_udata.data != NULL) && (cf->cf_udata.free_func != NULL))
+ {
+ cf->cf_udata.free_func (cf->cf_udata.data);
+ cf->cf_udata.data = NULL;
+ cf->cf_udata.free_func = NULL;
+ }
+ sfree (cf);
+} /* }}} void destroy_callback */
+
+static void destroy_all_callbacks (llist_t **list) /* {{{ */
+{
+ llentry_t *le;
+
+ if (*list == NULL)
+ return;
+
+ le = llist_head (*list);
+ while (le != NULL)
+ {
+ llentry_t *le_next;
+
+ le_next = le->next;
+
+ sfree (le->key);
+ destroy_callback (le->value);
+ le->value = NULL;
+
+ le = le_next;
+ }
+
+ llist_destroy (*list);
+ *list = NULL;
+} /* }}} void destroy_all_callbacks */
+
+static void destroy_read_heap (void) /* {{{ */
+{
+ if (read_heap == NULL)
+ return;
+
+ while (42)
+ {
+ callback_func_t *cf;
+
+ cf = c_heap_get_root (read_heap);
+ if (cf == NULL)
+ break;
+
+ destroy_callback (cf);
+ }
+
+ c_heap_destroy (read_heap);
+ read_heap = NULL;
+} /* }}} void destroy_read_heap */
+
+static int register_callback (llist_t **list, /* {{{ */
+ const char *name, callback_func_t *cf)
+{
+ llentry_t *le;
+ char *key;
+
+ if (*list == NULL)
+ {
+ *list = llist_create ();
+ if (*list == NULL)
+ {
+ ERROR ("plugin: register_callback: "
+ "llist_create failed.");
+ destroy_callback (cf);
+ return (-1);
+ }
+ }
+
+ key = strdup (name);
+ if (key == NULL)
+ {
+ ERROR ("plugin: register_callback: strdup failed.");
+ destroy_callback (cf);
+ return (-1);
+ }
+
+ le = llist_search (*list, name);
+ if (le == NULL)
+ {
+ le = llentry_create (key, cf);
+ if (le == NULL)
+ {
+ ERROR ("plugin: register_callback: "
+ "llentry_create failed.");
+ free (key);
+ destroy_callback (cf);
+ return (-1);
+ }
+
+ llist_append (*list, le);
+ }
+ else
+ {
+ callback_func_t *old_cf;
+
+ old_cf = le->value;
+ le->value = cf;
+
+ WARNING ("plugin: register_callback: "
+ "a callback named `%s' already exists - "
+ "overwriting the old entry!", name);
+
+ destroy_callback (old_cf);
+ sfree (key);
+ }
+
+ return (0);
+} /* }}} int register_callback */
+
+static int create_register_callback (llist_t **list, /* {{{ */
+ const char *name, void *callback, user_data_t *ud)
+{
+ callback_func_t *cf;
+
+ cf = (callback_func_t *) malloc (sizeof (*cf));
+ if (cf == NULL)
+ {
+ ERROR ("plugin: create_register_callback: malloc failed.");
+ return (-1);
+ }
+ memset (cf, 0, sizeof (*cf));
+
+ cf->cf_callback = callback;
+ if (ud == NULL)
+ {
+ cf->cf_udata.data = NULL;
+ cf->cf_udata.free_func = NULL;
+ }
+ else
+ {
+ cf->cf_udata = *ud;
+ }
+
+ cf->cf_ctx = plugin_get_ctx ();
+
+ return (register_callback (list, name, cf));
+} /* }}} int create_register_callback */
+
+static int plugin_unregister (llist_t *list, const char *name) /* {{{ */
+{
+ llentry_t *e;
+
+ if (list == NULL)
+ return (-1);
+
+ e = llist_search (list, name);
+ if (e == NULL)
+ return (-1);
+
+ llist_remove (list, e);
+
+ sfree (e->key);
+ destroy_callback (e->value);
+
+ llentry_destroy (e);
+
+ return (0);
+} /* }}} int plugin_unregister */
+
+/*
+ * (Try to) load the shared object `file'. Won't complain if it isn't a shared
+ * object, but it will bitch about a shared object not having a
+ * ``module_register'' symbol..
+ */
+static int plugin_load_file (char *file, uint32_t flags)
+{
+ lt_dlhandle dlh;
+ void (*reg_handle) (void);
+
+ lt_dlinit ();
+ lt_dlerror (); /* clear errors */
+
+#if LIBTOOL_VERSION == 2
+ if (flags & PLUGIN_FLAGS_GLOBAL) {
+ lt_dladvise advise;
+ lt_dladvise_init(&advise);
+ lt_dladvise_global(&advise);
+ dlh = lt_dlopenadvise(file, advise);
+ lt_dladvise_destroy(&advise);
+ } else {
+ dlh = lt_dlopen (file);
+ }
+#else /* if LIBTOOL_VERSION == 1 */
+ if (flags & PLUGIN_FLAGS_GLOBAL)
+ WARNING ("plugin_load_file: The global flag is not supported, "
+ "libtool 2 is required for this.");
+ dlh = lt_dlopen (file);
+#endif
+
+ if (dlh == NULL)
+ {
+ char errbuf[1024] = "";
+
+ ssnprintf (errbuf, sizeof (errbuf),
+ "lt_dlopen (\"%s\") failed: %s. "
+ "The most common cause for this problem are "
+ "missing dependencies. Use ldd(1) to check "
+ "the dependencies of the plugin "
+ "/ shared object.",
+ file, lt_dlerror ());
+
+ ERROR ("%s", errbuf);
+ /* Make sure this is printed to STDERR in any case, but also
+ * make sure it's printed only once. */
+ if (list_log != NULL)
+ fprintf (stderr, "ERROR: %s\n", errbuf);
+
+ return (1);
+ }
+
+ if ((reg_handle = (void (*) (void)) lt_dlsym (dlh, "module_register")) == NULL)
+ {
+ WARNING ("Couldn't find symbol \"module_register\" in \"%s\": %s\n",
+ file, lt_dlerror ());
+ lt_dlclose (dlh);
+ return (-1);
+ }
+
+ (*reg_handle) ();
+
+ return (0);
+}
+
+static void *plugin_read_thread (void __attribute__((unused)) *args)
+{
+ while (read_loop != 0)
+ {
+ read_func_t *rf;
+ plugin_ctx_t old_ctx;
+ cdtime_t now;
+ int status;
+ int rf_type;
+ int rc;
+
+ /* Get the read function that needs to be read next.
+ * We don't need to hold "read_lock" for the heap, but we need
+ * to call c_heap_get_root() and pthread_cond_wait() in the
+ * same protected block. */
+ pthread_mutex_lock (&read_lock);
+ rf = c_heap_get_root (read_heap);
+ if (rf == NULL)
+ {
+ pthread_cond_wait (&read_cond, &read_lock);
+ pthread_mutex_unlock (&read_lock);
+ continue;
+ }
+ pthread_mutex_unlock (&read_lock);
+
+ if (rf->rf_interval == 0)
+ {
+ /* this should not happen, because the interval is set
+ * for each plugin when loading it
+ * XXX: issue a warning? */
+ rf->rf_interval = plugin_get_interval ();
+ rf->rf_effective_interval = rf->rf_interval;
+
+ rf->rf_next_read = cdtime ();
+ }
+
+ /* sleep until this entry is due,
+ * using pthread_cond_timedwait */
+ pthread_mutex_lock (&read_lock);
+ /* In pthread_cond_timedwait, spurious wakeups are possible
+ * (and really happen, at least on NetBSD with > 1 CPU), thus
+ * we need to re-evaluate the condition every time
+ * pthread_cond_timedwait returns. */
+ rc = 0;
+ while ((read_loop != 0)
+ && (cdtime () < rf->rf_next_read)
+ && rc == 0)
+ {
+ struct timespec ts = { 0 };
+
+ CDTIME_T_TO_TIMESPEC (rf->rf_next_read, &ts);
+
+ rc = pthread_cond_timedwait (&read_cond, &read_lock,
+ &ts);
+ }
+
+ /* Must hold `read_lock' when accessing `rf->rf_type'. */
+ rf_type = rf->rf_type;
+ pthread_mutex_unlock (&read_lock);
+
+ /* Check if we're supposed to stop.. This may have interrupted
+ * the sleep, too. */
+ if (read_loop == 0)
+ {
+ /* Insert `rf' again, so it can be free'd correctly */
+ c_heap_insert (read_heap, rf);
+ break;
+ }
+
+ /* The entry has been marked for deletion. The linked list
+ * entry has already been removed by `plugin_unregister_read'.
+ * All we have to do here is free the `read_func_t' and
+ * continue. */
+ if (rf_type == RF_REMOVE)
+ {
+ DEBUG ("plugin_read_thread: Destroying the `%s' "
+ "callback.", rf->rf_name);
+ sfree (rf->rf_name);
+ destroy_callback ((callback_func_t *) rf);
+ rf = NULL;
+ continue;
+ }
+
+ DEBUG ("plugin_read_thread: Handling `%s'.", rf->rf_name);
+
+ old_ctx = plugin_set_ctx (rf->rf_ctx);
+
+ if (rf_type == RF_SIMPLE)
+ {
+ int (*callback) (void);
+
+ callback = rf->rf_callback;
+ status = (*callback) ();
+ }
+ else
+ {
+ plugin_read_cb callback;
+
+ assert (rf_type == RF_COMPLEX);
+
+ callback = rf->rf_callback;
+ status = (*callback) (&rf->rf_udata);
+ }
+
+ plugin_set_ctx (old_ctx);
+
+ /* If the function signals failure, we will increase the
+ * intervals in which it will be called. */
+ if (status != 0)
+ {
+ rf->rf_effective_interval *= 2;
+ if (rf->rf_effective_interval > max_read_interval)
+ rf->rf_effective_interval = max_read_interval;
+
+ NOTICE ("read-function of plugin `%s' failed. "
+ "Will suspend it for %.3f seconds.",
+ rf->rf_name,
+ CDTIME_T_TO_DOUBLE (rf->rf_effective_interval));
+ }
+ else
+ {
+ /* Success: Restore the interval, if it was changed. */
+ rf->rf_effective_interval = rf->rf_interval;
+ }
+
+ /* update the ``next read due'' field */
+ now = cdtime ();
+
+ DEBUG ("plugin_read_thread: Effective interval of the "
+ "%s plugin is %.3f seconds.",
+ rf->rf_name,
+ CDTIME_T_TO_DOUBLE (rf->rf_effective_interval));
+
+ /* Calculate the next (absolute) time at which this function
+ * should be called. */
+ rf->rf_next_read += rf->rf_effective_interval;
+
+ /* Check, if `rf_next_read' is in the past. */
+ if (rf->rf_next_read < now)
+ {
+ /* `rf_next_read' is in the past. Insert `now'
+ * so this value doesn't trail off into the
+ * past too much. */
+ rf->rf_next_read = now;
+ }
+
+ DEBUG ("plugin_read_thread: Next read of the %s plugin at %.3f.",
+ rf->rf_name,
+ CDTIME_T_TO_DOUBLE (rf->rf_next_read));
+
+ /* Re-insert this read function into the heap again. */
+ c_heap_insert (read_heap, rf);
+ } /* while (read_loop) */
+
+ pthread_exit (NULL);
+ return ((void *) 0);
+} /* void *plugin_read_thread */
+
+static void start_read_threads (int num)
+{
+ int i;
+
+ if (read_threads != NULL)
+ return;
+
+ read_threads = (pthread_t *) calloc (num, sizeof (pthread_t));
+ if (read_threads == NULL)
+ {
+ ERROR ("plugin: start_read_threads: calloc failed.");
+ return;
+ }
+
+ read_threads_num = 0;
+ for (i = 0; i < num; i++)
+ {
+ if (pthread_create (read_threads + read_threads_num, NULL,
+ plugin_read_thread, NULL) == 0)
+ {
+ read_threads_num++;
+ }
+ else
+ {
+ ERROR ("plugin: start_read_threads: pthread_create failed.");
+ return;
+ }
+ } /* for (i) */
+} /* void start_read_threads */
+
+static void stop_read_threads (void)
+{
+ int i;
+
+ if (read_threads == NULL)
+ return;
+
+ INFO ("collectd: Stopping %i read threads.", read_threads_num);
+
+ pthread_mutex_lock (&read_lock);
+ read_loop = 0;
+ DEBUG ("plugin: stop_read_threads: Signalling `read_cond'");
+ pthread_cond_broadcast (&read_cond);
+ pthread_mutex_unlock (&read_lock);
+
+ for (i = 0; i < read_threads_num; i++)
+ {
+ if (pthread_join (read_threads[i], NULL) != 0)
+ {
+ ERROR ("plugin: stop_read_threads: pthread_join failed.");
+ }
+ read_threads[i] = (pthread_t) 0;
+ }
+ sfree (read_threads);
+ read_threads_num = 0;
+} /* void stop_read_threads */
+
+static void plugin_value_list_free (value_list_t *vl) /* {{{ */
+{
+ if (vl == NULL)
+ return;
+
+ meta_data_destroy (vl->meta);
+ sfree (vl->values);
+ sfree (vl);
+} /* }}} void plugin_value_list_free */
+
+static value_list_t *plugin_value_list_clone (value_list_t const *vl_orig) /* {{{ */
+{
+ value_list_t *vl;
+
+ if (vl_orig == NULL)
+ return (NULL);
+
+ vl = malloc (sizeof (*vl));
+ if (vl == NULL)
+ return (NULL);
+ memcpy (vl, vl_orig, sizeof (*vl));
+
+ vl->values = calloc (vl_orig->values_len, sizeof (*vl->values));
+ if (vl->values == NULL)
+ {
+ plugin_value_list_free (vl);
+ return (NULL);
+ }
+ memcpy (vl->values, vl_orig->values,
+ vl_orig->values_len * sizeof (*vl->values));
+
+ vl->meta = meta_data_clone (vl->meta);
+ if ((vl_orig->meta != NULL) && (vl->meta == NULL))
+ {
+ plugin_value_list_free (vl);
+ return (NULL);
+ }
+
+ if (vl->time == 0)
+ vl->time = cdtime ();
+
+ /* Fill in the interval from the thread context, if it is zero. */
+ if (vl->interval == 0)
+ {
+ plugin_ctx_t ctx = plugin_get_ctx ();
+
+ if (ctx.interval != 0)
+ vl->interval = ctx.interval;
+ else
+ {
+ char name[6 * DATA_MAX_NAME_LEN];
+ FORMAT_VL (name, sizeof (name), vl);
+ ERROR ("plugin_value_list_clone: Unable to determine "
+ "interval from context for "
+ "value list \"%s\". "
+ "This indicates a broken plugin. "
+ "Please report this problem to the "
+ "collectd mailing list or at "
+ "<http://collectd.org/bugs/>.", name);
+ vl->interval = cf_get_default_interval ();
+ }
+ }
+
+ return (vl);
+} /* }}} value_list_t *plugin_value_list_clone */
+
+static int plugin_write_enqueue (value_list_t const *vl) /* {{{ */
+{
+ write_queue_t *q;
+
+ q = malloc (sizeof (*q));
+ if (q == NULL)
+ return (ENOMEM);
+ q->next = NULL;
+
+ q->vl = plugin_value_list_clone (vl);
+ if (q->vl == NULL)
+ {
+ sfree (q);
+ return (ENOMEM);
+ }
+
+ /* Store context of caller (read plugin); otherwise, it would not be
+ * available to the write plugins when actually dispatching the
+ * value-list later on. */
+ q->ctx = plugin_get_ctx ();
+
+ pthread_mutex_lock (&write_lock);
+
+ if (write_queue_tail == NULL)
+ {
+ write_queue_head = q;
+ write_queue_tail = q;
+ write_queue_length = 1;
+ }
+ else
+ {
+ write_queue_tail->next = q;
+ write_queue_tail = q;
+ write_queue_length += 1;
+ }
+
+ pthread_cond_signal (&write_cond);
+ pthread_mutex_unlock (&write_lock);
+
+ return (0);
+} /* }}} int plugin_write_enqueue */
+
+static value_list_t *plugin_write_dequeue (void) /* {{{ */
+{
+ write_queue_t *q;
+ value_list_t *vl;
+
+ pthread_mutex_lock (&write_lock);
+
+ while (write_loop && (write_queue_head == NULL))
+ pthread_cond_wait (&write_cond, &write_lock);
+
+ if (write_queue_head == NULL)
+ {
+ pthread_mutex_unlock (&write_lock);
+ return (NULL);
+ }
+
+ q = write_queue_head;
+ write_queue_head = q->next;
+ write_queue_length -= 1;
+ if (write_queue_head == NULL) {
+ write_queue_tail = NULL;
+ assert(0 == write_queue_length);
+ }
+
+ pthread_mutex_unlock (&write_lock);
+
+ (void) plugin_set_ctx (q->ctx);
+
+ vl = q->vl;
+ sfree (q);
+ return (vl);
+} /* }}} value_list_t *plugin_write_dequeue */
+
+static void *plugin_write_thread (void __attribute__((unused)) *args) /* {{{ */
+{
+ while (write_loop)
+ {
+ value_list_t *vl = plugin_write_dequeue ();
+ if (vl == NULL)
+ continue;
+
+ plugin_dispatch_values_internal (vl);
+
+ plugin_value_list_free (vl);
+ }
+
+ pthread_exit (NULL);
+ return ((void *) 0);
+} /* }}} void *plugin_write_thread */
+
+static void start_write_threads (size_t num) /* {{{ */
+{
+ size_t i;
+
+ if (write_threads != NULL)
+ return;
+
+ write_threads = (pthread_t *) calloc (num, sizeof (pthread_t));
+ if (write_threads == NULL)
+ {
+ ERROR ("plugin: start_write_threads: calloc failed.");
+ return;
+ }
+
+ write_threads_num = 0;
+ for (i = 0; i < num; i++)
+ {
+ int status;
+
+ status = pthread_create (write_threads + write_threads_num,
+ /* attr = */ NULL,
+ plugin_write_thread,
+ /* arg = */ NULL);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("plugin: start_write_threads: pthread_create failed "
+ "with status %i (%s).", status,
+ sstrerror (status, errbuf, sizeof (errbuf)));
+ return;
+ }
+
+ write_threads_num++;
+ } /* for (i) */
+} /* }}} void start_write_threads */
+
+static void stop_write_threads (void) /* {{{ */
+{
+ write_queue_t *q;
+ int i;
+
+ if (write_threads == NULL)
+ return;
+
+ INFO ("collectd: Stopping %zu write threads.", write_threads_num);
+
+ pthread_mutex_lock (&write_lock);
+ write_loop = 0;
+ DEBUG ("plugin: stop_write_threads: Signalling `write_cond'");
+ pthread_cond_broadcast (&write_cond);
+ pthread_mutex_unlock (&write_lock);
+
+ for (i = 0; i < write_threads_num; i++)
+ {
+ if (pthread_join (write_threads[i], NULL) != 0)
+ {
+ ERROR ("plugin: stop_write_threads: pthread_join failed.");
+ }
+ write_threads[i] = (pthread_t) 0;
+ }
+ sfree (write_threads);
+ write_threads_num = 0;
+
+ pthread_mutex_lock (&write_lock);
+ i = 0;
+ for (q = write_queue_head; q != NULL; )
+ {
+ write_queue_t *q1 = q;
+ plugin_value_list_free (q->vl);
+ q = q->next;
+ sfree (q1);
+ i++;
+ }
+ write_queue_head = NULL;
+ write_queue_tail = NULL;
+ write_queue_length = 0;
+ pthread_mutex_unlock (&write_lock);
+
+ if (i > 0)
+ {
+ WARNING ("plugin: %i value list%s left after shutting down "
+ "the write threads.",
+ i, (i == 1) ? " was" : "s were");
+ }
+} /* }}} void stop_write_threads */
+
+/*
+ * Public functions
+ */
+void plugin_set_dir (const char *dir)
+{
+ if (plugindir != NULL)
+ free (plugindir);
+
+ if (dir == NULL)
+ plugindir = NULL;
+ else if ((plugindir = strdup (dir)) == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("strdup failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ }
+}
+
+static _Bool plugin_is_loaded (char const *name)
+{
+ int status;
+
+ if (plugins_loaded == NULL)
+ plugins_loaded = c_avl_create ((void *) strcasecmp);
+ assert (plugins_loaded != NULL);
+
+ status = c_avl_get (plugins_loaded, name, /* ret_value = */ NULL);
+ return (status == 0);
+}
+
+static int plugin_mark_loaded (char const *name)
+{
+ char *name_copy;
+ int status;
+
+ name_copy = strdup (name);
+ if (name_copy == NULL)
+ return (ENOMEM);
+
+ status = c_avl_insert (plugins_loaded,
+ /* key = */ name_copy, /* value = */ NULL);
+ return (status);
+}
+
+static void plugin_free_loaded ()
+{
+ void *key;
+ void *value;
+
+ if (plugins_loaded == NULL)
+ return;
+
+ while (c_avl_pick (plugins_loaded, &key, &value) == 0)
+ {
+ sfree (key);
+ assert (value == NULL);
+ }
+
+ c_avl_destroy (plugins_loaded);
+ plugins_loaded = NULL;
+}
+
+#define BUFSIZE 512
+int plugin_load (char const *plugin_name, uint32_t flags)
+{
+ DIR *dh;
+ const char *dir;
+ char filename[BUFSIZE] = "";
+ char typename[BUFSIZE];
+ int typename_len;
+ int ret;
+ struct stat statbuf;
+ struct dirent *de;
+ int status;
+
+ if (plugin_name == NULL)
+ return (EINVAL);
+
+ /* Check if plugin is already loaded and don't do anything in this
+ * case. */
+ if (plugin_is_loaded (plugin_name))
+ return (0);
+
+ dir = plugin_get_dir ();
+ ret = 1;
+
+ /*
+ * XXX: Magic at work:
+ *
+ * Some of the language bindings, for example the Python and Perl
+ * plugins, need to be able to export symbols to the scripts they run.
+ * For this to happen, the "Globals" flag needs to be set.
+ * Unfortunately, this technical detail is hard to explain to the
+ * average user and she shouldn't have to worry about this, ideally.
+ * So in order to save everyone's sanity use a different default for a
+ * handful of special plugins. --octo
+ */
+ if ((strcasecmp ("perl", plugin_name) == 0)
+ || (strcasecmp ("python", plugin_name) == 0))
+ flags |= PLUGIN_FLAGS_GLOBAL;
+
+ /* `cpu' should not match `cpufreq'. To solve this we add `.so' to the
+ * type when matching the filename */
+ status = ssnprintf (typename, sizeof (typename), "%s.so", plugin_name);
+ if ((status < 0) || ((size_t) status >= sizeof (typename)))
+ {
+ WARNING ("plugin_load: Filename too long: \"%s.so\"", plugin_name);
+ return (-1);
+ }
+ typename_len = strlen (typename);
+
+ if ((dh = opendir (dir)) == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("plugin_load: opendir (%s) failed: %s", dir,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ while ((de = readdir (dh)) != NULL)
+ {
+ if (strncasecmp (de->d_name, typename, typename_len))
+ continue;
+
+ status = ssnprintf (filename, sizeof (filename),
+ "%s/%s", dir, de->d_name);
+ if ((status < 0) || ((size_t) status >= sizeof (filename)))
+ {
+ WARNING ("plugin_load: Filename too long: \"%s/%s\"",
+ dir, de->d_name);
+ continue;
+ }
+
+ if (lstat (filename, &statbuf) == -1)
+ {
+ char errbuf[1024];
+ WARNING ("plugin_load: stat (\"%s\") failed: %s",
+ filename,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ continue;
+ }
+ else if (!S_ISREG (statbuf.st_mode))
+ {
+ /* don't follow symlinks */
+ WARNING ("plugin_load: %s is not a regular file.",
+ filename);
+ continue;
+ }
+
+ status = plugin_load_file (filename, flags);
+ if (status == 0)
+ {
+ /* success */
+ plugin_mark_loaded (plugin_name);
+ ret = 0;
+ break;
+ }
+ else
+ {
+ ERROR ("plugin_load: Load plugin \"%s\" failed with "
+ "status %i.", plugin_name, status);
+ }
+ }
+
+ closedir (dh);
+
+ if (filename[0] == 0)
+ ERROR ("plugin_load: Could not find plugin \"%s\" in %s",
+ plugin_name, dir);
+
+ return (ret);
+}
+
+/*
+ * The `register_*' functions follow
+ */
+int plugin_register_config (const char *name,
+ int (*callback) (const char *key, const char *val),
+ const char **keys, int keys_num)
+{
+ cf_register (name, callback, keys, keys_num);
+ 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 (create_register_callback (&list_init, name, (void *) callback,
+ /* user_data = */ NULL));
+} /* plugin_register_init */
+
+static int plugin_compare_read_func (const void *arg0, const void *arg1)
+{
+ const read_func_t *rf0;
+ const read_func_t *rf1;
+
+ rf0 = arg0;
+ rf1 = arg1;
+
+ if (rf0->rf_next_read < rf1->rf_next_read)
+ return (-1);
+ else if (rf0->rf_next_read > rf1->rf_next_read)
+ return (1);
+ else
+ return (0);
+} /* int plugin_compare_read_func */
+
+/* Add a read function to both, the heap and a linked list. The linked list if
+ * used to look-up read functions, especially for the remove function. The heap
+ * is used to determine which plugin to read next. */
+static int plugin_insert_read (read_func_t *rf)
+{
+ int status;
+ llentry_t *le;
+
+ rf->rf_next_read = cdtime ();
+ rf->rf_effective_interval = rf->rf_interval;
+
+ pthread_mutex_lock (&read_lock);
+
+ if (read_list == NULL)
+ {
+ read_list = llist_create ();
+ if (read_list == NULL)
+ {
+ pthread_mutex_unlock (&read_lock);
+ ERROR ("plugin_insert_read: read_list failed.");
+ return (-1);
+ }
+ }
+
+ if (read_heap == NULL)
+ {
+ read_heap = c_heap_create (plugin_compare_read_func);
+ if (read_heap == NULL)
+ {
+ pthread_mutex_unlock (&read_lock);
+ ERROR ("plugin_insert_read: c_heap_create failed.");
+ return (-1);
+ }
+ }
+
+ le = llist_search (read_list, rf->rf_name);
+ if (le != NULL)
+ {
+ pthread_mutex_unlock (&read_lock);
+ WARNING ("The read function \"%s\" is already registered. "
+ "Check for duplicate \"LoadPlugin\" lines "
+ "in your configuration!",
+ rf->rf_name);
+ return (EINVAL);
+ }
+
+ le = llentry_create (rf->rf_name, rf);
+ if (le == NULL)
+ {
+ pthread_mutex_unlock (&read_lock);
+ ERROR ("plugin_insert_read: llentry_create failed.");
+ return (-1);
+ }
+
+ status = c_heap_insert (read_heap, rf);
+ if (status != 0)
+ {
+ pthread_mutex_unlock (&read_lock);
+ ERROR ("plugin_insert_read: c_heap_insert failed.");
+ llentry_destroy (le);
+ return (-1);
+ }
+
+ /* This does not fail. */
+ llist_append (read_list, le);
+
+ /* Wake up all the read threads. */
+ pthread_cond_broadcast (&read_cond);
+ pthread_mutex_unlock (&read_lock);
+ return (0);
+} /* int plugin_insert_read */
+
+int plugin_register_read (const char *name,
+ int (*callback) (void))
+{
+ read_func_t *rf;
+ int status;
+
+ rf = malloc (sizeof (*rf));
+ if (rf == NULL)
+ {
+ ERROR ("plugin_register_read: malloc failed.");
+ return (ENOMEM);
+ }
+
+ memset (rf, 0, sizeof (read_func_t));
+ rf->rf_callback = (void *) callback;
+ rf->rf_udata.data = NULL;
+ rf->rf_udata.free_func = NULL;
+ rf->rf_ctx = plugin_get_ctx ();
+ rf->rf_group[0] = '\0';
+ rf->rf_name = strdup (name);
+ rf->rf_type = RF_SIMPLE;
+ rf->rf_interval = plugin_get_interval ();
+
+ status = plugin_insert_read (rf);
+ if (status != 0)
+ sfree (rf);
+
+ return (status);
+} /* int plugin_register_read */
+
+int plugin_register_complex_read (const char *group, const char *name,
+ plugin_read_cb callback,
+ const struct timespec *interval,
+ user_data_t *user_data)
+{
+ read_func_t *rf;
+ int status;
+
+ rf = malloc (sizeof (*rf));
+ if (rf == NULL)
+ {
+ ERROR ("plugin_register_complex_read: malloc failed.");
+ return (ENOMEM);
+ }
+
+ memset (rf, 0, sizeof (read_func_t));
+ rf->rf_callback = (void *) callback;
+ if (group != NULL)
+ sstrncpy (rf->rf_group, group, sizeof (rf->rf_group));
+ else
+ rf->rf_group[0] = '\0';
+ rf->rf_name = strdup (name);
+ rf->rf_type = RF_COMPLEX;
+ if (interval != NULL)
+ rf->rf_interval = TIMESPEC_TO_CDTIME_T (interval);
+ else
+ rf->rf_interval = plugin_get_interval ();
+
+ /* Set user data */
+ if (user_data == NULL)
+ {
+ rf->rf_udata.data = NULL;
+ rf->rf_udata.free_func = NULL;
+ }
+ else
+ {
+ rf->rf_udata = *user_data;
+ }
+
+ rf->rf_ctx = plugin_get_ctx ();
+
+ status = plugin_insert_read (rf);
+ if (status != 0)
+ sfree (rf);
+
+ return (status);
+} /* int plugin_register_complex_read */
+
+int plugin_register_write (const char *name,
+ plugin_write_cb callback, user_data_t *ud)
+{
+ return (create_register_callback (&list_write, name,
+ (void *) callback, ud));
+} /* int plugin_register_write */
+
+int plugin_register_flush (const char *name,
+ plugin_flush_cb callback, user_data_t *ud)
+{
+ return (create_register_callback (&list_flush, name,
+ (void *) callback, ud));
+} /* int plugin_register_flush */
+
+int plugin_register_missing (const char *name,
+ plugin_missing_cb callback, user_data_t *ud)
+{
+ return (create_register_callback (&list_missing, name,
+ (void *) callback, ud));
+} /* int plugin_register_missing */
+
+int plugin_register_shutdown (const char *name,
+ int (*callback) (void))
+{
+ return (create_register_callback (&list_shutdown, name,
+ (void *) callback, /* user_data = */ NULL));
+} /* int plugin_register_shutdown */
+
+static void plugin_free_data_sets (void)
+{
+ void *key;
+ void *value;
+
+ if (data_sets == NULL)
+ return;
+
+ while (c_avl_pick (data_sets, &key, &value) == 0)
+ {
+ data_set_t *ds = value;
+ /* key is a pointer to ds->type */
+
+ sfree (ds->ds);
+ sfree (ds);
+ }
+
+ c_avl_destroy (data_sets);
+ data_sets = NULL;
+} /* void plugin_free_data_sets */
+
+int plugin_register_data_set (const data_set_t *ds)
+{
+ data_set_t *ds_copy;
+ int i;
+
+ if ((data_sets != NULL)
+ && (c_avl_get (data_sets, ds->type, NULL) == 0))
+ {
+ NOTICE ("Replacing DS `%s' with another version.", ds->type);
+ plugin_unregister_data_set (ds->type);
+ }
+ else if (data_sets == NULL)
+ {
+ data_sets = c_avl_create ((int (*) (const void *, const void *)) strcmp);
+ if (data_sets == NULL)
+ return (-1);
+ }
+
+ ds_copy = (data_set_t *) malloc (sizeof (data_set_t));
+ if (ds_copy == NULL)
+ return (-1);
+ memcpy(ds_copy, ds, sizeof (data_set_t));
+
+ ds_copy->ds = (data_source_t *) malloc (sizeof (data_source_t)
+ * ds->ds_num);
+ if (ds_copy->ds == NULL)
+ {
+ free (ds_copy);
+ return (-1);
+ }
+
+ for (i = 0; i < ds->ds_num; i++)
+ memcpy (ds_copy->ds + i, ds->ds + i, sizeof (data_source_t));
+
+ return (c_avl_insert (data_sets, (void *) ds_copy->type, (void *) ds_copy));
+} /* int plugin_register_data_set */
+
+int plugin_register_log (const char *name,
+ plugin_log_cb callback, user_data_t *ud)
+{
+ return (create_register_callback (&list_log, name,
+ (void *) callback, ud));
+} /* int plugin_register_log */
+
+int plugin_register_notification (const char *name,
+ plugin_notification_cb callback, user_data_t *ud)
+{
+ return (create_register_callback (&list_notification, name,
+ (void *) callback, ud));
+} /* int plugin_register_log */
+
+int plugin_unregister_config (const char *name)
+{
+ cf_unregister (name);
+ return (0);
+} /* int plugin_unregister_config */
+
+int plugin_unregister_complex_config (const char *name)
+{
+ cf_unregister_complex (name);
+ return (0);
+} /* int plugin_unregister_complex_config */
+
+int plugin_unregister_init (const char *name)
+{
+ return (plugin_unregister (list_init, name));
+}
+
+int plugin_unregister_read (const char *name) /* {{{ */
+{
+ llentry_t *le;
+ read_func_t *rf;
+
+ if (name == NULL)
+ return (-ENOENT);
+
+ pthread_mutex_lock (&read_lock);
+
+ if (read_list == NULL)
+ {
+ pthread_mutex_unlock (&read_lock);
+ return (-ENOENT);
+ }
+
+ le = llist_search (read_list, name);
+ if (le == NULL)
+ {
+ pthread_mutex_unlock (&read_lock);
+ WARNING ("plugin_unregister_read: No such read function: %s",
+ name);
+ return (-ENOENT);
+ }
+
+ llist_remove (read_list, le);
+
+ rf = le->value;
+ assert (rf != NULL);
+ rf->rf_type = RF_REMOVE;
+
+ pthread_mutex_unlock (&read_lock);
+
+ llentry_destroy (le);
+
+ DEBUG ("plugin_unregister_read: Marked `%s' for removal.", name);
+
+ return (0);
+} /* }}} int plugin_unregister_read */
+
+static int compare_read_func_group (llentry_t *e, void *ud) /* {{{ */
+{
+ read_func_t *rf = e->value;
+ char *group = ud;
+
+ return strcmp (rf->rf_group, (const char *)group);
+} /* }}} int compare_read_func_group */
+
+int plugin_unregister_read_group (const char *group) /* {{{ */
+{
+ llentry_t *le;
+ read_func_t *rf;
+
+ int found = 0;
+
+ if (group == NULL)
+ return (-ENOENT);
+
+ pthread_mutex_lock (&read_lock);
+
+ if (read_list == NULL)
+ {
+ pthread_mutex_unlock (&read_lock);
+ return (-ENOENT);
+ }
+
+ while (42)
+ {
+ le = llist_search_custom (read_list,
+ compare_read_func_group, (void *)group);
+
+ if (le == NULL)
+ break;
+
+ ++found;
+
+ llist_remove (read_list, le);
+
+ rf = le->value;
+ assert (rf != NULL);
+ rf->rf_type = RF_REMOVE;
+
+ llentry_destroy (le);
+
+ DEBUG ("plugin_unregister_read_group: "
+ "Marked `%s' (group `%s') for removal.",
+ rf->rf_name, group);
+ }
+
+ pthread_mutex_unlock (&read_lock);
+
+ if (found == 0)
+ {
+ WARNING ("plugin_unregister_read_group: No such "
+ "group of read function: %s", group);
+ return (-ENOENT);
+ }
+
+ return (0);
+} /* }}} int plugin_unregister_read_group */
+
+int plugin_unregister_write (const char *name)
+{
+ return (plugin_unregister (list_write, name));
+}
+
+int plugin_unregister_flush (const char *name)
+{
+ return (plugin_unregister (list_flush, name));
+}
+
+int plugin_unregister_missing (const char *name)
+{
+ return (plugin_unregister (list_missing, name));
+}
+
+int plugin_unregister_shutdown (const char *name)
+{
+ return (plugin_unregister (list_shutdown, name));
+}
+
+int plugin_unregister_data_set (const char *name)
+{
+ data_set_t *ds;
+
+ if (data_sets == NULL)
+ return (-1);
+
+ if (c_avl_remove (data_sets, name, NULL, (void *) &ds) != 0)
+ return (-1);
+
+ sfree (ds->ds);
+ sfree (ds);
+
+ return (0);
+} /* int plugin_unregister_data_set */
+
+int plugin_unregister_log (const char *name)
+{
+ return (plugin_unregister (list_log, name));
+}
+
+int plugin_unregister_notification (const char *name)
+{
+ return (plugin_unregister (list_notification, name));
+}
+
+void plugin_init_all (void)
+{
+ char const *chain_name;
+ long write_threads_num;
+ llentry_t *le;
+ int status;
+
+ /* Init the value cache */
+ uc_init ();
+
+ if (IS_TRUE (global_option_get ("CollectInternalStats")))
+ record_statistics = 1;
+
+ chain_name = global_option_get ("PreCacheChain");
+ pre_cache_chain = fc_chain_get_by_name (chain_name);
+
+ chain_name = global_option_get ("PostCacheChain");
+ post_cache_chain = fc_chain_get_by_name (chain_name);
+
+ write_limit_high = global_option_get_long ("WriteQueueLimitHigh",
+ /* default = */ 0);
+ if (write_limit_high < 0)
+ {
+ ERROR ("WriteQueueLimitHigh must be positive or zero.");
+ write_limit_high = 0;
+ }
+
+ write_limit_low = global_option_get_long ("WriteQueueLimitLow",
+ /* default = */ write_limit_high / 2);
+ if (write_limit_low < 0)
+ {
+ ERROR ("WriteQueueLimitLow must be positive or zero.");
+ write_limit_low = write_limit_high / 2;
+ }
+ else if (write_limit_low > write_limit_high)
+ {
+ ERROR ("WriteQueueLimitLow must not be larger than "
+ "WriteQueueLimitHigh.");
+ write_limit_low = write_limit_high;
+ }
+
+ write_threads_num = global_option_get_long ("WriteThreads",
+ /* default = */ 5);
+ if (write_threads_num < 1)
+ {
+ ERROR ("WriteThreads must be positive.");
+ write_threads_num = 5;
+ }
+
+ start_write_threads ((size_t) write_threads_num);
+
+ if ((list_init == NULL) && (read_heap == NULL))
+ return;
+
+ /* Calling all init callbacks before checking if read callbacks
+ * are available allows the init callbacks to register the read
+ * callback. */
+ le = llist_head (list_init);
+ while (le != NULL)
+ {
+ callback_func_t *cf;
+ plugin_init_cb callback;
+ plugin_ctx_t old_ctx;
+
+ cf = le->value;
+ old_ctx = plugin_set_ctx (cf->cf_ctx);
+ callback = cf->cf_callback;
+ status = (*callback) ();
+ plugin_set_ctx (old_ctx);
+
+ if (status != 0)
+ {
+ ERROR ("Initialization of plugin `%s' "
+ "failed with status %i. "
+ "Plugin will be unloaded.",
+ le->key, status);
+ /* Plugins that register read callbacks from the init
+ * callback should take care of appropriate error
+ * handling themselves. */
+ /* FIXME: Unload _all_ functions */
+ plugin_unregister_read (le->key);
+ }
+
+ le = le->next;
+ }
+
+ max_read_interval = global_option_get_time ("MaxReadInterval",
+ DEFAULT_MAX_READ_INTERVAL);
+
+ /* Start read-threads */
+ if (read_heap != NULL)
+ {
+ const char *rt;
+ int num;
+
+ rt = global_option_get ("ReadThreads");
+ num = atoi (rt);
+ if (num != -1)
+ start_read_threads ((num > 0) ? num : 5);
+ }
+} /* void plugin_init_all */
+
+/* TODO: Rename this function. */
+void plugin_read_all (void)
+{
+ if(record_statistics) {
+ plugin_update_internal_statistics ();
+ }
+ uc_check_timeout ();
+
+ return;
+} /* void plugin_read_all */
+
+/* Read function called when the `-T' command line argument is given. */
+int plugin_read_all_once (void)
+{
+ int status;
+ int return_status = 0;
+
+ if (read_heap == NULL)
+ {
+ NOTICE ("No read-functions are registered.");
+ return (0);
+ }
+
+ while (42)
+ {
+ read_func_t *rf;
+ plugin_ctx_t old_ctx;
+
+ rf = c_heap_get_root (read_heap);
+ if (rf == NULL)
+ break;
+
+ old_ctx = plugin_set_ctx (rf->rf_ctx);
+
+ if (rf->rf_type == RF_SIMPLE)
+ {
+ int (*callback) (void);
+
+ callback = rf->rf_callback;
+ status = (*callback) ();
+ }
+ else
+ {
+ plugin_read_cb callback;
+
+ callback = rf->rf_callback;
+ status = (*callback) (&rf->rf_udata);
+ }
+
+ plugin_set_ctx (old_ctx);
+
+ if (status != 0)
+ {
+ NOTICE ("read-function of plugin `%s' failed.",
+ rf->rf_name);
+ return_status = -1;
+ }
+
+ destroy_callback ((void *) rf);
+ }
+
+ return (return_status);
+} /* int plugin_read_all_once */
+
+int plugin_write (const char *plugin, /* {{{ */
+ const data_set_t *ds, const value_list_t *vl)
+{
+ llentry_t *le;
+ int status;
+
+ if (vl == NULL)
+ return (EINVAL);
+
+ if (list_write == NULL)
+ return (ENOENT);
+
+ if (ds == NULL)
+ {
+ ds = plugin_get_ds (vl->type);
+ if (ds == NULL)
+ {
+ ERROR ("plugin_write: Unable to lookup type `%s'.", vl->type);
+ return (ENOENT);
+ }
+ }
+
+ if (plugin == NULL)
+ {
+ int success = 0;
+ int failure = 0;
+
+ le = llist_head (list_write);
+ while (le != NULL)
+ {
+ callback_func_t *cf = le->value;
+ plugin_write_cb callback;
+
+ /* do not switch plugin context; rather keep the context (interval)
+ * information of the calling read plugin */
+
+ DEBUG ("plugin: plugin_write: Writing values via %s.", le->key);
+ callback = cf->cf_callback;
+ status = (*callback) (ds, vl, &cf->cf_udata);
+ if (status != 0)
+ failure++;
+ else
+ success++;
+
+ le = le->next;
+ }
+
+ if ((success == 0) && (failure != 0))
+ status = -1;
+ else
+ status = 0;
+ }
+ else /* plugin != NULL */
+ {
+ callback_func_t *cf;
+ plugin_write_cb callback;
+
+ le = llist_head (list_write);
+ while (le != NULL)
+ {
+ if (strcasecmp (plugin, le->key) == 0)
+ break;
+
+ le = le->next;
+ }
+
+ if (le == NULL)
+ return (ENOENT);
+
+ cf = le->value;
+
+ /* do not switch plugin context; rather keep the context (interval)
+ * information of the calling read plugin */
+
+ DEBUG ("plugin: plugin_write: Writing values via %s.", le->key);
+ callback = cf->cf_callback;
+ status = (*callback) (ds, vl, &cf->cf_udata);
+ }
+
+ return (status);
+} /* }}} int plugin_write */
+
+int plugin_flush (const char *plugin, cdtime_t timeout, const char *identifier)
+{
+ llentry_t *le;
+
+ if (list_flush == NULL)
+ return (0);
+
+ le = llist_head (list_flush);
+ while (le != NULL)
+ {
+ callback_func_t *cf;
+ plugin_flush_cb callback;
+ plugin_ctx_t old_ctx;
+
+ if ((plugin != NULL)
+ && (strcmp (plugin, le->key) != 0))
+ {
+ le = le->next;
+ continue;
+ }
+
+ cf = le->value;
+ old_ctx = plugin_set_ctx (cf->cf_ctx);
+ callback = cf->cf_callback;
+
+ (*callback) (timeout, identifier, &cf->cf_udata);
+
+ plugin_set_ctx (old_ctx);
+
+ le = le->next;
+ }
+ return (0);
+} /* int plugin_flush */
+
+void plugin_shutdown_all (void)
+{
+ llentry_t *le;
+
+ stop_read_threads ();
+
+ destroy_all_callbacks (&list_init);
+
+ pthread_mutex_lock (&read_lock);
+ llist_destroy (read_list);
+ read_list = NULL;
+ pthread_mutex_unlock (&read_lock);
+
+ destroy_read_heap ();
+
+ plugin_flush (/* plugin = */ NULL,
+ /* timeout = */ 0,
+ /* identifier = */ NULL);
+
+ le = NULL;
+ if (list_shutdown != NULL)
+ le = llist_head (list_shutdown);
+
+ while (le != NULL)
+ {
+ callback_func_t *cf;
+ plugin_shutdown_cb callback;
+ plugin_ctx_t old_ctx;
+
+ cf = le->value;
+ old_ctx = plugin_set_ctx (cf->cf_ctx);
+ callback = cf->cf_callback;
+
+ /* Advance the pointer before calling the callback allows
+ * shutdown functions to unregister themselves. If done the
+ * other way around the memory `le' points to will be freed
+ * after callback returns. */
+ le = le->next;
+
+ (*callback) ();
+
+ plugin_set_ctx (old_ctx);
+ }
+
+ stop_write_threads ();
+
+ /* Write plugins which use the `user_data' pointer usually need the
+ * same data available to the flush callback. If this is the case, set
+ * the free_function to NULL when registering the flush callback and to
+ * the real free function when registering the write callback. This way
+ * the data isn't freed twice. */
+ destroy_all_callbacks (&list_flush);
+ destroy_all_callbacks (&list_missing);
+ destroy_all_callbacks (&list_write);
+
+ destroy_all_callbacks (&list_notification);
+ destroy_all_callbacks (&list_shutdown);
+ destroy_all_callbacks (&list_log);
+
+ plugin_free_loaded ();
+ plugin_free_data_sets ();
+} /* void plugin_shutdown_all */
+
+int plugin_dispatch_missing (const value_list_t *vl) /* {{{ */
+{
+ llentry_t *le;
+
+ if (list_missing == NULL)
+ return (0);
+
+ le = llist_head (list_missing);
+ while (le != NULL)
+ {
+ callback_func_t *cf;
+ plugin_missing_cb callback;
+ plugin_ctx_t old_ctx;
+ int status;
+
+ cf = le->value;
+ old_ctx = plugin_set_ctx (cf->cf_ctx);
+ callback = cf->cf_callback;
+
+ status = (*callback) (vl, &cf->cf_udata);
+ plugin_set_ctx (old_ctx);
+ if (status != 0)
+ {
+ if (status < 0)
+ {
+ ERROR ("plugin_dispatch_missing: Callback function \"%s\" "
+ "failed with status %i.",
+ le->key, status);
+ return (status);
+ }
+ else
+ {
+ return (0);
+ }
+ }
+
+ le = le->next;
+ }
+ return (0);
+} /* int }}} plugin_dispatch_missing */
+
+static int plugin_dispatch_values_internal (value_list_t *vl)
+{
+ int status;
+ static c_complain_t no_write_complaint = C_COMPLAIN_INIT_STATIC;
+
+ value_t *saved_values;
+ int saved_values_len;
+
+ data_set_t *ds;
+
+ int free_meta_data = 0;
+
+ if ((vl == NULL) || (vl->type[0] == 0)
+ || (vl->values == NULL) || (vl->values_len < 1))
+ {
+ ERROR ("plugin_dispatch_values: Invalid value list "
+ "from plugin %s.", vl->plugin);
+ return (-1);
+ }
+
+ /* Free meta data only if the calling function didn't specify any. In
+ * this case matches and targets may add some and the calling function
+ * may not expect (and therefore free) that data. */
+ if (vl->meta == NULL)
+ free_meta_data = 1;
+
+ if (list_write == NULL)
+ c_complain_once (LOG_WARNING, &no_write_complaint,
+ "plugin_dispatch_values: No write callback has been "
+ "registered. Please load at least one output plugin, "
+ "if you want the collected data to be stored.");
+
+ if (data_sets == NULL)
+ {
+ ERROR ("plugin_dispatch_values: No data sets registered. "
+ "Could the types database be read? Check "
+ "your `TypesDB' setting!");
+ return (-1);
+ }
+
+ if (c_avl_get (data_sets, vl->type, (void *) &ds) != 0)
+ {
+ char ident[6 * DATA_MAX_NAME_LEN];
+
+ FORMAT_VL (ident, sizeof (ident), vl);
+ INFO ("plugin_dispatch_values: Dataset not found: %s "
+ "(from \"%s\"), check your types.db!",
+ vl->type, ident);
+ return (-1);
+ }
+
+ /* Assured by plugin_value_list_clone(). The time is determined at
+ * _enqueue_ time. */
+ assert (vl->time != 0);
+ assert (vl->interval != 0);
+
+ DEBUG ("plugin_dispatch_values: time = %.3f; interval = %.3f; "
+ "host = %s; "
+ "plugin = %s; plugin_instance = %s; "
+ "type = %s; type_instance = %s;",
+ CDTIME_T_TO_DOUBLE (vl->time),
+ CDTIME_T_TO_DOUBLE (vl->interval),
+ vl->host,
+ vl->plugin, vl->plugin_instance,
+ vl->type, vl->type_instance);
+
+#if COLLECT_DEBUG
+ assert (0 == strcmp (ds->type, vl->type));
+#else
+ if (0 != strcmp (ds->type, vl->type))
+ WARNING ("plugin_dispatch_values: (ds->type = %s) != (vl->type = %s)",
+ ds->type, vl->type);
+#endif
+
+#if COLLECT_DEBUG
+ assert (ds->ds_num == vl->values_len);
+#else
+ if (ds->ds_num != vl->values_len)
+ {
+ ERROR ("plugin_dispatch_values: ds->type = %s: "
+ "(ds->ds_num = %i) != "
+ "(vl->values_len = %i)",
+ ds->type, ds->ds_num, vl->values_len);
+ return (-1);
+ }
+#endif
+
+ escape_slashes (vl->host, sizeof (vl->host));
+ escape_slashes (vl->plugin, sizeof (vl->plugin));
+ escape_slashes (vl->plugin_instance, sizeof (vl->plugin_instance));
+ escape_slashes (vl->type, sizeof (vl->type));
+ escape_slashes (vl->type_instance, sizeof (vl->type_instance));
+
+ /* Copy the values. This way, we can assure `targets' that they get
+ * dynamically allocated values, which they can free and replace if
+ * they like. */
+ if ((pre_cache_chain != NULL) || (post_cache_chain != NULL))
+ {
+ saved_values = vl->values;
+ saved_values_len = vl->values_len;
+
+ vl->values = (value_t *) calloc (vl->values_len,
+ sizeof (*vl->values));
+ if (vl->values == NULL)
+ {
+ ERROR ("plugin_dispatch_values: calloc failed.");
+ vl->values = saved_values;
+ return (-1);
+ }
+ memcpy (vl->values, saved_values,
+ vl->values_len * sizeof (*vl->values));
+ }
+ else /* if ((pre == NULL) && (post == NULL)) */
+ {
+ saved_values = NULL;
+ saved_values_len = 0;
+ }
+
+ if (pre_cache_chain != NULL)
+ {
+ status = fc_process_chain (ds, vl, pre_cache_chain);
+ if (status < 0)
+ {
+ WARNING ("plugin_dispatch_values: Running the "
+ "pre-cache chain failed with "
+ "status %i (%#x).",
+ status, status);
+ }
+ else if (status == FC_TARGET_STOP)
+ {
+ /* Restore the state of the value_list so that plugins
+ * don't get confused.. */
+ if (saved_values != NULL)
+ {
+ free (vl->values);
+ vl->values = saved_values;
+ vl->values_len = saved_values_len;
+ }
+ return (0);
+ }
+ }
+
+ /* Update the value cache */
+ uc_update (ds, vl);
+
+ if (post_cache_chain != NULL)
+ {
+ status = fc_process_chain (ds, vl, post_cache_chain);
+ if (status < 0)
+ {
+ WARNING ("plugin_dispatch_values: Running the "
+ "post-cache chain failed with "
+ "status %i (%#x).",
+ status, status);
+ }
+ }
+ else
+ fc_default_action (ds, vl);
+
+ /* Restore the state of the value_list so that plugins don't get
+ * confused.. */
+ if (saved_values != NULL)
+ {
+ free (vl->values);
+ vl->values = saved_values;
+ vl->values_len = saved_values_len;
+ }
+
+ if ((free_meta_data != 0) && (vl->meta != NULL))
+ {
+ meta_data_destroy (vl->meta);
+ vl->meta = NULL;
+ }
+
+ return (0);
+} /* int plugin_dispatch_values_internal */
+
+static double get_drop_probability (void) /* {{{ */
+{
+ long pos;
+ long size;
+ long wql;
+
+ pthread_mutex_lock (&write_lock);
+ wql = write_queue_length;
+ pthread_mutex_unlock (&write_lock);
+
+ if (wql < write_limit_low)
+ return (0.0);
+ if (wql >= write_limit_high)
+ return (1.0);
+
+ pos = 1 + wql - write_limit_low;
+ size = 1 + write_limit_high - write_limit_low;
+
+ return (((double) pos) / ((double) size));
+} /* }}} double get_drop_probability */
+
+static _Bool check_drop_value (void) /* {{{ */
+{
+ static cdtime_t last_message_time = 0;
+ static pthread_mutex_t last_message_lock = PTHREAD_MUTEX_INITIALIZER;
+
+ double p;
+ double q;
+ int status;
+
+ if (write_limit_high == 0)
+ return (0);
+
+ p = get_drop_probability ();
+ if (p == 0.0)
+ return (0);
+
+ status = pthread_mutex_trylock (&last_message_lock);
+ if (status == 0)
+ {
+ cdtime_t now;
+
+ now = cdtime ();
+ if ((now - last_message_time) > TIME_T_TO_CDTIME_T (1))
+ {
+ last_message_time = now;
+ ERROR ("plugin_dispatch_values: Low water mark "
+ "reached. Dropping %.0f%% of metrics.",
+ 100.0 * p);
+ }
+ pthread_mutex_unlock (&last_message_lock);
+ }
+
+ if (p == 1.0)
+ return (1);
+
+ q = cdrand_d ();
+ if (q > p)
+ return (1);
+ else
+ return (0);
+} /* }}} _Bool check_drop_value */
+
+int plugin_dispatch_values (value_list_t const *vl)
+{
+ int status;
+ static pthread_mutex_t statistics_lock = PTHREAD_MUTEX_INITIALIZER;
+
+ if (check_drop_value ()) {
+ if(record_statistics) {
+ pthread_mutex_lock(&statistics_lock);
+ stats_values_dropped++;
+ pthread_mutex_unlock(&statistics_lock);
+ }
+ return (0);
+ }
+
+ status = plugin_write_enqueue (vl);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("plugin_dispatch_values: plugin_write_enqueue failed "
+ "with status %i (%s).", status,
+ sstrerror (status, errbuf, sizeof (errbuf)));
+ return (status);
+ }
+
+ return (0);
+}
+
+__attribute__((sentinel))
+int plugin_dispatch_multivalue (value_list_t const *template, /* {{{ */
+ _Bool store_percentage, ...)
+{
+ value_list_t *vl;
+ int failed = 0;
+ gauge_t sum = 0.0;
+ va_list ap;
+
+ assert (template->values_len == 1);
+
+ va_start (ap, store_percentage);
+ while (42)
+ {
+ char const *name;
+ gauge_t value;
+
+ name = va_arg (ap, char const *);
+ if (name == NULL)
+ break;
+
+ value = va_arg (ap, gauge_t);
+ if (!isnan (value))
+ sum += value;
+ }
+ va_end (ap);
+
+ vl = plugin_value_list_clone (template);
+ /* plugin_value_list_clone makes sure vl->time is set to non-zero. */
+ if (store_percentage)
+ sstrncpy (vl->type, "percent", sizeof (vl->type));
+
+ va_start (ap, store_percentage);
+ while (42)
+ {
+ char const *name;
+ int status;
+
+ /* Set the type instance. */
+ name = va_arg (ap, char const *);
+ if (name == NULL)
+ break;
+ sstrncpy (vl->type_instance, name, sizeof (vl->type_instance));
+
+ /* Set the value. */
+ vl->values[0].gauge = va_arg (ap, gauge_t);
+ if (store_percentage)
+ vl->values[0].gauge *= 100.0 / sum;
+
+ status = plugin_write_enqueue (vl);
+ if (status != 0)
+ failed++;
+ }
+ va_end (ap);
+
+ plugin_value_list_free (vl);
+ return (failed);
+} /* }}} int plugin_dispatch_multivalue */
+
+int plugin_dispatch_notification (const notification_t *notif)
+{
+ llentry_t *le;
+ /* Possible TODO: Add flap detection here */
+
+ DEBUG ("plugin_dispatch_notification: severity = %i; message = %s; "
+ "time = %.3f; host = %s;",
+ notif->severity, notif->message,
+ CDTIME_T_TO_DOUBLE (notif->time), notif->host);
+
+ /* Nobody cares for notifications */
+ if (list_notification == NULL)
+ return (-1);
+
+ le = llist_head (list_notification);
+ while (le != NULL)
+ {
+ callback_func_t *cf;
+ plugin_notification_cb callback;
+ int status;
+
+ /* do not switch plugin context; rather keep the context
+ * (interval) information of the calling plugin */
+
+ cf = le->value;
+ callback = cf->cf_callback;
+ status = (*callback) (notif, &cf->cf_udata);
+ if (status != 0)
+ {
+ WARNING ("plugin_dispatch_notification: Notification "
+ "callback %s returned %i.",
+ le->key, status);
+ }
+
+ le = le->next;
+ }
+
+ return (0);
+} /* int plugin_dispatch_notification */
+
+void plugin_log (int level, const char *format, ...)
+{
+ char msg[1024];
+ va_list ap;
+ llentry_t *le;
+
+#if !COLLECT_DEBUG
+ if (level >= LOG_DEBUG)
+ return;
+#endif
+
+ va_start (ap, format);
+ vsnprintf (msg, sizeof (msg), format, ap);
+ msg[sizeof (msg) - 1] = '\0';
+ va_end (ap);
+
+ if (list_log == NULL)
+ {
+ fprintf (stderr, "%s\n", msg);
+ return;
+ }
+
+ le = llist_head (list_log);
+ while (le != NULL)
+ {
+ callback_func_t *cf;
+ plugin_log_cb callback;
+
+ cf = le->value;
+ callback = cf->cf_callback;
+
+ /* do not switch plugin context; rather keep the context
+ * (interval) information of the calling plugin */
+
+ (*callback) (level, msg, &cf->cf_udata);
+
+ le = le->next;
+ }
+} /* void plugin_log */
+
+int parse_log_severity (const char *severity)
+{
+ int log_level = -1;
+
+ if ((0 == strcasecmp (severity, "emerg"))
+ || (0 == strcasecmp (severity, "alert"))
+ || (0 == strcasecmp (severity, "crit"))
+ || (0 == strcasecmp (severity, "err")))
+ log_level = LOG_ERR;
+ else if (0 == strcasecmp (severity, "warning"))
+ log_level = LOG_WARNING;
+ else if (0 == strcasecmp (severity, "notice"))
+ log_level = LOG_NOTICE;
+ else if (0 == strcasecmp (severity, "info"))
+ log_level = LOG_INFO;
+#if COLLECT_DEBUG
+ else if (0 == strcasecmp (severity, "debug"))
+ log_level = LOG_DEBUG;
+#endif /* COLLECT_DEBUG */
+
+ return (log_level);
+} /* int parse_log_severity */
+
+int parse_notif_severity (const char *severity)
+{
+ int notif_severity = -1;
+
+ if (strcasecmp (severity, "FAILURE") == 0)
+ notif_severity = NOTIF_FAILURE;
+ else if (strcmp (severity, "OKAY") == 0)
+ notif_severity = NOTIF_OKAY;
+ else if ((strcmp (severity, "WARNING") == 0)
+ || (strcmp (severity, "WARN") == 0))
+ notif_severity = NOTIF_WARNING;
+
+ return (notif_severity);
+} /* int parse_notif_severity */
+
+const data_set_t *plugin_get_ds (const char *name)
+{
+ data_set_t *ds;
+
+ if (data_sets == NULL)
+ {
+ ERROR ("plugin_get_ds: No data sets are defined yet.");
+ return (NULL);
+ }
+
+ if (c_avl_get (data_sets, name, (void *) &ds) != 0)
+ {
+ DEBUG ("No such dataset registered: %s", name);
+ return (NULL);
+ }
+
+ return (ds);
+} /* data_set_t *plugin_get_ds */
+
+static int plugin_notification_meta_add (notification_t *n,
+ const char *name,
+ enum notification_meta_type_e type,
+ const void *value)
+{
+ notification_meta_t *meta;
+ notification_meta_t *tail;
+
+ if ((n == NULL) || (name == NULL) || (value == NULL))
+ {
+ ERROR ("plugin_notification_meta_add: A pointer is NULL!");
+ return (-1);
+ }
+
+ meta = (notification_meta_t *) malloc (sizeof (notification_meta_t));
+ if (meta == NULL)
+ {
+ ERROR ("plugin_notification_meta_add: malloc failed.");
+ return (-1);
+ }
+ memset (meta, 0, sizeof (notification_meta_t));
+
+ sstrncpy (meta->name, name, sizeof (meta->name));
+ meta->type = type;
+
+ switch (type)
+ {
+ case NM_TYPE_STRING:
+ {
+ meta->nm_value.nm_string = strdup ((const char *) value);
+ if (meta->nm_value.nm_string == NULL)
+ {
+ ERROR ("plugin_notification_meta_add: strdup failed.");
+ sfree (meta);
+ return (-1);
+ }
+ break;
+ }
+ case NM_TYPE_SIGNED_INT:
+ {
+ meta->nm_value.nm_signed_int = *((int64_t *) value);
+ break;
+ }
+ case NM_TYPE_UNSIGNED_INT:
+ {
+ meta->nm_value.nm_unsigned_int = *((uint64_t *) value);
+ break;
+ }
+ case NM_TYPE_DOUBLE:
+ {
+ meta->nm_value.nm_double = *((double *) value);
+ break;
+ }
+ case NM_TYPE_BOOLEAN:
+ {
+ meta->nm_value.nm_boolean = *((_Bool *) value);
+ break;
+ }
+ default:
+ {
+ ERROR ("plugin_notification_meta_add: Unknown type: %i", type);
+ sfree (meta);
+ return (-1);
+ }
+ } /* switch (type) */
+
+ meta->next = NULL;
+ tail = n->meta;
+ while ((tail != NULL) && (tail->next != NULL))
+ tail = tail->next;
+
+ if (tail == NULL)
+ n->meta = meta;
+ else
+ tail->next = meta;
+
+ return (0);
+} /* int plugin_notification_meta_add */
+
+int plugin_notification_meta_add_string (notification_t *n,
+ const char *name,
+ const char *value)
+{
+ return (plugin_notification_meta_add (n, name, NM_TYPE_STRING, value));
+}
+
+int plugin_notification_meta_add_signed_int (notification_t *n,
+ const char *name,
+ int64_t value)
+{
+ return (plugin_notification_meta_add (n, name, NM_TYPE_SIGNED_INT, &value));
+}
+
+int plugin_notification_meta_add_unsigned_int (notification_t *n,
+ const char *name,
+ uint64_t value)
+{
+ return (plugin_notification_meta_add (n, name, NM_TYPE_UNSIGNED_INT, &value));
+}
+
+int plugin_notification_meta_add_double (notification_t *n,
+ const char *name,
+ double value)
+{
+ return (plugin_notification_meta_add (n, name, NM_TYPE_DOUBLE, &value));
+}
+
+int plugin_notification_meta_add_boolean (notification_t *n,
+ const char *name,
+ _Bool value)
+{
+ return (plugin_notification_meta_add (n, name, NM_TYPE_BOOLEAN, &value));
+}
+
+int plugin_notification_meta_copy (notification_t *dst,
+ const notification_t *src)
+{
+ notification_meta_t *meta;
+
+ assert (dst != NULL);
+ assert (src != NULL);
+ assert (dst != src);
+ assert ((src->meta == NULL) || (src->meta != dst->meta));
+
+ for (meta = src->meta; meta != NULL; meta = meta->next)
+ {
+ if (meta->type == NM_TYPE_STRING)
+ plugin_notification_meta_add_string (dst, meta->name,
+ meta->nm_value.nm_string);
+ else if (meta->type == NM_TYPE_SIGNED_INT)
+ plugin_notification_meta_add_signed_int (dst, meta->name,
+ meta->nm_value.nm_signed_int);
+ else if (meta->type == NM_TYPE_UNSIGNED_INT)
+ plugin_notification_meta_add_unsigned_int (dst, meta->name,
+ meta->nm_value.nm_unsigned_int);
+ else if (meta->type == NM_TYPE_DOUBLE)
+ plugin_notification_meta_add_double (dst, meta->name,
+ meta->nm_value.nm_double);
+ else if (meta->type == NM_TYPE_BOOLEAN)
+ plugin_notification_meta_add_boolean (dst, meta->name,
+ meta->nm_value.nm_boolean);
+ }
+
+ return (0);
+} /* int plugin_notification_meta_copy */
+
+int plugin_notification_meta_free (notification_meta_t *n)
+{
+ notification_meta_t *this;
+ notification_meta_t *next;
+
+ if (n == NULL)
+ {
+ ERROR ("plugin_notification_meta_free: n == NULL!");
+ return (-1);
+ }
+
+ this = n;
+ while (this != NULL)
+ {
+ next = this->next;
+
+ if (this->type == NM_TYPE_STRING)
+ {
+ free ((char *)this->nm_value.nm_string);
+ this->nm_value.nm_string = NULL;
+ }
+ sfree (this);
+
+ this = next;
+ }
+
+ return (0);
+} /* int plugin_notification_meta_free */
+
+static void plugin_ctx_destructor (void *ctx)
+{
+ sfree (ctx);
+} /* void plugin_ctx_destructor */
+
+static plugin_ctx_t ctx_init = { /* interval = */ 0 };
+
+static plugin_ctx_t *plugin_ctx_create (void)
+{
+ plugin_ctx_t *ctx;
+
+ ctx = malloc (sizeof (*ctx));
+ if (ctx == NULL) {
+ char errbuf[1024];
+ ERROR ("Failed to allocate plugin context: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return NULL;
+ }
+
+ *ctx = ctx_init;
+ assert (plugin_ctx_key_initialized);
+ pthread_setspecific (plugin_ctx_key, ctx);
+ DEBUG("Created new plugin context.");
+ return (ctx);
+} /* int plugin_ctx_create */
+
+void plugin_init_ctx (void)
+{
+ pthread_key_create (&plugin_ctx_key, plugin_ctx_destructor);
+ plugin_ctx_key_initialized = 1;
+} /* void plugin_init_ctx */
+
+plugin_ctx_t plugin_get_ctx (void)
+{
+ plugin_ctx_t *ctx;
+
+ assert (plugin_ctx_key_initialized);
+ ctx = pthread_getspecific (plugin_ctx_key);
+
+ if (ctx == NULL) {
+ ctx = plugin_ctx_create ();
+ /* this must no happen -- exit() instead? */
+ if (ctx == NULL)
+ return ctx_init;
+ }
+
+ return (*ctx);
+} /* plugin_ctx_t plugin_get_ctx */
+
+plugin_ctx_t plugin_set_ctx (plugin_ctx_t ctx)
+{
+ plugin_ctx_t *c;
+ plugin_ctx_t old;
+
+ assert (plugin_ctx_key_initialized);
+ c = pthread_getspecific (plugin_ctx_key);
+
+ if (c == NULL) {
+ c = plugin_ctx_create ();
+ /* this must no happen -- exit() instead? */
+ if (c == NULL)
+ return ctx_init;
+ }
+
+ old = *c;
+ *c = ctx;
+
+ return (old);
+} /* void plugin_set_ctx */
+
+cdtime_t plugin_get_interval (void)
+{
+ cdtime_t interval;
+
+ interval = plugin_get_ctx().interval;
+ if (interval > 0)
+ return interval;
+
+ return cf_get_default_interval ();
+} /* cdtime_t plugin_get_interval */
+
+typedef struct {
+ plugin_ctx_t ctx;
+ void *(*start_routine) (void *);
+ void *arg;
+} plugin_thread_t;
+
+static void *plugin_thread_start (void *arg)
+{
+ plugin_thread_t *plugin_thread = arg;
+
+ void *(*start_routine) (void *) = plugin_thread->start_routine;
+ void *plugin_arg = plugin_thread->arg;
+
+ plugin_set_ctx (plugin_thread->ctx);
+
+ free (plugin_thread);
+
+ return start_routine (plugin_arg);
+} /* void *plugin_thread_start */
+
+int plugin_thread_create (pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine) (void *), void *arg)
+{
+ plugin_thread_t *plugin_thread;
+
+ plugin_thread = malloc (sizeof (*plugin_thread));
+ if (plugin_thread == NULL)
+ return -1;
+
+ plugin_thread->ctx = plugin_get_ctx ();
+ plugin_thread->start_routine = start_routine;
+ plugin_thread->arg = arg;
+
+ return pthread_create (thread, attr,
+ plugin_thread_start, plugin_thread);
+} /* int plugin_thread_create */
+
+/* vim: set sw=8 ts=8 noet fdm=marker : */
diff --git a/src/daemon/plugin.h b/src/daemon/plugin.h
--- /dev/null
+++ b/src/daemon/plugin.h
@@ -0,0 +1,437 @@
+/**
+ * collectd - src/plugin.h
+ * Copyright (C) 2005-2014 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ * Sebastian Harl <sh at tokkee.org>
+ **/
+
+#ifndef PLUGIN_H
+#define PLUGIN_H
+
+#include "collectd.h"
+#include "configfile.h"
+#include "meta_data.h"
+#include "utils_time.h"
+
+#define PLUGIN_FLAGS_GLOBAL 0x0001
+
+#define DATA_MAX_NAME_LEN 64
+
+#define DS_TYPE_COUNTER 0
+#define DS_TYPE_GAUGE 1
+#define DS_TYPE_DERIVE 2
+#define DS_TYPE_ABSOLUTE 3
+
+#define DS_TYPE_TO_STRING(t) (t == DS_TYPE_COUNTER) ? "counter" : \
+ (t == DS_TYPE_GAUGE) ? "gauge" : \
+ (t == DS_TYPE_DERIVE) ? "derive" : \
+ (t == DS_TYPE_ABSOLUTE) ? "absolute" : \
+ "unknown"
+
+
+#ifndef LOG_ERR
+# define LOG_ERR 3
+#endif
+#ifndef LOG_WARNING
+# define LOG_WARNING 4
+#endif
+#ifndef LOG_NOTICE
+# define LOG_NOTICE 5
+#endif
+#ifndef LOG_INFO
+# define LOG_INFO 6
+#endif
+#ifndef LOG_DEBUG
+# define LOG_DEBUG 7
+#endif
+
+#define NOTIF_MAX_MSG_LEN 256
+
+#define NOTIF_FAILURE 1
+#define NOTIF_WARNING 2
+#define NOTIF_OKAY 4
+
+#define plugin_interval (plugin_get_ctx().interval)
+
+/*
+ * Public data types
+ */
+typedef unsigned long long counter_t;
+typedef double gauge_t;
+typedef int64_t derive_t;
+typedef uint64_t absolute_t;
+
+union value_u
+{
+ counter_t counter;
+ gauge_t gauge;
+ derive_t derive;
+ absolute_t absolute;
+};
+typedef union value_u value_t;
+
+struct value_list_s
+{
+ value_t *values;
+ int values_len;
+ cdtime_t time;
+ cdtime_t interval;
+ char host[DATA_MAX_NAME_LEN];
+ char plugin[DATA_MAX_NAME_LEN];
+ char plugin_instance[DATA_MAX_NAME_LEN];
+ char type[DATA_MAX_NAME_LEN];
+ char type_instance[DATA_MAX_NAME_LEN];
+ meta_data_t *meta;
+};
+typedef struct value_list_s value_list_t;
+
+#define VALUE_LIST_INIT { NULL, 0, 0, plugin_get_interval (), \
+ "localhost", "", "", "", "", NULL }
+#define VALUE_LIST_STATIC { NULL, 0, 0, 0, "localhost", "", "", "", "", NULL }
+
+struct data_source_s
+{
+ char name[DATA_MAX_NAME_LEN];
+ int type;
+ double min;
+ double max;
+};
+typedef struct data_source_s data_source_t;
+
+struct data_set_s
+{
+ char type[DATA_MAX_NAME_LEN];
+ int ds_num;
+ data_source_t *ds;
+};
+typedef struct data_set_s data_set_t;
+
+enum notification_meta_type_e
+{
+ NM_TYPE_STRING,
+ NM_TYPE_SIGNED_INT,
+ NM_TYPE_UNSIGNED_INT,
+ NM_TYPE_DOUBLE,
+ NM_TYPE_BOOLEAN
+};
+
+typedef struct notification_meta_s
+{
+ char name[DATA_MAX_NAME_LEN];
+ enum notification_meta_type_e type;
+ union
+ {
+ const char *nm_string;
+ int64_t nm_signed_int;
+ uint64_t nm_unsigned_int;
+ double nm_double;
+ _Bool nm_boolean;
+ } nm_value;
+ struct notification_meta_s *next;
+} notification_meta_t;
+
+typedef struct notification_s
+{
+ int severity;
+ cdtime_t time;
+ char message[NOTIF_MAX_MSG_LEN];
+ char host[DATA_MAX_NAME_LEN];
+ char plugin[DATA_MAX_NAME_LEN];
+ char plugin_instance[DATA_MAX_NAME_LEN];
+ char type[DATA_MAX_NAME_LEN];
+ char type_instance[DATA_MAX_NAME_LEN];
+ notification_meta_t *meta;
+} notification_t;
+
+struct user_data_s
+{
+ void *data;
+ void (*free_func) (void *);
+};
+typedef struct user_data_s user_data_t;
+
+struct plugin_ctx_s
+{
+ cdtime_t interval;
+};
+typedef struct plugin_ctx_s plugin_ctx_t;
+
+/*
+ * Callback types
+ */
+typedef int (*plugin_init_cb) (void);
+typedef int (*plugin_read_cb) (user_data_t *);
+typedef int (*plugin_write_cb) (const data_set_t *, const value_list_t *,
+ user_data_t *);
+typedef int (*plugin_flush_cb) (cdtime_t timeout, const char *identifier,
+ user_data_t *);
+/* "missing" callback. Returns less than zero on failure, zero if other
+ * callbacks should be called, greater than zero if no more callbacks should be
+ * called. */
+typedef int (*plugin_missing_cb) (const value_list_t *, user_data_t *);
+typedef void (*plugin_log_cb) (int severity, const char *message,
+ user_data_t *);
+typedef int (*plugin_shutdown_cb) (void);
+typedef int (*plugin_notification_cb) (const notification_t *,
+ user_data_t *);
+
+/*
+ * NAME
+ * plugin_set_dir
+ *
+ * DESCRIPTION
+ * Sets the current `plugindir'
+ *
+ * ARGUMENTS
+ * `dir' Path to the plugin directory
+ *
+ * NOTES
+ * If `dir' is NULL the compiled in default `PLUGINDIR' is used.
+ */
+void plugin_set_dir (const char *dir);
+
+/*
+ * NAME
+ * plugin_load
+ *
+ * DESCRIPTION
+ * Searches the current `plugindir' (see `plugin_set_dir') for the plugin
+ * named $type and loads it. Afterwards the plugin's `module_register'
+ * function is called, which then calls `plugin_register' to register callback
+ * functions.
+ *
+ * ARGUMENTS
+ * `name' Name of the plugin to load.
+ * `flags' Hints on how to handle this plugin.
+ *
+ * RETURN VALUE
+ * Returns zero upon success, a value greater than zero if no plugin was found
+ * and a value below zero if an error occurs.
+ *
+ * NOTES
+ * Re-loading an already loaded module is detected and zero is returned in
+ * this case.
+ */
+int plugin_load (const char *name, uint32_t flags);
+
+void plugin_init_all (void);
+void plugin_read_all (void);
+int plugin_read_all_once (void);
+void plugin_shutdown_all (void);
+
+/*
+ * NAME
+ * plugin_write
+ *
+ * DESCRIPTION
+ * Calls the write function of the given plugin with the provided data set and
+ * value list. It differs from `plugin_dispatch_value' in that it does not
+ * update the cache, does not do threshold checking, call the chain subsystem
+ * and so on. It looks up the requested plugin and invokes the function, end
+ * of story.
+ *
+ * ARGUMENTS
+ * plugin Name of the plugin. If NULL, the value is sent to all registered
+ * write functions.
+ * ds Pointer to the data_set_t structure. If NULL, the data set is
+ * looked up according to the `type' member in the `vl' argument.
+ * vl The actual value to be processed. Must not be NULL.
+ *
+ * RETURN VALUE
+ * Returns zero upon success or non-zero if an error occurred. If `plugin' is
+ * NULL and more than one plugin is called, an error is only returned if *all*
+ * plugins fail.
+ *
+ * NOTES
+ * This is the function used by the `write' built-in target. May be used by
+ * other target plugins.
+ */
+int plugin_write (const char *plugin,
+ const data_set_t *ds, const value_list_t *vl);
+
+int plugin_flush (const char *plugin, cdtime_t timeout, const char *identifier);
+
+/*
+ * The `plugin_register_*' functions are used to make `config', `init',
+ * `read', `write' and `shutdown' functions known to the plugin
+ * infrastructure. Also, the data-formats are made public like this.
+ */
+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,
+ plugin_init_cb callback);
+int plugin_register_read (const char *name,
+ int (*callback) (void));
+/* "user_data" will be freed automatically, unless
+ * "plugin_register_complex_read" returns an error (non-zero). */
+int plugin_register_complex_read (const char *group, const char *name,
+ plugin_read_cb callback,
+ const struct timespec *interval,
+ user_data_t *user_data);
+int plugin_register_write (const char *name,
+ plugin_write_cb callback, user_data_t *user_data);
+int plugin_register_flush (const char *name,
+ plugin_flush_cb callback, user_data_t *user_data);
+int plugin_register_missing (const char *name,
+ plugin_missing_cb callback, user_data_t *user_data);
+int plugin_register_shutdown (const char *name,
+ plugin_shutdown_cb callback);
+int plugin_register_data_set (const data_set_t *ds);
+int plugin_register_log (const char *name,
+ plugin_log_cb callback, user_data_t *user_data);
+int plugin_register_notification (const char *name,
+ plugin_notification_cb callback, user_data_t *user_data);
+
+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_read_group (const char *group);
+int plugin_unregister_write (const char *name);
+int plugin_unregister_flush (const char *name);
+int plugin_unregister_missing (const char *name);
+int plugin_unregister_shutdown (const char *name);
+int plugin_unregister_data_set (const char *name);
+int plugin_unregister_log (const char *name);
+int plugin_unregister_notification (const char *name);
+
+
+/*
+ * NAME
+ * plugin_dispatch_values
+ *
+ * DESCRIPTION
+ * This function is called by reading processes with the values they've
+ * aquired. The function fetches the data-set definition (that has been
+ * registered using `plugin_register_data_set') and calls _all_ registered
+ * write-functions.
+ *
+ * ARGUMENTS
+ * `vl' Value list of the values that have been read by a `read'
+ * function.
+ */
+int plugin_dispatch_values (value_list_t const *vl);
+
+/*
+ * NAME
+ * plugin_dispatch_multivalue
+ *
+ * SYNOPSIS
+ * plugin_dispatch_multivalue (vl, 1,
+ * "free", 42.0,
+ * "used", 58.0,
+ * NULL);
+ *
+ * DESCRIPTION
+ * Takes a list of type instances and values and dispatches that in a batch,
+ * making sure that all values have the same time stamp. If "store_percentage"
+ * is set to true, the "type" is set to "percent" and a percentage is
+ * calculated and dispatched, rather than the absolute values. Values that are
+ * NaN are dispatched as NaN and will not influence the total.
+ *
+ * The variadic arguments is a list of type_instance / gauge pairs, that are
+ * interpreted as type "char const *" and "gauge_t". The last argument must be
+ * a NULL pointer to signal end-of-list.
+ *
+ * RETURNS
+ * The number of values it failed to dispatch (zero on success).
+ */
+__attribute__((sentinel))
+int plugin_dispatch_multivalue (value_list_t const *vl,
+ _Bool store_percentage, ...);
+
+int plugin_dispatch_missing (const value_list_t *vl);
+
+int plugin_dispatch_notification (const notification_t *notif);
+
+void plugin_log (int level, const char *format, ...)
+ __attribute__ ((format(printf,2,3)));
+
+/* These functions return the parsed severity or less than zero on failure. */
+int parse_log_severity (const char *severity);
+int parse_notif_severity (const char *severity);
+
+#define ERROR(...) plugin_log (LOG_ERR, __VA_ARGS__)
+#define WARNING(...) plugin_log (LOG_WARNING, __VA_ARGS__)
+#define NOTICE(...) plugin_log (LOG_NOTICE, __VA_ARGS__)
+#define INFO(...) plugin_log (LOG_INFO, __VA_ARGS__)
+#if COLLECT_DEBUG
+# define DEBUG(...) plugin_log (LOG_DEBUG, __VA_ARGS__)
+#else /* COLLECT_DEBUG */
+# define DEBUG(...) /* noop */
+#endif /* ! COLLECT_DEBUG */
+
+const data_set_t *plugin_get_ds (const char *name);
+
+int plugin_notification_meta_add_string (notification_t *n,
+ const char *name,
+ const char *value);
+int plugin_notification_meta_add_signed_int (notification_t *n,
+ const char *name,
+ int64_t value);
+int plugin_notification_meta_add_unsigned_int (notification_t *n,
+ const char *name,
+ uint64_t value);
+int plugin_notification_meta_add_double (notification_t *n,
+ const char *name,
+ double value);
+int plugin_notification_meta_add_boolean (notification_t *n,
+ const char *name,
+ _Bool value);
+
+int plugin_notification_meta_copy (notification_t *dst,
+ const notification_t *src);
+
+int plugin_notification_meta_free (notification_meta_t *n);
+
+/*
+ * Plugin context management.
+ */
+
+void plugin_init_ctx (void);
+
+plugin_ctx_t plugin_get_ctx (void);
+plugin_ctx_t plugin_set_ctx (plugin_ctx_t ctx);
+
+/*
+ * NAME
+ * plugin_get_interval
+ *
+ * DESCRIPTION
+ * This function returns the current value of the plugin's interval. The
+ * return value will be strictly greater than zero in all cases. If
+ * everything else fails, it will fall back to 10 seconds.
+ */
+cdtime_t plugin_get_interval (void);
+
+/*
+ * Context-aware thread management.
+ */
+
+int plugin_thread_create (pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine) (void *), void *arg);
+
+#endif /* PLUGIN_H */
diff --git a/src/daemon/types_list.c b/src/daemon/types_list.c
--- /dev/null
+++ b/src/daemon/types_list.c
@@ -0,0 +1,207 @@
+/**
+ * collectd - src/types_list.c
+ * Copyright (C) 2007 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+
+#include "plugin.h"
+#include "configfile.h"
+
+static int parse_ds (data_source_t *dsrc, char *buf, size_t buf_len)
+{
+ char *dummy;
+ char *saveptr;
+ char *fields[8];
+ int fields_num;
+
+ if (buf_len < 11)
+ {
+ ERROR ("parse_ds: (buf_len = %zu) < 11", buf_len);
+ return (-1);
+ }
+
+ if (buf[buf_len - 1] == ',')
+ {
+ buf_len--;
+ buf[buf_len] = '\0';
+ }
+
+ dummy = buf;
+ saveptr = NULL;
+
+ fields_num = 0;
+ while (fields_num < 8)
+ {
+ if ((fields[fields_num] = strtok_r (dummy, ":", &saveptr)) == NULL)
+ break;
+ dummy = NULL;
+ fields_num++;
+ }
+
+ if (fields_num != 4)
+ {
+ ERROR ("parse_ds: (fields_num = %i) != 4", fields_num);
+ return (-1);
+ }
+
+ sstrncpy (dsrc->name, fields[0], sizeof (dsrc->name));
+
+ if (strcasecmp (fields[1], "GAUGE") == 0)
+ dsrc->type = DS_TYPE_GAUGE;
+ else if (strcasecmp (fields[1], "COUNTER") == 0)
+ dsrc->type = DS_TYPE_COUNTER;
+ else if (strcasecmp (fields[1], "DERIVE") == 0)
+ dsrc->type = DS_TYPE_DERIVE;
+ else if (strcasecmp (fields[1], "ABSOLUTE") == 0)
+ dsrc->type = DS_TYPE_ABSOLUTE;
+ else
+ {
+ ERROR ("(fields[1] = %s) != (GAUGE || COUNTER || DERIVE || ABSOLUTE)", fields[1]);
+ return (-1);
+ }
+
+ if (strcasecmp (fields[2], "U") == 0)
+ dsrc->min = NAN;
+ else
+ dsrc->min = atof (fields[2]);
+
+ if (strcasecmp (fields[3], "U") == 0)
+ dsrc->max = NAN;
+ else
+ dsrc->max = atof (fields[3]);
+
+ return (0);
+} /* int parse_ds */
+
+static void parse_line (char *buf)
+{
+ char *fields[64];
+ size_t fields_num;
+ data_set_t *ds;
+ int i;
+
+ fields_num = strsplit (buf, fields, 64);
+ if (fields_num < 2)
+ return;
+
+ /* Ignore lines which begin with a hash sign. */
+ if (fields[0][0] == '#')
+ return;
+
+ ds = (data_set_t *) malloc (sizeof (data_set_t));
+ if (ds == NULL)
+ return;
+
+ memset (ds, '\0', sizeof (data_set_t));
+
+ sstrncpy (ds->type, fields[0], sizeof (ds->type));
+
+ ds->ds_num = fields_num - 1;
+ ds->ds = (data_source_t *) calloc (ds->ds_num, sizeof (data_source_t));
+ if (ds->ds == NULL)
+ return;
+
+ for (i = 0; i < ds->ds_num; i++)
+ if (parse_ds (ds->ds + i, fields[i + 1], strlen (fields[i + 1])) != 0)
+ {
+ sfree (ds->ds);
+ ERROR ("types_list: parse_line: Cannot parse data source #%i "
+ "of data set %s", i, ds->type);
+ return;
+ }
+
+ plugin_register_data_set (ds);
+
+ sfree (ds->ds);
+ sfree (ds);
+} /* void parse_line */
+
+static void parse_file (FILE *fh)
+{
+ char buf[4096];
+ size_t buf_len;
+
+ while (fgets (buf, sizeof (buf), fh) != NULL)
+ {
+ buf_len = strlen (buf);
+
+ if (buf_len >= 4095)
+ {
+ NOTICE ("Skipping line with more than 4095 characters.");
+ do
+ {
+ if (fgets (buf, sizeof (buf), fh) == NULL)
+ break;
+ buf_len = strlen (buf);
+ } while (buf_len >= 4095);
+ continue;
+ } /* if (buf_len >= 4095) */
+
+ if ((buf_len == 0) || (buf[0] == '#'))
+ continue;
+
+ while ((buf_len > 0) && ((buf[buf_len - 1] == '\n')
+ || (buf[buf_len - 1] == '\n')))
+ buf[--buf_len] = '\0';
+
+ if (buf_len == 0)
+ continue;
+
+ parse_line (buf);
+ } /* while (fgets) */
+} /* void parse_file */
+
+int read_types_list (const char *file)
+{
+ FILE *fh;
+
+ if (file == NULL)
+ return (-1);
+
+ fh = fopen (file, "r");
+ if (fh == NULL)
+ {
+ char errbuf[1024];
+ fprintf (stderr, "Failed to open types database `%s': %s.\n",
+ file, sstrerror (errno, errbuf, sizeof (errbuf)));
+ ERROR ("Failed to open types database `%s': %s",
+ file, sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ parse_file (fh);
+
+ fclose (fh);
+ fh = NULL;
+
+ DEBUG ("Done parsing `%s'", file);
+
+ return (0);
+} /* int read_types_list */
+
+/*
+ * vim: shiftwidth=2:softtabstop=2:tabstop=8
+ */
diff --git a/src/daemon/types_list.h b/src/daemon/types_list.h
--- /dev/null
+++ b/src/daemon/types_list.h
@@ -0,0 +1,32 @@
+/**
+ * collectd - src/types_list.h
+ * Copyright (C) 2007 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#ifndef TYPES_LIST_H
+#define TYPES_LIST_H 1
+
+int read_types_list (const char *file);
+
+#endif /* TYPES_LIST_H */
diff --git a/src/daemon/utils_avltree.c b/src/daemon/utils_avltree.c
--- /dev/null
@@ -0,0 +1,730 @@
+/**
+ * collectd - src/utils_avltree.c
+ * Copyright (C) 2006,2007 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "utils_avltree.h"
+
+#define BALANCE(n) ((((n)->left == NULL) ? 0 : (n)->left->height) \
+ - (((n)->right == NULL) ? 0 : (n)->right->height))
+
+/*
+ * private data types
+ */
+struct c_avl_node_s
+{
+ void *key;
+ void *value;
+
+ int height;
+ struct c_avl_node_s *left;
+ struct c_avl_node_s *right;
+ struct c_avl_node_s *parent;
+};
+typedef struct c_avl_node_s c_avl_node_t;
+
+struct c_avl_tree_s
+{
+ c_avl_node_t *root;
+ int (*compare) (const void *, const void *);
+ int size;
+};
+
+struct c_avl_iterator_s
+{
+ c_avl_tree_t *tree;
+ c_avl_node_t *node;
+};
+
+/*
+ * private functions
+ */
+#if 0
+static void verify_tree (c_avl_node_t *n)
+{
+ if (n == NULL)
+ return;
+
+ verify_tree (n->left);
+ verify_tree (n->right);
+
+ assert ((BALANCE (n) >= -1) && (BALANCE (n) <= 1));
+ assert ((n->parent == NULL) || (n->parent->right == n) || (n->parent->left == n));
+} /* void verify_tree */
+#else
+# define verify_tree(n) /**/
+#endif
+
+static void free_node (c_avl_node_t *n)
+{
+ if (n == NULL)
+ return;
+
+ if (n->left != NULL)
+ free_node (n->left);
+ if (n->right != NULL)
+ free_node (n->right);
+
+ free (n);
+}
+
+static int calc_height (c_avl_node_t *n)
+{
+ int height_left;
+ int height_right;
+
+ if (n == NULL)
+ return (0);
+
+ height_left = (n->left == NULL) ? 0 : n->left->height;
+ height_right = (n->right == NULL) ? 0 : n->right->height;
+
+ return (((height_left > height_right)
+ ? height_left
+ : height_right) + 1);
+} /* int calc_height */
+
+static c_avl_node_t *search (c_avl_tree_t *t, const void *key)
+{
+ c_avl_node_t *n;
+ int cmp;
+
+ n = t->root;
+ while (n != NULL)
+ {
+ cmp = t->compare (key, n->key);
+ if (cmp == 0)
+ return (n);
+ else if (cmp < 0)
+ n = n->left;
+ else
+ n = n->right;
+ }
+
+ return (NULL);
+}
+
+/* (x) (y)
+ * / \ / \
+ * (y) /\ /\ (x)
+ * / \ /_c\ ==> / a\ / \
+ * /\ /\ /____\/\ /\
+ * / a\ /_b\ /_b\ /_c\
+ * /____\
+ */
+static c_avl_node_t *rotate_right (c_avl_tree_t *t, c_avl_node_t *x)
+{
+ c_avl_node_t *p;
+ c_avl_node_t *y;
+ c_avl_node_t *b;
+
+ p = x->parent;
+ y = x->left;
+ b = y->right;
+
+ x->left = b;
+ if (b != NULL)
+ b->parent = x;
+
+ x->parent = y;
+ y->right = x;
+
+ y->parent = p;
+ assert ((p == NULL) || (p->left == x) || (p->right == x));
+ if (p == NULL)
+ t->root = y;
+ else if (p->left == x)
+ p->left = y;
+ else
+ p->right = y;
+
+ x->height = calc_height (x);
+ y->height = calc_height (y);
+
+ return (y);
+} /* void rotate_left */
+
+/*
+ * (x) (y)
+ * / \ / \
+ * /\ (y) (x) /\
+ * /_a\ / \ ==> / \ / c\
+ * /\ /\ /\ /\/____\
+ * /_b\ / c\ /_a\ /_b\
+ * /____\
+ */
+static c_avl_node_t *rotate_left (c_avl_tree_t *t, c_avl_node_t *x)
+{
+ c_avl_node_t *p;
+ c_avl_node_t *y;
+ c_avl_node_t *b;
+
+ p = x->parent;
+ y = x->right;
+ b = y->left;
+
+ x->right = b;
+ if (b != NULL)
+ b->parent = x;
+
+ x->parent = y;
+ y->left = x;
+
+ y->parent = p;
+ assert ((p == NULL) || (p->left == x) || (p->right == x));
+ if (p == NULL)
+ t->root = y;
+ else if (p->left == x)
+ p->left = y;
+ else
+ p->right = y;
+
+ x->height = calc_height (x);
+ y->height = calc_height (y);
+
+ return (y);
+} /* void rotate_left */
+
+static c_avl_node_t *rotate_left_right (c_avl_tree_t *t, c_avl_node_t *x)
+{
+ rotate_left (t, x->left);
+ return (rotate_right (t, x));
+} /* void rotate_left_right */
+
+static c_avl_node_t *rotate_right_left (c_avl_tree_t *t, c_avl_node_t *x)
+{
+ rotate_right (t, x->right);
+ return (rotate_left (t, x));
+} /* void rotate_right_left */
+
+static void rebalance (c_avl_tree_t *t, c_avl_node_t *n)
+{
+ int b_top;
+ int b_bottom;
+
+ while (n != NULL)
+ {
+ b_top = BALANCE (n);
+ assert ((b_top >= -2) && (b_top <= 2));
+
+ if (b_top == -2)
+ {
+ assert (n->right != NULL);
+ b_bottom = BALANCE (n->right);
+ assert ((b_bottom >= -1) || (b_bottom <= 1));
+ if (b_bottom == 1)
+ n = rotate_right_left (t, n);
+ else
+ n = rotate_left (t, n);
+ }
+ else if (b_top == 2)
+ {
+ assert (n->left != NULL);
+ b_bottom = BALANCE (n->left);
+ assert ((b_bottom >= -1) || (b_bottom <= 1));
+ if (b_bottom == -1)
+ n = rotate_left_right (t, n);
+ else
+ n = rotate_right (t, n);
+ }
+ else
+ {
+ int height = calc_height (n);
+ if (height == n->height)
+ break;
+ n->height = height;
+ }
+
+ assert (n->height == calc_height (n));
+
+ n = n->parent;
+ } /* while (n != NULL) */
+} /* void rebalance */
+
+static c_avl_node_t *c_avl_node_next (c_avl_node_t *n)
+{
+ c_avl_node_t *r; /* return node */
+
+ if (n == NULL)
+ {
+ return (NULL);
+ }
+
+ /* If we can't descent any further, we have to backtrack to the first
+ * parent that's bigger than we, i. e. who's _left_ child we are. */
+ if (n->right == NULL)
+ {
+ r = n->parent;
+ while ((r != NULL) && (r->parent != NULL))
+ {
+ if (r->left == n)
+ break;
+ n = r;
+ r = n->parent;
+ }
+
+ /* n->right == NULL && r == NULL => t is root and has no next
+ * r->left != n => r->right = n => r->parent == NULL */
+ if ((r == NULL) || (r->left != n))
+ {
+ assert ((r == NULL) || (r->parent == NULL));
+ return (NULL);
+ }
+ else
+ {
+ assert (r->left == n);
+ return (r);
+ }
+ }
+ else
+ {
+ r = n->right;
+ while (r->left != NULL)
+ r = r->left;
+ }
+
+ return (r);
+} /* c_avl_node_t *c_avl_node_next */
+
+static c_avl_node_t *c_avl_node_prev (c_avl_node_t *n)
+{
+ c_avl_node_t *r; /* return node */
+
+ if (n == NULL)
+ {
+ return (NULL);
+ }
+
+ /* If we can't descent any further, we have to backtrack to the first
+ * parent that's smaller than we, i. e. who's _right_ child we are. */
+ if (n->left == NULL)
+ {
+ r = n->parent;
+ while ((r != NULL) && (r->parent != NULL))
+ {
+ if (r->right == n)
+ break;
+ n = r;
+ r = n->parent;
+ }
+
+ /* n->left == NULL && r == NULL => t is root and has no next
+ * r->right != n => r->left = n => r->parent == NULL */
+ if ((r == NULL) || (r->right != n))
+ {
+ assert ((r == NULL) || (r->parent == NULL));
+ return (NULL);
+ }
+ else
+ {
+ assert (r->right == n);
+ return (r);
+ }
+ }
+ else
+ {
+ r = n->left;
+ while (r->right != NULL)
+ r = r->right;
+ }
+
+ return (r);
+} /* c_avl_node_t *c_avl_node_prev */
+
+static int _remove (c_avl_tree_t *t, c_avl_node_t *n)
+{
+ assert ((t != NULL) && (n != NULL));
+
+ if ((n->left != NULL) && (n->right != NULL))
+ {
+ c_avl_node_t *r; /* replacement node */
+ if (BALANCE (n) > 0) /* left subtree is higher */
+ {
+ assert (n->left != NULL);
+ r = c_avl_node_prev (n);
+
+ }
+ else /* right subtree is higher */
+ {
+ assert (n->right != NULL);
+ r = c_avl_node_next (n);
+ }
+
+ assert ((r->left == NULL) || (r->right == NULL));
+
+ /* copy content */
+ n->key = r->key;
+ n->value = r->value;
+
+ n = r;
+ }
+
+ assert ((n->left == NULL) || (n->right == NULL));
+
+ if ((n->left == NULL) && (n->right == NULL))
+ {
+ /* Deleting a leave is easy */
+ if (n->parent == NULL)
+ {
+ assert (t->root == n);
+ t->root = NULL;
+ }
+ else
+ {
+ assert ((n->parent->left == n)
+ || (n->parent->right == n));
+ if (n->parent->left == n)
+ n->parent->left = NULL;
+ else
+ n->parent->right = NULL;
+
+ rebalance (t, n->parent);
+ }
+
+ free_node (n);
+ }
+ else if (n->left == NULL)
+ {
+ assert (BALANCE (n) == -1);
+ assert ((n->parent == NULL) || (n->parent->left == n) || (n->parent->right == n));
+ if (n->parent == NULL)
+ {
+ assert (t->root == n);
+ t->root = n->right;
+ }
+ else if (n->parent->left == n)
+ {
+ n->parent->left = n->right;
+ }
+ else
+ {
+ n->parent->right = n->right;
+ }
+ n->right->parent = n->parent;
+
+ if (n->parent != NULL)
+ rebalance (t, n->parent);
+
+ n->right = NULL;
+ free_node (n);
+ }
+ else if (n->right == NULL)
+ {
+ assert (BALANCE (n) == 1);
+ assert ((n->parent == NULL) || (n->parent->left == n) || (n->parent->right == n));
+ if (n->parent == NULL)
+ {
+ assert (t->root == n);
+ t->root = n->left;
+ }
+ else if (n->parent->left == n)
+ {
+ n->parent->left = n->left;
+ }
+ else
+ {
+ n->parent->right = n->left;
+ }
+ n->left->parent = n->parent;
+
+ if (n->parent != NULL)
+ rebalance (t, n->parent);
+
+ n->left = NULL;
+ free_node (n);
+ }
+ else
+ {
+ assert (0);
+ }
+
+ return (0);
+} /* void *_remove */
+
+/*
+ * public functions
+ */
+c_avl_tree_t *c_avl_create (int (*compare) (const void *, const void *))
+{
+ c_avl_tree_t *t;
+
+ if (compare == NULL)
+ return (NULL);
+
+ if ((t = (c_avl_tree_t *) malloc (sizeof (c_avl_tree_t))) == NULL)
+ return (NULL);
+
+ t->root = NULL;
+ t->compare = compare;
+ t->size = 0;
+
+ return (t);
+}
+
+void c_avl_destroy (c_avl_tree_t *t)
+{
+ if (t == NULL)
+ return;
+ free_node (t->root);
+ free (t);
+}
+
+int c_avl_insert (c_avl_tree_t *t, void *key, void *value)
+{
+ c_avl_node_t *new;
+ c_avl_node_t *nptr;
+ int cmp;
+
+ if ((new = (c_avl_node_t *) malloc (sizeof (c_avl_node_t))) == NULL)
+ return (-1);
+
+ new->key = key;
+ new->value = value;
+ new->height = 1;
+ new->left = NULL;
+ new->right = NULL;
+
+ if (t->root == NULL)
+ {
+ new->parent = NULL;
+ t->root = new;
+ t->size = 1;
+ return (0);
+ }
+
+ nptr = t->root;
+ while (42)
+ {
+ cmp = t->compare (nptr->key, new->key);
+ if (cmp == 0)
+ {
+ free_node (new);
+ return (1);
+ }
+ else if (cmp < 0)
+ {
+ /* nptr < new */
+ if (nptr->right == NULL)
+ {
+ nptr->right = new;
+ new->parent = nptr;
+ rebalance (t, nptr);
+ break;
+ }
+ else
+ {
+ nptr = nptr->right;
+ }
+ }
+ else /* if (cmp > 0) */
+ {
+ /* nptr > new */
+ if (nptr->left == NULL)
+ {
+ nptr->left = new;
+ new->parent = nptr;
+ rebalance (t, nptr);
+ break;
+ }
+ else
+ {
+ nptr = nptr->left;
+ }
+ }
+ } /* while (42) */
+
+ verify_tree (t->root);
+ ++t->size;
+ return (0);
+} /* int c_avl_insert */
+
+int c_avl_remove (c_avl_tree_t *t, const void *key, void **rkey, void **rvalue)
+{
+ c_avl_node_t *n;
+ int status;
+
+ assert (t != NULL);
+
+ n = search (t, key);
+ if (n == NULL)
+ return (-1);
+
+ if (rkey != NULL)
+ *rkey = n->key;
+ if (rvalue != NULL)
+ *rvalue = n->value;
+
+ status = _remove (t, n);
+ verify_tree (t->root);
+ --t->size;
+ return (status);
+} /* void *c_avl_remove */
+
+int c_avl_get (c_avl_tree_t *t, const void *key, void **value)
+{
+ c_avl_node_t *n;
+
+ assert (t != NULL);
+
+ n = search (t, key);
+ if (n == NULL)
+ return (-1);
+
+ if (value != NULL)
+ *value = n->value;
+
+ return (0);
+}
+
+int c_avl_pick (c_avl_tree_t *t, void **key, void **value)
+{
+ c_avl_node_t *n;
+ c_avl_node_t *p;
+
+ if ((key == NULL) || (value == NULL))
+ return (-1);
+ if (t->root == NULL)
+ return (-1);
+
+ n = t->root;
+ while ((n->left != NULL) || (n->right != NULL))
+ {
+ int height_left = (n->left == NULL) ? 0 : n->left->height;
+ int height_right = (n->right == NULL) ? 0 : n->right->height;
+
+ if (height_left > height_right)
+ n = n->left;
+ else
+ n = n->right;
+ }
+
+ p = n->parent;
+ if (p == NULL)
+ t->root = NULL;
+ else if (p->left == n)
+ p->left = NULL;
+ else
+ p->right = NULL;
+
+ *key = n->key;
+ *value = n->value;
+
+ free_node (n);
+ rebalance (t, p);
+
+ return (0);
+} /* int c_avl_pick */
+
+c_avl_iterator_t *c_avl_get_iterator (c_avl_tree_t *t)
+{
+ c_avl_iterator_t *iter;
+
+ if (t == NULL)
+ return (NULL);
+
+ iter = (c_avl_iterator_t *) malloc (sizeof (c_avl_iterator_t));
+ if (iter == NULL)
+ return (NULL);
+ memset (iter, '\0', sizeof (c_avl_iterator_t));
+ iter->tree = t;
+
+ return (iter);
+} /* c_avl_iterator_t *c_avl_get_iterator */
+
+int c_avl_iterator_next (c_avl_iterator_t *iter, void **key, void **value)
+{
+ c_avl_node_t *n;
+
+ if ((iter == NULL) || (key == NULL) || (value == NULL))
+ return (-1);
+
+ if (iter->node == NULL)
+ {
+ for (n = iter->tree->root; n != NULL; n = n->left)
+ if (n->left == NULL)
+ break;
+ iter->node = n;
+ }
+ else
+ {
+ n = c_avl_node_next (iter->node);
+ }
+
+ if (n == NULL)
+ return (-1);
+
+ iter->node = n;
+ *key = n->key;
+ *value = n->value;
+
+ return (0);
+} /* int c_avl_iterator_next */
+
+int c_avl_iterator_prev (c_avl_iterator_t *iter, void **key, void **value)
+{
+ c_avl_node_t *n;
+
+ if ((iter == NULL) || (key == NULL) || (value == NULL))
+ return (-1);
+
+ if (iter->node == NULL)
+ {
+ for (n = iter->tree->root; n != NULL; n = n->left)
+ if (n->right == NULL)
+ break;
+ iter->node = n;
+ }
+ else
+ {
+ n = c_avl_node_prev (iter->node);
+ }
+
+ if (n == NULL)
+ return (-1);
+
+ iter->node = n;
+ *key = n->key;
+ *value = n->value;
+
+ return (0);
+} /* int c_avl_iterator_prev */
+
+void c_avl_iterator_destroy (c_avl_iterator_t *iter)
+{
+ free (iter);
+}
+
+int c_avl_size (c_avl_tree_t *t)
+{
+ if (t == NULL)
+ return (0);
+ return (t->size);
+}
diff --git a/src/daemon/utils_avltree.h b/src/daemon/utils_avltree.h
--- /dev/null
@@ -0,0 +1,170 @@
+/**
+ * collectd - src/utils_avltree.h
+ * Copyright (C) 2006,2007 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#ifndef UTILS_AVLTREE_H
+#define UTILS_AVLTREE_H 1
+
+struct c_avl_tree_s;
+typedef struct c_avl_tree_s c_avl_tree_t;
+
+struct c_avl_iterator_s;
+typedef struct c_avl_iterator_s c_avl_iterator_t;
+
+/*
+ * NAME
+ * c_avl_create
+ *
+ * DESCRIPTION
+ * Allocates a new AVL-tree.
+ *
+ * PARAMETERS
+ * `compare' The function-pointer `compare' is used to compare two keys. It
+ * has to return less than zero if it's first argument is smaller
+ * then the second argument, more than zero if the first argument
+ * is bigger than the second argument and zero if they are equal.
+ * If your keys are char-pointers, you can use the `strcmp'
+ * function from the libc here.
+ *
+ * RETURN VALUE
+ * A c_avl_tree_t-pointer upon success or NULL upon failure.
+ */
+c_avl_tree_t *c_avl_create (int (*compare) (const void *, const void *));
+
+
+/*
+ * NAME
+ * c_avl_destroy
+ *
+ * DESCRIPTION
+ * Deallocates an AVL-tree. Stored value- and key-pointer are lost, but of
+ * course not freed.
+ */
+void c_avl_destroy (c_avl_tree_t *t);
+
+/*
+ * NAME
+ * c_avl_insert
+ *
+ * DESCRIPTION
+ * Stores the key-value-pair in the AVL-tree pointed to by `t'.
+ *
+ * PARAMETERS
+ * `t' AVL-tree to store the data in.
+ * `key' Key used to store the value under. This is used to get back to
+ * the value again. The pointer is stored in an internal structure
+ * and _not_ copied. So the memory pointed to may _not_ be freed
+ * before this entry is removed. You can use the `rkey' argument
+ * to `avl_remove' to get the original pointer back and free it.
+ * `value' Value to be stored.
+ *
+ * RETURN VALUE
+ * Zero upon success, non-zero otherwise. It's less than zero if an error
+ * occurred or greater than zero if the key is already stored in the tree.
+ */
+int c_avl_insert (c_avl_tree_t *t, void *key, void *value);
+
+/*
+ * NAME
+ * c_avl_remove
+ *
+ * DESCRIPTION
+ * Removes a key-value-pair from the tree t. The stored key and value may be
+ * returned in `rkey' and `rvalue'.
+ *
+ * PARAMETERS
+ * `t' AVL-tree to remove key-value-pair from.
+ * `key' Key to identify the entry.
+ * `rkey' Pointer to a pointer in which to store the key. May be NULL.
+ * Since the `key' pointer is not copied when creating an entry,
+ * the pointer may not be available anymore from outside the tree.
+ * You can use this argument to get the actual pointer back and
+ * free the memory pointed to by it.
+ * `rvalue' Pointer to a pointer in which to store the value. May be NULL.
+ *
+ * RETURN VALUE
+ * Zero upon success or non-zero if the key isn't found in the tree.
+ */
+int c_avl_remove (c_avl_tree_t *t, const void *key, void **rkey, void **rvalue);
+
+/*
+ * NAME
+ * c_avl_get
+ *
+ * DESCRIPTION
+ * Retrieve the `value' belonging to `key'.
+ *
+ * PARAMETERS
+ * `t' AVL-tree to get the value from.
+ * `key' Key to identify the entry.
+ * `value' Pointer to a pointer in which to store the value. May be NULL.
+ *
+ * RETURN VALUE
+ * Zero upon success or non-zero if the key isn't found in the tree.
+ */
+int c_avl_get (c_avl_tree_t *t, const void *key, void **value);
+
+/*
+ * NAME
+ * c_avl_pick
+ *
+ * DESCRIPTION
+ * Remove a (pseudo-)random element from the tree and return it's `key' and
+ * `value'. Entries are not returned in any particular order. This function
+ * is intended for cache-flushes that don't care about the order but simply
+ * want to remove all elements, one at a time.
+ *
+ * PARAMETERS
+ * `t' AVL-tree to get the value from.
+ * `key' Pointer to a pointer in which to store the key.
+ * `value' Pointer to a pointer in which to store the value.
+ *
+ * RETURN VALUE
+ * Zero upon success or non-zero if the tree is empty or key or value is
+ * NULL.
+ */
+int c_avl_pick (c_avl_tree_t *t, void **key, void **value);
+
+c_avl_iterator_t *c_avl_get_iterator (c_avl_tree_t *t);
+int c_avl_iterator_next (c_avl_iterator_t *iter, void **key, void **value);
+int c_avl_iterator_prev (c_avl_iterator_t *iter, void **key, void **value);
+void c_avl_iterator_destroy (c_avl_iterator_t *iter);
+
+/*
+ * NAME
+ * c_avl_size
+ *
+ * DESCRIPTION
+ * Return the size (number of nodes) of the specified tree.
+ *
+ * PARAMETERS
+ * `t' AVL-tree to get the size of.
+ *
+ * RETURN VALUE
+ * Number of nodes in the tree, 0 if the tree is empty or NULL.
+ */
+int c_avl_size (c_avl_tree_t *t);
+
+#endif /* UTILS_AVLTREE_H */
diff --git a/src/daemon/utils_cache.c b/src/daemon/utils_cache.c
--- /dev/null
+++ b/src/daemon/utils_cache.c
@@ -0,0 +1,988 @@
+/**
+ * collectd - src/utils_cache.c
+ * Copyright (C) 2007-2010 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "utils_avltree.h"
+#include "utils_cache.h"
+#include "meta_data.h"
+
+#include <assert.h>
+#include <pthread.h>
+
+typedef struct cache_entry_s
+{
+ char name[6 * DATA_MAX_NAME_LEN];
+ int values_num;
+ gauge_t *values_gauge;
+ value_t *values_raw;
+ /* Time contained in the package
+ * (for calculating rates) */
+ cdtime_t last_time;
+ /* Time according to the local clock
+ * (for purging old entries) */
+ cdtime_t last_update;
+ /* Interval in which the data is collected
+ * (for purding old entries) */
+ cdtime_t interval;
+ int state;
+ int hits;
+
+ /*
+ * +-----+-----+-----+-----+-----+-----+-----+-----+-----+----
+ * ! 0 ! 1 ! 2 ! 3 ! 4 ! 5 ! 6 ! 7 ! 8 ! ...
+ * +-----+-----+-----+-----+-----+-----+-----+-----+-----+----
+ * ! ds0 ! ds1 ! ds2 ! ds0 ! ds1 ! ds2 ! ds0 ! ds1 ! ds2 ! ...
+ * +-----+-----+-----+-----+-----+-----+-----+-----+-----+----
+ * ! t = 0 ! t = 1 ! t = 2 ! ...
+ * +-----------------+-----------------+-----------------+----
+ */
+ gauge_t *history;
+ size_t history_index; /* points to the next position to write to. */
+ size_t history_length;
+
+ meta_data_t *meta;
+} cache_entry_t;
+
+static c_avl_tree_t *cache_tree = NULL;
+static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static int cache_compare (const cache_entry_t *a, const cache_entry_t *b)
+{
+#if COLLECT_DEBUG
+ assert ((a != NULL) && (b != NULL));
+#endif
+ return (strcmp (a->name, b->name));
+} /* int cache_compare */
+
+static cache_entry_t *cache_alloc (int values_num)
+{
+ cache_entry_t *ce;
+
+ ce = (cache_entry_t *) malloc (sizeof (cache_entry_t));
+ if (ce == NULL)
+ {
+ ERROR ("utils_cache: cache_alloc: malloc failed.");
+ return (NULL);
+ }
+ memset (ce, '\0', sizeof (cache_entry_t));
+ ce->values_num = values_num;
+
+ ce->values_gauge = calloc (values_num, sizeof (*ce->values_gauge));
+ ce->values_raw = calloc (values_num, sizeof (*ce->values_raw));
+ if ((ce->values_gauge == NULL) || (ce->values_raw == NULL))
+ {
+ sfree (ce->values_gauge);
+ sfree (ce->values_raw);
+ sfree (ce);
+ ERROR ("utils_cache: cache_alloc: calloc failed.");
+ return (NULL);
+ }
+
+ ce->history = NULL;
+ ce->history_length = 0;
+ ce->meta = NULL;
+
+ return (ce);
+} /* cache_entry_t *cache_alloc */
+
+static void cache_free (cache_entry_t *ce)
+{
+ if (ce == NULL)
+ return;
+
+ sfree (ce->values_gauge);
+ sfree (ce->values_raw);
+ sfree (ce->history);
+ if (ce->meta != NULL)
+ {
+ meta_data_destroy (ce->meta);
+ ce->meta = NULL;
+ }
+ sfree (ce);
+} /* void cache_free */
+
+static void uc_check_range (const data_set_t *ds, cache_entry_t *ce)
+{
+ int i;
+
+ for (i = 0; i < ds->ds_num; i++)
+ {
+ if (isnan (ce->values_gauge[i]))
+ continue;
+ else if (ce->values_gauge[i] < ds->ds[i].min)
+ ce->values_gauge[i] = NAN;
+ else if (ce->values_gauge[i] > ds->ds[i].max)
+ ce->values_gauge[i] = NAN;
+ }
+} /* void uc_check_range */
+
+static int uc_insert (const data_set_t *ds, const value_list_t *vl,
+ const char *key)
+{
+ int i;
+ char *key_copy;
+ cache_entry_t *ce;
+
+ /* `cache_lock' has been locked by `uc_update' */
+
+ key_copy = strdup (key);
+ if (key_copy == NULL)
+ {
+ ERROR ("uc_insert: strdup failed.");
+ return (-1);
+ }
+
+ ce = cache_alloc (ds->ds_num);
+ if (ce == NULL)
+ {
+ sfree (key_copy);
+ ERROR ("uc_insert: cache_alloc (%i) failed.", ds->ds_num);
+ return (-1);
+ }
+
+ sstrncpy (ce->name, key, sizeof (ce->name));
+
+ for (i = 0; i < ds->ds_num; i++)
+ {
+ switch (ds->ds[i].type)
+ {
+ case DS_TYPE_COUNTER:
+ ce->values_gauge[i] = NAN;
+ ce->values_raw[i].counter = vl->values[i].counter;
+ break;
+
+ case DS_TYPE_GAUGE:
+ ce->values_gauge[i] = vl->values[i].gauge;
+ ce->values_raw[i].gauge = vl->values[i].gauge;
+ break;
+
+ case DS_TYPE_DERIVE:
+ ce->values_gauge[i] = NAN;
+ ce->values_raw[i].derive = vl->values[i].derive;
+ break;
+
+ case DS_TYPE_ABSOLUTE:
+ ce->values_gauge[i] = NAN;
+ if (vl->interval > 0)
+ ce->values_gauge[i] = ((double) vl->values[i].absolute)
+ / CDTIME_T_TO_DOUBLE (vl->interval);
+ ce->values_raw[i].absolute = vl->values[i].absolute;
+ break;
+
+ default:
+ /* This shouldn't happen. */
+ ERROR ("uc_insert: Don't know how to handle data source type %i.",
+ ds->ds[i].type);
+ return (-1);
+ } /* switch (ds->ds[i].type) */
+ } /* for (i) */
+
+ /* Prune invalid gauge data */
+ uc_check_range (ds, ce);
+
+ ce->last_time = vl->time;
+ ce->last_update = cdtime ();
+ ce->interval = vl->interval;
+ ce->state = STATE_OKAY;
+
+ if (c_avl_insert (cache_tree, key_copy, ce) != 0)
+ {
+ sfree (key_copy);
+ ERROR ("uc_insert: c_avl_insert failed.");
+ return (-1);
+ }
+
+ DEBUG ("uc_insert: Added %s to the cache.", key);
+ return (0);
+} /* int uc_insert */
+
+int uc_init (void)
+{
+ if (cache_tree == NULL)
+ cache_tree = c_avl_create ((int (*) (const void *, const void *))
+ cache_compare);
+
+ return (0);
+} /* int uc_init */
+
+int uc_check_timeout (void)
+{
+ cdtime_t now;
+ cache_entry_t *ce;
+
+ char **keys = NULL;
+ cdtime_t *keys_time = NULL;
+ cdtime_t *keys_interval = NULL;
+ int keys_len = 0;
+
+ char *key;
+ c_avl_iterator_t *iter;
+
+ int status;
+ int i;
+
+ pthread_mutex_lock (&cache_lock);
+
+ now = cdtime ();
+
+ /* Build a list of entries to be flushed */
+ iter = c_avl_get_iterator (cache_tree);
+ while (c_avl_iterator_next (iter, (void *) &key, (void *) &ce) == 0)
+ {
+ char **tmp;
+ cdtime_t *tmp_time;
+
+ /* If the entry is fresh enough, continue. */
+ if ((now - ce->last_update) < (ce->interval * timeout_g))
+ continue;
+
+ /* If entry has not been updated, add to `keys' array */
+ tmp = (char **) realloc ((void *) keys,
+ (keys_len + 1) * sizeof (char *));
+ if (tmp == NULL)
+ {
+ ERROR ("uc_check_timeout: realloc failed.");
+ continue;
+ }
+ keys = tmp;
+
+ tmp_time = realloc (keys_time, (keys_len + 1) * sizeof (*keys_time));
+ if (tmp_time == NULL)
+ {
+ ERROR ("uc_check_timeout: realloc failed.");
+ continue;
+ }
+ keys_time = tmp_time;
+
+ tmp_time = realloc (keys_interval, (keys_len + 1) * sizeof (*keys_interval));
+ if (tmp_time == NULL)
+ {
+ ERROR ("uc_check_timeout: realloc failed.");
+ continue;
+ }
+ keys_interval = tmp_time;
+
+ keys[keys_len] = strdup (key);
+ if (keys[keys_len] == NULL)
+ {
+ ERROR ("uc_check_timeout: strdup failed.");
+ continue;
+ }
+ keys_time[keys_len] = ce->last_time;
+ keys_interval[keys_len] = ce->interval;
+
+ keys_len++;
+ } /* while (c_avl_iterator_next) */
+
+ c_avl_iterator_destroy (iter);
+ pthread_mutex_unlock (&cache_lock);
+
+ if (keys_len == 0)
+ return (0);
+
+ /* Call the "missing" callback for each value. Do this before removing the
+ * value from the cache, so that callbacks can still access the data stored,
+ * including plugin specific meta data, rates, history, …. This must be done
+ * without holding the lock, otherwise we will run into a deadlock if a
+ * plugin calls the cache interface. */
+ for (i = 0; i < keys_len; i++)
+ {
+ value_list_t vl = VALUE_LIST_INIT;
+
+ vl.values = NULL;
+ vl.values_len = 0;
+ vl.meta = NULL;
+
+ status = parse_identifier_vl (keys[i], &vl);
+ if (status != 0)
+ {
+ ERROR ("uc_check_timeout: parse_identifier_vl (\"%s\") failed.", keys[i]);
+ cache_free (ce);
+ continue;
+ }
+
+ vl.time = keys_time[i];
+ vl.interval = keys_interval[i];
+
+ plugin_dispatch_missing (&vl);
+ } /* for (i = 0; i < keys_len; i++) */
+
+ /* Now actually remove all the values from the cache. We don't re-evaluate
+ * the timestamp again, so in theory it is possible we remove a value after
+ * it is updated here. */
+ pthread_mutex_lock (&cache_lock);
+ for (i = 0; i < keys_len; i++)
+ {
+ key = NULL;
+ ce = NULL;
+
+ status = c_avl_remove (cache_tree, keys[i],
+ (void *) &key, (void *) &ce);
+ if (status != 0)
+ {
+ ERROR ("uc_check_timeout: c_avl_remove (\"%s\") failed.", keys[i]);
+ sfree (keys[i]);
+ continue;
+ }
+
+ sfree (keys[i]);
+ sfree (key);
+ cache_free (ce);
+ } /* for (i = 0; i < keys_len; i++) */
+ pthread_mutex_unlock (&cache_lock);
+
+ sfree (keys);
+ sfree (keys_time);
+ sfree (keys_interval);
+
+ return (0);
+} /* int uc_check_timeout */
+
+int uc_update (const data_set_t *ds, const value_list_t *vl)
+{
+ char name[6 * DATA_MAX_NAME_LEN];
+ cache_entry_t *ce = NULL;
+ int status;
+ int i;
+
+ if (FORMAT_VL (name, sizeof (name), vl) != 0)
+ {
+ ERROR ("uc_update: FORMAT_VL failed.");
+ return (-1);
+ }
+
+ pthread_mutex_lock (&cache_lock);
+
+ status = c_avl_get (cache_tree, name, (void *) &ce);
+ if (status != 0) /* entry does not yet exist */
+ {
+ status = uc_insert (ds, vl, name);
+ pthread_mutex_unlock (&cache_lock);
+ return (status);
+ }
+
+ assert (ce != NULL);
+ assert (ce->values_num == ds->ds_num);
+
+ if (ce->last_time >= vl->time)
+ {
+ pthread_mutex_unlock (&cache_lock);
+ NOTICE ("uc_update: Value too old: name = %s; value time = %.3f; "
+ "last cache update = %.3f;",
+ name,
+ CDTIME_T_TO_DOUBLE (vl->time),
+ CDTIME_T_TO_DOUBLE (ce->last_time));
+ return (-1);
+ }
+
+ for (i = 0; i < ds->ds_num; i++)
+ {
+ switch (ds->ds[i].type)
+ {
+ case DS_TYPE_COUNTER:
+ {
+ counter_t diff;
+
+ /* check if the counter has wrapped around */
+ if (vl->values[i].counter < ce->values_raw[i].counter)
+ {
+ if (ce->values_raw[i].counter <= 4294967295U)
+ diff = (4294967295U - ce->values_raw[i].counter)
+ + vl->values[i].counter;
+ else
+ diff = (18446744073709551615ULL - ce->values_raw[i].counter)
+ + vl->values[i].counter;
+ }
+ else /* counter has NOT wrapped around */
+ {
+ diff = vl->values[i].counter - ce->values_raw[i].counter;
+ }
+
+ ce->values_gauge[i] = ((double) diff)
+ / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
+ ce->values_raw[i].counter = vl->values[i].counter;
+ }
+ break;
+
+ case DS_TYPE_GAUGE:
+ ce->values_raw[i].gauge = vl->values[i].gauge;
+ ce->values_gauge[i] = vl->values[i].gauge;
+ break;
+
+ case DS_TYPE_DERIVE:
+ {
+ derive_t diff;
+
+ diff = vl->values[i].derive - ce->values_raw[i].derive;
+
+ ce->values_gauge[i] = ((double) diff)
+ / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
+ ce->values_raw[i].derive = vl->values[i].derive;
+ }
+ break;
+
+ case DS_TYPE_ABSOLUTE:
+ ce->values_gauge[i] = ((double) vl->values[i].absolute)
+ / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
+ ce->values_raw[i].absolute = vl->values[i].absolute;
+ break;
+
+ default:
+ /* This shouldn't happen. */
+ pthread_mutex_unlock (&cache_lock);
+ ERROR ("uc_update: Don't know how to handle data source type %i.",
+ ds->ds[i].type);
+ return (-1);
+ } /* switch (ds->ds[i].type) */
+
+ DEBUG ("uc_update: %s: ds[%i] = %lf", name, i, ce->values_gauge[i]);
+ } /* for (i) */
+
+ /* Update the history if it exists. */
+ if (ce->history != NULL)
+ {
+ assert (ce->history_index < ce->history_length);
+ for (i = 0; i < ce->values_num; i++)
+ {
+ size_t hist_idx = (ce->values_num * ce->history_index) + i;
+ ce->history[hist_idx] = ce->values_gauge[i];
+ }
+
+ assert (ce->history_length > 0);
+ ce->history_index = (ce->history_index + 1) % ce->history_length;
+ }
+
+ /* Prune invalid gauge data */
+ uc_check_range (ds, ce);
+
+ ce->last_time = vl->time;
+ ce->last_update = cdtime ();
+ ce->interval = vl->interval;
+
+ pthread_mutex_unlock (&cache_lock);
+
+ return (0);
+} /* int uc_update */
+
+int uc_get_rate_by_name (const char *name, gauge_t **ret_values, size_t *ret_values_num)
+{
+ gauge_t *ret = NULL;
+ size_t ret_num = 0;
+ cache_entry_t *ce = NULL;
+ int status = 0;
+
+ pthread_mutex_lock (&cache_lock);
+
+ if (c_avl_get (cache_tree, name, (void *) &ce) == 0)
+ {
+ assert (ce != NULL);
+
+ /* remove missing values from getval */
+ if (ce->state == STATE_MISSING)
+ {
+ status = -1;
+ }
+ else
+ {
+ ret_num = ce->values_num;
+ ret = (gauge_t *) malloc (ret_num * sizeof (gauge_t));
+ if (ret == NULL)
+ {
+ ERROR ("utils_cache: uc_get_rate_by_name: malloc failed.");
+ status = -1;
+ }
+ else
+ {
+ memcpy (ret, ce->values_gauge, ret_num * sizeof (gauge_t));
+ }
+ }
+ }
+ else
+ {
+ DEBUG ("utils_cache: uc_get_rate_by_name: No such value: %s", name);
+ status = -1;
+ }
+
+ pthread_mutex_unlock (&cache_lock);
+
+ if (status == 0)
+ {
+ *ret_values = ret;
+ *ret_values_num = ret_num;
+ }
+
+ return (status);
+} /* gauge_t *uc_get_rate_by_name */
+
+gauge_t *uc_get_rate (const data_set_t *ds, const value_list_t *vl)
+{
+ char name[6 * DATA_MAX_NAME_LEN];
+ gauge_t *ret = NULL;
+ size_t ret_num = 0;
+ int status;
+
+ if (FORMAT_VL (name, sizeof (name), vl) != 0)
+ {
+ ERROR ("utils_cache: uc_get_rate: FORMAT_VL failed.");
+ return (NULL);
+ }
+
+ status = uc_get_rate_by_name (name, &ret, &ret_num);
+ if (status != 0)
+ return (NULL);
+
+ /* This is important - the caller has no other way of knowing how many
+ * values are returned. */
+ if (ret_num != (size_t) ds->ds_num)
+ {
+ ERROR ("utils_cache: uc_get_rate: ds[%s] has %i values, "
+ "but uc_get_rate_by_name returned %zu.",
+ ds->type, ds->ds_num, ret_num);
+ sfree (ret);
+ return (NULL);
+ }
+
+ return (ret);
+} /* gauge_t *uc_get_rate */
+
+size_t uc_get_size() {
+ size_t size_arrays = 0;
+
+ pthread_mutex_lock (&cache_lock);
+ size_arrays = (size_t) c_avl_size (cache_tree);
+ pthread_mutex_unlock (&cache_lock);
+
+ return (size_arrays);
+}
+
+int uc_get_names (char ***ret_names, cdtime_t **ret_times, size_t *ret_number)
+{
+ c_avl_iterator_t *iter;
+ char *key;
+ cache_entry_t *value;
+
+ char **names = NULL;
+ cdtime_t *times = NULL;
+ size_t number = 0;
+ size_t size_arrays = 0;
+
+ int status = 0;
+
+ if ((ret_names == NULL) || (ret_number == NULL))
+ return (-1);
+
+ pthread_mutex_lock (&cache_lock);
+
+ size_arrays = (size_t) c_avl_size (cache_tree);
+ if (size_arrays < 1)
+ {
+ /* Handle the "no values" case here, to avoid the error message when
+ * calloc() returns NULL. */
+ pthread_mutex_unlock (&cache_lock);
+ return (0);
+ }
+
+ names = calloc (size_arrays, sizeof (*names));
+ times = calloc (size_arrays, sizeof (*times));
+ if ((names == NULL) || (times == NULL))
+ {
+ ERROR ("uc_get_names: calloc failed.");
+ sfree (names);
+ sfree (times);
+ pthread_mutex_unlock (&cache_lock);
+ return (ENOMEM);
+ }
+
+ iter = c_avl_get_iterator (cache_tree);
+ while (c_avl_iterator_next (iter, (void *) &key, (void *) &value) == 0)
+ {
+ /* remove missing values when list values */
+ if (value->state == STATE_MISSING)
+ continue;
+
+ /* c_avl_size does not return a number smaller than the number of elements
+ * returned by c_avl_iterator_next. */
+ assert (number < size_arrays);
+
+ if (ret_times != NULL)
+ times[number] = value->last_time;
+
+ names[number] = strdup (key);
+ if (names[number] == NULL)
+ {
+ status = -1;
+ break;
+ }
+
+ number++;
+ } /* while (c_avl_iterator_next) */
+
+ c_avl_iterator_destroy (iter);
+ pthread_mutex_unlock (&cache_lock);
+
+ if (status != 0)
+ {
+ size_t i;
+
+ for (i = 0; i < number; i++)
+ {
+ sfree (names[i]);
+ }
+ sfree (names);
+
+ return (-1);
+ }
+
+ *ret_names = names;
+ if (ret_times != NULL)
+ *ret_times = times;
+ *ret_number = number;
+
+ return (0);
+} /* int uc_get_names */
+
+int uc_get_state (const data_set_t *ds, const value_list_t *vl)
+{
+ char name[6 * DATA_MAX_NAME_LEN];
+ cache_entry_t *ce = NULL;
+ int ret = STATE_ERROR;
+
+ if (FORMAT_VL (name, sizeof (name), vl) != 0)
+ {
+ ERROR ("uc_get_state: FORMAT_VL failed.");
+ return (STATE_ERROR);
+ }
+
+ pthread_mutex_lock (&cache_lock);
+
+ if (c_avl_get (cache_tree, name, (void *) &ce) == 0)
+ {
+ assert (ce != NULL);
+ ret = ce->state;
+ }
+
+ pthread_mutex_unlock (&cache_lock);
+
+ return (ret);
+} /* int uc_get_state */
+
+int uc_set_state (const data_set_t *ds, const value_list_t *vl, int state)
+{
+ char name[6 * DATA_MAX_NAME_LEN];
+ cache_entry_t *ce = NULL;
+ int ret = -1;
+
+ if (FORMAT_VL (name, sizeof (name), vl) != 0)
+ {
+ ERROR ("uc_get_state: FORMAT_VL failed.");
+ return (STATE_ERROR);
+ }
+
+ pthread_mutex_lock (&cache_lock);
+
+ if (c_avl_get (cache_tree, name, (void *) &ce) == 0)
+ {
+ assert (ce != NULL);
+ ret = ce->state;
+ ce->state = state;
+ }
+
+ pthread_mutex_unlock (&cache_lock);
+
+ return (ret);
+} /* int uc_set_state */
+
+int uc_get_history_by_name (const char *name,
+ gauge_t *ret_history, size_t num_steps, size_t num_ds)
+{
+ cache_entry_t *ce = NULL;
+ size_t i;
+ int status = 0;
+
+ pthread_mutex_lock (&cache_lock);
+
+ status = c_avl_get (cache_tree, name, (void *) &ce);
+ if (status != 0)
+ {
+ pthread_mutex_unlock (&cache_lock);
+ return (-ENOENT);
+ }
+
+ if (((size_t) ce->values_num) != num_ds)
+ {
+ pthread_mutex_unlock (&cache_lock);
+ return (-EINVAL);
+ }
+
+ /* Check if there are enough values available. If not, increase the buffer
+ * size. */
+ if (ce->history_length < num_steps)
+ {
+ gauge_t *tmp;
+ size_t i;
+
+ tmp = realloc (ce->history, sizeof (*ce->history)
+ * num_steps * ce->values_num);
+ if (tmp == NULL)
+ {
+ pthread_mutex_unlock (&cache_lock);
+ return (-ENOMEM);
+ }
+
+ for (i = ce->history_length * ce->values_num;
+ i < (num_steps * ce->values_num);
+ i++)
+ tmp[i] = NAN;
+
+ ce->history = tmp;
+ ce->history_length = num_steps;
+ } /* if (ce->history_length < num_steps) */
+
+ /* Copy the values to the output buffer. */
+ for (i = 0; i < num_steps; i++)
+ {
+ size_t src_index;
+ size_t dst_index;
+
+ if (i < ce->history_index)
+ src_index = ce->history_index - (i + 1);
+ else
+ src_index = ce->history_length + ce->history_index - (i + 1);
+ src_index = src_index * num_ds;
+
+ dst_index = i * num_ds;
+
+ memcpy (ret_history + dst_index, ce->history + src_index,
+ sizeof (*ret_history) * num_ds);
+ }
+
+ pthread_mutex_unlock (&cache_lock);
+
+ return (0);
+} /* int uc_get_history_by_name */
+
+int uc_get_history (const data_set_t *ds, const value_list_t *vl,
+ gauge_t *ret_history, size_t num_steps, size_t num_ds)
+{
+ char name[6 * DATA_MAX_NAME_LEN];
+
+ if (FORMAT_VL (name, sizeof (name), vl) != 0)
+ {
+ ERROR ("utils_cache: uc_get_history: FORMAT_VL failed.");
+ return (-1);
+ }
+
+ return (uc_get_history_by_name (name, ret_history, num_steps, num_ds));
+} /* int uc_get_history */
+
+int uc_get_hits (const data_set_t *ds, const value_list_t *vl)
+{
+ char name[6 * DATA_MAX_NAME_LEN];
+ cache_entry_t *ce = NULL;
+ int ret = STATE_ERROR;
+
+ if (FORMAT_VL (name, sizeof (name), vl) != 0)
+ {
+ ERROR ("uc_get_state: FORMAT_VL failed.");
+ return (STATE_ERROR);
+ }
+
+ pthread_mutex_lock (&cache_lock);
+
+ if (c_avl_get (cache_tree, name, (void *) &ce) == 0)
+ {
+ assert (ce != NULL);
+ ret = ce->hits;
+ }
+
+ pthread_mutex_unlock (&cache_lock);
+
+ return (ret);
+} /* int uc_get_hits */
+
+int uc_set_hits (const data_set_t *ds, const value_list_t *vl, int hits)
+{
+ char name[6 * DATA_MAX_NAME_LEN];
+ cache_entry_t *ce = NULL;
+ int ret = -1;
+
+ if (FORMAT_VL (name, sizeof (name), vl) != 0)
+ {
+ ERROR ("uc_get_state: FORMAT_VL failed.");
+ return (STATE_ERROR);
+ }
+
+ pthread_mutex_lock (&cache_lock);
+
+ if (c_avl_get (cache_tree, name, (void *) &ce) == 0)
+ {
+ assert (ce != NULL);
+ ret = ce->hits;
+ ce->hits = hits;
+ }
+
+ pthread_mutex_unlock (&cache_lock);
+
+ return (ret);
+} /* int uc_set_hits */
+
+int uc_inc_hits (const data_set_t *ds, const value_list_t *vl, int step)
+{
+ char name[6 * DATA_MAX_NAME_LEN];
+ cache_entry_t *ce = NULL;
+ int ret = -1;
+
+ if (FORMAT_VL (name, sizeof (name), vl) != 0)
+ {
+ ERROR ("uc_get_state: FORMAT_VL failed.");
+ return (STATE_ERROR);
+ }
+
+ pthread_mutex_lock (&cache_lock);
+
+ if (c_avl_get (cache_tree, name, (void *) &ce) == 0)
+ {
+ assert (ce != NULL);
+ ret = ce->hits;
+ ce->hits = ret + step;
+ }
+
+ pthread_mutex_unlock (&cache_lock);
+
+ return (ret);
+} /* int uc_inc_hits */
+
+/*
+ * Meta data interface
+ */
+/* XXX: This function will acquire `cache_lock' but will not free it! */
+static meta_data_t *uc_get_meta (const value_list_t *vl) /* {{{ */
+{
+ char name[6 * DATA_MAX_NAME_LEN];
+ cache_entry_t *ce = NULL;
+ int status;
+
+ status = FORMAT_VL (name, sizeof (name), vl);
+ if (status != 0)
+ {
+ ERROR ("utils_cache: uc_get_meta: FORMAT_VL failed.");
+ return (NULL);
+ }
+
+ pthread_mutex_lock (&cache_lock);
+
+ status = c_avl_get (cache_tree, name, (void *) &ce);
+ if (status != 0)
+ {
+ pthread_mutex_unlock (&cache_lock);
+ return (NULL);
+ }
+ assert (ce != NULL);
+
+ if (ce->meta == NULL)
+ ce->meta = meta_data_create ();
+
+ if (ce->meta == NULL)
+ pthread_mutex_unlock (&cache_lock);
+
+ return (ce->meta);
+} /* }}} meta_data_t *uc_get_meta */
+
+/* Sorry about this preprocessor magic, but it really makes this file much
+ * shorter.. */
+#define UC_WRAP(wrap_function) { \
+ meta_data_t *meta; \
+ int status; \
+ meta = uc_get_meta (vl); \
+ if (meta == NULL) return (-1); \
+ status = wrap_function (meta, key); \
+ pthread_mutex_unlock (&cache_lock); \
+ return (status); \
+}
+int uc_meta_data_exists (const value_list_t *vl, const char *key)
+ UC_WRAP (meta_data_exists)
+
+int uc_meta_data_delete (const value_list_t *vl, const char *key)
+ UC_WRAP (meta_data_delete)
+#undef UC_WRAP
+
+/* We need a new version of this macro because the following functions take
+ * two argumetns. */
+#define UC_WRAP(wrap_function) { \
+ meta_data_t *meta; \
+ int status; \
+ meta = uc_get_meta (vl); \
+ if (meta == NULL) return (-1); \
+ status = wrap_function (meta, key, value); \
+ pthread_mutex_unlock (&cache_lock); \
+ return (status); \
+}
+int uc_meta_data_add_string (const value_list_t *vl,
+ const char *key,
+ const char *value)
+ UC_WRAP(meta_data_add_string)
+int uc_meta_data_add_signed_int (const value_list_t *vl,
+ const char *key,
+ int64_t value)
+ UC_WRAP(meta_data_add_signed_int)
+int uc_meta_data_add_unsigned_int (const value_list_t *vl,
+ const char *key,
+ uint64_t value)
+ UC_WRAP(meta_data_add_unsigned_int)
+int uc_meta_data_add_double (const value_list_t *vl,
+ const char *key,
+ double value)
+ UC_WRAP(meta_data_add_double)
+int uc_meta_data_add_boolean (const value_list_t *vl,
+ const char *key,
+ _Bool value)
+ UC_WRAP(meta_data_add_boolean)
+
+int uc_meta_data_get_string (const value_list_t *vl,
+ const char *key,
+ char **value)
+ UC_WRAP(meta_data_get_string)
+int uc_meta_data_get_signed_int (const value_list_t *vl,
+ const char *key,
+ int64_t *value)
+ UC_WRAP(meta_data_get_signed_int)
+int uc_meta_data_get_unsigned_int (const value_list_t *vl,
+ const char *key,
+ uint64_t *value)
+ UC_WRAP(meta_data_get_unsigned_int)
+int uc_meta_data_get_double (const value_list_t *vl,
+ const char *key,
+ double *value)
+ UC_WRAP(meta_data_get_double)
+int uc_meta_data_get_boolean (const value_list_t *vl,
+ const char *key,
+ _Bool *value)
+ UC_WRAP(meta_data_get_boolean)
+#undef UC_WRAP
+
+/* vim: set sw=2 ts=8 sts=2 tw=78 : */
diff --git a/src/daemon/utils_cache.h b/src/daemon/utils_cache.h
--- /dev/null
+++ b/src/daemon/utils_cache.h
@@ -0,0 +1,96 @@
+/**
+ * collectd - src/utils_cache.h
+ * Copyright (C) 2007 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#ifndef UTILS_CACHE_H
+#define UTILS_CACHE_H 1
+
+#include "plugin.h"
+
+#define STATE_OKAY 0
+#define STATE_WARNING 1
+#define STATE_ERROR 2
+#define STATE_MISSING 15
+
+int uc_init (void);
+int uc_check_timeout (void);
+int uc_update (const data_set_t *ds, const value_list_t *vl);
+int uc_get_rate_by_name (const char *name, gauge_t **ret_values, size_t *ret_values_num);
+gauge_t *uc_get_rate (const data_set_t *ds, const value_list_t *vl);
+
+size_t uc_get_size();
+int uc_get_names (char ***ret_names, cdtime_t **ret_times, size_t *ret_number);
+
+int uc_get_state (const data_set_t *ds, const value_list_t *vl);
+int uc_set_state (const data_set_t *ds, const value_list_t *vl, int state);
+int uc_get_hits (const data_set_t *ds, const value_list_t *vl);
+int uc_set_hits (const data_set_t *ds, const value_list_t *vl, int hits);
+int uc_inc_hits (const data_set_t *ds, const value_list_t *vl, int step);
+
+int uc_get_history (const data_set_t *ds, const value_list_t *vl,
+ gauge_t *ret_history, size_t num_steps, size_t num_ds);
+int uc_get_history_by_name (const char *name,
+ gauge_t *ret_history, size_t num_steps, size_t num_ds);
+
+/*
+ * Meta data interface
+ */
+int uc_meta_data_exists (const value_list_t *vl, const char *key);
+int uc_meta_data_delete (const value_list_t *vl, const char *key);
+
+int uc_meta_data_add_string (const value_list_t *vl,
+ const char *key,
+ const char *value);
+int uc_meta_data_add_signed_int (const value_list_t *vl,
+ const char *key,
+ int64_t value);
+int uc_meta_data_add_unsigned_int (const value_list_t *vl,
+ const char *key,
+ uint64_t value);
+int uc_meta_data_add_double (const value_list_t *vl,
+ const char *key,
+ double value);
+int uc_meta_data_add_boolean (const value_list_t *vl,
+ const char *key,
+ _Bool value);
+
+int uc_meta_data_get_string (const value_list_t *vl,
+ const char *key,
+ char **value);
+int uc_meta_data_get_signed_int (const value_list_t *vl,
+ const char *key,
+ int64_t *value);
+int uc_meta_data_get_unsigned_int (const value_list_t *vl,
+ const char *key,
+ uint64_t *value);
+int uc_meta_data_get_double (const value_list_t *vl,
+ const char *key,
+ double *value);
+int uc_meta_data_get_boolean (const value_list_t *vl,
+ const char *key,
+ _Bool *value);
+
+/* vim: set shiftwidth=2 softtabstop=2 tabstop=8 : */
+#endif /* !UTILS_CACHE_H */
diff --git a/src/daemon/utils_complain.c b/src/daemon/utils_complain.c
--- /dev/null
@@ -0,0 +1,105 @@
+/**
+ * collectd - src/utils_complain.c
+ * Copyright (C) 2006-2013 Florian octo Forster
+ * Copyright (C) 2008 Sebastian tokkee Harl
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ * Sebastian tokkee Harl <sh at tokkee.org>
+ **/
+
+#include "collectd.h"
+#include "utils_complain.h"
+#include "plugin.h"
+
+/* vcomplain returns 0 if it did not report, 1 else */
+static int vcomplain (int level, c_complain_t *c,
+ const char *format, va_list ap)
+{
+ cdtime_t now;
+ char message[512];
+
+ now = cdtime ();
+
+ if (c->last + c->interval > now)
+ return 0;
+
+ c->last = now;
+
+ if (c->interval < plugin_get_interval ())
+ c->interval = plugin_get_interval ();
+ else
+ c->interval *= 2;
+
+ if (c->interval > TIME_T_TO_CDTIME_T (86400))
+ c->interval = TIME_T_TO_CDTIME_T (86400);
+
+ vsnprintf (message, sizeof (message), format, ap);
+ message[sizeof (message) - 1] = '\0';
+
+ plugin_log (level, "%s", message);
+ return 1;
+} /* vcomplain */
+
+void c_complain (int level, c_complain_t *c, const char *format, ...)
+{
+ va_list ap;
+
+ va_start (ap, format);
+ if (vcomplain (level, c, format, ap))
+ c->complained_once = 1;
+ va_end (ap);
+} /* c_complain */
+
+void c_complain_once (int level, c_complain_t *c, const char *format, ...)
+{
+ va_list ap;
+
+ if (c->complained_once)
+ return;
+
+ va_start (ap, format);
+ if (vcomplain (level, c, format, ap))
+ c->complained_once = 1;
+ va_end (ap);
+} /* c_complain_once */
+
+void c_do_release (int level, c_complain_t *c, const char *format, ...)
+{
+ char message[512];
+ va_list ap;
+
+ if (c->interval == 0)
+ return;
+
+ c->interval = 0;
+ c->complained_once = 0;
+
+ va_start (ap, format);
+ vsnprintf (message, sizeof (message), format, ap);
+ message[sizeof (message) - 1] = '\0';
+ va_end (ap);
+
+ plugin_log (level, "%s", message);
+} /* c_release */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
+
diff --git a/src/daemon/utils_complain.h b/src/daemon/utils_complain.h
--- /dev/null
@@ -0,0 +1,114 @@
+/**
+ * collectd - src/utils_complain.h
+ * Copyright (C) 2006-2013 Florian octo Forster
+ * Copyright (C) 2008 Sebastian tokkee Harl
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ * Sebastian tokkee Harl <sh at tokkee.org>
+ **/
+
+#ifndef UTILS_COMPLAIN_H
+#define UTILS_COMPLAIN_H 1
+
+#include "utils_time.h"
+
+typedef struct
+{
+ /* time of the last report */
+ cdtime_t last;
+
+ /* How long to wait until reporting again.
+ * 0 indicates that the complaint is no longer valid. */
+ cdtime_t interval;
+
+ _Bool complained_once;
+} c_complain_t;
+
+#define C_COMPLAIN_INIT_STATIC { 0, 0, 0 }
+#define C_COMPLAIN_INIT(c) do { \
+ (c)->last = 0; \
+ (c)->interval = 0; \
+ (c)->complained_once = 0; \
+} while (0)
+
+/*
+ * NAME
+ * c_complain
+ *
+ * DESCRIPTION
+ * Complain about something. This function will report a message (usually
+ * indicating some error condition) using the collectd logging mechanism.
+ * When this function is called again, reporting the message again will be
+ * deferred by an increasing interval (up to one day) to prevent flooding
+ * the logs. A call to `c_release' resets the counter.
+ *
+ * PARAMETERS
+ * `level' The log level passed to `plugin_log'.
+ * `c' Identifier for the complaint.
+ * `format' Message format - see the documentation of printf(3).
+ */
+void c_complain (int level, c_complain_t *c, const char *format, ...);
+
+/*
+ * NAME
+ * c_complain_once
+ *
+ * DESCRIPTION
+ * Complain about something once. This function will not report anything
+ * again, unless `c_release' has been called in between. If used after some
+ * calls to `c_complain', it will report again on the next interval and stop
+ * after that.
+ *
+ * See `c_complain' for further details and a description of the parameters.
+ */
+void c_complain_once (int level, c_complain_t *c, const char *format, ...);
+
+/*
+ * NAME
+ * c_would_release
+ *
+ * DESCRIPTION
+ * Returns true if the specified complaint would be released, false else.
+ */
+#define c_would_release(c) ((c)->interval != 0)
+
+/*
+ * NAME
+ * c_release
+ *
+ * DESCRIPTION
+ * Release a complaint. This will report a message once, marking the
+ * complaint as released.
+ *
+ * See `c_complain' for a description of the parameters.
+ */
+void c_do_release (int level, c_complain_t *c, const char *format, ...);
+#define c_release(level, c, ...) \
+ do { \
+ if (c_would_release (c)) \
+ c_do_release(level, c, __VA_ARGS__); \
+ } while (0)
+
+#endif /* UTILS_COMPLAIN_H */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
+
diff --git a/src/daemon/utils_heap.c b/src/daemon/utils_heap.c
--- /dev/null
+++ b/src/daemon/utils_heap.c
@@ -0,0 +1,230 @@
+/**
+ * collectd - src/utils_heap.c
+ * Copyright (C) 2009 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <pthread.h>
+
+#include "utils_heap.h"
+
+struct c_heap_s
+{
+ pthread_mutex_t lock;
+ int (*compare) (const void *, const void *);
+
+ void **list;
+ size_t list_len; /* # entries used */
+ size_t list_size; /* # entries allocated */
+};
+
+enum reheap_direction
+{
+ DIR_UP,
+ DIR_DOWN
+};
+
+static void reheap (c_heap_t *h, size_t root, enum reheap_direction dir)
+{
+ size_t left;
+ size_t right;
+ size_t min;
+ int status;
+
+ /* Calculate the positions of the children */
+ left = (2 * root) + 1;
+ if (left >= h->list_len)
+ left = 0;
+
+ right = (2 * root) + 2;
+ if (right >= h->list_len)
+ right = 0;
+
+ /* Check which one of the children is smaller. */
+ if ((left == 0) && (right == 0))
+ return;
+ else if (left == 0)
+ min = right;
+ else if (right == 0)
+ min = left;
+ else
+ {
+ status = h->compare (h->list[left], h->list[right]);
+ if (status > 0)
+ min = right;
+ else
+ min = left;
+ }
+
+ status = h->compare (h->list[root], h->list[min]);
+ if (status <= 0)
+ {
+ /* We didn't need to change anything, so the rest of the tree should be
+ * okay now. */
+ return;
+ }
+ else /* if (status > 0) */
+ {
+ void *tmp;
+
+ tmp = h->list[root];
+ h->list[root] = h->list[min];
+ h->list[min] = tmp;
+ }
+
+ if ((dir == DIR_UP) && (root == 0))
+ return;
+
+ if (dir == DIR_UP)
+ reheap (h, (root - 1) / 2, dir);
+ else if (dir == DIR_DOWN)
+ reheap (h, min, dir);
+} /* void reheap */
+
+c_heap_t *c_heap_create (int (*compare) (const void *, const void *))
+{
+ c_heap_t *h;
+
+ if (compare == NULL)
+ return (NULL);
+
+ h = malloc (sizeof (*h));
+ if (h == NULL)
+ return (NULL);
+
+ memset (h, 0, sizeof (*h));
+ pthread_mutex_init (&h->lock, /* attr = */ NULL);
+ h->compare = compare;
+
+ h->list = NULL;
+ h->list_len = 0;
+ h->list_size = 0;
+
+ return (h);
+} /* c_heap_t *c_heap_create */
+
+void c_heap_destroy (c_heap_t *h)
+{
+ if (h == NULL)
+ return;
+
+ h->list_len = 0;
+ h->list_size = 0;
+ free (h->list);
+ h->list = NULL;
+
+ pthread_mutex_destroy (&h->lock);
+
+ free (h);
+} /* void c_heap_destroy */
+
+int c_heap_insert (c_heap_t *h, void *ptr)
+{
+ size_t index;
+
+ if ((h == NULL) || (ptr == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&h->lock);
+
+ assert (h->list_len <= h->list_size);
+ if (h->list_len == h->list_size)
+ {
+ void **tmp;
+
+ tmp = realloc (h->list, (h->list_size + 16) * sizeof (*h->list));
+ if (tmp == NULL)
+ {
+ pthread_mutex_unlock (&h->lock);
+ return (-ENOMEM);
+ }
+
+ h->list = tmp;
+ h->list_size += 16;
+ }
+
+ /* Insert the new node as a leaf. */
+ index = h->list_len;
+ h->list[index] = ptr;
+ h->list_len++;
+
+ /* Reorganize the heap from bottom up. */
+ reheap (h, /* parent of this node = */ (index - 1) / 2, DIR_UP);
+
+ pthread_mutex_unlock (&h->lock);
+ return (0);
+} /* int c_heap_insert */
+
+void *c_heap_get_root (c_heap_t *h)
+{
+ void *ret = NULL;
+
+ if (h == NULL)
+ return (NULL);
+
+ pthread_mutex_lock (&h->lock);
+
+ if (h->list_len == 0)
+ {
+ pthread_mutex_unlock (&h->lock);
+ return (NULL);
+ }
+ else if (h->list_len == 1)
+ {
+ ret = h->list[0];
+ h->list[0] = NULL;
+ h->list_len = 0;
+ }
+ else /* if (h->list_len > 1) */
+ {
+ ret = h->list[0];
+ h->list[0] = h->list[h->list_len - 1];
+ h->list[h->list_len - 1] = NULL;
+ h->list_len--;
+
+ reheap (h, /* root = */ 0, DIR_DOWN);
+ }
+
+ /* free some memory */
+ if ((h->list_len + 32) < h->list_size)
+ {
+ void **tmp;
+
+ tmp = realloc (h->list, (h->list_len + 16) * sizeof (*h->list));
+ if (tmp != NULL)
+ {
+ h->list = tmp;
+ h->list_size = h->list_len + 16;
+ }
+ }
+
+ pthread_mutex_unlock (&h->lock);
+
+ return (ret);
+} /* void *c_heap_get_root */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/daemon/utils_heap.h b/src/daemon/utils_heap.h
--- /dev/null
+++ b/src/daemon/utils_heap.h
@@ -0,0 +1,100 @@
+/**
+ * collectd - src/utils_heap.h
+ * Copyright (C) 2009 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#ifndef UTILS_HEAP_H
+#define UTILS_HEAP_H 1
+
+struct c_heap_s;
+typedef struct c_heap_s c_heap_t;
+
+/*
+ * NAME
+ * c_heap_create
+ *
+ * DESCRIPTION
+ * Allocates a new heap.
+ *
+ * PARAMETERS
+ * `compare' The function-pointer `compare' is used to compare two keys. It
+ * has to return less than zero if it's first argument is smaller
+ * then the second argument, more than zero if the first argument
+ * is bigger than the second argument and zero if they are equal.
+ * If your keys are char-pointers, you can use the `strcmp'
+ * function from the libc here.
+ *
+ * RETURN VALUE
+ * A c_heap_t-pointer upon success or NULL upon failure.
+ */
+c_heap_t *c_heap_create (int (*compare) (const void *, const void *));
+
+/*
+ * NAME
+ * c_heap_destroy
+ *
+ * DESCRIPTION
+ * Deallocates a heap. Stored value- and key-pointer are lost, but of course
+ * not freed.
+ */
+void c_heap_destroy (c_heap_t *h);
+
+/*
+ * NAME
+ * c_heap_insert
+ *
+ * DESCRIPTION
+ * Stores the key-value-pair in the heap pointed to by `h'.
+ *
+ * PARAMETERS
+ * `h' Heap to store the data in.
+ * `ptr' Value to be stored. This is typically a pointer to a data
+ * structure. The data structure is of course *not* copied and may
+ * not be free'd before the pointer has been removed from the heap
+ * again.
+ *
+ * RETURN VALUE
+ * Zero upon success, non-zero otherwise. It's less than zero if an error
+ * occurred or greater than zero if the key is already stored in the tree.
+ */
+int c_heap_insert (c_heap_t *h, void *ptr);
+
+/*
+ * NAME
+ * c_heap_get_root
+ *
+ * DESCRIPTION
+ * Removes the value at the root of the heap and returns both, key and value.
+ *
+ * PARAMETERS
+ * `h' Heap to remove key-value-pair from.
+ *
+ * RETURN VALUE
+ * The pointer passed to `c_heap_insert' or NULL if there are no more
+ * elements in the heap (or an error occurred).
+ */
+void *c_heap_get_root (c_heap_t *h);
+
+#endif /* UTILS_HEAP_H */
+/* vim: set sw=2 sts=2 et : */
diff --git a/src/daemon/utils_llist.c b/src/daemon/utils_llist.c
--- /dev/null
+++ b/src/daemon/utils_llist.c
@@ -0,0 +1,190 @@
+/**
+ * collectd - src/utils_llist.c
+ * Copyright (C) 2006 Florian Forster <octo at collectd.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian Forster <octo at collectd.org>
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils_llist.h"
+
+/*
+ * Private data types
+ */
+struct llist_s
+{
+ llentry_t *head;
+ llentry_t *tail;
+ int size;
+};
+
+/*
+ * Public functions
+ */
+llist_t *llist_create (void)
+{
+ llist_t *ret;
+
+ ret = (llist_t *) malloc (sizeof (llist_t));
+ if (ret == NULL)
+ return (NULL);
+
+ memset (ret, '\0', sizeof (llist_t));
+
+ return (ret);
+}
+
+void llist_destroy (llist_t *l)
+{
+ llentry_t *e_this;
+ llentry_t *e_next;
+
+ if (l == NULL)
+ return;
+
+ for (e_this = l->head; e_this != NULL; e_this = e_next)
+ {
+ e_next = e_this->next;
+ llentry_destroy (e_this);
+ }
+
+ free (l);
+}
+
+llentry_t *llentry_create (char *key, void *value)
+{
+ llentry_t *e;
+
+ e = (llentry_t *) malloc (sizeof (llentry_t));
+ if (e)
+ {
+ e->key = key;
+ e->value = value;
+ e->next = NULL;
+ }
+
+ return (e);
+}
+
+void llentry_destroy (llentry_t *e)
+{
+ free (e);
+}
+
+void llist_append (llist_t *l, llentry_t *e)
+{
+ e->next = NULL;
+
+ if (l->tail == NULL)
+ l->head = e;
+ else
+ l->tail->next = e;
+
+ l->tail = e;
+
+ ++(l->size);
+}
+
+void llist_prepend (llist_t *l, llentry_t *e)
+{
+ e->next = l->head;
+ l->head = e;
+
+ if (l->tail == NULL)
+ l->tail = e;
+
+ ++(l->size);
+}
+
+void llist_remove (llist_t *l, llentry_t *e)
+{
+ llentry_t *prev;
+
+ prev = l->head;
+ while ((prev != NULL) && (prev->next != e))
+ prev = prev->next;
+
+ if (prev != NULL)
+ prev->next = e->next;
+ if (l->head == e)
+ l->head = e->next;
+ if (l->tail == e)
+ l->tail = prev;
+
+ --(l->size);
+}
+
+int llist_size (llist_t *l)
+{
+ return (l ? l->size : 0);
+}
+
+static int llist_strcmp (llentry_t *e, void *ud)
+{
+ if ((e == NULL) || (ud == NULL))
+ return (-1);
+ return (strcmp (e->key, (const char *)ud));
+}
+
+llentry_t *llist_search (llist_t *l, const char *key)
+{
+ return (llist_search_custom (l, llist_strcmp, (void *)key));
+}
+
+llentry_t *llist_search_custom (llist_t *l,
+ int (*compare) (llentry_t *, void *), void *user_data)
+{
+ llentry_t *e;
+
+ if (l == NULL)
+ return (NULL);
+
+ e = l->head;
+ while (e != NULL) {
+ llentry_t *next = e->next;
+
+ if (compare (e, user_data) == 0)
+ break;
+
+ e = next;
+ }
+
+ return (e);
+}
+
+llentry_t *llist_head (llist_t *l)
+{
+ if (l == NULL)
+ return (NULL);
+ return (l->head);
+}
+
+llentry_t *llist_tail (llist_t *l)
+{
+ if (l == NULL)
+ return (NULL);
+ return (l->tail);
+}
diff --git a/src/daemon/utils_llist.h b/src/daemon/utils_llist.h
--- /dev/null
+++ b/src/daemon/utils_llist.h
@@ -0,0 +1,66 @@
+/**
+ * collectd - src/utils_llist.h
+ * Copyright (C) 2006 Florian Forster <octo at collectd.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian Forster <octo at collectd.org>
+ */
+
+#ifndef UTILS_LLIST_H
+#define UTILS_LLIST_H 1
+
+/*
+ * Data types
+ */
+struct llentry_s
+{
+ char *key;
+ void *value;
+ struct llentry_s *next;
+};
+typedef struct llentry_s llentry_t;
+
+struct llist_s;
+typedef struct llist_s llist_t;
+
+/*
+ * Functions
+ */
+llist_t *llist_create (void);
+void llist_destroy (llist_t *l);
+
+llentry_t *llentry_create (char *key, void *value);
+void llentry_destroy (llentry_t *e);
+
+void llist_append (llist_t *l, llentry_t *e);
+void llist_prepend (llist_t *l, llentry_t *e);
+void llist_remove (llist_t *l, llentry_t *e);
+
+int llist_size (llist_t *l);
+
+llentry_t *llist_search (llist_t *l, const char *key);
+llentry_t *llist_search_custom (llist_t *l,
+ int (*compare) (llentry_t *, void *), void *user_data);
+
+llentry_t *llist_head (llist_t *l);
+llentry_t *llist_tail (llist_t *l);
+
+#endif /* UTILS_LLIST_H */
diff --git a/src/daemon/utils_match.c b/src/daemon/utils_match.c
--- /dev/null
+++ b/src/daemon/utils_match.c
@@ -0,0 +1,396 @@
+/**
+ * collectd - src/utils_match.c
+ * Copyright (C) 2008-2014 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#include "utils_match.h"
+
+#include <regex.h>
+
+#define UTILS_MATCH_FLAGS_FREE_USER_DATA 0x01
+#define UTILS_MATCH_FLAGS_EXCLUDE_REGEX 0x02
+
+struct cu_match_s
+{
+ regex_t regex;
+ regex_t excluderegex;
+ int flags;
+
+ int (*callback) (const char *str, char * const *matches, size_t matches_num,
+ void *user_data);
+ void *user_data;
+};
+
+/*
+ * Private functions
+ */
+static char *match_substr (const char *str, int begin, int end)
+{
+ char *ret;
+ size_t ret_len;
+
+ if ((begin < 0) || (end < 0) || (begin >= end))
+ return (NULL);
+ if ((size_t) end > (strlen (str) + 1))
+ {
+ ERROR ("utils_match: match_substr: `end' points after end of string.");
+ return (NULL);
+ }
+
+ ret_len = end - begin;
+ ret = (char *) malloc (sizeof (char) * (ret_len + 1));
+ if (ret == NULL)
+ {
+ ERROR ("utils_match: match_substr: malloc failed.");
+ return (NULL);
+ }
+
+ sstrncpy (ret, str + begin, ret_len + 1);
+ return (ret);
+} /* char *match_substr */
+
+static int default_callback (const char __attribute__((unused)) *str,
+ char * const *matches, size_t matches_num, void *user_data)
+{
+ cu_match_value_t *data = (cu_match_value_t *) user_data;
+
+ if (data->ds_type & UTILS_MATCH_DS_TYPE_GAUGE)
+ {
+ gauge_t value;
+ char *endptr = NULL;
+
+ if (data->ds_type & UTILS_MATCH_CF_GAUGE_INC)
+ {
+ data->value.gauge = isnan (data->value.gauge) ? 1 : data->value.gauge + 1;
+ data->values_num++;
+ return(0);
+ }
+
+ if (matches_num < 2)
+ return (-1);
+
+ value = (gauge_t) strtod (matches[1], &endptr);
+ if (matches[1] == endptr)
+ return (-1);
+
+ if ((data->values_num == 0)
+ || (data->ds_type & UTILS_MATCH_CF_GAUGE_LAST))
+ {
+ data->value.gauge = value;
+ }
+ else if (data->ds_type & UTILS_MATCH_CF_GAUGE_AVERAGE)
+ {
+ double f = ((double) data->values_num)
+ / ((double) (data->values_num + 1));
+ data->value.gauge = (data->value.gauge * f) + (value * (1.0 - f));
+ }
+ else if (data->ds_type & UTILS_MATCH_CF_GAUGE_MIN)
+ {
+ if (data->value.gauge > value)
+ data->value.gauge = value;
+ }
+ else if (data->ds_type & UTILS_MATCH_CF_GAUGE_MAX)
+ {
+ if (data->value.gauge < value)
+ data->value.gauge = value;
+ }
+ else if (data->ds_type & UTILS_MATCH_CF_GAUGE_ADD)
+ {
+ data->value.gauge += value;
+ }
+ else
+ {
+ ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
+ return (-1);
+ }
+
+ data->values_num++;
+ }
+ else if (data->ds_type & UTILS_MATCH_DS_TYPE_COUNTER)
+ {
+ counter_t value;
+ char *endptr = NULL;
+
+ if (data->ds_type & UTILS_MATCH_CF_COUNTER_INC)
+ {
+ data->value.counter++;
+ data->values_num++;
+ return (0);
+ }
+
+ if (matches_num < 2)
+ return (-1);
+
+ value = (counter_t) strtoull (matches[1], &endptr, 0);
+ if (matches[1] == endptr)
+ return (-1);
+
+ if (data->ds_type & UTILS_MATCH_CF_COUNTER_SET)
+ data->value.counter = value;
+ else if (data->ds_type & UTILS_MATCH_CF_COUNTER_ADD)
+ data->value.counter += value;
+ else
+ {
+ ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
+ return (-1);
+ }
+
+ data->values_num++;
+ }
+ else if (data->ds_type & UTILS_MATCH_DS_TYPE_DERIVE)
+ {
+ derive_t value;
+ char *endptr = NULL;
+
+ if (data->ds_type & UTILS_MATCH_CF_DERIVE_INC)
+ {
+ data->value.counter++;
+ data->values_num++;
+ return (0);
+ }
+
+ if (matches_num < 2)
+ return (-1);
+
+ value = (derive_t) strtoll (matches[1], &endptr, 0);
+ if (matches[1] == endptr)
+ return (-1);
+
+ if (data->ds_type & UTILS_MATCH_CF_DERIVE_SET)
+ data->value.derive = value;
+ else if (data->ds_type & UTILS_MATCH_CF_DERIVE_ADD)
+ data->value.derive += value;
+ else
+ {
+ ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
+ return (-1);
+ }
+
+ data->values_num++;
+ }
+ else if (data->ds_type & UTILS_MATCH_DS_TYPE_ABSOLUTE)
+ {
+ absolute_t value;
+ char *endptr = NULL;
+
+ if (matches_num < 2)
+ return (-1);
+
+ value = (absolute_t) strtoull (matches[1], &endptr, 0);
+ if (matches[1] == endptr)
+ return (-1);
+
+ if (data->ds_type & UTILS_MATCH_CF_ABSOLUTE_SET)
+ data->value.absolute = value;
+ else
+ {
+ ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
+ return (-1);
+ }
+
+ data->values_num++;
+ }
+ else
+ {
+ ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
+ return (-1);
+ }
+
+ return (0);
+} /* int default_callback */
+
+/*
+ * Public functions
+ */
+cu_match_t *match_create_callback (const char *regex, const char *excluderegex,
+ int (*callback) (const char *str,
+ char * const *matches, size_t matches_num, void *user_data),
+ void *user_data)
+{
+ cu_match_t *obj;
+ int status;
+
+ DEBUG ("utils_match: match_create_callback: regex = %s, excluderegex = %s",
+ regex, excluderegex);
+
+ obj = (cu_match_t *) malloc (sizeof (cu_match_t));
+ if (obj == NULL)
+ return (NULL);
+ memset (obj, '\0', sizeof (cu_match_t));
+
+ status = regcomp (&obj->regex, regex, REG_EXTENDED | REG_NEWLINE);
+ if (status != 0)
+ {
+ ERROR ("Compiling the regular expression \"%s\" failed.", regex);
+ sfree (obj);
+ return (NULL);
+ }
+
+ if (excluderegex && strcmp(excluderegex, "") != 0) {
+ status = regcomp (&obj->excluderegex, excluderegex, REG_EXTENDED);
+ if (status != 0)
+ {
+ ERROR ("Compiling the excluding regular expression \"%s\" failed.",
+ excluderegex);
+ sfree (obj);
+ return (NULL);
+ }
+ obj->flags |= UTILS_MATCH_FLAGS_EXCLUDE_REGEX;
+ }
+
+ obj->callback = callback;
+ obj->user_data = user_data;
+
+ return (obj);
+} /* cu_match_t *match_create_callback */
+
+cu_match_t *match_create_simple (const char *regex,
+ const char *excluderegex, int match_ds_type)
+{
+ cu_match_value_t *user_data;
+ cu_match_t *obj;
+
+ user_data = (cu_match_value_t *) malloc (sizeof (cu_match_value_t));
+ if (user_data == NULL)
+ return (NULL);
+ memset (user_data, '\0', sizeof (cu_match_value_t));
+ user_data->ds_type = match_ds_type;
+
+ obj = match_create_callback (regex, excluderegex,
+ default_callback, user_data);
+ if (obj == NULL)
+ {
+ sfree (user_data);
+ return (NULL);
+ }
+
+ obj->flags |= UTILS_MATCH_FLAGS_FREE_USER_DATA;
+
+ return (obj);
+} /* cu_match_t *match_create_simple */
+
+void match_value_reset (cu_match_value_t *mv)
+{
+ if (mv == NULL)
+ return;
+
+ if (mv->ds_type & UTILS_MATCH_DS_TYPE_GAUGE)
+ {
+ mv->value.gauge = NAN;
+ mv->values_num = 0;
+ }
+} /* }}} void match_value_reset */
+
+void match_destroy (cu_match_t *obj)
+{
+ if (obj == NULL)
+ return;
+
+ if (obj->flags & UTILS_MATCH_FLAGS_FREE_USER_DATA)
+ {
+ sfree (obj->user_data);
+ }
+
+ sfree (obj);
+} /* void match_destroy */
+
+int match_apply (cu_match_t *obj, const char *str)
+{
+ int status;
+ regmatch_t re_match[32];
+ char *matches[32];
+ size_t matches_num;
+ size_t i;
+
+ if ((obj == NULL) || (str == NULL))
+ return (-1);
+
+ if (obj->flags & UTILS_MATCH_FLAGS_EXCLUDE_REGEX) {
+ status = regexec (&obj->excluderegex, str,
+ STATIC_ARRAY_SIZE (re_match), re_match,
+ /* eflags = */ 0);
+ /* Regex did match, so exclude this line */
+ if (status == 0) {
+ DEBUG("ExludeRegex matched, don't count that line\n");
+ return (0);
+ }
+ }
+
+ status = regexec (&obj->regex, str,
+ STATIC_ARRAY_SIZE (re_match), re_match,
+ /* eflags = */ 0);
+
+ /* Regex did not match */
+ if (status != 0)
+ return (0);
+
+ memset (matches, '\0', sizeof (matches));
+ for (matches_num = 0; matches_num < STATIC_ARRAY_SIZE (matches); matches_num++)
+ {
+ if ((re_match[matches_num].rm_so < 0)
+ || (re_match[matches_num].rm_eo < 0))
+ break;
+
+ matches[matches_num] = match_substr (str,
+ re_match[matches_num].rm_so, re_match[matches_num].rm_eo);
+ if (matches[matches_num] == NULL)
+ {
+ status = -1;
+ break;
+ }
+ }
+
+ if (status != 0)
+ {
+ ERROR ("utils_match: match_apply: match_substr failed.");
+ }
+ else
+ {
+ status = obj->callback (str, matches, matches_num, obj->user_data);
+ if (status != 0)
+ {
+ ERROR ("utils_match: match_apply: callback failed.");
+ }
+ }
+
+ for (i = 0; i < matches_num; i++)
+ {
+ sfree (matches[i]);
+ }
+
+ return (status);
+} /* int match_apply */
+
+void *match_get_user_data (cu_match_t *obj)
+{
+ if (obj == NULL)
+ return (NULL);
+ return (obj->user_data);
+} /* void *match_get_user_data */
+
+/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/daemon/utils_match.h b/src/daemon/utils_match.h
--- /dev/null
+++ b/src/daemon/utils_match.h
@@ -0,0 +1,175 @@
+/**
+ * collectd - src/utils_match.h
+ * Copyright (C) 2008-2014 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#ifndef UTILS_MATCH_H
+#define UTILS_MATCH_H 1
+
+#include "plugin.h"
+
+/*
+ * Each type may have 12 sub-types
+ * 0x1000 = 1000000000000
+ * ^ <- Type bit
+ * ^^^^^^^^^^^^ <- Subtype bits
+ */
+#define UTILS_MATCH_DS_TYPE_GAUGE 0x1000
+#define UTILS_MATCH_DS_TYPE_COUNTER 0x2000
+#define UTILS_MATCH_DS_TYPE_DERIVE 0x4000
+#define UTILS_MATCH_DS_TYPE_ABSOLUTE 0x8000
+
+#define UTILS_MATCH_CF_GAUGE_AVERAGE 0x01
+#define UTILS_MATCH_CF_GAUGE_MIN 0x02
+#define UTILS_MATCH_CF_GAUGE_MAX 0x04
+#define UTILS_MATCH_CF_GAUGE_LAST 0x08
+#define UTILS_MATCH_CF_GAUGE_INC 0x10
+#define UTILS_MATCH_CF_GAUGE_ADD 0x20
+
+#define UTILS_MATCH_CF_COUNTER_SET 0x01
+#define UTILS_MATCH_CF_COUNTER_ADD 0x02
+#define UTILS_MATCH_CF_COUNTER_INC 0x04
+
+#define UTILS_MATCH_CF_DERIVE_SET 0x01
+#define UTILS_MATCH_CF_DERIVE_ADD 0x02
+#define UTILS_MATCH_CF_DERIVE_INC 0x04
+
+#define UTILS_MATCH_CF_ABSOLUTE_SET 0x01
+#define UTILS_MATCH_CF_ABSOLUTE_ADD 0x02
+#define UTILS_MATCH_CF_ABSOLUTE_INC 0x04
+
+/*
+ * Data types
+ */
+struct cu_match_s;
+typedef struct cu_match_s cu_match_t;
+
+struct cu_match_value_s
+{
+ int ds_type;
+ value_t value;
+ unsigned int values_num;
+};
+typedef struct cu_match_value_s cu_match_value_t;
+
+/*
+ * Prototypes
+ */
+/*
+ * NAME
+ * match_create_callback
+ *
+ * DESCRIPTION
+ * Creates a new `cu_match_t' object which will use the regular expression
+ * `regex' to match lines, see the `match_apply' method below. If the line
+ * matches, the callback passed in `callback' will be called along with the
+ * pointer `user_pointer'.
+ * The string that's passed to the callback depends on the regular expression:
+ * If the regular expression includes a sub-match, i. e. something like
+ * "value=([0-9][0-9]*)"
+ * then only the submatch (the part in the parenthesis) will be passed to the
+ * callback. If there is no submatch, then the entire string is passed to the
+ * callback.
+ * The optional `excluderegex' allows to exclude the line from the match, if
+ * the excluderegex matches.
+ */
+cu_match_t *match_create_callback (const char *regex, const char *excluderegex,
+ int (*callback) (const char *str,
+ char * const *matches, size_t matches_num, void *user_data),
+ void *user_data);
+
+/*
+ * NAME
+ * match_create_simple
+ *
+ * DESCRIPTION
+ * Creates a new `cu_match_t' with a default callback. The user data for that
+ * default callback will be a `cu_match_value_t' structure, with
+ * `ds_type' copied to the structure. The default callback will handle the
+ * string as containing a number (see strtoll(3) and strtod(3)) and store that
+ * number in the `value' member. How that is done depends on `ds_type':
+ *
+ * UTILS_MATCH_DS_TYPE_GAUGE
+ * The function will search for a floating point number in the string and
+ * store it in value.gauge.
+ * UTILS_MATCH_DS_TYPE_COUNTER_SET
+ * The function will search for an integer in the string and store it in
+ * value.counter.
+ * UTILS_MATCH_DS_TYPE_COUNTER_ADD
+ * The function will search for an integer in the string and add it to the
+ * value in value.counter.
+ * UTILS_MATCH_DS_TYPE_COUNTER_INC
+ * The function will not search for anything in the string and increase
+ * value.counter by one.
+ */
+cu_match_t *match_create_simple (const char *regex,
+ const char *excluderegex, int ds_type);
+
+/*
+ * NAME
+ * match_value_reset
+ *
+ * DESCRIPTION
+ * Resets the internal state, if applicable. This function must be called
+ * after each iteration for "simple" matches, usually after dispatching the
+ * metrics.
+ */
+void match_value_reset (cu_match_value_t *mv);
+
+/*
+ * NAME
+ * match_destroy
+ *
+ * DESCRIPTION
+ * Destroys the object and frees all internal resources.
+ */
+void match_destroy (cu_match_t *obj);
+
+/*
+ * NAME
+ * match_apply
+ *
+ * DESCRIPTION
+ * Tries to match the string `str' with the regular expression of `obj'. If
+ * the string matches, calls the callback in `obj' with the (sub-)match.
+ *
+ * The user_data pointer passed to `match_create_callback' is NOT freed
+ * automatically. The `cu_match_value_t' structure allocated by
+ * `match_create_callback' is freed automatically.
+ */
+int match_apply (cu_match_t *obj, const char *str);
+
+/*
+ * NAME
+ * match_get_user_data
+ *
+ * DESCRIPTION
+ * Returns the pointer passed to `match_create_callback' or a pointer to the
+ * `cu_match_value_t' structure allocated by `match_create_simple'.
+ */
+void *match_get_user_data (cu_match_t *obj);
+
+#endif /* UTILS_MATCH_H */
+
+/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/daemon/utils_parse_option.c b/src/daemon/utils_parse_option.c
--- /dev/null
@@ -0,0 +1,209 @@
+/**
+ * collectd - src/utils_parse_option.c
+ * Copyright (C) 2008 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "utils_parse_option.h"
+
+int parse_string (char **ret_buffer, char **ret_string)
+{
+ char *buffer;
+ char *string;
+
+ buffer = *ret_buffer;
+
+ /* Eat up leading spaces. */
+ string = buffer;
+ while (isspace ((int) *string))
+ string++;
+ if (*string == 0)
+ return (1);
+
+ /* A quoted string */
+ if (*string == '"')
+ {
+ char *dst;
+
+ string++;
+ if (*string == 0)
+ return (1);
+
+ dst = string;
+ buffer = string;
+ while ((*buffer != '"') && (*buffer != 0))
+ {
+ /* Un-escape backslashes */
+ if (*buffer == '\\')
+ {
+ buffer++;
+ /* Catch a backslash at the end of buffer */
+ if (*buffer == 0)
+ return (-1);
+ }
+ *dst = *buffer;
+ buffer++;
+ dst++;
+ }
+ /* No quote sign has been found */
+ if (*buffer == 0)
+ return (-1);
+
+ *dst = 0;
+ dst++;
+ *buffer = 0;
+ buffer++;
+
+ /* Check for trailing spaces. */
+ if ((*buffer != 0) && !isspace ((int) *buffer))
+ return (-1);
+ }
+ else /* an unquoted string */
+ {
+ buffer = string;
+ while ((*buffer != 0) && !isspace ((int) *buffer))
+ buffer++;
+ if (*buffer != 0)
+ {
+ *buffer = 0;
+ buffer++;
+ }
+ }
+
+ /* Eat up trailing spaces */
+ while (isspace ((int) *buffer))
+ buffer++;
+
+ *ret_buffer = buffer;
+ *ret_string = string;
+
+ return (0);
+} /* int parse_string */
+
+/*
+ * parse_option
+ * ------------
+ * Parses an ``option'' as used with the unixsock and exec commands. An
+ * option is of the form:
+ * name0="value"
+ * name1="value with \"quotes\""
+ * name2="value \\ backslash"
+ * However, if the value does *not* contain a space character, you can skip
+ * the quotes.
+ */
+int parse_option (char **ret_buffer, char **ret_key, char **ret_value)
+{
+ char *buffer;
+ char *key;
+ char *value;
+ int status;
+
+ buffer = *ret_buffer;
+
+ /* Eat up leading spaces */
+ key = buffer;
+ while (isspace ((int) *key))
+ key++;
+ if (*key == 0)
+ return (1);
+
+ /* Look for the equal sign */
+ buffer = key;
+ while (isalnum ((int) *buffer) || *buffer == '_' || *buffer == ':')
+ buffer++;
+ if ((*buffer != '=') || (buffer == key))
+ return (1);
+ *buffer = 0;
+ buffer++;
+ /* Empty values must be written as "" */
+ if (isspace ((int) *buffer) || (*buffer == 0))
+ return (-1);
+
+ status = parse_string (&buffer, &value);
+ if (status != 0)
+ return (-1);
+
+ /* NB: parse_string will have eaten up all trailing spaces. */
+
+ *ret_buffer = buffer;
+ *ret_key = key;
+ *ret_value = value;
+
+ return (0);
+} /* int parse_option */
+
+int escape_string (char *buffer, size_t buffer_size)
+{
+ char *temp;
+ size_t i;
+ size_t j;
+
+ /* Check if we need to escape at all first */
+ temp = strpbrk (buffer, " \t\"\\");
+ if (temp == NULL)
+ return (0);
+
+ temp = (char *) malloc (buffer_size);
+ if (temp == NULL)
+ return (-1);
+ memset (temp, 0, buffer_size);
+
+ temp[0] = '"';
+ j = 1;
+
+ for (i = 0; i < buffer_size; i++)
+ {
+ if (buffer[i] == 0)
+ {
+ break;
+ }
+ else if ((buffer[i] == '"') || (buffer[i] == '\\'))
+ {
+ if (j > (buffer_size - 4))
+ break;
+ temp[j] = '\\';
+ temp[j + 1] = buffer[i];
+ j += 2;
+ }
+ else
+ {
+ if (j > (buffer_size - 3))
+ break;
+ temp[j] = buffer[i];
+ j++;
+ }
+ }
+
+ assert ((j + 1) < buffer_size);
+ temp[j] = '"';
+ temp[j + 1] = 0;
+
+ sstrncpy (buffer, temp, buffer_size);
+ sfree (temp);
+ return (0);
+} /* int escape_string */
+
+/* vim: set sw=2 ts=8 tw=78 et : */
diff --git a/src/daemon/utils_parse_option.h b/src/daemon/utils_parse_option.h
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+ * collectd - src/utils_parse_option.h
+ * Copyright (C) 2008 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#ifndef UTILS_PARSE_OPTION
+#define UTILS_PARSE_OPTION 1
+
+int parse_string (char **ret_buffer, char **ret_string);
+int parse_option (char **ret_buffer, char **ret_key, char **ret_value);
+
+int escape_string (char *buffer, size_t buffer_size);
+
+#endif /* UTILS_PARSE_OPTION */
+
+/* vim: set sw=2 ts=8 tw=78 et : */
diff --git a/src/daemon/utils_random.c b/src/daemon/utils_random.c
--- /dev/null
@@ -0,0 +1,75 @@
+/**
+ * collectd - src/utils_random.c
+ * Copyright (C) 2013 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian Forster <octo at collectd.org>
+ **/
+
+#include "collectd.h"
+#include "utils_time.h"
+
+#include <pthread.h>
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+static _Bool have_seed = 0;
+static unsigned short seed[3];
+
+static void cdrand_seed (void)
+{
+ cdtime_t t;
+
+ if (have_seed)
+ return;
+
+ t = cdtime();
+
+ seed[0] = (unsigned short) t;
+ seed[1] = (unsigned short) (t >> 16);
+ seed[2] = (unsigned short) (t >> 32);
+
+ have_seed = 1;
+}
+
+double cdrand_d (void)
+{
+ double r;
+
+ pthread_mutex_lock (&lock);
+ cdrand_seed ();
+ r = erand48 (seed);
+ pthread_mutex_unlock (&lock);
+
+ return (r);
+}
+
+long cdrand_range (long min, long max)
+{
+ long range;
+ long r;
+
+ range = 1 + max - min;
+
+ r = (long) (0.5 + (cdrand_d () * range));
+ r += min;
+
+ return (r);
+}
diff --git a/src/daemon/utils_random.h b/src/daemon/utils_random.h
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+ * collectd - src/utils_random.h
+ * Copyright (C) 2013 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian Forster <octo at collectd.org>
+ **/
+
+/**
+ * Returns a random double value in the range [0..1), i.e. excluding 1.
+ *
+ * This function is thread- and reentrant-safe.
+ */
+double cdrand_d (void);
+
+/**
+ * Returns a random long between min and max, inclusively.
+ *
+ * If min is larger than max, the result may be rounded incorrectly and may be
+ * outside the intended range. This function is thread- and reentrant-safe.
+ */
+long cdrand_range (long min, long max);
diff --git a/src/daemon/utils_subst.c b/src/daemon/utils_subst.c
--- /dev/null
+++ b/src/daemon/utils_subst.c
@@ -0,0 +1,149 @@
+/**
+ * collectd - src/utils_subst.c
+ * Copyright (C) 2008 Sebastian Harl
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Sebastian "tokkee" Harl <sh at tokkee.org>
+ **/
+
+/*
+ * This module provides functions for string substitution.
+ */
+
+#include "collectd.h"
+#include "common.h"
+
+char *subst (char *buf, size_t buflen, const char *string, int off1, int off2,
+ const char *replacement)
+{
+ char *buf_ptr = buf;
+ size_t len = buflen;
+
+ if ((NULL == buf) || (0 >= buflen) || (NULL == string)
+ || (0 > off1) || (0 > off2) || (off1 > off2)
+ || (NULL == replacement))
+ return NULL;
+
+ sstrncpy (buf_ptr, string,
+ ((size_t)off1 + 1 > buflen) ? buflen : (size_t)off1 + 1);
+ buf_ptr += off1;
+ len -= off1;
+
+ if (0 >= len)
+ return buf;
+
+ sstrncpy (buf_ptr, replacement, len);
+ buf_ptr += strlen (replacement);
+ len -= strlen (replacement);
+
+ if (0 >= len)
+ return buf;
+
+ sstrncpy (buf_ptr, string + off2, len);
+ return buf;
+} /* subst */
+
+char *asubst (const char *string, int off1, int off2, const char *replacement)
+{
+ char *buf;
+ int len;
+
+ char *ret;
+
+ if ((NULL == string) || (0 > off1) || (0 > off2) || (off1 > off2)
+ || (NULL ==replacement))
+ return NULL;
+
+ len = off1 + strlen (replacement) + strlen (string) - off2 + 1;
+
+ buf = (char *)malloc (len);
+ if (NULL == buf)
+ return NULL;
+
+ ret = subst (buf, len, string, off1, off2, replacement);
+ if (NULL == ret)
+ free (buf);
+ return ret;
+} /* asubst */
+
+char *subst_string (char *buf, size_t buflen, const char *string,
+ const char *needle, const char *replacement)
+{
+ char *temp;
+ size_t needle_len;
+ size_t i;
+
+ if ((buf == NULL) || (string == NULL)
+ || (needle == NULL) || (replacement == NULL))
+ return (NULL);
+
+ temp = (char *) malloc (buflen);
+ if (temp == NULL)
+ {
+ ERROR ("subst_string: malloc failed.");
+ return (NULL);
+ }
+
+ needle_len = strlen (needle);
+ strncpy (buf, string, buflen);
+
+ /* Limit the loop to prevent endless loops. */
+ for (i = 0; i < buflen; i++)
+ {
+ char *begin_ptr;
+ size_t begin;
+
+ /* Find `needle' in `buf'. */
+ begin_ptr = strstr (buf, needle);
+ if (begin_ptr == NULL)
+ break;
+
+ /* Calculate the start offset. */
+ begin = begin_ptr - buf;
+
+ /* Substitute the region using `subst'. The result is stored in
+ * `temp'. */
+ begin_ptr = subst (temp, buflen, buf,
+ begin, begin + needle_len,
+ replacement);
+ if (begin_ptr == NULL)
+ {
+ WARNING ("subst_string: subst failed.");
+ break;
+ }
+
+ /* Copy the new string in `temp' to `buf' for the next round. */
+ strncpy (buf, temp, buflen);
+ }
+
+ if (i >= buflen)
+ {
+ WARNING ("subst_string: Loop exited after %zu iterations: "
+ "string = %s; needle = %s; replacement = %s;",
+ i, string, needle, replacement);
+ }
+
+ sfree (temp);
+ return (buf);
+} /* char *subst_string */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
+
diff --git a/src/daemon/utils_subst.h b/src/daemon/utils_subst.h
--- /dev/null
+++ b/src/daemon/utils_subst.h
@@ -0,0 +1,105 @@
+/**
+ * collectd - src/utils_subst.h
+ * Copyright (C) 2008 Sebastian Harl
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Sebastian "tokkee" Harl <sh at tokkee.org>
+ **/
+
+/*
+ * This module provides functions for string substitution.
+ */
+
+#ifndef UTILS_SUBST_H
+#define UTILS_SUBST_H 1
+
+#include <stddef.h>
+
+/*
+ * subst:
+ *
+ * Replace a substring of a string with the specified replacement text. The
+ * resulting string is stored in the buffer pointed to by 'buf' of length
+ * 'buflen'. Upon success, the buffer will always be null-terminated. The
+ * result may be truncated if the buffer is too small.
+ *
+ * The substring to be replaces is identified by the two offsets 'off1' and
+ * 'off2' where 'off1' specifies the offset to the beginning of the substring
+ * and 'off2' specifies the offset to the first byte after the substring.
+ *
+ * The minimum buffer size to store the complete return value (including the
+ * terminating '\0' character) thus has to be:
+ * off1 + strlen(replacement) + strlen(string) - off2 + 1
+ *
+ * Example:
+ *
+ * 01234567890
+ * string = "foo_____bar"
+ * ^ ^
+ * | |
+ * off1 off2
+ *
+ * off1 = 3
+ * off2 = 8
+ *
+ * replacement = " - "
+ *
+ * -> "foo - bar"
+ *
+ * The function returns 'buf' on success, NULL else.
+ */
+char *subst (char *buf, size_t buflen, const char *string, int off1, int off2,
+ const char *replacement);
+
+/*
+ * asubst:
+ *
+ * This function is very similar to subst(). It differs in that it
+ * automatically allocates the memory required for the return value which the
+ * user then has to free himself.
+ *
+ * Returns the newly allocated result string on success, NULL else.
+ */
+char *asubst (const char *string, int off1, int off2, const char *replacement);
+
+/*
+ * subst_string:
+ *
+ * Works like `subst', but instead of specifying start and end offsets you
+ * specify `needle', the string that is to be replaced. If `needle' is found
+ * in `string' (using strstr(3)), the offset is calculated and `subst' is
+ * called with the determined parameters.
+ *
+ * If the substring is not found, no error will be indicated and
+ * `subst_string' works mostly like `strncpy'.
+ *
+ * If the substring appears multiple times, all appearances will be replaced.
+ * If the substring has been found `buflen' times, an endless loop is assumed
+ * and the loop is broken. A warning is printed and the function returns
+ * success.
+ */
+char *subst_string (char *buf, size_t buflen, const char *string,
+ const char *needle, const char *replacement);
+
+#endif /* UTILS_SUBST_H */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
+
diff --git a/src/daemon/utils_tail.c b/src/daemon/utils_tail.c
--- /dev/null
+++ b/src/daemon/utils_tail.c
@@ -0,0 +1,260 @@
+/**
+ * collectd - src/utils_tail.c
+ * Copyright (C) 2007-2008 C-Ware, Inc.
+ * Copyright (C) 2008 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Luke Heberling <lukeh at c-ware.com>
+ * Florian Forster <octo at collectd.org>
+ *
+ * Description:
+ * Encapsulates useful code for plugins which must watch for appends to
+ * the end of a file.
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "utils_tail.h"
+
+struct cu_tail_s
+{
+ char *file;
+ FILE *fh;
+ struct stat stat;
+};
+
+static int cu_tail_reopen (cu_tail_t *obj)
+{
+ int seek_end = 0;
+ FILE *fh;
+ struct stat stat_buf;
+ int status;
+
+ memset (&stat_buf, 0, sizeof (stat_buf));
+ status = stat (obj->file, &stat_buf);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("utils_tail: stat (%s) failed: %s", obj->file,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ /* The file is already open.. */
+ if ((obj->fh != NULL) && (stat_buf.st_ino == obj->stat.st_ino))
+ {
+ /* Seek to the beginning if file was truncated */
+ if (stat_buf.st_size < obj->stat.st_size)
+ {
+ INFO ("utils_tail: File `%s' was truncated.", obj->file);
+ status = fseek (obj->fh, 0, SEEK_SET);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("utils_tail: fseek (%s) failed: %s", obj->file,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ fclose (obj->fh);
+ obj->fh = NULL;
+ return (-1);
+ }
+ }
+ memcpy (&obj->stat, &stat_buf, sizeof (struct stat));
+ return (1);
+ }
+
+ /* Seek to the end if we re-open the same file again or the file opened
+ * is the first at all or the first after an error */
+ if ((obj->stat.st_ino == 0) || (obj->stat.st_ino == stat_buf.st_ino))
+ seek_end = 1;
+
+ fh = fopen (obj->file, "r");
+ if (fh == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("utils_tail: fopen (%s) failed: %s", obj->file,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ if (seek_end != 0)
+ {
+ status = fseek (fh, 0, SEEK_END);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("utils_tail: fseek (%s) failed: %s", obj->file,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ fclose (fh);
+ return (-1);
+ }
+ }
+
+ if (obj->fh != NULL)
+ fclose (obj->fh);
+ obj->fh = fh;
+ memcpy (&obj->stat, &stat_buf, sizeof (struct stat));
+
+ return (0);
+} /* int cu_tail_reopen */
+
+cu_tail_t *cu_tail_create (const char *file)
+{
+ cu_tail_t *obj;
+
+ obj = (cu_tail_t *) malloc (sizeof (cu_tail_t));
+ if (obj == NULL)
+ return (NULL);
+ memset (obj, '\0', sizeof (cu_tail_t));
+
+ obj->file = strdup (file);
+ if (obj->file == NULL)
+ {
+ free (obj);
+ return (NULL);
+ }
+
+ obj->fh = NULL;
+
+ return (obj);
+} /* cu_tail_t *cu_tail_create */
+
+int cu_tail_destroy (cu_tail_t *obj)
+{
+ if (obj->fh != NULL)
+ fclose (obj->fh);
+ free (obj->file);
+ free (obj);
+
+ return (0);
+} /* int cu_tail_destroy */
+
+int cu_tail_readline (cu_tail_t *obj, char *buf, int buflen)
+{
+ int status;
+
+ if (buflen < 1)
+ {
+ ERROR ("utils_tail: cu_tail_readline: buflen too small: %i bytes.",
+ buflen);
+ return (-1);
+ }
+
+ if (obj->fh == NULL)
+ {
+ status = cu_tail_reopen (obj);
+ if (status < 0)
+ return (status);
+ }
+ assert (obj->fh != NULL);
+
+ /* Try to read from the filehandle. If that succeeds, everything appears to
+ * be fine and we can return. */
+ clearerr (obj->fh);
+ if (fgets (buf, buflen, obj->fh) != NULL)
+ {
+ buf[buflen - 1] = 0;
+ return (0);
+ }
+
+ /* Check if we encountered an error */
+ if (ferror (obj->fh) != 0)
+ {
+ /* Jupp, error. Force `cu_tail_reopen' to reopen the file.. */
+ fclose (obj->fh);
+ obj->fh = NULL;
+ }
+ /* else: eof -> check if the file was moved away and reopen the new file if
+ * so.. */
+
+ status = cu_tail_reopen (obj);
+ /* error -> return with error */
+ if (status < 0)
+ return (status);
+ /* file end reached and file not reopened -> nothing more to read */
+ else if (status > 0)
+ {
+ buf[0] = 0;
+ return (0);
+ }
+
+ /* If we get here: file was re-opened and there may be more to read.. Let's
+ * try again. */
+ if (fgets (buf, buflen, obj->fh) != NULL)
+ {
+ buf[buflen - 1] = 0;
+ return (0);
+ }
+
+ if (ferror (obj->fh) != 0)
+ {
+ char errbuf[1024];
+ WARNING ("utils_tail: fgets (%s) returned an error: %s", obj->file,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ fclose (obj->fh);
+ obj->fh = NULL;
+ return (-1);
+ }
+
+ /* EOf, well, apparently the new file is empty.. */
+ buf[0] = 0;
+ return (0);
+} /* int cu_tail_readline */
+
+int cu_tail_read (cu_tail_t *obj, char *buf, int buflen, tailfunc_t *callback,
+ void *data)
+{
+ int status;
+
+ while (42)
+ {
+ size_t len;
+
+ status = cu_tail_readline (obj, buf, buflen);
+ if (status != 0)
+ {
+ ERROR ("utils_tail: cu_tail_read: cu_tail_readline "
+ "failed.");
+ break;
+ }
+
+ /* check for EOF */
+ if (buf[0] == 0)
+ break;
+
+ len = strlen (buf);
+ while (len > 0) {
+ if (buf[len - 1] != '\n')
+ break;
+ buf[len - 1] = '\0';
+ len--;
+ }
+
+ status = callback (data, buf, buflen);
+ if (status != 0)
+ {
+ ERROR ("utils_tail: cu_tail_read: callback returned "
+ "status %i.", status);
+ break;
+ }
+ }
+
+ return status;
+} /* int cu_tail_read */
diff --git a/src/daemon/utils_tail.h b/src/daemon/utils_tail.h
--- /dev/null
+++ b/src/daemon/utils_tail.h
@@ -0,0 +1,88 @@
+/**
+ * collectd - src/utils_tail.h
+ * Copyright (C) 2007-2008 C-Ware, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Luke Heberling <lukeh at c-ware.com>
+ *
+ * DESCRIPTION
+ * Facilitates reading information that is appended to a file, taking into
+ * account that the file may be rotated and a new file created under the
+ * same name.
+ **/
+
+#ifndef UTILS_TAIL_H
+#define UTILS_TAIL_H 1
+
+struct cu_tail_s;
+typedef struct cu_tail_s cu_tail_t;
+
+typedef int tailfunc_t(void *data, char *buf, int buflen);
+
+/*
+ * NAME
+ * cu_tail_create
+ *
+ * DESCRIPTION
+ * Allocates a new tail object..
+ *
+ * PARAMETERS
+ * `file' The name of the file to be tailed.
+ */
+cu_tail_t *cu_tail_create (const char *file);
+
+/*
+ * cu_tail_destroy
+ *
+ * Takes a tail object returned by `cu_tail_create' and destroys it, freeing
+ * all internal memory.
+ *
+ * Returns 0 when successful and non-zero otherwise.
+ */
+int cu_tail_destroy (cu_tail_t *obj);
+
+/*
+ * cu_tail_readline
+ *
+ * Reads from the file until `buflen' characters are read, a newline
+ * character is read, or an eof condition is encountered. `buf' is
+ * always null-terminated on successful return and isn't touched when non-zero
+ * is returned.
+ *
+ * You can check if the EOF condition is reached by looking at the buffer: If
+ * the length of the string stored in the buffer is zero, EOF occurred.
+ * Otherwise at least the newline character will be in the buffer.
+ *
+ * Returns 0 when successful and non-zero otherwise.
+ */
+int cu_tail_readline (cu_tail_t *obj, char *buf, int buflen);
+
+/*
+ * cu_tail_readline
+ *
+ * Reads from the file until eof condition or an error is encountered.
+ *
+ * Returns 0 when successful and non-zero otherwise.
+ */
+int cu_tail_read (cu_tail_t *obj, char *buf, int buflen, tailfunc_t *callback,
+ void *data);
+
+#endif /* UTILS_TAIL_H */
diff --git a/src/daemon/utils_tail_match.c b/src/daemon/utils_tail_match.c
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * collectd - src/utils_tail_match.c
+ * Copyright (C) 2007-2008 C-Ware, Inc.
+ * Copyright (C) 2008 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Luke Heberling <lukeh at c-ware.com>
+ * Florian Forster <octo at collectd.org>
+ *
+ * Description:
+ * Encapsulates useful code to plugins which must parse a log file.
+ */
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "utils_match.h"
+#include "utils_tail.h"
+#include "utils_tail_match.h"
+
+struct cu_tail_match_simple_s
+{
+ char plugin[DATA_MAX_NAME_LEN];
+ char plugin_instance[DATA_MAX_NAME_LEN];
+ char type[DATA_MAX_NAME_LEN];
+ char type_instance[DATA_MAX_NAME_LEN];
+ cdtime_t interval;
+};
+typedef struct cu_tail_match_simple_s cu_tail_match_simple_t;
+
+struct cu_tail_match_match_s
+{
+ cu_match_t *match;
+ void *user_data;
+ int (*submit) (cu_match_t *match, void *user_data);
+ void (*free) (void *user_data);
+};
+typedef struct cu_tail_match_match_s cu_tail_match_match_t;
+
+struct cu_tail_match_s
+{
+ int flags;
+ cu_tail_t *tail;
+
+ cdtime_t interval;
+ cu_tail_match_match_t *matches;
+ size_t matches_num;
+};
+
+/*
+ * Private functions
+ */
+static int simple_submit_match (cu_match_t *match, void *user_data)
+{
+ cu_tail_match_simple_t *data = (cu_tail_match_simple_t *) user_data;
+ cu_match_value_t *match_value;
+ value_list_t vl = VALUE_LIST_INIT;
+ value_t values[1];
+
+ match_value = (cu_match_value_t *) match_get_user_data (match);
+ if (match_value == NULL)
+ return (-1);
+
+ if ((match_value->ds_type & UTILS_MATCH_DS_TYPE_GAUGE)
+ && (match_value->values_num == 0))
+ values[0].gauge = NAN;
+ else
+ values[0] = match_value->value;
+
+ vl.values = values;
+ vl.values_len = 1;
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, data->plugin, sizeof (vl.plugin));
+ sstrncpy (vl.plugin_instance, data->plugin_instance,
+ sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, data->type, sizeof (vl.type));
+ sstrncpy (vl.type_instance, data->type_instance,
+ sizeof (vl.type_instance));
+
+ vl.interval = data->interval;
+ plugin_dispatch_values (&vl);
+
+ if (match_value->ds_type & UTILS_MATCH_DS_TYPE_GAUGE)
+ {
+ match_value->value.gauge = NAN;
+ match_value->values_num = 0;
+ }
+
+ return (0);
+} /* int simple_submit_match */
+
+static int tail_callback (void *data, char *buf,
+ int __attribute__((unused)) buflen)
+{
+ cu_tail_match_t *obj = (cu_tail_match_t *) data;
+ size_t i;
+
+ for (i = 0; i < obj->matches_num; i++)
+ match_apply (obj->matches[i].match, buf);
+
+ return (0);
+} /* int tail_callback */
+
+/*
+ * Public functions
+ */
+cu_tail_match_t *tail_match_create (const char *filename)
+{
+ cu_tail_match_t *obj;
+
+ obj = (cu_tail_match_t *) malloc (sizeof (cu_tail_match_t));
+ if (obj == NULL)
+ return (NULL);
+ memset (obj, '\0', sizeof (cu_tail_match_t));
+
+ obj->tail = cu_tail_create (filename);
+ if (obj->tail == NULL)
+ {
+ sfree (obj);
+ return (NULL);
+ }
+
+ return (obj);
+} /* cu_tail_match_t *tail_match_create */
+
+void tail_match_destroy (cu_tail_match_t *obj)
+{
+ size_t i;
+
+ if (obj == NULL)
+ return;
+
+ if (obj->tail != NULL)
+ {
+ cu_tail_destroy (obj->tail);
+ obj->tail = NULL;
+ }
+
+ for (i = 0; i < obj->matches_num; i++)
+ {
+ cu_tail_match_match_t *match = obj->matches + i;
+ if (match->match != NULL)
+ {
+ match_destroy (match->match);
+ match->match = NULL;
+ }
+
+ if ((match->user_data != NULL)
+ && (match->free != NULL))
+ (*match->free) (match->user_data);
+ match->user_data = NULL;
+ }
+
+ sfree (obj->matches);
+ sfree (obj);
+} /* void tail_match_destroy */
+
+int tail_match_add_match (cu_tail_match_t *obj, cu_match_t *match,
+ int (*submit_match) (cu_match_t *match, void *user_data),
+ void *user_data,
+ void (*free_user_data) (void *user_data))
+{
+ cu_tail_match_match_t *temp;
+
+ temp = (cu_tail_match_match_t *) realloc (obj->matches,
+ sizeof (cu_tail_match_match_t) * (obj->matches_num + 1));
+ if (temp == NULL)
+ return (-1);
+
+ obj->matches = temp;
+ obj->matches_num++;
+
+ DEBUG ("tail_match_add_match interval %lf", CDTIME_T_TO_DOUBLE(((cu_tail_match_simple_t *)user_data)->interval));
+ temp = obj->matches + (obj->matches_num - 1);
+
+ temp->match = match;
+ temp->user_data = user_data;
+ temp->submit = submit_match;
+ temp->free = free_user_data;
+
+ return (0);
+} /* int tail_match_add_match */
+
+int tail_match_add_match_simple (cu_tail_match_t *obj,
+ const char *regex, const char *excluderegex, int ds_type,
+ const char *plugin, const char *plugin_instance,
+ const char *type, const char *type_instance, const cdtime_t interval)
+{
+ cu_match_t *match;
+ cu_tail_match_simple_t *user_data;
+ int status;
+
+ match = match_create_simple (regex, excluderegex, ds_type);
+ if (match == NULL)
+ return (-1);
+
+ user_data = (cu_tail_match_simple_t *) malloc (sizeof (cu_tail_match_simple_t));
+ if (user_data == NULL)
+ {
+ match_destroy (match);
+ return (-1);
+ }
+ memset (user_data, '\0', sizeof (cu_tail_match_simple_t));
+
+ sstrncpy (user_data->plugin, plugin, sizeof (user_data->plugin));
+ if (plugin_instance != NULL)
+ sstrncpy (user_data->plugin_instance, plugin_instance,
+ sizeof (user_data->plugin_instance));
+
+ sstrncpy (user_data->type, type, sizeof (user_data->type));
+ if (type_instance != NULL)
+ sstrncpy (user_data->type_instance, type_instance,
+ sizeof (user_data->type_instance));
+
+ user_data->interval = interval;
+
+ status = tail_match_add_match (obj, match, simple_submit_match,
+ user_data, free);
+
+ if (status != 0)
+ {
+ match_destroy (match);
+ sfree (user_data);
+ }
+
+ return (status);
+} /* int tail_match_add_match_simple */
+
+int tail_match_read (cu_tail_match_t *obj)
+{
+ char buffer[4096];
+ int status;
+ size_t i;
+
+ status = cu_tail_read (obj->tail, buffer, sizeof (buffer), tail_callback,
+ (void *) obj);
+ if (status != 0)
+ {
+ ERROR ("tail_match: cu_tail_read failed.");
+ return (status);
+ }
+
+ for (i = 0; i < obj->matches_num; i++)
+ {
+ cu_tail_match_match_t *lt_match = obj->matches + i;
+
+ if (lt_match->submit == NULL)
+ continue;
+
+ (*lt_match->submit) (lt_match->match, lt_match->user_data);
+ }
+
+ return (0);
+} /* int tail_match_read */
+
+/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/daemon/utils_tail_match.h b/src/daemon/utils_tail_match.h
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * collectd - src/utils_tail_match.h
+ * Copyright (C) 2007-2008 C-Ware, Inc.
+ * Copyright (C) 2008 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Luke Heberling <lukeh at c-ware.com>
+ * Florian Forster <octo at collectd.org>
+ *
+ * Description:
+ * `tail_match' uses `utils_tail' and `utils_match' to tail a file and try to
+ * match it using several regular expressions. Matches are then passed to
+ * user-provided callback functions or default handlers. This should keep all
+ * of the parsing logic out of the actual plugin, which only operate with
+ * regular expressions.
+ */
+
+#include "utils_match.h"
+
+struct cu_tail_match_s;
+typedef struct cu_tail_match_s cu_tail_match_t;
+
+/*
+ * NAME
+ * tail_match_create
+ *
+ * DESCRIPTION
+ * Allocates, initializes and returns a new `cu_tail_match_t' object.
+ *
+ * PARAMETERS
+ * `filename' The name to read data from.
+ *
+ * RETURN VALUE
+ * Returns NULL upon failure, non-NULL otherwise.
+ */
+cu_tail_match_t *tail_match_create (const char *filename);
+
+/*
+ * NAME
+ * tail_match_destroy
+ *
+ * DESCRIPTION
+ * Releases resources used by the `cu_tail_match_t' object.
+ *
+ * PARAMETERS
+ * The object to destroy.
+ */
+void tail_match_destroy (cu_tail_match_t *obj);
+
+/*
+ * NAME
+ * tail_match_add_match
+ *
+ * DESCRIPTION
+ * Adds a match, in form of a `cu_match_t' object, to the object.
+ * After data has been read from the logfile (using utils_tail) the callback
+ * function `submit_match' is called with the match object and the user
+ * supplied data.
+ * Please note that his function is called regardless whether this match
+ * matched any lines recently or not.
+ * When `tail_match_destroy' is called the `user_data' pointer is freed using
+ * the `free_user_data' callback - if it is not NULL.
+ * When using this interface the `tail_match' module doesn't dispatch any values
+ * itself - all that has to happen in either the match-callbacks or the
+ * submit_match callback.
+ *
+ * RETURN VALUE
+ * Zero upon success, non-zero otherwise.
+ */
+int tail_match_add_match (cu_tail_match_t *obj, cu_match_t *match,
+ int (*submit_match) (cu_match_t *match, void *user_data),
+ void *user_data,
+ void (*free_user_data) (void *user_data));
+
+/*
+ * NAME
+ * tail_match_add_match_simple
+ *
+ * DESCRIPTION
+ * A simplified version of `tail_match_add_match'. The regular expressen `regex'
+ * must match a number, which is then dispatched according to `ds_type'. See
+ * the `match_create_simple' function in utils_match.h for a description how
+ * this flag effects calculation of a new value.
+ * The values gathered are dispatched by the tail_match module in this case. The
+ * passed `plugin', `plugin_instance', `type', and `type_instance' are
+ * directly used when submitting these values.
+ * With excluderegex it is possible to exlude lines from the match.
+ *
+ * RETURN VALUE
+ * Zero upon success, non-zero otherwise.
+ */
+int tail_match_add_match_simple (cu_tail_match_t *obj,
+ const char *regex, const char *excluderegex, int ds_type,
+ const char *plugin, const char *plugin_instance,
+ const char *type, const char *type_instance, const cdtime_t interval);
+
+/*
+ * NAME
+ * tail_match_read
+ *
+ * DESCRIPTION
+ * This function should be called periodically by plugins. It reads new lines
+ * from the logfile using `utils_tail' and tries to match them using all
+ * added `utils_match' objects.
+ * After all lines have been read and processed, the submit_match callback is
+ * called or, in case of tail_match_add_match_simple, the data is dispatched to
+ * the daemon directly.
+ *
+ * RETURN VALUE
+ * Zero on success, nonzero on failure.
+*/
+int tail_match_read (cu_tail_match_t *obj);
+
+/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/daemon/utils_threshold.c b/src/daemon/utils_threshold.c
--- /dev/null
@@ -0,0 +1,143 @@
+/**
+ * collectd - src/utils_threshold.c
+ * Copyright (C) 2014 Pierre-Yves Ritschard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Pierre-Yves Ritschard <pyr at spootnik.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "utils_avltree.h"
+#include "utils_threshold.h"
+
+#include <pthread.h>
+
+/*
+ * Exported symbols
+ * {{{ */
+c_avl_tree_t *threshold_tree = NULL;
+pthread_mutex_t threshold_lock = PTHREAD_MUTEX_INITIALIZER;
+/* }}} */
+
+/*
+ * threshold_t *threshold_get
+ *
+ * Retrieve one specific threshold configuration. For looking up a threshold
+ * matching a value_list_t, see "threshold_search" below. Returns NULL if the
+ * specified threshold doesn't exist.
+ */
+threshold_t *threshold_get (const char *hostname,
+ const char *plugin, const char *plugin_instance,
+ const char *type, const char *type_instance)
+{ /* {{{ */
+ char name[6 * DATA_MAX_NAME_LEN];
+ threshold_t *th = NULL;
+
+ format_name (name, sizeof (name),
+ (hostname == NULL) ? "" : hostname,
+ (plugin == NULL) ? "" : plugin, plugin_instance,
+ (type == NULL) ? "" : type, type_instance);
+ name[sizeof (name) - 1] = '\0';
+
+ if (c_avl_get (threshold_tree, name, (void *) &th) == 0)
+ return (th);
+ else
+ return (NULL);
+} /* }}} threshold_t *threshold_get */
+
+/*
+ * threshold_t *threshold_search
+ *
+ * Searches for a threshold configuration using all the possible variations of
+ * "Host", "Plugin" and "Type" blocks. Returns NULL if no threshold could be
+ * found.
+ * XXX: This is likely the least efficient function in collectd.
+ */
+threshold_t *threshold_search (const value_list_t *vl)
+{ /* {{{ */
+ threshold_t *th;
+
+ if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
+ vl->type, vl->type_instance)) != NULL)
+ return (th);
+ else if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
+ vl->type, NULL)) != NULL)
+ return (th);
+ else if ((th = threshold_get (vl->host, vl->plugin, NULL,
+ vl->type, vl->type_instance)) != NULL)
+ return (th);
+ else if ((th = threshold_get (vl->host, vl->plugin, NULL,
+ vl->type, NULL)) != NULL)
+ return (th);
+ else if ((th = threshold_get (vl->host, "", NULL,
+ vl->type, vl->type_instance)) != NULL)
+ return (th);
+ else if ((th = threshold_get (vl->host, "", NULL,
+ vl->type, NULL)) != NULL)
+ return (th);
+ else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
+ vl->type, vl->type_instance)) != NULL)
+ return (th);
+ else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
+ vl->type, NULL)) != NULL)
+ return (th);
+ else if ((th = threshold_get ("", vl->plugin, NULL,
+ vl->type, vl->type_instance)) != NULL)
+ return (th);
+ else if ((th = threshold_get ("", vl->plugin, NULL,
+ vl->type, NULL)) != NULL)
+ return (th);
+ else if ((th = threshold_get ("", "", NULL,
+ vl->type, vl->type_instance)) != NULL)
+ return (th);
+ else if ((th = threshold_get ("", "", NULL,
+ vl->type, NULL)) != NULL)
+ return (th);
+
+ return (NULL);
+} /* }}} threshold_t *threshold_search */
+
+int ut_search_threshold (const value_list_t *vl, /* {{{ */
+ threshold_t *ret_threshold)
+{
+ threshold_t *t;
+
+ if (vl == NULL)
+ return (EINVAL);
+
+ /* Is this lock really necessary? */
+ pthread_mutex_lock (&threshold_lock);
+ t = threshold_search (vl);
+ if (t == NULL) {
+ pthread_mutex_unlock (&threshold_lock);
+ return (ENOENT);
+ }
+
+ memcpy (ret_threshold, t, sizeof (*ret_threshold));
+ pthread_mutex_unlock (&threshold_lock);
+
+ ret_threshold->next = NULL;
+
+ return (0);
+} /* }}} int ut_search_threshold */
+
+
diff --git a/src/daemon/utils_threshold.h b/src/daemon/utils_threshold.h
--- /dev/null
@@ -0,0 +1,67 @@
+/**
+ * collectd - src/utils_threshold.h
+ * Copyright (C) 2014 Pierre-Yves Ritschard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Pierre-Yves Ritschard <pyr at spootnik.org>
+ **/
+
+#ifndef UTILS_THRESHOLD_H
+#define UTILS_THRESHOLD_H 1
+
+#define UT_FLAG_INVERT 0x01
+#define UT_FLAG_PERSIST 0x02
+#define UT_FLAG_PERCENTAGE 0x04
+#define UT_FLAG_INTERESTING 0x08
+#define UT_FLAG_PERSIST_OK 0x10
+typedef struct threshold_s
+{
+ char host[DATA_MAX_NAME_LEN];
+ char plugin[DATA_MAX_NAME_LEN];
+ char plugin_instance[DATA_MAX_NAME_LEN];
+ char type[DATA_MAX_NAME_LEN];
+ char type_instance[DATA_MAX_NAME_LEN];
+ char data_source[DATA_MAX_NAME_LEN];
+ gauge_t warning_min;
+ gauge_t warning_max;
+ gauge_t failure_min;
+ gauge_t failure_max;
+ gauge_t hysteresis;
+ unsigned int flags;
+ int hits;
+ struct threshold_s *next;
+} threshold_t;
+
+extern c_avl_tree_t *threshold_tree;
+extern pthread_mutex_t threshold_lock;
+
+threshold_t *threshold_get (const char *hostname,
+ const char *plugin, const char *plugin_instance,
+ const char *type, const char *type_instance);
+
+threshold_t *threshold_search (const value_list_t *vl);
+
+int ut_search_threshold (const value_list_t *vl,
+ threshold_t *ret_threshold);
+
+#endif /* UTILS_THRESHOLD_H */
+
+/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/daemon/utils_time.c b/src/daemon/utils_time.c
--- /dev/null
+++ b/src/daemon/utils_time.c
@@ -0,0 +1,104 @@
+/**
+ * collectd - src/utils_time.c
+ * Copyright (C) 2010 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <ff at octo.it>
+ **/
+
+#include "collectd.h"
+#include "utils_time.h"
+#include "plugin.h"
+#include "common.h"
+
+#if HAVE_CLOCK_GETTIME
+cdtime_t cdtime (void) /* {{{ */
+{
+ int status;
+ struct timespec ts = { 0, 0 };
+
+ status = clock_gettime (CLOCK_REALTIME, &ts);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("cdtime: clock_gettime failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (0);
+ }
+
+ return (TIMESPEC_TO_CDTIME_T (&ts));
+} /* }}} cdtime_t cdtime */
+#else
+/* Work around for Mac OS X which doesn't have clock_gettime(2). *sigh* */
+cdtime_t cdtime (void) /* {{{ */
+{
+ int status;
+ struct timeval tv = { 0, 0 };
+
+ status = gettimeofday (&tv, /* struct timezone = */ NULL);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("cdtime: gettimeofday failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (0);
+ }
+
+ return (TIMEVAL_TO_CDTIME_T (&tv));
+} /* }}} cdtime_t cdtime */
+#endif
+
+size_t cdtime_to_iso8601 (char *s, size_t max, cdtime_t t) /* {{{ */
+{
+ struct timespec t_spec;
+ struct tm t_tm;
+
+ size_t len;
+
+ CDTIME_T_TO_TIMESPEC (t, &t_spec);
+ NORMALIZE_TIMESPEC (t_spec);
+
+ if (localtime_r ((time_t *)&t_spec.tv_sec, &t_tm) == NULL) {
+ char errbuf[1024];
+ ERROR ("cdtime_to_iso8601: localtime_r failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (0);
+ }
+
+ len = strftime (s, max, "%Y-%m-%dT%H:%M:%S", &t_tm);
+ if (len == 0)
+ return 0;
+
+ if (max - len > 2) {
+ int n = snprintf (s + len, max - len, ".%09i", (int)t_spec.tv_nsec);
+ len += (n < max - len) ? n : max - len;
+ }
+
+ if (max - len > 3) {
+ int n = strftime (s + len, max - len, "%z", &t_tm);
+ len += (n < max - len) ? n : max - len;
+ }
+
+ s[max - 1] = '\0';
+ return len;
+} /* }}} size_t cdtime_to_iso8601 */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/daemon/utils_time.h b/src/daemon/utils_time.h
--- /dev/null
+++ b/src/daemon/utils_time.h
@@ -0,0 +1,81 @@
+/**
+ * collectd - src/utils_time.h
+ * Copyright (C) 2010 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <ff at octo.it>
+ **/
+
+#ifndef UTILS_TIME_H
+#define UTILS_TIME_H 1
+
+#include "collectd.h"
+
+/*
+ * "cdtime_t" is a 64bit unsigned integer. The time is stored at a 2^-30 second
+ * resolution, i.e. the most significant 34 bit are used to store the time in
+ * seconds, the least significant bits store the sub-second part in something
+ * very close to nanoseconds. *The* big advantage of storing time in this
+ * manner is that comparing times and calculating differences is as simple as
+ * it is with "time_t", i.e. a simple integer comparison / subtraction works.
+ */
+/*
+ * cdtime_t is defined in "collectd.h" */
+/* typedef uint64_t cdtime_t; */
+
+/* 2^30 = 1073741824 */
+#define TIME_T_TO_CDTIME_T(t) (((cdtime_t) (t)) * 1073741824)
+#define CDTIME_T_TO_TIME_T(t) ((time_t) ((t) / 1073741824))
+
+#define CDTIME_T_TO_DOUBLE(t) (((double) (t)) / 1073741824.0)
+#define DOUBLE_TO_CDTIME_T(d) ((cdtime_t) ((d) * 1073741824.0))
+
+#define MS_TO_CDTIME_T(ms) ((cdtime_t) (((double) (ms)) * 1073741.824))
+#define CDTIME_T_TO_MS(t) ((long) (((double) (t)) / 1073741.824))
+#define US_TO_CDTIME_T(us) ((cdtime_t) (((double) (us)) * 1073.741824))
+#define CDTIME_T_TO_US(t) ((suseconds_t) (((double) (t)) / 1073.741824))
+#define NS_TO_CDTIME_T(ns) ((cdtime_t) (((double) (ns)) * 1.073741824))
+#define CDTIME_T_TO_NS(t) ((long) (((double) (t)) / 1.073741824))
+
+#define CDTIME_T_TO_TIMEVAL(cdt,tvp) do { \
+ (tvp)->tv_sec = CDTIME_T_TO_TIME_T (cdt); \
+ (tvp)->tv_usec = CDTIME_T_TO_US ((cdt) % 1073741824); \
+} while (0)
+#define TIMEVAL_TO_CDTIME_T(tv) (TIME_T_TO_CDTIME_T ((tv)->tv_sec) \
+ + US_TO_CDTIME_T ((tv)->tv_usec))
+
+#define CDTIME_T_TO_TIMESPEC(cdt,tsp) do { \
+ (tsp)->tv_sec = CDTIME_T_TO_TIME_T (cdt); \
+ (tsp)->tv_nsec = CDTIME_T_TO_NS ((cdt) % 1073741824); \
+} while (0)
+#define TIMESPEC_TO_CDTIME_T(ts) (TIME_T_TO_CDTIME_T ((ts)->tv_sec) \
+ + NS_TO_CDTIME_T ((ts)->tv_nsec))
+
+cdtime_t cdtime (void);
+
+/* format a cdtime_t value in ISO 8601 format:
+ * returns the number of characters written to the string (not including the
+ * terminating null byte or 0 on error; the function ensures that the string
+ * is null terminated */
+size_t cdtime_to_iso8601 (char *s, size_t max, cdtime_t t);
+
+#endif /* UTILS_TIME_H */
+/* vim: set sw=2 sts=2 et : */
diff --git a/src/filter_chain.c b/src/filter_chain.c
--- a/src/filter_chain.c
+++ /dev/null
@@ -1,1058 +0,0 @@
-/**
- * collectd - src/filter_chain.c
- * Copyright (C) 2008-2010 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#include "collectd.h"
-#include "configfile.h"
-#include "plugin.h"
-#include "utils_complain.h"
-#include "common.h"
-#include "filter_chain.h"
-
-/*
- * Data types
- */
-/* List of matches, used in fc_rule_t and for the global `match_list_head'
- * variable. */
-struct fc_match_s;
-typedef struct fc_match_s fc_match_t; /* {{{ */
-struct fc_match_s
-{
- char name[DATA_MAX_NAME_LEN];
- match_proc_t proc;
- void *user_data;
- fc_match_t *next;
-}; /* }}} */
-
-/* List of targets, used in fc_rule_t and for the global `target_list_head'
- * variable. */
-struct fc_target_s;
-typedef struct fc_target_s fc_target_t; /* {{{ */
-struct fc_target_s
-{
- char name[DATA_MAX_NAME_LEN];
- void *user_data;
- target_proc_t proc;
- fc_target_t *next;
-}; /* }}} */
-
-/* List of rules, used in fc_chain_t */
-struct fc_rule_s;
-typedef struct fc_rule_s fc_rule_t; /* {{{ */
-struct fc_rule_s
-{
- char name[DATA_MAX_NAME_LEN];
- fc_match_t *matches;
- fc_target_t *targets;
- fc_rule_t *next;
-}; /* }}} */
-
-/* List of chains, used for `chain_list_head' */
-struct fc_chain_s /* {{{ */
-{
- char name[DATA_MAX_NAME_LEN];
- fc_rule_t *rules;
- fc_target_t *targets;
- fc_chain_t *next;
-}; /* }}} */
-
-/*
- * Global variables
- */
-static fc_match_t *match_list_head;
-static fc_target_t *target_list_head;
-static fc_chain_t *chain_list_head;
-
-/*
- * Private functions
- */
-static void fc_free_matches (fc_match_t *m) /* {{{ */
-{
- if (m == NULL)
- return;
-
- if (m->proc.destroy != NULL)
- (*m->proc.destroy) (&m->user_data);
- else if (m->user_data != NULL)
- {
- ERROR ("Filter subsystem: fc_free_matches: There is user data, but no "
- "destroy functions has been specified. "
- "Memory will probably be lost!");
- }
-
- if (m->next != NULL)
- fc_free_matches (m->next);
-
- free (m);
-} /* }}} void fc_free_matches */
-
-static void fc_free_targets (fc_target_t *t) /* {{{ */
-{
- if (t == NULL)
- return;
-
- if (t->proc.destroy != NULL)
- (*t->proc.destroy) (&t->user_data);
- else if (t->user_data != NULL)
- {
- ERROR ("Filter subsystem: fc_free_targets: There is user data, but no "
- "destroy functions has been specified. "
- "Memory will probably be lost!");
- }
-
- if (t->next != NULL)
- fc_free_targets (t->next);
-
- free (t);
-} /* }}} void fc_free_targets */
-
-static void fc_free_rules (fc_rule_t *r) /* {{{ */
-{
- if (r == NULL)
- return;
-
- fc_free_matches (r->matches);
- fc_free_targets (r->targets);
-
- if (r->next != NULL)
- fc_free_rules (r->next);
-
- free (r);
-} /* }}} void fc_free_rules */
-
-static void fc_free_chains (fc_chain_t *c) /* {{{ */
-{
- if (c == NULL)
- return;
-
- fc_free_rules (c->rules);
- fc_free_targets (c->targets);
-
- if (c->next != NULL)
- fc_free_chains (c->next);
-
- free (c);
-} /* }}} void fc_free_chains */
-
-static char *fc_strdup (const char *orig) /* {{{ */
-{
- size_t sz;
- char *dest;
-
- if (orig == NULL)
- return (NULL);
-
- sz = strlen (orig) + 1;
- dest = (char *) malloc (sz);
- if (dest == NULL)
- return (NULL);
-
- memcpy (dest, orig, sz);
-
- return (dest);
-} /* }}} char *fc_strdup */
-
-/*
- * Configuration.
- *
- * The configuration looks somewhat like this:
- *
- * <Chain "PreCache">
- * <Rule>
- * <Match "regex">
- * Plugin "^mysql$"
- * Type "^mysql_command$"
- * TypeInstance "^show_"
- * </Match>
- * <Target "drop">
- * </Target>
- * </Rule>
- *
- * <Target "write">
- * Plugin "rrdtool"
- * </Target>
- * </Chain>
- */
-static int fc_config_add_match (fc_match_t **matches_head, /* {{{ */
- oconfig_item_t *ci)
-{
- fc_match_t *m;
- fc_match_t *ptr;
- int status;
-
- if ((ci->values_num != 1)
- || (ci->values[0].type != OCONFIG_TYPE_STRING))
- {
- WARNING ("Filter subsystem: `Match' blocks require "
- "exactly one string argument.");
- return (-1);
- }
-
- ptr = match_list_head;
- while (ptr != NULL)
- {
- if (strcasecmp (ptr->name, ci->values[0].value.string) == 0)
- break;
- ptr = ptr->next;
- }
-
- if (ptr == NULL)
- {
- WARNING ("Filter subsystem: Cannot find a \"%s\" match. "
- "Did you load the appropriate plugin?",
- ci->values[0].value.string);
- return (-1);
- }
-
- m = (fc_match_t *) malloc (sizeof (*m));
- if (m == NULL)
- {
- ERROR ("fc_config_add_match: malloc failed.");
- return (-1);
- }
- memset (m, 0, sizeof (*m));
-
- sstrncpy (m->name, ptr->name, sizeof (m->name));
- memcpy (&m->proc, &ptr->proc, sizeof (m->proc));
- m->user_data = NULL;
- m->next = NULL;
-
- if (m->proc.create != NULL)
- {
- status = (*m->proc.create) (ci, &m->user_data);
- if (status != 0)
- {
- WARNING ("Filter subsystem: Failed to create a %s match.",
- m->name);
- fc_free_matches (m);
- return (-1);
- }
- }
-
- if (*matches_head != NULL)
- {
- ptr = *matches_head;
- while (ptr->next != NULL)
- ptr = ptr->next;
-
- ptr->next = m;
- }
- else
- {
- *matches_head = m;
- }
-
- return (0);
-} /* }}} int fc_config_add_match */
-
-static int fc_config_add_target (fc_target_t **targets_head, /* {{{ */
- oconfig_item_t *ci)
-{
- fc_target_t *t;
- fc_target_t *ptr;
- int status;
-
- if ((ci->values_num != 1)
- || (ci->values[0].type != OCONFIG_TYPE_STRING))
- {
- WARNING ("Filter subsystem: `Target' blocks require "
- "exactly one string argument.");
- return (-1);
- }
-
- ptr = target_list_head;
- while (ptr != NULL)
- {
- if (strcasecmp (ptr->name, ci->values[0].value.string) == 0)
- break;
- ptr = ptr->next;
- }
-
- if (ptr == NULL)
- {
- WARNING ("Filter subsystem: Cannot find a \"%s\" target. "
- "Did you load the appropriate plugin?",
- ci->values[0].value.string);
- return (-1);
- }
-
- t = (fc_target_t *) malloc (sizeof (*t));
- if (t == NULL)
- {
- ERROR ("fc_config_add_target: malloc failed.");
- return (-1);
- }
- memset (t, 0, sizeof (*t));
-
- sstrncpy (t->name, ptr->name, sizeof (t->name));
- memcpy (&t->proc, &ptr->proc, sizeof (t->proc));
- t->user_data = NULL;
- t->next = NULL;
-
- if (t->proc.create != NULL)
- {
- status = (*t->proc.create) (ci, &t->user_data);
- if (status != 0)
- {
- WARNING ("Filter subsystem: Failed to create a %s target.",
- t->name);
- fc_free_targets (t);
- return (-1);
- }
- }
- else
- {
- t->user_data = NULL;
- }
-
- if (*targets_head != NULL)
- {
- ptr = *targets_head;
- while (ptr->next != NULL)
- ptr = ptr->next;
-
- ptr->next = t;
- }
- else
- {
- *targets_head = t;
- }
-
- return (0);
-} /* }}} int fc_config_add_target */
-
-static int fc_config_add_rule (fc_chain_t *chain, /* {{{ */
- oconfig_item_t *ci)
-{
- fc_rule_t *rule;
- char rule_name[2*DATA_MAX_NAME_LEN] = "Unnamed rule";
- int status = 0;
- int i;
-
- if (ci->values_num > 1)
- {
- WARNING ("Filter subsystem: `Rule' blocks have at most one argument.");
- return (-1);
- }
- else if ((ci->values_num == 1)
- && (ci->values[0].type != OCONFIG_TYPE_STRING))
- {
- WARNING ("Filter subsystem: `Rule' blocks expect one string argument "
- "or no argument at all.");
- return (-1);
- }
-
- rule = (fc_rule_t *) malloc (sizeof (*rule));
- if (rule == NULL)
- {
- ERROR ("fc_config_add_rule: malloc failed.");
- return (-1);
- }
- memset (rule, 0, sizeof (*rule));
- rule->next = NULL;
-
- if (ci->values_num == 1)
- {
- sstrncpy (rule->name, ci->values[0].value.string, sizeof (rule->name));
- ssnprintf (rule_name, sizeof (rule_name), "Rule \"%s\"",
- ci->values[0].value.string);
- }
-
- for (i = 0; i < ci->children_num; i++)
- {
- oconfig_item_t *option = ci->children + i;
- status = 0;
-
- if (strcasecmp ("Match", option->key) == 0)
- status = fc_config_add_match (&rule->matches, option);
- else if (strcasecmp ("Target", option->key) == 0)
- status = fc_config_add_target (&rule->targets, option);
- else
- {
- WARNING ("Filter subsystem: %s: Option `%s' not allowed "
- "inside a <Rule> block.", rule_name, option->key);
- status = -1;
- }
-
- if (status != 0)
- break;
- } /* for (ci->children) */
-
- /* Additional sanity checking. */
- while (status == 0)
- {
- if (rule->targets == NULL)
- {
- WARNING ("Filter subsystem: %s: No target has been specified.",
- rule_name);
- status = -1;
- break;
- }
-
- break;
- } /* while (status == 0) */
-
- if (status != 0)
- {
- fc_free_rules (rule);
- return (-1);
- }
-
- if (chain->rules != NULL)
- {
- fc_rule_t *ptr;
-
- ptr = chain->rules;
- while (ptr->next != NULL)
- ptr = ptr->next;
-
- ptr->next = rule;
- }
- else
- {
- chain->rules = rule;
- }
-
- return (0);
-} /* }}} int fc_config_add_rule */
-
-static int fc_config_add_chain (const oconfig_item_t *ci) /* {{{ */
-{
- fc_chain_t *chain = NULL;
- int status = 0;
- int i;
- int new_chain = 1;
-
- if ((ci->values_num != 1)
- || (ci->values[0].type != OCONFIG_TYPE_STRING))
- {
- WARNING ("Filter subsystem: <Chain> blocks require exactly one "
- "string argument.");
- return (-1);
- }
-
- if (chain_list_head != NULL)
- {
- if ((chain = fc_chain_get_by_name (ci->values[0].value.string)) != NULL)
- new_chain = 0;
- }
-
- if (chain == NULL)
- {
- chain = (fc_chain_t *) malloc (sizeof (*chain));
- if (chain == NULL)
- {
- ERROR ("fc_config_add_chain: malloc failed.");
- return (-1);
- }
- memset (chain, 0, sizeof (*chain));
- sstrncpy (chain->name, ci->values[0].value.string, sizeof (chain->name));
- chain->rules = NULL;
- chain->targets = NULL;
- chain->next = NULL;
- }
-
- for (i = 0; i < ci->children_num; i++)
- {
- oconfig_item_t *option = ci->children + i;
- status = 0;
-
- if (strcasecmp ("Rule", option->key) == 0)
- status = fc_config_add_rule (chain, option);
- else if (strcasecmp ("Target", option->key) == 0)
- status = fc_config_add_target (&chain->targets, option);
- else
- {
- WARNING ("Filter subsystem: Chain %s: Option `%s' not allowed "
- "inside a <Chain> block.", chain->name, option->key);
- status = -1;
- }
-
- if (status != 0)
- break;
- } /* for (ci->children) */
-
- if (status != 0)
- {
- fc_free_chains (chain);
- return (-1);
- }
-
- if (chain_list_head != NULL)
- {
- if (!new_chain)
- return (0);
-
- fc_chain_t *ptr;
-
- ptr = chain_list_head;
- while (ptr->next != NULL)
- ptr = ptr->next;
-
- ptr->next = chain;
- }
- else
- {
- chain_list_head = chain;
- }
-
- return (0);
-} /* }}} int fc_config_add_chain */
-
-/*
- * Built-in target "jump"
- *
- * Prefix `bit' like `_b_uilt-_i_n _t_arget'
- */
-static int fc_bit_jump_create (const oconfig_item_t *ci, /* {{{ */
- void **user_data)
-{
- oconfig_item_t *ci_chain;
-
- if (ci->children_num != 1)
- {
- ERROR ("Filter subsystem: The built-in target `jump' needs exactly "
- "one `Chain' argument!");
- return (-1);
- }
-
- ci_chain = ci->children;
- if (strcasecmp ("Chain", ci_chain->key) != 0)
- {
- ERROR ("Filter subsystem: The built-in target `jump' does not "
- "support the configuration option `%s'.",
- ci_chain->key);
- return (-1);
- }
-
- if ((ci_chain->values_num != 1)
- || (ci_chain->values[0].type != OCONFIG_TYPE_STRING))
- {
- ERROR ("Filter subsystem: Built-in target `jump': The `Chain' option "
- "needs exactly one string argument.");
- return (-1);
- }
-
- *user_data = fc_strdup (ci_chain->values[0].value.string);
- if (*user_data == NULL)
- {
- ERROR ("fc_bit_jump_create: fc_strdup failed.");
- return (-1);
- }
-
- return (0);
-} /* }}} int fc_bit_jump_create */
-
-static int fc_bit_jump_destroy (void **user_data) /* {{{ */
-{
- if (user_data != NULL)
- {
- free (*user_data);
- *user_data = NULL;
- }
-
- return (0);
-} /* }}} int fc_bit_jump_destroy */
-
-static int fc_bit_jump_invoke (const data_set_t *ds, /* {{{ */
- value_list_t *vl, notification_meta_t __attribute__((unused)) **meta,
- void **user_data)
-{
- char *chain_name;
- fc_chain_t *chain;
- int status;
-
- chain_name = *user_data;
-
- for (chain = chain_list_head; chain != NULL; chain = chain->next)
- if (strcasecmp (chain_name, chain->name) == 0)
- break;
-
- if (chain == NULL)
- {
- ERROR ("Filter subsystem: Built-in target `jump': There is no chain "
- "named `%s'.", chain_name);
- return (-1);
- }
-
- status = fc_process_chain (ds, vl, chain);
- if (status < 0)
- return (status);
- else if (status == FC_TARGET_STOP)
- return (FC_TARGET_STOP);
- else
- return (FC_TARGET_CONTINUE);
-} /* }}} int fc_bit_jump_invoke */
-
-static int fc_bit_stop_invoke (const data_set_t __attribute__((unused)) *ds, /* {{{ */
- value_list_t __attribute__((unused)) *vl,
- notification_meta_t __attribute__((unused)) **meta,
- void __attribute__((unused)) **user_data)
-{
- return (FC_TARGET_STOP);
-} /* }}} int fc_bit_stop_invoke */
-
-static int fc_bit_return_invoke (const data_set_t __attribute__((unused)) *ds, /* {{{ */
- value_list_t __attribute__((unused)) *vl,
- notification_meta_t __attribute__((unused)) **meta,
- void __attribute__((unused)) **user_data)
-{
- return (FC_TARGET_RETURN);
-} /* }}} int fc_bit_return_invoke */
-
-static int fc_bit_write_create (const oconfig_item_t *ci, /* {{{ */
- void **user_data)
-{
- int i;
-
- char **plugin_list;
- size_t plugin_list_len;
-
- plugin_list = NULL;
- plugin_list_len = 0;
-
- for (i = 0; i < ci->children_num; i++)
- {
- oconfig_item_t *child = ci->children + i;
- char **temp;
- int j;
-
- if (strcasecmp ("Plugin", child->key) != 0)
- {
- ERROR ("Filter subsystem: The built-in target `write' does not "
- "support the configuration option `%s'.",
- child->key);
- continue;
- }
-
- for (j = 0; j < child->values_num; j++)
- {
- if (child->values[j].type != OCONFIG_TYPE_STRING)
- {
- ERROR ("Filter subsystem: Built-in target `write': "
- "The `Plugin' option accepts only string arguments.");
- continue;
- }
-
- temp = (char **) realloc (plugin_list, (plugin_list_len + 2)
- * (sizeof (*plugin_list)));
- if (temp == NULL)
- {
- ERROR ("fc_bit_write_create: realloc failed.");
- continue;
- }
- plugin_list = temp;
-
- plugin_list[plugin_list_len] = fc_strdup (child->values[j].value.string);
- if (plugin_list[plugin_list_len] == NULL)
- {
- ERROR ("fc_bit_write_create: fc_strdup failed.");
- continue;
- }
- plugin_list_len++;
- plugin_list[plugin_list_len] = NULL;
- } /* for (j = 0; j < child->values_num; j++) */
- } /* for (i = 0; i < ci->children_num; i++) */
-
- *user_data = plugin_list;
-
- return (0);
-} /* }}} int fc_bit_write_create */
-
-static int fc_bit_write_destroy (void **user_data) /* {{{ */
-{
- char **plugin_list;
- size_t i;
-
- if ((user_data == NULL) || (*user_data == NULL))
- return (0);
-
- plugin_list = *user_data;
-
- for (i = 0; plugin_list[i] != NULL; i++)
- free (plugin_list[i]);
- free (plugin_list);
-
- return (0);
-} /* }}} int fc_bit_write_destroy */
-
-static int fc_bit_write_invoke (const data_set_t *ds, /* {{{ */
- value_list_t *vl, notification_meta_t __attribute__((unused)) **meta,
- void **user_data)
-{
- char **plugin_list;
- int status;
-
- plugin_list = NULL;
- if (user_data != NULL)
- plugin_list = *user_data;
-
- if ((plugin_list == NULL) || (plugin_list[0] == NULL))
- {
- static c_complain_t enoent_complaint = C_COMPLAIN_INIT_STATIC;
-
- status = plugin_write (/* plugin = */ NULL, ds, vl);
- if (status == ENOENT)
- {
- /* in most cases this is a permanent error, so use the complain
- * mechanism rather than spamming the logs */
- c_complain (LOG_INFO, &enoent_complaint,
- "Filter subsystem: Built-in target `write': Dispatching value to "
- "all write plugins failed with status %i (ENOENT). "
- "Most likely this means you didn't load any write plugins.",
- status);
- }
- else if (status != 0)
- {
- INFO ("Filter subsystem: Built-in target `write': Dispatching value to "
- "all write plugins failed with status %i.", status);
- }
- else
- {
- assert (status == 0);
- c_release (LOG_INFO, &enoent_complaint, "Filter subsystem: "
- "Built-in target `write': Some write plugin is back to normal "
- "operation. `write' succeeded.");
- }
- }
- else
- {
- size_t i;
-
- for (i = 0; plugin_list[i] != NULL; i++)
- {
- status = plugin_write (plugin_list[i], ds, vl);
- if (status != 0)
- {
- INFO ("Filter subsystem: Built-in target `write': Dispatching value to "
- "the `%s' plugin failed with status %i.", plugin_list[i], status);
- }
- } /* for (i = 0; plugin_list[i] != NULL; i++) */
- }
-
- return (FC_TARGET_CONTINUE);
-} /* }}} int fc_bit_write_invoke */
-
-static int fc_init_once (void) /* {{{ */
-{
- static int done = 0;
- target_proc_t tproc;
-
- if (done != 0)
- return (0);
-
- memset (&tproc, 0, sizeof (tproc));
- tproc.create = fc_bit_jump_create;
- tproc.destroy = fc_bit_jump_destroy;
- tproc.invoke = fc_bit_jump_invoke;
- fc_register_target ("jump", tproc);
-
- memset (&tproc, 0, sizeof (tproc));
- tproc.create = NULL;
- tproc.destroy = NULL;
- tproc.invoke = fc_bit_stop_invoke;
- fc_register_target ("stop", tproc);
-
- memset (&tproc, 0, sizeof (tproc));
- tproc.create = NULL;
- tproc.destroy = NULL;
- tproc.invoke = fc_bit_return_invoke;
- fc_register_target ("return", tproc);
-
- memset (&tproc, 0, sizeof (tproc));
- tproc.create = fc_bit_write_create;
- tproc.destroy = fc_bit_write_destroy;
- tproc.invoke = fc_bit_write_invoke;
- fc_register_target ("write", tproc);
-
- done++;
- return (0);
-} /* }}} int fc_init_once */
-
-/*
- * Public functions
- */
-/* Add a match to list of available matches. */
-int fc_register_match (const char *name, match_proc_t proc) /* {{{ */
-{
- fc_match_t *m;
-
- DEBUG ("fc_register_match (%s);", name);
-
- m = (fc_match_t *) malloc (sizeof (*m));
- if (m == NULL)
- return (-ENOMEM);
- memset (m, 0, sizeof (*m));
-
- sstrncpy (m->name, name, sizeof (m->name));
- memcpy (&m->proc, &proc, sizeof (m->proc));
- m->next = NULL;
-
- if (match_list_head == NULL)
- {
- match_list_head = m;
- }
- else
- {
- fc_match_t *ptr;
-
- ptr = match_list_head;
- while (ptr->next != NULL)
- ptr = ptr->next;
-
- ptr->next = m;
- }
-
- return (0);
-} /* }}} int fc_register_match */
-
-/* Add a target to list of available targets. */
-int fc_register_target (const char *name, target_proc_t proc) /* {{{ */
-{
- fc_target_t *t;
-
- DEBUG ("fc_register_target (%s);", name);
-
- t = (fc_target_t *) malloc (sizeof (*t));
- if (t == NULL)
- return (-ENOMEM);
- memset (t, 0, sizeof (*t));
-
- sstrncpy (t->name, name, sizeof (t->name));
- memcpy (&t->proc, &proc, sizeof (t->proc));
- t->next = NULL;
-
- if (target_list_head == NULL)
- {
- target_list_head = t;
- }
- else
- {
- fc_target_t *ptr;
-
- ptr = target_list_head;
- while (ptr->next != NULL)
- ptr = ptr->next;
-
- ptr->next = t;
- }
-
- return (0);
-} /* }}} int fc_register_target */
-
-fc_chain_t *fc_chain_get_by_name (const char *chain_name) /* {{{ */
-{
- fc_chain_t *chain;
-
- if (chain_name == NULL)
- return (NULL);
-
- for (chain = chain_list_head; chain != NULL; chain = chain->next)
- if (strcasecmp (chain_name, chain->name) == 0)
- return (chain);
-
- return (NULL);
-} /* }}} int fc_chain_get_by_name */
-
-int fc_process_chain (const data_set_t *ds, value_list_t *vl, /* {{{ */
- fc_chain_t *chain)
-{
- fc_rule_t *rule;
- fc_target_t *target;
- int status;
-
- if (chain == NULL)
- return (-1);
-
- DEBUG ("fc_process_chain (chain = %s);", chain->name);
-
- status = FC_TARGET_CONTINUE;
- for (rule = chain->rules; rule != NULL; rule = rule->next)
- {
- fc_match_t *match;
-
- if (rule->name[0] != 0)
- {
- DEBUG ("fc_process_chain (%s): Testing the `%s' rule.",
- chain->name, rule->name);
- }
-
- /* N. B.: rule->matches may be NULL. */
- for (match = rule->matches; match != NULL; match = match->next)
- {
- /* FIXME: Pass the meta-data to match targets here (when implemented). */
- status = (*match->proc.match) (ds, vl, /* meta = */ NULL,
- &match->user_data);
- if (status < 0)
- {
- WARNING ("fc_process_chain (%s): A match failed.", chain->name);
- break;
- }
- else if (status != FC_MATCH_MATCHES)
- break;
- }
-
- /* for-loop has been aborted: Either error or no match. */
- if (match != NULL)
- {
- status = FC_TARGET_CONTINUE;
- continue;
- }
-
- if (rule->name[0] != 0)
- {
- DEBUG ("fc_process_chain (%s): Rule `%s' matches.",
- chain->name, rule->name);
- }
-
- for (target = rule->targets; target != NULL; target = target->next)
- {
- /* If we get here, all matches have matched the value. Execute the
- * target. */
- /* FIXME: Pass the meta-data to match targets here (when implemented). */
- status = (*target->proc.invoke) (ds, vl, /* meta = */ NULL,
- &target->user_data);
- if (status < 0)
- {
- WARNING ("fc_process_chain (%s): A target failed.", chain->name);
- continue;
- }
- else if (status == FC_TARGET_CONTINUE)
- continue;
- else if (status == FC_TARGET_STOP)
- break;
- else if (status == FC_TARGET_RETURN)
- break;
- else
- {
- WARNING ("fc_process_chain (%s): Unknown return value "
- "from target `%s': %i",
- chain->name, target->name, status);
- }
- }
-
- if ((status == FC_TARGET_STOP)
- || (status == FC_TARGET_RETURN))
- {
- if (rule->name[0] != 0)
- {
- DEBUG ("fc_process_chain (%s): Rule `%s' signaled "
- "the %s condition.",
- chain->name, rule->name,
- (status == FC_TARGET_STOP) ? "stop" : "return");
- }
- break;
- }
- else
- {
- status = FC_TARGET_CONTINUE;
- }
- } /* for (rule) */
-
- if (status == FC_TARGET_STOP)
- return (FC_TARGET_STOP);
- else if (status == FC_TARGET_RETURN)
- return (FC_TARGET_CONTINUE);
-
- /* for-loop has been aborted: A target returned `FC_TARGET_STOP' */
- if (rule != NULL)
- return (FC_TARGET_CONTINUE);
-
- DEBUG ("fc_process_chain (%s): Executing the default targets.",
- chain->name);
-
- status = FC_TARGET_CONTINUE;
- for (target = chain->targets; target != NULL; target = target->next)
- {
- /* If we get here, all matches have matched the value. Execute the
- * target. */
- /* FIXME: Pass the meta-data to match targets here (when implemented). */
- status = (*target->proc.invoke) (ds, vl, /* meta = */ NULL,
- &target->user_data);
- if (status < 0)
- {
- WARNING ("fc_process_chain (%s): The default target failed.",
- chain->name);
- }
- else if (status == FC_TARGET_CONTINUE)
- continue;
- else if (status == FC_TARGET_STOP)
- break;
- else if (status == FC_TARGET_RETURN)
- break;
- else
- {
- WARNING ("fc_process_chain (%s): Unknown return value "
- "from target `%s': %i",
- chain->name, target->name, status);
- }
- }
-
- if ((status == FC_TARGET_STOP)
- || (status == FC_TARGET_RETURN))
- {
- assert (target != NULL);
- DEBUG ("fc_process_chain (%s): Default target `%s' signaled "
- "the %s condition.",
- chain->name, target->name,
- (status == FC_TARGET_STOP) ? "stop" : "return");
- if (status == FC_TARGET_STOP)
- return (FC_TARGET_STOP);
- else
- return (FC_TARGET_CONTINUE);
- }
-
- DEBUG ("fc_process_chain (%s): Signaling `continue' at end of chain.",
- chain->name);
-
- return (FC_TARGET_CONTINUE);
-} /* }}} int fc_process_chain */
-
-/* Iterate over all rules in the chain and execute all targets for which all
- * matches match. */
-int fc_default_action (const data_set_t *ds, value_list_t *vl) /* {{{ */
-{
- /* FIXME: Pass the meta-data to match targets here (when implemented). */
- return (fc_bit_write_invoke (ds, vl,
- /* meta = */ NULL, /* user_data = */ NULL));
-} /* }}} int fc_default_action */
-
-int fc_configure (const oconfig_item_t *ci) /* {{{ */
-{
- fc_init_once ();
-
- if (ci == NULL)
- return (-EINVAL);
-
- if (strcasecmp ("Chain", ci->key) == 0)
- return (fc_config_add_chain (ci));
-
- WARNING ("Filter subsystem: Unknown top level config option `%s'.",
- ci->key);
-
- return (-1);
-} /* }}} int fc_configure */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/filter_chain.h b/src/filter_chain.h
--- a/src/filter_chain.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/**
- * collectd - src/filter_chain.h
- * Copyright (C) 2008,2009 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#ifndef FILTER_CHAIN_H
-#define FILTER_CHAIN_H 1
-
-#include "collectd.h"
-#include "plugin.h"
-
-#define FC_MATCH_NO_MATCH 0
-#define FC_MATCH_MATCHES 1
-
-#define FC_TARGET_CONTINUE 0
-#define FC_TARGET_STOP 1
-#define FC_TARGET_RETURN 2
-
-/*
- * Match functions
- */
-struct match_proc_s
-{
- int (*create) (const oconfig_item_t *ci, void **user_data);
- int (*destroy) (void **user_data);
- int (*match) (const data_set_t *ds, const value_list_t *vl,
- notification_meta_t **meta, void **user_data);
-};
-typedef struct match_proc_s match_proc_t;
-
-int fc_register_match (const char *name, match_proc_t proc);
-
-/*
- * Target functions
- */
-struct target_proc_s
-{
- int (*create) (const oconfig_item_t *ci, void **user_data);
- int (*destroy) (void **user_data);
- int (*invoke) (const data_set_t *ds, value_list_t *vl,
- notification_meta_t **meta, void **user_data);
-};
-typedef struct target_proc_s target_proc_t;
-
-struct fc_chain_s;
-typedef struct fc_chain_s fc_chain_t;
-
-int fc_register_target (const char *name, target_proc_t proc);
-
-/*
- * TODO: Chain management
- */
-#if 0
-int fc_chain_add (const char *chain_name,
- const char *target_name, int target_argc, char **target_argv);
-int fc_chain_delete (const char *chain_name);
-#endif
-
-/*
- * TODO: Rule management
- */
-#if 0
-int fc_rule_add (const char *chain_name, int position,
- int match_num, const char **match_name, int *match_argc, char ***match_argv,
- const char *target_name, int target_argc, char **target_argv);
-int fc_rule_delete (const char *chain_name, int position);
-#endif
-
-/*
- * Processing function
- */
-fc_chain_t *fc_chain_get_by_name (const char *chain_name);
-
-int fc_process_chain (const data_set_t *ds, value_list_t *vl,
- fc_chain_t *chain);
-
-int fc_default_action (const data_set_t *ds, value_list_t *vl);
-
-/*
- * Shortcut for global configuration
- */
-int fc_configure (const oconfig_item_t *ci);
-
-#endif /* FILTER_CHAIN_H */
-/* vim: set sw=2 sts=2 et : */
index 1d4dff59fccc29e180aa67544285ee0a8b2330b4..2fc3152d0ed6a28937c5628a7fedc7113e4bf43d 100644 (file)
BUILT_SOURCES = collectd/lcc_features.h
libcollectdclient_la_SOURCES = client.c network.c network_buffer.c
-libcollectdclient_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/src/libcollectdclient/collectd -I$(top_srcdir)/src
+libcollectdclient_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/src/libcollectdclient/collectd -I$(top_srcdir)/src/daemon
libcollectdclient_la_LDFLAGS = -version-info 1:0:0
libcollectdclient_la_LIBADD =
if BUILD_WITH_LIBGCRYPT
diff --git a/src/meta_data.c b/src/meta_data.c
--- a/src/meta_data.c
+++ /dev/null
@@ -1,637 +0,0 @@
-/**
- * collectd - src/meta_data.c
- * Copyright (C) 2008-2011 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#include "collectd.h"
-#include "plugin.h"
-#include "meta_data.h"
-
-#include <pthread.h>
-
-/*
- * Data types
- */
-union meta_value_u
-{
- char *mv_string;
- int64_t mv_signed_int;
- uint64_t mv_unsigned_int;
- double mv_double;
- _Bool mv_boolean;
-};
-typedef union meta_value_u meta_value_t;
-
-struct meta_entry_s;
-typedef struct meta_entry_s meta_entry_t;
-struct meta_entry_s
-{
- char *key;
- meta_value_t value;
- int type;
- meta_entry_t *next;
-};
-
-struct meta_data_s
-{
- meta_entry_t *head;
- pthread_mutex_t lock;
-};
-
-/*
- * Private functions
- */
-static char *md_strdup (const char *orig) /* {{{ */
-{
- size_t sz;
- char *dest;
-
- if (orig == NULL)
- return (NULL);
-
- sz = strlen (orig) + 1;
- dest = (char *) malloc (sz);
- if (dest == NULL)
- return (NULL);
-
- memcpy (dest, orig, sz);
-
- return (dest);
-} /* }}} char *md_strdup */
-
-static meta_entry_t *md_entry_alloc (const char *key) /* {{{ */
-{
- meta_entry_t *e;
-
- e = (meta_entry_t *) malloc (sizeof (*e));
- if (e == NULL)
- {
- ERROR ("md_entry_alloc: malloc failed.");
- return (NULL);
- }
- memset (e, 0, sizeof (*e));
-
- e->key = md_strdup (key);
- if (e->key == NULL)
- {
- free (e);
- ERROR ("md_entry_alloc: md_strdup failed.");
- return (NULL);
- }
-
- e->type = 0;
- e->next = NULL;
-
- return (e);
-} /* }}} meta_entry_t *md_entry_alloc */
-
-static meta_entry_t *md_entry_clone (const meta_entry_t *orig) /* {{{ */
-{
- meta_entry_t *copy;
-
- if (orig == NULL)
- return (NULL);
-
- copy = md_entry_alloc (orig->key);
- copy->type = orig->type;
- if (copy->type == MD_TYPE_STRING)
- copy->value.mv_string = strdup (orig->value.mv_string);
- else
- copy->value = orig->value;
-
- copy->next = md_entry_clone (orig->next);
- return (copy);
-} /* }}} meta_entry_t *md_entry_clone */
-
-static void md_entry_free (meta_entry_t *e) /* {{{ */
-{
- if (e == NULL)
- return;
-
- free (e->key);
-
- if (e->type == MD_TYPE_STRING)
- free (e->value.mv_string);
-
- if (e->next != NULL)
- md_entry_free (e->next);
-
- free (e);
-} /* }}} void md_entry_free */
-
-static int md_entry_insert (meta_data_t *md, meta_entry_t *e) /* {{{ */
-{
- meta_entry_t *this;
- meta_entry_t *prev;
-
- if ((md == NULL) || (e == NULL))
- return (-EINVAL);
-
- pthread_mutex_lock (&md->lock);
-
- prev = NULL;
- this = md->head;
- while (this != NULL)
- {
- if (strcasecmp (e->key, this->key) == 0)
- break;
-
- prev = this;
- this = this->next;
- }
-
- if (this == NULL)
- {
- /* This key does not exist yet. */
- if (md->head == NULL)
- md->head = e;
- else
- {
- assert (prev != NULL);
- prev->next = e;
- }
-
- e->next = NULL;
- }
- else /* (this != NULL) */
- {
- if (prev == NULL)
- md->head = e;
- else
- prev->next = e;
-
- e->next = this->next;
- }
-
- pthread_mutex_unlock (&md->lock);
-
- if (this != NULL)
- {
- this->next = NULL;
- md_entry_free (this);
- }
-
- return (0);
-} /* }}} int md_entry_insert */
-
-/* XXX: The lock on md must be held while calling this function! */
-static meta_entry_t *md_entry_lookup (meta_data_t *md, /* {{{ */
- const char *key)
-{
- meta_entry_t *e;
-
- if ((md == NULL) || (key == NULL))
- return (NULL);
-
- for (e = md->head; e != NULL; e = e->next)
- if (strcasecmp (key, e->key) == 0)
- break;
-
- return (e);
-} /* }}} meta_entry_t *md_entry_lookup */
-
-/*
- * Public functions
- */
-meta_data_t *meta_data_create (void) /* {{{ */
-{
- meta_data_t *md;
-
- md = (meta_data_t *) malloc (sizeof (*md));
- if (md == NULL)
- {
- ERROR ("meta_data_create: malloc failed.");
- return (NULL);
- }
- memset (md, 0, sizeof (*md));
-
- md->head = NULL;
- pthread_mutex_init (&md->lock, /* attr = */ NULL);
-
- return (md);
-} /* }}} meta_data_t *meta_data_create */
-
-meta_data_t *meta_data_clone (meta_data_t *orig) /* {{{ */
-{
- meta_data_t *copy;
-
- if (orig == NULL)
- return (NULL);
-
- copy = meta_data_create ();
- if (copy == NULL)
- return (NULL);
-
- pthread_mutex_lock (&orig->lock);
- copy->head = md_entry_clone (orig->head);
- pthread_mutex_unlock (&orig->lock);
-
- return (copy);
-} /* }}} meta_data_t *meta_data_clone */
-
-void meta_data_destroy (meta_data_t *md) /* {{{ */
-{
- if (md == NULL)
- return;
-
- pthread_mutex_destroy(&md->lock);
- md_entry_free (md->head);
- pthread_mutex_destroy (&md->lock);
- free (md);
-} /* }}} void meta_data_destroy */
-
-int meta_data_exists (meta_data_t *md, const char *key) /* {{{ */
-{
- meta_entry_t *e;
-
- if ((md == NULL) || (key == NULL))
- return (-EINVAL);
-
- pthread_mutex_lock (&md->lock);
-
- for (e = md->head; e != NULL; e = e->next)
- {
- if (strcasecmp (key, e->key) == 0)
- {
- pthread_mutex_unlock (&md->lock);
- return (1);
- }
- }
-
- pthread_mutex_unlock (&md->lock);
- return (0);
-} /* }}} int meta_data_exists */
-
-int meta_data_type (meta_data_t *md, const char *key) /* {{{ */
-{
- meta_entry_t *e;
-
- if ((md == NULL) || (key == NULL))
- return -EINVAL;
-
- pthread_mutex_lock (&md->lock);
-
- for (e = md->head; e != NULL; e = e->next)
- {
- if (strcasecmp (key, e->key) == 0)
- {
- pthread_mutex_unlock (&md->lock);
- return e->type;
- }
- }
-
- pthread_mutex_unlock (&md->lock);
- return 0;
-} /* }}} int meta_data_type */
-
-int meta_data_toc (meta_data_t *md, char ***toc) /* {{{ */
-{
- int i = 0, count = 0;
- meta_entry_t *e;
-
- if ((md == NULL) || (toc == NULL))
- return -EINVAL;
-
- pthread_mutex_lock (&md->lock);
-
- for (e = md->head; e != NULL; e = e->next)
- ++count;
-
- if (count == 0)
- {
- pthread_mutex_unlock (&md->lock);
- return (count);
- }
-
- *toc = calloc(count, sizeof(**toc));
- for (e = md->head; e != NULL; e = e->next)
- (*toc)[i++] = strdup(e->key);
-
- pthread_mutex_unlock (&md->lock);
- return count;
-} /* }}} int meta_data_toc */
-
-int meta_data_delete (meta_data_t *md, const char *key) /* {{{ */
-{
- meta_entry_t *this;
- meta_entry_t *prev;
-
- if ((md == NULL) || (key == NULL))
- return (-EINVAL);
-
- pthread_mutex_lock (&md->lock);
-
- prev = NULL;
- this = md->head;
- while (this != NULL)
- {
- if (strcasecmp (key, this->key) == 0)
- break;
-
- prev = this;
- this = this->next;
- }
-
- if (this == NULL)
- {
- pthread_mutex_unlock (&md->lock);
- return (-ENOENT);
- }
-
- if (prev == NULL)
- md->head = this->next;
- else
- prev->next = this->next;
-
- pthread_mutex_unlock (&md->lock);
-
- this->next = NULL;
- md_entry_free (this);
-
- return (0);
-} /* }}} int meta_data_delete */
-
-/*
- * Add functions
- */
-int meta_data_add_string (meta_data_t *md, /* {{{ */
- const char *key, const char *value)
-{
- meta_entry_t *e;
-
- if ((md == NULL) || (key == NULL) || (value == NULL))
- return (-EINVAL);
-
- e = md_entry_alloc (key);
- if (e == NULL)
- return (-ENOMEM);
-
- e->value.mv_string = md_strdup (value);
- if (e->value.mv_string == NULL)
- {
- ERROR ("meta_data_add_string: md_strdup failed.");
- md_entry_free (e);
- return (-ENOMEM);
- }
- e->type = MD_TYPE_STRING;
-
- return (md_entry_insert (md, e));
-} /* }}} int meta_data_add_string */
-
-int meta_data_add_signed_int (meta_data_t *md, /* {{{ */
- const char *key, int64_t value)
-{
- meta_entry_t *e;
-
- if ((md == NULL) || (key == NULL))
- return (-EINVAL);
-
- e = md_entry_alloc (key);
- if (e == NULL)
- return (-ENOMEM);
-
- e->value.mv_signed_int = value;
- e->type = MD_TYPE_SIGNED_INT;
-
- return (md_entry_insert (md, e));
-} /* }}} int meta_data_add_signed_int */
-
-int meta_data_add_unsigned_int (meta_data_t *md, /* {{{ */
- const char *key, uint64_t value)
-{
- meta_entry_t *e;
-
- if ((md == NULL) || (key == NULL))
- return (-EINVAL);
-
- e = md_entry_alloc (key);
- if (e == NULL)
- return (-ENOMEM);
-
- e->value.mv_unsigned_int = value;
- e->type = MD_TYPE_UNSIGNED_INT;
-
- return (md_entry_insert (md, e));
-} /* }}} int meta_data_add_unsigned_int */
-
-int meta_data_add_double (meta_data_t *md, /* {{{ */
- const char *key, double value)
-{
- meta_entry_t *e;
-
- if ((md == NULL) || (key == NULL))
- return (-EINVAL);
-
- e = md_entry_alloc (key);
- if (e == NULL)
- return (-ENOMEM);
-
- e->value.mv_double = value;
- e->type = MD_TYPE_DOUBLE;
-
- return (md_entry_insert (md, e));
-} /* }}} int meta_data_add_double */
-
-int meta_data_add_boolean (meta_data_t *md, /* {{{ */
- const char *key, _Bool value)
-{
- meta_entry_t *e;
-
- if ((md == NULL) || (key == NULL))
- return (-EINVAL);
-
- e = md_entry_alloc (key);
- if (e == NULL)
- return (-ENOMEM);
-
- e->value.mv_boolean = value;
- e->type = MD_TYPE_BOOLEAN;
-
- return (md_entry_insert (md, e));
-} /* }}} int meta_data_add_boolean */
-
-/*
- * Get functions
- */
-int meta_data_get_string (meta_data_t *md, /* {{{ */
- const char *key, char **value)
-{
- meta_entry_t *e;
- char *temp;
-
- if ((md == NULL) || (key == NULL) || (value == NULL))
- return (-EINVAL);
-
- pthread_mutex_lock (&md->lock);
-
- e = md_entry_lookup (md, key);
- if (e == NULL)
- {
- pthread_mutex_unlock (&md->lock);
- return (-ENOENT);
- }
-
- if (e->type != MD_TYPE_STRING)
- {
- ERROR ("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
- pthread_mutex_unlock (&md->lock);
- return (-ENOENT);
- }
-
- temp = md_strdup (e->value.mv_string);
- if (temp == NULL)
- {
- pthread_mutex_unlock (&md->lock);
- ERROR ("meta_data_get_string: md_strdup failed.");
- return (-ENOMEM);
- }
-
- pthread_mutex_unlock (&md->lock);
-
- *value = temp;
-
- return (0);
-} /* }}} int meta_data_get_string */
-
-int meta_data_get_signed_int (meta_data_t *md, /* {{{ */
- const char *key, int64_t *value)
-{
- meta_entry_t *e;
-
- if ((md == NULL) || (key == NULL) || (value == NULL))
- return (-EINVAL);
-
- pthread_mutex_lock (&md->lock);
-
- e = md_entry_lookup (md, key);
- if (e == NULL)
- {
- pthread_mutex_unlock (&md->lock);
- return (-ENOENT);
- }
-
- if (e->type != MD_TYPE_SIGNED_INT)
- {
- ERROR ("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
- pthread_mutex_unlock (&md->lock);
- return (-ENOENT);
- }
-
- *value = e->value.mv_signed_int;
-
- pthread_mutex_unlock (&md->lock);
- return (0);
-} /* }}} int meta_data_get_signed_int */
-
-int meta_data_get_unsigned_int (meta_data_t *md, /* {{{ */
- const char *key, uint64_t *value)
-{
- meta_entry_t *e;
-
- if ((md == NULL) || (key == NULL) || (value == NULL))
- return (-EINVAL);
-
- pthread_mutex_lock (&md->lock);
-
- e = md_entry_lookup (md, key);
- if (e == NULL)
- {
- pthread_mutex_unlock (&md->lock);
- return (-ENOENT);
- }
-
- if (e->type != MD_TYPE_UNSIGNED_INT)
- {
- ERROR ("meta_data_get_unsigned_int: Type mismatch for key `%s'", e->key);
- pthread_mutex_unlock (&md->lock);
- return (-ENOENT);
- }
-
- *value = e->value.mv_unsigned_int;
-
- pthread_mutex_unlock (&md->lock);
- return (0);
-} /* }}} int meta_data_get_unsigned_int */
-
-int meta_data_get_double (meta_data_t *md, /* {{{ */
- const char *key, double *value)
-{
- meta_entry_t *e;
-
- if ((md == NULL) || (key == NULL) || (value == NULL))
- return (-EINVAL);
-
- pthread_mutex_lock (&md->lock);
-
- e = md_entry_lookup (md, key);
- if (e == NULL)
- {
- pthread_mutex_unlock (&md->lock);
- return (-ENOENT);
- }
-
- if (e->type != MD_TYPE_DOUBLE)
- {
- ERROR ("meta_data_get_double: Type mismatch for key `%s'", e->key);
- pthread_mutex_unlock (&md->lock);
- return (-ENOENT);
- }
-
- *value = e->value.mv_double;
-
- pthread_mutex_unlock (&md->lock);
- return (0);
-} /* }}} int meta_data_get_double */
-
-int meta_data_get_boolean (meta_data_t *md, /* {{{ */
- const char *key, _Bool *value)
-{
- meta_entry_t *e;
-
- if ((md == NULL) || (key == NULL) || (value == NULL))
- return (-EINVAL);
-
- pthread_mutex_lock (&md->lock);
-
- e = md_entry_lookup (md, key);
- if (e == NULL)
- {
- pthread_mutex_unlock (&md->lock);
- return (-ENOENT);
- }
-
- if (e->type != MD_TYPE_BOOLEAN)
- {
- ERROR ("meta_data_get_boolean: Type mismatch for key `%s'", e->key);
- pthread_mutex_unlock (&md->lock);
- return (-ENOENT);
- }
-
- *value = e->value.mv_boolean;
-
- pthread_mutex_unlock (&md->lock);
- return (0);
-} /* }}} int meta_data_get_boolean */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/meta_data.h b/src/meta_data.h
--- a/src/meta_data.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * collectd - src/meta_data.h
- * Copyright (C) 2008-2011 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#ifndef META_DATA_H
-#define META_DATA_H
-
-#include "collectd.h"
-
-/*
- * Defines
- */
-#define MD_TYPE_STRING 1
-#define MD_TYPE_SIGNED_INT 2
-#define MD_TYPE_UNSIGNED_INT 3
-#define MD_TYPE_DOUBLE 4
-#define MD_TYPE_BOOLEAN 5
-
-struct meta_data_s;
-typedef struct meta_data_s meta_data_t;
-
-meta_data_t *meta_data_create (void);
-meta_data_t *meta_data_clone (meta_data_t *orig);
-void meta_data_destroy (meta_data_t *md);
-
-int meta_data_exists (meta_data_t *md, const char *key);
-int meta_data_type (meta_data_t *md, const char *key);
-int meta_data_toc (meta_data_t *md, char ***toc);
-int meta_data_delete (meta_data_t *md, const char *key);
-
-int meta_data_add_string (meta_data_t *md,
- const char *key,
- const char *value);
-int meta_data_add_signed_int (meta_data_t *md,
- const char *key,
- int64_t value);
-int meta_data_add_unsigned_int (meta_data_t *md,
- const char *key,
- uint64_t value);
-int meta_data_add_double (meta_data_t *md,
- const char *key,
- double value);
-int meta_data_add_boolean (meta_data_t *md,
- const char *key,
- _Bool value);
-
-int meta_data_get_string (meta_data_t *md,
- const char *key,
- char **value);
-int meta_data_get_signed_int (meta_data_t *md,
- const char *key,
- int64_t *value);
-int meta_data_get_unsigned_int (meta_data_t *md,
- const char *key,
- uint64_t *value);
-int meta_data_get_double (meta_data_t *md,
- const char *key,
- double *value);
-int meta_data_get_boolean (meta_data_t *md,
- const char *key,
- _Bool *value);
-
-#endif /* META_DATA_H */
-/* vim: set sw=2 sts=2 et : */
diff --git a/src/plugin.c b/src/plugin.c
--- a/src/plugin.c
+++ /dev/null
@@ -1,2656 +0,0 @@
-/**
- * collectd - src/plugin.c
- * Copyright (C) 2005-2014 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- * Sebastian Harl <sh at tokkee.org>
- **/
-
-#include "collectd.h"
-#include "common.h"
-#include "plugin.h"
-#include "configfile.h"
-#include "filter_chain.h"
-#include "utils_avltree.h"
-#include "utils_cache.h"
-#include "utils_complain.h"
-#include "utils_llist.h"
-#include "utils_heap.h"
-#include "utils_time.h"
-#include "utils_random.h"
-
-#if HAVE_PTHREAD_H
-# include <pthread.h>
-#endif
-
-#include <ltdl.h>
-
-/*
- * Private structures
- */
-struct callback_func_s
-{
- void *cf_callback;
- user_data_t cf_udata;
- plugin_ctx_t cf_ctx;
-};
-typedef struct callback_func_s callback_func_t;
-
-#define RF_SIMPLE 0
-#define RF_COMPLEX 1
-#define RF_REMOVE 65535
-struct read_func_s
-{
- /* `read_func_t' "inherits" from `callback_func_t'.
- * The `rf_super' member MUST be the first one in this structure! */
-#define rf_callback rf_super.cf_callback
-#define rf_udata rf_super.cf_udata
-#define rf_ctx rf_super.cf_ctx
- callback_func_t rf_super;
- char rf_group[DATA_MAX_NAME_LEN];
- char *rf_name;
- int rf_type;
- cdtime_t rf_interval;
- cdtime_t rf_effective_interval;
- cdtime_t rf_next_read;
-};
-typedef struct read_func_s read_func_t;
-
-struct write_queue_s;
-typedef struct write_queue_s write_queue_t;
-struct write_queue_s
-{
- value_list_t *vl;
- plugin_ctx_t ctx;
- write_queue_t *next;
-};
-
-/*
- * Private variables
- */
-static c_avl_tree_t *plugins_loaded = NULL;
-
-static llist_t *list_init;
-static llist_t *list_write;
-static llist_t *list_flush;
-static llist_t *list_missing;
-static llist_t *list_shutdown;
-static llist_t *list_log;
-static llist_t *list_notification;
-
-static fc_chain_t *pre_cache_chain = NULL;
-static fc_chain_t *post_cache_chain = NULL;
-
-static c_avl_tree_t *data_sets;
-
-static char *plugindir = NULL;
-
-#ifndef DEFAULT_MAX_READ_INTERVAL
-# define DEFAULT_MAX_READ_INTERVAL TIME_T_TO_CDTIME_T (86400)
-#endif
-static c_heap_t *read_heap = NULL;
-static llist_t *read_list;
-static int read_loop = 1;
-static pthread_mutex_t read_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t read_cond = PTHREAD_COND_INITIALIZER;
-static pthread_t *read_threads = NULL;
-static int read_threads_num = 0;
-static cdtime_t max_read_interval = DEFAULT_MAX_READ_INTERVAL;
-
-static write_queue_t *write_queue_head;
-static write_queue_t *write_queue_tail;
-static long write_queue_length = 0;
-static _Bool write_loop = 1;
-static pthread_mutex_t write_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t write_cond = PTHREAD_COND_INITIALIZER;
-static pthread_t *write_threads = NULL;
-static size_t write_threads_num = 0;
-
-static pthread_key_t plugin_ctx_key;
-static _Bool plugin_ctx_key_initialized = 0;
-
-static long write_limit_high = 0;
-static long write_limit_low = 0;
-
-static derive_t stats_values_dropped = 0;
-static _Bool record_statistics = 0;
-
-/*
- * Static functions
- */
-static int plugin_dispatch_values_internal (value_list_t *vl);
-
-static const char *plugin_get_dir (void)
-{
- if (plugindir == NULL)
- return (PLUGINDIR);
- else
- return (plugindir);
-}
-
-static void plugin_update_internal_statistics (void) { /* {{{ */
- derive_t copy_write_queue_length;
- value_list_t vl = VALUE_LIST_INIT;
- value_t values[2];
-
- copy_write_queue_length = write_queue_length;
-
- /* Initialize `vl' */
- vl.values = values;
- vl.values_len = 2;
- vl.time = 0;
- sstrncpy (vl.host, hostname_g, sizeof (vl.host));
- sstrncpy (vl.plugin, "collectd", sizeof (vl.plugin));
-
- vl.type_instance[0] = 0;
- vl.values_len = 1;
-
- /* Write queue */
- sstrncpy (vl.plugin_instance, "write_queue",
- sizeof (vl.plugin_instance));
-
- /* Write queue : queue length */
- vl.values[0].gauge = (gauge_t) copy_write_queue_length;
- sstrncpy (vl.type, "queue_length", sizeof (vl.type));
- vl.type_instance[0] = 0;
- plugin_dispatch_values (&vl);
-
- /* Write queue : Values dropped (queue length > low limit) */
- vl.values[0].derive = (derive_t) stats_values_dropped;
- sstrncpy (vl.type, "derive", sizeof (vl.type));
- sstrncpy (vl.type_instance, "dropped", sizeof (vl.type_instance));
- plugin_dispatch_values (&vl);
-
- /* Cache */
- sstrncpy (vl.plugin_instance, "cache",
- sizeof (vl.plugin_instance));
-
- /* Cache : Nb entry in cache tree */
- vl.values[0].gauge = (gauge_t) uc_get_size();
- sstrncpy (vl.type, "cache_size", sizeof (vl.type));
- vl.type_instance[0] = 0;
- plugin_dispatch_values (&vl);
-
- return;
-} /* }}} void plugin_update_internal_statistics */
-
-static void destroy_callback (callback_func_t *cf) /* {{{ */
-{
- if (cf == NULL)
- return;
-
- if ((cf->cf_udata.data != NULL) && (cf->cf_udata.free_func != NULL))
- {
- cf->cf_udata.free_func (cf->cf_udata.data);
- cf->cf_udata.data = NULL;
- cf->cf_udata.free_func = NULL;
- }
- sfree (cf);
-} /* }}} void destroy_callback */
-
-static void destroy_all_callbacks (llist_t **list) /* {{{ */
-{
- llentry_t *le;
-
- if (*list == NULL)
- return;
-
- le = llist_head (*list);
- while (le != NULL)
- {
- llentry_t *le_next;
-
- le_next = le->next;
-
- sfree (le->key);
- destroy_callback (le->value);
- le->value = NULL;
-
- le = le_next;
- }
-
- llist_destroy (*list);
- *list = NULL;
-} /* }}} void destroy_all_callbacks */
-
-static void destroy_read_heap (void) /* {{{ */
-{
- if (read_heap == NULL)
- return;
-
- while (42)
- {
- callback_func_t *cf;
-
- cf = c_heap_get_root (read_heap);
- if (cf == NULL)
- break;
-
- destroy_callback (cf);
- }
-
- c_heap_destroy (read_heap);
- read_heap = NULL;
-} /* }}} void destroy_read_heap */
-
-static int register_callback (llist_t **list, /* {{{ */
- const char *name, callback_func_t *cf)
-{
- llentry_t *le;
- char *key;
-
- if (*list == NULL)
- {
- *list = llist_create ();
- if (*list == NULL)
- {
- ERROR ("plugin: register_callback: "
- "llist_create failed.");
- destroy_callback (cf);
- return (-1);
- }
- }
-
- key = strdup (name);
- if (key == NULL)
- {
- ERROR ("plugin: register_callback: strdup failed.");
- destroy_callback (cf);
- return (-1);
- }
-
- le = llist_search (*list, name);
- if (le == NULL)
- {
- le = llentry_create (key, cf);
- if (le == NULL)
- {
- ERROR ("plugin: register_callback: "
- "llentry_create failed.");
- free (key);
- destroy_callback (cf);
- return (-1);
- }
-
- llist_append (*list, le);
- }
- else
- {
- callback_func_t *old_cf;
-
- old_cf = le->value;
- le->value = cf;
-
- WARNING ("plugin: register_callback: "
- "a callback named `%s' already exists - "
- "overwriting the old entry!", name);
-
- destroy_callback (old_cf);
- sfree (key);
- }
-
- return (0);
-} /* }}} int register_callback */
-
-static int create_register_callback (llist_t **list, /* {{{ */
- const char *name, void *callback, user_data_t *ud)
-{
- callback_func_t *cf;
-
- cf = (callback_func_t *) malloc (sizeof (*cf));
- if (cf == NULL)
- {
- ERROR ("plugin: create_register_callback: malloc failed.");
- return (-1);
- }
- memset (cf, 0, sizeof (*cf));
-
- cf->cf_callback = callback;
- if (ud == NULL)
- {
- cf->cf_udata.data = NULL;
- cf->cf_udata.free_func = NULL;
- }
- else
- {
- cf->cf_udata = *ud;
- }
-
- cf->cf_ctx = plugin_get_ctx ();
-
- return (register_callback (list, name, cf));
-} /* }}} int create_register_callback */
-
-static int plugin_unregister (llist_t *list, const char *name) /* {{{ */
-{
- llentry_t *e;
-
- if (list == NULL)
- return (-1);
-
- e = llist_search (list, name);
- if (e == NULL)
- return (-1);
-
- llist_remove (list, e);
-
- sfree (e->key);
- destroy_callback (e->value);
-
- llentry_destroy (e);
-
- return (0);
-} /* }}} int plugin_unregister */
-
-/*
- * (Try to) load the shared object `file'. Won't complain if it isn't a shared
- * object, but it will bitch about a shared object not having a
- * ``module_register'' symbol..
- */
-static int plugin_load_file (char *file, uint32_t flags)
-{
- lt_dlhandle dlh;
- void (*reg_handle) (void);
-
- lt_dlinit ();
- lt_dlerror (); /* clear errors */
-
-#if LIBTOOL_VERSION == 2
- if (flags & PLUGIN_FLAGS_GLOBAL) {
- lt_dladvise advise;
- lt_dladvise_init(&advise);
- lt_dladvise_global(&advise);
- dlh = lt_dlopenadvise(file, advise);
- lt_dladvise_destroy(&advise);
- } else {
- dlh = lt_dlopen (file);
- }
-#else /* if LIBTOOL_VERSION == 1 */
- if (flags & PLUGIN_FLAGS_GLOBAL)
- WARNING ("plugin_load_file: The global flag is not supported, "
- "libtool 2 is required for this.");
- dlh = lt_dlopen (file);
-#endif
-
- if (dlh == NULL)
- {
- char errbuf[1024] = "";
-
- ssnprintf (errbuf, sizeof (errbuf),
- "lt_dlopen (\"%s\") failed: %s. "
- "The most common cause for this problem are "
- "missing dependencies. Use ldd(1) to check "
- "the dependencies of the plugin "
- "/ shared object.",
- file, lt_dlerror ());
-
- ERROR ("%s", errbuf);
- /* Make sure this is printed to STDERR in any case, but also
- * make sure it's printed only once. */
- if (list_log != NULL)
- fprintf (stderr, "ERROR: %s\n", errbuf);
-
- return (1);
- }
-
- if ((reg_handle = (void (*) (void)) lt_dlsym (dlh, "module_register")) == NULL)
- {
- WARNING ("Couldn't find symbol \"module_register\" in \"%s\": %s\n",
- file, lt_dlerror ());
- lt_dlclose (dlh);
- return (-1);
- }
-
- (*reg_handle) ();
-
- return (0);
-}
-
-static void *plugin_read_thread (void __attribute__((unused)) *args)
-{
- while (read_loop != 0)
- {
- read_func_t *rf;
- plugin_ctx_t old_ctx;
- cdtime_t now;
- int status;
- int rf_type;
- int rc;
-
- /* Get the read function that needs to be read next.
- * We don't need to hold "read_lock" for the heap, but we need
- * to call c_heap_get_root() and pthread_cond_wait() in the
- * same protected block. */
- pthread_mutex_lock (&read_lock);
- rf = c_heap_get_root (read_heap);
- if (rf == NULL)
- {
- pthread_cond_wait (&read_cond, &read_lock);
- pthread_mutex_unlock (&read_lock);
- continue;
- }
- pthread_mutex_unlock (&read_lock);
-
- if (rf->rf_interval == 0)
- {
- /* this should not happen, because the interval is set
- * for each plugin when loading it
- * XXX: issue a warning? */
- rf->rf_interval = plugin_get_interval ();
- rf->rf_effective_interval = rf->rf_interval;
-
- rf->rf_next_read = cdtime ();
- }
-
- /* sleep until this entry is due,
- * using pthread_cond_timedwait */
- pthread_mutex_lock (&read_lock);
- /* In pthread_cond_timedwait, spurious wakeups are possible
- * (and really happen, at least on NetBSD with > 1 CPU), thus
- * we need to re-evaluate the condition every time
- * pthread_cond_timedwait returns. */
- rc = 0;
- while ((read_loop != 0)
- && (cdtime () < rf->rf_next_read)
- && rc == 0)
- {
- struct timespec ts = { 0 };
-
- CDTIME_T_TO_TIMESPEC (rf->rf_next_read, &ts);
-
- rc = pthread_cond_timedwait (&read_cond, &read_lock,
- &ts);
- }
-
- /* Must hold `read_lock' when accessing `rf->rf_type'. */
- rf_type = rf->rf_type;
- pthread_mutex_unlock (&read_lock);
-
- /* Check if we're supposed to stop.. This may have interrupted
- * the sleep, too. */
- if (read_loop == 0)
- {
- /* Insert `rf' again, so it can be free'd correctly */
- c_heap_insert (read_heap, rf);
- break;
- }
-
- /* The entry has been marked for deletion. The linked list
- * entry has already been removed by `plugin_unregister_read'.
- * All we have to do here is free the `read_func_t' and
- * continue. */
- if (rf_type == RF_REMOVE)
- {
- DEBUG ("plugin_read_thread: Destroying the `%s' "
- "callback.", rf->rf_name);
- sfree (rf->rf_name);
- destroy_callback ((callback_func_t *) rf);
- rf = NULL;
- continue;
- }
-
- DEBUG ("plugin_read_thread: Handling `%s'.", rf->rf_name);
-
- old_ctx = plugin_set_ctx (rf->rf_ctx);
-
- if (rf_type == RF_SIMPLE)
- {
- int (*callback) (void);
-
- callback = rf->rf_callback;
- status = (*callback) ();
- }
- else
- {
- plugin_read_cb callback;
-
- assert (rf_type == RF_COMPLEX);
-
- callback = rf->rf_callback;
- status = (*callback) (&rf->rf_udata);
- }
-
- plugin_set_ctx (old_ctx);
-
- /* If the function signals failure, we will increase the
- * intervals in which it will be called. */
- if (status != 0)
- {
- rf->rf_effective_interval *= 2;
- if (rf->rf_effective_interval > max_read_interval)
- rf->rf_effective_interval = max_read_interval;
-
- NOTICE ("read-function of plugin `%s' failed. "
- "Will suspend it for %.3f seconds.",
- rf->rf_name,
- CDTIME_T_TO_DOUBLE (rf->rf_effective_interval));
- }
- else
- {
- /* Success: Restore the interval, if it was changed. */
- rf->rf_effective_interval = rf->rf_interval;
- }
-
- /* update the ``next read due'' field */
- now = cdtime ();
-
- DEBUG ("plugin_read_thread: Effective interval of the "
- "%s plugin is %.3f seconds.",
- rf->rf_name,
- CDTIME_T_TO_DOUBLE (rf->rf_effective_interval));
-
- /* Calculate the next (absolute) time at which this function
- * should be called. */
- rf->rf_next_read += rf->rf_effective_interval;
-
- /* Check, if `rf_next_read' is in the past. */
- if (rf->rf_next_read < now)
- {
- /* `rf_next_read' is in the past. Insert `now'
- * so this value doesn't trail off into the
- * past too much. */
- rf->rf_next_read = now;
- }
-
- DEBUG ("plugin_read_thread: Next read of the %s plugin at %.3f.",
- rf->rf_name,
- CDTIME_T_TO_DOUBLE (rf->rf_next_read));
-
- /* Re-insert this read function into the heap again. */
- c_heap_insert (read_heap, rf);
- } /* while (read_loop) */
-
- pthread_exit (NULL);
- return ((void *) 0);
-} /* void *plugin_read_thread */
-
-static void start_read_threads (int num)
-{
- int i;
-
- if (read_threads != NULL)
- return;
-
- read_threads = (pthread_t *) calloc (num, sizeof (pthread_t));
- if (read_threads == NULL)
- {
- ERROR ("plugin: start_read_threads: calloc failed.");
- return;
- }
-
- read_threads_num = 0;
- for (i = 0; i < num; i++)
- {
- if (pthread_create (read_threads + read_threads_num, NULL,
- plugin_read_thread, NULL) == 0)
- {
- read_threads_num++;
- }
- else
- {
- ERROR ("plugin: start_read_threads: pthread_create failed.");
- return;
- }
- } /* for (i) */
-} /* void start_read_threads */
-
-static void stop_read_threads (void)
-{
- int i;
-
- if (read_threads == NULL)
- return;
-
- INFO ("collectd: Stopping %i read threads.", read_threads_num);
-
- pthread_mutex_lock (&read_lock);
- read_loop = 0;
- DEBUG ("plugin: stop_read_threads: Signalling `read_cond'");
- pthread_cond_broadcast (&read_cond);
- pthread_mutex_unlock (&read_lock);
-
- for (i = 0; i < read_threads_num; i++)
- {
- if (pthread_join (read_threads[i], NULL) != 0)
- {
- ERROR ("plugin: stop_read_threads: pthread_join failed.");
- }
- read_threads[i] = (pthread_t) 0;
- }
- sfree (read_threads);
- read_threads_num = 0;
-} /* void stop_read_threads */
-
-static void plugin_value_list_free (value_list_t *vl) /* {{{ */
-{
- if (vl == NULL)
- return;
-
- meta_data_destroy (vl->meta);
- sfree (vl->values);
- sfree (vl);
-} /* }}} void plugin_value_list_free */
-
-static value_list_t *plugin_value_list_clone (value_list_t const *vl_orig) /* {{{ */
-{
- value_list_t *vl;
-
- if (vl_orig == NULL)
- return (NULL);
-
- vl = malloc (sizeof (*vl));
- if (vl == NULL)
- return (NULL);
- memcpy (vl, vl_orig, sizeof (*vl));
-
- vl->values = calloc (vl_orig->values_len, sizeof (*vl->values));
- if (vl->values == NULL)
- {
- plugin_value_list_free (vl);
- return (NULL);
- }
- memcpy (vl->values, vl_orig->values,
- vl_orig->values_len * sizeof (*vl->values));
-
- vl->meta = meta_data_clone (vl->meta);
- if ((vl_orig->meta != NULL) && (vl->meta == NULL))
- {
- plugin_value_list_free (vl);
- return (NULL);
- }
-
- if (vl->time == 0)
- vl->time = cdtime ();
-
- /* Fill in the interval from the thread context, if it is zero. */
- if (vl->interval == 0)
- {
- plugin_ctx_t ctx = plugin_get_ctx ();
-
- if (ctx.interval != 0)
- vl->interval = ctx.interval;
- else
- {
- char name[6 * DATA_MAX_NAME_LEN];
- FORMAT_VL (name, sizeof (name), vl);
- ERROR ("plugin_value_list_clone: Unable to determine "
- "interval from context for "
- "value list \"%s\". "
- "This indicates a broken plugin. "
- "Please report this problem to the "
- "collectd mailing list or at "
- "<http://collectd.org/bugs/>.", name);
- vl->interval = cf_get_default_interval ();
- }
- }
-
- return (vl);
-} /* }}} value_list_t *plugin_value_list_clone */
-
-static int plugin_write_enqueue (value_list_t const *vl) /* {{{ */
-{
- write_queue_t *q;
-
- q = malloc (sizeof (*q));
- if (q == NULL)
- return (ENOMEM);
- q->next = NULL;
-
- q->vl = plugin_value_list_clone (vl);
- if (q->vl == NULL)
- {
- sfree (q);
- return (ENOMEM);
- }
-
- /* Store context of caller (read plugin); otherwise, it would not be
- * available to the write plugins when actually dispatching the
- * value-list later on. */
- q->ctx = plugin_get_ctx ();
-
- pthread_mutex_lock (&write_lock);
-
- if (write_queue_tail == NULL)
- {
- write_queue_head = q;
- write_queue_tail = q;
- write_queue_length = 1;
- }
- else
- {
- write_queue_tail->next = q;
- write_queue_tail = q;
- write_queue_length += 1;
- }
-
- pthread_cond_signal (&write_cond);
- pthread_mutex_unlock (&write_lock);
-
- return (0);
-} /* }}} int plugin_write_enqueue */
-
-static value_list_t *plugin_write_dequeue (void) /* {{{ */
-{
- write_queue_t *q;
- value_list_t *vl;
-
- pthread_mutex_lock (&write_lock);
-
- while (write_loop && (write_queue_head == NULL))
- pthread_cond_wait (&write_cond, &write_lock);
-
- if (write_queue_head == NULL)
- {
- pthread_mutex_unlock (&write_lock);
- return (NULL);
- }
-
- q = write_queue_head;
- write_queue_head = q->next;
- write_queue_length -= 1;
- if (write_queue_head == NULL) {
- write_queue_tail = NULL;
- assert(0 == write_queue_length);
- }
-
- pthread_mutex_unlock (&write_lock);
-
- (void) plugin_set_ctx (q->ctx);
-
- vl = q->vl;
- sfree (q);
- return (vl);
-} /* }}} value_list_t *plugin_write_dequeue */
-
-static void *plugin_write_thread (void __attribute__((unused)) *args) /* {{{ */
-{
- while (write_loop)
- {
- value_list_t *vl = plugin_write_dequeue ();
- if (vl == NULL)
- continue;
-
- plugin_dispatch_values_internal (vl);
-
- plugin_value_list_free (vl);
- }
-
- pthread_exit (NULL);
- return ((void *) 0);
-} /* }}} void *plugin_write_thread */
-
-static void start_write_threads (size_t num) /* {{{ */
-{
- size_t i;
-
- if (write_threads != NULL)
- return;
-
- write_threads = (pthread_t *) calloc (num, sizeof (pthread_t));
- if (write_threads == NULL)
- {
- ERROR ("plugin: start_write_threads: calloc failed.");
- return;
- }
-
- write_threads_num = 0;
- for (i = 0; i < num; i++)
- {
- int status;
-
- status = pthread_create (write_threads + write_threads_num,
- /* attr = */ NULL,
- plugin_write_thread,
- /* arg = */ NULL);
- if (status != 0)
- {
- char errbuf[1024];
- ERROR ("plugin: start_write_threads: pthread_create failed "
- "with status %i (%s).", status,
- sstrerror (status, errbuf, sizeof (errbuf)));
- return;
- }
-
- write_threads_num++;
- } /* for (i) */
-} /* }}} void start_write_threads */
-
-static void stop_write_threads (void) /* {{{ */
-{
- write_queue_t *q;
- int i;
-
- if (write_threads == NULL)
- return;
-
- INFO ("collectd: Stopping %zu write threads.", write_threads_num);
-
- pthread_mutex_lock (&write_lock);
- write_loop = 0;
- DEBUG ("plugin: stop_write_threads: Signalling `write_cond'");
- pthread_cond_broadcast (&write_cond);
- pthread_mutex_unlock (&write_lock);
-
- for (i = 0; i < write_threads_num; i++)
- {
- if (pthread_join (write_threads[i], NULL) != 0)
- {
- ERROR ("plugin: stop_write_threads: pthread_join failed.");
- }
- write_threads[i] = (pthread_t) 0;
- }
- sfree (write_threads);
- write_threads_num = 0;
-
- pthread_mutex_lock (&write_lock);
- i = 0;
- for (q = write_queue_head; q != NULL; )
- {
- write_queue_t *q1 = q;
- plugin_value_list_free (q->vl);
- q = q->next;
- sfree (q1);
- i++;
- }
- write_queue_head = NULL;
- write_queue_tail = NULL;
- write_queue_length = 0;
- pthread_mutex_unlock (&write_lock);
-
- if (i > 0)
- {
- WARNING ("plugin: %i value list%s left after shutting down "
- "the write threads.",
- i, (i == 1) ? " was" : "s were");
- }
-} /* }}} void stop_write_threads */
-
-/*
- * Public functions
- */
-void plugin_set_dir (const char *dir)
-{
- if (plugindir != NULL)
- free (plugindir);
-
- if (dir == NULL)
- plugindir = NULL;
- else if ((plugindir = strdup (dir)) == NULL)
- {
- char errbuf[1024];
- ERROR ("strdup failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- }
-}
-
-static _Bool plugin_is_loaded (char const *name)
-{
- int status;
-
- if (plugins_loaded == NULL)
- plugins_loaded = c_avl_create ((void *) strcasecmp);
- assert (plugins_loaded != NULL);
-
- status = c_avl_get (plugins_loaded, name, /* ret_value = */ NULL);
- return (status == 0);
-}
-
-static int plugin_mark_loaded (char const *name)
-{
- char *name_copy;
- int status;
-
- name_copy = strdup (name);
- if (name_copy == NULL)
- return (ENOMEM);
-
- status = c_avl_insert (plugins_loaded,
- /* key = */ name_copy, /* value = */ NULL);
- return (status);
-}
-
-static void plugin_free_loaded ()
-{
- void *key;
- void *value;
-
- if (plugins_loaded == NULL)
- return;
-
- while (c_avl_pick (plugins_loaded, &key, &value) == 0)
- {
- sfree (key);
- assert (value == NULL);
- }
-
- c_avl_destroy (plugins_loaded);
- plugins_loaded = NULL;
-}
-
-#define BUFSIZE 512
-int plugin_load (char const *plugin_name, uint32_t flags)
-{
- DIR *dh;
- const char *dir;
- char filename[BUFSIZE] = "";
- char typename[BUFSIZE];
- int typename_len;
- int ret;
- struct stat statbuf;
- struct dirent *de;
- int status;
-
- if (plugin_name == NULL)
- return (EINVAL);
-
- /* Check if plugin is already loaded and don't do anything in this
- * case. */
- if (plugin_is_loaded (plugin_name))
- return (0);
-
- dir = plugin_get_dir ();
- ret = 1;
-
- /*
- * XXX: Magic at work:
- *
- * Some of the language bindings, for example the Python and Perl
- * plugins, need to be able to export symbols to the scripts they run.
- * For this to happen, the "Globals" flag needs to be set.
- * Unfortunately, this technical detail is hard to explain to the
- * average user and she shouldn't have to worry about this, ideally.
- * So in order to save everyone's sanity use a different default for a
- * handful of special plugins. --octo
- */
- if ((strcasecmp ("perl", plugin_name) == 0)
- || (strcasecmp ("python", plugin_name) == 0))
- flags |= PLUGIN_FLAGS_GLOBAL;
-
- /* `cpu' should not match `cpufreq'. To solve this we add `.so' to the
- * type when matching the filename */
- status = ssnprintf (typename, sizeof (typename), "%s.so", plugin_name);
- if ((status < 0) || ((size_t) status >= sizeof (typename)))
- {
- WARNING ("plugin_load: Filename too long: \"%s.so\"", plugin_name);
- return (-1);
- }
- typename_len = strlen (typename);
-
- if ((dh = opendir (dir)) == NULL)
- {
- char errbuf[1024];
- ERROR ("plugin_load: opendir (%s) failed: %s", dir,
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (-1);
- }
-
- while ((de = readdir (dh)) != NULL)
- {
- if (strncasecmp (de->d_name, typename, typename_len))
- continue;
-
- status = ssnprintf (filename, sizeof (filename),
- "%s/%s", dir, de->d_name);
- if ((status < 0) || ((size_t) status >= sizeof (filename)))
- {
- WARNING ("plugin_load: Filename too long: \"%s/%s\"",
- dir, de->d_name);
- continue;
- }
-
- if (lstat (filename, &statbuf) == -1)
- {
- char errbuf[1024];
- WARNING ("plugin_load: stat (\"%s\") failed: %s",
- filename,
- sstrerror (errno, errbuf, sizeof (errbuf)));
- continue;
- }
- else if (!S_ISREG (statbuf.st_mode))
- {
- /* don't follow symlinks */
- WARNING ("plugin_load: %s is not a regular file.",
- filename);
- continue;
- }
-
- status = plugin_load_file (filename, flags);
- if (status == 0)
- {
- /* success */
- plugin_mark_loaded (plugin_name);
- ret = 0;
- break;
- }
- else
- {
- ERROR ("plugin_load: Load plugin \"%s\" failed with "
- "status %i.", plugin_name, status);
- }
- }
-
- closedir (dh);
-
- if (filename[0] == 0)
- ERROR ("plugin_load: Could not find plugin \"%s\" in %s",
- plugin_name, dir);
-
- return (ret);
-}
-
-/*
- * The `register_*' functions follow
- */
-int plugin_register_config (const char *name,
- int (*callback) (const char *key, const char *val),
- const char **keys, int keys_num)
-{
- cf_register (name, callback, keys, keys_num);
- 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 (create_register_callback (&list_init, name, (void *) callback,
- /* user_data = */ NULL));
-} /* plugin_register_init */
-
-static int plugin_compare_read_func (const void *arg0, const void *arg1)
-{
- const read_func_t *rf0;
- const read_func_t *rf1;
-
- rf0 = arg0;
- rf1 = arg1;
-
- if (rf0->rf_next_read < rf1->rf_next_read)
- return (-1);
- else if (rf0->rf_next_read > rf1->rf_next_read)
- return (1);
- else
- return (0);
-} /* int plugin_compare_read_func */
-
-/* Add a read function to both, the heap and a linked list. The linked list if
- * used to look-up read functions, especially for the remove function. The heap
- * is used to determine which plugin to read next. */
-static int plugin_insert_read (read_func_t *rf)
-{
- int status;
- llentry_t *le;
-
- rf->rf_next_read = cdtime ();
- rf->rf_effective_interval = rf->rf_interval;
-
- pthread_mutex_lock (&read_lock);
-
- if (read_list == NULL)
- {
- read_list = llist_create ();
- if (read_list == NULL)
- {
- pthread_mutex_unlock (&read_lock);
- ERROR ("plugin_insert_read: read_list failed.");
- return (-1);
- }
- }
-
- if (read_heap == NULL)
- {
- read_heap = c_heap_create (plugin_compare_read_func);
- if (read_heap == NULL)
- {
- pthread_mutex_unlock (&read_lock);
- ERROR ("plugin_insert_read: c_heap_create failed.");
- return (-1);
- }
- }
-
- le = llist_search (read_list, rf->rf_name);
- if (le != NULL)
- {
- pthread_mutex_unlock (&read_lock);
- WARNING ("The read function \"%s\" is already registered. "
- "Check for duplicate \"LoadPlugin\" lines "
- "in your configuration!",
- rf->rf_name);
- return (EINVAL);
- }
-
- le = llentry_create (rf->rf_name, rf);
- if (le == NULL)
- {
- pthread_mutex_unlock (&read_lock);
- ERROR ("plugin_insert_read: llentry_create failed.");
- return (-1);
- }
-
- status = c_heap_insert (read_heap, rf);
- if (status != 0)
- {
- pthread_mutex_unlock (&read_lock);
- ERROR ("plugin_insert_read: c_heap_insert failed.");
- llentry_destroy (le);
- return (-1);
- }
-
- /* This does not fail. */
- llist_append (read_list, le);
-
- /* Wake up all the read threads. */
- pthread_cond_broadcast (&read_cond);
- pthread_mutex_unlock (&read_lock);
- return (0);
-} /* int plugin_insert_read */
-
-int plugin_register_read (const char *name,
- int (*callback) (void))
-{
- read_func_t *rf;
- int status;
-
- rf = malloc (sizeof (*rf));
- if (rf == NULL)
- {
- ERROR ("plugin_register_read: malloc failed.");
- return (ENOMEM);
- }
-
- memset (rf, 0, sizeof (read_func_t));
- rf->rf_callback = (void *) callback;
- rf->rf_udata.data = NULL;
- rf->rf_udata.free_func = NULL;
- rf->rf_ctx = plugin_get_ctx ();
- rf->rf_group[0] = '\0';
- rf->rf_name = strdup (name);
- rf->rf_type = RF_SIMPLE;
- rf->rf_interval = plugin_get_interval ();
-
- status = plugin_insert_read (rf);
- if (status != 0)
- sfree (rf);
-
- return (status);
-} /* int plugin_register_read */
-
-int plugin_register_complex_read (const char *group, const char *name,
- plugin_read_cb callback,
- const struct timespec *interval,
- user_data_t *user_data)
-{
- read_func_t *rf;
- int status;
-
- rf = malloc (sizeof (*rf));
- if (rf == NULL)
- {
- ERROR ("plugin_register_complex_read: malloc failed.");
- return (ENOMEM);
- }
-
- memset (rf, 0, sizeof (read_func_t));
- rf->rf_callback = (void *) callback;
- if (group != NULL)
- sstrncpy (rf->rf_group, group, sizeof (rf->rf_group));
- else
- rf->rf_group[0] = '\0';
- rf->rf_name = strdup (name);
- rf->rf_type = RF_COMPLEX;
- if (interval != NULL)
- rf->rf_interval = TIMESPEC_TO_CDTIME_T (interval);
- else
- rf->rf_interval = plugin_get_interval ();
-
- /* Set user data */
- if (user_data == NULL)
- {
- rf->rf_udata.data = NULL;
- rf->rf_udata.free_func = NULL;
- }
- else
- {
- rf->rf_udata = *user_data;
- }
-
- rf->rf_ctx = plugin_get_ctx ();
-
- status = plugin_insert_read (rf);
- if (status != 0)
- sfree (rf);
-
- return (status);
-} /* int plugin_register_complex_read */
-
-int plugin_register_write (const char *name,
- plugin_write_cb callback, user_data_t *ud)
-{
- return (create_register_callback (&list_write, name,
- (void *) callback, ud));
-} /* int plugin_register_write */
-
-int plugin_register_flush (const char *name,
- plugin_flush_cb callback, user_data_t *ud)
-{
- return (create_register_callback (&list_flush, name,
- (void *) callback, ud));
-} /* int plugin_register_flush */
-
-int plugin_register_missing (const char *name,
- plugin_missing_cb callback, user_data_t *ud)
-{
- return (create_register_callback (&list_missing, name,
- (void *) callback, ud));
-} /* int plugin_register_missing */
-
-int plugin_register_shutdown (const char *name,
- int (*callback) (void))
-{
- return (create_register_callback (&list_shutdown, name,
- (void *) callback, /* user_data = */ NULL));
-} /* int plugin_register_shutdown */
-
-static void plugin_free_data_sets (void)
-{
- void *key;
- void *value;
-
- if (data_sets == NULL)
- return;
-
- while (c_avl_pick (data_sets, &key, &value) == 0)
- {
- data_set_t *ds = value;
- /* key is a pointer to ds->type */
-
- sfree (ds->ds);
- sfree (ds);
- }
-
- c_avl_destroy (data_sets);
- data_sets = NULL;
-} /* void plugin_free_data_sets */
-
-int plugin_register_data_set (const data_set_t *ds)
-{
- data_set_t *ds_copy;
- int i;
-
- if ((data_sets != NULL)
- && (c_avl_get (data_sets, ds->type, NULL) == 0))
- {
- NOTICE ("Replacing DS `%s' with another version.", ds->type);
- plugin_unregister_data_set (ds->type);
- }
- else if (data_sets == NULL)
- {
- data_sets = c_avl_create ((int (*) (const void *, const void *)) strcmp);
- if (data_sets == NULL)
- return (-1);
- }
-
- ds_copy = (data_set_t *) malloc (sizeof (data_set_t));
- if (ds_copy == NULL)
- return (-1);
- memcpy(ds_copy, ds, sizeof (data_set_t));
-
- ds_copy->ds = (data_source_t *) malloc (sizeof (data_source_t)
- * ds->ds_num);
- if (ds_copy->ds == NULL)
- {
- free (ds_copy);
- return (-1);
- }
-
- for (i = 0; i < ds->ds_num; i++)
- memcpy (ds_copy->ds + i, ds->ds + i, sizeof (data_source_t));
-
- return (c_avl_insert (data_sets, (void *) ds_copy->type, (void *) ds_copy));
-} /* int plugin_register_data_set */
-
-int plugin_register_log (const char *name,
- plugin_log_cb callback, user_data_t *ud)
-{
- return (create_register_callback (&list_log, name,
- (void *) callback, ud));
-} /* int plugin_register_log */
-
-int plugin_register_notification (const char *name,
- plugin_notification_cb callback, user_data_t *ud)
-{
- return (create_register_callback (&list_notification, name,
- (void *) callback, ud));
-} /* int plugin_register_log */
-
-int plugin_unregister_config (const char *name)
-{
- cf_unregister (name);
- return (0);
-} /* int plugin_unregister_config */
-
-int plugin_unregister_complex_config (const char *name)
-{
- cf_unregister_complex (name);
- return (0);
-} /* int plugin_unregister_complex_config */
-
-int plugin_unregister_init (const char *name)
-{
- return (plugin_unregister (list_init, name));
-}
-
-int plugin_unregister_read (const char *name) /* {{{ */
-{
- llentry_t *le;
- read_func_t *rf;
-
- if (name == NULL)
- return (-ENOENT);
-
- pthread_mutex_lock (&read_lock);
-
- if (read_list == NULL)
- {
- pthread_mutex_unlock (&read_lock);
- return (-ENOENT);
- }
-
- le = llist_search (read_list, name);
- if (le == NULL)
- {
- pthread_mutex_unlock (&read_lock);
- WARNING ("plugin_unregister_read: No such read function: %s",
- name);
- return (-ENOENT);
- }
-
- llist_remove (read_list, le);
-
- rf = le->value;
- assert (rf != NULL);
- rf->rf_type = RF_REMOVE;
-
- pthread_mutex_unlock (&read_lock);
-
- llentry_destroy (le);
-
- DEBUG ("plugin_unregister_read: Marked `%s' for removal.", name);
-
- return (0);
-} /* }}} int plugin_unregister_read */
-
-static int compare_read_func_group (llentry_t *e, void *ud) /* {{{ */
-{
- read_func_t *rf = e->value;
- char *group = ud;
-
- return strcmp (rf->rf_group, (const char *)group);
-} /* }}} int compare_read_func_group */
-
-int plugin_unregister_read_group (const char *group) /* {{{ */
-{
- llentry_t *le;
- read_func_t *rf;
-
- int found = 0;
-
- if (group == NULL)
- return (-ENOENT);
-
- pthread_mutex_lock (&read_lock);
-
- if (read_list == NULL)
- {
- pthread_mutex_unlock (&read_lock);
- return (-ENOENT);
- }
-
- while (42)
- {
- le = llist_search_custom (read_list,
- compare_read_func_group, (void *)group);
-
- if (le == NULL)
- break;
-
- ++found;
-
- llist_remove (read_list, le);
-
- rf = le->value;
- assert (rf != NULL);
- rf->rf_type = RF_REMOVE;
-
- llentry_destroy (le);
-
- DEBUG ("plugin_unregister_read_group: "
- "Marked `%s' (group `%s') for removal.",
- rf->rf_name, group);
- }
-
- pthread_mutex_unlock (&read_lock);
-
- if (found == 0)
- {
- WARNING ("plugin_unregister_read_group: No such "
- "group of read function: %s", group);
- return (-ENOENT);
- }
-
- return (0);
-} /* }}} int plugin_unregister_read_group */
-
-int plugin_unregister_write (const char *name)
-{
- return (plugin_unregister (list_write, name));
-}
-
-int plugin_unregister_flush (const char *name)
-{
- return (plugin_unregister (list_flush, name));
-}
-
-int plugin_unregister_missing (const char *name)
-{
- return (plugin_unregister (list_missing, name));
-}
-
-int plugin_unregister_shutdown (const char *name)
-{
- return (plugin_unregister (list_shutdown, name));
-}
-
-int plugin_unregister_data_set (const char *name)
-{
- data_set_t *ds;
-
- if (data_sets == NULL)
- return (-1);
-
- if (c_avl_remove (data_sets, name, NULL, (void *) &ds) != 0)
- return (-1);
-
- sfree (ds->ds);
- sfree (ds);
-
- return (0);
-} /* int plugin_unregister_data_set */
-
-int plugin_unregister_log (const char *name)
-{
- return (plugin_unregister (list_log, name));
-}
-
-int plugin_unregister_notification (const char *name)
-{
- return (plugin_unregister (list_notification, name));
-}
-
-void plugin_init_all (void)
-{
- char const *chain_name;
- long write_threads_num;
- llentry_t *le;
- int status;
-
- /* Init the value cache */
- uc_init ();
-
- if (IS_TRUE (global_option_get ("CollectInternalStats")))
- record_statistics = 1;
-
- chain_name = global_option_get ("PreCacheChain");
- pre_cache_chain = fc_chain_get_by_name (chain_name);
-
- chain_name = global_option_get ("PostCacheChain");
- post_cache_chain = fc_chain_get_by_name (chain_name);
-
- write_limit_high = global_option_get_long ("WriteQueueLimitHigh",
- /* default = */ 0);
- if (write_limit_high < 0)
- {
- ERROR ("WriteQueueLimitHigh must be positive or zero.");
- write_limit_high = 0;
- }
-
- write_limit_low = global_option_get_long ("WriteQueueLimitLow",
- /* default = */ write_limit_high / 2);
- if (write_limit_low < 0)
- {
- ERROR ("WriteQueueLimitLow must be positive or zero.");
- write_limit_low = write_limit_high / 2;
- }
- else if (write_limit_low > write_limit_high)
- {
- ERROR ("WriteQueueLimitLow must not be larger than "
- "WriteQueueLimitHigh.");
- write_limit_low = write_limit_high;
- }
-
- write_threads_num = global_option_get_long ("WriteThreads",
- /* default = */ 5);
- if (write_threads_num < 1)
- {
- ERROR ("WriteThreads must be positive.");
- write_threads_num = 5;
- }
-
- start_write_threads ((size_t) write_threads_num);
-
- if ((list_init == NULL) && (read_heap == NULL))
- return;
-
- /* Calling all init callbacks before checking if read callbacks
- * are available allows the init callbacks to register the read
- * callback. */
- le = llist_head (list_init);
- while (le != NULL)
- {
- callback_func_t *cf;
- plugin_init_cb callback;
- plugin_ctx_t old_ctx;
-
- cf = le->value;
- old_ctx = plugin_set_ctx (cf->cf_ctx);
- callback = cf->cf_callback;
- status = (*callback) ();
- plugin_set_ctx (old_ctx);
-
- if (status != 0)
- {
- ERROR ("Initialization of plugin `%s' "
- "failed with status %i. "
- "Plugin will be unloaded.",
- le->key, status);
- /* Plugins that register read callbacks from the init
- * callback should take care of appropriate error
- * handling themselves. */
- /* FIXME: Unload _all_ functions */
- plugin_unregister_read (le->key);
- }
-
- le = le->next;
- }
-
- max_read_interval = global_option_get_time ("MaxReadInterval",
- DEFAULT_MAX_READ_INTERVAL);
-
- /* Start read-threads */
- if (read_heap != NULL)
- {
- const char *rt;
- int num;
-
- rt = global_option_get ("ReadThreads");
- num = atoi (rt);
- if (num != -1)
- start_read_threads ((num > 0) ? num : 5);
- }
-} /* void plugin_init_all */
-
-/* TODO: Rename this function. */
-void plugin_read_all (void)
-{
- if(record_statistics) {
- plugin_update_internal_statistics ();
- }
- uc_check_timeout ();
-
- return;
-} /* void plugin_read_all */
-
-/* Read function called when the `-T' command line argument is given. */
-int plugin_read_all_once (void)
-{
- int status;
- int return_status = 0;
-
- if (read_heap == NULL)
- {
- NOTICE ("No read-functions are registered.");
- return (0);
- }
-
- while (42)
- {
- read_func_t *rf;
- plugin_ctx_t old_ctx;
-
- rf = c_heap_get_root (read_heap);
- if (rf == NULL)
- break;
-
- old_ctx = plugin_set_ctx (rf->rf_ctx);
-
- if (rf->rf_type == RF_SIMPLE)
- {
- int (*callback) (void);
-
- callback = rf->rf_callback;
- status = (*callback) ();
- }
- else
- {
- plugin_read_cb callback;
-
- callback = rf->rf_callback;
- status = (*callback) (&rf->rf_udata);
- }
-
- plugin_set_ctx (old_ctx);
-
- if (status != 0)
- {
- NOTICE ("read-function of plugin `%s' failed.",
- rf->rf_name);
- return_status = -1;
- }
-
- destroy_callback ((void *) rf);
- }
-
- return (return_status);
-} /* int plugin_read_all_once */
-
-int plugin_write (const char *plugin, /* {{{ */
- const data_set_t *ds, const value_list_t *vl)
-{
- llentry_t *le;
- int status;
-
- if (vl == NULL)
- return (EINVAL);
-
- if (list_write == NULL)
- return (ENOENT);
-
- if (ds == NULL)
- {
- ds = plugin_get_ds (vl->type);
- if (ds == NULL)
- {
- ERROR ("plugin_write: Unable to lookup type `%s'.", vl->type);
- return (ENOENT);
- }
- }
-
- if (plugin == NULL)
- {
- int success = 0;
- int failure = 0;
-
- le = llist_head (list_write);
- while (le != NULL)
- {
- callback_func_t *cf = le->value;
- plugin_write_cb callback;
-
- /* do not switch plugin context; rather keep the context (interval)
- * information of the calling read plugin */
-
- DEBUG ("plugin: plugin_write: Writing values via %s.", le->key);
- callback = cf->cf_callback;
- status = (*callback) (ds, vl, &cf->cf_udata);
- if (status != 0)
- failure++;
- else
- success++;
-
- le = le->next;
- }
-
- if ((success == 0) && (failure != 0))
- status = -1;
- else
- status = 0;
- }
- else /* plugin != NULL */
- {
- callback_func_t *cf;
- plugin_write_cb callback;
-
- le = llist_head (list_write);
- while (le != NULL)
- {
- if (strcasecmp (plugin, le->key) == 0)
- break;
-
- le = le->next;
- }
-
- if (le == NULL)
- return (ENOENT);
-
- cf = le->value;
-
- /* do not switch plugin context; rather keep the context (interval)
- * information of the calling read plugin */
-
- DEBUG ("plugin: plugin_write: Writing values via %s.", le->key);
- callback = cf->cf_callback;
- status = (*callback) (ds, vl, &cf->cf_udata);
- }
-
- return (status);
-} /* }}} int plugin_write */
-
-int plugin_flush (const char *plugin, cdtime_t timeout, const char *identifier)
-{
- llentry_t *le;
-
- if (list_flush == NULL)
- return (0);
-
- le = llist_head (list_flush);
- while (le != NULL)
- {
- callback_func_t *cf;
- plugin_flush_cb callback;
- plugin_ctx_t old_ctx;
-
- if ((plugin != NULL)
- && (strcmp (plugin, le->key) != 0))
- {
- le = le->next;
- continue;
- }
-
- cf = le->value;
- old_ctx = plugin_set_ctx (cf->cf_ctx);
- callback = cf->cf_callback;
-
- (*callback) (timeout, identifier, &cf->cf_udata);
-
- plugin_set_ctx (old_ctx);
-
- le = le->next;
- }
- return (0);
-} /* int plugin_flush */
-
-void plugin_shutdown_all (void)
-{
- llentry_t *le;
-
- stop_read_threads ();
-
- destroy_all_callbacks (&list_init);
-
- pthread_mutex_lock (&read_lock);
- llist_destroy (read_list);
- read_list = NULL;
- pthread_mutex_unlock (&read_lock);
-
- destroy_read_heap ();
-
- plugin_flush (/* plugin = */ NULL,
- /* timeout = */ 0,
- /* identifier = */ NULL);
-
- le = NULL;
- if (list_shutdown != NULL)
- le = llist_head (list_shutdown);
-
- while (le != NULL)
- {
- callback_func_t *cf;
- plugin_shutdown_cb callback;
- plugin_ctx_t old_ctx;
-
- cf = le->value;
- old_ctx = plugin_set_ctx (cf->cf_ctx);
- callback = cf->cf_callback;
-
- /* Advance the pointer before calling the callback allows
- * shutdown functions to unregister themselves. If done the
- * other way around the memory `le' points to will be freed
- * after callback returns. */
- le = le->next;
-
- (*callback) ();
-
- plugin_set_ctx (old_ctx);
- }
-
- stop_write_threads ();
-
- /* Write plugins which use the `user_data' pointer usually need the
- * same data available to the flush callback. If this is the case, set
- * the free_function to NULL when registering the flush callback and to
- * the real free function when registering the write callback. This way
- * the data isn't freed twice. */
- destroy_all_callbacks (&list_flush);
- destroy_all_callbacks (&list_missing);
- destroy_all_callbacks (&list_write);
-
- destroy_all_callbacks (&list_notification);
- destroy_all_callbacks (&list_shutdown);
- destroy_all_callbacks (&list_log);
-
- plugin_free_loaded ();
- plugin_free_data_sets ();
-} /* void plugin_shutdown_all */
-
-int plugin_dispatch_missing (const value_list_t *vl) /* {{{ */
-{
- llentry_t *le;
-
- if (list_missing == NULL)
- return (0);
-
- le = llist_head (list_missing);
- while (le != NULL)
- {
- callback_func_t *cf;
- plugin_missing_cb callback;
- plugin_ctx_t old_ctx;
- int status;
-
- cf = le->value;
- old_ctx = plugin_set_ctx (cf->cf_ctx);
- callback = cf->cf_callback;
-
- status = (*callback) (vl, &cf->cf_udata);
- plugin_set_ctx (old_ctx);
- if (status != 0)
- {
- if (status < 0)
- {
- ERROR ("plugin_dispatch_missing: Callback function \"%s\" "
- "failed with status %i.",
- le->key, status);
- return (status);
- }
- else
- {
- return (0);
- }
- }
-
- le = le->next;
- }
- return (0);
-} /* int }}} plugin_dispatch_missing */
-
-static int plugin_dispatch_values_internal (value_list_t *vl)
-{
- int status;
- static c_complain_t no_write_complaint = C_COMPLAIN_INIT_STATIC;
-
- value_t *saved_values;
- int saved_values_len;
-
- data_set_t *ds;
-
- int free_meta_data = 0;
-
- if ((vl == NULL) || (vl->type[0] == 0)
- || (vl->values == NULL) || (vl->values_len < 1))
- {
- ERROR ("plugin_dispatch_values: Invalid value list "
- "from plugin %s.", vl->plugin);
- return (-1);
- }
-
- /* Free meta data only if the calling function didn't specify any. In
- * this case matches and targets may add some and the calling function
- * may not expect (and therefore free) that data. */
- if (vl->meta == NULL)
- free_meta_data = 1;
-
- if (list_write == NULL)
- c_complain_once (LOG_WARNING, &no_write_complaint,
- "plugin_dispatch_values: No write callback has been "
- "registered. Please load at least one output plugin, "
- "if you want the collected data to be stored.");
-
- if (data_sets == NULL)
- {
- ERROR ("plugin_dispatch_values: No data sets registered. "
- "Could the types database be read? Check "
- "your `TypesDB' setting!");
- return (-1);
- }
-
- if (c_avl_get (data_sets, vl->type, (void *) &ds) != 0)
- {
- char ident[6 * DATA_MAX_NAME_LEN];
-
- FORMAT_VL (ident, sizeof (ident), vl);
- INFO ("plugin_dispatch_values: Dataset not found: %s "
- "(from \"%s\"), check your types.db!",
- vl->type, ident);
- return (-1);
- }
-
- /* Assured by plugin_value_list_clone(). The time is determined at
- * _enqueue_ time. */
- assert (vl->time != 0);
- assert (vl->interval != 0);
-
- DEBUG ("plugin_dispatch_values: time = %.3f; interval = %.3f; "
- "host = %s; "
- "plugin = %s; plugin_instance = %s; "
- "type = %s; type_instance = %s;",
- CDTIME_T_TO_DOUBLE (vl->time),
- CDTIME_T_TO_DOUBLE (vl->interval),
- vl->host,
- vl->plugin, vl->plugin_instance,
- vl->type, vl->type_instance);
-
-#if COLLECT_DEBUG
- assert (0 == strcmp (ds->type, vl->type));
-#else
- if (0 != strcmp (ds->type, vl->type))
- WARNING ("plugin_dispatch_values: (ds->type = %s) != (vl->type = %s)",
- ds->type, vl->type);
-#endif
-
-#if COLLECT_DEBUG
- assert (ds->ds_num == vl->values_len);
-#else
- if (ds->ds_num != vl->values_len)
- {
- ERROR ("plugin_dispatch_values: ds->type = %s: "
- "(ds->ds_num = %i) != "
- "(vl->values_len = %i)",
- ds->type, ds->ds_num, vl->values_len);
- return (-1);
- }
-#endif
-
- escape_slashes (vl->host, sizeof (vl->host));
- escape_slashes (vl->plugin, sizeof (vl->plugin));
- escape_slashes (vl->plugin_instance, sizeof (vl->plugin_instance));
- escape_slashes (vl->type, sizeof (vl->type));
- escape_slashes (vl->type_instance, sizeof (vl->type_instance));
-
- /* Copy the values. This way, we can assure `targets' that they get
- * dynamically allocated values, which they can free and replace if
- * they like. */
- if ((pre_cache_chain != NULL) || (post_cache_chain != NULL))
- {
- saved_values = vl->values;
- saved_values_len = vl->values_len;
-
- vl->values = (value_t *) calloc (vl->values_len,
- sizeof (*vl->values));
- if (vl->values == NULL)
- {
- ERROR ("plugin_dispatch_values: calloc failed.");
- vl->values = saved_values;
- return (-1);
- }
- memcpy (vl->values, saved_values,
- vl->values_len * sizeof (*vl->values));
- }
- else /* if ((pre == NULL) && (post == NULL)) */
- {
- saved_values = NULL;
- saved_values_len = 0;
- }
-
- if (pre_cache_chain != NULL)
- {
- status = fc_process_chain (ds, vl, pre_cache_chain);
- if (status < 0)
- {
- WARNING ("plugin_dispatch_values: Running the "
- "pre-cache chain failed with "
- "status %i (%#x).",
- status, status);
- }
- else if (status == FC_TARGET_STOP)
- {
- /* Restore the state of the value_list so that plugins
- * don't get confused.. */
- if (saved_values != NULL)
- {
- free (vl->values);
- vl->values = saved_values;
- vl->values_len = saved_values_len;
- }
- return (0);
- }
- }
-
- /* Update the value cache */
- uc_update (ds, vl);
-
- if (post_cache_chain != NULL)
- {
- status = fc_process_chain (ds, vl, post_cache_chain);
- if (status < 0)
- {
- WARNING ("plugin_dispatch_values: Running the "
- "post-cache chain failed with "
- "status %i (%#x).",
- status, status);
- }
- }
- else
- fc_default_action (ds, vl);
-
- /* Restore the state of the value_list so that plugins don't get
- * confused.. */
- if (saved_values != NULL)
- {
- free (vl->values);
- vl->values = saved_values;
- vl->values_len = saved_values_len;
- }
-
- if ((free_meta_data != 0) && (vl->meta != NULL))
- {
- meta_data_destroy (vl->meta);
- vl->meta = NULL;
- }
-
- return (0);
-} /* int plugin_dispatch_values_internal */
-
-static double get_drop_probability (void) /* {{{ */
-{
- long pos;
- long size;
- long wql;
-
- pthread_mutex_lock (&write_lock);
- wql = write_queue_length;
- pthread_mutex_unlock (&write_lock);
-
- if (wql < write_limit_low)
- return (0.0);
- if (wql >= write_limit_high)
- return (1.0);
-
- pos = 1 + wql - write_limit_low;
- size = 1 + write_limit_high - write_limit_low;
-
- return (((double) pos) / ((double) size));
-} /* }}} double get_drop_probability */
-
-static _Bool check_drop_value (void) /* {{{ */
-{
- static cdtime_t last_message_time = 0;
- static pthread_mutex_t last_message_lock = PTHREAD_MUTEX_INITIALIZER;
-
- double p;
- double q;
- int status;
-
- if (write_limit_high == 0)
- return (0);
-
- p = get_drop_probability ();
- if (p == 0.0)
- return (0);
-
- status = pthread_mutex_trylock (&last_message_lock);
- if (status == 0)
- {
- cdtime_t now;
-
- now = cdtime ();
- if ((now - last_message_time) > TIME_T_TO_CDTIME_T (1))
- {
- last_message_time = now;
- ERROR ("plugin_dispatch_values: Low water mark "
- "reached. Dropping %.0f%% of metrics.",
- 100.0 * p);
- }
- pthread_mutex_unlock (&last_message_lock);
- }
-
- if (p == 1.0)
- return (1);
-
- q = cdrand_d ();
- if (q > p)
- return (1);
- else
- return (0);
-} /* }}} _Bool check_drop_value */
-
-int plugin_dispatch_values (value_list_t const *vl)
-{
- int status;
- static pthread_mutex_t statistics_lock = PTHREAD_MUTEX_INITIALIZER;
-
- if (check_drop_value ()) {
- if(record_statistics) {
- pthread_mutex_lock(&statistics_lock);
- stats_values_dropped++;
- pthread_mutex_unlock(&statistics_lock);
- }
- return (0);
- }
-
- status = plugin_write_enqueue (vl);
- if (status != 0)
- {
- char errbuf[1024];
- ERROR ("plugin_dispatch_values: plugin_write_enqueue failed "
- "with status %i (%s).", status,
- sstrerror (status, errbuf, sizeof (errbuf)));
- return (status);
- }
-
- return (0);
-}
-
-__attribute__((sentinel))
-int plugin_dispatch_multivalue (value_list_t const *template, /* {{{ */
- _Bool store_percentage, ...)
-{
- value_list_t *vl;
- int failed = 0;
- gauge_t sum = 0.0;
- va_list ap;
-
- assert (template->values_len == 1);
-
- va_start (ap, store_percentage);
- while (42)
- {
- char const *name;
- gauge_t value;
-
- name = va_arg (ap, char const *);
- if (name == NULL)
- break;
-
- value = va_arg (ap, gauge_t);
- if (!isnan (value))
- sum += value;
- }
- va_end (ap);
-
- vl = plugin_value_list_clone (template);
- /* plugin_value_list_clone makes sure vl->time is set to non-zero. */
- if (store_percentage)
- sstrncpy (vl->type, "percent", sizeof (vl->type));
-
- va_start (ap, store_percentage);
- while (42)
- {
- char const *name;
- int status;
-
- /* Set the type instance. */
- name = va_arg (ap, char const *);
- if (name == NULL)
- break;
- sstrncpy (vl->type_instance, name, sizeof (vl->type_instance));
-
- /* Set the value. */
- vl->values[0].gauge = va_arg (ap, gauge_t);
- if (store_percentage)
- vl->values[0].gauge *= 100.0 / sum;
-
- status = plugin_write_enqueue (vl);
- if (status != 0)
- failed++;
- }
- va_end (ap);
-
- plugin_value_list_free (vl);
- return (failed);
-} /* }}} int plugin_dispatch_multivalue */
-
-int plugin_dispatch_notification (const notification_t *notif)
-{
- llentry_t *le;
- /* Possible TODO: Add flap detection here */
-
- DEBUG ("plugin_dispatch_notification: severity = %i; message = %s; "
- "time = %.3f; host = %s;",
- notif->severity, notif->message,
- CDTIME_T_TO_DOUBLE (notif->time), notif->host);
-
- /* Nobody cares for notifications */
- if (list_notification == NULL)
- return (-1);
-
- le = llist_head (list_notification);
- while (le != NULL)
- {
- callback_func_t *cf;
- plugin_notification_cb callback;
- int status;
-
- /* do not switch plugin context; rather keep the context
- * (interval) information of the calling plugin */
-
- cf = le->value;
- callback = cf->cf_callback;
- status = (*callback) (notif, &cf->cf_udata);
- if (status != 0)
- {
- WARNING ("plugin_dispatch_notification: Notification "
- "callback %s returned %i.",
- le->key, status);
- }
-
- le = le->next;
- }
-
- return (0);
-} /* int plugin_dispatch_notification */
-
-void plugin_log (int level, const char *format, ...)
-{
- char msg[1024];
- va_list ap;
- llentry_t *le;
-
-#if !COLLECT_DEBUG
- if (level >= LOG_DEBUG)
- return;
-#endif
-
- va_start (ap, format);
- vsnprintf (msg, sizeof (msg), format, ap);
- msg[sizeof (msg) - 1] = '\0';
- va_end (ap);
-
- if (list_log == NULL)
- {
- fprintf (stderr, "%s\n", msg);
- return;
- }
-
- le = llist_head (list_log);
- while (le != NULL)
- {
- callback_func_t *cf;
- plugin_log_cb callback;
-
- cf = le->value;
- callback = cf->cf_callback;
-
- /* do not switch plugin context; rather keep the context
- * (interval) information of the calling plugin */
-
- (*callback) (level, msg, &cf->cf_udata);
-
- le = le->next;
- }
-} /* void plugin_log */
-
-int parse_log_severity (const char *severity)
-{
- int log_level = -1;
-
- if ((0 == strcasecmp (severity, "emerg"))
- || (0 == strcasecmp (severity, "alert"))
- || (0 == strcasecmp (severity, "crit"))
- || (0 == strcasecmp (severity, "err")))
- log_level = LOG_ERR;
- else if (0 == strcasecmp (severity, "warning"))
- log_level = LOG_WARNING;
- else if (0 == strcasecmp (severity, "notice"))
- log_level = LOG_NOTICE;
- else if (0 == strcasecmp (severity, "info"))
- log_level = LOG_INFO;
-#if COLLECT_DEBUG
- else if (0 == strcasecmp (severity, "debug"))
- log_level = LOG_DEBUG;
-#endif /* COLLECT_DEBUG */
-
- return (log_level);
-} /* int parse_log_severity */
-
-int parse_notif_severity (const char *severity)
-{
- int notif_severity = -1;
-
- if (strcasecmp (severity, "FAILURE") == 0)
- notif_severity = NOTIF_FAILURE;
- else if (strcmp (severity, "OKAY") == 0)
- notif_severity = NOTIF_OKAY;
- else if ((strcmp (severity, "WARNING") == 0)
- || (strcmp (severity, "WARN") == 0))
- notif_severity = NOTIF_WARNING;
-
- return (notif_severity);
-} /* int parse_notif_severity */
-
-const data_set_t *plugin_get_ds (const char *name)
-{
- data_set_t *ds;
-
- if (data_sets == NULL)
- {
- ERROR ("plugin_get_ds: No data sets are defined yet.");
- return (NULL);
- }
-
- if (c_avl_get (data_sets, name, (void *) &ds) != 0)
- {
- DEBUG ("No such dataset registered: %s", name);
- return (NULL);
- }
-
- return (ds);
-} /* data_set_t *plugin_get_ds */
-
-static int plugin_notification_meta_add (notification_t *n,
- const char *name,
- enum notification_meta_type_e type,
- const void *value)
-{
- notification_meta_t *meta;
- notification_meta_t *tail;
-
- if ((n == NULL) || (name == NULL) || (value == NULL))
- {
- ERROR ("plugin_notification_meta_add: A pointer is NULL!");
- return (-1);
- }
-
- meta = (notification_meta_t *) malloc (sizeof (notification_meta_t));
- if (meta == NULL)
- {
- ERROR ("plugin_notification_meta_add: malloc failed.");
- return (-1);
- }
- memset (meta, 0, sizeof (notification_meta_t));
-
- sstrncpy (meta->name, name, sizeof (meta->name));
- meta->type = type;
-
- switch (type)
- {
- case NM_TYPE_STRING:
- {
- meta->nm_value.nm_string = strdup ((const char *) value);
- if (meta->nm_value.nm_string == NULL)
- {
- ERROR ("plugin_notification_meta_add: strdup failed.");
- sfree (meta);
- return (-1);
- }
- break;
- }
- case NM_TYPE_SIGNED_INT:
- {
- meta->nm_value.nm_signed_int = *((int64_t *) value);
- break;
- }
- case NM_TYPE_UNSIGNED_INT:
- {
- meta->nm_value.nm_unsigned_int = *((uint64_t *) value);
- break;
- }
- case NM_TYPE_DOUBLE:
- {
- meta->nm_value.nm_double = *((double *) value);
- break;
- }
- case NM_TYPE_BOOLEAN:
- {
- meta->nm_value.nm_boolean = *((_Bool *) value);
- break;
- }
- default:
- {
- ERROR ("plugin_notification_meta_add: Unknown type: %i", type);
- sfree (meta);
- return (-1);
- }
- } /* switch (type) */
-
- meta->next = NULL;
- tail = n->meta;
- while ((tail != NULL) && (tail->next != NULL))
- tail = tail->next;
-
- if (tail == NULL)
- n->meta = meta;
- else
- tail->next = meta;
-
- return (0);
-} /* int plugin_notification_meta_add */
-
-int plugin_notification_meta_add_string (notification_t *n,
- const char *name,
- const char *value)
-{
- return (plugin_notification_meta_add (n, name, NM_TYPE_STRING, value));
-}
-
-int plugin_notification_meta_add_signed_int (notification_t *n,
- const char *name,
- int64_t value)
-{
- return (plugin_notification_meta_add (n, name, NM_TYPE_SIGNED_INT, &value));
-}
-
-int plugin_notification_meta_add_unsigned_int (notification_t *n,
- const char *name,
- uint64_t value)
-{
- return (plugin_notification_meta_add (n, name, NM_TYPE_UNSIGNED_INT, &value));
-}
-
-int plugin_notification_meta_add_double (notification_t *n,
- const char *name,
- double value)
-{
- return (plugin_notification_meta_add (n, name, NM_TYPE_DOUBLE, &value));
-}
-
-int plugin_notification_meta_add_boolean (notification_t *n,
- const char *name,
- _Bool value)
-{
- return (plugin_notification_meta_add (n, name, NM_TYPE_BOOLEAN, &value));
-}
-
-int plugin_notification_meta_copy (notification_t *dst,
- const notification_t *src)
-{
- notification_meta_t *meta;
-
- assert (dst != NULL);
- assert (src != NULL);
- assert (dst != src);
- assert ((src->meta == NULL) || (src->meta != dst->meta));
-
- for (meta = src->meta; meta != NULL; meta = meta->next)
- {
- if (meta->type == NM_TYPE_STRING)
- plugin_notification_meta_add_string (dst, meta->name,
- meta->nm_value.nm_string);
- else if (meta->type == NM_TYPE_SIGNED_INT)
- plugin_notification_meta_add_signed_int (dst, meta->name,
- meta->nm_value.nm_signed_int);
- else if (meta->type == NM_TYPE_UNSIGNED_INT)
- plugin_notification_meta_add_unsigned_int (dst, meta->name,
- meta->nm_value.nm_unsigned_int);
- else if (meta->type == NM_TYPE_DOUBLE)
- plugin_notification_meta_add_double (dst, meta->name,
- meta->nm_value.nm_double);
- else if (meta->type == NM_TYPE_BOOLEAN)
- plugin_notification_meta_add_boolean (dst, meta->name,
- meta->nm_value.nm_boolean);
- }
-
- return (0);
-} /* int plugin_notification_meta_copy */
-
-int plugin_notification_meta_free (notification_meta_t *n)
-{
- notification_meta_t *this;
- notification_meta_t *next;
-
- if (n == NULL)
- {
- ERROR ("plugin_notification_meta_free: n == NULL!");
- return (-1);
- }
-
- this = n;
- while (this != NULL)
- {
- next = this->next;
-
- if (this->type == NM_TYPE_STRING)
- {
- free ((char *)this->nm_value.nm_string);
- this->nm_value.nm_string = NULL;
- }
- sfree (this);
-
- this = next;
- }
-
- return (0);
-} /* int plugin_notification_meta_free */
-
-static void plugin_ctx_destructor (void *ctx)
-{
- sfree (ctx);
-} /* void plugin_ctx_destructor */
-
-static plugin_ctx_t ctx_init = { /* interval = */ 0 };
-
-static plugin_ctx_t *plugin_ctx_create (void)
-{
- plugin_ctx_t *ctx;
-
- ctx = malloc (sizeof (*ctx));
- if (ctx == NULL) {
- char errbuf[1024];
- ERROR ("Failed to allocate plugin context: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return NULL;
- }
-
- *ctx = ctx_init;
- assert (plugin_ctx_key_initialized);
- pthread_setspecific (plugin_ctx_key, ctx);
- DEBUG("Created new plugin context.");
- return (ctx);
-} /* int plugin_ctx_create */
-
-void plugin_init_ctx (void)
-{
- pthread_key_create (&plugin_ctx_key, plugin_ctx_destructor);
- plugin_ctx_key_initialized = 1;
-} /* void plugin_init_ctx */
-
-plugin_ctx_t plugin_get_ctx (void)
-{
- plugin_ctx_t *ctx;
-
- assert (plugin_ctx_key_initialized);
- ctx = pthread_getspecific (plugin_ctx_key);
-
- if (ctx == NULL) {
- ctx = plugin_ctx_create ();
- /* this must no happen -- exit() instead? */
- if (ctx == NULL)
- return ctx_init;
- }
-
- return (*ctx);
-} /* plugin_ctx_t plugin_get_ctx */
-
-plugin_ctx_t plugin_set_ctx (plugin_ctx_t ctx)
-{
- plugin_ctx_t *c;
- plugin_ctx_t old;
-
- assert (plugin_ctx_key_initialized);
- c = pthread_getspecific (plugin_ctx_key);
-
- if (c == NULL) {
- c = plugin_ctx_create ();
- /* this must no happen -- exit() instead? */
- if (c == NULL)
- return ctx_init;
- }
-
- old = *c;
- *c = ctx;
-
- return (old);
-} /* void plugin_set_ctx */
-
-cdtime_t plugin_get_interval (void)
-{
- cdtime_t interval;
-
- interval = plugin_get_ctx().interval;
- if (interval > 0)
- return interval;
-
- return cf_get_default_interval ();
-} /* cdtime_t plugin_get_interval */
-
-typedef struct {
- plugin_ctx_t ctx;
- void *(*start_routine) (void *);
- void *arg;
-} plugin_thread_t;
-
-static void *plugin_thread_start (void *arg)
-{
- plugin_thread_t *plugin_thread = arg;
-
- void *(*start_routine) (void *) = plugin_thread->start_routine;
- void *plugin_arg = plugin_thread->arg;
-
- plugin_set_ctx (plugin_thread->ctx);
-
- free (plugin_thread);
-
- return start_routine (plugin_arg);
-} /* void *plugin_thread_start */
-
-int plugin_thread_create (pthread_t *thread, const pthread_attr_t *attr,
- void *(*start_routine) (void *), void *arg)
-{
- plugin_thread_t *plugin_thread;
-
- plugin_thread = malloc (sizeof (*plugin_thread));
- if (plugin_thread == NULL)
- return -1;
-
- plugin_thread->ctx = plugin_get_ctx ();
- plugin_thread->start_routine = start_routine;
- plugin_thread->arg = arg;
-
- return pthread_create (thread, attr,
- plugin_thread_start, plugin_thread);
-} /* int plugin_thread_create */
-
-/* vim: set sw=8 ts=8 noet fdm=marker : */
diff --git a/src/plugin.h b/src/plugin.h
--- a/src/plugin.h
+++ /dev/null
@@ -1,437 +0,0 @@
-/**
- * collectd - src/plugin.h
- * Copyright (C) 2005-2014 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- * Sebastian Harl <sh at tokkee.org>
- **/
-
-#ifndef PLUGIN_H
-#define PLUGIN_H
-
-#include "collectd.h"
-#include "configfile.h"
-#include "meta_data.h"
-#include "utils_time.h"
-
-#define PLUGIN_FLAGS_GLOBAL 0x0001
-
-#define DATA_MAX_NAME_LEN 64
-
-#define DS_TYPE_COUNTER 0
-#define DS_TYPE_GAUGE 1
-#define DS_TYPE_DERIVE 2
-#define DS_TYPE_ABSOLUTE 3
-
-#define DS_TYPE_TO_STRING(t) (t == DS_TYPE_COUNTER) ? "counter" : \
- (t == DS_TYPE_GAUGE) ? "gauge" : \
- (t == DS_TYPE_DERIVE) ? "derive" : \
- (t == DS_TYPE_ABSOLUTE) ? "absolute" : \
- "unknown"
-
-
-#ifndef LOG_ERR
-# define LOG_ERR 3
-#endif
-#ifndef LOG_WARNING
-# define LOG_WARNING 4
-#endif
-#ifndef LOG_NOTICE
-# define LOG_NOTICE 5
-#endif
-#ifndef LOG_INFO
-# define LOG_INFO 6
-#endif
-#ifndef LOG_DEBUG
-# define LOG_DEBUG 7
-#endif
-
-#define NOTIF_MAX_MSG_LEN 256
-
-#define NOTIF_FAILURE 1
-#define NOTIF_WARNING 2
-#define NOTIF_OKAY 4
-
-#define plugin_interval (plugin_get_ctx().interval)
-
-/*
- * Public data types
- */
-typedef unsigned long long counter_t;
-typedef double gauge_t;
-typedef int64_t derive_t;
-typedef uint64_t absolute_t;
-
-union value_u
-{
- counter_t counter;
- gauge_t gauge;
- derive_t derive;
- absolute_t absolute;
-};
-typedef union value_u value_t;
-
-struct value_list_s
-{
- value_t *values;
- int values_len;
- cdtime_t time;
- cdtime_t interval;
- char host[DATA_MAX_NAME_LEN];
- char plugin[DATA_MAX_NAME_LEN];
- char plugin_instance[DATA_MAX_NAME_LEN];
- char type[DATA_MAX_NAME_LEN];
- char type_instance[DATA_MAX_NAME_LEN];
- meta_data_t *meta;
-};
-typedef struct value_list_s value_list_t;
-
-#define VALUE_LIST_INIT { NULL, 0, 0, plugin_get_interval (), \
- "localhost", "", "", "", "", NULL }
-#define VALUE_LIST_STATIC { NULL, 0, 0, 0, "localhost", "", "", "", "", NULL }
-
-struct data_source_s
-{
- char name[DATA_MAX_NAME_LEN];
- int type;
- double min;
- double max;
-};
-typedef struct data_source_s data_source_t;
-
-struct data_set_s
-{
- char type[DATA_MAX_NAME_LEN];
- int ds_num;
- data_source_t *ds;
-};
-typedef struct data_set_s data_set_t;
-
-enum notification_meta_type_e
-{
- NM_TYPE_STRING,
- NM_TYPE_SIGNED_INT,
- NM_TYPE_UNSIGNED_INT,
- NM_TYPE_DOUBLE,
- NM_TYPE_BOOLEAN
-};
-
-typedef struct notification_meta_s
-{
- char name[DATA_MAX_NAME_LEN];
- enum notification_meta_type_e type;
- union
- {
- const char *nm_string;
- int64_t nm_signed_int;
- uint64_t nm_unsigned_int;
- double nm_double;
- _Bool nm_boolean;
- } nm_value;
- struct notification_meta_s *next;
-} notification_meta_t;
-
-typedef struct notification_s
-{
- int severity;
- cdtime_t time;
- char message[NOTIF_MAX_MSG_LEN];
- char host[DATA_MAX_NAME_LEN];
- char plugin[DATA_MAX_NAME_LEN];
- char plugin_instance[DATA_MAX_NAME_LEN];
- char type[DATA_MAX_NAME_LEN];
- char type_instance[DATA_MAX_NAME_LEN];
- notification_meta_t *meta;
-} notification_t;
-
-struct user_data_s
-{
- void *data;
- void (*free_func) (void *);
-};
-typedef struct user_data_s user_data_t;
-
-struct plugin_ctx_s
-{
- cdtime_t interval;
-};
-typedef struct plugin_ctx_s plugin_ctx_t;
-
-/*
- * Callback types
- */
-typedef int (*plugin_init_cb) (void);
-typedef int (*plugin_read_cb) (user_data_t *);
-typedef int (*plugin_write_cb) (const data_set_t *, const value_list_t *,
- user_data_t *);
-typedef int (*plugin_flush_cb) (cdtime_t timeout, const char *identifier,
- user_data_t *);
-/* "missing" callback. Returns less than zero on failure, zero if other
- * callbacks should be called, greater than zero if no more callbacks should be
- * called. */
-typedef int (*plugin_missing_cb) (const value_list_t *, user_data_t *);
-typedef void (*plugin_log_cb) (int severity, const char *message,
- user_data_t *);
-typedef int (*plugin_shutdown_cb) (void);
-typedef int (*plugin_notification_cb) (const notification_t *,
- user_data_t *);
-
-/*
- * NAME
- * plugin_set_dir
- *
- * DESCRIPTION
- * Sets the current `plugindir'
- *
- * ARGUMENTS
- * `dir' Path to the plugin directory
- *
- * NOTES
- * If `dir' is NULL the compiled in default `PLUGINDIR' is used.
- */
-void plugin_set_dir (const char *dir);
-
-/*
- * NAME
- * plugin_load
- *
- * DESCRIPTION
- * Searches the current `plugindir' (see `plugin_set_dir') for the plugin
- * named $type and loads it. Afterwards the plugin's `module_register'
- * function is called, which then calls `plugin_register' to register callback
- * functions.
- *
- * ARGUMENTS
- * `name' Name of the plugin to load.
- * `flags' Hints on how to handle this plugin.
- *
- * RETURN VALUE
- * Returns zero upon success, a value greater than zero if no plugin was found
- * and a value below zero if an error occurs.
- *
- * NOTES
- * Re-loading an already loaded module is detected and zero is returned in
- * this case.
- */
-int plugin_load (const char *name, uint32_t flags);
-
-void plugin_init_all (void);
-void plugin_read_all (void);
-int plugin_read_all_once (void);
-void plugin_shutdown_all (void);
-
-/*
- * NAME
- * plugin_write
- *
- * DESCRIPTION
- * Calls the write function of the given plugin with the provided data set and
- * value list. It differs from `plugin_dispatch_value' in that it does not
- * update the cache, does not do threshold checking, call the chain subsystem
- * and so on. It looks up the requested plugin and invokes the function, end
- * of story.
- *
- * ARGUMENTS
- * plugin Name of the plugin. If NULL, the value is sent to all registered
- * write functions.
- * ds Pointer to the data_set_t structure. If NULL, the data set is
- * looked up according to the `type' member in the `vl' argument.
- * vl The actual value to be processed. Must not be NULL.
- *
- * RETURN VALUE
- * Returns zero upon success or non-zero if an error occurred. If `plugin' is
- * NULL and more than one plugin is called, an error is only returned if *all*
- * plugins fail.
- *
- * NOTES
- * This is the function used by the `write' built-in target. May be used by
- * other target plugins.
- */
-int plugin_write (const char *plugin,
- const data_set_t *ds, const value_list_t *vl);
-
-int plugin_flush (const char *plugin, cdtime_t timeout, const char *identifier);
-
-/*
- * The `plugin_register_*' functions are used to make `config', `init',
- * `read', `write' and `shutdown' functions known to the plugin
- * infrastructure. Also, the data-formats are made public like this.
- */
-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,
- plugin_init_cb callback);
-int plugin_register_read (const char *name,
- int (*callback) (void));
-/* "user_data" will be freed automatically, unless
- * "plugin_register_complex_read" returns an error (non-zero). */
-int plugin_register_complex_read (const char *group, const char *name,
- plugin_read_cb callback,
- const struct timespec *interval,
- user_data_t *user_data);
-int plugin_register_write (const char *name,
- plugin_write_cb callback, user_data_t *user_data);
-int plugin_register_flush (const char *name,
- plugin_flush_cb callback, user_data_t *user_data);
-int plugin_register_missing (const char *name,
- plugin_missing_cb callback, user_data_t *user_data);
-int plugin_register_shutdown (const char *name,
- plugin_shutdown_cb callback);
-int plugin_register_data_set (const data_set_t *ds);
-int plugin_register_log (const char *name,
- plugin_log_cb callback, user_data_t *user_data);
-int plugin_register_notification (const char *name,
- plugin_notification_cb callback, user_data_t *user_data);
-
-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_read_group (const char *group);
-int plugin_unregister_write (const char *name);
-int plugin_unregister_flush (const char *name);
-int plugin_unregister_missing (const char *name);
-int plugin_unregister_shutdown (const char *name);
-int plugin_unregister_data_set (const char *name);
-int plugin_unregister_log (const char *name);
-int plugin_unregister_notification (const char *name);
-
-
-/*
- * NAME
- * plugin_dispatch_values
- *
- * DESCRIPTION
- * This function is called by reading processes with the values they've
- * aquired. The function fetches the data-set definition (that has been
- * registered using `plugin_register_data_set') and calls _all_ registered
- * write-functions.
- *
- * ARGUMENTS
- * `vl' Value list of the values that have been read by a `read'
- * function.
- */
-int plugin_dispatch_values (value_list_t const *vl);
-
-/*
- * NAME
- * plugin_dispatch_multivalue
- *
- * SYNOPSIS
- * plugin_dispatch_multivalue (vl, 1,
- * "free", 42.0,
- * "used", 58.0,
- * NULL);
- *
- * DESCRIPTION
- * Takes a list of type instances and values and dispatches that in a batch,
- * making sure that all values have the same time stamp. If "store_percentage"
- * is set to true, the "type" is set to "percent" and a percentage is
- * calculated and dispatched, rather than the absolute values. Values that are
- * NaN are dispatched as NaN and will not influence the total.
- *
- * The variadic arguments is a list of type_instance / gauge pairs, that are
- * interpreted as type "char const *" and "gauge_t". The last argument must be
- * a NULL pointer to signal end-of-list.
- *
- * RETURNS
- * The number of values it failed to dispatch (zero on success).
- */
-__attribute__((sentinel))
-int plugin_dispatch_multivalue (value_list_t const *vl,
- _Bool store_percentage, ...);
-
-int plugin_dispatch_missing (const value_list_t *vl);
-
-int plugin_dispatch_notification (const notification_t *notif);
-
-void plugin_log (int level, const char *format, ...)
- __attribute__ ((format(printf,2,3)));
-
-/* These functions return the parsed severity or less than zero on failure. */
-int parse_log_severity (const char *severity);
-int parse_notif_severity (const char *severity);
-
-#define ERROR(...) plugin_log (LOG_ERR, __VA_ARGS__)
-#define WARNING(...) plugin_log (LOG_WARNING, __VA_ARGS__)
-#define NOTICE(...) plugin_log (LOG_NOTICE, __VA_ARGS__)
-#define INFO(...) plugin_log (LOG_INFO, __VA_ARGS__)
-#if COLLECT_DEBUG
-# define DEBUG(...) plugin_log (LOG_DEBUG, __VA_ARGS__)
-#else /* COLLECT_DEBUG */
-# define DEBUG(...) /* noop */
-#endif /* ! COLLECT_DEBUG */
-
-const data_set_t *plugin_get_ds (const char *name);
-
-int plugin_notification_meta_add_string (notification_t *n,
- const char *name,
- const char *value);
-int plugin_notification_meta_add_signed_int (notification_t *n,
- const char *name,
- int64_t value);
-int plugin_notification_meta_add_unsigned_int (notification_t *n,
- const char *name,
- uint64_t value);
-int plugin_notification_meta_add_double (notification_t *n,
- const char *name,
- double value);
-int plugin_notification_meta_add_boolean (notification_t *n,
- const char *name,
- _Bool value);
-
-int plugin_notification_meta_copy (notification_t *dst,
- const notification_t *src);
-
-int plugin_notification_meta_free (notification_meta_t *n);
-
-/*
- * Plugin context management.
- */
-
-void plugin_init_ctx (void);
-
-plugin_ctx_t plugin_get_ctx (void);
-plugin_ctx_t plugin_set_ctx (plugin_ctx_t ctx);
-
-/*
- * NAME
- * plugin_get_interval
- *
- * DESCRIPTION
- * This function returns the current value of the plugin's interval. The
- * return value will be strictly greater than zero in all cases. If
- * everything else fails, it will fall back to 10 seconds.
- */
-cdtime_t plugin_get_interval (void);
-
-/*
- * Context-aware thread management.
- */
-
-int plugin_thread_create (pthread_t *thread, const pthread_attr_t *attr,
- void *(*start_routine) (void *), void *arg);
-
-#endif /* PLUGIN_H */
diff --git a/src/types_list.c b/src/types_list.c
--- a/src/types_list.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/**
- * collectd - src/types_list.c
- * Copyright (C) 2007 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#include "collectd.h"
-#include "common.h"
-
-#include "plugin.h"
-#include "configfile.h"
-
-static int parse_ds (data_source_t *dsrc, char *buf, size_t buf_len)
-{
- char *dummy;
- char *saveptr;
- char *fields[8];
- int fields_num;
-
- if (buf_len < 11)
- {
- ERROR ("parse_ds: (buf_len = %zu) < 11", buf_len);
- return (-1);
- }
-
- if (buf[buf_len - 1] == ',')
- {
- buf_len--;
- buf[buf_len] = '\0';
- }
-
- dummy = buf;
- saveptr = NULL;
-
- fields_num = 0;
- while (fields_num < 8)
- {
- if ((fields[fields_num] = strtok_r (dummy, ":", &saveptr)) == NULL)
- break;
- dummy = NULL;
- fields_num++;
- }
-
- if (fields_num != 4)
- {
- ERROR ("parse_ds: (fields_num = %i) != 4", fields_num);
- return (-1);
- }
-
- sstrncpy (dsrc->name, fields[0], sizeof (dsrc->name));
-
- if (strcasecmp (fields[1], "GAUGE") == 0)
- dsrc->type = DS_TYPE_GAUGE;
- else if (strcasecmp (fields[1], "COUNTER") == 0)
- dsrc->type = DS_TYPE_COUNTER;
- else if (strcasecmp (fields[1], "DERIVE") == 0)
- dsrc->type = DS_TYPE_DERIVE;
- else if (strcasecmp (fields[1], "ABSOLUTE") == 0)
- dsrc->type = DS_TYPE_ABSOLUTE;
- else
- {
- ERROR ("(fields[1] = %s) != (GAUGE || COUNTER || DERIVE || ABSOLUTE)", fields[1]);
- return (-1);
- }
-
- if (strcasecmp (fields[2], "U") == 0)
- dsrc->min = NAN;
- else
- dsrc->min = atof (fields[2]);
-
- if (strcasecmp (fields[3], "U") == 0)
- dsrc->max = NAN;
- else
- dsrc->max = atof (fields[3]);
-
- return (0);
-} /* int parse_ds */
-
-static void parse_line (char *buf)
-{
- char *fields[64];
- size_t fields_num;
- data_set_t *ds;
- int i;
-
- fields_num = strsplit (buf, fields, 64);
- if (fields_num < 2)
- return;
-
- /* Ignore lines which begin with a hash sign. */
- if (fields[0][0] == '#')
- return;
-
- ds = (data_set_t *) malloc (sizeof (data_set_t));
- if (ds == NULL)
- return;
-
- memset (ds, '\0', sizeof (data_set_t));
-
- sstrncpy (ds->type, fields[0], sizeof (ds->type));
-
- ds->ds_num = fields_num - 1;
- ds->ds = (data_source_t *) calloc (ds->ds_num, sizeof (data_source_t));
- if (ds->ds == NULL)
- return;
-
- for (i = 0; i < ds->ds_num; i++)
- if (parse_ds (ds->ds + i, fields[i + 1], strlen (fields[i + 1])) != 0)
- {
- sfree (ds->ds);
- ERROR ("types_list: parse_line: Cannot parse data source #%i "
- "of data set %s", i, ds->type);
- return;
- }
-
- plugin_register_data_set (ds);
-
- sfree (ds->ds);
- sfree (ds);
-} /* void parse_line */
-
-static void parse_file (FILE *fh)
-{
- char buf[4096];
- size_t buf_len;
-
- while (fgets (buf, sizeof (buf), fh) != NULL)
- {
- buf_len = strlen (buf);
-
- if (buf_len >= 4095)
- {
- NOTICE ("Skipping line with more than 4095 characters.");
- do
- {
- if (fgets (buf, sizeof (buf), fh) == NULL)
- break;
- buf_len = strlen (buf);
- } while (buf_len >= 4095);
- continue;
- } /* if (buf_len >= 4095) */
-
- if ((buf_len == 0) || (buf[0] == '#'))
- continue;
-
- while ((buf_len > 0) && ((buf[buf_len - 1] == '\n')
- || (buf[buf_len - 1] == '\n')))
- buf[--buf_len] = '\0';
-
- if (buf_len == 0)
- continue;
-
- parse_line (buf);
- } /* while (fgets) */
-} /* void parse_file */
-
-int read_types_list (const char *file)
-{
- FILE *fh;
-
- if (file == NULL)
- return (-1);
-
- fh = fopen (file, "r");
- if (fh == NULL)
- {
- char errbuf[1024];
- fprintf (stderr, "Failed to open types database `%s': %s.\n",
- file, sstrerror (errno, errbuf, sizeof (errbuf)));
- ERROR ("Failed to open types database `%s': %s",
- file, sstrerror (errno, errbuf, sizeof (errbuf)));
- return (-1);
- }
-
- parse_file (fh);
-
- fclose (fh);
- fh = NULL;
-
- DEBUG ("Done parsing `%s'", file);
-
- return (0);
-} /* int read_types_list */
-
-/*
- * vim: shiftwidth=2:softtabstop=2:tabstop=8
- */
diff --git a/src/types_list.h b/src/types_list.h
--- a/src/types_list.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * collectd - src/types_list.h
- * Copyright (C) 2007 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#ifndef TYPES_LIST_H
-#define TYPES_LIST_H 1
-
-int read_types_list (const char *file);
-
-#endif /* TYPES_LIST_H */
diff --git a/src/utils_avltree.c b/src/utils_avltree.c
--- a/src/utils_avltree.c
+++ /dev/null
@@ -1,730 +0,0 @@
-/**
- * collectd - src/utils_avltree.c
- * Copyright (C) 2006,2007 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-#include "utils_avltree.h"
-
-#define BALANCE(n) ((((n)->left == NULL) ? 0 : (n)->left->height) \
- - (((n)->right == NULL) ? 0 : (n)->right->height))
-
-/*
- * private data types
- */
-struct c_avl_node_s
-{
- void *key;
- void *value;
-
- int height;
- struct c_avl_node_s *left;
- struct c_avl_node_s *right;
- struct c_avl_node_s *parent;
-};
-typedef struct c_avl_node_s c_avl_node_t;
-
-struct c_avl_tree_s
-{
- c_avl_node_t *root;
- int (*compare) (const void *, const void *);
- int size;
-};
-
-struct c_avl_iterator_s
-{
- c_avl_tree_t *tree;
- c_avl_node_t *node;
-};
-
-/*
- * private functions
- */
-#if 0
-static void verify_tree (c_avl_node_t *n)
-{
- if (n == NULL)
- return;
-
- verify_tree (n->left);
- verify_tree (n->right);
-
- assert ((BALANCE (n) >= -1) && (BALANCE (n) <= 1));
- assert ((n->parent == NULL) || (n->parent->right == n) || (n->parent->left == n));
-} /* void verify_tree */
-#else
-# define verify_tree(n) /**/
-#endif
-
-static void free_node (c_avl_node_t *n)
-{
- if (n == NULL)
- return;
-
- if (n->left != NULL)
- free_node (n->left);
- if (n->right != NULL)
- free_node (n->right);
-
- free (n);
-}
-
-static int calc_height (c_avl_node_t *n)
-{
- int height_left;
- int height_right;
-
- if (n == NULL)
- return (0);
-
- height_left = (n->left == NULL) ? 0 : n->left->height;
- height_right = (n->right == NULL) ? 0 : n->right->height;
-
- return (((height_left > height_right)
- ? height_left
- : height_right) + 1);
-} /* int calc_height */
-
-static c_avl_node_t *search (c_avl_tree_t *t, const void *key)
-{
- c_avl_node_t *n;
- int cmp;
-
- n = t->root;
- while (n != NULL)
- {
- cmp = t->compare (key, n->key);
- if (cmp == 0)
- return (n);
- else if (cmp < 0)
- n = n->left;
- else
- n = n->right;
- }
-
- return (NULL);
-}
-
-/* (x) (y)
- * / \ / \
- * (y) /\ /\ (x)
- * / \ /_c\ ==> / a\ / \
- * /\ /\ /____\/\ /\
- * / a\ /_b\ /_b\ /_c\
- * /____\
- */
-static c_avl_node_t *rotate_right (c_avl_tree_t *t, c_avl_node_t *x)
-{
- c_avl_node_t *p;
- c_avl_node_t *y;
- c_avl_node_t *b;
-
- p = x->parent;
- y = x->left;
- b = y->right;
-
- x->left = b;
- if (b != NULL)
- b->parent = x;
-
- x->parent = y;
- y->right = x;
-
- y->parent = p;
- assert ((p == NULL) || (p->left == x) || (p->right == x));
- if (p == NULL)
- t->root = y;
- else if (p->left == x)
- p->left = y;
- else
- p->right = y;
-
- x->height = calc_height (x);
- y->height = calc_height (y);
-
- return (y);
-} /* void rotate_left */
-
-/*
- * (x) (y)
- * / \ / \
- * /\ (y) (x) /\
- * /_a\ / \ ==> / \ / c\
- * /\ /\ /\ /\/____\
- * /_b\ / c\ /_a\ /_b\
- * /____\
- */
-static c_avl_node_t *rotate_left (c_avl_tree_t *t, c_avl_node_t *x)
-{
- c_avl_node_t *p;
- c_avl_node_t *y;
- c_avl_node_t *b;
-
- p = x->parent;
- y = x->right;
- b = y->left;
-
- x->right = b;
- if (b != NULL)
- b->parent = x;
-
- x->parent = y;
- y->left = x;
-
- y->parent = p;
- assert ((p == NULL) || (p->left == x) || (p->right == x));
- if (p == NULL)
- t->root = y;
- else if (p->left == x)
- p->left = y;
- else
- p->right = y;
-
- x->height = calc_height (x);
- y->height = calc_height (y);
-
- return (y);
-} /* void rotate_left */
-
-static c_avl_node_t *rotate_left_right (c_avl_tree_t *t, c_avl_node_t *x)
-{
- rotate_left (t, x->left);
- return (rotate_right (t, x));
-} /* void rotate_left_right */
-
-static c_avl_node_t *rotate_right_left (c_avl_tree_t *t, c_avl_node_t *x)
-{
- rotate_right (t, x->right);
- return (rotate_left (t, x));
-} /* void rotate_right_left */
-
-static void rebalance (c_avl_tree_t *t, c_avl_node_t *n)
-{
- int b_top;
- int b_bottom;
-
- while (n != NULL)
- {
- b_top = BALANCE (n);
- assert ((b_top >= -2) && (b_top <= 2));
-
- if (b_top == -2)
- {
- assert (n->right != NULL);
- b_bottom = BALANCE (n->right);
- assert ((b_bottom >= -1) || (b_bottom <= 1));
- if (b_bottom == 1)
- n = rotate_right_left (t, n);
- else
- n = rotate_left (t, n);
- }
- else if (b_top == 2)
- {
- assert (n->left != NULL);
- b_bottom = BALANCE (n->left);
- assert ((b_bottom >= -1) || (b_bottom <= 1));
- if (b_bottom == -1)
- n = rotate_left_right (t, n);
- else
- n = rotate_right (t, n);
- }
- else
- {
- int height = calc_height (n);
- if (height == n->height)
- break;
- n->height = height;
- }
-
- assert (n->height == calc_height (n));
-
- n = n->parent;
- } /* while (n != NULL) */
-} /* void rebalance */
-
-static c_avl_node_t *c_avl_node_next (c_avl_node_t *n)
-{
- c_avl_node_t *r; /* return node */
-
- if (n == NULL)
- {
- return (NULL);
- }
-
- /* If we can't descent any further, we have to backtrack to the first
- * parent that's bigger than we, i. e. who's _left_ child we are. */
- if (n->right == NULL)
- {
- r = n->parent;
- while ((r != NULL) && (r->parent != NULL))
- {
- if (r->left == n)
- break;
- n = r;
- r = n->parent;
- }
-
- /* n->right == NULL && r == NULL => t is root and has no next
- * r->left != n => r->right = n => r->parent == NULL */
- if ((r == NULL) || (r->left != n))
- {
- assert ((r == NULL) || (r->parent == NULL));
- return (NULL);
- }
- else
- {
- assert (r->left == n);
- return (r);
- }
- }
- else
- {
- r = n->right;
- while (r->left != NULL)
- r = r->left;
- }
-
- return (r);
-} /* c_avl_node_t *c_avl_node_next */
-
-static c_avl_node_t *c_avl_node_prev (c_avl_node_t *n)
-{
- c_avl_node_t *r; /* return node */
-
- if (n == NULL)
- {
- return (NULL);
- }
-
- /* If we can't descent any further, we have to backtrack to the first
- * parent that's smaller than we, i. e. who's _right_ child we are. */
- if (n->left == NULL)
- {
- r = n->parent;
- while ((r != NULL) && (r->parent != NULL))
- {
- if (r->right == n)
- break;
- n = r;
- r = n->parent;
- }
-
- /* n->left == NULL && r == NULL => t is root and has no next
- * r->right != n => r->left = n => r->parent == NULL */
- if ((r == NULL) || (r->right != n))
- {
- assert ((r == NULL) || (r->parent == NULL));
- return (NULL);
- }
- else
- {
- assert (r->right == n);
- return (r);
- }
- }
- else
- {
- r = n->left;
- while (r->right != NULL)
- r = r->right;
- }
-
- return (r);
-} /* c_avl_node_t *c_avl_node_prev */
-
-static int _remove (c_avl_tree_t *t, c_avl_node_t *n)
-{
- assert ((t != NULL) && (n != NULL));
-
- if ((n->left != NULL) && (n->right != NULL))
- {
- c_avl_node_t *r; /* replacement node */
- if (BALANCE (n) > 0) /* left subtree is higher */
- {
- assert (n->left != NULL);
- r = c_avl_node_prev (n);
-
- }
- else /* right subtree is higher */
- {
- assert (n->right != NULL);
- r = c_avl_node_next (n);
- }
-
- assert ((r->left == NULL) || (r->right == NULL));
-
- /* copy content */
- n->key = r->key;
- n->value = r->value;
-
- n = r;
- }
-
- assert ((n->left == NULL) || (n->right == NULL));
-
- if ((n->left == NULL) && (n->right == NULL))
- {
- /* Deleting a leave is easy */
- if (n->parent == NULL)
- {
- assert (t->root == n);
- t->root = NULL;
- }
- else
- {
- assert ((n->parent->left == n)
- || (n->parent->right == n));
- if (n->parent->left == n)
- n->parent->left = NULL;
- else
- n->parent->right = NULL;
-
- rebalance (t, n->parent);
- }
-
- free_node (n);
- }
- else if (n->left == NULL)
- {
- assert (BALANCE (n) == -1);
- assert ((n->parent == NULL) || (n->parent->left == n) || (n->parent->right == n));
- if (n->parent == NULL)
- {
- assert (t->root == n);
- t->root = n->right;
- }
- else if (n->parent->left == n)
- {
- n->parent->left = n->right;
- }
- else
- {
- n->parent->right = n->right;
- }
- n->right->parent = n->parent;
-
- if (n->parent != NULL)
- rebalance (t, n->parent);
-
- n->right = NULL;
- free_node (n);
- }
- else if (n->right == NULL)
- {
- assert (BALANCE (n) == 1);
- assert ((n->parent == NULL) || (n->parent->left == n) || (n->parent->right == n));
- if (n->parent == NULL)
- {
- assert (t->root == n);
- t->root = n->left;
- }
- else if (n->parent->left == n)
- {
- n->parent->left = n->left;
- }
- else
- {
- n->parent->right = n->left;
- }
- n->left->parent = n->parent;
-
- if (n->parent != NULL)
- rebalance (t, n->parent);
-
- n->left = NULL;
- free_node (n);
- }
- else
- {
- assert (0);
- }
-
- return (0);
-} /* void *_remove */
-
-/*
- * public functions
- */
-c_avl_tree_t *c_avl_create (int (*compare) (const void *, const void *))
-{
- c_avl_tree_t *t;
-
- if (compare == NULL)
- return (NULL);
-
- if ((t = (c_avl_tree_t *) malloc (sizeof (c_avl_tree_t))) == NULL)
- return (NULL);
-
- t->root = NULL;
- t->compare = compare;
- t->size = 0;
-
- return (t);
-}
-
-void c_avl_destroy (c_avl_tree_t *t)
-{
- if (t == NULL)
- return;
- free_node (t->root);
- free (t);
-}
-
-int c_avl_insert (c_avl_tree_t *t, void *key, void *value)
-{
- c_avl_node_t *new;
- c_avl_node_t *nptr;
- int cmp;
-
- if ((new = (c_avl_node_t *) malloc (sizeof (c_avl_node_t))) == NULL)
- return (-1);
-
- new->key = key;
- new->value = value;
- new->height = 1;
- new->left = NULL;
- new->right = NULL;
-
- if (t->root == NULL)
- {
- new->parent = NULL;
- t->root = new;
- t->size = 1;
- return (0);
- }
-
- nptr = t->root;
- while (42)
- {
- cmp = t->compare (nptr->key, new->key);
- if (cmp == 0)
- {
- free_node (new);
- return (1);
- }
- else if (cmp < 0)
- {
- /* nptr < new */
- if (nptr->right == NULL)
- {
- nptr->right = new;
- new->parent = nptr;
- rebalance (t, nptr);
- break;
- }
- else
- {
- nptr = nptr->right;
- }
- }
- else /* if (cmp > 0) */
- {
- /* nptr > new */
- if (nptr->left == NULL)
- {
- nptr->left = new;
- new->parent = nptr;
- rebalance (t, nptr);
- break;
- }
- else
- {
- nptr = nptr->left;
- }
- }
- } /* while (42) */
-
- verify_tree (t->root);
- ++t->size;
- return (0);
-} /* int c_avl_insert */
-
-int c_avl_remove (c_avl_tree_t *t, const void *key, void **rkey, void **rvalue)
-{
- c_avl_node_t *n;
- int status;
-
- assert (t != NULL);
-
- n = search (t, key);
- if (n == NULL)
- return (-1);
-
- if (rkey != NULL)
- *rkey = n->key;
- if (rvalue != NULL)
- *rvalue = n->value;
-
- status = _remove (t, n);
- verify_tree (t->root);
- --t->size;
- return (status);
-} /* void *c_avl_remove */
-
-int c_avl_get (c_avl_tree_t *t, const void *key, void **value)
-{
- c_avl_node_t *n;
-
- assert (t != NULL);
-
- n = search (t, key);
- if (n == NULL)
- return (-1);
-
- if (value != NULL)
- *value = n->value;
-
- return (0);
-}
-
-int c_avl_pick (c_avl_tree_t *t, void **key, void **value)
-{
- c_avl_node_t *n;
- c_avl_node_t *p;
-
- if ((key == NULL) || (value == NULL))
- return (-1);
- if (t->root == NULL)
- return (-1);
-
- n = t->root;
- while ((n->left != NULL) || (n->right != NULL))
- {
- int height_left = (n->left == NULL) ? 0 : n->left->height;
- int height_right = (n->right == NULL) ? 0 : n->right->height;
-
- if (height_left > height_right)
- n = n->left;
- else
- n = n->right;
- }
-
- p = n->parent;
- if (p == NULL)
- t->root = NULL;
- else if (p->left == n)
- p->left = NULL;
- else
- p->right = NULL;
-
- *key = n->key;
- *value = n->value;
-
- free_node (n);
- rebalance (t, p);
-
- return (0);
-} /* int c_avl_pick */
-
-c_avl_iterator_t *c_avl_get_iterator (c_avl_tree_t *t)
-{
- c_avl_iterator_t *iter;
-
- if (t == NULL)
- return (NULL);
-
- iter = (c_avl_iterator_t *) malloc (sizeof (c_avl_iterator_t));
- if (iter == NULL)
- return (NULL);
- memset (iter, '\0', sizeof (c_avl_iterator_t));
- iter->tree = t;
-
- return (iter);
-} /* c_avl_iterator_t *c_avl_get_iterator */
-
-int c_avl_iterator_next (c_avl_iterator_t *iter, void **key, void **value)
-{
- c_avl_node_t *n;
-
- if ((iter == NULL) || (key == NULL) || (value == NULL))
- return (-1);
-
- if (iter->node == NULL)
- {
- for (n = iter->tree->root; n != NULL; n = n->left)
- if (n->left == NULL)
- break;
- iter->node = n;
- }
- else
- {
- n = c_avl_node_next (iter->node);
- }
-
- if (n == NULL)
- return (-1);
-
- iter->node = n;
- *key = n->key;
- *value = n->value;
-
- return (0);
-} /* int c_avl_iterator_next */
-
-int c_avl_iterator_prev (c_avl_iterator_t *iter, void **key, void **value)
-{
- c_avl_node_t *n;
-
- if ((iter == NULL) || (key == NULL) || (value == NULL))
- return (-1);
-
- if (iter->node == NULL)
- {
- for (n = iter->tree->root; n != NULL; n = n->left)
- if (n->right == NULL)
- break;
- iter->node = n;
- }
- else
- {
- n = c_avl_node_prev (iter->node);
- }
-
- if (n == NULL)
- return (-1);
-
- iter->node = n;
- *key = n->key;
- *value = n->value;
-
- return (0);
-} /* int c_avl_iterator_prev */
-
-void c_avl_iterator_destroy (c_avl_iterator_t *iter)
-{
- free (iter);
-}
-
-int c_avl_size (c_avl_tree_t *t)
-{
- if (t == NULL)
- return (0);
- return (t->size);
-}
diff --git a/src/utils_avltree.h b/src/utils_avltree.h
--- a/src/utils_avltree.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/**
- * collectd - src/utils_avltree.h
- * Copyright (C) 2006,2007 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#ifndef UTILS_AVLTREE_H
-#define UTILS_AVLTREE_H 1
-
-struct c_avl_tree_s;
-typedef struct c_avl_tree_s c_avl_tree_t;
-
-struct c_avl_iterator_s;
-typedef struct c_avl_iterator_s c_avl_iterator_t;
-
-/*
- * NAME
- * c_avl_create
- *
- * DESCRIPTION
- * Allocates a new AVL-tree.
- *
- * PARAMETERS
- * `compare' The function-pointer `compare' is used to compare two keys. It
- * has to return less than zero if it's first argument is smaller
- * then the second argument, more than zero if the first argument
- * is bigger than the second argument and zero if they are equal.
- * If your keys are char-pointers, you can use the `strcmp'
- * function from the libc here.
- *
- * RETURN VALUE
- * A c_avl_tree_t-pointer upon success or NULL upon failure.
- */
-c_avl_tree_t *c_avl_create (int (*compare) (const void *, const void *));
-
-
-/*
- * NAME
- * c_avl_destroy
- *
- * DESCRIPTION
- * Deallocates an AVL-tree. Stored value- and key-pointer are lost, but of
- * course not freed.
- */
-void c_avl_destroy (c_avl_tree_t *t);
-
-/*
- * NAME
- * c_avl_insert
- *
- * DESCRIPTION
- * Stores the key-value-pair in the AVL-tree pointed to by `t'.
- *
- * PARAMETERS
- * `t' AVL-tree to store the data in.
- * `key' Key used to store the value under. This is used to get back to
- * the value again. The pointer is stored in an internal structure
- * and _not_ copied. So the memory pointed to may _not_ be freed
- * before this entry is removed. You can use the `rkey' argument
- * to `avl_remove' to get the original pointer back and free it.
- * `value' Value to be stored.
- *
- * RETURN VALUE
- * Zero upon success, non-zero otherwise. It's less than zero if an error
- * occurred or greater than zero if the key is already stored in the tree.
- */
-int c_avl_insert (c_avl_tree_t *t, void *key, void *value);
-
-/*
- * NAME
- * c_avl_remove
- *
- * DESCRIPTION
- * Removes a key-value-pair from the tree t. The stored key and value may be
- * returned in `rkey' and `rvalue'.
- *
- * PARAMETERS
- * `t' AVL-tree to remove key-value-pair from.
- * `key' Key to identify the entry.
- * `rkey' Pointer to a pointer in which to store the key. May be NULL.
- * Since the `key' pointer is not copied when creating an entry,
- * the pointer may not be available anymore from outside the tree.
- * You can use this argument to get the actual pointer back and
- * free the memory pointed to by it.
- * `rvalue' Pointer to a pointer in which to store the value. May be NULL.
- *
- * RETURN VALUE
- * Zero upon success or non-zero if the key isn't found in the tree.
- */
-int c_avl_remove (c_avl_tree_t *t, const void *key, void **rkey, void **rvalue);
-
-/*
- * NAME
- * c_avl_get
- *
- * DESCRIPTION
- * Retrieve the `value' belonging to `key'.
- *
- * PARAMETERS
- * `t' AVL-tree to get the value from.
- * `key' Key to identify the entry.
- * `value' Pointer to a pointer in which to store the value. May be NULL.
- *
- * RETURN VALUE
- * Zero upon success or non-zero if the key isn't found in the tree.
- */
-int c_avl_get (c_avl_tree_t *t, const void *key, void **value);
-
-/*
- * NAME
- * c_avl_pick
- *
- * DESCRIPTION
- * Remove a (pseudo-)random element from the tree and return it's `key' and
- * `value'. Entries are not returned in any particular order. This function
- * is intended for cache-flushes that don't care about the order but simply
- * want to remove all elements, one at a time.
- *
- * PARAMETERS
- * `t' AVL-tree to get the value from.
- * `key' Pointer to a pointer in which to store the key.
- * `value' Pointer to a pointer in which to store the value.
- *
- * RETURN VALUE
- * Zero upon success or non-zero if the tree is empty or key or value is
- * NULL.
- */
-int c_avl_pick (c_avl_tree_t *t, void **key, void **value);
-
-c_avl_iterator_t *c_avl_get_iterator (c_avl_tree_t *t);
-int c_avl_iterator_next (c_avl_iterator_t *iter, void **key, void **value);
-int c_avl_iterator_prev (c_avl_iterator_t *iter, void **key, void **value);
-void c_avl_iterator_destroy (c_avl_iterator_t *iter);
-
-/*
- * NAME
- * c_avl_size
- *
- * DESCRIPTION
- * Return the size (number of nodes) of the specified tree.
- *
- * PARAMETERS
- * `t' AVL-tree to get the size of.
- *
- * RETURN VALUE
- * Number of nodes in the tree, 0 if the tree is empty or NULL.
- */
-int c_avl_size (c_avl_tree_t *t);
-
-#endif /* UTILS_AVLTREE_H */
diff --git a/src/utils_cache.c b/src/utils_cache.c
--- a/src/utils_cache.c
+++ /dev/null
@@ -1,988 +0,0 @@
-/**
- * collectd - src/utils_cache.c
- * Copyright (C) 2007-2010 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#include "collectd.h"
-#include "common.h"
-#include "plugin.h"
-#include "utils_avltree.h"
-#include "utils_cache.h"
-#include "meta_data.h"
-
-#include <assert.h>
-#include <pthread.h>
-
-typedef struct cache_entry_s
-{
- char name[6 * DATA_MAX_NAME_LEN];
- int values_num;
- gauge_t *values_gauge;
- value_t *values_raw;
- /* Time contained in the package
- * (for calculating rates) */
- cdtime_t last_time;
- /* Time according to the local clock
- * (for purging old entries) */
- cdtime_t last_update;
- /* Interval in which the data is collected
- * (for purding old entries) */
- cdtime_t interval;
- int state;
- int hits;
-
- /*
- * +-----+-----+-----+-----+-----+-----+-----+-----+-----+----
- * ! 0 ! 1 ! 2 ! 3 ! 4 ! 5 ! 6 ! 7 ! 8 ! ...
- * +-----+-----+-----+-----+-----+-----+-----+-----+-----+----
- * ! ds0 ! ds1 ! ds2 ! ds0 ! ds1 ! ds2 ! ds0 ! ds1 ! ds2 ! ...
- * +-----+-----+-----+-----+-----+-----+-----+-----+-----+----
- * ! t = 0 ! t = 1 ! t = 2 ! ...
- * +-----------------+-----------------+-----------------+----
- */
- gauge_t *history;
- size_t history_index; /* points to the next position to write to. */
- size_t history_length;
-
- meta_data_t *meta;
-} cache_entry_t;
-
-static c_avl_tree_t *cache_tree = NULL;
-static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
-
-static int cache_compare (const cache_entry_t *a, const cache_entry_t *b)
-{
-#if COLLECT_DEBUG
- assert ((a != NULL) && (b != NULL));
-#endif
- return (strcmp (a->name, b->name));
-} /* int cache_compare */
-
-static cache_entry_t *cache_alloc (int values_num)
-{
- cache_entry_t *ce;
-
- ce = (cache_entry_t *) malloc (sizeof (cache_entry_t));
- if (ce == NULL)
- {
- ERROR ("utils_cache: cache_alloc: malloc failed.");
- return (NULL);
- }
- memset (ce, '\0', sizeof (cache_entry_t));
- ce->values_num = values_num;
-
- ce->values_gauge = calloc (values_num, sizeof (*ce->values_gauge));
- ce->values_raw = calloc (values_num, sizeof (*ce->values_raw));
- if ((ce->values_gauge == NULL) || (ce->values_raw == NULL))
- {
- sfree (ce->values_gauge);
- sfree (ce->values_raw);
- sfree (ce);
- ERROR ("utils_cache: cache_alloc: calloc failed.");
- return (NULL);
- }
-
- ce->history = NULL;
- ce->history_length = 0;
- ce->meta = NULL;
-
- return (ce);
-} /* cache_entry_t *cache_alloc */
-
-static void cache_free (cache_entry_t *ce)
-{
- if (ce == NULL)
- return;
-
- sfree (ce->values_gauge);
- sfree (ce->values_raw);
- sfree (ce->history);
- if (ce->meta != NULL)
- {
- meta_data_destroy (ce->meta);
- ce->meta = NULL;
- }
- sfree (ce);
-} /* void cache_free */
-
-static void uc_check_range (const data_set_t *ds, cache_entry_t *ce)
-{
- int i;
-
- for (i = 0; i < ds->ds_num; i++)
- {
- if (isnan (ce->values_gauge[i]))
- continue;
- else if (ce->values_gauge[i] < ds->ds[i].min)
- ce->values_gauge[i] = NAN;
- else if (ce->values_gauge[i] > ds->ds[i].max)
- ce->values_gauge[i] = NAN;
- }
-} /* void uc_check_range */
-
-static int uc_insert (const data_set_t *ds, const value_list_t *vl,
- const char *key)
-{
- int i;
- char *key_copy;
- cache_entry_t *ce;
-
- /* `cache_lock' has been locked by `uc_update' */
-
- key_copy = strdup (key);
- if (key_copy == NULL)
- {
- ERROR ("uc_insert: strdup failed.");
- return (-1);
- }
-
- ce = cache_alloc (ds->ds_num);
- if (ce == NULL)
- {
- sfree (key_copy);
- ERROR ("uc_insert: cache_alloc (%i) failed.", ds->ds_num);
- return (-1);
- }
-
- sstrncpy (ce->name, key, sizeof (ce->name));
-
- for (i = 0; i < ds->ds_num; i++)
- {
- switch (ds->ds[i].type)
- {
- case DS_TYPE_COUNTER:
- ce->values_gauge[i] = NAN;
- ce->values_raw[i].counter = vl->values[i].counter;
- break;
-
- case DS_TYPE_GAUGE:
- ce->values_gauge[i] = vl->values[i].gauge;
- ce->values_raw[i].gauge = vl->values[i].gauge;
- break;
-
- case DS_TYPE_DERIVE:
- ce->values_gauge[i] = NAN;
- ce->values_raw[i].derive = vl->values[i].derive;
- break;
-
- case DS_TYPE_ABSOLUTE:
- ce->values_gauge[i] = NAN;
- if (vl->interval > 0)
- ce->values_gauge[i] = ((double) vl->values[i].absolute)
- / CDTIME_T_TO_DOUBLE (vl->interval);
- ce->values_raw[i].absolute = vl->values[i].absolute;
- break;
-
- default:
- /* This shouldn't happen. */
- ERROR ("uc_insert: Don't know how to handle data source type %i.",
- ds->ds[i].type);
- return (-1);
- } /* switch (ds->ds[i].type) */
- } /* for (i) */
-
- /* Prune invalid gauge data */
- uc_check_range (ds, ce);
-
- ce->last_time = vl->time;
- ce->last_update = cdtime ();
- ce->interval = vl->interval;
- ce->state = STATE_OKAY;
-
- if (c_avl_insert (cache_tree, key_copy, ce) != 0)
- {
- sfree (key_copy);
- ERROR ("uc_insert: c_avl_insert failed.");
- return (-1);
- }
-
- DEBUG ("uc_insert: Added %s to the cache.", key);
- return (0);
-} /* int uc_insert */
-
-int uc_init (void)
-{
- if (cache_tree == NULL)
- cache_tree = c_avl_create ((int (*) (const void *, const void *))
- cache_compare);
-
- return (0);
-} /* int uc_init */
-
-int uc_check_timeout (void)
-{
- cdtime_t now;
- cache_entry_t *ce;
-
- char **keys = NULL;
- cdtime_t *keys_time = NULL;
- cdtime_t *keys_interval = NULL;
- int keys_len = 0;
-
- char *key;
- c_avl_iterator_t *iter;
-
- int status;
- int i;
-
- pthread_mutex_lock (&cache_lock);
-
- now = cdtime ();
-
- /* Build a list of entries to be flushed */
- iter = c_avl_get_iterator (cache_tree);
- while (c_avl_iterator_next (iter, (void *) &key, (void *) &ce) == 0)
- {
- char **tmp;
- cdtime_t *tmp_time;
-
- /* If the entry is fresh enough, continue. */
- if ((now - ce->last_update) < (ce->interval * timeout_g))
- continue;
-
- /* If entry has not been updated, add to `keys' array */
- tmp = (char **) realloc ((void *) keys,
- (keys_len + 1) * sizeof (char *));
- if (tmp == NULL)
- {
- ERROR ("uc_check_timeout: realloc failed.");
- continue;
- }
- keys = tmp;
-
- tmp_time = realloc (keys_time, (keys_len + 1) * sizeof (*keys_time));
- if (tmp_time == NULL)
- {
- ERROR ("uc_check_timeout: realloc failed.");
- continue;
- }
- keys_time = tmp_time;
-
- tmp_time = realloc (keys_interval, (keys_len + 1) * sizeof (*keys_interval));
- if (tmp_time == NULL)
- {
- ERROR ("uc_check_timeout: realloc failed.");
- continue;
- }
- keys_interval = tmp_time;
-
- keys[keys_len] = strdup (key);
- if (keys[keys_len] == NULL)
- {
- ERROR ("uc_check_timeout: strdup failed.");
- continue;
- }
- keys_time[keys_len] = ce->last_time;
- keys_interval[keys_len] = ce->interval;
-
- keys_len++;
- } /* while (c_avl_iterator_next) */
-
- c_avl_iterator_destroy (iter);
- pthread_mutex_unlock (&cache_lock);
-
- if (keys_len == 0)
- return (0);
-
- /* Call the "missing" callback for each value. Do this before removing the
- * value from the cache, so that callbacks can still access the data stored,
- * including plugin specific meta data, rates, history, …. This must be done
- * without holding the lock, otherwise we will run into a deadlock if a
- * plugin calls the cache interface. */
- for (i = 0; i < keys_len; i++)
- {
- value_list_t vl = VALUE_LIST_INIT;
-
- vl.values = NULL;
- vl.values_len = 0;
- vl.meta = NULL;
-
- status = parse_identifier_vl (keys[i], &vl);
- if (status != 0)
- {
- ERROR ("uc_check_timeout: parse_identifier_vl (\"%s\") failed.", keys[i]);
- cache_free (ce);
- continue;
- }
-
- vl.time = keys_time[i];
- vl.interval = keys_interval[i];
-
- plugin_dispatch_missing (&vl);
- } /* for (i = 0; i < keys_len; i++) */
-
- /* Now actually remove all the values from the cache. We don't re-evaluate
- * the timestamp again, so in theory it is possible we remove a value after
- * it is updated here. */
- pthread_mutex_lock (&cache_lock);
- for (i = 0; i < keys_len; i++)
- {
- key = NULL;
- ce = NULL;
-
- status = c_avl_remove (cache_tree, keys[i],
- (void *) &key, (void *) &ce);
- if (status != 0)
- {
- ERROR ("uc_check_timeout: c_avl_remove (\"%s\") failed.", keys[i]);
- sfree (keys[i]);
- continue;
- }
-
- sfree (keys[i]);
- sfree (key);
- cache_free (ce);
- } /* for (i = 0; i < keys_len; i++) */
- pthread_mutex_unlock (&cache_lock);
-
- sfree (keys);
- sfree (keys_time);
- sfree (keys_interval);
-
- return (0);
-} /* int uc_check_timeout */
-
-int uc_update (const data_set_t *ds, const value_list_t *vl)
-{
- char name[6 * DATA_MAX_NAME_LEN];
- cache_entry_t *ce = NULL;
- int status;
- int i;
-
- if (FORMAT_VL (name, sizeof (name), vl) != 0)
- {
- ERROR ("uc_update: FORMAT_VL failed.");
- return (-1);
- }
-
- pthread_mutex_lock (&cache_lock);
-
- status = c_avl_get (cache_tree, name, (void *) &ce);
- if (status != 0) /* entry does not yet exist */
- {
- status = uc_insert (ds, vl, name);
- pthread_mutex_unlock (&cache_lock);
- return (status);
- }
-
- assert (ce != NULL);
- assert (ce->values_num == ds->ds_num);
-
- if (ce->last_time >= vl->time)
- {
- pthread_mutex_unlock (&cache_lock);
- NOTICE ("uc_update: Value too old: name = %s; value time = %.3f; "
- "last cache update = %.3f;",
- name,
- CDTIME_T_TO_DOUBLE (vl->time),
- CDTIME_T_TO_DOUBLE (ce->last_time));
- return (-1);
- }
-
- for (i = 0; i < ds->ds_num; i++)
- {
- switch (ds->ds[i].type)
- {
- case DS_TYPE_COUNTER:
- {
- counter_t diff;
-
- /* check if the counter has wrapped around */
- if (vl->values[i].counter < ce->values_raw[i].counter)
- {
- if (ce->values_raw[i].counter <= 4294967295U)
- diff = (4294967295U - ce->values_raw[i].counter)
- + vl->values[i].counter;
- else
- diff = (18446744073709551615ULL - ce->values_raw[i].counter)
- + vl->values[i].counter;
- }
- else /* counter has NOT wrapped around */
- {
- diff = vl->values[i].counter - ce->values_raw[i].counter;
- }
-
- ce->values_gauge[i] = ((double) diff)
- / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
- ce->values_raw[i].counter = vl->values[i].counter;
- }
- break;
-
- case DS_TYPE_GAUGE:
- ce->values_raw[i].gauge = vl->values[i].gauge;
- ce->values_gauge[i] = vl->values[i].gauge;
- break;
-
- case DS_TYPE_DERIVE:
- {
- derive_t diff;
-
- diff = vl->values[i].derive - ce->values_raw[i].derive;
-
- ce->values_gauge[i] = ((double) diff)
- / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
- ce->values_raw[i].derive = vl->values[i].derive;
- }
- break;
-
- case DS_TYPE_ABSOLUTE:
- ce->values_gauge[i] = ((double) vl->values[i].absolute)
- / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
- ce->values_raw[i].absolute = vl->values[i].absolute;
- break;
-
- default:
- /* This shouldn't happen. */
- pthread_mutex_unlock (&cache_lock);
- ERROR ("uc_update: Don't know how to handle data source type %i.",
- ds->ds[i].type);
- return (-1);
- } /* switch (ds->ds[i].type) */
-
- DEBUG ("uc_update: %s: ds[%i] = %lf", name, i, ce->values_gauge[i]);
- } /* for (i) */
-
- /* Update the history if it exists. */
- if (ce->history != NULL)
- {
- assert (ce->history_index < ce->history_length);
- for (i = 0; i < ce->values_num; i++)
- {
- size_t hist_idx = (ce->values_num * ce->history_index) + i;
- ce->history[hist_idx] = ce->values_gauge[i];
- }
-
- assert (ce->history_length > 0);
- ce->history_index = (ce->history_index + 1) % ce->history_length;
- }
-
- /* Prune invalid gauge data */
- uc_check_range (ds, ce);
-
- ce->last_time = vl->time;
- ce->last_update = cdtime ();
- ce->interval = vl->interval;
-
- pthread_mutex_unlock (&cache_lock);
-
- return (0);
-} /* int uc_update */
-
-int uc_get_rate_by_name (const char *name, gauge_t **ret_values, size_t *ret_values_num)
-{
- gauge_t *ret = NULL;
- size_t ret_num = 0;
- cache_entry_t *ce = NULL;
- int status = 0;
-
- pthread_mutex_lock (&cache_lock);
-
- if (c_avl_get (cache_tree, name, (void *) &ce) == 0)
- {
- assert (ce != NULL);
-
- /* remove missing values from getval */
- if (ce->state == STATE_MISSING)
- {
- status = -1;
- }
- else
- {
- ret_num = ce->values_num;
- ret = (gauge_t *) malloc (ret_num * sizeof (gauge_t));
- if (ret == NULL)
- {
- ERROR ("utils_cache: uc_get_rate_by_name: malloc failed.");
- status = -1;
- }
- else
- {
- memcpy (ret, ce->values_gauge, ret_num * sizeof (gauge_t));
- }
- }
- }
- else
- {
- DEBUG ("utils_cache: uc_get_rate_by_name: No such value: %s", name);
- status = -1;
- }
-
- pthread_mutex_unlock (&cache_lock);
-
- if (status == 0)
- {
- *ret_values = ret;
- *ret_values_num = ret_num;
- }
-
- return (status);
-} /* gauge_t *uc_get_rate_by_name */
-
-gauge_t *uc_get_rate (const data_set_t *ds, const value_list_t *vl)
-{
- char name[6 * DATA_MAX_NAME_LEN];
- gauge_t *ret = NULL;
- size_t ret_num = 0;
- int status;
-
- if (FORMAT_VL (name, sizeof (name), vl) != 0)
- {
- ERROR ("utils_cache: uc_get_rate: FORMAT_VL failed.");
- return (NULL);
- }
-
- status = uc_get_rate_by_name (name, &ret, &ret_num);
- if (status != 0)
- return (NULL);
-
- /* This is important - the caller has no other way of knowing how many
- * values are returned. */
- if (ret_num != (size_t) ds->ds_num)
- {
- ERROR ("utils_cache: uc_get_rate: ds[%s] has %i values, "
- "but uc_get_rate_by_name returned %zu.",
- ds->type, ds->ds_num, ret_num);
- sfree (ret);
- return (NULL);
- }
-
- return (ret);
-} /* gauge_t *uc_get_rate */
-
-size_t uc_get_size() {
- size_t size_arrays = 0;
-
- pthread_mutex_lock (&cache_lock);
- size_arrays = (size_t) c_avl_size (cache_tree);
- pthread_mutex_unlock (&cache_lock);
-
- return (size_arrays);
-}
-
-int uc_get_names (char ***ret_names, cdtime_t **ret_times, size_t *ret_number)
-{
- c_avl_iterator_t *iter;
- char *key;
- cache_entry_t *value;
-
- char **names = NULL;
- cdtime_t *times = NULL;
- size_t number = 0;
- size_t size_arrays = 0;
-
- int status = 0;
-
- if ((ret_names == NULL) || (ret_number == NULL))
- return (-1);
-
- pthread_mutex_lock (&cache_lock);
-
- size_arrays = (size_t) c_avl_size (cache_tree);
- if (size_arrays < 1)
- {
- /* Handle the "no values" case here, to avoid the error message when
- * calloc() returns NULL. */
- pthread_mutex_unlock (&cache_lock);
- return (0);
- }
-
- names = calloc (size_arrays, sizeof (*names));
- times = calloc (size_arrays, sizeof (*times));
- if ((names == NULL) || (times == NULL))
- {
- ERROR ("uc_get_names: calloc failed.");
- sfree (names);
- sfree (times);
- pthread_mutex_unlock (&cache_lock);
- return (ENOMEM);
- }
-
- iter = c_avl_get_iterator (cache_tree);
- while (c_avl_iterator_next (iter, (void *) &key, (void *) &value) == 0)
- {
- /* remove missing values when list values */
- if (value->state == STATE_MISSING)
- continue;
-
- /* c_avl_size does not return a number smaller than the number of elements
- * returned by c_avl_iterator_next. */
- assert (number < size_arrays);
-
- if (ret_times != NULL)
- times[number] = value->last_time;
-
- names[number] = strdup (key);
- if (names[number] == NULL)
- {
- status = -1;
- break;
- }
-
- number++;
- } /* while (c_avl_iterator_next) */
-
- c_avl_iterator_destroy (iter);
- pthread_mutex_unlock (&cache_lock);
-
- if (status != 0)
- {
- size_t i;
-
- for (i = 0; i < number; i++)
- {
- sfree (names[i]);
- }
- sfree (names);
-
- return (-1);
- }
-
- *ret_names = names;
- if (ret_times != NULL)
- *ret_times = times;
- *ret_number = number;
-
- return (0);
-} /* int uc_get_names */
-
-int uc_get_state (const data_set_t *ds, const value_list_t *vl)
-{
- char name[6 * DATA_MAX_NAME_LEN];
- cache_entry_t *ce = NULL;
- int ret = STATE_ERROR;
-
- if (FORMAT_VL (name, sizeof (name), vl) != 0)
- {
- ERROR ("uc_get_state: FORMAT_VL failed.");
- return (STATE_ERROR);
- }
-
- pthread_mutex_lock (&cache_lock);
-
- if (c_avl_get (cache_tree, name, (void *) &ce) == 0)
- {
- assert (ce != NULL);
- ret = ce->state;
- }
-
- pthread_mutex_unlock (&cache_lock);
-
- return (ret);
-} /* int uc_get_state */
-
-int uc_set_state (const data_set_t *ds, const value_list_t *vl, int state)
-{
- char name[6 * DATA_MAX_NAME_LEN];
- cache_entry_t *ce = NULL;
- int ret = -1;
-
- if (FORMAT_VL (name, sizeof (name), vl) != 0)
- {
- ERROR ("uc_get_state: FORMAT_VL failed.");
- return (STATE_ERROR);
- }
-
- pthread_mutex_lock (&cache_lock);
-
- if (c_avl_get (cache_tree, name, (void *) &ce) == 0)
- {
- assert (ce != NULL);
- ret = ce->state;
- ce->state = state;
- }
-
- pthread_mutex_unlock (&cache_lock);
-
- return (ret);
-} /* int uc_set_state */
-
-int uc_get_history_by_name (const char *name,
- gauge_t *ret_history, size_t num_steps, size_t num_ds)
-{
- cache_entry_t *ce = NULL;
- size_t i;
- int status = 0;
-
- pthread_mutex_lock (&cache_lock);
-
- status = c_avl_get (cache_tree, name, (void *) &ce);
- if (status != 0)
- {
- pthread_mutex_unlock (&cache_lock);
- return (-ENOENT);
- }
-
- if (((size_t) ce->values_num) != num_ds)
- {
- pthread_mutex_unlock (&cache_lock);
- return (-EINVAL);
- }
-
- /* Check if there are enough values available. If not, increase the buffer
- * size. */
- if (ce->history_length < num_steps)
- {
- gauge_t *tmp;
- size_t i;
-
- tmp = realloc (ce->history, sizeof (*ce->history)
- * num_steps * ce->values_num);
- if (tmp == NULL)
- {
- pthread_mutex_unlock (&cache_lock);
- return (-ENOMEM);
- }
-
- for (i = ce->history_length * ce->values_num;
- i < (num_steps * ce->values_num);
- i++)
- tmp[i] = NAN;
-
- ce->history = tmp;
- ce->history_length = num_steps;
- } /* if (ce->history_length < num_steps) */
-
- /* Copy the values to the output buffer. */
- for (i = 0; i < num_steps; i++)
- {
- size_t src_index;
- size_t dst_index;
-
- if (i < ce->history_index)
- src_index = ce->history_index - (i + 1);
- else
- src_index = ce->history_length + ce->history_index - (i + 1);
- src_index = src_index * num_ds;
-
- dst_index = i * num_ds;
-
- memcpy (ret_history + dst_index, ce->history + src_index,
- sizeof (*ret_history) * num_ds);
- }
-
- pthread_mutex_unlock (&cache_lock);
-
- return (0);
-} /* int uc_get_history_by_name */
-
-int uc_get_history (const data_set_t *ds, const value_list_t *vl,
- gauge_t *ret_history, size_t num_steps, size_t num_ds)
-{
- char name[6 * DATA_MAX_NAME_LEN];
-
- if (FORMAT_VL (name, sizeof (name), vl) != 0)
- {
- ERROR ("utils_cache: uc_get_history: FORMAT_VL failed.");
- return (-1);
- }
-
- return (uc_get_history_by_name (name, ret_history, num_steps, num_ds));
-} /* int uc_get_history */
-
-int uc_get_hits (const data_set_t *ds, const value_list_t *vl)
-{
- char name[6 * DATA_MAX_NAME_LEN];
- cache_entry_t *ce = NULL;
- int ret = STATE_ERROR;
-
- if (FORMAT_VL (name, sizeof (name), vl) != 0)
- {
- ERROR ("uc_get_state: FORMAT_VL failed.");
- return (STATE_ERROR);
- }
-
- pthread_mutex_lock (&cache_lock);
-
- if (c_avl_get (cache_tree, name, (void *) &ce) == 0)
- {
- assert (ce != NULL);
- ret = ce->hits;
- }
-
- pthread_mutex_unlock (&cache_lock);
-
- return (ret);
-} /* int uc_get_hits */
-
-int uc_set_hits (const data_set_t *ds, const value_list_t *vl, int hits)
-{
- char name[6 * DATA_MAX_NAME_LEN];
- cache_entry_t *ce = NULL;
- int ret = -1;
-
- if (FORMAT_VL (name, sizeof (name), vl) != 0)
- {
- ERROR ("uc_get_state: FORMAT_VL failed.");
- return (STATE_ERROR);
- }
-
- pthread_mutex_lock (&cache_lock);
-
- if (c_avl_get (cache_tree, name, (void *) &ce) == 0)
- {
- assert (ce != NULL);
- ret = ce->hits;
- ce->hits = hits;
- }
-
- pthread_mutex_unlock (&cache_lock);
-
- return (ret);
-} /* int uc_set_hits */
-
-int uc_inc_hits (const data_set_t *ds, const value_list_t *vl, int step)
-{
- char name[6 * DATA_MAX_NAME_LEN];
- cache_entry_t *ce = NULL;
- int ret = -1;
-
- if (FORMAT_VL (name, sizeof (name), vl) != 0)
- {
- ERROR ("uc_get_state: FORMAT_VL failed.");
- return (STATE_ERROR);
- }
-
- pthread_mutex_lock (&cache_lock);
-
- if (c_avl_get (cache_tree, name, (void *) &ce) == 0)
- {
- assert (ce != NULL);
- ret = ce->hits;
- ce->hits = ret + step;
- }
-
- pthread_mutex_unlock (&cache_lock);
-
- return (ret);
-} /* int uc_inc_hits */
-
-/*
- * Meta data interface
- */
-/* XXX: This function will acquire `cache_lock' but will not free it! */
-static meta_data_t *uc_get_meta (const value_list_t *vl) /* {{{ */
-{
- char name[6 * DATA_MAX_NAME_LEN];
- cache_entry_t *ce = NULL;
- int status;
-
- status = FORMAT_VL (name, sizeof (name), vl);
- if (status != 0)
- {
- ERROR ("utils_cache: uc_get_meta: FORMAT_VL failed.");
- return (NULL);
- }
-
- pthread_mutex_lock (&cache_lock);
-
- status = c_avl_get (cache_tree, name, (void *) &ce);
- if (status != 0)
- {
- pthread_mutex_unlock (&cache_lock);
- return (NULL);
- }
- assert (ce != NULL);
-
- if (ce->meta == NULL)
- ce->meta = meta_data_create ();
-
- if (ce->meta == NULL)
- pthread_mutex_unlock (&cache_lock);
-
- return (ce->meta);
-} /* }}} meta_data_t *uc_get_meta */
-
-/* Sorry about this preprocessor magic, but it really makes this file much
- * shorter.. */
-#define UC_WRAP(wrap_function) { \
- meta_data_t *meta; \
- int status; \
- meta = uc_get_meta (vl); \
- if (meta == NULL) return (-1); \
- status = wrap_function (meta, key); \
- pthread_mutex_unlock (&cache_lock); \
- return (status); \
-}
-int uc_meta_data_exists (const value_list_t *vl, const char *key)
- UC_WRAP (meta_data_exists)
-
-int uc_meta_data_delete (const value_list_t *vl, const char *key)
- UC_WRAP (meta_data_delete)
-#undef UC_WRAP
-
-/* We need a new version of this macro because the following functions take
- * two argumetns. */
-#define UC_WRAP(wrap_function) { \
- meta_data_t *meta; \
- int status; \
- meta = uc_get_meta (vl); \
- if (meta == NULL) return (-1); \
- status = wrap_function (meta, key, value); \
- pthread_mutex_unlock (&cache_lock); \
- return (status); \
-}
-int uc_meta_data_add_string (const value_list_t *vl,
- const char *key,
- const char *value)
- UC_WRAP(meta_data_add_string)
-int uc_meta_data_add_signed_int (const value_list_t *vl,
- const char *key,
- int64_t value)
- UC_WRAP(meta_data_add_signed_int)
-int uc_meta_data_add_unsigned_int (const value_list_t *vl,
- const char *key,
- uint64_t value)
- UC_WRAP(meta_data_add_unsigned_int)
-int uc_meta_data_add_double (const value_list_t *vl,
- const char *key,
- double value)
- UC_WRAP(meta_data_add_double)
-int uc_meta_data_add_boolean (const value_list_t *vl,
- const char *key,
- _Bool value)
- UC_WRAP(meta_data_add_boolean)
-
-int uc_meta_data_get_string (const value_list_t *vl,
- const char *key,
- char **value)
- UC_WRAP(meta_data_get_string)
-int uc_meta_data_get_signed_int (const value_list_t *vl,
- const char *key,
- int64_t *value)
- UC_WRAP(meta_data_get_signed_int)
-int uc_meta_data_get_unsigned_int (const value_list_t *vl,
- const char *key,
- uint64_t *value)
- UC_WRAP(meta_data_get_unsigned_int)
-int uc_meta_data_get_double (const value_list_t *vl,
- const char *key,
- double *value)
- UC_WRAP(meta_data_get_double)
-int uc_meta_data_get_boolean (const value_list_t *vl,
- const char *key,
- _Bool *value)
- UC_WRAP(meta_data_get_boolean)
-#undef UC_WRAP
-
-/* vim: set sw=2 ts=8 sts=2 tw=78 : */
diff --git a/src/utils_cache.h b/src/utils_cache.h
--- a/src/utils_cache.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * collectd - src/utils_cache.h
- * Copyright (C) 2007 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#ifndef UTILS_CACHE_H
-#define UTILS_CACHE_H 1
-
-#include "plugin.h"
-
-#define STATE_OKAY 0
-#define STATE_WARNING 1
-#define STATE_ERROR 2
-#define STATE_MISSING 15
-
-int uc_init (void);
-int uc_check_timeout (void);
-int uc_update (const data_set_t *ds, const value_list_t *vl);
-int uc_get_rate_by_name (const char *name, gauge_t **ret_values, size_t *ret_values_num);
-gauge_t *uc_get_rate (const data_set_t *ds, const value_list_t *vl);
-
-size_t uc_get_size();
-int uc_get_names (char ***ret_names, cdtime_t **ret_times, size_t *ret_number);
-
-int uc_get_state (const data_set_t *ds, const value_list_t *vl);
-int uc_set_state (const data_set_t *ds, const value_list_t *vl, int state);
-int uc_get_hits (const data_set_t *ds, const value_list_t *vl);
-int uc_set_hits (const data_set_t *ds, const value_list_t *vl, int hits);
-int uc_inc_hits (const data_set_t *ds, const value_list_t *vl, int step);
-
-int uc_get_history (const data_set_t *ds, const value_list_t *vl,
- gauge_t *ret_history, size_t num_steps, size_t num_ds);
-int uc_get_history_by_name (const char *name,
- gauge_t *ret_history, size_t num_steps, size_t num_ds);
-
-/*
- * Meta data interface
- */
-int uc_meta_data_exists (const value_list_t *vl, const char *key);
-int uc_meta_data_delete (const value_list_t *vl, const char *key);
-
-int uc_meta_data_add_string (const value_list_t *vl,
- const char *key,
- const char *value);
-int uc_meta_data_add_signed_int (const value_list_t *vl,
- const char *key,
- int64_t value);
-int uc_meta_data_add_unsigned_int (const value_list_t *vl,
- const char *key,
- uint64_t value);
-int uc_meta_data_add_double (const value_list_t *vl,
- const char *key,
- double value);
-int uc_meta_data_add_boolean (const value_list_t *vl,
- const char *key,
- _Bool value);
-
-int uc_meta_data_get_string (const value_list_t *vl,
- const char *key,
- char **value);
-int uc_meta_data_get_signed_int (const value_list_t *vl,
- const char *key,
- int64_t *value);
-int uc_meta_data_get_unsigned_int (const value_list_t *vl,
- const char *key,
- uint64_t *value);
-int uc_meta_data_get_double (const value_list_t *vl,
- const char *key,
- double *value);
-int uc_meta_data_get_boolean (const value_list_t *vl,
- const char *key,
- _Bool *value);
-
-/* vim: set shiftwidth=2 softtabstop=2 tabstop=8 : */
-#endif /* !UTILS_CACHE_H */
diff --git a/src/utils_complain.c b/src/utils_complain.c
--- a/src/utils_complain.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/**
- * collectd - src/utils_complain.c
- * Copyright (C) 2006-2013 Florian octo Forster
- * Copyright (C) 2008 Sebastian tokkee Harl
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- * Sebastian tokkee Harl <sh at tokkee.org>
- **/
-
-#include "collectd.h"
-#include "utils_complain.h"
-#include "plugin.h"
-
-/* vcomplain returns 0 if it did not report, 1 else */
-static int vcomplain (int level, c_complain_t *c,
- const char *format, va_list ap)
-{
- cdtime_t now;
- char message[512];
-
- now = cdtime ();
-
- if (c->last + c->interval > now)
- return 0;
-
- c->last = now;
-
- if (c->interval < plugin_get_interval ())
- c->interval = plugin_get_interval ();
- else
- c->interval *= 2;
-
- if (c->interval > TIME_T_TO_CDTIME_T (86400))
- c->interval = TIME_T_TO_CDTIME_T (86400);
-
- vsnprintf (message, sizeof (message), format, ap);
- message[sizeof (message) - 1] = '\0';
-
- plugin_log (level, "%s", message);
- return 1;
-} /* vcomplain */
-
-void c_complain (int level, c_complain_t *c, const char *format, ...)
-{
- va_list ap;
-
- va_start (ap, format);
- if (vcomplain (level, c, format, ap))
- c->complained_once = 1;
- va_end (ap);
-} /* c_complain */
-
-void c_complain_once (int level, c_complain_t *c, const char *format, ...)
-{
- va_list ap;
-
- if (c->complained_once)
- return;
-
- va_start (ap, format);
- if (vcomplain (level, c, format, ap))
- c->complained_once = 1;
- va_end (ap);
-} /* c_complain_once */
-
-void c_do_release (int level, c_complain_t *c, const char *format, ...)
-{
- char message[512];
- va_list ap;
-
- if (c->interval == 0)
- return;
-
- c->interval = 0;
- c->complained_once = 0;
-
- va_start (ap, format);
- vsnprintf (message, sizeof (message), format, ap);
- message[sizeof (message) - 1] = '\0';
- va_end (ap);
-
- plugin_log (level, "%s", message);
-} /* c_release */
-
-/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
-
diff --git a/src/utils_complain.h b/src/utils_complain.h
--- a/src/utils_complain.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * collectd - src/utils_complain.h
- * Copyright (C) 2006-2013 Florian octo Forster
- * Copyright (C) 2008 Sebastian tokkee Harl
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- * Sebastian tokkee Harl <sh at tokkee.org>
- **/
-
-#ifndef UTILS_COMPLAIN_H
-#define UTILS_COMPLAIN_H 1
-
-#include "utils_time.h"
-
-typedef struct
-{
- /* time of the last report */
- cdtime_t last;
-
- /* How long to wait until reporting again.
- * 0 indicates that the complaint is no longer valid. */
- cdtime_t interval;
-
- _Bool complained_once;
-} c_complain_t;
-
-#define C_COMPLAIN_INIT_STATIC { 0, 0, 0 }
-#define C_COMPLAIN_INIT(c) do { \
- (c)->last = 0; \
- (c)->interval = 0; \
- (c)->complained_once = 0; \
-} while (0)
-
-/*
- * NAME
- * c_complain
- *
- * DESCRIPTION
- * Complain about something. This function will report a message (usually
- * indicating some error condition) using the collectd logging mechanism.
- * When this function is called again, reporting the message again will be
- * deferred by an increasing interval (up to one day) to prevent flooding
- * the logs. A call to `c_release' resets the counter.
- *
- * PARAMETERS
- * `level' The log level passed to `plugin_log'.
- * `c' Identifier for the complaint.
- * `format' Message format - see the documentation of printf(3).
- */
-void c_complain (int level, c_complain_t *c, const char *format, ...);
-
-/*
- * NAME
- * c_complain_once
- *
- * DESCRIPTION
- * Complain about something once. This function will not report anything
- * again, unless `c_release' has been called in between. If used after some
- * calls to `c_complain', it will report again on the next interval and stop
- * after that.
- *
- * See `c_complain' for further details and a description of the parameters.
- */
-void c_complain_once (int level, c_complain_t *c, const char *format, ...);
-
-/*
- * NAME
- * c_would_release
- *
- * DESCRIPTION
- * Returns true if the specified complaint would be released, false else.
- */
-#define c_would_release(c) ((c)->interval != 0)
-
-/*
- * NAME
- * c_release
- *
- * DESCRIPTION
- * Release a complaint. This will report a message once, marking the
- * complaint as released.
- *
- * See `c_complain' for a description of the parameters.
- */
-void c_do_release (int level, c_complain_t *c, const char *format, ...);
-#define c_release(level, c, ...) \
- do { \
- if (c_would_release (c)) \
- c_do_release(level, c, __VA_ARGS__); \
- } while (0)
-
-#endif /* UTILS_COMPLAIN_H */
-
-/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
-
diff --git a/src/utils_heap.c b/src/utils_heap.c
--- a/src/utils_heap.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/**
- * collectd - src/utils_heap.c
- * Copyright (C) 2009 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-#include <pthread.h>
-
-#include "utils_heap.h"
-
-struct c_heap_s
-{
- pthread_mutex_t lock;
- int (*compare) (const void *, const void *);
-
- void **list;
- size_t list_len; /* # entries used */
- size_t list_size; /* # entries allocated */
-};
-
-enum reheap_direction
-{
- DIR_UP,
- DIR_DOWN
-};
-
-static void reheap (c_heap_t *h, size_t root, enum reheap_direction dir)
-{
- size_t left;
- size_t right;
- size_t min;
- int status;
-
- /* Calculate the positions of the children */
- left = (2 * root) + 1;
- if (left >= h->list_len)
- left = 0;
-
- right = (2 * root) + 2;
- if (right >= h->list_len)
- right = 0;
-
- /* Check which one of the children is smaller. */
- if ((left == 0) && (right == 0))
- return;
- else if (left == 0)
- min = right;
- else if (right == 0)
- min = left;
- else
- {
- status = h->compare (h->list[left], h->list[right]);
- if (status > 0)
- min = right;
- else
- min = left;
- }
-
- status = h->compare (h->list[root], h->list[min]);
- if (status <= 0)
- {
- /* We didn't need to change anything, so the rest of the tree should be
- * okay now. */
- return;
- }
- else /* if (status > 0) */
- {
- void *tmp;
-
- tmp = h->list[root];
- h->list[root] = h->list[min];
- h->list[min] = tmp;
- }
-
- if ((dir == DIR_UP) && (root == 0))
- return;
-
- if (dir == DIR_UP)
- reheap (h, (root - 1) / 2, dir);
- else if (dir == DIR_DOWN)
- reheap (h, min, dir);
-} /* void reheap */
-
-c_heap_t *c_heap_create (int (*compare) (const void *, const void *))
-{
- c_heap_t *h;
-
- if (compare == NULL)
- return (NULL);
-
- h = malloc (sizeof (*h));
- if (h == NULL)
- return (NULL);
-
- memset (h, 0, sizeof (*h));
- pthread_mutex_init (&h->lock, /* attr = */ NULL);
- h->compare = compare;
-
- h->list = NULL;
- h->list_len = 0;
- h->list_size = 0;
-
- return (h);
-} /* c_heap_t *c_heap_create */
-
-void c_heap_destroy (c_heap_t *h)
-{
- if (h == NULL)
- return;
-
- h->list_len = 0;
- h->list_size = 0;
- free (h->list);
- h->list = NULL;
-
- pthread_mutex_destroy (&h->lock);
-
- free (h);
-} /* void c_heap_destroy */
-
-int c_heap_insert (c_heap_t *h, void *ptr)
-{
- size_t index;
-
- if ((h == NULL) || (ptr == NULL))
- return (-EINVAL);
-
- pthread_mutex_lock (&h->lock);
-
- assert (h->list_len <= h->list_size);
- if (h->list_len == h->list_size)
- {
- void **tmp;
-
- tmp = realloc (h->list, (h->list_size + 16) * sizeof (*h->list));
- if (tmp == NULL)
- {
- pthread_mutex_unlock (&h->lock);
- return (-ENOMEM);
- }
-
- h->list = tmp;
- h->list_size += 16;
- }
-
- /* Insert the new node as a leaf. */
- index = h->list_len;
- h->list[index] = ptr;
- h->list_len++;
-
- /* Reorganize the heap from bottom up. */
- reheap (h, /* parent of this node = */ (index - 1) / 2, DIR_UP);
-
- pthread_mutex_unlock (&h->lock);
- return (0);
-} /* int c_heap_insert */
-
-void *c_heap_get_root (c_heap_t *h)
-{
- void *ret = NULL;
-
- if (h == NULL)
- return (NULL);
-
- pthread_mutex_lock (&h->lock);
-
- if (h->list_len == 0)
- {
- pthread_mutex_unlock (&h->lock);
- return (NULL);
- }
- else if (h->list_len == 1)
- {
- ret = h->list[0];
- h->list[0] = NULL;
- h->list_len = 0;
- }
- else /* if (h->list_len > 1) */
- {
- ret = h->list[0];
- h->list[0] = h->list[h->list_len - 1];
- h->list[h->list_len - 1] = NULL;
- h->list_len--;
-
- reheap (h, /* root = */ 0, DIR_DOWN);
- }
-
- /* free some memory */
- if ((h->list_len + 32) < h->list_size)
- {
- void **tmp;
-
- tmp = realloc (h->list, (h->list_len + 16) * sizeof (*h->list));
- if (tmp != NULL)
- {
- h->list = tmp;
- h->list_size = h->list_len + 16;
- }
- }
-
- pthread_mutex_unlock (&h->lock);
-
- return (ret);
-} /* void *c_heap_get_root */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/utils_heap.h b/src/utils_heap.h
--- a/src/utils_heap.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * collectd - src/utils_heap.h
- * Copyright (C) 2009 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#ifndef UTILS_HEAP_H
-#define UTILS_HEAP_H 1
-
-struct c_heap_s;
-typedef struct c_heap_s c_heap_t;
-
-/*
- * NAME
- * c_heap_create
- *
- * DESCRIPTION
- * Allocates a new heap.
- *
- * PARAMETERS
- * `compare' The function-pointer `compare' is used to compare two keys. It
- * has to return less than zero if it's first argument is smaller
- * then the second argument, more than zero if the first argument
- * is bigger than the second argument and zero if they are equal.
- * If your keys are char-pointers, you can use the `strcmp'
- * function from the libc here.
- *
- * RETURN VALUE
- * A c_heap_t-pointer upon success or NULL upon failure.
- */
-c_heap_t *c_heap_create (int (*compare) (const void *, const void *));
-
-/*
- * NAME
- * c_heap_destroy
- *
- * DESCRIPTION
- * Deallocates a heap. Stored value- and key-pointer are lost, but of course
- * not freed.
- */
-void c_heap_destroy (c_heap_t *h);
-
-/*
- * NAME
- * c_heap_insert
- *
- * DESCRIPTION
- * Stores the key-value-pair in the heap pointed to by `h'.
- *
- * PARAMETERS
- * `h' Heap to store the data in.
- * `ptr' Value to be stored. This is typically a pointer to a data
- * structure. The data structure is of course *not* copied and may
- * not be free'd before the pointer has been removed from the heap
- * again.
- *
- * RETURN VALUE
- * Zero upon success, non-zero otherwise. It's less than zero if an error
- * occurred or greater than zero if the key is already stored in the tree.
- */
-int c_heap_insert (c_heap_t *h, void *ptr);
-
-/*
- * NAME
- * c_heap_get_root
- *
- * DESCRIPTION
- * Removes the value at the root of the heap and returns both, key and value.
- *
- * PARAMETERS
- * `h' Heap to remove key-value-pair from.
- *
- * RETURN VALUE
- * The pointer passed to `c_heap_insert' or NULL if there are no more
- * elements in the heap (or an error occurred).
- */
-void *c_heap_get_root (c_heap_t *h);
-
-#endif /* UTILS_HEAP_H */
-/* vim: set sw=2 sts=2 et : */
diff --git a/src/utils_llist.c b/src/utils_llist.c
--- a/src/utils_llist.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/**
- * collectd - src/utils_llist.c
- * Copyright (C) 2006 Florian Forster <octo at collectd.org>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian Forster <octo at collectd.org>
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "utils_llist.h"
-
-/*
- * Private data types
- */
-struct llist_s
-{
- llentry_t *head;
- llentry_t *tail;
- int size;
-};
-
-/*
- * Public functions
- */
-llist_t *llist_create (void)
-{
- llist_t *ret;
-
- ret = (llist_t *) malloc (sizeof (llist_t));
- if (ret == NULL)
- return (NULL);
-
- memset (ret, '\0', sizeof (llist_t));
-
- return (ret);
-}
-
-void llist_destroy (llist_t *l)
-{
- llentry_t *e_this;
- llentry_t *e_next;
-
- if (l == NULL)
- return;
-
- for (e_this = l->head; e_this != NULL; e_this = e_next)
- {
- e_next = e_this->next;
- llentry_destroy (e_this);
- }
-
- free (l);
-}
-
-llentry_t *llentry_create (char *key, void *value)
-{
- llentry_t *e;
-
- e = (llentry_t *) malloc (sizeof (llentry_t));
- if (e)
- {
- e->key = key;
- e->value = value;
- e->next = NULL;
- }
-
- return (e);
-}
-
-void llentry_destroy (llentry_t *e)
-{
- free (e);
-}
-
-void llist_append (llist_t *l, llentry_t *e)
-{
- e->next = NULL;
-
- if (l->tail == NULL)
- l->head = e;
- else
- l->tail->next = e;
-
- l->tail = e;
-
- ++(l->size);
-}
-
-void llist_prepend (llist_t *l, llentry_t *e)
-{
- e->next = l->head;
- l->head = e;
-
- if (l->tail == NULL)
- l->tail = e;
-
- ++(l->size);
-}
-
-void llist_remove (llist_t *l, llentry_t *e)
-{
- llentry_t *prev;
-
- prev = l->head;
- while ((prev != NULL) && (prev->next != e))
- prev = prev->next;
-
- if (prev != NULL)
- prev->next = e->next;
- if (l->head == e)
- l->head = e->next;
- if (l->tail == e)
- l->tail = prev;
-
- --(l->size);
-}
-
-int llist_size (llist_t *l)
-{
- return (l ? l->size : 0);
-}
-
-static int llist_strcmp (llentry_t *e, void *ud)
-{
- if ((e == NULL) || (ud == NULL))
- return (-1);
- return (strcmp (e->key, (const char *)ud));
-}
-
-llentry_t *llist_search (llist_t *l, const char *key)
-{
- return (llist_search_custom (l, llist_strcmp, (void *)key));
-}
-
-llentry_t *llist_search_custom (llist_t *l,
- int (*compare) (llentry_t *, void *), void *user_data)
-{
- llentry_t *e;
-
- if (l == NULL)
- return (NULL);
-
- e = l->head;
- while (e != NULL) {
- llentry_t *next = e->next;
-
- if (compare (e, user_data) == 0)
- break;
-
- e = next;
- }
-
- return (e);
-}
-
-llentry_t *llist_head (llist_t *l)
-{
- if (l == NULL)
- return (NULL);
- return (l->head);
-}
-
-llentry_t *llist_tail (llist_t *l)
-{
- if (l == NULL)
- return (NULL);
- return (l->tail);
-}
diff --git a/src/utils_llist.h b/src/utils_llist.h
--- a/src/utils_llist.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * collectd - src/utils_llist.h
- * Copyright (C) 2006 Florian Forster <octo at collectd.org>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian Forster <octo at collectd.org>
- */
-
-#ifndef UTILS_LLIST_H
-#define UTILS_LLIST_H 1
-
-/*
- * Data types
- */
-struct llentry_s
-{
- char *key;
- void *value;
- struct llentry_s *next;
-};
-typedef struct llentry_s llentry_t;
-
-struct llist_s;
-typedef struct llist_s llist_t;
-
-/*
- * Functions
- */
-llist_t *llist_create (void);
-void llist_destroy (llist_t *l);
-
-llentry_t *llentry_create (char *key, void *value);
-void llentry_destroy (llentry_t *e);
-
-void llist_append (llist_t *l, llentry_t *e);
-void llist_prepend (llist_t *l, llentry_t *e);
-void llist_remove (llist_t *l, llentry_t *e);
-
-int llist_size (llist_t *l);
-
-llentry_t *llist_search (llist_t *l, const char *key);
-llentry_t *llist_search_custom (llist_t *l,
- int (*compare) (llentry_t *, void *), void *user_data);
-
-llentry_t *llist_head (llist_t *l);
-llentry_t *llist_tail (llist_t *l);
-
-#endif /* UTILS_LLIST_H */
diff --git a/src/utils_match.c b/src/utils_match.c
--- a/src/utils_match.c
+++ /dev/null
@@ -1,396 +0,0 @@
-/**
- * collectd - src/utils_match.c
- * Copyright (C) 2008-2014 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#include "collectd.h"
-#include "common.h"
-#include "plugin.h"
-
-#include "utils_match.h"
-
-#include <regex.h>
-
-#define UTILS_MATCH_FLAGS_FREE_USER_DATA 0x01
-#define UTILS_MATCH_FLAGS_EXCLUDE_REGEX 0x02
-
-struct cu_match_s
-{
- regex_t regex;
- regex_t excluderegex;
- int flags;
-
- int (*callback) (const char *str, char * const *matches, size_t matches_num,
- void *user_data);
- void *user_data;
-};
-
-/*
- * Private functions
- */
-static char *match_substr (const char *str, int begin, int end)
-{
- char *ret;
- size_t ret_len;
-
- if ((begin < 0) || (end < 0) || (begin >= end))
- return (NULL);
- if ((size_t) end > (strlen (str) + 1))
- {
- ERROR ("utils_match: match_substr: `end' points after end of string.");
- return (NULL);
- }
-
- ret_len = end - begin;
- ret = (char *) malloc (sizeof (char) * (ret_len + 1));
- if (ret == NULL)
- {
- ERROR ("utils_match: match_substr: malloc failed.");
- return (NULL);
- }
-
- sstrncpy (ret, str + begin, ret_len + 1);
- return (ret);
-} /* char *match_substr */
-
-static int default_callback (const char __attribute__((unused)) *str,
- char * const *matches, size_t matches_num, void *user_data)
-{
- cu_match_value_t *data = (cu_match_value_t *) user_data;
-
- if (data->ds_type & UTILS_MATCH_DS_TYPE_GAUGE)
- {
- gauge_t value;
- char *endptr = NULL;
-
- if (data->ds_type & UTILS_MATCH_CF_GAUGE_INC)
- {
- data->value.gauge = isnan (data->value.gauge) ? 1 : data->value.gauge + 1;
- data->values_num++;
- return(0);
- }
-
- if (matches_num < 2)
- return (-1);
-
- value = (gauge_t) strtod (matches[1], &endptr);
- if (matches[1] == endptr)
- return (-1);
-
- if ((data->values_num == 0)
- || (data->ds_type & UTILS_MATCH_CF_GAUGE_LAST))
- {
- data->value.gauge = value;
- }
- else if (data->ds_type & UTILS_MATCH_CF_GAUGE_AVERAGE)
- {
- double f = ((double) data->values_num)
- / ((double) (data->values_num + 1));
- data->value.gauge = (data->value.gauge * f) + (value * (1.0 - f));
- }
- else if (data->ds_type & UTILS_MATCH_CF_GAUGE_MIN)
- {
- if (data->value.gauge > value)
- data->value.gauge = value;
- }
- else if (data->ds_type & UTILS_MATCH_CF_GAUGE_MAX)
- {
- if (data->value.gauge < value)
- data->value.gauge = value;
- }
- else if (data->ds_type & UTILS_MATCH_CF_GAUGE_ADD)
- {
- data->value.gauge += value;
- }
- else
- {
- ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
- return (-1);
- }
-
- data->values_num++;
- }
- else if (data->ds_type & UTILS_MATCH_DS_TYPE_COUNTER)
- {
- counter_t value;
- char *endptr = NULL;
-
- if (data->ds_type & UTILS_MATCH_CF_COUNTER_INC)
- {
- data->value.counter++;
- data->values_num++;
- return (0);
- }
-
- if (matches_num < 2)
- return (-1);
-
- value = (counter_t) strtoull (matches[1], &endptr, 0);
- if (matches[1] == endptr)
- return (-1);
-
- if (data->ds_type & UTILS_MATCH_CF_COUNTER_SET)
- data->value.counter = value;
- else if (data->ds_type & UTILS_MATCH_CF_COUNTER_ADD)
- data->value.counter += value;
- else
- {
- ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
- return (-1);
- }
-
- data->values_num++;
- }
- else if (data->ds_type & UTILS_MATCH_DS_TYPE_DERIVE)
- {
- derive_t value;
- char *endptr = NULL;
-
- if (data->ds_type & UTILS_MATCH_CF_DERIVE_INC)
- {
- data->value.counter++;
- data->values_num++;
- return (0);
- }
-
- if (matches_num < 2)
- return (-1);
-
- value = (derive_t) strtoll (matches[1], &endptr, 0);
- if (matches[1] == endptr)
- return (-1);
-
- if (data->ds_type & UTILS_MATCH_CF_DERIVE_SET)
- data->value.derive = value;
- else if (data->ds_type & UTILS_MATCH_CF_DERIVE_ADD)
- data->value.derive += value;
- else
- {
- ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
- return (-1);
- }
-
- data->values_num++;
- }
- else if (data->ds_type & UTILS_MATCH_DS_TYPE_ABSOLUTE)
- {
- absolute_t value;
- char *endptr = NULL;
-
- if (matches_num < 2)
- return (-1);
-
- value = (absolute_t) strtoull (matches[1], &endptr, 0);
- if (matches[1] == endptr)
- return (-1);
-
- if (data->ds_type & UTILS_MATCH_CF_ABSOLUTE_SET)
- data->value.absolute = value;
- else
- {
- ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
- return (-1);
- }
-
- data->values_num++;
- }
- else
- {
- ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
- return (-1);
- }
-
- return (0);
-} /* int default_callback */
-
-/*
- * Public functions
- */
-cu_match_t *match_create_callback (const char *regex, const char *excluderegex,
- int (*callback) (const char *str,
- char * const *matches, size_t matches_num, void *user_data),
- void *user_data)
-{
- cu_match_t *obj;
- int status;
-
- DEBUG ("utils_match: match_create_callback: regex = %s, excluderegex = %s",
- regex, excluderegex);
-
- obj = (cu_match_t *) malloc (sizeof (cu_match_t));
- if (obj == NULL)
- return (NULL);
- memset (obj, '\0', sizeof (cu_match_t));
-
- status = regcomp (&obj->regex, regex, REG_EXTENDED | REG_NEWLINE);
- if (status != 0)
- {
- ERROR ("Compiling the regular expression \"%s\" failed.", regex);
- sfree (obj);
- return (NULL);
- }
-
- if (excluderegex && strcmp(excluderegex, "") != 0) {
- status = regcomp (&obj->excluderegex, excluderegex, REG_EXTENDED);
- if (status != 0)
- {
- ERROR ("Compiling the excluding regular expression \"%s\" failed.",
- excluderegex);
- sfree (obj);
- return (NULL);
- }
- obj->flags |= UTILS_MATCH_FLAGS_EXCLUDE_REGEX;
- }
-
- obj->callback = callback;
- obj->user_data = user_data;
-
- return (obj);
-} /* cu_match_t *match_create_callback */
-
-cu_match_t *match_create_simple (const char *regex,
- const char *excluderegex, int match_ds_type)
-{
- cu_match_value_t *user_data;
- cu_match_t *obj;
-
- user_data = (cu_match_value_t *) malloc (sizeof (cu_match_value_t));
- if (user_data == NULL)
- return (NULL);
- memset (user_data, '\0', sizeof (cu_match_value_t));
- user_data->ds_type = match_ds_type;
-
- obj = match_create_callback (regex, excluderegex,
- default_callback, user_data);
- if (obj == NULL)
- {
- sfree (user_data);
- return (NULL);
- }
-
- obj->flags |= UTILS_MATCH_FLAGS_FREE_USER_DATA;
-
- return (obj);
-} /* cu_match_t *match_create_simple */
-
-void match_value_reset (cu_match_value_t *mv)
-{
- if (mv == NULL)
- return;
-
- if (mv->ds_type & UTILS_MATCH_DS_TYPE_GAUGE)
- {
- mv->value.gauge = NAN;
- mv->values_num = 0;
- }
-} /* }}} void match_value_reset */
-
-void match_destroy (cu_match_t *obj)
-{
- if (obj == NULL)
- return;
-
- if (obj->flags & UTILS_MATCH_FLAGS_FREE_USER_DATA)
- {
- sfree (obj->user_data);
- }
-
- sfree (obj);
-} /* void match_destroy */
-
-int match_apply (cu_match_t *obj, const char *str)
-{
- int status;
- regmatch_t re_match[32];
- char *matches[32];
- size_t matches_num;
- size_t i;
-
- if ((obj == NULL) || (str == NULL))
- return (-1);
-
- if (obj->flags & UTILS_MATCH_FLAGS_EXCLUDE_REGEX) {
- status = regexec (&obj->excluderegex, str,
- STATIC_ARRAY_SIZE (re_match), re_match,
- /* eflags = */ 0);
- /* Regex did match, so exclude this line */
- if (status == 0) {
- DEBUG("ExludeRegex matched, don't count that line\n");
- return (0);
- }
- }
-
- status = regexec (&obj->regex, str,
- STATIC_ARRAY_SIZE (re_match), re_match,
- /* eflags = */ 0);
-
- /* Regex did not match */
- if (status != 0)
- return (0);
-
- memset (matches, '\0', sizeof (matches));
- for (matches_num = 0; matches_num < STATIC_ARRAY_SIZE (matches); matches_num++)
- {
- if ((re_match[matches_num].rm_so < 0)
- || (re_match[matches_num].rm_eo < 0))
- break;
-
- matches[matches_num] = match_substr (str,
- re_match[matches_num].rm_so, re_match[matches_num].rm_eo);
- if (matches[matches_num] == NULL)
- {
- status = -1;
- break;
- }
- }
-
- if (status != 0)
- {
- ERROR ("utils_match: match_apply: match_substr failed.");
- }
- else
- {
- status = obj->callback (str, matches, matches_num, obj->user_data);
- if (status != 0)
- {
- ERROR ("utils_match: match_apply: callback failed.");
- }
- }
-
- for (i = 0; i < matches_num; i++)
- {
- sfree (matches[i]);
- }
-
- return (status);
-} /* int match_apply */
-
-void *match_get_user_data (cu_match_t *obj)
-{
- if (obj == NULL)
- return (NULL);
- return (obj->user_data);
-} /* void *match_get_user_data */
-
-/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/utils_match.h b/src/utils_match.h
--- a/src/utils_match.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/**
- * collectd - src/utils_match.h
- * Copyright (C) 2008-2014 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#ifndef UTILS_MATCH_H
-#define UTILS_MATCH_H 1
-
-#include "plugin.h"
-
-/*
- * Each type may have 12 sub-types
- * 0x1000 = 1000000000000
- * ^ <- Type bit
- * ^^^^^^^^^^^^ <- Subtype bits
- */
-#define UTILS_MATCH_DS_TYPE_GAUGE 0x1000
-#define UTILS_MATCH_DS_TYPE_COUNTER 0x2000
-#define UTILS_MATCH_DS_TYPE_DERIVE 0x4000
-#define UTILS_MATCH_DS_TYPE_ABSOLUTE 0x8000
-
-#define UTILS_MATCH_CF_GAUGE_AVERAGE 0x01
-#define UTILS_MATCH_CF_GAUGE_MIN 0x02
-#define UTILS_MATCH_CF_GAUGE_MAX 0x04
-#define UTILS_MATCH_CF_GAUGE_LAST 0x08
-#define UTILS_MATCH_CF_GAUGE_INC 0x10
-#define UTILS_MATCH_CF_GAUGE_ADD 0x20
-
-#define UTILS_MATCH_CF_COUNTER_SET 0x01
-#define UTILS_MATCH_CF_COUNTER_ADD 0x02
-#define UTILS_MATCH_CF_COUNTER_INC 0x04
-
-#define UTILS_MATCH_CF_DERIVE_SET 0x01
-#define UTILS_MATCH_CF_DERIVE_ADD 0x02
-#define UTILS_MATCH_CF_DERIVE_INC 0x04
-
-#define UTILS_MATCH_CF_ABSOLUTE_SET 0x01
-#define UTILS_MATCH_CF_ABSOLUTE_ADD 0x02
-#define UTILS_MATCH_CF_ABSOLUTE_INC 0x04
-
-/*
- * Data types
- */
-struct cu_match_s;
-typedef struct cu_match_s cu_match_t;
-
-struct cu_match_value_s
-{
- int ds_type;
- value_t value;
- unsigned int values_num;
-};
-typedef struct cu_match_value_s cu_match_value_t;
-
-/*
- * Prototypes
- */
-/*
- * NAME
- * match_create_callback
- *
- * DESCRIPTION
- * Creates a new `cu_match_t' object which will use the regular expression
- * `regex' to match lines, see the `match_apply' method below. If the line
- * matches, the callback passed in `callback' will be called along with the
- * pointer `user_pointer'.
- * The string that's passed to the callback depends on the regular expression:
- * If the regular expression includes a sub-match, i. e. something like
- * "value=([0-9][0-9]*)"
- * then only the submatch (the part in the parenthesis) will be passed to the
- * callback. If there is no submatch, then the entire string is passed to the
- * callback.
- * The optional `excluderegex' allows to exclude the line from the match, if
- * the excluderegex matches.
- */
-cu_match_t *match_create_callback (const char *regex, const char *excluderegex,
- int (*callback) (const char *str,
- char * const *matches, size_t matches_num, void *user_data),
- void *user_data);
-
-/*
- * NAME
- * match_create_simple
- *
- * DESCRIPTION
- * Creates a new `cu_match_t' with a default callback. The user data for that
- * default callback will be a `cu_match_value_t' structure, with
- * `ds_type' copied to the structure. The default callback will handle the
- * string as containing a number (see strtoll(3) and strtod(3)) and store that
- * number in the `value' member. How that is done depends on `ds_type':
- *
- * UTILS_MATCH_DS_TYPE_GAUGE
- * The function will search for a floating point number in the string and
- * store it in value.gauge.
- * UTILS_MATCH_DS_TYPE_COUNTER_SET
- * The function will search for an integer in the string and store it in
- * value.counter.
- * UTILS_MATCH_DS_TYPE_COUNTER_ADD
- * The function will search for an integer in the string and add it to the
- * value in value.counter.
- * UTILS_MATCH_DS_TYPE_COUNTER_INC
- * The function will not search for anything in the string and increase
- * value.counter by one.
- */
-cu_match_t *match_create_simple (const char *regex,
- const char *excluderegex, int ds_type);
-
-/*
- * NAME
- * match_value_reset
- *
- * DESCRIPTION
- * Resets the internal state, if applicable. This function must be called
- * after each iteration for "simple" matches, usually after dispatching the
- * metrics.
- */
-void match_value_reset (cu_match_value_t *mv);
-
-/*
- * NAME
- * match_destroy
- *
- * DESCRIPTION
- * Destroys the object and frees all internal resources.
- */
-void match_destroy (cu_match_t *obj);
-
-/*
- * NAME
- * match_apply
- *
- * DESCRIPTION
- * Tries to match the string `str' with the regular expression of `obj'. If
- * the string matches, calls the callback in `obj' with the (sub-)match.
- *
- * The user_data pointer passed to `match_create_callback' is NOT freed
- * automatically. The `cu_match_value_t' structure allocated by
- * `match_create_callback' is freed automatically.
- */
-int match_apply (cu_match_t *obj, const char *str);
-
-/*
- * NAME
- * match_get_user_data
- *
- * DESCRIPTION
- * Returns the pointer passed to `match_create_callback' or a pointer to the
- * `cu_match_value_t' structure allocated by `match_create_simple'.
- */
-void *match_get_user_data (cu_match_t *obj);
-
-#endif /* UTILS_MATCH_H */
-
-/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/utils_parse_option.c b/src/utils_parse_option.c
--- a/src/utils_parse_option.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/**
- * collectd - src/utils_parse_option.c
- * Copyright (C) 2008 Florian Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#include "collectd.h"
-#include "common.h"
-#include "plugin.h"
-#include "utils_parse_option.h"
-
-int parse_string (char **ret_buffer, char **ret_string)
-{
- char *buffer;
- char *string;
-
- buffer = *ret_buffer;
-
- /* Eat up leading spaces. */
- string = buffer;
- while (isspace ((int) *string))
- string++;
- if (*string == 0)
- return (1);
-
- /* A quoted string */
- if (*string == '"')
- {
- char *dst;
-
- string++;
- if (*string == 0)
- return (1);
-
- dst = string;
- buffer = string;
- while ((*buffer != '"') && (*buffer != 0))
- {
- /* Un-escape backslashes */
- if (*buffer == '\\')
- {
- buffer++;
- /* Catch a backslash at the end of buffer */
- if (*buffer == 0)
- return (-1);
- }
- *dst = *buffer;
- buffer++;
- dst++;
- }
- /* No quote sign has been found */
- if (*buffer == 0)
- return (-1);
-
- *dst = 0;
- dst++;
- *buffer = 0;
- buffer++;
-
- /* Check for trailing spaces. */
- if ((*buffer != 0) && !isspace ((int) *buffer))
- return (-1);
- }
- else /* an unquoted string */
- {
- buffer = string;
- while ((*buffer != 0) && !isspace ((int) *buffer))
- buffer++;
- if (*buffer != 0)
- {
- *buffer = 0;
- buffer++;
- }
- }
-
- /* Eat up trailing spaces */
- while (isspace ((int) *buffer))
- buffer++;
-
- *ret_buffer = buffer;
- *ret_string = string;
-
- return (0);
-} /* int parse_string */
-
-/*
- * parse_option
- * ------------
- * Parses an ``option'' as used with the unixsock and exec commands. An
- * option is of the form:
- * name0="value"
- * name1="value with \"quotes\""
- * name2="value \\ backslash"
- * However, if the value does *not* contain a space character, you can skip
- * the quotes.
- */
-int parse_option (char **ret_buffer, char **ret_key, char **ret_value)
-{
- char *buffer;
- char *key;
- char *value;
- int status;
-
- buffer = *ret_buffer;
-
- /* Eat up leading spaces */
- key = buffer;
- while (isspace ((int) *key))
- key++;
- if (*key == 0)
- return (1);
-
- /* Look for the equal sign */
- buffer = key;
- while (isalnum ((int) *buffer) || *buffer == '_' || *buffer == ':')
- buffer++;
- if ((*buffer != '=') || (buffer == key))
- return (1);
- *buffer = 0;
- buffer++;
- /* Empty values must be written as "" */
- if (isspace ((int) *buffer) || (*buffer == 0))
- return (-1);
-
- status = parse_string (&buffer, &value);
- if (status != 0)
- return (-1);
-
- /* NB: parse_string will have eaten up all trailing spaces. */
-
- *ret_buffer = buffer;
- *ret_key = key;
- *ret_value = value;
-
- return (0);
-} /* int parse_option */
-
-int escape_string (char *buffer, size_t buffer_size)
-{
- char *temp;
- size_t i;
- size_t j;
-
- /* Check if we need to escape at all first */
- temp = strpbrk (buffer, " \t\"\\");
- if (temp == NULL)
- return (0);
-
- temp = (char *) malloc (buffer_size);
- if (temp == NULL)
- return (-1);
- memset (temp, 0, buffer_size);
-
- temp[0] = '"';
- j = 1;
-
- for (i = 0; i < buffer_size; i++)
- {
- if (buffer[i] == 0)
- {
- break;
- }
- else if ((buffer[i] == '"') || (buffer[i] == '\\'))
- {
- if (j > (buffer_size - 4))
- break;
- temp[j] = '\\';
- temp[j + 1] = buffer[i];
- j += 2;
- }
- else
- {
- if (j > (buffer_size - 3))
- break;
- temp[j] = buffer[i];
- j++;
- }
- }
-
- assert ((j + 1) < buffer_size);
- temp[j] = '"';
- temp[j + 1] = 0;
-
- sstrncpy (buffer, temp, buffer_size);
- sfree (temp);
- return (0);
-} /* int escape_string */
-
-/* vim: set sw=2 ts=8 tw=78 et : */
diff --git a/src/utils_parse_option.h b/src/utils_parse_option.h
--- a/src/utils_parse_option.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * collectd - src/utils_parse_option.h
- * Copyright (C) 2008 Florian Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <octo at collectd.org>
- **/
-
-#ifndef UTILS_PARSE_OPTION
-#define UTILS_PARSE_OPTION 1
-
-int parse_string (char **ret_buffer, char **ret_string);
-int parse_option (char **ret_buffer, char **ret_key, char **ret_value);
-
-int escape_string (char *buffer, size_t buffer_size);
-
-#endif /* UTILS_PARSE_OPTION */
-
-/* vim: set sw=2 ts=8 tw=78 et : */
diff --git a/src/utils_random.c b/src/utils_random.c
--- a/src/utils_random.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * collectd - src/utils_random.c
- * Copyright (C) 2013 Florian Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian Forster <octo at collectd.org>
- **/
-
-#include "collectd.h"
-#include "utils_time.h"
-
-#include <pthread.h>
-
-static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
-static _Bool have_seed = 0;
-static unsigned short seed[3];
-
-static void cdrand_seed (void)
-{
- cdtime_t t;
-
- if (have_seed)
- return;
-
- t = cdtime();
-
- seed[0] = (unsigned short) t;
- seed[1] = (unsigned short) (t >> 16);
- seed[2] = (unsigned short) (t >> 32);
-
- have_seed = 1;
-}
-
-double cdrand_d (void)
-{
- double r;
-
- pthread_mutex_lock (&lock);
- cdrand_seed ();
- r = erand48 (seed);
- pthread_mutex_unlock (&lock);
-
- return (r);
-}
-
-long cdrand_range (long min, long max)
-{
- long range;
- long r;
-
- range = 1 + max - min;
-
- r = (long) (0.5 + (cdrand_d () * range));
- r += min;
-
- return (r);
-}
diff --git a/src/utils_random.h b/src/utils_random.h
--- a/src/utils_random.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * collectd - src/utils_random.h
- * Copyright (C) 2013 Florian Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian Forster <octo at collectd.org>
- **/
-
-/**
- * Returns a random double value in the range [0..1), i.e. excluding 1.
- *
- * This function is thread- and reentrant-safe.
- */
-double cdrand_d (void);
-
-/**
- * Returns a random long between min and max, inclusively.
- *
- * If min is larger than max, the result may be rounded incorrectly and may be
- * outside the intended range. This function is thread- and reentrant-safe.
- */
-long cdrand_range (long min, long max);
diff --git a/src/utils_subst.c b/src/utils_subst.c
--- a/src/utils_subst.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/**
- * collectd - src/utils_subst.c
- * Copyright (C) 2008 Sebastian Harl
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Sebastian "tokkee" Harl <sh at tokkee.org>
- **/
-
-/*
- * This module provides functions for string substitution.
- */
-
-#include "collectd.h"
-#include "common.h"
-
-char *subst (char *buf, size_t buflen, const char *string, int off1, int off2,
- const char *replacement)
-{
- char *buf_ptr = buf;
- size_t len = buflen;
-
- if ((NULL == buf) || (0 >= buflen) || (NULL == string)
- || (0 > off1) || (0 > off2) || (off1 > off2)
- || (NULL == replacement))
- return NULL;
-
- sstrncpy (buf_ptr, string,
- ((size_t)off1 + 1 > buflen) ? buflen : (size_t)off1 + 1);
- buf_ptr += off1;
- len -= off1;
-
- if (0 >= len)
- return buf;
-
- sstrncpy (buf_ptr, replacement, len);
- buf_ptr += strlen (replacement);
- len -= strlen (replacement);
-
- if (0 >= len)
- return buf;
-
- sstrncpy (buf_ptr, string + off2, len);
- return buf;
-} /* subst */
-
-char *asubst (const char *string, int off1, int off2, const char *replacement)
-{
- char *buf;
- int len;
-
- char *ret;
-
- if ((NULL == string) || (0 > off1) || (0 > off2) || (off1 > off2)
- || (NULL ==replacement))
- return NULL;
-
- len = off1 + strlen (replacement) + strlen (string) - off2 + 1;
-
- buf = (char *)malloc (len);
- if (NULL == buf)
- return NULL;
-
- ret = subst (buf, len, string, off1, off2, replacement);
- if (NULL == ret)
- free (buf);
- return ret;
-} /* asubst */
-
-char *subst_string (char *buf, size_t buflen, const char *string,
- const char *needle, const char *replacement)
-{
- char *temp;
- size_t needle_len;
- size_t i;
-
- if ((buf == NULL) || (string == NULL)
- || (needle == NULL) || (replacement == NULL))
- return (NULL);
-
- temp = (char *) malloc (buflen);
- if (temp == NULL)
- {
- ERROR ("subst_string: malloc failed.");
- return (NULL);
- }
-
- needle_len = strlen (needle);
- strncpy (buf, string, buflen);
-
- /* Limit the loop to prevent endless loops. */
- for (i = 0; i < buflen; i++)
- {
- char *begin_ptr;
- size_t begin;
-
- /* Find `needle' in `buf'. */
- begin_ptr = strstr (buf, needle);
- if (begin_ptr == NULL)
- break;
-
- /* Calculate the start offset. */
- begin = begin_ptr - buf;
-
- /* Substitute the region using `subst'. The result is stored in
- * `temp'. */
- begin_ptr = subst (temp, buflen, buf,
- begin, begin + needle_len,
- replacement);
- if (begin_ptr == NULL)
- {
- WARNING ("subst_string: subst failed.");
- break;
- }
-
- /* Copy the new string in `temp' to `buf' for the next round. */
- strncpy (buf, temp, buflen);
- }
-
- if (i >= buflen)
- {
- WARNING ("subst_string: Loop exited after %zu iterations: "
- "string = %s; needle = %s; replacement = %s;",
- i, string, needle, replacement);
- }
-
- sfree (temp);
- return (buf);
-} /* char *subst_string */
-
-/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
-
diff --git a/src/utils_subst.h b/src/utils_subst.h
--- a/src/utils_subst.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/**
- * collectd - src/utils_subst.h
- * Copyright (C) 2008 Sebastian Harl
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Sebastian "tokkee" Harl <sh at tokkee.org>
- **/
-
-/*
- * This module provides functions for string substitution.
- */
-
-#ifndef UTILS_SUBST_H
-#define UTILS_SUBST_H 1
-
-#include <stddef.h>
-
-/*
- * subst:
- *
- * Replace a substring of a string with the specified replacement text. The
- * resulting string is stored in the buffer pointed to by 'buf' of length
- * 'buflen'. Upon success, the buffer will always be null-terminated. The
- * result may be truncated if the buffer is too small.
- *
- * The substring to be replaces is identified by the two offsets 'off1' and
- * 'off2' where 'off1' specifies the offset to the beginning of the substring
- * and 'off2' specifies the offset to the first byte after the substring.
- *
- * The minimum buffer size to store the complete return value (including the
- * terminating '\0' character) thus has to be:
- * off1 + strlen(replacement) + strlen(string) - off2 + 1
- *
- * Example:
- *
- * 01234567890
- * string = "foo_____bar"
- * ^ ^
- * | |
- * off1 off2
- *
- * off1 = 3
- * off2 = 8
- *
- * replacement = " - "
- *
- * -> "foo - bar"
- *
- * The function returns 'buf' on success, NULL else.
- */
-char *subst (char *buf, size_t buflen, const char *string, int off1, int off2,
- const char *replacement);
-
-/*
- * asubst:
- *
- * This function is very similar to subst(). It differs in that it
- * automatically allocates the memory required for the return value which the
- * user then has to free himself.
- *
- * Returns the newly allocated result string on success, NULL else.
- */
-char *asubst (const char *string, int off1, int off2, const char *replacement);
-
-/*
- * subst_string:
- *
- * Works like `subst', but instead of specifying start and end offsets you
- * specify `needle', the string that is to be replaced. If `needle' is found
- * in `string' (using strstr(3)), the offset is calculated and `subst' is
- * called with the determined parameters.
- *
- * If the substring is not found, no error will be indicated and
- * `subst_string' works mostly like `strncpy'.
- *
- * If the substring appears multiple times, all appearances will be replaced.
- * If the substring has been found `buflen' times, an endless loop is assumed
- * and the loop is broken. A warning is printed and the function returns
- * success.
- */
-char *subst_string (char *buf, size_t buflen, const char *string,
- const char *needle, const char *replacement);
-
-#endif /* UTILS_SUBST_H */
-
-/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
-
diff --git a/src/utils_tail.c b/src/utils_tail.c
--- a/src/utils_tail.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/**
- * collectd - src/utils_tail.c
- * Copyright (C) 2007-2008 C-Ware, Inc.
- * Copyright (C) 2008 Florian Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Author:
- * Luke Heberling <lukeh at c-ware.com>
- * Florian Forster <octo at collectd.org>
- *
- * Description:
- * Encapsulates useful code for plugins which must watch for appends to
- * the end of a file.
- **/
-
-#include "collectd.h"
-#include "common.h"
-#include "utils_tail.h"
-
-struct cu_tail_s
-{
- char *file;
- FILE *fh;
- struct stat stat;
-};
-
-static int cu_tail_reopen (cu_tail_t *obj)
-{
- int seek_end = 0;
- FILE *fh;
- struct stat stat_buf;
- int status;
-
- memset (&stat_buf, 0, sizeof (stat_buf));
- status = stat (obj->file, &stat_buf);
- if (status != 0)
- {
- char errbuf[1024];
- ERROR ("utils_tail: stat (%s) failed: %s", obj->file,
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (-1);
- }
-
- /* The file is already open.. */
- if ((obj->fh != NULL) && (stat_buf.st_ino == obj->stat.st_ino))
- {
- /* Seek to the beginning if file was truncated */
- if (stat_buf.st_size < obj->stat.st_size)
- {
- INFO ("utils_tail: File `%s' was truncated.", obj->file);
- status = fseek (obj->fh, 0, SEEK_SET);
- if (status != 0)
- {
- char errbuf[1024];
- ERROR ("utils_tail: fseek (%s) failed: %s", obj->file,
- sstrerror (errno, errbuf, sizeof (errbuf)));
- fclose (obj->fh);
- obj->fh = NULL;
- return (-1);
- }
- }
- memcpy (&obj->stat, &stat_buf, sizeof (struct stat));
- return (1);
- }
-
- /* Seek to the end if we re-open the same file again or the file opened
- * is the first at all or the first after an error */
- if ((obj->stat.st_ino == 0) || (obj->stat.st_ino == stat_buf.st_ino))
- seek_end = 1;
-
- fh = fopen (obj->file, "r");
- if (fh == NULL)
- {
- char errbuf[1024];
- ERROR ("utils_tail: fopen (%s) failed: %s", obj->file,
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (-1);
- }
-
- if (seek_end != 0)
- {
- status = fseek (fh, 0, SEEK_END);
- if (status != 0)
- {
- char errbuf[1024];
- ERROR ("utils_tail: fseek (%s) failed: %s", obj->file,
- sstrerror (errno, errbuf, sizeof (errbuf)));
- fclose (fh);
- return (-1);
- }
- }
-
- if (obj->fh != NULL)
- fclose (obj->fh);
- obj->fh = fh;
- memcpy (&obj->stat, &stat_buf, sizeof (struct stat));
-
- return (0);
-} /* int cu_tail_reopen */
-
-cu_tail_t *cu_tail_create (const char *file)
-{
- cu_tail_t *obj;
-
- obj = (cu_tail_t *) malloc (sizeof (cu_tail_t));
- if (obj == NULL)
- return (NULL);
- memset (obj, '\0', sizeof (cu_tail_t));
-
- obj->file = strdup (file);
- if (obj->file == NULL)
- {
- free (obj);
- return (NULL);
- }
-
- obj->fh = NULL;
-
- return (obj);
-} /* cu_tail_t *cu_tail_create */
-
-int cu_tail_destroy (cu_tail_t *obj)
-{
- if (obj->fh != NULL)
- fclose (obj->fh);
- free (obj->file);
- free (obj);
-
- return (0);
-} /* int cu_tail_destroy */
-
-int cu_tail_readline (cu_tail_t *obj, char *buf, int buflen)
-{
- int status;
-
- if (buflen < 1)
- {
- ERROR ("utils_tail: cu_tail_readline: buflen too small: %i bytes.",
- buflen);
- return (-1);
- }
-
- if (obj->fh == NULL)
- {
- status = cu_tail_reopen (obj);
- if (status < 0)
- return (status);
- }
- assert (obj->fh != NULL);
-
- /* Try to read from the filehandle. If that succeeds, everything appears to
- * be fine and we can return. */
- clearerr (obj->fh);
- if (fgets (buf, buflen, obj->fh) != NULL)
- {
- buf[buflen - 1] = 0;
- return (0);
- }
-
- /* Check if we encountered an error */
- if (ferror (obj->fh) != 0)
- {
- /* Jupp, error. Force `cu_tail_reopen' to reopen the file.. */
- fclose (obj->fh);
- obj->fh = NULL;
- }
- /* else: eof -> check if the file was moved away and reopen the new file if
- * so.. */
-
- status = cu_tail_reopen (obj);
- /* error -> return with error */
- if (status < 0)
- return (status);
- /* file end reached and file not reopened -> nothing more to read */
- else if (status > 0)
- {
- buf[0] = 0;
- return (0);
- }
-
- /* If we get here: file was re-opened and there may be more to read.. Let's
- * try again. */
- if (fgets (buf, buflen, obj->fh) != NULL)
- {
- buf[buflen - 1] = 0;
- return (0);
- }
-
- if (ferror (obj->fh) != 0)
- {
- char errbuf[1024];
- WARNING ("utils_tail: fgets (%s) returned an error: %s", obj->file,
- sstrerror (errno, errbuf, sizeof (errbuf)));
- fclose (obj->fh);
- obj->fh = NULL;
- return (-1);
- }
-
- /* EOf, well, apparently the new file is empty.. */
- buf[0] = 0;
- return (0);
-} /* int cu_tail_readline */
-
-int cu_tail_read (cu_tail_t *obj, char *buf, int buflen, tailfunc_t *callback,
- void *data)
-{
- int status;
-
- while (42)
- {
- size_t len;
-
- status = cu_tail_readline (obj, buf, buflen);
- if (status != 0)
- {
- ERROR ("utils_tail: cu_tail_read: cu_tail_readline "
- "failed.");
- break;
- }
-
- /* check for EOF */
- if (buf[0] == 0)
- break;
-
- len = strlen (buf);
- while (len > 0) {
- if (buf[len - 1] != '\n')
- break;
- buf[len - 1] = '\0';
- len--;
- }
-
- status = callback (data, buf, buflen);
- if (status != 0)
- {
- ERROR ("utils_tail: cu_tail_read: callback returned "
- "status %i.", status);
- break;
- }
- }
-
- return status;
-} /* int cu_tail_read */
diff --git a/src/utils_tail.h b/src/utils_tail.h
--- a/src/utils_tail.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- * collectd - src/utils_tail.h
- * Copyright (C) 2007-2008 C-Ware, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Author:
- * Luke Heberling <lukeh at c-ware.com>
- *
- * DESCRIPTION
- * Facilitates reading information that is appended to a file, taking into
- * account that the file may be rotated and a new file created under the
- * same name.
- **/
-
-#ifndef UTILS_TAIL_H
-#define UTILS_TAIL_H 1
-
-struct cu_tail_s;
-typedef struct cu_tail_s cu_tail_t;
-
-typedef int tailfunc_t(void *data, char *buf, int buflen);
-
-/*
- * NAME
- * cu_tail_create
- *
- * DESCRIPTION
- * Allocates a new tail object..
- *
- * PARAMETERS
- * `file' The name of the file to be tailed.
- */
-cu_tail_t *cu_tail_create (const char *file);
-
-/*
- * cu_tail_destroy
- *
- * Takes a tail object returned by `cu_tail_create' and destroys it, freeing
- * all internal memory.
- *
- * Returns 0 when successful and non-zero otherwise.
- */
-int cu_tail_destroy (cu_tail_t *obj);
-
-/*
- * cu_tail_readline
- *
- * Reads from the file until `buflen' characters are read, a newline
- * character is read, or an eof condition is encountered. `buf' is
- * always null-terminated on successful return and isn't touched when non-zero
- * is returned.
- *
- * You can check if the EOF condition is reached by looking at the buffer: If
- * the length of the string stored in the buffer is zero, EOF occurred.
- * Otherwise at least the newline character will be in the buffer.
- *
- * Returns 0 when successful and non-zero otherwise.
- */
-int cu_tail_readline (cu_tail_t *obj, char *buf, int buflen);
-
-/*
- * cu_tail_readline
- *
- * Reads from the file until eof condition or an error is encountered.
- *
- * Returns 0 when successful and non-zero otherwise.
- */
-int cu_tail_read (cu_tail_t *obj, char *buf, int buflen, tailfunc_t *callback,
- void *data);
-
-#endif /* UTILS_TAIL_H */
diff --git a/src/utils_tail_match.c b/src/utils_tail_match.c
--- a/src/utils_tail_match.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * collectd - src/utils_tail_match.c
- * Copyright (C) 2007-2008 C-Ware, Inc.
- * Copyright (C) 2008 Florian Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Author:
- * Luke Heberling <lukeh at c-ware.com>
- * Florian Forster <octo at collectd.org>
- *
- * Description:
- * Encapsulates useful code to plugins which must parse a log file.
- */
-
-#include "collectd.h"
-#include "common.h"
-#include "plugin.h"
-#include "utils_match.h"
-#include "utils_tail.h"
-#include "utils_tail_match.h"
-
-struct cu_tail_match_simple_s
-{
- char plugin[DATA_MAX_NAME_LEN];
- char plugin_instance[DATA_MAX_NAME_LEN];
- char type[DATA_MAX_NAME_LEN];
- char type_instance[DATA_MAX_NAME_LEN];
- cdtime_t interval;
-};
-typedef struct cu_tail_match_simple_s cu_tail_match_simple_t;
-
-struct cu_tail_match_match_s
-{
- cu_match_t *match;
- void *user_data;
- int (*submit) (cu_match_t *match, void *user_data);
- void (*free) (void *user_data);
-};
-typedef struct cu_tail_match_match_s cu_tail_match_match_t;
-
-struct cu_tail_match_s
-{
- int flags;
- cu_tail_t *tail;
-
- cdtime_t interval;
- cu_tail_match_match_t *matches;
- size_t matches_num;
-};
-
-/*
- * Private functions
- */
-static int simple_submit_match (cu_match_t *match, void *user_data)
-{
- cu_tail_match_simple_t *data = (cu_tail_match_simple_t *) user_data;
- cu_match_value_t *match_value;
- value_list_t vl = VALUE_LIST_INIT;
- value_t values[1];
-
- match_value = (cu_match_value_t *) match_get_user_data (match);
- if (match_value == NULL)
- return (-1);
-
- if ((match_value->ds_type & UTILS_MATCH_DS_TYPE_GAUGE)
- && (match_value->values_num == 0))
- values[0].gauge = NAN;
- else
- values[0] = match_value->value;
-
- vl.values = values;
- vl.values_len = 1;
- sstrncpy (vl.host, hostname_g, sizeof (vl.host));
- sstrncpy (vl.plugin, data->plugin, sizeof (vl.plugin));
- sstrncpy (vl.plugin_instance, data->plugin_instance,
- sizeof (vl.plugin_instance));
- sstrncpy (vl.type, data->type, sizeof (vl.type));
- sstrncpy (vl.type_instance, data->type_instance,
- sizeof (vl.type_instance));
-
- vl.interval = data->interval;
- plugin_dispatch_values (&vl);
-
- if (match_value->ds_type & UTILS_MATCH_DS_TYPE_GAUGE)
- {
- match_value->value.gauge = NAN;
- match_value->values_num = 0;
- }
-
- return (0);
-} /* int simple_submit_match */
-
-static int tail_callback (void *data, char *buf,
- int __attribute__((unused)) buflen)
-{
- cu_tail_match_t *obj = (cu_tail_match_t *) data;
- size_t i;
-
- for (i = 0; i < obj->matches_num; i++)
- match_apply (obj->matches[i].match, buf);
-
- return (0);
-} /* int tail_callback */
-
-/*
- * Public functions
- */
-cu_tail_match_t *tail_match_create (const char *filename)
-{
- cu_tail_match_t *obj;
-
- obj = (cu_tail_match_t *) malloc (sizeof (cu_tail_match_t));
- if (obj == NULL)
- return (NULL);
- memset (obj, '\0', sizeof (cu_tail_match_t));
-
- obj->tail = cu_tail_create (filename);
- if (obj->tail == NULL)
- {
- sfree (obj);
- return (NULL);
- }
-
- return (obj);
-} /* cu_tail_match_t *tail_match_create */
-
-void tail_match_destroy (cu_tail_match_t *obj)
-{
- size_t i;
-
- if (obj == NULL)
- return;
-
- if (obj->tail != NULL)
- {
- cu_tail_destroy (obj->tail);
- obj->tail = NULL;
- }
-
- for (i = 0; i < obj->matches_num; i++)
- {
- cu_tail_match_match_t *match = obj->matches + i;
- if (match->match != NULL)
- {
- match_destroy (match->match);
- match->match = NULL;
- }
-
- if ((match->user_data != NULL)
- && (match->free != NULL))
- (*match->free) (match->user_data);
- match->user_data = NULL;
- }
-
- sfree (obj->matches);
- sfree (obj);
-} /* void tail_match_destroy */
-
-int tail_match_add_match (cu_tail_match_t *obj, cu_match_t *match,
- int (*submit_match) (cu_match_t *match, void *user_data),
- void *user_data,
- void (*free_user_data) (void *user_data))
-{
- cu_tail_match_match_t *temp;
-
- temp = (cu_tail_match_match_t *) realloc (obj->matches,
- sizeof (cu_tail_match_match_t) * (obj->matches_num + 1));
- if (temp == NULL)
- return (-1);
-
- obj->matches = temp;
- obj->matches_num++;
-
- DEBUG ("tail_match_add_match interval %lf", CDTIME_T_TO_DOUBLE(((cu_tail_match_simple_t *)user_data)->interval));
- temp = obj->matches + (obj->matches_num - 1);
-
- temp->match = match;
- temp->user_data = user_data;
- temp->submit = submit_match;
- temp->free = free_user_data;
-
- return (0);
-} /* int tail_match_add_match */
-
-int tail_match_add_match_simple (cu_tail_match_t *obj,
- const char *regex, const char *excluderegex, int ds_type,
- const char *plugin, const char *plugin_instance,
- const char *type, const char *type_instance, const cdtime_t interval)
-{
- cu_match_t *match;
- cu_tail_match_simple_t *user_data;
- int status;
-
- match = match_create_simple (regex, excluderegex, ds_type);
- if (match == NULL)
- return (-1);
-
- user_data = (cu_tail_match_simple_t *) malloc (sizeof (cu_tail_match_simple_t));
- if (user_data == NULL)
- {
- match_destroy (match);
- return (-1);
- }
- memset (user_data, '\0', sizeof (cu_tail_match_simple_t));
-
- sstrncpy (user_data->plugin, plugin, sizeof (user_data->plugin));
- if (plugin_instance != NULL)
- sstrncpy (user_data->plugin_instance, plugin_instance,
- sizeof (user_data->plugin_instance));
-
- sstrncpy (user_data->type, type, sizeof (user_data->type));
- if (type_instance != NULL)
- sstrncpy (user_data->type_instance, type_instance,
- sizeof (user_data->type_instance));
-
- user_data->interval = interval;
-
- status = tail_match_add_match (obj, match, simple_submit_match,
- user_data, free);
-
- if (status != 0)
- {
- match_destroy (match);
- sfree (user_data);
- }
-
- return (status);
-} /* int tail_match_add_match_simple */
-
-int tail_match_read (cu_tail_match_t *obj)
-{
- char buffer[4096];
- int status;
- size_t i;
-
- status = cu_tail_read (obj->tail, buffer, sizeof (buffer), tail_callback,
- (void *) obj);
- if (status != 0)
- {
- ERROR ("tail_match: cu_tail_read failed.");
- return (status);
- }
-
- for (i = 0; i < obj->matches_num; i++)
- {
- cu_tail_match_match_t *lt_match = obj->matches + i;
-
- if (lt_match->submit == NULL)
- continue;
-
- (*lt_match->submit) (lt_match->match, lt_match->user_data);
- }
-
- return (0);
-} /* int tail_match_read */
-
-/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/utils_tail_match.h b/src/utils_tail_match.h
--- a/src/utils_tail_match.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * collectd - src/utils_tail_match.h
- * Copyright (C) 2007-2008 C-Ware, Inc.
- * Copyright (C) 2008 Florian Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Luke Heberling <lukeh at c-ware.com>
- * Florian Forster <octo at collectd.org>
- *
- * Description:
- * `tail_match' uses `utils_tail' and `utils_match' to tail a file and try to
- * match it using several regular expressions. Matches are then passed to
- * user-provided callback functions or default handlers. This should keep all
- * of the parsing logic out of the actual plugin, which only operate with
- * regular expressions.
- */
-
-#include "utils_match.h"
-
-struct cu_tail_match_s;
-typedef struct cu_tail_match_s cu_tail_match_t;
-
-/*
- * NAME
- * tail_match_create
- *
- * DESCRIPTION
- * Allocates, initializes and returns a new `cu_tail_match_t' object.
- *
- * PARAMETERS
- * `filename' The name to read data from.
- *
- * RETURN VALUE
- * Returns NULL upon failure, non-NULL otherwise.
- */
-cu_tail_match_t *tail_match_create (const char *filename);
-
-/*
- * NAME
- * tail_match_destroy
- *
- * DESCRIPTION
- * Releases resources used by the `cu_tail_match_t' object.
- *
- * PARAMETERS
- * The object to destroy.
- */
-void tail_match_destroy (cu_tail_match_t *obj);
-
-/*
- * NAME
- * tail_match_add_match
- *
- * DESCRIPTION
- * Adds a match, in form of a `cu_match_t' object, to the object.
- * After data has been read from the logfile (using utils_tail) the callback
- * function `submit_match' is called with the match object and the user
- * supplied data.
- * Please note that his function is called regardless whether this match
- * matched any lines recently or not.
- * When `tail_match_destroy' is called the `user_data' pointer is freed using
- * the `free_user_data' callback - if it is not NULL.
- * When using this interface the `tail_match' module doesn't dispatch any values
- * itself - all that has to happen in either the match-callbacks or the
- * submit_match callback.
- *
- * RETURN VALUE
- * Zero upon success, non-zero otherwise.
- */
-int tail_match_add_match (cu_tail_match_t *obj, cu_match_t *match,
- int (*submit_match) (cu_match_t *match, void *user_data),
- void *user_data,
- void (*free_user_data) (void *user_data));
-
-/*
- * NAME
- * tail_match_add_match_simple
- *
- * DESCRIPTION
- * A simplified version of `tail_match_add_match'. The regular expressen `regex'
- * must match a number, which is then dispatched according to `ds_type'. See
- * the `match_create_simple' function in utils_match.h for a description how
- * this flag effects calculation of a new value.
- * The values gathered are dispatched by the tail_match module in this case. The
- * passed `plugin', `plugin_instance', `type', and `type_instance' are
- * directly used when submitting these values.
- * With excluderegex it is possible to exlude lines from the match.
- *
- * RETURN VALUE
- * Zero upon success, non-zero otherwise.
- */
-int tail_match_add_match_simple (cu_tail_match_t *obj,
- const char *regex, const char *excluderegex, int ds_type,
- const char *plugin, const char *plugin_instance,
- const char *type, const char *type_instance, const cdtime_t interval);
-
-/*
- * NAME
- * tail_match_read
- *
- * DESCRIPTION
- * This function should be called periodically by plugins. It reads new lines
- * from the logfile using `utils_tail' and tries to match them using all
- * added `utils_match' objects.
- * After all lines have been read and processed, the submit_match callback is
- * called or, in case of tail_match_add_match_simple, the data is dispatched to
- * the daemon directly.
- *
- * RETURN VALUE
- * Zero on success, nonzero on failure.
-*/
-int tail_match_read (cu_tail_match_t *obj);
-
-/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/utils_threshold.c b/src/utils_threshold.c
--- a/src/utils_threshold.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/**
- * collectd - src/utils_threshold.c
- * Copyright (C) 2014 Pierre-Yves Ritschard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Pierre-Yves Ritschard <pyr at spootnik.org>
- **/
-
-#include "collectd.h"
-#include "common.h"
-#include "utils_avltree.h"
-#include "utils_threshold.h"
-
-#include <pthread.h>
-
-/*
- * Exported symbols
- * {{{ */
-c_avl_tree_t *threshold_tree = NULL;
-pthread_mutex_t threshold_lock = PTHREAD_MUTEX_INITIALIZER;
-/* }}} */
-
-/*
- * threshold_t *threshold_get
- *
- * Retrieve one specific threshold configuration. For looking up a threshold
- * matching a value_list_t, see "threshold_search" below. Returns NULL if the
- * specified threshold doesn't exist.
- */
-threshold_t *threshold_get (const char *hostname,
- const char *plugin, const char *plugin_instance,
- const char *type, const char *type_instance)
-{ /* {{{ */
- char name[6 * DATA_MAX_NAME_LEN];
- threshold_t *th = NULL;
-
- format_name (name, sizeof (name),
- (hostname == NULL) ? "" : hostname,
- (plugin == NULL) ? "" : plugin, plugin_instance,
- (type == NULL) ? "" : type, type_instance);
- name[sizeof (name) - 1] = '\0';
-
- if (c_avl_get (threshold_tree, name, (void *) &th) == 0)
- return (th);
- else
- return (NULL);
-} /* }}} threshold_t *threshold_get */
-
-/*
- * threshold_t *threshold_search
- *
- * Searches for a threshold configuration using all the possible variations of
- * "Host", "Plugin" and "Type" blocks. Returns NULL if no threshold could be
- * found.
- * XXX: This is likely the least efficient function in collectd.
- */
-threshold_t *threshold_search (const value_list_t *vl)
-{ /* {{{ */
- threshold_t *th;
-
- if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
- vl->type, vl->type_instance)) != NULL)
- return (th);
- else if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
- vl->type, NULL)) != NULL)
- return (th);
- else if ((th = threshold_get (vl->host, vl->plugin, NULL,
- vl->type, vl->type_instance)) != NULL)
- return (th);
- else if ((th = threshold_get (vl->host, vl->plugin, NULL,
- vl->type, NULL)) != NULL)
- return (th);
- else if ((th = threshold_get (vl->host, "", NULL,
- vl->type, vl->type_instance)) != NULL)
- return (th);
- else if ((th = threshold_get (vl->host, "", NULL,
- vl->type, NULL)) != NULL)
- return (th);
- else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
- vl->type, vl->type_instance)) != NULL)
- return (th);
- else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
- vl->type, NULL)) != NULL)
- return (th);
- else if ((th = threshold_get ("", vl->plugin, NULL,
- vl->type, vl->type_instance)) != NULL)
- return (th);
- else if ((th = threshold_get ("", vl->plugin, NULL,
- vl->type, NULL)) != NULL)
- return (th);
- else if ((th = threshold_get ("", "", NULL,
- vl->type, vl->type_instance)) != NULL)
- return (th);
- else if ((th = threshold_get ("", "", NULL,
- vl->type, NULL)) != NULL)
- return (th);
-
- return (NULL);
-} /* }}} threshold_t *threshold_search */
-
-int ut_search_threshold (const value_list_t *vl, /* {{{ */
- threshold_t *ret_threshold)
-{
- threshold_t *t;
-
- if (vl == NULL)
- return (EINVAL);
-
- /* Is this lock really necessary? */
- pthread_mutex_lock (&threshold_lock);
- t = threshold_search (vl);
- if (t == NULL) {
- pthread_mutex_unlock (&threshold_lock);
- return (ENOENT);
- }
-
- memcpy (ret_threshold, t, sizeof (*ret_threshold));
- pthread_mutex_unlock (&threshold_lock);
-
- ret_threshold->next = NULL;
-
- return (0);
-} /* }}} int ut_search_threshold */
-
-
diff --git a/src/utils_threshold.h b/src/utils_threshold.h
--- a/src/utils_threshold.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * collectd - src/utils_threshold.h
- * Copyright (C) 2014 Pierre-Yves Ritschard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Pierre-Yves Ritschard <pyr at spootnik.org>
- **/
-
-#ifndef UTILS_THRESHOLD_H
-#define UTILS_THRESHOLD_H 1
-
-#define UT_FLAG_INVERT 0x01
-#define UT_FLAG_PERSIST 0x02
-#define UT_FLAG_PERCENTAGE 0x04
-#define UT_FLAG_INTERESTING 0x08
-#define UT_FLAG_PERSIST_OK 0x10
-typedef struct threshold_s
-{
- char host[DATA_MAX_NAME_LEN];
- char plugin[DATA_MAX_NAME_LEN];
- char plugin_instance[DATA_MAX_NAME_LEN];
- char type[DATA_MAX_NAME_LEN];
- char type_instance[DATA_MAX_NAME_LEN];
- char data_source[DATA_MAX_NAME_LEN];
- gauge_t warning_min;
- gauge_t warning_max;
- gauge_t failure_min;
- gauge_t failure_max;
- gauge_t hysteresis;
- unsigned int flags;
- int hits;
- struct threshold_s *next;
-} threshold_t;
-
-extern c_avl_tree_t *threshold_tree;
-extern pthread_mutex_t threshold_lock;
-
-threshold_t *threshold_get (const char *hostname,
- const char *plugin, const char *plugin_instance,
- const char *type, const char *type_instance);
-
-threshold_t *threshold_search (const value_list_t *vl);
-
-int ut_search_threshold (const value_list_t *vl,
- threshold_t *ret_threshold);
-
-#endif /* UTILS_THRESHOLD_H */
-
-/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/utils_time.c b/src/utils_time.c
--- a/src/utils_time.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- * collectd - src/utils_time.c
- * Copyright (C) 2010 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <ff at octo.it>
- **/
-
-#include "collectd.h"
-#include "utils_time.h"
-#include "plugin.h"
-#include "common.h"
-
-#if HAVE_CLOCK_GETTIME
-cdtime_t cdtime (void) /* {{{ */
-{
- int status;
- struct timespec ts = { 0, 0 };
-
- status = clock_gettime (CLOCK_REALTIME, &ts);
- if (status != 0)
- {
- char errbuf[1024];
- ERROR ("cdtime: clock_gettime failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (0);
- }
-
- return (TIMESPEC_TO_CDTIME_T (&ts));
-} /* }}} cdtime_t cdtime */
-#else
-/* Work around for Mac OS X which doesn't have clock_gettime(2). *sigh* */
-cdtime_t cdtime (void) /* {{{ */
-{
- int status;
- struct timeval tv = { 0, 0 };
-
- status = gettimeofday (&tv, /* struct timezone = */ NULL);
- if (status != 0)
- {
- char errbuf[1024];
- ERROR ("cdtime: gettimeofday failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (0);
- }
-
- return (TIMEVAL_TO_CDTIME_T (&tv));
-} /* }}} cdtime_t cdtime */
-#endif
-
-size_t cdtime_to_iso8601 (char *s, size_t max, cdtime_t t) /* {{{ */
-{
- struct timespec t_spec;
- struct tm t_tm;
-
- size_t len;
-
- CDTIME_T_TO_TIMESPEC (t, &t_spec);
- NORMALIZE_TIMESPEC (t_spec);
-
- if (localtime_r ((time_t *)&t_spec.tv_sec, &t_tm) == NULL) {
- char errbuf[1024];
- ERROR ("cdtime_to_iso8601: localtime_r failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (0);
- }
-
- len = strftime (s, max, "%Y-%m-%dT%H:%M:%S", &t_tm);
- if (len == 0)
- return 0;
-
- if (max - len > 2) {
- int n = snprintf (s + len, max - len, ".%09i", (int)t_spec.tv_nsec);
- len += (n < max - len) ? n : max - len;
- }
-
- if (max - len > 3) {
- int n = strftime (s + len, max - len, "%z", &t_tm);
- len += (n < max - len) ? n : max - len;
- }
-
- s[max - 1] = '\0';
- return len;
-} /* }}} size_t cdtime_to_iso8601 */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/utils_time.h b/src/utils_time.h
--- a/src/utils_time.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * collectd - src/utils_time.h
- * Copyright (C) 2010 Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Florian octo Forster <ff at octo.it>
- **/
-
-#ifndef UTILS_TIME_H
-#define UTILS_TIME_H 1
-
-#include "collectd.h"
-
-/*
- * "cdtime_t" is a 64bit unsigned integer. The time is stored at a 2^-30 second
- * resolution, i.e. the most significant 34 bit are used to store the time in
- * seconds, the least significant bits store the sub-second part in something
- * very close to nanoseconds. *The* big advantage of storing time in this
- * manner is that comparing times and calculating differences is as simple as
- * it is with "time_t", i.e. a simple integer comparison / subtraction works.
- */
-/*
- * cdtime_t is defined in "collectd.h" */
-/* typedef uint64_t cdtime_t; */
-
-/* 2^30 = 1073741824 */
-#define TIME_T_TO_CDTIME_T(t) (((cdtime_t) (t)) * 1073741824)
-#define CDTIME_T_TO_TIME_T(t) ((time_t) ((t) / 1073741824))
-
-#define CDTIME_T_TO_DOUBLE(t) (((double) (t)) / 1073741824.0)
-#define DOUBLE_TO_CDTIME_T(d) ((cdtime_t) ((d) * 1073741824.0))
-
-#define MS_TO_CDTIME_T(ms) ((cdtime_t) (((double) (ms)) * 1073741.824))
-#define CDTIME_T_TO_MS(t) ((long) (((double) (t)) / 1073741.824))
-#define US_TO_CDTIME_T(us) ((cdtime_t) (((double) (us)) * 1073.741824))
-#define CDTIME_T_TO_US(t) ((suseconds_t) (((double) (t)) / 1073.741824))
-#define NS_TO_CDTIME_T(ns) ((cdtime_t) (((double) (ns)) * 1.073741824))
-#define CDTIME_T_TO_NS(t) ((long) (((double) (t)) / 1.073741824))
-
-#define CDTIME_T_TO_TIMEVAL(cdt,tvp) do { \
- (tvp)->tv_sec = CDTIME_T_TO_TIME_T (cdt); \
- (tvp)->tv_usec = CDTIME_T_TO_US ((cdt) % 1073741824); \
-} while (0)
-#define TIMEVAL_TO_CDTIME_T(tv) (TIME_T_TO_CDTIME_T ((tv)->tv_sec) \
- + US_TO_CDTIME_T ((tv)->tv_usec))
-
-#define CDTIME_T_TO_TIMESPEC(cdt,tsp) do { \
- (tsp)->tv_sec = CDTIME_T_TO_TIME_T (cdt); \
- (tsp)->tv_nsec = CDTIME_T_TO_NS ((cdt) % 1073741824); \
-} while (0)
-#define TIMESPEC_TO_CDTIME_T(ts) (TIME_T_TO_CDTIME_T ((ts)->tv_sec) \
- + NS_TO_CDTIME_T ((ts)->tv_nsec))
-
-cdtime_t cdtime (void);
-
-/* format a cdtime_t value in ISO 8601 format:
- * returns the number of characters written to the string (not including the
- * terminating null byte or 0 on error; the function ensures that the string
- * is null terminated */
-size_t cdtime_to_iso8601 (char *s, size_t max, cdtime_t t);
-
-#endif /* UTILS_TIME_H */
-/* vim: set sw=2 sts=2 et : */