libcollectdclient: Remove lcc_strdup().
[collectd.git] / src / libcollectdclient / client.c
index 98b7372..9ee02c9 100644 (file)
  *   Florian octo Forster <octo at verplant.org>
  **/
 
-/* Set to C99 and POSIX code */
-#ifndef _ISOC99_SOURCE
-# define _ISOC99_SOURCE
-#endif
-#ifndef _POSIX_SOURCE
-# define _POSIX_SOURCE
-#endif
-#ifndef _POSIX_C_SOURCE
-# define _POSIX_C_SOURCE 200112L
-#endif
-#ifndef _REENTRANT
-# define _REENTRANT
-#endif
-
-/* Disable non-standard extensions */
-#ifdef _BSD_SOURCE
-# undef _BSD_SOURCE
-#endif
-#ifdef _SVID_SOURCE
-# undef _SVID_SOURCE
-#endif
-#ifdef _GNU_SOURCE
-# undef _GNU_SOURCE
+#if HAVE_CONFIG_H
+# include "config.h"
 #endif
 
 #if !defined(__GNUC__) || !__GNUC__
 # define __attribute__(x) /**/
 #endif
 
+#include "lcc_features.h"
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -57,6 +38,7 @@
 #include <string.h>
 #include <assert.h>
 #include <errno.h>
+#include <math.h>
 #include <netdb.h>
 
 #include "client.h"
 # define NI_MAXHOST 1025
 #endif
 
+/* OpenBSD doesn't have EPROTO, FreeBSD doesn't have EILSEQ. Oh what joy! */
+#ifndef EILSEQ
+# ifdef EPROTO
+#  define EILSEQ EPROTO
+# else
+#  define EILSEQ EINVAL
+# endif
+#endif
+
 /* Secure/static macros. They work like `strcpy' and `strcat', but assure null
  * termination. They work for static buffers only, because they use `sizeof'.
  * The `SSTRCATF' combines the functionality of `snprintf' and `strcat' which
@@ -77,7 +68,8 @@
   } while (0)
 
 #define SSTRCAT(d,s) do { \
-    strncat ((d), (s), sizeof (d)); \
+    size_t _l = strlen (d); \
+    strncpy ((d) + _l, (s), sizeof (d) - _l); \
     (d)[sizeof (d) - 1] = 0; \
   } while (0)
 
@@ -94,7 +86,7 @@
   (c)->errbuf[sizeof ((c)->errbuf) - 1] = 0; \
 } while (0)
 
-#if 1
+#if COLLECT_DEBUG
 # define LCC_DEBUG(...) printf (__VA_ARGS__)
 #else
 # define LCC_DEBUG(...) /**/
@@ -121,34 +113,59 @@ typedef struct lcc_response_s lcc_response_t;
 /*
  * Private functions
  */
+/* Even though Posix requires "strerror_r" to return an "int",
+ * some systems (e.g. the GNU libc) return a "char *" _and_
+ * ignore the second argument ... -tokkee */
+static char *sstrerror (int errnum, char *buf, size_t buflen)
+{
+  buf[0] = 0;
+
+#if !HAVE_STRERROR_R
+  snprintf (buf, buflen, "Error #%i; strerror_r is not available.", errnum);
+/* #endif !HAVE_STRERROR_R */
+
+#elif STRERROR_R_CHAR_P
+  {
+    char *temp;
+    temp = strerror_r (errnum, buf, buflen);
+    if (buf[0] == 0)
+    {
+      if ((temp != NULL) && (temp != buf) && (temp[0] != 0))
+        strncpy (buf, temp, buflen);
+      else
+        strncpy (buf, "strerror_r did not return "
+            "an error message", buflen);
+    }
+  }
+/* #endif STRERROR_R_CHAR_P */
+
+#else
+  if (strerror_r (errnum, buf, buflen) != 0)
+  {
+    snprintf (buf, buflen, "Error #%i; "
+        "Additionally, strerror_r failed.",
+        errnum);
+  }
+#endif /* STRERROR_R_CHAR_P */
+
+  buf[buflen - 1] = 0;
+
+  return (buf);
+} /* char *sstrerror */
+
 static int lcc_set_errno (lcc_connection_t *c, int err) /* {{{ */
 {
   if (c == NULL)
     return (-1);
 
-  strerror_r (err, c->errbuf, sizeof (c->errbuf));
+  sstrerror (err, c->errbuf, sizeof (c->errbuf));
   c->errbuf[sizeof (c->errbuf) - 1] = 0;
 
   return (0);
 } /* }}} int lcc_set_errno */
 
-/* lcc_strdup: Since `strdup' is an XSI extension, we provide our own version
- * here. */
-__attribute__((malloc, nonnull (1)))
-static char *lcc_strdup (const char *str) /* {{{ */
-{
-  size_t strsize;
-  char *ret;
-
-  strsize = strlen (str) + 1;
-  ret = (char *) malloc (strsize);
-  if (ret != NULL)
-    memcpy (ret, str, strsize);
-  return (ret);
-} /* }}} char *lcc_strdup */
-
 __attribute__((nonnull (1, 2)))
