contrib/exec-nagios.px: Added a Perl script which handles Nagios plugins.
[collectd.git] / src / common.c
index 98e6704..e805041 100644 (file)
@@ -1,81 +1,56 @@
 /**
  * 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 "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[] =
-{
-       "AVERAGE",
-       "MIN",
-       "MAX",
-       NULL
-};
-static int rra_types_num = 3;
-#endif /* HAVE_LIBRRD */
+#if !HAVE_STRERROR_R
+static pthread_mutex_t strerror_r_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
 
 void sstrncpy (char *d, const char *s, int len)
 {
@@ -92,20 +67,68 @@ char *sstrdup (const char *s)
 
        if((r = strdup (s)) == NULL)
        {
-               DBG ("Not enough memory.");
+               DEBUG ("Not enough memory.");
                exit(3);
        }
 
        return (r);
 }
 
+/* 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);
+               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 */
+
 void *smalloc (size_t size)
 {
        void *r;
 
        if ((r = malloc (size)) == NULL)
        {
-               DBG("Not enough memory.");
+               DEBUG("Not enough memory.");
                exit(3);
        }
 
@@ -144,7 +167,16 @@ ssize_t sread (int fd, void *buf, size_t count)
                if (status < 0)
                        return (status);
 
-               assert (nleft >= 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;
@@ -184,10 +216,12 @@ 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", &saveptr)) != NULL)
        {
                ptr = NULL;
                i++;
@@ -203,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);
@@ -216,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))
                {
@@ -258,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)
 {
@@ -273,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++)
        {
@@ -286,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)
 {
@@ -311,7 +349,7 @@ int timeval_sub_timespec (struct timeval *tv0, struct timeval *tv1, struct times
        return (0);
 }
 
-static int check_create_dir (const char *file_orig)
+int check_create_dir (const char *file_orig)
 {
        struct stat statbuf;
 
@@ -321,7 +359,9 @@ static int check_create_dir (const char *file_orig)
        char *fields[16];
        int   fields_num;
        char *ptr;
+       char *saveptr;
        int   last_is_file = 1;
+       int   path_is_absolute = 0;
        int   len;
        int   i;
 
@@ -342,9 +382,11 @@ static 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';
@@ -354,8 +396,9 @@ static int check_create_dir (const char *file_orig)
         * 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++;
@@ -376,16 +419,18 @@ static int check_create_dir (const char *file_orig)
                 */
                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);
                }
 
@@ -395,440 +440,344 @@ static int check_create_dir (const char *file_orig)
                        {
                                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 buffer[64];
-
-       if ((rra_num != 0) && (rra_def != NULL))
-       {
-               *ret = rra_def;
-               return (rra_num);
-       }
-
-       if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
+       char ident[128];
+       
+       if (kc == NULL)
                return (-1);
-       memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
-
-       step = atoi (COLLECTD_STEP);
-       rows = atoi (COLLECTD_ROWS);
 
-       if ((step <= 0) || (rows <= 0))
-       {
-               *ret = NULL;
-               return (-1);
-       }
+       snprintf (ident, 128, "%s,%i,%s", module, instance, name);
+       ident[127] = '\0';
 
-       cdp_len = 0;
-       for (i = 0; i < rra_timespans_num; i++)
+       if (*ksp_ptr == NULL)
        {
-               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 ((*ksp_ptr = kstat_lookup (kc, module, instance, name)) == NULL)
                {
-                       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;
-                       }
+                       ERROR ("Cound not find kstat %s", ident);
+                       return (-1);
+               }
 
-                       rra_def[rra_num++] = sstrdup (buffer);
+               if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
+               {
+                       WARNING ("kstat %s has wrong type", ident);
+                       *ksp_ptr = NULL;
+                       return (-1);
                }
        }
 
-#if COLLECT_DEBUG
-       DBG ("rra_num = %i", rra_num);
-       for (i = 0; i < rra_num; i++)
-               DBG ("  %s", rra_def[i]);
+#ifdef assert
+       assert (*ksp_ptr != NULL);
+       assert ((*ksp_ptr)->ks_type == KSTAT_TYPE_NAMED);
 #endif
 
