Code

Imported upstream SVN snapshot 1.4~rc2+20091004.
authorSebastian Harl <sh@tokkee.org>
Sun, 4 Oct 2009 13:25:34 +0000 (15:25 +0200)
committerSebastian Harl <sh@tokkee.org>
Sun, 4 Oct 2009 13:25:34 +0000 (15:25 +0200)
This is based on SVN trunk at revision 1930.

src/rrd_client.c
src/rrd_daemon.c
src/rrd_fetch.c
src/rrd_fetch_libdbi.c
src/rrd_flushcached.c
src/rrd_tool.h

index 8e606640455eaa01b47d6f4ff7c7771c2b746a34..a4f1ba9c86fd8022db488da266547af6b8fba4f9 100644 (file)
@@ -17,6 +17,7 @@
  *
  * Authors:
  *   Florian octo Forster <octo at verplant.org>
+ *   Sebastian tokkee Harl <sh at tokkee.org>
  **/
 
 #include "rrd.h"
@@ -51,6 +52,45 @@ static int sd = -1;
 static FILE *sh = NULL;
 static char *sd_path = NULL; /* cache the path for sd */
 
+/* get_path: Return a path name appropriate to be sent to the daemon.
+ *
+ * When talking to a local daemon (thru a UNIX socket), relative path names
+ * are resolved to absolute path names to allow for transparent integration
+ * into existing solutions (as requested by Tobi). Else, absolute path names
+ * are not allowed, since path name translation is done by the server.
+ *
+ * One must hold `lock' when calling this function. */
+static const char *get_path (const char *path, char *resolved_path) /* {{{ */
+{
+  const char *ret = path;
+  int is_unix = 0;
+
+  if ((*sd_path == '/')
+      || (strncmp ("unix:", sd_path, strlen ("unix:")) == 0))
+    is_unix = 1;
+
+  if (*path == '/') /* absolute path */
+  {
+    if (! is_unix)
+    {
+      rrd_set_error ("absolute path names not allowed when talking "
+          "to a remote daemon");
+      return (NULL);
+    }
+    /* else: nothing to do */
+  }
+  else /* relative path */
+  {
+    if (is_unix)
+    {
+      realpath (path, resolved_path);
+      ret = resolved_path;
+    }
+    /* else: nothing to do */
+  }
+  return (ret);
+} /* }}} char *get_path */
+
 /* One must hold `lock' when calling `close_connection'. */
 static void close_connection (void) /* {{{ */
 {
@@ -255,19 +295,13 @@ static int request (const char *buffer, size_t buffer_size, /* {{{ */
   int status;
   rrdc_response_t *res;
 
-  pthread_mutex_lock (&lock);
-
   if (sh == NULL)
-  {
-    pthread_mutex_unlock (&lock);
     return (ENOTCONN);
-  }
 
   status = (int) fwrite (buffer, buffer_size, /* nmemb = */ 1, sh);
   if (status != 1)
   {
     close_connection ();
-    pthread_mutex_unlock (&lock);
     rrd_set_error("request: socket error (%d) while talking to rrdcached",
                   status);
     return (-1);
@@ -277,8 +311,6 @@ static int request (const char *buffer, size_t buffer_size, /* {{{ */
   res = NULL;
   status = response_read (&res);
 
-  pthread_mutex_unlock (&lock);
-
   if (status != 0)
   {
     if (status < 0)
@@ -404,8 +436,8 @@ static int rrdc_connect_network (const char *addr_orig) /* {{{ */
       rrd_set_error("garbage after address: %s", port);
       return (-1);
     }
-  } /* if (*addr = ']') */
-  else if (strchr (addr, '.') != NULL) /* Hostname or IPv4 */
+  } /* if (*addr == '[') */
+  else
   {
     port = rindex(addr, ':');
     if (port != NULL)
@@ -420,7 +452,12 @@ static int rrdc_connect_network (const char *addr_orig) /* {{{ */
                         port == NULL ? RRDCACHED_DEFAULT_PORT : port,
                         &ai_hints, &ai_res);
   if (status != 0)
-    return (status);
+  {
+    rrd_set_error ("failed to resolve address `%s' (port %s): %s",
+        addr, port == NULL ? RRDCACHED_DEFAULT_PORT : port,
+        gai_strerror (status));
+    return (-1);
+  }
 
   for (ai_ptr = ai_res; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
   {
@@ -478,6 +515,7 @@ int rrdc_connect (const char *addr) /* {{{ */
     close_connection();
   }
 
+  rrd_clear_error ();
   if (strncmp ("unix:", addr, strlen ("unix:")) == 0)
     status = rrdc_connect_unix (addr + strlen ("unix:"));
   else if (addr[0] == '/')
@@ -488,10 +526,18 @@ int rrdc_connect (const char *addr) /* {{{ */
   if (status == 0 && sd >= 0)
     sd_path = strdup(addr);
   else
+  {
+    char *err = rrd_test_error () ? rrd_get_error () : "Internal error";
+    /* err points the string that gets written to by rrd_set_error(), thus we
+     * cannot pass it to that function */
+    err = strdup (err);
     rrd_set_error("Unable to connect to rrdcached: %s",
                   (status < 0)
-                  ? "Internal error"
+                  ? (err ? err : "Internal error")
                   : rrd_strerror (status));
+    if (err != NULL)
+      free (err);
+  }
 
   pthread_mutex_unlock (&lock);
   return (status);
@@ -528,19 +574,29 @@ int rrdc_update (const char *filename, int values_num, /* {{{ */
   if (status != 0)
     return (ENOBUFS);
 
-  /* change to absolute path for rrdcached */
-  if (*filename != '/' && realpath(filename, file_path) != NULL)
-      filename = file_path;
+  pthread_mutex_lock (&lock);
+  filename = get_path (filename, file_path);
+  if (filename == NULL)
+  {
+    pthread_mutex_unlock (&lock);
+    return (-1);
+  }
 
   status = buffer_add_string (filename, &buffer_ptr, &buffer_free);
   if (status != 0)
+  {
+    pthread_mutex_unlock (&lock);
     return (ENOBUFS);
+  }
 
   for (i = 0; i < values_num; i++)
   {
     status = buffer_add_value (values[i], &buffer_ptr, &buffer_free);
     if (status != 0)
+    {
+      pthread_mutex_unlock (&lock);
       return (ENOBUFS);
+    }
   }
 
   assert (buffer_free < sizeof (buffer));
@@ -550,6 +606,8 @@ int rrdc_update (const char *filename, int values_num, /* {{{ */
 
   res = NULL;
   status = request (buffer, buffer_size, &res);
+  pthread_mutex_unlock (&lock);
+
   if (status != 0)
     return (status);
 
@@ -580,13 +638,20 @@ int rrdc_flush (const char *filename) /* {{{ */
   if (status != 0)
     return (ENOBUFS);
 
-  /* change to absolute path for rrdcached */
-  if (*filename != '/' && realpath(filename, file_path) != NULL)
-      filename = file_path;
+  pthread_mutex_lock (&lock);
+  filename = get_path (filename, file_path);
+  if (filename == NULL)
+  {
+    pthread_mutex_unlock (&lock);
+    return (-1);
+  }
 
   status = buffer_add_string (filename, &buffer_ptr, &buffer_free);
   if (status != 0)
+  {
+    pthread_mutex_unlock (&lock);
     return (ENOBUFS);
+  }
 
   assert (buffer_free < sizeof (buffer));
   buffer_size = sizeof (buffer) - buffer_free;
@@ -595,6 +660,8 @@ int rrdc_flush (const char *filename) /* {{{ */
 
   res = NULL;
   status = request (buffer, buffer_size, &res);
+  pthread_mutex_unlock (&lock);
+
   if (status != 0)
     return (status);
 
@@ -659,7 +726,10 @@ int rrdc_stats_get (rrdc_stats_t **ret_stats) /* {{{ */
    * }}} */
 
   res = NULL;
+  pthread_mutex_lock (&lock);
   status = request ("STATS\n", strlen ("STATS\n"), &res);
+  pthread_mutex_unlock (&lock);
+
   if (status != 0)
     return (status);
 
index 710fa017d747210882aeba6e9ecdba188b93c933..0ca1818d462b40e0bdd766c2de45eda6003178ef 100644 (file)
 #include <assert.h>
 #include <sys/time.h>
 #include <time.h>
+#include <libgen.h>
 
 #include <glib-2.0/glib.h>
 /* }}} */
@@ -348,12 +349,32 @@ static void install_signal_handlers(void) /* {{{ */
 static int open_pidfile(char *action, int oflag) /* {{{ */
 {
   int fd;
-  char *file;
+  const char *file;
+  char *file_copy, *dir;
 
   file = (config_pid_file != NULL)
     ? config_pid_file
     : LOCALSTATEDIR "/run/rrdcached.pid";
 
+  /* dirname may modify its argument */
+  file_copy = strdup(file);
+  if (file_copy == NULL)
+  {
+    fprintf(stderr, "rrdcached: strdup(): %s\n",
+        rrd_strerror(errno));
+    return -1;
+  }
+
+  dir = dirname(file_copy);
+  if (rrd_mkdir_p(dir, 0777) != 0)
+  {
+    fprintf(stderr, "Failed to create pidfile directory '%s': %s\n",
+        dir, rrd_strerror(errno));
+    return -1;
+  }
+
+  free(file_copy);
+
   fd = open(file, oflag, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH);
   if (fd < 0)
     fprintf(stderr, "rrdcached: can't %s pid file '%s' (%s)\n",
@@ -1652,6 +1673,9 @@ static int socket_permission_check (listen_socket_t *sock, /* {{{ */
 {
   ssize_t i;
 
+  if (sock == NULL) /* journal replay */
+    return (1);
+
   if (cmd == NULL)
     return (-1);
 
@@ -2239,11 +2263,31 @@ static int open_listen_socket_unix (const listen_socket_t *sock) /* {{{ */
   listen_socket_t *temp;
   int status;
   const char *path;
+  char *path_copy, *dir;
 
   path = sock->addr;
   if (strncmp(path, "unix:", strlen("unix:")) == 0)
     path += strlen("unix:");
 
+  /* dirname may modify its argument */
+  path_copy = strdup(path);
+  if (path_copy == NULL)
+  {
+    fprintf(stderr, "rrdcached: strdup(): %s\n",
+        rrd_strerror(errno));
+    return (-1);
+  }
+
+  dir = dirname(path_copy);
+  if (rrd_mkdir_p(dir, 0777) != 0)
+  {
+    fprintf(stderr, "Failed to create socket directory '%s': %s\n",
+        dir, rrd_strerror(errno));
+    return (-1);
+  }
+
+  free(path_copy);
+
   temp = (listen_socket_t *) rrd_realloc (listen_fds,
       sizeof (listen_fds[0]) * (listen_fds_num + 1));
   if (temp == NULL)
@@ -2346,8 +2390,8 @@ static int open_listen_socket_network(const listen_socket_t *sock) /* {{{ */
       fprintf (stderr, "rrdcached: Garbage after address: %s\n", port);
       return (-1);
     }
-  } /* if (*addr = ']') */
-  else if (strchr (addr, '.') != NULL) /* Hostname or IPv4 */
+  } /* if (*addr == '[') */
+  else
   {
     port = rindex(addr, ':');
     if (port != NULL)
@@ -2866,6 +2910,13 @@ static int read_options (int argc, char **argv) /* {{{ */
           return (3);
         }
 
+        if (rrd_mkdir_p (config_base_dir, 0777) != 0)
+        {
+          fprintf (stderr, "Failed to create base directory '%s': %s\n",
+              config_base_dir, rrd_strerror (errno));
+          return (3);
+        }
+
         /* make sure that the base directory is not resolved via
          * symbolic links.  this makes some performance-enhancing
          * assumptions possible (we don't have to resolve paths
@@ -2873,17 +2924,8 @@ static int read_options (int argc, char **argv) /* {{{ */
          */
         if (realpath(config_base_dir, base_realpath) == NULL)
         {
-          fprintf (stderr, "Invalid base directory '%s'.\n", config_base_dir);
-          return 5;
-        }
-        else if (strncmp(config_base_dir,
-                         base_realpath, sizeof(base_realpath)) != 0)
-        {
-          fprintf(stderr,
-                  "Base directory (-b) resolved via file system links!\n"
-                  "Please consult rrdcached '-b' documentation!\n"
-                  "Consider specifying the real directory (%s)\n",
-                  base_realpath);
+          fprintf (stderr, "Failed to canonicalize the base directory '%s': "
+              "%s\n", config_base_dir, rrd_strerror(errno));
           return 5;
         }
 
@@ -2901,6 +2943,24 @@ static int read_options (int argc, char **argv) /* {{{ */
         }
 
         _config_base_dir_len = len;
+
+        len = strlen (base_realpath);
+        while ((len > 0) && (base_realpath[len - 1] == '/'))
+        {
+          base_realpath[len - 1] = '\0';
+          len--;
+        }
+
+        if (strncmp(config_base_dir,
+                         base_realpath, sizeof(base_realpath)) != 0)
+        {
+          fprintf(stderr,
+                  "Base directory (-b) resolved via file system links!\n"
+                  "Please consult rrdcached '-b' documentation!\n"
+                  "Consider specifying the real directory (%s)\n",
+                  base_realpath);
+          return 5;
+        }
       }
       break;
 
index 2c30a980735dd40f24b6fb575672ea6e8c1ef865..b60ea158e53223651b6ac4c54a100c38f97fd000 100644 (file)
@@ -163,7 +163,7 @@ int rrd_fetch(
     *step = step_tmp;
 
     if (optind + 1 >= argc) {
-        rrd_set_error("not enough arguments");
+        rrd_set_error("Usage: rrdtool %s <file> <CF> [options]", argv[0]);
         return -1;
     }
 
index ad9a7664d0439af7fb20bb22e8a483b496e759fa..0e8bc939b32eab0bdc5c4999241fdaebb25be7ba 100644 (file)
@@ -17,20 +17,20 @@ struct sql_table_helper {
 };
 
 /* the prototypes */
-void _sql_close(struct sql_table_helper* th);
-int _sql_setparam(struct sql_table_helper* th,char* key, char* value);
-int _sql_fetchrow(struct sql_table_helper* th,time_t *timestamp, rrd_value_t *value,int ordered);
-char* _find_next_separator(char* start,char separator);
-char* _find_next_separator_twice(char*start,char separator);
-char _hexcharhelper(char c);
-int _inline_unescape (char* string);
-double rrd_fetch_dbi_double(dbi_result *result,int idx);
-long rrd_fetch_dbi_long(dbi_result *result,int idx);
+static void _sql_close(struct sql_table_helper* th);
+static int _sql_setparam(struct sql_table_helper* th,char* key, char* value);
+static int _sql_fetchrow(struct sql_table_helper* th,time_t *timestamp, rrd_value_t *value,int ordered);
+static char* _find_next_separator(char* start,char separator);
+static char* _find_next_separator_twice(char*start,char separator);
+static char _hexcharhelper(char c);
+static int _inline_unescape (char* string);
+static double rrd_fetch_dbi_double(dbi_result *result,int idx);
+static long rrd_fetch_dbi_long(dbi_result *result,int idx);
 
 /* the real code */
 
 /* helpers to get correctly converted values from DB*/
-long rrd_fetch_dbi_long(dbi_result *result,int idx) {
+static long rrd_fetch_dbi_long(dbi_result *result,int idx) {
   char *ptmp="";
   long value=DNAN;
   /* get the attributes for this filed */
@@ -87,7 +87,7 @@ long rrd_fetch_dbi_long(dbi_result *result,int idx) {
   return value;
 }
 
-double rrd_fetch_dbi_double(dbi_result *result,int idx) {
+static double rrd_fetch_dbi_double(dbi_result *result,int idx) {
   char *ptmp="";
   double value=DNAN;
   /* get the attributes for this filed */
@@ -144,7 +144,7 @@ double rrd_fetch_dbi_double(dbi_result *result,int idx) {
   return value;
 }
 
-void _sql_close(struct sql_table_helper* th) {
+static void _sql_close(struct sql_table_helper* th) {
   /* close only if connected */
   if (th->conn) {
     if (getenv("RRDDEBUGSQL")) { fprintf(stderr,"RRDDEBUGSQL: %li: close connection\n",time(NULL) ); }
@@ -158,7 +158,7 @@ void _sql_close(struct sql_table_helper* th) {
   }
 }
 
-int _sql_setparam(struct sql_table_helper* th,char* key, char* value) {
+static int _sql_setparam(struct sql_table_helper* th,char* key, char* value) {
   char* dbi_errstr=NULL;
   dbi_driver driver;
   /* if not connected */
@@ -200,7 +200,7 @@ int _sql_setparam(struct sql_table_helper* th,char* key, char* value) {
   return 0;
 }
 
-int _sql_fetchrow(struct sql_table_helper* th,time_t *timestamp, rrd_value_t *value,int ordered) {
+static int _sql_fetchrow(struct sql_table_helper* th,time_t *timestamp, rrd_value_t *value,int ordered) {
   char* dbi_errstr=NULL;
   char sql[10240];
   time_t startt=0,endt=0;
@@ -269,7 +269,7 @@ int _sql_fetchrow(struct sql_table_helper* th,time_t *timestamp, rrd_value_t *va
   return 1;
 }
 
-char* _find_next_separator(char* start,char separator) {
+static char* _find_next_separator(char* start,char separator) {
   char* found=strchr(start,separator);
   /* have we found it */
   if (found) {
@@ -282,7 +282,7 @@ char* _find_next_separator(char* start,char separator) {
   return NULL;
 }
 
-char* _find_next_separator_twice(char*start,char separator) {
+static char* _find_next_separator_twice(char*start,char separator) {
   char *found=start;
   /* find next separator in string*/
   while (found) {
@@ -300,7 +300,7 @@ char* _find_next_separator_twice(char*start,char separator) {
   return NULL;
 }
 
-char _hexcharhelper(char c) {
+static char _hexcharhelper(char c) {
   switch (c) {
   case '0': return 0 ; break;
   case '1': return 1 ; break;
@@ -328,7 +328,7 @@ char _hexcharhelper(char c) {
   return -1;
 }
 
-int _inline_unescape (char* string) {
+static int _inline_unescape (char* string) {
   char *src=string;
   char *dst=string;
   char c,h1,h2;
@@ -341,9 +341,15 @@ int _inline_unescape (char* string) {
       } else {
        /* try to calculate hex value from the next 2 values*/
        h1=_hexcharhelper(*src);
-       if (h1<0) { rrd_set_error( "string escape error at: %s\n",string);return(1); }
+       if (h1 == (char)-1) {
+         rrd_set_error("string escape error at: %s\n",string);
+         return(1);
+       }
        h2=_hexcharhelper(*(src+1));
-       if (h2<0) { rrd_set_error( "string escape error at: %s\n",string);return(1); }
+       if (h1 == (char)-1) {
+         rrd_set_error("string escape error at: %s\n",string);
+         return(1);
+       }
        c=h2+(h1<<4);
        /* increase src pointer by 2 skiping 2 chars */
        src+=2;
@@ -358,8 +364,8 @@ int _inline_unescape (char* string) {
 
 int
 rrd_fetch_fn_libdbi(
-    char           *filename,  /* name of the rrd */
-    enum cf_en     cf_idx,     /* which consolidation function ?*/
+    const char     *filename,  /* name of the rrd */
+    enum cf_en     cf_idx __attribute__((unused)), /* consolidation function */
     time_t         *start,
     time_t         *end,       /* which time frame do you want ?
                                * will be changed to represent reality */
index f7a715e110c85528ae991decff7ea10a8eecd5a7..5d18a1e211549e948f863c978771dbf2c1787bf8 100644 (file)
@@ -74,7 +74,6 @@ int rrd_flushcached (int argc, char **argv)
 
     /* try to connect to rrdcached */
     status = rrdc_connect(opt_daemon);
-    if (opt_daemon) free(opt_daemon);
     if (status != 0) return status;
 
     if (! rrdc_is_connected(opt_daemon))
@@ -107,6 +106,8 @@ int rrd_flushcached (int argc, char **argv)
         }
     }
 
+    if (opt_daemon) free(opt_daemon);
+
     return ((status == 0) ? 0 : -1);
 } /* int rrd_flush */
 
index c1c9728436a327ea5f4d924eb207f4fbb9a7c359..47d231db4bbf711f7a696e368a2d853fdf5b138e 100644 (file)
@@ -94,7 +94,7 @@ extern    "C" {
 
 
 #ifdef HAVE_LIBDBI
-int rrd_fetch_fn_libdbi(char *filename, enum cf_en cf_idx,
+int rrd_fetch_fn_libdbi(const char *filename, enum cf_en cf_idx,
                        time_t *start,time_t *end,
                        unsigned long *step,
                        unsigned long *ds_cnt,