Code

collectd.conf(5): Documented the option of the rrdtool-plugin.
[collectd.git] / src / common.c
index 72cc5589d42bd2b16697e7ea037f28b31e8296d7..cf2a63989f357600d3dc7aa011b551c90abf59f4 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/common.c
- * Copyright (C) 2005  Florian octo Forster
+ * Copyright (C) 2005,2006  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-
 #  include <math.h>
 #endif
 
-#ifdef HAVE_LIBKSTAT
-extern kstat_ctl_t *kc;
+/* for ntohl and htonl */
+#if HAVE_ARPA_INET_H
+# include <arpa/inet.h>
 #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;
-#endif
+extern int operating_mode;
 
-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 */
+#ifdef HAVE_LIBKSTAT
+extern kstat_ctl_t *kc;
+#endif
 
 void sstrncpy (char *d, const char *s, int len)
 {
@@ -123,6 +88,70 @@ 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)
+               {
+                       DBG ("Received EOF from fd %i. "
+                                       "Closing fd and returning error.",
+                                       fd);
+                       close (fd);
+                       return (-1);
+               }
+
+               assert (nleft >= 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;
@@ -182,6 +211,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 escape_slashes (char *buf, int buf_len)
 {
        int i;
@@ -233,7 +283,6 @@ int timeval_sub_timespec (struct timeval *tv0, struct timeval *tv1, struct times
        return (0);
 }
 
-#ifdef HAVE_LIBRRD
 int check_create_dir (const char *file_orig)
 {
        struct stat statbuf;
@@ -338,146 +387,69 @@ int check_create_dir (const char *file_orig)
        return (0);
 }
 
-/* * * * *
- * Magic *
- * * * * */
-int rra_get (char ***ret)
+static int log_create_file (char *filename, char **ds_def, int ds_num)
 {
-       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);
-       }
+       FILE *log;
+       int i;
 
-       if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
+       if (check_create_dir (filename))
                return (-1);
-       memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
-
-       step = atoi (COLLECTD_STEP);
-       rows = atoi (COLLECTD_ROWS);
 
-       if ((step <= 0) || (rows <= 0))
+       log = fopen (filename, "w");
+       if (log == NULL)
        {
-               *ret = NULL;
+               syslog (LOG_WARNING, "Failed to create %s: %s", filename,
+                               strerror(errno));
                return (-1);
        }
 
-       cdp_len = 0;
-       for (i = 0; i < rra_timespans_num; i++)
+       fprintf (log, "epoch");
+       for (i = 0; i < ds_num; i++)
        {
-               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)));
+               char *name;
+               char *tmp;
 
-               for (j = 0; j < rra_types_num; j++)
+               name = strchr (ds_def[i], ':');
+               if (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;
-                       }
-
-                       rra_def[rra_num++] = sstrdup (buffer);
+                       syslog (LOG_WARNING, "Invalid DS definition '%s' for %s",
+                                       ds_def[i], filename);
+                       fclose(log);
+                       remove(filename);
+                       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);
-}
-
-int rrd_create_file (char *filename, char **ds_def, int ds_num)
-{
-       char **argv;
-       int argc;
-       char **rra_def;
-       int rra_num;
-       int i, j;
-       int status = 0;
-
-       if (check_create_dir (filename))
-               return (-1);
-
-       if ((rra_num = rra_get (&rra_def)) < 1)
-       {
-               syslog (LOG_ERR, "rra_create failed: Could not calculate RRAs");
-               return (-1);
-       }
-
-       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] = COLLECTD_STEP;
+               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);
+               }
 
-       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;
+               /* The `%.*s' is needed because there is no null-byte behind
+                * the name. */
+               fprintf(log, ",%.*s", (int) (tmp - name), name);
        }
+       fprintf(log, "\n");
+       fclose(log);
 
-       free (argv);
-       
-       return (status);
+       return 0;
 }
-#endif /* HAVE_LIBRRD */
 
-int rrd_update_file (char *host, char *file, char *values,
+int log_update_file (char *host, char *file, char *values,
                char **ds_def, int ds_num)
 {
-#ifdef HAVE_LIBRRD
+       char *tmp;
+       FILE *fp;
        struct stat statbuf;
        char full_file[1024];
-       char *argv[4] = { "update", full_file, values, NULL };
+
+       /* Cook the values a bit: Substitute colons with commas */
+       strsubstitute (values, ':', ',');
 
        /* host == NULL => local mode */
        if (host != NULL)
@@ -491,11 +463,35 @@ int rrd_update_file (char *host, char *file, char *values,
                        return (-1);
        }
 
+       strncpy (full_file, file, 1024);
+
+       tmp = full_file + strlen (full_file) - 4;
+       assert ((tmp != NULL) && (tmp > full_file));
+
+       /* Change the filename for logfiles. */
+       if (strncmp (tmp, ".rrd", 4) == 0)
+       {
+               time_t now;
+               struct tm *tm;
+
+               /* TODO: Find a way to minimize the calls to `localtime', since
+                * they are pretty expensive.. */
+               now = time (NULL);
+               tm = localtime (&now);
+
+               strftime (tmp, 1024 - (tmp - full_file), "-%Y-%m-%d", tm);
+
+               /* `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);
+
        if (stat (full_file, &statbuf) == -1)
        {
                if (errno == ENOENT)
                {
-                       if (rrd_create_file (full_file, ds_def, ds_num))
+                       if (log_create_file (full_file, ds_def, ds_num))
                                return (-1);
                }
                else
@@ -510,17 +506,20 @@ int rrd_update_file (char *host, char *file, char *values,
                return (-1);
        }
 
-       optind = 0; /* bug in librrd? */
-       rrd_clear_error ();
-       if (rrd_update (3, argv) == -1)
+
+       fp = fopen (full_file, "a");
+       if (fp == NULL)
        {
-               syslog (LOG_WARNING, "rrd_update failed: %s: %s", full_file, rrd_get_error ());
+               syslog (LOG_WARNING, "Failed to append to %s: %s", full_file,
+                               strerror(errno));
                return (-1);
        }
-#endif /* HAVE_LIBRRD */
+       fprintf(fp, "%s\n", values);
+       fclose(fp);
 
        return (0);
-}
+} /* int log_update_file */
+
 
 #ifdef HAVE_LIBKSTAT
 int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name)
@@ -607,3 +606,21 @@ long long get_kstat_value (kstat_t *ksp, char *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 htonll (unsigned long long n)
+{
+#if __BYTE_ORDER == __BIG_ENDIAN
+       return (n);
+#else
+       return (((unsigned long long) htonl (n)) << 32) + htonl (n >> 32);
+#endif
+}