Merge branch 'collectd-4.5'
[collectd.git] / src / common.c
index 1addb32..119d284 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/common.c
- * Copyright (C) 2005-2007  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 License as published by the
 # include "config.h"
 #endif
 
+#include "collectd.h"
 #include "common.h"
 #include "plugin.h"
 
+#if HAVE_PTHREAD_H
+# include <pthread.h>
+#endif
+
 #ifdef HAVE_MATH_H
-#  include <math.h>
+# include <math.h>
 #endif
 
 /* for ntohl and htonl */
 extern kstat_ctl_t *kc;
 #endif
 
-void sstrncpy (char *d, const char *s, int len)
+#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 (d, s, len);
-       d[len - 1] = '\0';
-}
+       strncpy (dest, src, n);
+       dest[n - 1] = '\0';
+
+       return (dest);
+} /* char *sstrncpy */
+
+int ssnprintf (char *dest, size_t n, const char *format, ...)
+{
+       int ret = 0;
+       va_list ap;
+
+       va_start (ap, format);
+       ret = vsnprintf (dest, n, format, ap);
+       dest[n - 1] = '\0';
+       va_end (ap);
+
+       return (ret);
+} /* int ssnprintf */
 
 char *sstrdup (const char *s)
 {
@@ -55,19 +83,57 @@ char *sstrdup (const char *s)
 
        if((r = strdup (s)) == NULL)
        {
-               DEBUG ("Not enough memory.");
-               exit(3);
+               ERROR ("Not enough memory.");
+               exit (3);
        }
 
        return (r);
-}
+} /* char *sstrdup */
 
-/* Don't use the return value of `strerror_r', because the GNU-people got
- * inventive there.. -octo */
+/* 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';
-       strerror_r (errnum, buf, buflen);
+
+#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 */
 
@@ -77,12 +143,12 @@ void *smalloc (size_t size)
 
        if ((r = malloc (size)) == NULL)
        {
-               DEBUG("Not enough memory.");
-               exit(3);
+               ERROR ("Not enough memory.");
+               exit (3);
        }
 
-       return r;
-}
+       return (r);
+} /* void *smalloc */
 
 #if 0
 void sfree (void **ptr)
@@ -125,7 +191,7 @@ ssize_t sread (int fd, void *buf, size_t count)
                        return (-1);
                }
 
-               assert (nleft >= status);
+               assert ((0 > status) || (nleft >= (size_t)status));
 
                nleft = nleft - status;
                ptr   = ptr   + status;
@@ -170,7 +236,7 @@ int strsplit (char *string, char **fields, size_t size)
        i = 0;
        ptr = string;
        saveptr = NULL;
-       while ((fields[i] = strtok_r (ptr, " \t", &saveptr)) != NULL)
+       while ((fields[i] = strtok_r (ptr, " \t\r\n", &saveptr)) != NULL)
        {
                ptr = NULL;
                i++;
@@ -186,8 +252,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);
@@ -199,7 +265,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))
                {
@@ -322,7 +388,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);
 
        /*
@@ -337,8 +403,7 @@ int check_create_dir (const char *file_orig)
        /*
         * 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
@@ -390,7 +455,7 @@ int check_create_dir (const char *file_orig)
                                if (mkdir (dir, 0755) == -1)
                                {
                                        char errbuf[1024];
-                                       ERROR ("mkdir (%s): %s", dir,
+                                       ERROR ("check_create_dir: mkdir (%s): %s", dir,
                                                        sstrerror (errno,
                                                                errbuf, sizeof (errbuf)));
                                        return (-1);
@@ -413,7 +478,7 @@ int check_create_dir (const char *file_orig)
        }
 
        return (0);
-}
+} /* check_create_dir */
 
 #ifdef HAVE_LIBKSTAT
 int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
@@ -423,8 +488,7 @@ 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)
        {
@@ -473,12 +537,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
@@ -503,7 +567,7 @@ long long get_kstat_value (kstat_t *ksp, char *name)
 
 unsigned long long ntohll (unsigned long long n)
 {
-#if __BYTE_ORDER == __BIG_ENDIAN
+#if BYTE_ORDER == BIG_ENDIAN
        return (n);
 #else
        return (((unsigned long long) ntohl (n)) << 32) + ntohl (n >> 32);
@@ -512,13 +576,90 @@ unsigned long long ntohll (unsigned long long n)
 
 unsigned long long htonll (unsigned long long n)
 {
-#if __BYTE_ORDER == __BIG_ENDIAN
+#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,
@@ -532,21 +673,21 @@ int format_name (char *ret, int ret_len,
        if ((plugin_instance == NULL) || (strlen (plugin_instance) == 0))
        {
                if ((type_instance == NULL) || (strlen (type_instance) == 0))
-                       status = snprintf (ret, ret_len, "%s/%s/%s",
+                       status = ssnprintf (ret, ret_len, "%s/%s/%s",
                                        hostname, plugin, type);
                else
-                       status = snprintf (ret, ret_len, "%s/%s/%s-%s",
+                       status = ssnprintf (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",
+                       status = ssnprintf (ret, ret_len, "%s/%s-%s/%s",
                                        hostname, plugin, plugin_instance,
                                        type);
                else
-                       status = snprintf (ret, ret_len, "%s/%s-%s/%s-%s",
+                       status = ssnprintf (ret, ret_len, "%s/%s-%s/%s-%s",
                                        hostname, plugin, plugin_instance,
                                        type, type_instance);
        }
@@ -643,3 +784,139 @@ int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
                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;
+}
+
+