]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev: make parser for attribute of $result harder
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 30 Apr 2019 18:30:49 +0000 (20:30 +0200)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 2 Jun 2019 23:35:33 +0000 (08:35 +0900)
src/udev/udev-event.c

index 6b6b7522eb7c540c5bcedffce129778ccc6b687c..8d96e8e3e2172f065756bb23a1c70298bb89b26f 100644 (file)
@@ -20,6 +20,7 @@
 #include "format-util.h"
 #include "libudev-util.h"
 #include "netlink-util.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "rlimit-util.h"
@@ -204,6 +205,26 @@ static int get_subst_type(const char **str, FormatSubstitutionType *ret_type, ch
         return 1;
 }
 
+static int safe_atou_optional_plus(const char *s, unsigned *ret) {
+        const char *p;
+        int r;
+
+        assert(s);
+        assert(ret);
+
+        /* Returns 1 if plus, 0 if no plus, negative on error */
+
+        p = endswith(s, "+");
+        if (p)
+                s = strndupa(s, p - s);
+
+        r = safe_atou(s, ret);
+        if (r < 0)
+                return r;
+
+        return !!p;
+}
+
 static ssize_t udev_event_subst_format(
                 UdevEvent *event,
                 FormatSubstitutionType type,
@@ -267,43 +288,50 @@ static ssize_t udev_event_subst_format(
                 break;
         }
         case FORMAT_SUBST_RESULT: {
-                char *rest;
-                int i;
+                unsigned index = 0; /* 0 means whole string */
+                bool has_plus;
 
                 if (!event->program_result)
                         goto null_terminate;
 
-                /* get part of the result string */
-                i = 0;
-                if (!isempty(attr))
-                        i = strtoul(attr, &rest, 10);
-                if (i > 0) {
-                        char result[UTIL_PATH_SIZE], tmp[UTIL_PATH_SIZE], *cpos;
-
-                        strscpy(result, sizeof(result), event->program_result);
-                        cpos = result;
-                        while (--i) {
-                                while (cpos[0] != '\0' && !isspace(cpos[0]))
-                                        cpos++;
-                                while (isspace(cpos[0]))
-                                        cpos++;
-                                if (cpos[0] == '\0')
+                if (!isempty(attr)) {
+                        r = safe_atou_optional_plus(attr, &index);
+                        if (r < 0)
+                                return r;
+
+                        has_plus = r;
+                }
+
+                if (index == 0)
+                        l = strpcpy(&s, l, event->program_result);
+                else {
+                        const char *start, *p;
+                        unsigned i;
+
+                        p = skip_leading_chars(event->program_result, NULL);
+
+                        for (i = 1; i < index; i++) {
+                                while (p[0] != '\0' && !strchr(WHITESPACE, p[0]))
+                                        p++;
+                                p = skip_leading_chars(p, NULL);
+                                if (*p == '\0')
                                         break;
                         }
-                        if (i > 0) {
-                                log_error("requested part of result string not found");
-                                break;
+                        if (i != index) {
+                                log_device_debug(dev, "requested part of result string not found");
+                                goto null_terminate;
                         }
-                        strscpy(tmp, sizeof(tmp), cpos);
-                        /* %{2+}c copies the whole string from the second part on */
-                        if (rest[0] != '+') {
-                                cpos = strchr(tmp, ' ');
-                                if (cpos)
-                                        cpos[0] = '\0';
+
+                        start = p;
+                        /* %c{2+} copies the whole string from the second part on */
+                        if (has_plus)
+                                l = strpcpy(&s, l, start);
+                        else {
+                                while (p[0] != '\0' && !strchr(WHITESPACE, p[0]))
+                                        p++;
+                                l = strnpcpy(&s, l, start, p - start);
                         }
-                        l = strpcpy(&s, l, tmp);
-                } else
-                        l = strpcpy(&s, l, event->program_result);
+                }
                 break;
         }
         case FORMAT_SUBST_ATTR: {