use fgets in parse_value_file, fixes #1941
[collectd.git] / src / daemon / common.c
index 7806c71..d2fae57 100644 (file)
@@ -334,50 +334,60 @@ int strsplit (char *string, char **fields, size_t size)
        return ((int) i);
 }
 
-int strjoin (char *buffer, size_t buffer_size,
-               char **fields, size_t fields_num,
-               const char *sep)
-{
-       size_t avail;
-       char *ptr;
-       size_t sep_len;
+int strjoin(char *buffer, size_t buffer_size, char **fields, size_t fields_num,
+            const char *sep) {
+  size_t avail = 0;
+  char *ptr = buffer;
+  size_t sep_len = 0;
 
-       if ((buffer_size < 1) || (fields_num == 0))
-               return (-1);
+  size_t buffer_req = 0;
 
-       memset (buffer, 0, buffer_size);
-       ptr = buffer;
-       avail = buffer_size - 1;
+  if (((fields_num != 0) && (fields == NULL)) ||
+      ((buffer_size != 0) && (buffer == NULL)))
+    return (-EINVAL);
 
-       sep_len = 0;
-       if (sep != NULL)
-               sep_len = strlen (sep);
+  if (buffer != NULL)
+    buffer[0] = 0;
 
-       for (size_t i = 0; i < fields_num; i++)
-       {
-               size_t field_len;
+  if (buffer_size != 0)
+    avail = buffer_size - 1;
 
-               if ((i > 0) && (sep_len > 0))
-               {
-                       if (avail < sep_len)
-                               return (-1);
+  if (sep != NULL)
+    sep_len = strlen(sep);
 
-                       memcpy (ptr, sep, sep_len);
-                       ptr += sep_len;
-                       avail -= sep_len;
-               }
+  for (size_t i = 0; i < fields_num; i++) {
+    size_t field_len = strlen(fields[i]);
 
-               field_len = strlen (fields[i]);
-               if (avail < field_len)
-                       return (-1);
+    if (i != 0)
+      buffer_req += sep_len;
+    buffer_req += field_len;
 
-               memcpy (ptr, fields[i], field_len);
-               ptr += field_len;
-               avail -= field_len;
-       }
+    if ((i != 0) && (sep_len > 0)) {
+      if (sep_len >= avail) {
+        /* prevent subsequent iterations from writing to the
+         * buffer. */
+        avail = 0;
+        continue;
+      }
+
+      memcpy(ptr, sep, sep_len);
+
+      ptr += sep_len;
+      avail -= sep_len;
+    }
+
+    if (field_len > avail)
+      field_len = avail;
 
-       assert (buffer[buffer_size - 1] == 0);
-       return ((int) strlen (buffer));
+    memcpy(ptr, fields[i], field_len);
+    ptr += field_len;
+
+    avail -= field_len;
+    if (ptr != NULL)
+      *ptr = 0;
+  }
+
+  return (int)buffer_req;
 }
 
 int escape_string (char *buffer, size_t buffer_size)
@@ -1081,6 +1091,11 @@ int parse_identifier_vl (const char *str, value_list_t *vl) /* {{{ */
 
 int parse_value (const char *value_orig, value_t *ret_value, int ds_type)
 {
+  return parse_value_ext(value_orig, ret_value, ds_type, "");
+}
+
+int parse_value_ext (const char *value_orig, value_t *ret_value, int ds_type, const char *error_identifier)
+{
   char *value;
   char *endptr = NULL;
   size_t value_len;
@@ -1119,19 +1134,19 @@ int parse_value (const char *value_orig, value_t *ret_value, int ds_type)
 
     default:
       sfree (value);
-      ERROR ("parse_value: Invalid data source type: %i.", ds_type);
+      ERROR ("parse_value %s: Invalid data source type: %i.", error_identifier, ds_type);
       return -1;
   }
 
   if (value == endptr) {
-    ERROR ("parse_value: Failed to parse string as %s: %s.",
+    ERROR ("parse_value %s: Failed to parse string as %s: %s.", error_identifier,
         DS_TYPE_TO_STRING (ds_type), value);
     sfree (value);
     return -1;
   }
   else if ((NULL != endptr) && ('\0' != *endptr))
-    INFO ("parse_value: Ignoring trailing garbage \"%s\" after %s value. "
-        "Input string was \"%s\".",
+    INFO ("parse_value %s: Ignoring trailing garbage \"%s\" after %s value. "
+        "Input string was \"%s\".", error_identifier,
         endptr, DS_TYPE_TO_STRING (ds_type), value_orig);
 
   sfree (value);
@@ -1201,14 +1216,22 @@ int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
 
 int parse_value_file (char const *path, value_t *ret_value, int ds_type)
 {
+       FILE *fh;
        char buffer[256];
 
-       if (read_file_contents (path, buffer, sizeof (buffer)) < 0)
-               return errno;
+       fh = fopen (path, "r");
+       if (fh == NULL)
+               return (-1);
+
+       if (fgets (buffer, sizeof (buffer), fh) == NULL)
+       {
+               fclose (fh);
+               return (-1);
+       }
 
-       strstripnewline (buffer);
+       fclose (fh);
 
-       return parse_value (buffer, ret_value, ds_type);
+       return parse_value_ext (buffer, ret_value, ds_type, path);
 } /* int parse_value_file */
 
 #if !HAVE_GETPWNAM_R