* this preserves principle of least surprise when dealing with files that
[rrdtool.git] / src / rrd_client.c
index 11fb80d..5583bfe 100644 (file)
@@ -212,6 +212,8 @@ static int response_read (rrdc_response_t **ret_response) /* {{{ */
 
   if (ret->status <= 0)
   {
+    if (ret->status < 0)
+      rrd_set_error("rrdcached: %s", ret->message);
     *ret_response = ret;
     return (0);
   }
@@ -266,6 +268,8 @@ static int request (const char *buffer, size_t buffer_size, /* {{{ */
   {
     close_connection ();
     pthread_mutex_unlock (&lock);
+    rrd_set_error("request: socket error (%d) while talking to rrdcached",
+                  status);
     return (-1);
   }
   fflush (sh);
@@ -276,7 +280,11 @@ static int request (const char *buffer, size_t buffer_size, /* {{{ */
   pthread_mutex_unlock (&lock);
 
   if (status != 0)
+  {
+    if (status < 0)
+      rrd_set_error("request: internal error while talking to rrdcached");
     return (status);
+  }
 
   *ret_response = res;
   return (0);
@@ -347,15 +355,22 @@ static int rrdc_connect_unix (const char *path) /* {{{ */
   return (0);
 } /* }}} int rrdc_connect_unix */
 
-static int rrdc_connect_network (const char *addr) /* {{{ */
+static int rrdc_connect_network (const char *addr_orig) /* {{{ */
 {
   struct addrinfo ai_hints;
   struct addrinfo *ai_res;
   struct addrinfo *ai_ptr;
+  char addr_copy[NI_MAXHOST];
+  char *addr;
+  char *port;
 
-  assert (addr != NULL);
+  assert (addr_orig != NULL);
   assert (sd == -1);
 
+  strncpy(addr_copy, addr_orig, sizeof(addr_copy));
+  addr_copy[sizeof(addr_copy) - 1] = '\0';
+  addr = addr_copy;
+
   int status;
   memset (&ai_hints, 0, sizeof (ai_hints));
   ai_hints.ai_flags = 0;
@@ -365,8 +380,45 @@ static int rrdc_connect_network (const char *addr) /* {{{ */
   ai_hints.ai_family = AF_UNSPEC;
   ai_hints.ai_socktype = SOCK_STREAM;
 
+  port = NULL;
+  if (*addr == '[') /* IPv6+port format */
+  {
+    /* `addr' is something like "[2001:780:104:2:211:24ff:feab:26f8]:12345" */
+    addr++;
+
+    port = strchr (addr, ']');
+    if (port == NULL)
+    {
+      rrd_set_error("malformed address: %s", addr_orig);
+      return (-1);
+    }
+    *port = 0;
+    port++;
+
+    if (*port == ':')
+      port++;
+    else if (*port == 0)
+      port = NULL;
+    else
+    {
+      rrd_set_error("garbage after address: %s", port);
+      return (-1);
+    }
+  } /* if (*addr = ']') */
+  else if (strchr (addr, '.') != NULL) /* Hostname or IPv4 */
+  {
+    port = rindex(addr, ':');
+    if (port != NULL)
+    {
+      *port = 0;
+      port++;
+    }
+  }
+
   ai_res = NULL;
-  status = getaddrinfo (addr, RRDCACHED_DEFAULT_PORT, &ai_hints, &ai_res);
+  status = getaddrinfo (addr,
+                        port == NULL ? RRDCACHED_DEFAULT_PORT : port,
+                        &ai_hints, &ai_res);
   if (status != 0)
     return (status);
 
@@ -466,6 +518,7 @@ int rrdc_update (const char *filename, int values_num, /* {{{ */
   rrdc_response_t *res;
   int status;
   int i;
+  char file_path[PATH_MAX];
 
   memset (buffer, 0, sizeof (buffer));
   buffer_ptr = &buffer[0];
@@ -475,6 +528,10 @@ 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;
+
   status = buffer_add_string (filename, &buffer_ptr, &buffer_free);
   if (status != 0)
     return (ENOBUFS);
@@ -510,6 +567,7 @@ int rrdc_flush (const char *filename) /* {{{ */
   size_t buffer_size;
   rrdc_response_t *res;
   int status;
+  char file_path[PATH_MAX];
 
   if (filename == NULL)
     return (-1);
@@ -522,6 +580,10 @@ 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;
+
   status = buffer_add_string (filename, &buffer_ptr, &buffer_free);
   if (status != 0)
     return (ENOBUFS);
@@ -560,7 +622,7 @@ int rrdc_flush_if_daemon (const char *opt_daemon, const char *filename) /* {{{ *
       rrd_set_error ("rrdc_flush (%s) failed with status %i.",
                      filename, status);
     }
-  } /* if (daemon_addr) */
+  } /* if (rrdc_is_connected(..)) */
 
   return status;
 } /* }}} int rrdc_flush_if_daemon */
@@ -689,7 +751,7 @@ void rrdc_stats_free (rrdc_stats_t *ret_stats) /* {{{ */
 
     if (this->name != NULL)
     {
-      free (this->name);
+      free ((char *)this->name);
       this->name = NULL;
     }
     free (this);