email plugin: Avoid strtok_r to tokenize input.
[collectd.git] / src / powerdns.c
index 5f7a542..da72ec8 100644 (file)
     ERROR("powerdns plugin: %s failed: %s", func,                              \
           sstrerror(errno, errbuf, sizeof(errbuf)));                           \
   } while (0)
+#define SOCK_ERROR(func, sockpath)                                             \
+  do {                                                                         \
+    char errbuf[1024];                                                         \
+    ERROR("powerdns plugin: Socket `%s` %s failed: %s", sockpath, func,        \
+          sstrerror(errno, errbuf, sizeof(errbuf)));                           \
+  } while (0)
 
 #define SERVER_SOCKET LOCALSTATEDIR "/run/pdns.controlsocket"
 #define SERVER_COMMAND "SHOW * \n"
@@ -314,9 +320,9 @@ static char *local_sockpath = NULL;
 
 /* <https://doc.powerdns.com/md/recursor/stats/> */
 static void submit(const char *plugin_instance, /* {{{ */
-                   const char *pdns_type, const char *value) {
+                   const char *pdns_type, const char *value_str) {
   value_list_t vl = VALUE_LIST_INIT;
-  value_t values[1];
+  value_t value;
 
   const char *type = NULL;
   const char *type_instance = NULL;
@@ -330,7 +336,7 @@ static void submit(const char *plugin_instance, /* {{{ */
 
   if (i >= lookup_table_length) {
     INFO("powerdns plugin: submit: Not found in lookup table: %s = %s;",
-         pdns_type, value);
+         pdns_type, value_str);
     return;
   }
 
@@ -355,16 +361,15 @@ static void submit(const char *plugin_instance, /* {{{ */
     return;
   }
 
-  if (0 != parse_value(value, &values[0], ds->ds[0].type)) {
+  if (0 != parse_value(value_str, &value, ds->ds[0].type)) {
     ERROR("powerdns plugin: Cannot convert `%s' "
           "to a number.",
-          value);
+          value_str);
     return;
   }
 
-  vl.values = values;
+  vl.values = &value;
   vl.values_len = 1;
-  sstrncpy(vl.host, hostname_g, sizeof(vl.host));
   sstrncpy(vl.plugin, "powerdns", sizeof(vl.plugin));
   sstrncpy(vl.type, type, sizeof(vl.type));
   if (type_instance != NULL)
@@ -374,8 +379,8 @@ static void submit(const char *plugin_instance, /* {{{ */
   plugin_dispatch_values(&vl);
 } /* }}} static void submit */
 
-static int powerdns_get_data_dgram(list_item_t *item, /* {{{ */
-                                   char **ret_buffer, size_t *ret_buffer_size) {
+static int powerdns_get_data_dgram(list_item_t *item, char **ret_buffer) {
+  /* {{{ */
   int sd;
   int status;
 
@@ -385,7 +390,6 @@ static int powerdns_get_data_dgram(list_item_t *item, /* {{{ */
 
   struct sockaddr_un sa_unix = {0};
 
-  struct timeval stv_timeout;
   cdtime_t cdt_timeout;
 
   sd = socket(PF_UNIX, item->socktype, 0);
@@ -401,7 +405,7 @@ static int powerdns_get_data_dgram(list_item_t *item, /* {{{ */
 
   status = unlink(sa_unix.sun_path);
   if ((status != 0) && (errno != ENOENT)) {
-    FUNC_ERROR("unlink");
+    SOCK_ERROR("unlink", sa_unix.sun_path);
     close(sd);
     return (-1);
   }
@@ -412,14 +416,14 @@ static int powerdns_get_data_dgram(list_item_t *item, /* {{{ */
      * and otherwise the daemon cannot answer. */
     status = bind(sd, (struct sockaddr *)&sa_unix, sizeof(sa_unix));
     if (status != 0) {
-      FUNC_ERROR("bind");
+      SOCK_ERROR("bind", sa_unix.sun_path);
       break;
     }
 
     /* Make the socket writeable by the daemon.. */
     status = chmod(sa_unix.sun_path, 0666);
     if (status != 0) {
-      FUNC_ERROR("chmod");
+      SOCK_ERROR("chmod", sa_unix.sun_path);
       break;
     }
 
@@ -427,31 +431,30 @@ static int powerdns_get_data_dgram(list_item_t *item, /* {{{ */
     if (cdt_timeout < TIME_T_TO_CDTIME_T(2))
       cdt_timeout = TIME_T_TO_CDTIME_T(2);
 
-    CDTIME_T_TO_TIMEVAL(cdt_timeout, &stv_timeout);
-
-    status = setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, &stv_timeout,
-                        sizeof(stv_timeout));
+    status =
+        setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO,
+                   &CDTIME_T_TO_TIMEVAL(cdt_timeout), sizeof(struct timeval));
     if (status != 0) {
-      FUNC_ERROR("setsockopt");
+      SOCK_ERROR("setsockopt", sa_unix.sun_path);
       break;
     }
 
     status =
         connect(sd, (struct sockaddr *)&item->sockaddr, sizeof(item->sockaddr));
     if (status != 0) {
-      FUNC_ERROR("connect");
+      SOCK_ERROR("connect", sa_unix.sun_path);
       break;
     }
 
     status = send(sd, item->command, strlen(item->command), 0);
     if (status < 0) {
-      FUNC_ERROR("send");
+      SOCK_ERROR("send", sa_unix.sun_path);
       break;
     }
 
     status = recv(sd, temp, sizeof(temp), /* flags = */ 0);
     if (status < 0) {
-      FUNC_ERROR("recv");
+      SOCK_ERROR("recv", sa_unix.sun_path);
       break;
     }
     buffer_size = status + 1;
@@ -475,14 +478,11 @@ static int powerdns_get_data_dgram(list_item_t *item, /* {{{ */
   buffer[buffer_size - 1] = 0;
 
   *ret_buffer = buffer;
-  *ret_buffer_size = buffer_size;
-
   return (0);
 } /* }}} int powerdns_get_data_dgram */
 
-static int powerdns_get_data_stream(list_item_t *item, /* {{{ */
-                                    char **ret_buffer,
-                                    size_t *ret_buffer_size) {
+static int powerdns_get_data_stream(list_item_t *item, char **ret_buffer) {
+  /* {{{ */
   int sd;
   int status;
 
@@ -509,7 +509,7 @@ static int powerdns_get_data_stream(list_item_t *item, /* {{{ */
   status =
       connect(sd, (struct sockaddr *)&item->sockaddr, sizeof(item->sockaddr));
   if (status != 0) {
-    FUNC_ERROR("connect");
+    SOCK_ERROR("connect", item->sockaddr.sun_path);
     close(sd);
     return (-1);
   }
@@ -518,7 +518,7 @@ static int powerdns_get_data_stream(list_item_t *item, /* {{{ */
   status = send(sd, item->command, strlen(item->command) + 1,
                 /* flags = */ 0);
   if (status < 0) {
-    FUNC_ERROR("send");
+    SOCK_ERROR("send", item->sockaddr.sun_path);
     close(sd);
     return (-1);
   }
@@ -528,15 +528,16 @@ static int powerdns_get_data_stream(list_item_t *item, /* {{{ */
 
     status = recv(sd, temp, sizeof(temp), /* flags = */ 0);
     if (status < 0) {
-      FUNC_ERROR("recv");
+      SOCK_ERROR("recv", item->sockaddr.sun_path);
       break;
-    } else if (status == 0)
+    } else if (status == 0) {
       break;
+    }
 
     buffer_new = realloc(buffer, buffer_size + status + 1);
     if (buffer_new == NULL) {
       FUNC_ERROR("realloc");
-      status = -1;
+      status = ENOMEM;
       break;
     }
     buffer = buffer_new;
@@ -547,23 +548,20 @@ static int powerdns_get_data_stream(list_item_t *item, /* {{{ */
   } /* while (42) */
   close(sd);
 
-  if (status < 0) {
+  if (status != 0) {
     sfree(buffer);
-  } else {
-    assert(status == 0);
-    *ret_buffer = buffer;
-    *ret_buffer_size = buffer_size;
+    return status;
   }
 
-  return (status);
+  *ret_buffer = buffer;
+  return 0;
 } /* }}} int powerdns_get_data_stream */
 
-static int powerdns_get_data(list_item_t *item, char **ret_buffer,
-                             size_t *ret_buffer_size) {
+static int powerdns_get_data(list_item_t *item, char **ret_buffer) {
   if (item->socktype == SOCK_DGRAM)
-    return (powerdns_get_data_dgram(item, ret_buffer, ret_buffer_size));
+    return (powerdns_get_data_dgram(item, ret_buffer));
   else if (item->socktype == SOCK_STREAM)
-    return (powerdns_get_data_stream(item, ret_buffer, ret_buffer_size));
+    return (powerdns_get_data_stream(item, ret_buffer));
   else {
     ERROR("powerdns plugin: Unknown socket type: %i", (int)item->socktype);
     return (-1);
@@ -572,19 +570,6 @@ static int powerdns_get_data(list_item_t *item, char **ret_buffer,
 
 static int powerdns_read_server(list_item_t *item) /* {{{ */
 {
-  char *buffer = NULL;
-  size_t buffer_size = 0;
-  int status;
-
-  char *dummy;
-  char *saveptr;
-
-  char *key;
-  char *value;
-
-  const char *const *fields;
-  int fields_num;
-
   if (item->command == NULL)
     item->command = strdup(SERVER_COMMAND);
   if (item->command == NULL) {
@@ -592,16 +577,21 @@ static int powerdns_read_server(list_item_t *item) /* {{{ */
     return (-1);
   }
 
-  status = powerdns_get_data(item, &buffer, &buffer_size);
-  if (status != 0)
-    return (-1);
+  char *buffer = NULL;
+  int status = powerdns_get_data(item, &buffer);
+  if (status != 0) {
+    ERROR("powerdns plugin: powerdns_get_data failed.");
+    return (status);
+  }
+  if (buffer == NULL) {
+    return EINVAL;
+  }
 
+  const char *const *fields = default_server_fields;
+  int fields_num = default_server_fields_num;
   if (item->fields_num != 0) {
     fields = (const char *const *)item->fields;
     fields_num = item->fields_num;
-  } else {
-    fields = default_server_fields;
-    fields_num = default_server_fields_num;
   }
 
   assert(fields != NULL);
@@ -609,12 +599,13 @@ static int powerdns_read_server(list_item_t *item) /* {{{ */
 
   /* corrupt-packets=0,deferred-cache-inserts=0,deferred-cache-lookup=0,latency=0,packetcache-hit=0,packetcache-miss=0,packetcache-size=0,qsize-q=0,query-cache-hit=0,query-cache-miss=0,recursing-answers=0,recursing-questions=0,servfail-packets=0,tcp-answers=0,tcp-queries=0,timedout-packets=0,udp-answers=0,udp-queries=0,udp4-answers=0,udp4-queries=0,udp6-answers=0,udp6-queries=0,
    */
-  dummy = buffer;
-  saveptr = NULL;
+  char *dummy = buffer;
+  char *saveptr = NULL;
+  char *key;
   while ((key = strtok_r(dummy, ",", &saveptr)) != NULL) {
     dummy = NULL;
 
-    value = strchr(key, '=');
+    char *value = strchr(key, '=');
     if (value == NULL)
       break;
 
@@ -688,7 +679,6 @@ static int powerdns_update_recursor_command(list_item_t *li) /* {{{ */
 static int powerdns_read_recursor(list_item_t *item) /* {{{ */
 {
   char *buffer = NULL;
-  size_t buffer_size = 0;
   int status;
 
   char *dummy;
@@ -711,7 +701,7 @@ static int powerdns_read_recursor(list_item_t *item) /* {{{ */
   }
   assert(item->command != NULL);
 
-  status = powerdns_get_data(item, &buffer, &buffer_size);
+  status = powerdns_get_data(item, &buffer);
   if (status != 0) {
     ERROR("powerdns plugin: powerdns_get_data failed.");
     return (-1);