From: Florian Forster Date: Sat, 20 Sep 2014 04:49:01 +0000 (+0200) Subject: Move collectd daemon files to the src/daemon/ directory. X-Git-Tag: collectd-5.5.0~183 X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=216c6246;p=collectd.git Move collectd daemon files to the src/daemon/ directory. --- diff --git a/configure.ac b/configure.ac index 65e535a6..9dd30c78 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ 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]) @@ -5580,7 +5580,7 @@ AC_SUBST(LCC_VERSION_STRING) 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 340c7928..b3bd26ed 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,12 +2,14 @@ SUBDIRS = libcollectdclient 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}"' @@ -19,78 +21,9 @@ AM_CPPFLAGS += -DPKGDATADIR='"${pkgdatadir}"' 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) @@ -121,7 +54,7 @@ collectdctl_LDADD += libcollectdclient/libcollectdclient.la 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 @@ -148,8 +81,6 @@ aggregation_la_SOURCES = aggregation.c \ 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 @@ -161,8 +92,6 @@ amqp_la_SOURCES = amqp.c \ 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 @@ -171,12 +100,10 @@ apache_la_SOURCES = apache.c 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 @@ -187,8 +114,6 @@ apcups_la_LIBADD = if BUILD_WITH_LIBSOCKET apcups_la_LIBADD += -lsocket endif -collectd_LDADD += "-dlopen" apcups.la -collectd_DEPENDENCIES += apcups.la endif if BUILD_PLUGIN_APPLE_SENSORS @@ -196,8 +121,6 @@ pkglib_LTLIBRARIES += apple_sensors.la 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 @@ -206,8 +129,6 @@ aquaero_la_SOURCES = aquaero.c 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 @@ -217,8 +138,6 @@ ascent_la_LDFLAGS = -module -avoid-version 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 @@ -226,8 +145,6 @@ pkglib_LTLIBRARIES += barometer.la 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 @@ -238,8 +155,6 @@ battery_la_LIBADD = if BUILD_WITH_LIBIOKIT battery_la_LDFLAGS += -framework IOKit endif -collectd_LDADD += "-dlopen" battery.la -collectd_DEPENDENCIES += battery.la endif if BUILD_PLUGIN_BIND @@ -247,26 +162,22 @@ pkglib_LTLIBRARIES += bind.la 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 @@ -277,8 +188,6 @@ contextswitch_la_LIBADD = if BUILD_WITH_PERFSTAT contextswitch_la_LIBADD += -lperfstat endif -collectd_LDADD += "-dlopen" contextswitch.la -collectd_DEPENDENCIES += contextswitch.la endif if BUILD_PLUGIN_CPU @@ -300,24 +209,18 @@ endif 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 @@ -326,12 +229,10 @@ curl_la_SOURCES = curl.c 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 @@ -339,14 +240,12 @@ pkglib_LTLIBRARIES += curl_json.la 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 @@ -356,8 +255,6 @@ curl_xml_la_LDFLAGS = -module -avoid-version 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 @@ -367,21 +264,20 @@ dbi_la_SOURCES = dbi.c \ dbi_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBDBI_CPPFLAGS) dbi_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBDBI_LDFLAGS) dbi_la_LIBADD = $(BUILD_WITH_LIBDBI_LIBS) -collectd_LDADD += "-dlopen" dbi.la -collectd_DEPENDENCIES += dbi.la endif if BUILD_PLUGIN_DF pkglib_LTLIBRARIES += df.la -df_la_SOURCES = df.c 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 = @@ -404,8 +300,6 @@ endif if BUILD_WITH_PERFSTAT disk_la_LIBADD += -lperfstat endif -collectd_LDADD += "-dlopen" disk.la -collectd_DEPENDENCIES += disk.la endif if BUILD_PLUGIN_DNS @@ -413,8 +307,6 @@ pkglib_LTLIBRARIES += dns.la 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 @@ -422,8 +314,6 @@ pkglib_LTLIBRARIES += drbd.la 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 @@ -431,16 +321,12 @@ pkglib_LTLIBRARIES += email.la 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 @@ -450,24 +336,18 @@ exec_la_SOURCES = exec.c \ 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 @@ -476,8 +356,6 @@ gmond_la_SOURCES = gmond.c 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 @@ -488,18 +366,15 @@ hddtemp_la_LIBADD = 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) @@ -522,18 +397,15 @@ iptables_la_SOURCES = iptables.c 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 @@ -543,16 +415,13 @@ if IP_VS_H_NEEDS_KERNEL_CFLAGS 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 @@ -562,8 +431,6 @@ java_la_CPPFLAGS = $(AM_CPPFLAGS) $(JAVA_CPPFLAGS) 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 @@ -572,8 +439,6 @@ load_la_SOURCES = load.c 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) @@ -587,8 +452,6 @@ if BUILD_PLUGIN_LOGFILE 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 @@ -598,16 +461,12 @@ log_logstash_la_CFLAGS = $(AM_CFLAGS) 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 @@ -616,56 +475,43 @@ pkglib_LTLIBRARIES += lvm.la 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 @@ -676,26 +522,21 @@ mbmon_la_LIBADD = 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 @@ -706,8 +547,6 @@ memcached_la_LIBADD = if BUILD_WITH_LIBSOCKET memcached_la_LIBADD += -lsocket endif -collectd_LDADD += "-dlopen" memcached.la -collectd_DEPENDENCIES += memcached.la endif if BUILD_PLUGIN_MEMORY @@ -716,8 +555,6 @@ memory_la_SOURCES = memory.c 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 @@ -733,22 +570,27 @@ memory_la_LIBADD += -lperfstat 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 @@ -757,22 +599,19 @@ mysql_la_SOURCES = mysql.c 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 @@ -781,8 +620,6 @@ netlink_la_SOURCES = netlink.c 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 @@ -800,24 +637,18 @@ network_la_CPPFLAGS += $(GCRYPT_CPPFLAGS) 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 @@ -830,8 +661,6 @@ if BUILD_WITH_LIBCURL 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 @@ -840,8 +669,6 @@ notify_desktop_la_SOURCES = notify_desktop.c 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 @@ -849,8 +676,6 @@ pkglib_LTLIBRARIES += notify_email.la 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 @@ -861,16 +686,12 @@ ntpd_la_LIBADD = 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 @@ -879,8 +700,6 @@ nut_la_SOURCES = nut.c 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 @@ -891,19 +710,16 @@ olsrd_la_LIBADD = 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 @@ -911,8 +727,6 @@ pkglib_LTLIBRARIES += openvpn.la 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 @@ -920,11 +734,9 @@ pkglib_LTLIBRARIES += oracle.la 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 @@ -943,16 +755,12 @@ perl_la_CFLAGS += -Wno-nonnull 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 @@ -961,8 +769,6 @@ pinba_la_SOURCES = pinba.c 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 @@ -971,8 +777,6 @@ ping_la_SOURCES = ping.c 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 @@ -983,16 +787,12 @@ postgresql_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBPQ_CPPFLAGS) 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 @@ -1005,8 +805,6 @@ python_la_CFLAGS += -fno-strict-aliasing -Wno-strict-aliasing 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 @@ -1014,8 +812,6 @@ pkglib_LTLIBRARIES += processes.la processes_la_SOURCES = processes.c processes_la_LDFLAGS = -module -avoid-version processes_la_LIBADD = -collectd_LDADD += "-dlopen" processes.la -collectd_DEPENDENCIES += processes.la if BUILD_WITH_LIBKVM_GETPROCS processes_la_LIBADD += -lkvm endif @@ -1023,10 +819,9 @@ 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 @@ -1035,18 +830,14 @@ redis_la_SOURCES = redis.c 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 @@ -1055,8 +846,6 @@ rrdcached_la_SOURCES = rrdcached.c utils_rrdcreate.c utils_rrdcreate.h rrdcached_la_LDFLAGS = -module -avoid-version rrdcached_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBRRD_CFLAGS) rrdcached_la_LIBADD = $(BUILD_WITH_LIBRRD_LDFLAGS) -collectd_LDADD += "-dlopen" rrdcached.la -collectd_DEPENDENCIES += rrdcached.la endif if BUILD_PLUGIN_RRDTOOL @@ -1065,26 +854,21 @@ rrdtool_la_SOURCES = rrdtool.c utils_rrdcreate.c utils_rrdcreate.h rrdtool_la_LDFLAGS = -module -avoid-version rrdtool_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBRRD_CFLAGS) rrdtool_la_LIBADD = $(BUILD_WITH_LIBRRD_LDFLAGS) -collectd_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 @@ -1093,8 +877,6 @@ sigrok_la_SOURCES = sigrok.c 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 @@ -1110,8 +892,6 @@ endif if BUILD_WITH_LIBPTHREAD snmp_la_LIBADD += -lpthread endif -collectd_LDADD += "-dlopen" snmp.la -collectd_DEPENDENCIES += snmp.la endif if BUILD_PLUGIN_STATSD @@ -1120,8 +900,6 @@ statsd_la_SOURCES = statsd.c \ 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 @@ -1130,8 +908,6 @@ swap_la_SOURCES = swap.c 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 @@ -1155,32 +931,24 @@ if BUILD_PLUGIN_SYSLOG 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 @@ -1188,48 +956,36 @@ pkglib_LTLIBRARIES += tape.la 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 @@ -1237,8 +993,6 @@ pkglib_LTLIBRARIES += tcpconns.la tcpconns_la_SOURCES = tcpconns.c tcpconns_la_LDFLAGS = -module -avoid-version tcpconns_la_LIBADD = -collectd_LDADD += "-dlopen" tcpconns.la -collectd_DEPENDENCIES += tcpconns.la if BUILD_WITH_LIBKVM_NLIST tcpconns_la_LIBADD += -lkvm endif @@ -1248,32 +1002,25 @@ if BUILD_PLUGIN_TEAMSPEAK2 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 @@ -1285,8 +1032,6 @@ tokyotyrant_la_LIBADD = $(BUILD_WITH_LIBTOKYOTYRANT_LIBS) if BUILD_WITH_LIBSOCKET tokyotyrant_la_LIBADD += -lsocket endif -collectd_LDADD += "-dlopen" tokyotyrant.la -collectd_DEPENDENCIES += tokyotyrant.la endif if BUILD_PLUGIN_UNIXSOCK @@ -1300,8 +1045,6 @@ unixsock_la_SOURCES = unixsock.c \ 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 @@ -1316,8 +1059,6 @@ endif if BUILD_WITH_PERFSTAT uptime_la_LIBADD += -lperfstat endif -collectd_LDADD += "-dlopen" uptime.la -collectd_DEPENDENCIES += uptime.la endif if BUILD_PLUGIN_USERS @@ -1330,8 +1071,6 @@ if BUILD_WITH_LIBSTATGRAB 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 @@ -1340,18 +1079,6 @@ uuid_la_SOURCES = uuid.c 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 @@ -1360,43 +1087,34 @@ varnish_la_SOURCES = varnish.c 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 @@ -1405,8 +1123,6 @@ write_graphite_la_SOURCES = write_graphite.c \ 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 @@ -1416,12 +1132,10 @@ write_http_la_SOURCES = write_http.c \ 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 @@ -1433,8 +1147,6 @@ write_kafka_la_SOURCES = write_kafka.c \ 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 @@ -1443,8 +1155,6 @@ write_mongodb_la_SOURCES = write_mongodb.c 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 @@ -1453,8 +1163,6 @@ write_redis_la_SOURCES = write_redis.c 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 @@ -1463,16 +1171,12 @@ write_riemann_la_SOURCES = write_riemann.c write_riemann_threshold.c 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 @@ -1481,8 +1185,6 @@ xmms_la_SOURCES = xmms.c 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 @@ -1500,8 +1202,6 @@ else 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 deleted file mode 100644 index 2e2d821a..00000000 --- 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 - * Alvaro Barcellos - **/ - -#include "collectd.h" -#include "common.h" - -#include "plugin.h" -#include "configfile.h" - -#include -#include -#include - -#include - -#if HAVE_LOCALE_H -# include -#endif - -#if HAVE_STATGRAB_H -# include -#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 Configuration file.\n" - " Default: "CONFIGFILE"\n" - " -t Test config and exit.\n" - " -T Test plugin read and exit.\n" - " -P 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 \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 : ""); - 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 deleted file mode 100644 index 6886c123..00000000 --- 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 - **/ - -#ifndef COLLECTD_H -#define COLLECTD_H - -#if HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#if HAVE_SYS_TYPES_H -# include -#endif -#if HAVE_SYS_STAT_H -# include -#endif -#if STDC_HEADERS -# include -# include -#else -# if HAVE_STDLIB_H -# include -# endif -#endif -#if HAVE_STRING_H -# if !STDC_HEADERS && HAVE_MEMORY_H -# include -# endif -# include -#endif -#if HAVE_STRINGS_H -# include -#endif -#if HAVE_INTTYPES_H -# include -#endif -#if HAVE_STDINT_H -# include -#endif -#if HAVE_UNISTD_H -# include -#endif -#if HAVE_SYS_WAIT_H -# include -#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 -#endif -#if HAVE_FCNTL_H -# include -#endif -#if HAVE_ERRNO_H -# include -#endif -#if HAVE_LIMITS_H -# include -#endif -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif - -#if HAVE_ASSERT_H -# include -#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 -/* #endif NAN_STATIC_DEFAULT*/ -#elif NAN_STATIC_ISOC -# ifndef __USE_ISOC99 -# define DISABLE_ISOC99 1 -# define __USE_ISOC99 1 -# endif /* !defined(__USE_ISOC99) */ -# include -# if DISABLE_ISOC99 -# undef DISABLE_ISOC99 -# undef __USE_ISOC99 -# endif /* DISABLE_ISOC99 */ -/* #endif NAN_STATIC_ISOC */ -#elif NAN_ZERO_ZERO -# include -# 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 , possibly some other Solaris versions do - * this too.. */ -#if HAVE_ENDIAN_H -# include -#elif HAVE_SYS_ISA_DEFS_H -# include -#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 -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# if HAVE_SYS_NDIR_H -# include -# endif -# if HAVE_SYS_DIR_H -# include -# endif -# if HAVE_NDIR_H -# include -# endif -#endif - -#if HAVE_STDARG_H -# include -#endif -#if HAVE_CTYPE_H -# include -#endif -#if HAVE_SYS_PARAM_H -# include -#endif - -#if HAVE_KSTAT_H -# include -#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 deleted file mode 100644 index 5386739f..00000000 --- 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 - * Niki W. Waibel - * Sebastian Harl - * Michał Mirosław -**/ - -#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 -#endif - -#ifdef HAVE_MATH_H -# include -#endif - -/* for getaddrinfo */ -#include -#include -#include - -#if HAVE_NETINET_IN_H -# include -#endif - -/* for ntohl and htonl */ -#if HAVE_ARPA_INET_H -# include -#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 deleted file mode 100644 index 434ed019..00000000 --- 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 - * Niki W. Waibel -**/ - -#ifndef COMMON_H -#define COMMON_H - -#include "collectd.h" -#include "plugin.h" - -#if HAVE_PWD_H -# include -#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 -> - * \n -> - * \r -> - * - * 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 deleted file mode 100644 index 02fd96f6..00000000 --- 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 - * Sebastian tokkee Harl - **/ - -#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 -#endif /* HAVE_WORDEXP_H */ - -#if HAVE_FNMATCH_H -# include -#endif /* HAVE_FNMATCH_H */ - -#if HAVE_LIBGEN_H -# include -#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 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 deleted file mode 100644 index 5bc9b305..00000000 --- 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 - **/ - -#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 - * `' 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 new file mode 100644 index 00000000..c4010779 --- /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 new file mode 100644 index 00000000..2e2d821a --- /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 + * Alvaro Barcellos + **/ + +#include "collectd.h" +#include "common.h" + +#include "plugin.h" +#include "configfile.h" + +#include +#include +#include + +#include + +#if HAVE_LOCALE_H +# include +#endif + +#if HAVE_STATGRAB_H +# include +#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 Configuration file.\n" + " Default: "CONFIGFILE"\n" + " -t Test config and exit.\n" + " -T Test plugin read and exit.\n" + " -P 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 \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 : ""); + 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 new file mode 100644 index 00000000..6886c123 --- /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 + **/ + +#ifndef COLLECTD_H +#define COLLECTD_H + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#endif +#if HAVE_STDINT_H +# include +#endif +#if HAVE_UNISTD_H +# include +#endif +#if HAVE_SYS_WAIT_H +# include +#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 +#endif +#if HAVE_FCNTL_H +# include +#endif +#if HAVE_ERRNO_H +# include +#endif +#if HAVE_LIMITS_H +# include +#endif +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#if HAVE_ASSERT_H +# include +#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 +/* #endif NAN_STATIC_DEFAULT*/ +#elif NAN_STATIC_ISOC +# ifndef __USE_ISOC99 +# define DISABLE_ISOC99 1 +# define __USE_ISOC99 1 +# endif /* !defined(__USE_ISOC99) */ +# include +# if DISABLE_ISOC99 +# undef DISABLE_ISOC99 +# undef __USE_ISOC99 +# endif /* DISABLE_ISOC99 */ +/* #endif NAN_STATIC_ISOC */ +#elif NAN_ZERO_ZERO +# include +# 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 , possibly some other Solaris versions do + * this too.. */ +#if HAVE_ENDIAN_H +# include +#elif HAVE_SYS_ISA_DEFS_H +# include +#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 +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# endif +#endif + +#if HAVE_STDARG_H +# include +#endif +#if HAVE_CTYPE_H +# include +#endif +#if HAVE_SYS_PARAM_H +# include +#endif + +#if HAVE_KSTAT_H +# include +#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 new file mode 100644 index 00000000..5386739f --- /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 + * Niki W. Waibel + * Sebastian Harl + * Michał Mirosław +**/ + +#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 +#endif + +#ifdef HAVE_MATH_H +# include +#endif + +/* for getaddrinfo */ +#include +#include +#include + +#if HAVE_NETINET_IN_H +# include +#endif + +/* for ntohl and htonl */ +#if HAVE_ARPA_INET_H +# include +#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 new file mode 100644 index 00000000..434ed019 --- /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 + * Niki W. Waibel +**/ + +#ifndef COMMON_H +#define COMMON_H + +#include "collectd.h" +#include "plugin.h" + +#if HAVE_PWD_H +# include +#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 -> + * \n -> + * \r -> + * + * 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 new file mode 100644 index 00000000..02fd96f6 --- /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 + * Sebastian tokkee Harl + **/ + +#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 +#endif /* HAVE_WORDEXP_H */ + +#if HAVE_FNMATCH_H +# include +#endif /* HAVE_FNMATCH_H */ + +#if HAVE_LIBGEN_H +# include +#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 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 new file mode 100644 index 00000000..5bc9b305 --- /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 + **/ + +#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 + * `' 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 new file mode 100644 index 00000000..c87b8773 --- /dev/null +++ b/src/daemon/filter_chain.c @@ -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 + **/ + +#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: + * + * + * + * + * Plugin "^mysql$" + * Type "^mysql_command$" + * TypeInstance "^show_" + * + * + * + * + * + * + * Plugin "rrdtool" + * + * + */ +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 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: 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 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 new file mode 100644 index 00000000..2db90dbb --- /dev/null +++ b/src/daemon/filter_chain.h @@ -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 + **/ + +#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 new file mode 100644 index 00000000..d3da9bb5 --- /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 + **/ + +#include "collectd.h" +#include "plugin.h" +#include "meta_data.h" + +#include + +/* + * 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 new file mode 100644 index 00000000..fa48df32 --- /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 + **/ + +#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 new file mode 100644 index 00000000..cd992044 --- /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 + * Sebastian Harl + **/ + +#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 +#endif + +#include + +/* + * 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 " + ".", 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 new file mode 100644 index 00000000..dfc608e8 --- /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 + * Sebastian Harl + **/ + +#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 new file mode 100644 index 00000000..b3cb8cf8 --- /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 + **/ + +#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 new file mode 100644 index 00000000..f375a2fb --- /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 + **/ + +#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 new file mode 100644 index 00000000..04e54032 --- /dev/null +++ b/src/daemon/utils_avltree.c @@ -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 + **/ + +#include "config.h" + +#include +#include +#include +#include + +#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 new file mode 100644 index 00000000..1e0f271f --- /dev/null +++ b/src/daemon/utils_avltree.h @@ -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 + **/ + +#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 new file mode 100644 index 00000000..fe22f211 --- /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 + **/ + +#include "collectd.h" +#include "common.h" +#include "plugin.h" +#include "utils_avltree.h" +#include "utils_cache.h" +#include "meta_data.h" + +#include +#include + +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 new file mode 100644 index 00000000..ea3eb2f4 --- /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 + **/ + +#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 new file mode 100644 index 00000000..61936149 --- /dev/null +++ b/src/daemon/utils_complain.c @@ -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 + * Sebastian tokkee Harl + **/ + +#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 new file mode 100644 index 00000000..390f9616 --- /dev/null +++ b/src/daemon/utils_complain.h @@ -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 + * Sebastian tokkee Harl + **/ + +#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 new file mode 100644 index 00000000..1b5dca73 --- /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 + **/ + +#include +#include +#include +#include +#include + +#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 new file mode 100644 index 00000000..6d71c43a --- /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 + **/ + +#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 new file mode 100644 index 00000000..09c9834d --- /dev/null +++ b/src/daemon/utils_llist.c @@ -0,0 +1,190 @@ +/** + * collectd - src/utils_llist.c + * Copyright (C) 2006 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 + */ + +#include "config.h" + +#include +#include + +#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 new file mode 100644 index 00000000..59bf2e41 --- /dev/null +++ b/src/daemon/utils_llist.h @@ -0,0 +1,66 @@ +/** + * collectd - src/utils_llist.h + * Copyright (C) 2006 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 + */ + +#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 new file mode 100644 index 00000000..5083b05a --- /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 + **/ + +#include "collectd.h" +#include "common.h" +#include "plugin.h" + +#include "utils_match.h" + +#include + +#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 new file mode 100644 index 00000000..a1d10020 --- /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 + **/ + +#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 new file mode 100644 index 00000000..56e65ea5 --- /dev/null +++ b/src/daemon/utils_parse_option.c @@ -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 + **/ + +#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 new file mode 100644 index 00000000..01b73d16 --- /dev/null +++ b/src/daemon/utils_parse_option.h @@ -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 + **/ + +#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 new file mode 100644 index 00000000..b8738458 --- /dev/null +++ b/src/daemon/utils_random.c @@ -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 + **/ + +#include "collectd.h" +#include "utils_time.h" + +#include + +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 new file mode 100644 index 00000000..b05f4c86 --- /dev/null +++ b/src/daemon/utils_random.h @@ -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 + **/ + +/** + * 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 new file mode 100644 index 00000000..2f28eb9b --- /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 + **/ + +/* + * 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 new file mode 100644 index 00000000..9085286a --- /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 + **/ + +/* + * This module provides functions for string substitution. + */ + +#ifndef UTILS_SUBST_H +#define UTILS_SUBST_H 1 + +#include + +/* + * 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 new file mode 100644 index 00000000..fe5dca89 --- /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 + * Florian Forster + * + * 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 new file mode 100644 index 00000000..6fb70133 --- /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 + * + * 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 new file mode 100644 index 00000000..8776ad11 --- /dev/null +++ b/src/daemon/utils_tail_match.c @@ -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 + * Florian Forster + * + * 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 new file mode 100644 index 00000000..0404de2f --- /dev/null +++ b/src/daemon/utils_tail_match.h @@ -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 + * Florian Forster + * + * 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 new file mode 100644 index 00000000..4a8df89d --- /dev/null +++ b/src/daemon/utils_threshold.c @@ -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 + **/ + +#include "collectd.h" +#include "common.h" +#include "utils_avltree.h" +#include "utils_threshold.h" + +#include + +/* + * 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 new file mode 100644 index 00000000..bf097fae --- /dev/null +++ b/src/daemon/utils_threshold.h @@ -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 + **/ + +#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 new file mode 100644 index 00000000..6603c15e --- /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 + **/ + +#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 new file mode 100644 index 00000000..9b08e8e4 --- /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 + **/ + +#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 deleted file mode 100644 index c87b8773..00000000 --- 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 - **/ - -#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: - * - * - * - * - * Plugin "^mysql$" - * Type "^mysql_command$" - * TypeInstance "^show_" - * - * - * - * - * - * - * Plugin "rrdtool" - * - * - */ -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 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: 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 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 deleted file mode 100644 index 2db90dbb..00000000 --- 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 - **/ - -#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/libcollectdclient/Makefile.am b/src/libcollectdclient/Makefile.am index 1d4dff59..2fc3152d 100644 --- a/src/libcollectdclient/Makefile.am +++ b/src/libcollectdclient/Makefile.am @@ -11,7 +11,7 @@ nodist_pkgconfig_DATA = libcollectdclient.pc 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 deleted file mode 100644 index d3da9bb5..00000000 --- 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 - **/ - -#include "collectd.h" -#include "plugin.h" -#include "meta_data.h" - -#include - -/* - * 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 deleted file mode 100644 index fa48df32..00000000 --- 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 - **/ - -#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 deleted file mode 100644 index cd992044..00000000 --- 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 - * Sebastian Harl - **/ - -#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 -#endif - -#include - -/* - * 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 " - ".", 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 deleted file mode 100644 index dfc608e8..00000000 --- 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 - * Sebastian Harl - **/ - -#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 deleted file mode 100644 index b3cb8cf8..00000000 --- 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 - **/ - -#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 deleted file mode 100644 index f375a2fb..00000000 --- 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 - **/ - -#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 deleted file mode 100644 index 04e54032..00000000 --- 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 - **/ - -#include "config.h" - -#include -#include -#include -#include - -#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 deleted file mode 100644 index 1e0f271f..00000000 --- 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 - **/ - -#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 deleted file mode 100644 index fe22f211..00000000 --- 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 - **/ - -#include "collectd.h" -#include "common.h" -#include "plugin.h" -#include "utils_avltree.h" -#include "utils_cache.h" -#include "meta_data.h" - -#include -#include - -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 deleted file mode 100644 index ea3eb2f4..00000000 --- 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 - **/ - -#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 deleted file mode 100644 index 61936149..00000000 --- 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 - * Sebastian tokkee Harl - **/ - -#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 deleted file mode 100644 index 390f9616..00000000 --- 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 - * Sebastian tokkee Harl - **/ - -#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 deleted file mode 100644 index 1b5dca73..00000000 --- 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 - **/ - -#include -#include -#include -#include -#include - -#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 deleted file mode 100644 index 6d71c43a..00000000 --- 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 - **/ - -#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 deleted file mode 100644 index 09c9834d..00000000 --- a/src/utils_llist.c +++ /dev/null @@ -1,190 +0,0 @@ -/** - * collectd - src/utils_llist.c - * Copyright (C) 2006 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 - */ - -#include "config.h" - -#include -#include - -#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 deleted file mode 100644 index 59bf2e41..00000000 --- a/src/utils_llist.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * collectd - src/utils_llist.h - * Copyright (C) 2006 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 - */ - -#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 deleted file mode 100644 index 5083b05a..00000000 --- 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 - **/ - -#include "collectd.h" -#include "common.h" -#include "plugin.h" - -#include "utils_match.h" - -#include - -#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 deleted file mode 100644 index a1d10020..00000000 --- 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 - **/ - -#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 deleted file mode 100644 index 56e65ea5..00000000 --- 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 - **/ - -#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 deleted file mode 100644 index 01b73d16..00000000 --- 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 - **/ - -#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 deleted file mode 100644 index b8738458..00000000 --- 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 - **/ - -#include "collectd.h" -#include "utils_time.h" - -#include - -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 deleted file mode 100644 index b05f4c86..00000000 --- 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 - **/ - -/** - * 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 deleted file mode 100644 index 2f28eb9b..00000000 --- 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 - **/ - -/* - * 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 deleted file mode 100644 index 9085286a..00000000 --- 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 - **/ - -/* - * This module provides functions for string substitution. - */ - -#ifndef UTILS_SUBST_H -#define UTILS_SUBST_H 1 - -#include - -/* - * 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 deleted file mode 100644 index fe5dca89..00000000 --- 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 - * Florian Forster - * - * 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 deleted file mode 100644 index 6fb70133..00000000 --- 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 - * - * 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 deleted file mode 100644 index 8776ad11..00000000 --- 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 - * Florian Forster - * - * 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 deleted file mode 100644 index 0404de2f..00000000 --- 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 - * Florian Forster - * - * 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 deleted file mode 100644 index 4a8df89d..00000000 --- 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 - **/ - -#include "collectd.h" -#include "common.h" -#include "utils_avltree.h" -#include "utils_threshold.h" - -#include - -/* - * 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 deleted file mode 100644 index bf097fae..00000000 --- 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 - **/ - -#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 deleted file mode 100644 index 6603c15e..00000000 --- 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 - **/ - -#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 deleted file mode 100644 index 9b08e8e4..00000000 --- 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 - **/ - -#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 : */