contrib/exec-nagios.px: Added a Perl script which handles Nagios plugins.
[collectd.git] / src / common.c
index 6521a58..e805041 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
  *   Niki W. Waibel <niki.waibel@gmx.net>
 **/
 
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
 #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
 
+#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
+
 void sstrncpy (char *d, const char *s, int len)
 {
        strncpy (d, s, len);
@@ -58,12 +74,51 @@ char *sstrdup (const char *s)
        return (r);
 }
 
-/* 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);
+               strncpy (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'))
+                               strncpy (buf, temp, buflen);
+                       else
+                               strncpy (buf, "strerror_r did not return "
+                                               "an error message", buflen);
+               }
+       }
+/* #endif STRERROR_R_CHAR_P */
+
+#else
+       if (strerror_r (errnum, buf, buflen) != 0)
+       {
+               snprintf (buf, buflen, "Error #%i; "
+                               "Additionally, strerror_r failed.",
+                               errnum);
+       }
+#endif /* STRERROR_R_CHAR_P */
+
+       buf[buflen - 1] = '\0';
        return (buf);
 } /* char *sstrerror */
 
@@ -121,7 +176,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;
@@ -182,8 +237,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);
@@ -195,7 +250,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))
                {
@@ -237,7 +292,7 @@ int strsubstitute (char *str, char c_from, char c_to)
        }
 
        return (ret);
-}
+} /* int strsubstitute */
 
 int escape_slashes (char *buf, int buf_len)
 {
@@ -252,8 +307,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++)
        {
@@ -265,7 +324,7 @@ int escape_slashes (char *buf, int buf_len)
        buf[i] = '\0';
 
        return (0);
-}
+} /* int escape_slashes */
 
 int timeval_sub_timespec (struct timeval *tv0, struct timeval *tv1, struct timespec *ret)
 {
@@ -382,7 +441,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);
@@ -405,7 +464,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)
@@ -547,3 +606,178 @@ int format_name (char *ret, int 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)
+               strncpy (n->message, message, sizeof (n->message));
+       if (host != NULL)
+               strncpy (n->host, host, sizeof (n->host));
+       if (plugin != NULL)
+               strncpy (n->plugin, plugin, sizeof (n->plugin));
+       if (plugin_instance != NULL)
+               strncpy (n->plugin_instance, plugin_instance,
+                               sizeof (n->plugin_instance));
+       if (type != NULL)
+               strncpy (n->type, type, sizeof (n->type));
+       if (type_instance != NULL)
+               strncpy (n->type_instance, type_instance,
+                               sizeof (n->type_instance));
+
+       n->message[sizeof (n->message) - 1] = '\0';
+       n->host[sizeof (n->host) - 1] = '\0';
+       n->plugin[sizeof (n->plugin) - 1] = '\0';
+       n->plugin_instance[sizeof (n->plugin_instance) - 1] = '\0';
+       n->type[sizeof (n->type) - 1] = '\0';
+       n->type_instance[sizeof (n->type_instance) - 1] = '\0';
+
+       return (0);
+} /* int notification_init */