-static char *lcc_strescape (char *dest, char *src, size_t dest_size) /* {{{ */
+static char *lcc_strescape (char *dest, const char *src, size_t dest_size) /* {{{ */
 {
   size_t dest_pos;
   size_t src_pos;
@@ -306,7 +323,7 @@ static int lcc_receive (lcc_connection_t *c, /* {{{ */
     lcc_chomp (buffer);
     LCC_DEBUG ("receive: <-- %s\n", buffer);
 
-    res.lines[i] = lcc_strdup (buffer);
+    res.lines[i] = strdup (buffer);
     if (res.lines[i] == NULL)
     {
       lcc_set_errno (c, ENOMEM);
@@ -336,6 +353,12 @@ static int lcc_sendreceive (lcc_connection_t *c, /* {{{ */
   lcc_response_t res;
   int status;
 
+  if (c->fh == NULL)
+  {
+    lcc_set_errno (c, EBADF);
+    return (-1);
+  }
+
   status = lcc_send (c, command);
   if (status != 0)
     return (status);
@@ -358,7 +381,9 @@ static int lcc_open_unixsocket (lcc_connection_t *c, const char *path) /* {{{ */
   assert (c->fh == NULL);
   assert (path != NULL);
 
-  fd = socket (PF_UNIX, SOCK_STREAM, /* protocol = */ 0);
+  /* Don't use PF_UNIX here, because it's broken on Mac OS X (10.4, possibly
+   * others). */
+  fd = socket (AF_UNIX, SOCK_STREAM, /* protocol = */ 0);
   if (fd < 0)
   {
     lcc_set_errno (c, errno);
@@ -526,9 +551,25 @@ static int lcc_open_socket (lcc_connection_t *c, const char *addr) /* {{{ */
 /*
  * Public functions
  */
+unsigned int lcc_version (void) /* {{{ */
+{
+  return (LCC_VERSION);
+} /* }}} unsigned int lcc_version */
+
+const char *lcc_version_string (void) /* {{{ */
+{
+  return (LCC_VERSION_STRING);
+} /* }}} const char *lcc_version_string */
+
+const char *lcc_version_extra (void) /* {{{ */
+{
+  return (LCC_VERSION_EXTRA);
+} /* }}} const char *lcc_version_extra */
+
 int lcc_connect (const char *address, lcc_connection_t **ret_con) /* {{{ */
 {
   lcc_connection_t *c;
+  int status;
 
   if (address == NULL)
     return (-1);
@@ -541,8 +582,15 @@ int lcc_connect (const char *address, lcc_connection_t **ret_con) /* {{{ */
     return (-1);
   memset (c, 0, sizeof (*c));
 
+  status = lcc_open_socket (c, address);
+  if (status != 0)
+  {
+    lcc_disconnect (c);
+    return (status);
+  }
+
   *ret_con = c;
-  return (lcc_open_socket (c, address));
+  return (0);
 } /* }}} int lcc_connect */
 
 int lcc_disconnect (lcc_connection_t *c) /* {{{ */
@@ -653,7 +701,7 @@ int lcc_getval (lcc_connection_t *c, lcc_identifier_t *ident, /* {{{ */
     key = res.lines[i];
     value = strchr (key, '=');
     if (value == NULL)
-      BAIL_OUT (EPROTO);
+      BAIL_OUT (EILSEQ);
 
     *value = 0;
     value++;
@@ -670,7 +718,7 @@ int lcc_getval (lcc_connection_t *c, lcc_identifier_t *ident, /* {{{ */
 
     if (values_names != NULL)
     {
-      values_names[i] = lcc_strdup (key);
+      values_names[i] = strdup (key);
       if (values_names[i] == NULL)
         BAIL_OUT (ENOMEM);
     }
@@ -714,9 +762,9 @@ int lcc_putval (lcc_connection_t *c, const lcc_value_list_t *vl) /* {{{ */
     SSTRCATF (command, " interval=%i", vl->interval);
 
   if (vl->time > 0)
-    SSTRCATF (command, "%u", (unsigned int) vl->time);
+    SSTRCATF (command, " %u", (unsigned int) vl->time);
   else
-    SSTRCAT (command, "N");
+    SSTRCAT (command, " N");
 
   for (i = 0; i < vl->values_len; i++)
   {
@@ -725,10 +773,15 @@ int lcc_putval (lcc_connection_t *c, const lcc_value_list_t *vl) /* {{{ */
     else if (vl->values_types[i] == LCC_TYPE_GAUGE)
     {
       if (isnan (vl->values[i].gauge))
-        SSTRCPY (command, ":U");
+        SSTRCATF (command, ":U");
       else
         SSTRCATF (command, ":%g", vl->values[i].gauge);
     }
+    else if (vl->values_types[i] == LCC_TYPE_DERIVE)
+       SSTRCATF (command, ":%"PRIu64, vl->values[i].derive);
+    else if (vl->values_types[i] == LCC_TYPE_ABSOLUTE)
+       SSTRCATF (command, ":%"PRIu64, vl->values[i].absolute);
+
   } /* for (i = 0; i < vl->values_len; i++) */
 
   status = lcc_sendreceive (c, command, &res);
@@ -749,7 +802,7 @@ int lcc_putval (lcc_connection_t *c, const lcc_value_list_t *vl) /* {{{ */
 int lcc_flush (lcc_connection_t *c, const char *plugin, /* {{{ */
     lcc_identifier_t *ident, int timeout)
 {
-  char command[1024];
+  char command[1024] = "";
   lcc_response_t res;
   int status;
 
@@ -860,7 +913,7 @@ int lcc_listval (lcc_connection_t *c, /* {{{ */
 
     if (*ident_str == 0)
     {
-      lcc_set_errno (c, EPROTO);
+      lcc_set_errno (c, EILSEQ);
       status = -1;
       break;
     }
@@ -945,7 +998,7 @@ int lcc_string_to_identifier (lcc_connection_t *c, /* {{{ */
   char *type;
   char *type_instance;
 
-  string_copy = lcc_strdup (string);
+  string_copy = strdup (string);
   if (string_copy == NULL)
   {
     lcc_set_errno (c, ENOMEM);