-       *ret = rra_def;
-       return (rra_num);
-}
-#endif /* HAVE_LIBRRD */
-
-static int log_create_file (char *filename, char **ds_def, int ds_num)
-{
-       FILE *log;
-       int i;
-
-       if (check_create_dir (filename))
-               return (-1);
-
-       log = fopen (filename, "w");
-       if (log == NULL)
+       if (kstat_read (kc, *ksp_ptr, NULL) == -1)
        {
-               syslog (LOG_WARNING, "Failed to create %s: %s", filename,
-                               strerror(errno));
+               WARNING ("kstat %s could not be read", ident);
                return (-1);
        }
 
-       fprintf (log, "epoch");
-       for (i = 0; i < ds_num; i++)
+       if ((*ksp_ptr)->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);
+               WARNING ("kstat %s has wrong type", ident);
+               return (-1);
        }
-       fprintf(log, "\n");
-       fclose(log);
 
-       return 0;
+       return (0);
 }
 
-static int log_update_file (char *host, char *file, char *values,
-               char **ds_def, int ds_num)
+long long get_kstat_value (kstat_t *ksp, char *name)
 {
-       char *tmp;
-       FILE *fp;
-       struct stat statbuf;
-       char full_file[1024];
-
-       /* Cook the values a bit: Substitute colons with commas */
-       strsubstitute (values, ':', ',');
+       kstat_named_t *kn;
+       long long retval = -1LL;
 
-       /* host == NULL => local mode */
-       if (host != NULL)
+#ifdef assert
+       assert (ksp != NULL);
+       assert (ksp->ks_type == KSTAT_TYPE_NAMED);
+#else
+       if (ksp == NULL)
        {
-               if (snprintf (full_file, 1024, "%s/%s", host, file) >= 1024)
-                       return (-1);
+               fprintf (stderr, "ERROR: %s:%i: ksp == NULL\n", __FILE__, __LINE__);
+               return (-1LL);
        }
-       else
+       else if (ksp->ks_type != KSTAT_TYPE_NAMED)
        {
-               if (snprintf (full_file, 1024, "%s", file) >= 1024)
-                       return (-1);
+               fprintf (stderr, "ERROR: %s:%i: ksp->ks_type != KSTAT_TYPE_NAMED\n", __FILE__, __LINE__);
+               return (-1LL);
        }
+#endif
 
-       strncpy (full_file, file, 1024);
+       if ((kn = (kstat_named_t *) kstat_data_lookup (ksp, name)) == NULL)
+               return (retval);
 
-       tmp = full_file + strlen (full_file) - 4;
-       assert ((tmp != NULL) && (tmp > full_file));
+       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 */
 
-       /* Change the filename for logfiles. */
-       if (strncmp (tmp, ".rrd", 4) == 0)
-       {
-               time_t now;
-               struct tm *tm;
+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 */
 
-               /* TODO: Find a way to minimize the calls to `localtime', since
-                * they are pretty expensive.. */
-               now = time (NULL);
-               tm = localtime (&now);
+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 */
 
-               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 = snprintf (ret, ret_len, "%s/%s/%s",
+                                       hostname, plugin, type);
                else
-               {
-                       syslog (LOG_ERR, "stat %s: %s", full_file, strerror (errno));
-                       return (-1);
-               }
+                       status = snprintf (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 = snprintf (ret, ret_len, "%s/%s-%s/%s",
+                                       hostname, plugin, plugin_instance,
+                                       type);
+               else
+                       status = snprintf (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)
-       {
-               syslog (LOG_WARNING, "kstat %s could not be read", ident);
-               return (-1);
-       }
+               if (pwbufp != NULL)
+                       *pwbufp = pwbuf;
+       } while (0);
 
-       if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED)
-       {
-               syslog (LOG_WARNING, "kstat %s has wrong type", ident);
-               return (-1);
-       }
+       pthread_mutex_unlock (&getpwnam_r_lock);
 
-       return (0);
-}
+       return (status);
+} /* int getpwnam_r */
+#endif /* !HAVE_GETPWNAM_R */
 
-long long get_kstat_value (kstat_t *ksp, char *name)
+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)
 {
-       kstat_named_t *kn;
-       long long retval = -1LL;
+       memset (n, '\0', sizeof (notification_t));
 
-#ifdef assert
-       assert (ksp != NULL);
-       assert (ksp->ks_type == KSTAT_TYPE_NAMED);
-#else
-       if (ksp == NULL)
-       {
-               fprintf (stderr, "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__);
-               return (-1LL);
-       }
-#endif
+       n->severity = severity;
 
-       if ((kn = (kstat_named_t *) kstat_data_lookup (ksp, name)) == NULL)
-               return (retval);
+       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';
 
-       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 (0);
+} /* int notification_init */