X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fcommon.c;h=7555b7ef99d26150d81193ce7e1d4d1a8e3a4b33;hb=f453199292b45007e5078f568f3bce2e8c8b4067;hp=db8fce1a99f63b9691595adcfe96a7cc511902d9;hpb=6180d760a005346e40908d07e618bd93efa51ffd;p=collectd.git diff --git a/src/common.c b/src/common.c index db8fce1a..3ec4c6e1 100644 --- a/src/common.c +++ b/src/common.c @@ -1,88 +1,248 @@ /** * collectd - src/common.c - * Copyright (C) 2005 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 * Niki W. Waibel **/ +#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 +#endif + +#ifdef HAVE_MATH_H +# include +#endif + +/* for ntohl and htonl */ +#if HAVE_ARPA_INET_H +# include +#endif #ifdef HAVE_LIBKSTAT extern kstat_ctl_t *kc; #endif -#ifdef HAVE_LIBRRD -static char *rra_def[] = +#if !HAVE_GETPWNAM_R +static pthread_mutex_t getpwnam_r_lock = PTHREAD_MUTEX_INITIALIZER; +#endif + +#if !HAVE_STRERROR_R +static pthread_mutex_t strerror_r_lock = PTHREAD_MUTEX_INITIALIZER; +#endif + +char *sstrncpy (char *dest, const char *src, size_t n) +{ + strncpy (dest, src, n); + dest[n - 1] = '\0'; + + return (dest); +} /* char *sstrncpy */ + +int ssnprintf (char *dest, size_t n, const char *format, ...) { - "RRA:AVERAGE:0.2:6:1500", - "RRA:AVERAGE:0.1:180:1680", - "RRA:AVERAGE:0.1:2160:1520", - "RRA:MIN:0.2:6:1500", - "RRA:MIN:0.1:180:1680", - "RRA:MIN:0.1:2160:1520", - "RRA:MAX:0.2:6:1500", - "RRA:MAX:0.1:180:1680", - "RRA:MAX:0.1:2160:1520", - NULL -}; -static int rra_num = 9; -#endif /* HAVE_LIBRRD */ - -void -sstrncpy(char *d, const char *s, int len) + 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); + + /* Do not use `strdup' here, because it's not specified in POSIX. It's + * ``only'' an XSI extension. */ + sz = strlen (s) + 1; + r = (char *) malloc (sizeof (char) * sz); + if (r == NULL) + { + ERROR ("sstrdup: Out of memory."); + exit (3); + } + memcpy (r, s, sizeof (char) * sz); + + return (r); +} /* char *sstrdup */ + +/* Even though Posix requires "strerror_r" to return an "int", + * some systems (e.g. the GNU libc) return a "char *" _and_ + * ignore the second argument ... -tokkee */ +char *sstrerror (int errnum, char *buf, size_t buflen) { - strncpy(d, s, len); - d[len - 1] = 0; + buf[0] = '\0'; + +#if !HAVE_STRERROR_R + { + char *temp; + + pthread_mutex_lock (&strerror_r_lock); + + temp = strerror (errnum); + sstrncpy (buf, temp, buflen); + + pthread_mutex_unlock (&strerror_r_lock); + } +/* #endif !HAVE_STRERROR_R */ + +#elif STRERROR_R_CHAR_P + { + char *temp; + temp = strerror_r (errnum, buf, buflen); + if (buf[0] == '\0') + { + if ((temp != NULL) && (temp != buf) && (temp[0] != '\0')) + sstrncpy (buf, temp, buflen); + else + sstrncpy (buf, "strerror_r did not return " + "an error message", buflen); + } + } +/* #endif STRERROR_R_CHAR_P */ + +#else + if (strerror_r (errnum, buf, buflen) != 0) + { + ssnprintf (buf, buflen, "Error #%i; " + "Additionally, strerror_r failed.", + errnum); + } +#endif /* STRERROR_R_CHAR_P */ + + return (buf); +} /* char *sstrerror */ + +void *smalloc (size_t size) +{ + void *r; + + if ((r = malloc (size)) == NULL) + { + ERROR ("Not enough memory."); + exit (3); + } + + return (r); +} /* void *smalloc */ + +#if 0 +void sfree (void **ptr) +{ + if (ptr == NULL) + return; + + if (*ptr != NULL) + free (*ptr); + + *ptr = NULL; } +#endif -char * -sstrdup(const char *s) +ssize_t sread (int fd, void *buf, size_t count) { - char *r = strdup(s); - if(r == NULL) { - DBG("Not enough memory."); - exit(3); + 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 r; + + return (0); } -void * -smalloc(size_t size) + +ssize_t swrite (int fd, const void *buf, size_t count) { - void *r = malloc(size); - if(r == NULL) { - DBG("Not enough memory."); - exit(3); + 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 r; + + 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++; @@ -98,8 +258,8 @@ int strjoin (char *dst, size_t dst_len, 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); @@ -111,7 +271,7 @@ int strjoin (char *dst, size_t 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)) { @@ -134,6 +294,27 @@ int strjoin (char *dst, size_t dst_len, return (strlen (dst)); } +int strsubstitute (char *str, char c_from, char c_to) +{ + int ret; + + if (str == NULL) + return (-1); + + ret = 0; + while (*str != '\0') + { + if (*str == c_from) + { + *str = c_to; + ret++; + } + str++; + } + + return (ret); +} /* int strsubstitute */ + int escape_slashes (char *buf, int buf_len) { int i; @@ -147,8 +328,12 @@ 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++) { @@ -160,9 +345,72 @@ int escape_slashes (char *buf, int buf_len) buf[i] = '\0'; return (0); -} +} /* int escape_slashes */ + +void replace_special (char *buffer, size_t buffer_size) +{ + size_t i; + + for (i = 0; i < buffer_size; i++) + { + if (buffer[i] == 0) + return; + if ((!isalnum ((int) buffer[i])) && (buffer[i] != '-')) + buffer[i] = '_'; + } +} /* void replace_special */ + +int timeval_cmp (struct timeval tv0, struct timeval tv1, struct timeval *delta) +{ + struct timeval *larger; + struct timeval *smaller; + + int status; + + NORMALIZE_TIMEVAL (tv0); + NORMALIZE_TIMEVAL (tv1); + + if ((tv0.tv_sec == tv1.tv_sec) && (tv0.tv_usec == tv1.tv_usec)) + { + if (delta != NULL) { + delta->tv_sec = 0; + delta->tv_usec = 0; + } + return (0); + } + + if ((tv0.tv_sec < tv1.tv_sec) + || ((tv0.tv_sec == tv1.tv_sec) && (tv0.tv_usec < tv1.tv_usec))) + { + larger = &tv1; + smaller = &tv0; + status = -1; + } + else + { + larger = &tv0; + smaller = &tv1; + status = 1; + } + + if (delta != NULL) { + delta->tv_sec = larger->tv_sec - smaller->tv_sec; + + if (smaller->tv_usec <= larger->tv_usec) + delta->tv_usec = larger->tv_usec - smaller->tv_usec; + else + { + --delta->tv_sec; + delta->tv_usec = 1000000 + larger->tv_usec - smaller->tv_usec; + } + } + + assert ((delta == NULL) + || ((0 <= delta->tv_usec) && (delta->tv_usec < 1000000))); + + return (status); +} /* int timeval_cmp */ -#ifdef HAVE_LIBRRD int check_create_dir (const char *file_orig) { struct stat statbuf; @@ -173,8 +421,10 @@ int check_create_dir (const char *file_orig) 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; /* @@ -185,7 +435,7 @@ int check_create_dir (const char *file_orig) if ((len = strlen (file_orig)) < 1) return (-1); - else if (len >= 512) + else if (len >= sizeof (file_copy)) return (-1); /* @@ -194,20 +444,22 @@ int check_create_dir (const char *file_orig) */ 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++; @@ -222,142 +474,58 @@ int check_create_dir (const char *file_orig) for (i = 0; i < (fields_num - last_is_file); i++) { /* - * Join the components together again - */ - if (strjoin (dir, dir_len, fields, i + 1, "/") < 0) - return (-1); - - /* * Do not create directories that start with a dot. This * prevents `../../' attacks and other likely malicious * behavior. */ if (fields[i][0] == '.') { - syslog (LOG_ERR, "Cowardly refusing to create a directory that begins with a `.' (dot): `%s'", dir); + ERROR ("Cowardly refusing to create a directory that begins with a `.' (dot): `%s'", file_orig); return (-2); } + /* + * Join the components together again + */ + dir[0] = '/'; + if (strjoin (dir + path_is_absolute, dir_len - path_is_absolute, + fields, i + 1, "/") < 0) + { + ERROR ("strjoin failed: `%s', component #%i", file_orig, i); + return (-1); + } + if (stat (dir, &statbuf) == -1) { if (errno == ENOENT) { 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); - return (-1); - } - } - - return (0); -} - -int rrd_create_file (char *filename, char **ds_def, int ds_num) -{ - char **argv; - int argc; - int i, j; - int status = 0; - - argc = ds_num + rra_num + 4; - - if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL) - { - syslog (LOG_ERR, "rrd_create failed: %s", strerror (errno)); - return (-1); - } - - argv[0] = "create"; - argv[1] = filename; - argv[2] = "-s"; - argv[3] = "10"; - - 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) - { - syslog (LOG_ERR, "rrd_create failed: %s: %s", filename, rrd_get_error ()); - status = -1; - } - - free (argv); - - return (status); -} -#endif /* HAVE_LIBRRD */ - -int rrd_update_file (char *host, char *file, char *values, - char **ds_def, int ds_num) -{ -#ifdef HAVE_LIBRRD - struct stat statbuf; - char full_file[1024]; - char *argv[4] = { "update", full_file, values, NULL }; - - /* host == NULL => local mode */ - if (host != NULL) - { - if (check_create_dir (host)) - return (-1); - - if (snprintf (full_file, 1024, "%s/%s", host, file) >= 1024) - return (-1); - } - else - { - if (snprintf (full_file, 1024, "%s", file) >= 1024) - return (-1); - } - - if (stat (full_file, &statbuf) == -1) - { - if (errno == ENOENT) - { - if (rrd_create_file (full_file, ds_def, ds_num)) - return (-1); - } - else - { - syslog (LOG_ERR, "stat %s: %s", full_file, strerror (errno)); + ERROR ("stat (%s): Not a directory!", dir); return (-1); } } - 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 ()); - return (-1); - } -#endif /* HAVE_LIBRRD */ return (0); -} +} /* check_create_dir */ #ifdef HAVE_LIBKSTAT int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name) @@ -367,20 +535,19 @@ int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name) if (kc == NULL) return (-1); - snprintf (ident, 128, "%s,%i,%s", module, instance, name); - ident[127] = '\0'; + ssnprintf (ident, sizeof (ident), "%s,%i,%s", module, instance, name); if (*ksp_ptr == NULL) { if ((*ksp_ptr = kstat_lookup (kc, module, instance, name)) == NULL) { - syslog (LOG_ERR, "Cound not find kstat %s", ident); + ERROR ("Cound not find kstat %s", ident); return (-1); } if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED) { - syslog (LOG_WARNING, "kstat %s has wrong type", ident); + WARNING ("kstat %s has wrong type", ident); *ksp_ptr = NULL; return (-1); } @@ -393,13 +560,13 @@ int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name) if (kstat_read (kc, *ksp_ptr, NULL) == -1) { - syslog (LOG_WARNING, "kstat %s could not be read", ident); + WARNING ("kstat %s could not be read", ident); return (-1); } if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED) { - syslog (LOG_WARNING, "kstat %s has wrong type", ident); + WARNING ("kstat %s has wrong type", ident); return (-1); } @@ -417,12 +584,12 @@ long long get_kstat_value (kstat_t *ksp, char *name) #else if (ksp == NULL) { - fprintf (stderr, "ERROR: %s:%i: ksp == NULL\n", __FILE__, __LINE__); + ERROR ("ERROR: %s:%i: ksp == NULL\n", __FILE__, __LINE__); return (-1LL); } else if (ksp->ks_type != KSTAT_TYPE_NAMED) { - fprintf (stderr, "ERROR: %s:%i: ksp->ks_type != KSTAT_TYPE_NAMED\n", __FILE__, __LINE__); + ERROR ("ERROR: %s:%i: ksp->ks_type != KSTAT_TYPE_NAMED\n", __FILE__, __LINE__); return (-1LL); } #endif @@ -439,8 +606,382 @@ long long get_kstat_value (kstat_t *ksp, char *name) 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); + WARNING ("get_kstat_value: Not a numeric value: %s", name); return (retval); } #endif /* HAVE_LIBKSTAT */ + +unsigned long long ntohll (unsigned long long n) +{ +#if BYTE_ORDER == BIG_ENDIAN + return (n); +#else + return (((unsigned long long) ntohl (n)) << 32) + ntohl (n >> 32); +#endif +} /* unsigned long long ntohll */ + +unsigned long long htonll (unsigned long long n) +{ +#if BYTE_ORDER == BIG_ENDIAN + return (n); +#else + return (((unsigned long long) htonl (n)) << 32) + htonl (n >> 32); +#endif +} /* unsigned long long htonll */ + +#if FP_LAYOUT_NEED_NOTHING +/* Well, we need nothing.. */ +/* #endif FP_LAYOUT_NEED_NOTHING */ + +#elif FP_LAYOUT_NEED_ENDIANFLIP || FP_LAYOUT_NEED_INTSWAP +# if FP_LAYOUT_NEED_ENDIANFLIP +# define FP_CONVERT(A) ((((uint64_t)(A) & 0xff00000000000000LL) >> 56) | \ + (((uint64_t)(A) & 0x00ff000000000000LL) >> 40) | \ + (((uint64_t)(A) & 0x0000ff0000000000LL) >> 24) | \ + (((uint64_t)(A) & 0x000000ff00000000LL) >> 8) | \ + (((uint64_t)(A) & 0x00000000ff000000LL) << 8) | \ + (((uint64_t)(A) & 0x0000000000ff0000LL) << 24) | \ + (((uint64_t)(A) & 0x000000000000ff00LL) << 40) | \ + (((uint64_t)(A) & 0x00000000000000ffLL) << 56)) +# else +# define FP_CONVERT(A) ((((uint64_t)(A) & 0xffffffff00000000LL) >> 32) | \ + (((uint64_t)(A) & 0x00000000ffffffffLL) << 32)) +# endif + +double ntohd (double d) +{ + union + { + uint8_t byte[8]; + uint64_t integer; + double floating; + } ret; + + ret.floating = d; + + /* NAN in x86 byte order */ + if ((ret.byte[0] == 0x00) && (ret.byte[1] == 0x00) + && (ret.byte[2] == 0x00) && (ret.byte[3] == 0x00) + && (ret.byte[4] == 0x00) && (ret.byte[5] == 0x00) + && (ret.byte[6] == 0xf8) && (ret.byte[7] == 0x7f)) + { + return (NAN); + } + else + { + uint64_t tmp; + + tmp = ret.integer; + ret.integer = FP_CONVERT (tmp); + return (ret.floating); + } +} /* double ntohd */ + +double htond (double d) +{ + union + { + uint8_t byte[8]; + uint64_t integer; + double floating; + } ret; + + if (isnan (d)) + { + ret.byte[0] = ret.byte[1] = ret.byte[2] = ret.byte[3] = 0x00; + ret.byte[4] = ret.byte[5] = 0x00; + ret.byte[6] = 0xf8; + ret.byte[7] = 0x7f; + return (ret.floating); + } + else + { + uint64_t tmp; + + ret.floating = d; + tmp = FP_CONVERT (ret.integer); + ret.integer = tmp; + return (ret.floating); + } +} /* double htond */ +#endif /* FP_LAYOUT_NEED_ENDIANFLIP || FP_LAYOUT_NEED_INTSWAP */ + +int format_name (char *ret, int ret_len, + const char *hostname, + const char *plugin, const char *plugin_instance, + const char *type, const char *type_instance) +{ + 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); + } + + if ((status < 1) || (status >= ret_len)) + return (-1); + return (0); +} /* int format_name */ + +int parse_identifier (char *str, char **ret_host, + char **ret_plugin, char **ret_plugin_instance, + char **ret_type, char **ret_type_instance) +{ + char *hostname = NULL; + char *plugin = NULL; + char *plugin_instance = NULL; + char *type = NULL; + char *type_instance = NULL; + + hostname = str; + if (hostname == NULL) + return (-1); + + plugin = strchr (hostname, '/'); + if (plugin == NULL) + return (-1); + *plugin = '\0'; plugin++; + + type = strchr (plugin, '/'); + if (type == NULL) + return (-1); + *type = '\0'; type++; + + plugin_instance = strchr (plugin, '-'); + if (plugin_instance != NULL) + { + *plugin_instance = '\0'; + plugin_instance++; + } + + type_instance = strchr (type, '-'); + if (type_instance != NULL) + { + *type_instance = '\0'; + type_instance++; + } + + *ret_host = hostname; + *ret_plugin = plugin; + *ret_plugin_instance = plugin_instance; + *ret_type = type; + *ret_type_instance = type_instance; + return (0); +} /* int parse_identifier */ + +int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds) +{ + int i; + char *dummy; + char *ptr; + char *saveptr; + + i = -1; + dummy = buffer; + saveptr = NULL; + while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL) + { + dummy = NULL; + + if (i >= vl->values_len) + break; + + if (i == -1) + { + if (strcmp ("N", ptr) == 0) + vl->time = time (NULL); + else + vl->time = (time_t) atoi (ptr); + } + else + { + 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); + } + + i++; + } /* while (strtok_r) */ + + if ((ptr != NULL) || (i != vl->values_len)) + return (-1); + return (0); +} /* int parse_values */ + +#if !HAVE_GETPWNAM_R +int getpwnam_r (const char *name, struct passwd *pwbuf, char *buf, + size_t buflen, struct passwd **pwbufp) +{ + int status = 0; + struct passwd *pw; + + memset (pwbuf, '\0', sizeof (struct passwd)); + + pthread_mutex_lock (&getpwnam_r_lock); + + do + { + pw = getpwnam (name); + if (pw == NULL) + { + status = (errno != 0) ? errno : ENOENT; + break; + } + +#define GETPWNAM_COPY_MEMBER(member) \ + if (pw->member != NULL) \ + { \ + int len = strlen (pw->member); \ + if (len >= buflen) \ + { \ + status = ENOMEM; \ + break; \ + } \ + sstrncpy (buf, pw->member, buflen); \ + pwbuf->member = buf; \ + buf += (len + 1); \ + buflen -= (len + 1); \ + } + GETPWNAM_COPY_MEMBER(pw_name); + GETPWNAM_COPY_MEMBER(pw_passwd); + GETPWNAM_COPY_MEMBER(pw_gecos); + GETPWNAM_COPY_MEMBER(pw_dir); + GETPWNAM_COPY_MEMBER(pw_shell); + + pwbuf->pw_uid = pw->pw_uid; + pwbuf->pw_gid = pw->pw_gid; + + if (pwbufp != NULL) + *pwbufp = pwbuf; + } while (0); + + pthread_mutex_unlock (&getpwnam_r_lock); + + return (status); +} /* int getpwnam_r */ +#endif /* !HAVE_GETPWNAM_R */ + +int notification_init (notification_t *n, int severity, const char *message, + const char *host, + const char *plugin, const char *plugin_instance, + const char *type, const char *type_instance) +{ + memset (n, '\0', sizeof (notification_t)); + + n->severity = severity; + + if (message != NULL) + sstrncpy (n->message, message, sizeof (n->message)); + if (host != NULL) + sstrncpy (n->host, host, sizeof (n->host)); + if (plugin != NULL) + sstrncpy (n->plugin, plugin, sizeof (n->plugin)); + if (plugin_instance != NULL) + sstrncpy (n->plugin_instance, plugin_instance, + sizeof (n->plugin_instance)); + if (type != NULL) + sstrncpy (n->type, type, sizeof (n->type)); + if (type_instance != NULL) + sstrncpy (n->type_instance, type_instance, + sizeof (n->type_instance)); + + return (0); +} /* int notification_init */ + +int walk_directory (const char *dir, dirwalk_callback_f callback, + void *user_data) +{ + struct dirent *ent; + DIR *dh; + int success; + int failure; + + success = 0; + failure = 0; + + if ((dh = opendir (dir)) == NULL) + { + char errbuf[1024]; + ERROR ("walk_directory: Cannot open '%s': %s", dir, + sstrerror (errno, errbuf, sizeof (errbuf))); + return -1; + } + + while ((ent = readdir (dh)) != NULL) + { + int status; + + if (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); +} + +int read_file_contents (const char *filename, char *buf, int bufsize) +{ + FILE *fh; + int n; + + 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) + { + if (old_value <= 4294967295U) + diff = (4294967295U - old_value) + new_value; + else + diff = (18446744073709551615ULL - old_value) + + new_value; + } + else + { + diff = new_value - old_value; + } + + return (diff); +} /* counter_t counter_to_gauge */