From: Yu Watanabe Date: Tue, 30 Apr 2019 18:30:49 +0000 (+0200) Subject: udev: make parser for attribute of $result harder X-Git-Tag: v243-rc1~328^2~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ce4f94b8e9c685814232b8daa54a0e2211607449;p=thirdparty%2Fsystemd.git udev: make parser for attribute of $result harder --- diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 6b6b7522eb7..8d96e8e3e21 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -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: {