/**
* collectd - src/common.c
- * Copyright (C) 2005,2006 Florian octo Forster
+ * Copyright (C) 2005-2008 Florian octo Forster
*
- * This program is free software; you can redistribute it and/
- * or modify it under the terms of the GNU General Public Li-
- * cence as published by the Free Software Foundation; either
- * version 2 of the Licence, or any later version.
+ * 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 use-
- * ful, but WITHOUT ANY WARRANTY; without even the implied war-
- * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public Licence for more details.
+ * 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
- * Licence along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
* Florian octo Forster <octo at verplant.org>
* Niki W. Waibel <niki.waibel@gmx.net>
**/
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "collectd.h"
#include "common.h"
-#include "utils_debug.h"
+#include "plugin.h"
+
+#if HAVE_PTHREAD_H
+# include <pthread.h>
+#endif
#ifdef HAVE_MATH_H
-# include <math.h>
+# include <math.h>
#endif
-extern int operating_mode;
+/* for ntohl and htonl */
+#if HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
#ifdef HAVE_LIBKSTAT
extern kstat_ctl_t *kc;
#endif
-#ifdef HAVE_LIBRRD
-#if 0
-static char *rra_def[] =
-{
- "RRA:AVERAGE:0.0:1:1500",
- "RRA:AVERAGE:0.2:6:1500",
- "RRA:AVERAGE:0.1:180:1680",
- "RRA:AVERAGE:0.1:2160:1520",
- "RRA:MIN:0.0:1:1500",
- "RRA:MIN:0.2:6:1500",
- "RRA:MIN:0.1:180:1680",
- "RRA:MIN:0.1:2160:1520",
- "RRA:MAX:0.0:1:1500",
- "RRA:MAX:0.2:6:1500",
- "RRA:MAX:0.1:180:1680",
- "RRA:MAX:0.1:2160:1520",
- NULL
-};
-static int rra_num = 12;
+#if !HAVE_GETPWNAM_R
+static pthread_mutex_t getpwnam_r_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
-static int rra_timespans[] =
-{
- 3600,
- 86400,
- 604800,
- 2678400,
- 31622400,
- 0
-};
-static int rra_timespans_num = 5;
-
-static char *rra_types[] =
+#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)
{
- "AVERAGE",
- "MIN",
- "MAX",
- NULL
-};
-static int rra_types_num = 3;
-#endif /* HAVE_LIBRRD */
-
-void sstrncpy (char *d, const char *s, int len)
+ strncpy (dest, src, n);
+ dest[n - 1] = '\0';
+
+ return (dest);
+} /* char *sstrncpy */
+
+int ssnprintf (char *dest, size_t n, const char *format, ...)
{
- strncpy (d, s, len);
- d[len - 1] = '\0';
-}
+ 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 *sstrdup (const char *s)
{
char *r;
+ size_t sz;
if (s == NULL)
return (NULL);
- if((r = strdup (s)) == 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)
{
- DBG ("Not enough memory.");
- exit(3);
+ 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)
{
if ((r = malloc (size)) == NULL)
{
- DBG("Not enough memory.");
- exit(3);
+ ERROR ("Not enough memory.");
+ exit (3);
}
- return r;
-}
+ return (r);
+} /* void *smalloc */
#if 0
void sfree (void **ptr)
}
#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;
- while ((fields[i] = strtok (ptr, " \t")) != NULL)
+ saveptr = NULL;
+ while ((fields[i] = strtok_r (ptr, " \t\r\n", &saveptr)) != NULL)
{
ptr = NULL;
i++;
char **fields, size_t fields_num,
const char *sep)
{
- int field_len;
- int sep_len;
+ size_t field_len;
+ size_t sep_len;
int i;
memset (dst, '\0', dst_len);
if (sep != NULL)
sep_len = strlen (sep);
- for (i = 0; i < fields_num; i++)
+ for (i = 0; i < (int)fields_num; i++)
{
if ((i > 0) && (sep_len > 0))
{
}
return (ret);
-}
+} /* int strsubstitute */
int escape_slashes (char *buf, int buf_len)
{
return (0);
}
+ if (buf_len <= 1)
+ return (0);
+
/* Move one to the left */
- memmove (buf, buf + 1, buf_len - 1);
+ if (buf[0] == '/')
+ memmove (buf, buf + 1, buf_len - 1);
for (i = 0; i < buf_len - 1; i++)
{
buf[i] = '\0';
return (0);
-}
+} /* int escape_slashes */
-int timeval_sub_timespec (struct timeval *tv0, struct timeval *tv1, struct timespec *ret)
+void replace_special (char *buffer, size_t buffer_size)
{
- if ((tv0 == NULL) || (tv1 == NULL) || (ret == NULL))
- return (-2);
+ size_t i;
- if ((tv0->tv_sec < tv1->tv_sec)
- || ((tv0->tv_sec == tv1->tv_sec) && (tv0->tv_usec < tv1->tv_usec)))
- return (-1);
+ 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;
- ret->tv_sec = tv0->tv_sec - tv1->tv_sec;
- ret->tv_nsec = 1000 * ((long) (tv0->tv_usec - tv1->tv_usec));
+ NORMALIZE_TIMEVAL (tv0);
+ NORMALIZE_TIMEVAL (tv1);
- if (ret->tv_nsec < 0)
+ if ((tv0.tv_sec == tv1.tv_sec) && (tv0.tv_usec == tv1.tv_usec))
{
- assert (ret->tv_sec > 0);
+ if (delta != NULL) {
+ delta->tv_sec = 0;
+ delta->tv_usec = 0;
+ }
+ return (0);
+ }
- ret->tv_nsec += 1000000000;
- ret->tv_sec -= 1;
+ 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;
}
- return (0);
-}
+ 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 */
-static int check_create_dir (const char *file_orig)
+int check_create_dir (const char *file_orig)
{
struct stat statbuf;
char *fields[16];
int fields_num;
char *ptr;
+ char *saveptr;
int last_is_file = 1;
- int len;
+ int path_is_absolute = 0;
+ size_t len;
int i;
/*
if ((len = strlen (file_orig)) < 1)
return (-1);
- else if (len >= 512)
+ else if (len >= sizeof (file_copy))
return (-1);
/*
*/
if (file_orig[len - 1] == '/')
last_is_file = 0;
+ if (file_orig[0] == '/')
+ path_is_absolute = 1;
/*
- * Create a copy for `strtok' to destroy
+ * Create a copy for `strtok_r' to destroy
*/
- strncpy (file_copy, file_orig, 512);
- file_copy[511] = '\0';
+ 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 (ptr, "/")) != NULL)
+ while ((fields[fields_num] = strtok_r (ptr, "/", &saveptr)) != NULL)
{
ptr = NULL;
fields_num++;
*/
if (fields[i][0] == '.')
{
- syslog (LOG_ERR, "Cowardly refusing to create a directory that begins with a `.' (dot): `%s'", file_orig);
+ ERROR ("Cowardly refusing to create a directory that begins with a `.' (dot): `%s'", file_orig);
return (-2);
}
/*
* Join the components together again
*/
- if (strjoin (dir, dir_len, fields, i + 1, "/") < 0)
+ dir[0] = '/';
+ if (strjoin (dir + path_is_absolute, dir_len - path_is_absolute,
+ fields, i + 1, "/") < 0)
{
- syslog (LOG_ERR, "strjoin failed: `%s', component #%i", file_orig, i);
+ ERROR ("strjoin failed: `%s', component #%i", file_orig, i);
return (-1);
}
{
if (mkdir (dir, 0755) == -1)
{
- syslog (LOG_ERR, "mkdir (%s): %s", dir, strerror (errno));
+ char errbuf[1024];
+ ERROR ("check_create_dir: mkdir (%s): %s", dir,
+ sstrerror (errno,
+ errbuf, sizeof (errbuf)));
return (-1);
}
}
else
{
- syslog (LOG_ERR, "stat (%s): %s", dir, strerror (errno));
+ char errbuf[1024];
+ ERROR ("stat (%s): %s", dir,
+ sstrerror (errno, errbuf,
+ sizeof (errbuf)));
return (-1);
}
}
else if (!S_ISDIR (statbuf.st_mode))
{
- syslog (LOG_ERR, "stat (%s): Not a directory!", dir);
+ ERROR ("stat (%s): Not a directory!", dir);
return (-1);
}
}
return (0);
-}
+} /* check_create_dir */
-/* * * * *
- * Magic *
- * * * * */
-#if HAVE_LIBRRD
-static int rra_get (char ***ret)
+#ifdef HAVE_LIBKSTAT
+int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
{
- static char **rra_def = NULL;
- static int rra_num = 0;
-
- int rra_max = rra_timespans_num * rra_types_num;
-
- int step;
- int rows;
- int span;
-
- int cdp_num;
- int cdp_len;
- int i, j;
+ char ident[128];
+
+ if (kc == NULL)
+ return (-1);
- char buffer[64];
+ ssnprintf (ident, sizeof (ident), "%s,%i,%s", module, instance, name);
- if ((rra_num != 0) && (rra_def != NULL))
+ if (*ksp_ptr == NULL)
{
- *ret = rra_def;
- return (rra_num);
- }
+ if ((*ksp_ptr = kstat_lookup (kc, module, instance, name)) == NULL)
+ {
+ ERROR ("Cound not find kstat %s", ident);
+ return (-1);
+ }
- if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
- return (-1);
- memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
+ if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
+ {
+ WARNING ("kstat %s has wrong type", ident);
+ *ksp_ptr = NULL;
+ return (-1);
+ }
+ }
- step = atoi (COLLECTD_STEP);
- rows = atoi (COLLECTD_ROWS);
+#ifdef assert
+ assert (*ksp_ptr != NULL);
+ assert ((*ksp_ptr)->ks_type == KSTAT_TYPE_NAMED);
+#endif
- if ((step <= 0) || (rows <= 0))
+ if (kstat_read (kc, *ksp_ptr, NULL) == -1)
{
- *ret = NULL;
+ WARNING ("kstat %s could not be read", ident);
return (-1);
}
- cdp_len = 0;
- for (i = 0; i < rra_timespans_num; i++)
+ if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
{
- span = rra_timespans[i];
-
- if ((span / step) < rows)
- continue;
-
- if (cdp_len == 0)
- cdp_len = 1;
- else
- cdp_len = (int) floor (((double) span) / ((double) (rows * step)));
-
- cdp_num = (int) ceil (((double) span) / ((double) (cdp_len * step)));
-
- for (j = 0; j < rra_types_num; j++)
- {
- if (rra_num >= rra_max)
- break;
-
- if (snprintf (buffer, sizeof(buffer), "RRA:%s:%3.1f:%u:%u",
- rra_types[j], COLLECTD_XFF,
- cdp_len, cdp_num) >= sizeof (buffer))
- {
- syslog (LOG_ERR, "rra_get: Buffer would have been truncated.");
- continue;
- }
-
- rra_def[rra_num++] = sstrdup (buffer);
- }
+ WARNING ("kstat %s has wrong type", ident);
+ return (-1);
}
-#if COLLECT_DEBUG
- DBG ("rra_num = %i", rra_num);
- for (i = 0; i < rra_num; i++)
- DBG (" %s", rra_def[i]);
-#endif
-
- *ret = rra_def;
- return (rra_num);
+ return (0);
}
-#endif /* HAVE_LIBRRD */
-static int log_create_file (char *filename, char **ds_def, int ds_num)
+long long get_kstat_value (kstat_t *ksp, char *name)
{
- FILE *log;
- int i;
-
- if (check_create_dir (filename))
- return (-1);
+ kstat_named_t *kn;
+ long long retval = -1LL;
- log = fopen (filename, "w");
- if (log == NULL)
+#ifdef assert
+ assert (ksp != NULL);
+ assert (ksp->ks_type == KSTAT_TYPE_NAMED);
+#else
+ if (ksp == NULL)
{
- syslog (LOG_WARNING, "Failed to create %s: %s", filename,
- strerror(errno));
- return (-1);
+ ERROR ("ERROR: %s:%i: ksp == NULL\n", __FILE__, __LINE__);
+ return (-1LL);
}
-
- fprintf (log, "epoch");
- for (i = 0; i < ds_num; i++)
+ else if (ksp->ks_type != KSTAT_TYPE_NAMED)
{
- char *name;
- char *tmp;
-
- name = strchr (ds_def[i], ':');
- if (name == NULL)
- {
- syslog (LOG_WARNING, "Invalid DS definition '%s' for %s",
- ds_def[i], filename);
- fclose(log);
- remove(filename);
- return (-1);
- }
-
- name += 1;
- tmp = strchr (name, ':');
- if (tmp == NULL)
- {
- syslog (LOG_WARNING, "Invalid DS definition '%s' for %s",
- ds_def[i], filename);
- fclose(log);
- remove(filename);
- return (-1);
- }
-
- /* The `%.*s' is needed because there is no null-byte behind
- * the name. */
- fprintf(log, ",%.*s", (int) (tmp - name), name);
+ ERROR ("ERROR: %s:%i: ksp->ks_type != KSTAT_TYPE_NAMED\n", __FILE__, __LINE__);
+ return (-1LL);
}
- fprintf(log, "\n");
- fclose(log);
+#endif
+
+ if ((kn = (kstat_named_t *) kstat_data_lookup (ksp, name)) == NULL)
+ return (retval);
- return 0;
+ 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 */
-static int log_update_file (char *host, char *file, char *values,
- char **ds_def, int ds_num)
+unsigned long long ntohll (unsigned long long n)
{
- char *tmp;
- FILE *fp;
- struct stat statbuf;
- char full_file[1024];
+#if BYTE_ORDER == BIG_ENDIAN
+ return (n);
+#else
+ return (((unsigned long long) ntohl (n)) << 32) + ntohl (n >> 32);
+#endif
+} /* unsigned long long ntohll */
- /* Cook the values a bit: Substitute colons with commas */
- strsubstitute (values, ':', ',');
+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 */
+
+#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;
- /* host == NULL => local mode */
- if (host != NULL)
+ 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))
{
- if (snprintf (full_file, 1024, "%s/%s", host, file) >= 1024)
- return (-1);
+ return (NAN);
}
else
{
- if (snprintf (full_file, 1024, "%s", file) >= 1024)
- return (-1);
- }
+ uint64_t tmp;
- strncpy (full_file, file, 1024);
+ tmp = ret.integer;
+ ret.integer = FP_CONVERT (tmp);
+ return (ret.floating);
+ }
+} /* double ntohd */
- tmp = full_file + strlen (full_file) - 4;
- assert ((tmp != NULL) && (tmp > full_file));
+double htond (double d)
+{
+ union
+ {
+ uint8_t byte[8];
+ uint64_t integer;
+ double floating;
+ } ret;
- /* Change the filename for logfiles. */
- if (strncmp (tmp, ".rrd", 4) == 0)
+ if (isnan (d))
{
- time_t now;
- struct tm *tm;
+ 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;
- /* TODO: Find a way to minimize the calls to `localtime', since
- * they are pretty expensive.. */
- now = time (NULL);
- tm = localtime (&now);
+ 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 */
- strftime (tmp, 1024 - (tmp - full_file), "-%Y-%m-%d", tm);
+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)
+{
+ int status;
- /* `localtime(3)' returns a pointer to static data,
- * therefore the pointer may not be free'd. */
- }
- else
- DBG ("The filename ends with `%s' which is unexpected.", tmp);
+ assert (plugin != NULL);
+ assert (type != NULL);
- if (stat (full_file, &statbuf) == -1)
+ if ((plugin_instance == NULL) || (strlen (plugin_instance) == 0))
{
- if (errno == ENOENT)
- {
- if (log_create_file (full_file, ds_def, ds_num))
- return (-1);
- }
+ if ((type_instance == NULL) || (strlen (type_instance) == 0))
+ status = ssnprintf (ret, ret_len, "%s/%s/%s",
+ hostname, plugin, type);
else
- {
- syslog (LOG_ERR, "stat %s: %s", full_file, strerror (errno));
- return (-1);
- }
+ status = ssnprintf (ret, ret_len, "%s/%s/%s-%s",
+ hostname, plugin, type,
+ type_instance);
}
- else if (!S_ISREG (statbuf.st_mode))
+ else
{
- syslog (LOG_ERR, "stat %s: Not a regular file!", full_file);
- return (-1);
+ 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);
}
-
- fp = fopen (full_file, "a");
- if (fp == NULL)
- {
- syslog (LOG_WARNING, "Failed to append to %s: %s", full_file,
- strerror(errno));
+ if ((status < 1) || (status >= ret_len))
return (-1);
- }
- fprintf(fp, "%s\n", values);
- fclose(fp);
-
return (0);
-} /* int log_update_file */
+} /* int format_name */
-#if HAVE_LIBRRD
-static int rrd_create_file (char *filename, char **ds_def, int ds_num)
+int parse_identifier (char *str, char **ret_host,
+ char **ret_plugin, char **ret_plugin_instance,
+ char **ret_type, char **ret_type_instance)
{
- char **argv;
- int argc;
- char **rra_def;
- int rra_num;
- int i, j;
- int status = 0;
-
- if (check_create_dir (filename))
+ char *hostname = NULL;
+ char *plugin = NULL;
+ char *plugin_instance = NULL;
+ char *type = NULL;
+ char *type_instance = NULL;
+
+ hostname = str;
+ if (hostname == NULL)
return (-1);
- if ((rra_num = rra_get (&rra_def)) < 1)
- {
- syslog (LOG_ERR, "rra_create failed: Could not calculate RRAs");
+ plugin = strchr (hostname, '/');
+ if (plugin == NULL)
return (-1);
- }
+ *plugin = '\0'; plugin++;
- argc = ds_num + rra_num + 4;
+ type = strchr (plugin, '/');
+ if (type == NULL)
+ return (-1);
+ *type = '\0'; type++;
- if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
+ plugin_instance = strchr (plugin, '-');
+ if (plugin_instance != NULL)
{
- syslog (LOG_ERR, "rrd_create failed: %s", strerror (errno));
- return (-1);
+ *plugin_instance = '\0';
+ plugin_instance++;
}
- argv[0] = "create";
- argv[1] = filename;
- argv[2] = "-s";
- argv[3] = COLLECTD_STEP;
-
- j = 4;
- for (i = 0; i < ds_num; i++)
- argv[j++] = ds_def[i];
- for (i = 0; i < rra_num; i++)
- argv[j++] = rra_def[i];
- argv[j] = NULL;
-
- optind = 0; /* bug in librrd? */
- rrd_clear_error ();
- if (rrd_create (argc, argv) == -1)
+ type_instance = strchr (type, '-');
+ if (type_instance != NULL)
{
- syslog (LOG_ERR, "rrd_create failed: %s: %s", filename, rrd_get_error ());
- status = -1;
+ *type_instance = '\0';
+ type_instance++;
}
- free (argv);
-
- return (status);
-}
-#endif /* HAVE_LIBRRD */
+ *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 rrd_update_file (char *host, char *file, char *values,
- char **ds_def, int ds_num)
+int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
{
-#if HAVE_LIBRRD
- struct stat statbuf;
- char full_file[1024];
- char *argv[4] = { "update", full_file, values, NULL };
-#endif /* HAVE_LIBRRD */
-
- /* I'd rather have a function `common_update_file' to make this
- * decission, but for that we'd need to touch all plugins.. */
- if (operating_mode == MODE_LOG)
- return (log_update_file (host, file, values,
- ds_def, ds_num));
-
-#if HAVE_LIBRRD
- /* host == NULL => local mode */
- if (host != NULL)
- {
- if (snprintf (full_file, 1024, "%s/%s", host, file) >= 1024)
- return (-1);
- }
- else
- {
- if (snprintf (full_file, 1024, "%s", file) >= 1024)
- return (-1);
- }
+ int i;
+ char *dummy;
+ char *ptr;
+ char *saveptr;
- if (stat (full_file, &statbuf) == -1)
+ i = -1;
+ dummy = buffer;
+ saveptr = NULL;
+ while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL)
{
- if (errno == ENOENT)
+ dummy = NULL;
+
+ if (i >= vl->values_len)
+ break;
+
+ if (i == -1)
{
- if (rrd_create_file (full_file, ds_def, ds_num))
- return (-1);
+ if (strcmp ("N", ptr) == 0)
+ vl->time = time (NULL);
+ else
+ vl->time = (time_t) atoi (ptr);
}
else
{
- syslog (LOG_ERR, "stat %s: %s", full_file, strerror (errno));
- return (-1);
+ if (strcmp ("U", ptr) == 0)
+ vl->values[i].gauge = NAN;
+ else if (ds->ds[i].type == DS_TYPE_COUNTER)
+ vl->values[i].counter = atoll (ptr);
+ else if (ds->ds[i].type == DS_TYPE_GAUGE)
+ vl->values[i].gauge = atof (ptr);
}
- }
- else if (!S_ISREG (statbuf.st_mode))
- {
- syslog (LOG_ERR, "stat %s: Not a regular file!", full_file);
- return (-1);
- }
- optind = 0; /* bug in librrd? */
- rrd_clear_error ();
- if (rrd_update (3, argv) == -1)
- {
- syslog (LOG_WARNING, "rrd_update failed: %s: %s", full_file, rrd_get_error ());
+ i++;
+ } /* while (strtok_r) */
+
+ if ((ptr != NULL) || (i != vl->values_len))
return (-1);
- }
return (0);
-/* #endif HAVE_LIBRRD */
+} /* int parse_values */
-#else
- syslog (LOG_ERR, "`rrd_update_file' was called, but collectd isn't linked against librrd!");
- return (-1);
-#endif
-}
-
-#ifdef HAVE_LIBKSTAT
-int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
+#if !HAVE_GETPWNAM_R
+int getpwnam_r (const char *name, struct passwd *pwbuf, char *buf,
+ size_t buflen, struct passwd **pwbufp)
{
- char ident[128];
-
- if (kc == NULL)
- return (-1);
+ int status = 0;
+ struct passwd *pw;
- snprintf (ident, 128, "%s,%i,%s", module, instance, name);
- ident[127] = '\0';
+ memset (pwbuf, '\0', sizeof (struct passwd));
- if (*ksp_ptr == NULL)
+ pthread_mutex_lock (&getpwnam_r_lock);
+
+ do
{
- if ((*ksp_ptr = kstat_lookup (kc, module, instance, name)) == NULL)
+ pw = getpwnam (name);
+ if (pw == NULL)
{
- syslog (LOG_ERR, "Cound not find kstat %s", ident);
- return (-1);
+ status = (errno != 0) ? errno : ENOENT;
+ break;
}
- if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
- {
- syslog (LOG_WARNING, "kstat %s has wrong type", ident);
- *ksp_ptr = NULL;
- return (-1);
+#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);
-#ifdef assert
- assert (*ksp_ptr != NULL);
- assert ((*ksp_ptr)->ks_type == KSTAT_TYPE_NAMED);
-#endif
+ pwbuf->pw_uid = pw->pw_uid;
+ pwbuf->pw_gid = pw->pw_gid;
- if (kstat_read (kc, *ksp_ptr, NULL) == -1)
+ 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)
+{
+ struct dirent *ent;
+ DIR *dh;
+ int success;
+ int failure;
+
+ success = 0;
+ failure = 0;
+
+ if ((dh = opendir (dir)) == NULL)
{
- syslog (LOG_WARNING, "kstat %s could not be read", ident);
- return (-1);
+ char errbuf[1024];
+ ERROR ("walk_directory: Cannot open '%s': %s", dir,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return -1;
}
- if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
+ while ((ent = readdir (dh)) != NULL)
{
- syslog (LOG_WARNING, "kstat %s has wrong type", ident);
- return (-1);
+ int status;
+
+ 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);
}
-long long get_kstat_value (kstat_t *ksp, char *name)
+int read_file_contents (const char *filename, char *buf, int bufsize)
{
- kstat_named_t *kn;
- long long retval = -1LL;
+ FILE *fh;
+ int n;
-#ifdef assert
- assert (ksp != NULL);
- assert (ksp->ks_type == KSTAT_TYPE_NAMED);
-#else
- if (ksp == NULL)
+ if ((fh = fopen (filename, "r")) == NULL)
+ return -1;
+
+ n = fread(buf, 1, bufsize, fh);
+ fclose(fh);
+
+ return n;
+}
+
+counter_t counter_diff (counter_t old_value, counter_t new_value)
+{
+ counter_t diff;
+
+ if (old_value > new_value)
{
- fprintf (stderr, "ERROR: %s:%i: ksp == NULL\n", __FILE__, __LINE__);
- return (-1LL);
+ if (old_value <= 4294967295U)
+ diff = (4294967295U - old_value) + new_value;
+ else
+ diff = (18446744073709551615ULL - old_value)
+ + new_value;
}
- else if (ksp->ks_type != KSTAT_TYPE_NAMED)
+ else
{
- fprintf (stderr, "ERROR: %s:%i: ksp->ks_type != KSTAT_TYPE_NAMED\n", __FILE__, __LINE__);
- return (-1LL);
+ diff = new_value - old_value;
}
-#endif
- if ((kn = (kstat_named_t *) kstat_data_lookup (ksp, name)) == NULL)
- return (retval);
-
- 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
- syslog (LOG_WARNING, "get_kstat_value: Not a numeric value: %s", name);
-
- return (retval);
-}
-#endif /* HAVE_LIBKSTAT */
+ return (diff);
+} /* counter_t counter_to_gauge */