]> git.itanic.dy.fi Git - rrdd/blobdiff - onewire_parser.c
onewire_parser.c: Fix compiler warnings about string lengths
[rrdd] / onewire_parser.c
index fe29aa483c2f01749c029d0f7e74908ba3dbaa8e..958cff952cb7c8bbdfcca76f0f013ed0f6e92bd3 100644 (file)
@@ -5,6 +5,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <math.h>
+#include <time.h>
 
 #include "parser.h"
 #include "debug.h"
@@ -23,34 +24,50 @@ static struct owparser_state *allocate_parser_state(const char **datastr)
 {
        int i;
 
-       /* Count how many sensor entries we need */
+       /*
+        * Count how many sensor entries we need. First entry belongs
+        * to server address or mount point and last one is NULL. So
+        * the index final is the count of actual valid sensor
+        * entries.
+        */
        for (i = 0; datastr[i]; i++)
                ;
 
-       /* The first entry belongs to server address or mount point */
-       i--;
-
        return calloc(sizeof(struct owparser_state), i);
 }
 
-static int might_be_glitch(double data, const struct owparser_state *s)
+static double max_glitch_delta(const struct owparser_state *s)
 {
-       double max_delta = 0, delta;
+       double max_delta = 0;
        int i;
 
        for (i = 0; i < ARRAY_SIZE(s->prev_delta); i++)
                max_delta = max(s->prev_delta[i], max_delta);
 
+       return max_delta;
+}
+
+static int might_be_glitch(double data, const struct owparser_state *s)
+{
+       double max_delta, delta;
+
+       /* The known bad data value from the sensor */
+       if (data == 85)
+               return 1;
+
+       max_delta = max_glitch_delta(s);
+
        /* Probably no enough data yet, so no glitch detection */
-       if (!max_delta)
+       if (max_delta == 0)
                return 0;
 
        /*
         * Simple glitch detection. If delta to previous value is more
-        * than twice as larger as some older delta, we might have a
-        * glit
+        * than twice as larger as any of the older delta, we might
+        * have a glitch
         */
        delta = fabs(data - s->prev_data);
+
        return delta > max_delta * 2;
 }
 
@@ -90,7 +107,7 @@ static int parse_opts(const char *str, char *ow_path, size_t pathlen,
                        break;
 
        /* Copy the onewire path without options */
-       strncpy(ow_path, start_str, pathlen);
+       strncpy(ow_path, start_str, pathlen - 1);
        ow_path[str - start_str] = '\0';
 
        /* Get the next non-space, which is where the argument begins */
@@ -112,11 +129,15 @@ static int parse_opts(const char *str, char *ow_path, size_t pathlen,
 
 static int make_uncached(char *path, size_t len)
 {
-       char p1[32], p2[32], *p = path;
+       int ret;
+       char p1[1028], p2[1028], *p = path;
 
        if (strstr(path, "/uncached/"))
                return 0;
 
+       p1[sizeof(p1) - 1] = '\0';
+       p2[sizeof(p2) - 1] = '\0';
+
        /*
         * Naively assume the "uncached" string can be put after the
         * first slash
@@ -130,9 +151,13 @@ static int make_uncached(char *path, size_t len)
        *p = 0;
        p++;
 
-       strncpy(p1, path, sizeof(p1));
-       strncpy(p2, p, sizeof(p2));
-       snprintf(path, len, "%s/uncached/%s", p1, p2);
+       strncpy(p1, path, sizeof(p1) - 1);
+       strncpy(p2, p, sizeof(p2) - 1);
+       ret = snprintf(path, len, "%s/uncached/%s", p1, p2);
+
+       /* No actual data overflow, snprintf just couldn't fit all data in the buffer */
+       if (ret >= RRD_DATA_MAX_LEN)
+               pr_err("Buffer overlfow\n");
 
        return 0;
 }
@@ -165,6 +190,52 @@ out_close:
        return ret;
 }
 
+static void enable_simultaneous_reading(const char *mountpoint)
+{
+       static time_t last_simultaneous;
+       static struct mutex lock = {
+               .lock = PTHREAD_MUTEX_INITIALIZER,
+       };
+
+       time_t now = time(0);
+       int fd;
+       int ret;
+       char path[4096];
+       char one = '1';
+
+       mutex_lock(&lock);
+       /* Arbitrary 10 second limit between simultaneous reads */
+       if (now < last_simultaneous + 10) {
+               mutex_unlock(&lock);
+               return;
+       }
+
+       last_simultaneous = now;
+       mutex_unlock(&lock);
+
+       /*
+        * We only protect setting the variable. From now on we have
+        * 10 seconds time until we could race writing multiple times
+        * to this file. If that happens, well, can't help it..
+        */
+
+       strncpy(path, mountpoint, sizeof(path) - 1);
+       strncat(path, "/simultaneous/temperature", sizeof(path) - 1);
+       path[sizeof(path) - 1 ] = '\0';
+
+       fd = open(path, O_WRONLY);
+       if (path < 0) {
+               pr_err("Failed to open %s for writing: %m\n", path);
+               return;
+       }
+
+       ret = write(fd, &one, 1);
+       if (ret < 0)
+               pr_warn("Failed to write to %s: %m\n", path);
+
+       close(fd);
+}
+
 static int is_mount_point(const char *str)
 {
        /*
@@ -234,8 +305,11 @@ undefined:
 
                parse_opts(parser_data[i], ow_path, sizeof(ow_path), &offset);
 
+               if (is_mountpoint)
+                       enable_simultaneous_reading(mount_point);
+
                while (1) {
-                       int fail, j;
+                       int j;
                        char *tmp2;
 
                        tmp = NULL;
@@ -252,15 +326,9 @@ undefined:
                        for (j = 0; j < ret && *tmp2 == ' '; j++)
                                tmp2++;
 
-                       if (ret > 0)
-                               fail = !strncmp(tmp2, "85", 2);
-                       else
-                               fail = 1;
-
-                       if (ret <= 0 || fail)
+                       if (ret <= 0)
                                goto retry;
 
-
                        /*
                         * Older versions of OWNET_read did not NULL
                         * terminate data.
@@ -274,14 +342,18 @@ undefined:
                        tmp = NULL;
 
                        /*
-                        * If we read the same value as previously,
-                        * it's not a glitch
+                        * If we read the almost same value as
+                        * previously, it's not a glitch
                         */
-                       if (glitches && prev_data == data)
-                               break;
+                       if (glitches && prev_data != 85) {
+                               double d = max_glitch_delta(&state[i]);
+
+                               if (fabs(data - prev_data) <= d * 2)
+                                       break;
+                       }
 
                        if (might_be_glitch(data, &state[i]) &&
-                               glitches < 2 && retries < 7) {
+                               glitches < 4 && retries < 7) {
                                glitches++;
                                prev_data = data;
                                pr_info("Retrying due to a glitch: %f\n", data);