/**
* collectd - src/common.c
- * Copyright (C) 2005-2009 Florian octo Forster
+ * Copyright (C) 2005-2010 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
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
- * Florian octo Forster <octo at verplant.org>
+ * Florian octo Forster <octo at collectd.org>
* Niki W. Waibel <niki.waibel@gmx.net>
* Sebastian Harl <sh at tokkee.org>
* Michał Mirosław <mirq-linux at rere.qmqm.pl>
#include "collectd.h"
#include "common.h"
#include "plugin.h"
+#include "utils_cache.h"
#if HAVE_PTHREAD_H
# include <pthread.h>
# include <math.h>
#endif
-/* for ntohl and htonl */
-#if HAVE_ARPA_INET_H
-# include <arpa/inet.h>
-#endif
-
/* for getaddrinfo */
#include <sys/types.h>
#include <sys/socket.h>
# include <netinet/in.h>
#endif
+/* for ntohl and htonl */
+#if HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
#ifdef HAVE_LIBKSTAT
extern kstat_ctl_t *kc;
#endif
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;
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 *buf, int buf_len)
{
int i;
}
while (42) {
- if (stat (dir, &statbuf) == -1)
+ if ((stat (dir, &statbuf) == -1)
+ && (lstat (dir, &statbuf) == -1))
{
if (errno == ENOENT)
{
- if (mkdir (dir, 0755) == 0)
+ if (mkdir (dir, S_IRWXU | S_IRWXG | S_IRWXO) == 0)
break;
/* this might happen, if a different thread created
kstat_named_t *kn;
long long retval = -1LL;
-#ifdef assert
- assert (ksp != NULL);
- assert (ksp->ks_type == KSTAT_TYPE_NAMED);
-#else
if (ksp == NULL)
{
- ERROR ("ERROR: %s:%i: ksp == NULL\n", __FILE__, __LINE__);
+ ERROR ("get_kstat_value (\"%s\"): ksp is NULL.", name);
return (-1LL);
}
else if (ksp->ks_type != KSTAT_TYPE_NAMED)
{
- ERROR ("ERROR: %s:%i: ksp->ks_type != KSTAT_TYPE_NAMED\n", __FILE__, __LINE__);
+ 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);
}
-#endif
if ((kn = (kstat_named_t *) kstat_data_lookup (ksp, name)) == NULL)
- return (retval);
+ return (-1LL);
if (kn->data_type == KSTAT_DATA_INT32)
retval = (long long) kn->value.i32;
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 */
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 = ssnprintf (ret, ret_len, "%s/%s/%s",
- hostname, plugin, type);
- else
- status = ssnprintf (ret, ret_len, "%s/%s/%s-%s",
- hostname, plugin, type,
- type_instance);
- }
- else
- {
- if ((type_instance == NULL) || (strlen (type_instance) == 0))
- status = ssnprintf (ret, ret_len, "%s/%s-%s/%s",
- hostname, plugin, plugin_instance,
- type);
- else
- status = ssnprintf (ret, ret_len, "%s/%s-%s/%s-%s",
- hostname, plugin, plugin_instance,
- type, 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;
- if ((status < 1) || (status >= ret_len))
- return (-1);
- return (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)
return (0);
} /* int parse_identifier */
-int parse_value (const char *value, value_t *ret_value, int ds_type)
+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)
{
break;
default:
+ sfree (value);
ERROR ("parse_value: Invalid data source type: %i.", ds_type);
return -1;
}
if (value == endptr) {
+ sfree (value);
ERROR ("parse_value: Failed to parse string as %s: %s.",
DS_TYPE_TO_STRING (ds_type), 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);
+ endptr, DS_TYPE_TO_STRING (ds_type), value_orig);
+ sfree (value);
return 0;
} /* int parse_value */
if (i == -1)
{
if (strcmp ("N", ptr) == 0)
- vl->time = time (NULL);
+ vl->time = cdtime ();
else
- vl->time = (time_t) atoi (ptr);
+ {
+ 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
{
return (0);
}
-int read_file_contents (const char *filename, char *buf, int bufsize)
+ssize_t read_file_contents (const char *filename, char *buf, size_t bufsize)
{
FILE *fh;
- int n;
+ ssize_t ret;
- if ((fh = fopen (filename, "r")) == NULL)
- return -1;
+ fh = fopen (filename, "r");
+ if (fh == NULL)
+ return (-1);
- n = fread(buf, 1, bufsize, fh);
- fclose(fh);
+ 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;
+ }
- return n;
+ fclose(fh);
+ return (ret);
}
counter_t counter_diff (counter_t old_value, counter_t new_value)
}
return (diff);
-} /* counter_t counter_to_gauge */
+} /* 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 service_name_to_port_number (const char *service_name)
{
*ret_value = tmp;
return (0);
} /* }}} int strtoderive */
+
+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 */