X-Git-Url: https://git.octo.it/?p=rrdtool.git;a=blobdiff_plain;f=src%2Frrd_client.c;h=0b69000f26b1e01e0469289f31ef0f8c510fe776;hp=11fb80dc19cb25135c277ca68a8d234deeb0bbc3;hb=b4fd5d71cb3e4bdb9e12cc22f3d1373123c7e050;hpb=bfe17937473b1b69f0a0af5797d22205048ff416 diff --git a/src/rrd_client.c b/src/rrd_client.c index 11fb80d..0b69000 100644 --- a/src/rrd_client.c +++ b/src/rrd_client.c @@ -17,14 +17,17 @@ * * Authors: * Florian octo Forster + * Sebastian tokkee Harl **/ #include "rrd.h" -#include "rrd_client.h" #include "rrd_tool.h" +#include "rrd_client.h" +#include #include #include +#include #include #include #include @@ -32,6 +35,7 @@ #include #include #include +#include #ifndef ENODATA #define ENODATA ENOENT @@ -51,6 +55,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) /* {{{ */ { @@ -212,6 +255,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); } @@ -253,19 +298,15 @@ 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); } fflush (sh); @@ -273,10 +314,12 @@ 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) + rrd_set_error("request: internal error while talking to rrdcached"); return (status); + } *ret_response = res; return (0); @@ -347,15 +390,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,10 +415,52 @@ 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 + { + 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); + { + 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) { @@ -426,6 +518,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] == '/') @@ -436,10 +529,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); @@ -466,6 +567,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,15 +577,29 @@ int rrdc_update (const char *filename, int values_num, /* {{{ */ if (status != 0) return (ENOBUFS); + 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)); @@ -493,6 +609,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); @@ -510,6 +628,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,9 +641,20 @@ int rrdc_flush (const char *filename) /* {{{ */ if (status != 0) return (ENOBUFS); + 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; @@ -533,6 +663,8 @@ int rrdc_flush (const char *filename) /* {{{ */ res = NULL; status = request (buffer, buffer_size, &res); + pthread_mutex_unlock (&lock); + if (status != 0) return (status); @@ -554,13 +686,23 @@ int rrdc_flush_if_daemon (const char *opt_daemon, const char *filename) /* {{{ * if (rrdc_is_connected(opt_daemon)) { + rrd_clear_error(); status = rrdc_flush (filename); - if (status != 0) + + if (status != 0 && !rrd_test_error()) { - rrd_set_error ("rrdc_flush (%s) failed with status %i.", - filename, status); + if (status > 0) + { + rrd_set_error("rrdc_flush (%s) failed: %s", + filename, rrd_strerror(status)); + } + else if (status < 0) + { + 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 */ @@ -587,7 +729,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); @@ -689,7 +834,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);