AC_COLLECTD([swap], [disable], [module], [swap statistics])
AC_COLLECTD([tape], [disable], [module], [tape statistics])
AC_COLLECTD([traffic], [disable], [module], [system traffic statistics])
+AC_COLLECTD([unixsock], [disable], [module], [UNIX socket plugin])
AC_COLLECTD([users], [disable], [module], [user count statistics])
AC_COLLECTD([vserver], [disable], [module], [vserver statistics])
AC_COLLECTD([wireless], [disable], [module], [wireless link statistics])
swap . . . . . . . $enable_swap
tape . . . . . . . $enable_tape
traffic . . . . . . $enable_traffic
+ unixsock . . . . . $enable_unixsock
users . . . . . . . $enable_users
vserver . . . . . . $enable_vserver
wireless . . . . . $enable_wireless
endif
sbin_PROGRAMS = collectd
+bin_PROGRAMS = collectd-nagios
collectd_SOURCES = collectd.c collectd.h \
utils_debug.c utils_debug.h \
plugin.c plugin.h \
configfile.c configfile.h
collectd_CPPFLAGS = $(LTDLINCL)
+collectd_CPPFLAGS += -DPREFIX='"${prefix}"'
collectd_CPPFLAGS += -DCONFIGFILE='"${sysconfdir}/${PACKAGE_NAME}.conf"'
collectd_CPPFLAGS += -DPKGLOCALSTATEDIR='"${localstatedir}/lib/${PACKAGE_NAME}"'
if BUILD_FEATURE_DAEMON
collectd_LDADD = $(LIBLTDL) libconfig/libconfig.la "-dlopen" self
collectd_DEPENDENCIES = $(LIBLTDL) libconfig/libconfig.la
+collectd_nagios_SOURCES = collectd-nagios.c
+
pkglib_LTLIBRARIES =
if BUILD_MODULE_APACHE
endif
endif
+if BUILD_MODULE_UNIXSOCK
+pkglib_LTLIBRARIES += unixsock.la
+unixsock_la_SOURCES = unixsock.c
+unixsock_la_LDFLAGS = -module -avoid-version
+if BUILD_WITH_LIBPTHREAD
+unixsock_la_LDFLAGS += -lpthread
+endif
+collectd_LDADD += "-dlopen" unixsock.la
+collectd_DEPENDENCIES += unixsock.la
+endif
+
if BUILD_MODULE_USERS
pkglib_LTLIBRARIES += users.la
users_la_SOURCES = users.c
/**
* collectd - src/battery.c
- * Copyright (C) 2006 Florian octo Forster
+ * Copyright (C) 2006,2007 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * Free Software Foundation; only version 2 of the License is applicable.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
#include "plugin.h"
#include "utils_debug.h"
-#define MODULE_NAME "battery"
-#define BUFSIZE 512
-
#if HAVE_MACH_MACH_TYPES_H
# include <mach/mach_types.h>
#endif
#define INVALID_VALUE 47841.29
-static char *battery_current_file = "battery-%s/current.rrd";
-static char *battery_voltage_file = "battery-%s/voltage.rrd";
-static char *battery_charge_file = "battery-%s/charge.rrd";
+static data_source_t data_source_charge[1] =
+{
+ {"charge", DS_TYPE_GAUGE, 0, NAN}
+};
+
+static data_set_t charge_ds =
+{
+ "charge", 1, data_source_charge
+};
+
+static data_source_t data_source_current[1] =
+{
+ {"current", DS_TYPE_GAUGE, NAN, NAN}
+};
-static char *ds_def_current[] =
+static data_set_t current_ds =
{
- "DS:current:GAUGE:"COLLECTD_HEARTBEAT":U:U",
- NULL
+ "current", 1, data_source_current
};
-static int ds_num_current = 1;
-static char *ds_def_voltage[] =
+static data_source_t data_source_voltage[1] =
{
- "DS:voltage:GAUGE:"COLLECTD_HEARTBEAT":U:U",
- NULL
+ {"voltage", DS_TYPE_GAUGE, NAN, NAN}
};
-static int ds_num_voltage = 1;
-static char *ds_def_charge[] =
+static data_set_t voltage_ds =
{
- "DS:charge:GAUGE:"COLLECTD_HEARTBEAT":0:U",
- NULL
+ "voltage", 1, data_source_voltage
};
-static int ds_num_charge = 1;
+#if BATTERY_HAVE_READ
#if HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H
/* No global variables */
/* #endif HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H */
static char *battery_pmu_file = "/proc/pmu/battery_%i";
#endif /* KERNEL_LINUX */
-static void battery_init (void)
+static int battery_init (void)
{
#if HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H
/* No init neccessary */
#elif KERNEL_LINUX
int len;
- char filename[BUFSIZE];
+ char filename[128];
for (battery_pmu_num = 0; ; battery_pmu_num++)
{
- len = snprintf (filename, BUFSIZE, battery_pmu_file, battery_pmu_num);
+ len = snprintf (filename, sizeof (filename), battery_pmu_file, battery_pmu_num);
- if ((len >= BUFSIZE) || (len < 0))
+ if ((len >= sizeof (filename)) || (len < 0))
break;
if (access (filename, R_OK))
}
#endif /* KERNEL_LINUX */
- return;
-}
-
-static void battery_current_write (char *host, char *inst, char *val)
-{
- char filename[BUFSIZE];
- int len;
-
- len = snprintf (filename, BUFSIZE, battery_current_file, inst);
- if ((len >= BUFSIZE) || (len < 0))
- return;
-
- rrd_update_file (host, filename, val,
- ds_def_current, ds_num_current);
-}
-
-static void battery_voltage_write (char *host, char *inst, char *val)
-{
- char filename[BUFSIZE];
- int len;
-
- len = snprintf (filename, BUFSIZE, battery_voltage_file, inst);
- if ((len >= BUFSIZE) || (len < 0))
- return;
-
- rrd_update_file (host, filename, val,
- ds_def_voltage, ds_num_voltage);
+ return (0);
}
-static void battery_charge_write (char *host, char *inst, char *val)
+static void battery_submit (const char *plugin_instance, const char *type, double value)
{
- char filename[BUFSIZE];
- int len;
-
- len = snprintf (filename, BUFSIZE, battery_charge_file, inst);
- if ((len >= BUFSIZE) || (len < 0))
- return;
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
- rrd_update_file (host, filename, val,
- ds_def_charge, ds_num_charge);
-}
+ values[0].gauge = value;
-#if BATTERY_HAVE_READ
-static void battery_submit (char *inst, double current, double voltage, double charge)
-{
- int len;
- char buffer[BUFSIZE];
+ vl.values = values;
+ vl.values_len = 1;
+ vl.time = time (NULL);
+ strcpy (vl.host, hostname);
+ strcpy (vl.plugin, "battery");
+ strcpy (vl.plugin_instance, plugin_instance);
- if (current != INVALID_VALUE)
- {
- len = snprintf (buffer, BUFSIZE, "N:%.3f", current);
-
- if ((len > 0) && (len < BUFSIZE))
- plugin_submit ("battery_current", inst, buffer);
- }
- else
- {
- plugin_submit ("battery_current", inst, "N:U");
- }
-
- if (voltage != INVALID_VALUE)
- {
- len = snprintf (buffer, BUFSIZE, "N:%.3f", voltage);
-
- if ((len > 0) && (len < BUFSIZE))
- plugin_submit ("battery_voltage", inst, buffer);
- }
- else
- {
- plugin_submit ("battery_voltage", inst, "N:U");
- }
-
- if (charge != INVALID_VALUE)
- {
- len = snprintf (buffer, BUFSIZE, "N:%.3f", charge);
-
- if ((len > 0) && (len < BUFSIZE))
- plugin_submit ("battery_charge", inst, buffer);
- }
- else
- {
- plugin_submit ("battery_charge", inst, "N:U");
- }
-}
+ plugin_dispatch_values (type, &vl);
+} /* void battery_submit */
#if HAVE_IOKIT_PS_IOPOWERSOURCES_H || HAVE_IOKIT_IOKITLIB_H
double dict_get_double (CFDictionaryRef dict, char *key_string)
}
#endif /* HAVE_IOKIT_IOKITLIB_H */
-static void battery_read (void)
+static int battery_read (void)
{
#if HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H
double charge = INVALID_VALUE; /* Current charge in Ah */
if ((charge_rel != INVALID_VALUE) && (charge_abs != INVALID_VALUE))
charge = charge_abs * charge_rel / 100.0;
- if ((charge != INVALID_VALUE)
- || (current != INVALID_VALUE)
- || (voltage != INVALID_VALUE))
- battery_submit ("0", current, voltage, charge);
+ if (charge != INVALID_VALUE)
+ battery_submit ("0", "charge", charge);
+ if (current != INVALID_VALUE)
+ battery_submit ("0", "current", current);
+ if (voltage != INVALID_VALUE)
+ battery_submit ("0", "voltage", voltage);
/* #endif HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H */
#elif KERNEL_LINUX
FILE *fh;
- char buffer[BUFSIZE];
- char filename[BUFSIZE];
+ char buffer[1024];
+ char filename[256];
char *fields[8];
int numfields;
for (i = 0; i < battery_pmu_num; i++)
{
- char batnum_str[BUFSIZE];
+ char batnum_str[256];
double current = INVALID_VALUE;
double voltage = INVALID_VALUE;
double charge = INVALID_VALUE;
double *valptr = NULL;
- len = snprintf (filename, BUFSIZE, battery_pmu_file, i);
- if ((len >= BUFSIZE) || (len < 0))
+ len = snprintf (filename, sizeof (filename), battery_pmu_file, i);
+ if ((len >= sizeof (filename)) || (len < 0))
continue;
- len = snprintf (batnum_str, BUFSIZE, "%i", i);
- if ((len >= BUFSIZE) || (len < 0))
+ len = snprintf (batnum_str, sizeof (batnum_str), "%i", i);
+ if ((len >= sizeof (batnum_str)) || (len < 0))
continue;
if ((fh = fopen (filename, "r")) == NULL)
continue;
- while (fgets (buffer, BUFSIZE, fh) != NULL)
+ while (fgets (buffer, sizeof (buffer), fh) != NULL)
{
numfields = strsplit (buffer, fields, 8);
}
}
- if ((current != INVALID_VALUE)
- || (voltage != INVALID_VALUE)
- || (charge != INVALID_VALUE))
- battery_submit (batnum_str, current, voltage, charge);
-
fclose (fh);
fh = NULL;
+
+ if (charge != INVALID_VALUE)
+ battery_submit ("0", "charge", charge);
+ if (current != INVALID_VALUE)
+ battery_submit ("0", "current", current);
+ if (voltage != INVALID_VALUE)
+ battery_submit ("0", "voltage", voltage);
}
if (access ("/proc/acpi/battery", R_OK | X_OK) == 0)
if ((dh = opendir ("/proc/acpi/battery")) == NULL)
{
syslog (LOG_ERR, "Cannot open `/proc/acpi/battery': %s", strerror (errno));
- return;
+ return (-1);
}
while ((ent = readdir (dh)) != NULL)
if (ent->d_name[0] == '.')
continue;
- len = snprintf (filename, BUFSIZE, "/proc/acpi/battery/%s/state", ent->d_name);
- if ((len >= BUFSIZE) || (len < 0))
+ len = snprintf (filename, sizeof (filename),
+ "/proc/acpi/battery/%s/state",
+ ent->d_name);
+ if ((len >= sizeof (filename)) || (len < 0))
continue;
if ((fh = fopen (filename, "r")) == NULL)
* [11:00] <@tokkee> remaining capacity: 4136 mAh
* [11:00] <@tokkee> present voltage: 12428 mV
*/
- while (fgets (buffer, BUFSIZE, fh) != NULL)
+ while (fgets (buffer, sizeof (buffer), fh) != NULL)
{
numfields = strsplit (buffer, fields, 8);
if ((fields[2] == endptr) || (errno != 0))
*valptr = INVALID_VALUE;
}
- }
+ } /* while (fgets (buffer, sizeof (buffer), fh) != NULL) */
+
+ fclose (fh);
if ((current != INVALID_VALUE) && (charging == 0))
current *= -1;
- if ((current != INVALID_VALUE)
- || (voltage != INVALID_VALUE)
- || (charge != INVALID_VALUE))
- battery_submit (ent->d_name, current, voltage, charge);
-
- fclose (fh);
+ if (charge != INVALID_VALUE)
+ battery_submit ("0", "charge", charge);
+ if (current != INVALID_VALUE)
+ battery_submit ("0", "current", current);
+ if (voltage != INVALID_VALUE)
+ battery_submit ("0", "voltage", voltage);
}
closedir (dh);
}
#endif /* KERNEL_LINUX */
+
+ return (0);
}
-#else
-# define battery_read NULL
#endif /* BATTERY_HAVE_READ */
void module_register (void)
{
- plugin_register (MODULE_NAME, battery_init, battery_read, NULL);
- plugin_register ("battery_current", NULL, NULL, battery_current_write);
- plugin_register ("battery_voltage", NULL, NULL, battery_voltage_write);
- plugin_register ("battery_charge", NULL, NULL, battery_charge_write);
-}
+ plugin_register_data_set (&charge_ds);
+ plugin_register_data_set (¤t_ds);
+ plugin_register_data_set (&voltage_ds);
-#undef BUFSIZE
-#undef MODULE_NAME
+#if BATTERY_HAVE_READ
+ plugin_register_init ("battery", battery_init);
+ plugin_register_read ("battery", battery_read);
+#endif /* BATTERY_HAVE_READ */
+}
--- /dev/null
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+/*
+ * This weird macro cascade forces the glibc to define `NAN'. I don't know
+ * another way to solve this, so more intelligent solutions are welcome. -octo
+ */
+#ifndef __USE_ISOC99
+# define DISABLE__USE_ISOC99 1
+# define __USE_ISOC99 1
+#endif
+#include <math.h>
+#ifdef DISABLE__USE_ISOC99
+# undef DISABLE__USE_ISOC99
+# undef __USE_ISOC99
+#endif
+
+#define RET_OKAY 0
+#define RET_WARNING 1
+#define RET_CRITICAL 2
+#define RET_UNKNOWN 3
+
+#define CON_NONE 0
+#define CON_AVERAGE 1
+#define CON_SUM 2
+
+struct range_s
+{
+ double min;
+ double max;
+ int invert;
+};
+typedef struct range_s range_t;
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+
+static char *socket_file_g = NULL;
+static char *value_string_g = NULL;
+static char *hostname_g = NULL;
+
+static range_t range_critical_g;
+static range_t range_warning_g;
+static int consolitation_g = CON_NONE;
+
+static char **match_ds_g = NULL;
+static int match_ds_num_g = 0;
+
+static int ignore_ds (const char *name)
+{
+ int i;
+
+ if (match_ds_g == NULL)
+ return (0);
+
+ for (i = 0; i < match_ds_num_g; i++)
+ if (strcasecmp (match_ds_g[i], name) == 0)
+ return (0);
+
+ return (1);
+} /* int ignore_ds */
+
+static void parse_range (char *string, range_t *range)
+{
+ char *min_ptr;
+ char *max_ptr;
+
+ if (*string == '@')
+ {
+ range->invert = 1;
+ string++;
+ }
+
+ max_ptr = strchr (string, ':');
+ if (max_ptr == NULL)
+ {
+ min_ptr = NULL;
+ max_ptr = string;
+ }
+ else
+ {
+ min_ptr = string;
+ *max_ptr = '\0';
+ max_ptr++;
+ }
+
+ assert (max_ptr != NULL);
+
+ /* `10' == `0:10' */
+ if (min_ptr == NULL)
+ range->min = 0.0;
+ /* :10 == ~:10 == -inf:10 */
+ else if ((*min_ptr == '\0') || (*min_ptr == '~'))
+ range->min = NAN;
+ else
+ range->min = atof (min_ptr);
+
+ if ((*max_ptr == '\0') || (*max_ptr == '~'))
+ range->max = NAN;
+ else
+ range->max = atof (max_ptr);
+} /* void parse_range */
+
+int match_range (range_t *range, double value)
+{
+ int ret = 0;
+
+ if ((range->min != NAN) && (range->min > value))
+ ret = 1;
+ if ((range->max != NAN) && (range->max < value))
+ ret = 1;
+
+ return (((ret - range->invert) == 0) ? 0 : 1);
+}
+
+static int get_values (int *ret_values_num, double **ret_values,
+ char ***ret_values_names)
+{
+ struct sockaddr_un sa;
+ int status;
+ int fd;
+ FILE *fh;
+ char buffer[4096];
+
+ int values_num;
+ double *values;
+ char **values_names;
+
+ int i;
+
+ fd = socket (PF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0)
+ {
+ fprintf (stderr, "socket failed: %s\n",
+ strerror (errno));
+ return (-1);
+ }
+
+ memset (&sa, '\0', sizeof (sa));
+ sa.sun_family = AF_UNIX;
+ strncpy (sa.sun_path, socket_file_g,
+ sizeof (sa.sun_path) - 1);
+
+ status = connect (fd, (struct sockaddr *) &sa, sizeof (sa));
+ if (status != 0)
+ {
+ fprintf (stderr, "connect failed: %s\n",
+ strerror (errno));
+ return (-1);
+ }
+
+ fh = fdopen (fd, "r+");
+ if (fh == NULL)
+ {
+ fprintf (stderr, "fdopen failed: %s\n",
+ strerror (errno));
+ close (fd);
+ return (-1);
+ }
+
+ fprintf (fh, "GETVAL %s/%s\n", hostname_g, value_string_g);
+ fflush (fh);
+
+ if (fgets (buffer, sizeof (buffer), fh) == NULL)
+ {
+ fprintf (stderr, "fgets failed: %s\n",
+ strerror (errno));
+ close (fd);
+ return (-1);
+ }
+ close (fd); fd = -1;
+
+ values_num = atoi (buffer);
+ if (values_num < 1)
+ return (-1);
+
+ values = (double *) malloc (values_num * sizeof (double));
+ if (values == NULL)
+ {
+ fprintf (stderr, "malloc failed: %s\n",
+ strerror (errno));
+ return (-1);
+ }
+
+ values_names = (char **) malloc (values_num * sizeof (char *));
+ if (values_names == NULL)
+ {
+ fprintf (stderr, "malloc failed: %s\n",
+ strerror (errno));
+ free (values);
+ return (-1);
+ }
+
+ {
+ char *ptr = strchr (buffer, ' ') + 1;
+ char *key;
+ char *value;
+
+ i = 0;
+ while ((key = strtok (ptr, " \t")) != NULL)
+ {
+ ptr = NULL;
+ value = strchr (key, '=');
+ if (value == NULL)
+ continue;
+ *value = '\0'; value++;
+
+ if (ignore_ds (key) != 0)
+ continue;
+
+ values_names[i] = strdup (key);
+ values[i] = atof (value);
+
+ i++;
+ if (i >= values_num)
+ break;
+ }
+ values_num = i;
+ }
+
+ *ret_values_num = values_num;
+ *ret_values = values;
+ *ret_values_names = values_names;
+
+ return (0);
+} /* int get_values */
+
+static void usage (const char *name)
+{
+ fprintf (stderr, "Usage: %s <-s socket> <-n value_spec> <-H hostname> [options]\n"
+ "\n"
+ "Valid options are:\n"
+ " -s <socket> Path to collectd's UNIX-socket.\n"
+ " -n <v_spec> Value specification to get from collectd.\n"
+ " Format: `plugin-instance/type-instance'\n"
+ " -d <ds> Select the DS to examine. May be repeated to examine multiple\n"
+ " DSes. By default all DSes are used.\n"
+ " -g <consol> Method to use to consolidate several DSes.\n"
+ " Valid arguments are `none', `average' and `sum'\n"
+ " -H <host> Hostname to query the values for.\n"
+ " -c <range> Critical range\n"
+ " -w <range> Warning range\n"
+ "\n"
+ "Consolidation functions:\n"
+ " none: Apply the warning- and critical-ranges to each data-source\n"
+ " individually.\n"
+ " average: Calculate the average of all matching DSes and apply the\n"
+ " warning- and critical-ranges to the calculated average.\n"
+ " sum: Apply the ranges to the sum of all DSes.\n"
+ "\n", name);
+ exit (1);
+} /* void usage */
+
+int do_check_con_none (int values_num, double *values, char **values_names)
+{
+ int i;
+
+ int num_critical = 0;
+ int num_warning = 0;
+ int num_okay = 0;
+
+ for (i = 0; i < values_num; i++)
+ {
+ if (values[i] == NAN)
+ num_warning++;
+ else if (match_range (&range_critical_g, values[i]) != 0)
+ num_critical++;
+ else if (match_range (&range_warning_g, values[i]) != 0)
+ num_warning++;
+ else
+ num_okay++;
+ }
+
+ if ((num_critical != 0) || (values_num == 0))
+ {
+ printf ("CRITICAL: %i critical, %i warning, %i okay\n",
+ num_critical, num_warning, num_okay);
+ return (RET_CRITICAL);
+ }
+ else if (num_warning != 0)
+ {
+ printf ("WARNING: %i warning, %i okay\n",
+ num_warning, num_okay);
+ return (RET_WARNING);
+ }
+ else
+ {
+ printf ("OKAY: %i okay\n", num_okay);
+ return (RET_OKAY);
+ }
+
+ return (RET_UNKNOWN);
+} /* int do_check_con_none */
+
+int do_check_con_average (int values_num, double *values, char **values_names)
+{
+ int i;
+ double total;
+ int total_num;
+
+ total = 0.0;
+ total_num = 0;
+ for (i = 0; i < values_num; i++)
+ {
+ if (values[i] != NAN)
+ {
+ total += values[i];
+ total_num++;
+ }
+ }
+
+ if (total_num == 0)
+ {
+ printf ("WARNING: No defined values found\n");
+ return (RET_WARNING);
+ }
+
+ if (match_range (&range_critical_g, total / total_num) != 0)
+ {
+ printf ("CRITICAL: Average = %lf\n",
+ (double) (total / total_num));
+ return (RET_CRITICAL);
+ }
+ else if (match_range (&range_warning_g, total / total_num) != 0)
+ {
+ printf ("WARNING: Average = %lf\n",
+ (double) (total / total_num));
+ return (RET_WARNING);
+ }
+ else
+ {
+ printf ("OKAY: Average = %lf\n",
+ (double) (total / total_num));
+ return (RET_OKAY);
+ }
+
+ return (RET_UNKNOWN);
+} /* int do_check_con_average */
+
+int do_check_con_sum (int values_num, double *values, char **values_names)
+{
+ int i;
+ double total;
+ int total_num;
+
+ total = 0.0;
+ total_num = 0;
+ for (i = 0; i < values_num; i++)
+ {
+ if (values[i] != NAN)
+ {
+ total += values[i];
+ total_num++;
+ }
+ }
+
+ if (total_num == 0)
+ {
+ printf ("WARNING: No defined values found\n");
+ return (RET_WARNING);
+ }
+
+ if (match_range (&range_critical_g, total) != 0)
+ {
+ printf ("CRITICAL: Sum = %lf\n", total);
+ return (RET_CRITICAL);
+ }
+ else if (match_range (&range_warning_g, total) != 0)
+ {
+ printf ("WARNING: Sum = %lf\n", total);
+ return (RET_WARNING);
+ }
+ else
+ {
+ printf ("OKAY: Sum = %lf\n", total);
+ return (RET_OKAY);
+ }
+
+ return (RET_UNKNOWN);
+} /* int do_check_con_sum */
+
+int do_check (void)
+{
+ double *values;
+ char **values_names;
+ int values_num;
+
+ if (get_values (&values_num, &values, &values_names) != 0)
+ {
+ fputs ("ERROR: Cannot get values from daemon\n", stdout);
+ return (RET_CRITICAL);
+ }
+
+ if (consolitation_g == CON_NONE)
+ return (do_check_con_none (values_num, values, values_names));
+ else if (consolitation_g == CON_AVERAGE)
+ return (do_check_con_average (values_num, values, values_names));
+ else if (consolitation_g == CON_SUM)
+ return (do_check_con_sum (values_num, values, values_names));
+
+ free (values);
+ free (values_names);
+
+ return (RET_UNKNOWN);
+}
+
+int main (int argc, char **argv)
+{
+ range_critical_g.min = NAN;
+ range_critical_g.max = NAN;
+ range_critical_g.invert = 0;
+
+ range_warning_g.min = NAN;
+ range_warning_g.max = NAN;
+ range_warning_g.invert = 0;
+
+ while (42)
+ {
+ int c;
+
+ c = getopt (argc, argv, "w:c:s:n:H:g:d:h");
+ if (c < 0)
+ break;
+
+ switch (c)
+ {
+ case 'c':
+ parse_range (optarg, &range_critical_g);
+ break;
+ case 'w':
+ parse_range (optarg, &range_warning_g);
+ break;
+ case 's':
+ socket_file_g = optarg;
+ break;
+ case 'n':
+ value_string_g = optarg;
+ break;
+ case 'H':
+ hostname_g = optarg;
+ break;
+ case 'g':
+ if (strcasecmp (optarg, "none") == 0)
+ consolitation_g = CON_NONE;
+ else if (strcasecmp (optarg, "average") == 0)
+ consolitation_g = CON_AVERAGE;
+ else if (strcasecmp (optarg, "sum") == 0)
+ consolitation_g = CON_SUM;
+ else
+ usage (argv[0]);
+ break;
+ case 'd':
+ {
+ char **tmp;
+ tmp = (char **) realloc (match_ds_g,
+ (match_ds_num_g + 1)
+ * sizeof (char *));
+ if (tmp == NULL)
+ {
+ fprintf (stderr, "realloc failed: %s\n",
+ strerror (errno));
+ return (RET_UNKNOWN);
+ }
+ match_ds_g = tmp;
+ match_ds_g[match_ds_num_g] = strdup (optarg);
+ if (match_ds_g[match_ds_num_g] == NULL)
+ {
+ fprintf (stderr, "strdup failed: %s\n",
+ strerror (errno));
+ return (RET_UNKNOWN);
+ }
+ match_ds_num_g++;
+ break;
+ }
+ default:
+ usage (argv[0]);
+ } /* switch (c) */
+ }
+
+ if ((socket_file_g == NULL) || (value_string_g == NULL)
+ || (hostname_g == NULL))
+ usage (argv[0]);
+
+ return (do_check ());
+} /* int main */
# define CPU_HAVE_READ 0
#endif
-static data_source_t dsrc[5] =
+static data_source_t dsrc[1] =
{
- {"user", DS_TYPE_COUNTER, 0, 4294967295.0},
- {"nice", DS_TYPE_COUNTER, 0, 4294967295.0},
- {"syst", DS_TYPE_COUNTER, 0, 4294967295.0},
- {"idle", DS_TYPE_COUNTER, 0, 4294967295.0},
- {"wait", DS_TYPE_COUNTER, 0, 4294967295.0}
+ {"value", DS_TYPE_COUNTER, 0, 4294967295.0}
};
static data_set_t ds =
{
- "cpu", 5, dsrc
+ "cpu", 1, dsrc
};
#if CPU_HAVE_READ
return (0);
} /* int init */
-static void submit (int cpu_num, unsigned long long user,
- unsigned long long nice, unsigned long long syst,
- unsigned long long idle, unsigned long long wait)
+static void submit (int cpu_num, const char *type_instance, counter_t value)
{
- value_t values[5];
+ value_t values[1];
value_list_t vl = VALUE_LIST_INIT;
- values[0].counter = user;
- values[1].counter = nice;
- values[2].counter = syst;
- values[3].counter = idle;
- values[4].counter = wait;
+ values[0].counter = value;
vl.values = values;
- vl.values_len = 2;
+ vl.values_len = 1;
vl.time = time (NULL);
strcpy (vl.host, hostname);
strcpy (vl.plugin, "cpu");
- strcpy (vl.plugin_instance, "");
- snprintf (vl.type_instance, sizeof (vl.type_instance),
+ snprintf (vl.plugin_instance, sizeof (vl.type_instance),
"%i", cpu_num);
- vl.type_instance[DATA_MAX_NAME_LEN - 1] = '\0';
+ vl.plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
+ strcpy (vl.type_instance, type_instance);
plugin_dispatch_values ("cpu", &vl);
}
continue;
}
- submit (cpu, cpu_info.cpu_ticks[CPU_STATE_USER],
- cpu_info.cpu_ticks[CPU_STATE_NICE],
- cpu_info.cpu_ticks[CPU_STATE_SYSTEM],
- cpu_info.cpu_ticks[CPU_STATE_IDLE],
- 0ULL);
+ submit (cpu, "user", (counter_t) cpu_info.cpu_ticks[CPU_STATE_USER]);
+ submit (cpu, "nice", (counter_t) cpu_info.cpu_ticks[CPU_STATE_USER]);
+ submit (cpu, "system", (counter_t) cpu_info.cpu_ticks[CPU_STATE_USER]);
+ submit (cpu, "idle", (counter_t) cpu_info.cpu_ticks[CPU_STATE_USER]);
#endif /* PROCESSOR_CPU_LOAD_INFO */
#if PROCESSOR_TEMPERATURE
/*
#elif defined(KERNEL_LINUX)
int cpu;
- unsigned long long user, nice, syst, idle;
- unsigned long long wait, intr, sitr; /* sitr == soft interrupt */
+ counter_t user, nice, syst, idle;
+ counter_t wait, intr, sitr; /* sitr == soft interrupt */
FILE *fh;
char buf[1024];
syst = atoll (fields[3]);
idle = atoll (fields[4]);
+ submit (cpu, "user", user);
+ submit (cpu, "nice", nice);
+ submit (cpu, "system", syst);
+ submit (cpu, "idle", idle);
+
if (numfields >= 8)
{
wait = atoll (fields[5]);
intr = atoll (fields[6]);
sitr = atoll (fields[7]);
- /* I doubt anyone cares about the time spent in
- * interrupt handlers.. */
- syst += intr + sitr;
- }
- else
- {
- wait = 0LL;
+ submit (cpu, "wait", wait);
+ submit (cpu, "interrupt", intr);
+ submit (cpu, "softirq", sitr);
}
-
- submit (cpu, user, nice, syst, idle, wait);
}
fclose (fh);
#elif defined(HAVE_LIBKSTAT)
int cpu;
- unsigned long long user, syst, idle, wait;
+ counter_t user, syst, idle, wait;
static cpu_stat_t cs;
if (kc == NULL)
if (kstat_read (kc, ksp[cpu], &cs) == -1)
continue; /* error message? */
- idle = (unsigned long long) cs.cpu_sysinfo.cpu[CPU_IDLE];
- user = (unsigned long long) cs.cpu_sysinfo.cpu[CPU_USER];
- syst = (unsigned long long) cs.cpu_sysinfo.cpu[CPU_KERNEL];
- wait = (unsigned long long) cs.cpu_sysinfo.cpu[CPU_WAIT];
+ idle = (counter_t) cs.cpu_sysinfo.cpu[CPU_IDLE];
+ user = (counter_t) cs.cpu_sysinfo.cpu[CPU_USER];
+ syst = (counter_t) cs.cpu_sysinfo.cpu[CPU_KERNEL];
+ wait = (counter_t) cs.cpu_sysinfo.cpu[CPU_WAIT];
- submit (ksp[cpu]->ks_instance,
- user, 0LL, syst, idle, wait);
+ submit (ksp[cpu]->ks_instance, "user", user);
+ submit (ksp[cpu]->ks_instance, "system", syst);
+ submit (ksp[cpu]->ks_instance, "idle", idle);
+ submit (ksp[cpu]->ks_instance, "wait", wait);
}
/* #endif defined(HAVE_LIBKSTAT) */
cpuinfo[CP_SYS] += cpuinfo[CP_INTR];
- /* FIXME: Instance is always `0' */
- submit (0, cpuinfo[CP_USER], cpuinfo[CP_NICE], cpuinfo[CP_SYS], cpuinfo[CP_IDLE], 0LL);
+ submit (0, "user", cpuinfo[CP_USER]);
+ submit (0, "nice", cpuinfo[CP_NICE]);
+ submit (0, "system", cpuinfo[CP_SYS]);
+ submit (0, "idle", cpuinfo[CP_IDLE]);
#endif
return (0);
/**
* collectd - src/cpufreq.c
- * Copyright (C) 2005,2006 Peter Holik
+ * Copyright (C) 2005-2007 Peter Holik
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
# define CPUFREQ_HAVE_READ 0
#endif
-static char *cpufreq_file = "cpufreq-%s.rrd";
+static data_source_t data_source[1] =
+{
+ {"value", DS_TYPE_GAUGE, 0, NAN}
+};
-static char *ds_def[] =
+static data_set_t data_set =
{
- "DS:value:GAUGE:"COLLECTD_HEARTBEAT":0:U",
- NULL
+ "cpufreq", 1, data_source
};
-static int ds_num = 1;
+#if CPUFREQ_HAVE_READ
#ifdef KERNEL_LINUX
static int num_cpu = 0;
#endif
-#define BUFSIZE 256
-
-static void cpufreq_init (void)
+static int cpufreq_init (void)
{
#ifdef KERNEL_LINUX
int status;
- char filename[BUFSIZE];
+ char filename[256];
num_cpu = 0;
while (1)
{
- status = snprintf (filename, BUFSIZE, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", num_cpu);
- if (status < 1 || status >= BUFSIZE)
+ status = snprintf (filename, sizeof (filename),
+ "/sys/devices/system/cpu/cpu%d/cpufreq/"
+ "scaling_cur_freq", num_cpu);
+ if (status < 1 || status >= sizeof (filename))
break;
- if (access(filename, R_OK))
+ if (access (filename, R_OK))
break;
num_cpu++;
}
- syslog (LOG_INFO, MODULE_NAME" found %d cpu(s)", num_cpu);
+ syslog (LOG_INFO, "cpufreq plugin: Found %d CPU%s", num_cpu,
+ (num_cpu == 1) ? "" : "s");
+
+ if (num_cpu == 0)
+ plugin_unregister_read ("cpufreq");
#endif /* defined(KERNEL_LINUX) */
- return;
-}
+ return (0);
+} /* int cpufreq_init */
-static void cpufreq_write (char *host, char *inst, char *val)
+static void cpufreq_submit (int cpu_num, double value)
{
- int status;
- char file[BUFSIZE];
-
- status = snprintf (file, BUFSIZE, cpufreq_file, inst);
- if (status < 1 || status >= BUFSIZE)
- return;
-
- rrd_update_file (host, file, val, ds_def, ds_num);
-}
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
-#if CPUFREQ_HAVE_READ
-static void cpufreq_submit (int cpu_num, unsigned long long val)
-{
- char buf[BUFSIZE];
- char cpu[16];
+ values[0].gauge = value;
- if (snprintf (buf, BUFSIZE, "%u:%llu", (unsigned int) curtime, val) >= BUFSIZE)
- return;
- snprintf (cpu, 16, "%i", cpu_num);
+ vl.values = values;
+ vl.values_len = 1;
+ vl.time = time (NULL);
+ strcpy (vl.host, hostname);
+ strcpy (vl.plugin, "cpufreq");
+ snprintf (vl.type_instance, sizeof (vl.type_instance),
+ "%i", cpu_num);
- plugin_submit (MODULE_NAME, cpu, buf);
+ plugin_dispatch_values ("cpufreq", &vl);
}
-static void cpufreq_read (void)
+static int cpufreq_read (void)
{
#ifdef KERNEL_LINUX
int status;
unsigned long long val;
int i = 0;
FILE *fp;
- char filename[BUFSIZE];
+ char filename[256];
char buffer[16];
for (i = 0; i < num_cpu; i++)
{
- status = snprintf (filename, BUFSIZE, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", i);
- if (status < 1 || status >= BUFSIZE)
- return;
+ status = snprintf (filename, sizeof (filename),
+ "/sys/devices/system/cpu/cpu%d/cpufreq/"
+ "scaling_cur_freq", i);
+ if (status < 1 || status >= sizeof (filename))
+ return (-1);
if ((fp = fopen (filename, "r")) == NULL)
{
syslog (LOG_WARNING, "cpufreq: fopen: %s", strerror (errno));
- return;
+ return (-1);
}
if (fgets (buffer, 16, fp) == NULL)
{
syslog (LOG_WARNING, "cpufreq: fgets: %s", strerror (errno));
fclose (fp);
- return;
+ return (-1);
}
if (fclose (fp))
}
#endif /* defined(KERNEL_LINUX) */
- return;
-}
-#else
-#define cpufreq_read NULL
-#endif
+ return (0);
+} /* int cpufreq_read */
+#endif /* CPUFREQ_HAVE_READ */
#undef BUFSIZE
void module_register (void)
{
- plugin_register (MODULE_NAME, cpufreq_init, cpufreq_read, cpufreq_write);
-}
+ plugin_register_data_set (&data_set);
-#undef MODULE_NAME
+#if CPUFREQ_HAVE_READ
+ plugin_register_init ("cpufreq", cpufreq_init);
+ plugin_register_read ("cpufreq", cpufreq_read);
+#endif /* CPUFREQ_HAVE_READ */
+}
/**
* collectd - src/df.c
- * Copyright (C) 2005,2006 Florian octo Forster
+ * Copyright (C) 2005-2007 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * Free Software Foundation; only version 2 of the License is applicable.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
#include "utils_mount.h"
#include "utils_ignorelist.h"
-#define MODULE_NAME "df"
-
#if HAVE_STATFS || HAVE_STATVFS
# define DF_HAVE_READ 1
#else
# define BLOCKSIZE(s) (s).f_bsize
#endif
-static char *filename_template = "df-%s.rrd";
+/* 2^50 - 1 == 1125899906842623 = 1 Petabyte */
+static data_source_t dsrc[2] =
+{
+ {"free", DS_TYPE_GAUGE, 0, 1125899906842623.0},
+ {"used", DS_TYPE_GAUGE, 0, 1125899906842623.0}
+};
-static char *ds_def[] =
+static data_set_t ds =
{
- "DS:used:GAUGE:"COLLECTD_HEARTBEAT":0:U",
- "DS:free:GAUGE:"COLLECTD_HEARTBEAT":0:U",
- NULL
+ "df", 2, dsrc
};
-static int ds_num = 2;
-static char *config_keys[] =
+#if DF_HAVE_READ
+static const char *config_keys[] =
{
"Device",
"MountPoint",
static ignorelist_t *il_mountpoint = NULL;
static ignorelist_t *il_fstype = NULL;
-#define BUFSIZE 512
-
-static void df_init (void)
+static int df_init (void)
{
if (il_device == NULL)
il_device = ignorelist_create (1);
if (il_fstype == NULL)
il_fstype = ignorelist_create (1);
- return;
+ return (0);
}
-static int df_config (char *key, char *value)
+static int df_config (const char *key, const char *value)
{
df_init ();
return (-1);
}
-static void df_write (char *host, char *inst, char *val)
-{
- char file[BUFSIZE];
- int status;
-
- status = snprintf (file, BUFSIZE, filename_template, inst);
- if (status < 1)
- return;
- else if (status >= BUFSIZE)
- return;
-
- rrd_update_file (host, file, val, ds_def, ds_num);
-}
-
-#if DF_HAVE_READ
static void df_submit (char *df_name,
- unsigned long long df_used,
- unsigned long long df_free)
+ gauge_t df_used,
+ gauge_t df_free)
{
- char buf[BUFSIZE];
+ value_t values[2];
+ value_list_t vl = VALUE_LIST_INIT;
- if (snprintf (buf, BUFSIZE, "%u:%llu:%llu", (unsigned int) curtime,
- df_used, df_free) >= BUFSIZE)
- return;
+ values[0].gauge = df_used;
+ values[1].gauge = df_free;
- plugin_submit (MODULE_NAME, df_name, buf);
-}
+ vl.values = values;
+ vl.values_len = 2;
+ vl.time = time (NULL);
+ strcpy (vl.host, hostname);
+ strcpy (vl.plugin, "df");
+ strcpy (vl.plugin_instance, "");
+ strncpy (vl.type_instance, df_name, sizeof (vl.type_instance));
-static void df_read (void)
+ plugin_dispatch_values ("df", &vl);
+} /* void df_submit */
+
+static int df_read (void)
{
#if HAVE_STATVFS
struct statvfs statbuf;
cu_mount_t *mnt_ptr;
unsigned long long blocksize;
- unsigned long long df_free;
- unsigned long long df_used;
- char mnt_name[BUFSIZE];
+ gauge_t df_free;
+ gauge_t df_used;
+ char mnt_name[256];
mnt_list = NULL;
if (cu_mount_getlist (&mnt_list) == NULL)
- return;
+ return (-1);
for (mnt_ptr = mnt_list; mnt_ptr != NULL; mnt_ptr = mnt_ptr->next)
{
if (strcmp (mnt_ptr->dir, "/") == 0)
{
- strncpy (mnt_name, "root", BUFSIZE);
+ strncpy (mnt_name, "root", sizeof (mnt_name));
}
else
{
int i, len;
- strncpy (mnt_name, mnt_ptr->dir + 1, BUFSIZE);
+ strncpy (mnt_name, mnt_ptr->dir + 1, sizeof (mnt_name));
len = strlen (mnt_name);
for (i = 0; i < len; i++)
}
cu_mount_freelist (mnt_list);
-} /* static void df_read (void) */
-#else
-# define df_read NULL
+
+ return (0);
+} /* int df_read */
#endif /* DF_HAVE_READ */
void module_register (void)
{
- plugin_register (MODULE_NAME, df_init, df_read, df_write);
- cf_register (MODULE_NAME, df_config, config_keys, config_keys_num);
-}
+ plugin_register_data_set (&ds);
-#undef BUFSIZE
-#undef MODULE_NAME
+#if DF_HAVE_READ
+ plugin_register_config ("df", df_config, config_keys, config_keys_num);
+ plugin_register_init ("df", df_init);
+ plugin_register_read ("df", df_read);
+#endif
+} /* void module_register */
/**
* collectd - src/disk.c
- * Copyright (C) 2005,2006 Florian octo Forster
+ * Copyright (C) 2005-2007 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * Free Software Foundation; only version 2 of the License is applicable.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
#include "plugin.h"
#include "utils_debug.h"
-#define MODULE_NAME "disk"
-
#if HAVE_MACH_MACH_TYPES_H
# include <mach/mach_types.h>
#endif
# define DISK_HAVE_READ 0
#endif
-static char *disk_filename_template = "disk-%s.rrd";
-static char *part_filename_template = "partition-%s.rrd";
+/* 2^34 = 17179869184 = ~17.2GByte/s */
+static data_source_t octets_dsrc[2] =
+{
+ {"read", DS_TYPE_COUNTER, 0, 17179869183.0},
+ {"write", DS_TYPE_COUNTER, 0, 17179869183.0}
+};
+
+static data_set_t octets_ds =
+{
+ "disk_octets", 2, octets_dsrc
+};
+
+static data_source_t operations_dsrc[2] =
+{
+ {"read", DS_TYPE_COUNTER, 0, 4294967295.0},
+ {"write", DS_TYPE_COUNTER, 0, 4294967295.0}
+};
-/* 104857600 == 100 MB */
-static char *disk_ds_def[] =
+static data_set_t operations_ds =
{
- "DS:rcount:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:rmerged:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:rbytes:COUNTER:"COLLECTD_HEARTBEAT":0:104857600",
- "DS:rtime:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:wcount:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:wmerged:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:wbytes:COUNTER:"COLLECTD_HEARTBEAT":0:104857600",
- "DS:wtime:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- NULL
+ "disk_ops", 2, operations_dsrc
};
-static int disk_ds_num = 8;
-static char *part_ds_def[] =
+static data_source_t merged_dsrc[2] =
{
- "DS:rcount:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:rbytes:COUNTER:"COLLECTD_HEARTBEAT":0:104857600",
- "DS:wcount:COUNTER:"COLLECTD_HEARTBEAT":0:U",
- "DS:wbytes:COUNTER:"COLLECTD_HEARTBEAT":0:104857600",
- NULL
+ {"read", DS_TYPE_COUNTER, 0, 4294967295.0},
+ {"write", DS_TYPE_COUNTER, 0, 4294967295.0}
};
-static int part_ds_num = 4;
+static data_set_t merged_ds =
+{
+ "disk_merged", 2, merged_dsrc
+};
+
+/* max is 1000000us per second. */
+static data_source_t time_dsrc[2] =
+{
+ {"read", DS_TYPE_COUNTER, 0, 1000000.0},
+ {"write", DS_TYPE_COUNTER, 0, 1000000.0}
+};
+
+static data_set_t time_ds =
+{
+ "disk_time", 2, time_dsrc
+};
+
+#if DISK_HAVE_READ
#if HAVE_IOKIT_IOKITLIB_H
static mach_port_t io_master_port = MACH_PORT_NULL;
/* #endif HAVE_IOKIT_IOKITLIB_H */
/* This overflows in roughly 1361 year */
unsigned int poll_count;
- unsigned long long read_sectors;
- unsigned long long write_sectors;
+ counter_t read_sectors;
+ counter_t write_sectors;
- unsigned long long read_bytes;
- unsigned long long write_bytes;
+ counter_t read_bytes;
+ counter_t write_bytes;
struct diskstats *next;
} diskstats_t;
static int numdisk = 0;
#endif /* HAVE_LIBKSTAT */
-static void disk_init (void)
+static int disk_init (void)
{
#if HAVE_IOKIT_IOKITLIB_H
kern_return_t status;
syslog (LOG_ERR, "IOMasterPort failed: %s",
mach_error_string (status));
io_master_port = MACH_PORT_NULL;
- return;
+ return (-1);
}
/* #endif HAVE_IOKIT_IOKITLIB_H */
numdisk = 0;
if (kc == NULL)
- return;
+ return (-1);
for (numdisk = 0, ksp_chain = kc->kc_chain;
(numdisk < MAX_NUMDISK) && (ksp_chain != NULL);
}
#endif /* HAVE_LIBKSTAT */
- return;
-}
+ return (0);
+} /* int disk_init */
-static void disk_write (char *host, char *inst, char *val)
+static void disk_submit (const char *plugin_instance,
+ const char *type,
+ counter_t read, counter_t write)
{
- char file[512];
- int status;
+ value_t values[2];
+ value_list_t vl = VALUE_LIST_INIT;
- status = snprintf (file, 512, disk_filename_template, inst);
- if (status < 1)
- return;
- else if (status >= 512)
- return;
+ values[0].counter = read;
+ values[1].counter = write;
- rrd_update_file (host, file, val, disk_ds_def, disk_ds_num);
-}
+ vl.values = values;
+ vl.values_len = 2;
+ vl.time = time (NULL);
+ strcpy (vl.host, hostname);
+ strcpy (vl.plugin, "disk");
+ strncpy (vl.plugin_instance, plugin_instance,
+ sizeof (vl.plugin_instance));
-static void partition_write (char *host, char *inst, char *val)
-{
- char file[512];
- int status;
-
- status = snprintf (file, 512, part_filename_template, inst);
- if (status < 1)
- return;
- else if (status >= 512)
- return;
-
- rrd_update_file (host, file, val, part_ds_def, part_ds_num);
-}
-
-#if DISK_HAVE_READ
-#define BUFSIZE 512
-static void disk_submit (char *disk_name,
- unsigned long long read_count,
- unsigned long long read_merged,
- unsigned long long read_bytes,
- unsigned long long read_time,
- unsigned long long write_count,
- unsigned long long write_merged,
- unsigned long long write_bytes,
- unsigned long long write_time)
-{
- char buf[BUFSIZE];
-
- if (snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu",
- (unsigned int) curtime,
- read_count, read_merged, read_bytes, read_time,
- write_count, write_merged, write_bytes,
- write_time) >= BUFSIZE)
- return;
-
- DBG ("disk_name = %s; buf = %s;",
- disk_name, buf);
-
- plugin_submit (MODULE_NAME, disk_name, buf);
-}
-
-#if KERNEL_LINUX || HAVE_LIBKSTAT
-static void partition_submit (char *part_name,
- unsigned long long read_count,
- unsigned long long read_bytes,
- unsigned long long write_count,
- unsigned long long write_bytes)
-{
- char buf[BUFSIZE];
-
- if (snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu",
- (unsigned int) curtime,
- read_count, read_bytes, write_count,
- write_bytes) >= BUFSIZE)
- return;
-
- plugin_submit ("partition", part_name, buf);
-}
-#endif /* KERNEL_LINUX || HAVE_LIBKSTAT */
-#undef BUFSIZE
+ plugin_dispatch_values (type, &vl);
+} /* void disk_submit */
#if HAVE_IOKIT_IOKITLIB_H
static signed long long dict_get_value (CFDictionaryRef dict, const char *key)
}
#endif /* HAVE_IOKIT_IOKITLIB_H */
-static void disk_read (void)
+static int disk_read (void)
{
#if HAVE_IOKIT_IOKITLIB_H
io_registry_entry_t disk;
{
plugin_complain (LOG_ERR, &complain_obj, "disk plugin: "
"IOServiceGetMatchingServices failed.");
- return;
+ return (-1);
}
else if (complain_obj.interval != 0)
{
continue;
}
+ /* kIOBSDNameKey */
disk_major = (int) dict_get_value (child_dict,
kIOBSDMajorKey);
disk_minor = (int) dict_get_value (child_dict,
kIOBlockStorageDriverStatisticsWritesKey);
write_byt = dict_get_value (stats_dict,
kIOBlockStorageDriverStatisticsBytesWrittenKey);
+ /* This property describes the number of nanoseconds spent
+ * performing writes since the block storage driver was
+ * instantiated. It is one of the statistic entries listed
+ * under the top-level kIOBlockStorageDriverStatisticsKey
+ * property table. It has an OSNumber value. */
write_tme = dict_get_value (stats_dict,
kIOBlockStorageDriverStatisticsTotalWriteTimeKey);
}
DBG ("disk_name = %s", disk_name);
- if ((read_ops != -1LL)
- || (read_byt != -1LL)
- || (read_tme != -1LL)
- || (write_ops != -1LL)
- || (write_byt != -1LL)
- || (write_tme != -1LL))
- disk_submit (disk_name,
- read_ops, 0ULL, read_byt, read_tme,
- write_ops, 0ULL, write_byt, write_tme);
+ if ((read_byt != -1LL) || (write_byt != -1LL))
+ disk_submit (disk_name, "disk_octets", read_byt, write_byt);
+ if ((read_ops != -1LL) || (write_ops != -1LL))
+ disk_submit (disk_name, "disk_ops", read_ops, write_ops);
+ if ((read_tme != -1LL) || (write_tme != -1LL))
+ disk_submit (disk_name, "disk_time",
+ read_tme / 1000,
+ write_tme / 1000);
CFRelease (child_dict);
IOObjectRelease (disk_child);
#elif KERNEL_LINUX
FILE *fh;
char buffer[1024];
- char disk_name[128];
char *fields[32];
int numfields;
int major = 0;
int minor = 0;
- unsigned long long read_sectors = 0ULL;
- unsigned long long write_sectors = 0ULL;
-
- unsigned long long read_count = 0ULL;
- unsigned long long read_merged = 0ULL;
- unsigned long long read_bytes = 0ULL;
- unsigned long long read_time = 0ULL;
- unsigned long long write_count = 0ULL;
- unsigned long long write_merged = 0ULL;
- unsigned long long write_bytes = 0ULL;
- unsigned long long write_time = 0ULL;
+ counter_t read_sectors = 0;
+ counter_t write_sectors = 0;
+
+ counter_t read_count = 0;
+ counter_t read_merged = 0;
+ counter_t read_bytes = 0;
+ counter_t read_time = 0;
+ counter_t write_count = 0;
+ counter_t write_merged = 0;
+ counter_t write_bytes = 0;
+ counter_t write_time = 0;
int is_disk = 0;
diskstats_t *ds, *pre_ds;
{
if ((fh = fopen ("/proc/partitions", "r")) == NULL)
{
- plugin_complain (LOG_ERR, &complain_obj, "disk plugin: Failed to open /proc/{diskstats,partitions}.");
- return;
+ plugin_complain (LOG_ERR, &complain_obj,
+ "disk plugin: Failed to open /proc/"
+ "{diskstats,partitions}.");
+ return (-1);
}
/* Kernel is 2.4.* */
fieldshift = 1;
}
- plugin_relief (LOG_NOTICE, &complain_obj, "disk plugin: Succeeded to open /proc/{diskstats,partitions}.");
+ plugin_relief (LOG_NOTICE, &complain_obj, "disk plugin: "
+ "Succeeded to open /proc/{diskstats,partitions}.");
- while (fgets (buffer, 1024, fh) != NULL)
+ while (fgets (buffer, sizeof (buffer), fh) != NULL)
{
+ char *disk_name;
+
numfields = strsplit (buffer, fields, 32);
if ((numfields != (14 + fieldshift)) && (numfields != 7))
major = atoll (fields[0]);
minor = atoll (fields[1]);
- if (snprintf (disk_name, 128, "%i-%i", major, minor) < 1)
- continue;
- disk_name[127] = '\0';
+ disk_name = fields[2];
for (ds = disklist, pre_ds = disklist; ds != NULL; pre_ds = ds, ds = ds->next)
if (strcmp (disk_name, ds->name) == 0)
continue;
}
+ if ((read_bytes != -1LL) || (write_bytes != -1LL))
+ disk_submit (disk_name, "disk_octets", read_bytes, write_bytes);
+ if ((read_count != -1LL) || (write_count != -1LL))
+ disk_submit (disk_name, "disk_ops", read_count, write_count);
if (is_disk)
- disk_submit (disk_name, read_count, read_merged, read_bytes, read_time,
- write_count, write_merged, write_bytes, write_time);
- else
- partition_submit (disk_name, read_count, read_bytes, write_count, write_bytes);
- }
+ {
+ if ((read_merged != -1LL) || (write_merged != -1LL))
+ disk_submit (disk_name, "disk_merged",
+ read_merged, write_merged);
+ if ((read_time != -1LL) || (write_time != -1LL))
+ disk_submit (disk_name, "disk_time",
+ read_time * 1000,
+ write_time * 1000);
+ }
+ } /* while (fgets (buffer, sizeof (buffer), fh) != NULL) */
fclose (fh);
/* #endif defined(KERNEL_LINUX) */
int i;
if (kc == NULL)
- return;
+ return (-1);
for (i = 0; i < numdisk; i++)
{
continue;
if (strncmp (ksp[i]->ks_class, "disk", 4) == 0)
- disk_submit (ksp[i]->ks_name,
- kio.reads, 0LL, kio.nread, kio.rtime,
- kio.writes, 0LL, kio.nwritten, kio.wtime);
+ {
+ disk_submit (ksp[i]->ks_name, "disk_octets", kio.reads, kio.writes);
+ disk_submit (ksp[i]->ks_name, "disk_ops", kio.nreads, kio.nwrites);
+ /* FIXME: Convert this to microseconds if necessary */
+ disk_submit (ksp[i]->ks_name, "disk_time", kio.rtime, kio.wtime);
+ }
else if (strncmp (ksp[i]->ks_class, "partition", 9) == 0)
- partition_submit (ksp[i]->ks_name,
- kio.reads, kio.nread,
- kio.writes,kio.nwritten);
+ {
+ disk_submit (ksp[i]->ks_name, "disk_octets", kio.reads, kio.writes);
+ disk_submit (ksp[i]->ks_name, "disk_ops", kio.nreads, kio.nwrites);
+ }
}
#endif /* defined(HAVE_LIBKSTAT) */
-} /* static void disk_read (void) */
-#else
-# define disk_read NULL
+
+ return (0);
+} /* int disk_read */
#endif /* DISK_HAVE_READ */
void module_register (void)
{
- plugin_register ("partition", NULL, NULL, partition_write);
- plugin_register (MODULE_NAME, disk_init, disk_read, disk_write);
-}
+ plugin_register_data_set (&octets_ds);
+ plugin_register_data_set (&operations_ds);
+ plugin_register_data_set (&merged_ds);
+ plugin_register_data_set (&time_ds);
-#undef MODULE_NAME
+#if DISK_HAVE_READ
+ plugin_register_init ("disk", disk_init);
+ plugin_register_read ("disk", disk_read);
+#endif /* DISK_HAVE_READ */
+}
#include "utils_debug.h"
/*
+ * Private structures
+ */
+struct read_func_s
+{
+ int wait_time;
+ int wait_left;
+ int (*callback) (void);
+};
+typedef struct read_func_s read_func_t;
+
+/*
* Private variables
*/
static llist_t *list_init;
return (0);
} /* int register_callback */
+static int plugin_unregister (llist_t *list, const char *name)
+{
+ llentry_t *e;
+
+ e = llist_search (list, name);
+
+ if (e == NULL)
+ return (-1);
+
+ llist_remove (list, e);
+ 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
int plugin_register_read (const char *name,
int (*callback) (void))
{
- return (register_callback (&list_read, name, (void *) callback));
+ read_func_t *rf;
+
+ rf = (read_func_t *) malloc (sizeof (read_func_t));
+ if (rf == NULL)
+ {
+ syslog (LOG_ERR, "plugin_register_read: malloc failed: %s",
+ strerror (errno));
+ return (-1);
+ }
+
+ memset (rf, '\0', sizeof (read_func_t));
+ rf->wait_time = atoi (COLLECTD_STEP);
+ rf->wait_left = 0;
+ rf->callback = callback;
+
+ return (register_callback (&list_read, name, (void *) rf));
} /* int plugin_register_read */
int plugin_register_write (const char *name,
return (register_callback (&list_data_set, ds->type, (void *) ds));
} /* int plugin_register_data_set */
+int plugin_unregister_init (const char *name)
+{
+ return (plugin_unregister (list_init, name));
+}
+
+int plugin_unregister_read (const char *name)
+{
+ return (plugin_unregister (list_read, name));
+ llentry_t *e;
+
+ e = llist_search (list_read, name);
+
+ if (e == NULL)
+ return (-1);
+
+ llist_remove (list_read, e);
+ free (e->value);
+ llentry_destroy (e);
+
+ return (0);
+}
+
+int plugin_unregister_write (const char *name)
+{
+ return (plugin_unregister (list_write, name));
+}
+
+int plugin_unregister_shutdown (const char *name)
+{
+ return (plugin_unregister (list_shutdown, name));
+}
+
+int plugin_unregister_data_set (const char *name)
+{
+ return (plugin_unregister (list_data_set, name));
+}
+
void plugin_init_all (void)
{
int (*callback) (void);
void plugin_read_all (const int *loop)
{
- int (*callback) (void);
- llentry_t *le;
+ llentry_t *le;
+ read_func_t *rf;
+ int status;
+ int step;
if (list_read == NULL)
return;
+ step = atoi (COLLECTD_STEP);
+
le = llist_head (list_read);
while ((*loop == 0) && (le != NULL))
{
- callback = le->value;
- (*callback) ();
+ rf = (read_func_t *) le->value;
+
+ if (rf->wait_left > 0)
+ rf->wait_left -= step;
+ if (rf->wait_left > 0)
+ {
+ le = le->next;
+ continue;
+ }
+
+ status = rf->callback ();
+ if (status != 0)
+ {
+ rf->wait_left = rf->wait_time;
+ rf->wait_time = rf->wait_time * 2;
+ if (rf->wait_time > 86400)
+ rf->wait_time = 86400;
+
+ syslog (LOG_NOTICE, "read-function of plugin `%s' "
+ "failed. Will syspend it for %i "
+ "seconds.", le->key, rf->wait_left);
+ }
+ else
+ {
+ rf->wait_left = 0;
+ rf->wait_time = step;
+ }
le = le->next;
- }
+ } /* while ((*loop == 0) && (le != NULL)) */
} /* void plugin_read_all */
void plugin_shutdown_all (void)
int (*callback) (void));
int plugin_register_data_set (const data_set_t *ds);
+int plugin_unregister_init (const char *name);
+int plugin_unregister_read (const char *name);
+int plugin_unregister_write (const char *name);
+int plugin_unregister_shutdown (const char *name);
+int plugin_unregister_data_set (const char *name);
+
/*
* NAME
* plugin_dispatch_values
--- /dev/null
+/**
+ * collectd - src/unixsock.c
+ * Copyright (C) 2007 Florian octo Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+#include "utils_debug.h"
+
+/* Folks without pthread will need to disable this plugin. */
+#include <pthread.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/poll.h>
+
+#include <grp.h>
+
+#ifndef UNIX_PATH_MAX
+# define UNIX_PATH_MAX sizeof (((struct sockaddr_un *)0)->sun_path)
+#endif
+
+#define US_DEFAULT_PATH PREFIX"/var/run/"PACKAGE_NAME"-unixsock"
+
+/*
+ * Private data structures
+ */
+/* linked list of cached values */
+typedef struct value_cache_s
+{
+ char name[4*DATA_MAX_NAME_LEN];
+ int values_num;
+ gauge_t *gauge;
+ counter_t *counter;
+ const data_set_t *ds;
+ time_t time;
+ struct value_cache_s *next;
+} value_cache_t;
+
+/*
+ * Private variables
+ */
+/* valid configuration file keys */
+static const char *config_keys[] =
+{
+ "SocketFile",
+ "SocketGroup",
+ "SocketPerms",
+ NULL
+};
+static int config_keys_num = 3;
+
+/* socket configuration */
+static int sock_fd = -1;
+static char *sock_file = NULL;
+static char *sock_group = NULL;
+static int sock_perms = S_IRWXU | S_IRWXG;
+
+static pthread_t listen_thread = -1;
+
+/* Linked list and auxilliary variables for saving values */
+static value_cache_t *cache_head = NULL;
+static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
+static unsigned int cache_oldest = UINT_MAX;
+
+/*
+ * Functions
+ */
+static value_cache_t *cache_search (const char *name)
+{
+ value_cache_t *vc;
+
+ for (vc = cache_head; vc != NULL; vc = vc->next)
+ {
+ if (strcmp (vc->name, name) == 0)
+ break;
+ } /* for vc = cache_head .. NULL */
+
+ return (vc);
+} /* value_cache_t *cache_search */
+
+static int cache_alloc_name (char *ret, int ret_len,
+ const char *hostname,
+ const char *plugin, const char *plugin_instance,
+ const char *type, const char *type_instance)
+{
+ int status;
+
+ assert (plugin != NULL);
+ assert (type != NULL);
+
+ if ((plugin_instance == NULL) || (strlen (plugin_instance) == 0))
+ {
+ if ((type_instance == NULL) || (strlen (type_instance) == 0))
+ status = snprintf (ret, ret_len, "%s/%s/%s",
+ hostname, plugin, type);
+ else
+ status = snprintf (ret, ret_len, "%s/%s/%s-%s",
+ hostname, plugin, type, type_instance);
+ }
+ else
+ {
+ if ((type_instance == NULL) || (strlen (type_instance) == 0))
+ status = snprintf (ret, ret_len, "%s/%s-%s/%s",
+ hostname, plugin, plugin_instance, type);
+ else
+ status = snprintf (ret, ret_len, "%s/%s-%s/%s-%s",
+ hostname, plugin, plugin_instance, type, type_instance);
+ }
+
+ if ((status < 1) || (status >= ret_len))
+ return (-1);
+ return (0);
+} /* int cache_alloc_name */
+
+static int cache_insert (const data_set_t *ds, const value_list_t *vl)
+{
+ /* We're called from `cache_update' so we don't need to lock the mutex */
+ value_cache_t *vc;
+ int i;
+
+ DBG ("ds->ds_num = %i; vl->values_len = %i;",
+ ds->ds_num, vl->values_len);
+ assert (ds->ds_num == vl->values_len);
+
+ vc = (value_cache_t *) malloc (sizeof (value_cache_t));
+ if (vc == NULL)
+ {
+ pthread_mutex_unlock (&cache_lock);
+ syslog (LOG_ERR, "unixsock plugin: malloc failed: %s",
+ strerror (errno));
+ return (-1);
+ }
+
+ vc->gauge = (gauge_t *) malloc (sizeof (gauge_t) * vl->values_len);
+ if (vc->gauge == NULL)
+ {
+ pthread_mutex_unlock (&cache_lock);
+ syslog (LOG_ERR, "unixsock plugin: malloc failed: %s",
+ strerror (errno));
+ free (vc);
+ return (-1);
+ }
+
+ vc->counter = (counter_t *) malloc (sizeof (counter_t) * vl->values_len);
+ if (vc->counter == NULL)
+ {
+ pthread_mutex_unlock (&cache_lock);
+ syslog (LOG_ERR, "unixsock plugin: malloc failed: %s",
+ strerror (errno));
+ free (vc->gauge);
+ free (vc);
+ return (-1);
+ }
+
+ if (cache_alloc_name (vc->name, sizeof (vc->name),
+ vl->host, vl->plugin, vl->plugin_instance,
+ ds->type, vl->type_instance) != 0)
+ {
+ pthread_mutex_unlock (&cache_lock);
+ syslog (LOG_ERR, "unixsock plugin: cache_alloc_name failed.");
+ free (vc->counter);
+ free (vc->gauge);
+ free (vc);
+ return (-1);
+ }
+
+ for (i = 0; i < ds->ds_num; i++)
+ {
+ if (ds->ds[i].type == DS_TYPE_COUNTER)
+ {
+ vc->gauge[i] = 0.0;
+ vc->counter[i] = vl->values[i].counter;
+ }
+ else if (ds->ds[i].type == DS_TYPE_GAUGE)
+ {
+ vc->gauge[i] = vl->values[i].gauge;
+ vc->counter[i] = 0;
+ }
+ else
+ {
+ vc->gauge[i] = 0.0;
+ vc->counter[i] = 0;
+ }
+ }
+ vc->values_num = ds->ds_num;
+ vc->ds = ds;
+
+ vc->next = cache_head;
+ cache_head = vc;
+
+ vc->time = vl->time;
+ if (vc->time < cache_oldest)
+ cache_oldest = vc->time;
+
+ pthread_mutex_unlock (&cache_lock);
+ return (0);
+} /* int cache_insert */
+
+static int cache_update (const data_set_t *ds, const value_list_t *vl)
+{
+ char name[4*DATA_MAX_NAME_LEN];;
+ value_cache_t *vc;
+ int i;
+
+ if (cache_alloc_name (name, sizeof (name),
+ vl->host,
+ vl->plugin, vl->plugin_instance,
+ ds->type, vl->type_instance) != 0)
+ return (-1);
+
+ pthread_mutex_lock (&cache_lock);
+
+ vc = cache_search (name);
+
+ if (vc == NULL)
+ return (cache_insert (ds, vl));
+
+ assert (vc->values_num == ds->ds_num);
+ assert (vc->values_num == vl->values_len);
+
+ /*
+ * Update the values. This is possibly a lot more that you'd expect
+ * because we honor min and max values and handle counter overflows here.
+ */
+ for (i = 0; i < ds->ds_num; i++)
+ {
+ if (ds->ds[i].type == DS_TYPE_COUNTER)
+ {
+ if (vl->values[i].counter < vc->counter[i])
+ {
+ if (vl->values[i].counter <= 4294967295U)
+ {
+ vc->gauge[i] = ((4294967295U - vl->values[i].counter)
+ + vc->counter[i]) / (vl->time - vc->time);
+ }
+ else
+ {
+ vc->gauge[i] = ((18446744073709551615ULL - vl->values[i].counter)
+ + vc->counter[i]) / (vl->time - vc->time);
+ }
+ }
+ else
+ {
+ vc->gauge[i] = (vl->values[i].counter - vc->counter[i])
+ / (vl->time - vc->time);
+ }
+
+ vc->counter[i] = vl->values[i].counter;
+ }
+ else if (ds->ds[i].type == DS_TYPE_GAUGE)
+ {
+ vc->gauge[i] = vl->values[i].gauge;
+ vc->counter[i] = 0;
+ }
+ else
+ {
+ vc->gauge[i] = NAN;
+ vc->counter[i] = 0;
+ }
+
+ if ((vc->gauge[i] == NAN)
+ || ((ds->ds[i].min != NAN) && (vc->gauge[i] < ds->ds[i].min))
+ || ((ds->ds[i].max != NAN) && (vc->gauge[i] > ds->ds[i].max)))
+ vc->gauge[i] = NAN;
+ } /* for i = 0 .. ds->ds_num */
+
+ vc->ds = ds;
+ vc->time = vl->time;
+
+ if (vc->time < cache_oldest)
+ cache_oldest = vc->time;
+
+ pthread_mutex_unlock (&cache_lock);
+ return (0);
+} /* int cache_update */
+
+static void cache_flush (int max_age)
+{
+ value_cache_t *this;
+ value_cache_t *prev;
+ time_t now;
+
+ pthread_mutex_lock (&cache_lock);
+
+ now = time (NULL);
+
+ if ((now - cache_oldest) <= max_age)
+ {
+ pthread_mutex_unlock (&cache_lock);
+ return;
+ }
+
+ cache_oldest = now;
+
+ prev = NULL;
+ this = cache_head;
+
+ while (this != NULL)
+ {
+ if ((now - this->time) <= max_age)
+ {
+ if (this->time < cache_oldest)
+ cache_oldest = this->time;
+
+ prev = this;
+ this = this->next;
+ continue;
+ }
+
+ if (prev == NULL)
+ cache_head = this->next;
+ else
+ prev->next = this->next;
+
+ free (this->gauge);
+ free (this->counter);
+ free (this);
+
+ if (prev == NULL)
+ this = cache_head;
+ else
+ this = prev->next;
+ } /* while (this != NULL) */
+
+ pthread_mutex_unlock (&cache_lock);
+} /* int cache_flush */
+
+static int us_open_socket (void)
+{
+ struct sockaddr_un sa;
+ int status;
+
+ sock_fd = socket (PF_UNIX, SOCK_STREAM, 0);
+ if (sock_fd < 0)
+ {
+ syslog (LOG_ERR, "unixsock plugin: socket failed: %s",
+ strerror (errno));
+ return (-1);
+ }
+
+ memset (&sa, '\0', sizeof (sa));
+ sa.sun_family = AF_UNIX;
+ strncpy (sa.sun_path, (sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
+ sizeof (sa.sun_path) - 1);
+ /* unlink (sa.sun_path); */
+
+ status = bind (sock_fd, (struct sockaddr *) &sa, sizeof (sa));
+ if (status != 0)
+ {
+ DBG ("bind failed: %s; sa.sun_path = %s",
+ strerror (errno), sa.sun_path);
+ syslog (LOG_ERR, "unixsock plugin: bind failed: %s",
+ strerror (errno));
+ close (sock_fd);
+ sock_fd = -1;
+ return (-1);
+ }
+
+ status = listen (sock_fd, 8);
+ if (status != 0)
+ {
+ syslog (LOG_ERR, "unixsock plugin: listen failed: %s",
+ strerror (errno));
+ close (sock_fd);
+ sock_fd = -1;
+ return (-1);
+ }
+
+ do
+ {
+ struct group *g;
+
+ errno = 0;
+ g = getgrnam ((sock_group != NULL) ? sock_group : COLLECTD_GRP_NAME);
+
+ if (errno != 0)
+ {
+ syslog (LOG_WARNING, "unixsock plugin: getgrnam (%s) failed: %s",
+ (sock_group != NULL) ? sock_group : COLLECTD_GRP_NAME,
+ strerror (errno));
+ break;
+ }
+
+ if (g == NULL)
+ break;
+
+ if (chown ((sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
+ (uid_t) -1, g->gr_gid) != 0)
+ {
+ syslog (LOG_WARNING, "unixsock plugin: chown (%s, -1, %i) failed: %s",
+ (sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
+ (int) g->gr_gid,
+ strerror (errno));
+ }
+ } while (0);
+
+ return (0);
+} /* int us_open_socket */
+
+static int us_handle_getval (FILE *fh, char **fields, int fields_num)
+{
+ char *hostname = fields[1];
+ char *plugin;
+ char *plugin_instance;
+ char *type;
+ char *type_instance;
+ char name[4*DATA_MAX_NAME_LEN];
+ value_cache_t *vc;
+ int status;
+ int i;
+
+ if (fields_num != 2)
+ 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++;
+ }
+
+ status = cache_alloc_name (name, sizeof (name),
+ hostname, plugin, plugin_instance, type, type_instance);
+ if (status != 0)
+ return (-1);
+
+ pthread_mutex_lock (&cache_lock);
+
+ DBG ("vc = cache_search (%s)", name);
+ vc = cache_search (name);
+
+ if (vc == NULL)
+ {
+ DBG ("Did not find cache entry.");
+ fprintf (fh, "-1 No such value");
+ }
+ else
+ {
+ DBG ("Found cache entry.");
+ fprintf (fh, "%i", vc->values_num);
+ for (i = 0; i < vc->values_num; i++)
+ {
+ fprintf (fh, " %s=", vc->ds->ds[i].name);
+ if (vc->gauge[i] == NAN)
+ fprintf (fh, "NaN");
+ else
+ fprintf (fh, "%12e", vc->gauge[i]);
+ }
+ }
+
+ /* Free the mutex as soon as possible and definitely before flushing */
+ pthread_mutex_unlock (&cache_lock);
+
+ fprintf (fh, "\n");
+ fflush (fh);
+
+ return (0);
+} /* int us_handle_getval */
+
+static void *us_handle_client (void *arg)
+{
+ int fd;
+ FILE *fh;
+ char buffer[1024];
+ char *fields[128];
+ int fields_num;
+
+ fd = *((int *) arg);
+ free (arg);
+ arg = NULL;
+
+ DBG ("Reading from fd #%i", fd);
+
+ fh = fdopen (fd, "r+");
+ if (fh == NULL)
+ {
+ syslog (LOG_ERR, "unixsock plugin: fdopen failed: %s",
+ strerror (errno));
+ close (fd);
+ pthread_exit ((void *) 1);
+ }
+
+ while (fgets (buffer, sizeof (buffer), fh) != NULL)
+ {
+ int len;
+
+ len = strlen (buffer);
+ while ((len > 0)
+ && ((buffer[len - 1] == '\n') || (buffer[len - 1] == '\r')))
+ buffer[--len] = '\0';
+
+ if (len == 0)
+ continue;
+
+ DBG ("fgets -> buffer = %s; len = %i;", buffer, len);
+
+ fields_num = strsplit (buffer, fields,
+ sizeof (fields) / sizeof (fields[0]));
+
+ if (fields_num < 1)
+ {
+ close (fd);
+ break;
+ }
+
+ if (strcasecmp (fields[0], "getval") == 0)
+ {
+ us_handle_getval (fh, fields, fields_num);
+ }
+ else
+ {
+ fprintf (fh, "Unknown command: %s\n", fields[0]);
+ fflush (fh);
+ }
+ } /* while (fgets) */
+
+ DBG ("Exiting..");
+ close (fd);
+
+ pthread_exit ((void *) 0);
+} /* void *us_handle_client */
+
+static void *us_server_thread (void *arg)
+{
+ int status;
+ int *remote_fd;
+ pthread_t th;
+ pthread_attr_t th_attr;
+
+ if (us_open_socket () != 0)
+ pthread_exit ((void *) 1);
+
+ while (42)
+ {
+ DBG ("Calling accept..");
+ status = accept (sock_fd, NULL, NULL);
+ if (status < 0)
+ {
+ if (errno == EINTR)
+ continue;
+
+ syslog (LOG_ERR, "unixsock plugin: accept failed: %s",
+ strerror (errno));
+ close (sock_fd);
+ sock_fd = -1;
+ pthread_exit ((void *) 1);
+ }
+
+ remote_fd = (int *) malloc (sizeof (int));
+ if (remote_fd == NULL)
+ {
+ syslog (LOG_WARNING, "unixsock plugin: malloc failed: %s",
+ strerror (errno));
+ close (status);
+ continue;
+ }
+ *remote_fd = status;
+
+ DBG ("Spawning child to handle connection on fd #%i", *remote_fd);
+
+ pthread_attr_init (&th_attr);
+ pthread_attr_setdetachstate (&th_attr, PTHREAD_CREATE_DETACHED);
+
+ status = pthread_create (&th, &th_attr, us_handle_client, (void *) remote_fd);
+ if (status != 0)
+ {
+ syslog (LOG_WARNING, "unixsock plugin: pthread_create failed: %s",
+ strerror (status));
+ close (*remote_fd);
+ free (remote_fd);
+ continue;
+ }
+ } /* while (42) */
+
+ return ((void *) 0);
+} /* void *us_server_thread */
+
+static int us_config (const char *key, const char *val)
+{
+ if (strcasecmp (key, "SocketFile") == 0)
+ {
+ sfree (sock_file);
+ sock_file = strdup (val);
+ }
+ else if (strcasecmp (key, "SocketGroup") == 0)
+ {
+ sfree (sock_group);
+ sock_group = strdup (val);
+ }
+ else if (strcasecmp (key, "SocketPerms") == 0)
+ {
+ sock_perms = (int) strtol (val, NULL, 8);
+ }
+ else
+ {
+ return (-1);
+ }
+
+ return (0);
+} /* int us_config */
+
+static int us_init (void)
+{
+ int status;
+
+ status = pthread_create (&listen_thread, NULL, us_server_thread, NULL);
+ if (status != 0)
+ {
+ syslog (LOG_ERR, "unixsock plugin: pthread_create failed: %s",
+ strerror (status));
+ return (-1);
+ }
+
+ return (0);
+} /* int us_init */
+
+static int us_shutdown (void)
+{
+ void *ret;
+
+ if (listen_thread >= 0)
+ {
+ pthread_kill (listen_thread, SIGTERM);
+ pthread_join (listen_thread, &ret);
+ }
+
+ plugin_unregister_init ("unixsock");
+ plugin_unregister_write ("unixsock");
+ plugin_unregister_shutdown ("unixsock");
+
+ return (0);
+} /* int us_shutdown */
+
+static int us_write (const data_set_t *ds, const value_list_t *vl)
+{
+ cache_update (ds, vl);
+ cache_flush (2 * atoi (COLLECTD_STEP));
+
+ return (0);
+}
+
+void module_register (void)
+{
+ plugin_register_config ("unixsock", us_config,
+ config_keys, config_keys_num);
+ plugin_register_init ("unixsock", us_init);
+ plugin_register_write ("unixsock", us_write);
+ plugin_register_shutdown ("unixsock", us_shutdown);
+} /* void module_register (void) */
+
+/* vim: set sw=4 ts=4 sts=4 tw=78 : */