diff --git a/src/shared/udev-util.c b/src/shared/udev-util.c index 98bbfb2ae3..500eb13c65 100644 --- a/src/shared/udev-util.c +++ b/src/shared/udev-util.c @@ -6,13 +6,16 @@ #include "alloc-util.h" #include "device-util.h" #include "env-file.h" +#include "escape.h" #include "log.h" +#include "macro.h" #include "parse-util.h" #include "path-util.h" #include "signal-util.h" #include "string-table.h" #include "string-util.h" #include "udev-util.h" +#include "utf8.h" static const char* const resolve_name_timing_table[_RESOLVE_NAME_TIMING_MAX] = { [RESOLVE_NAME_NEVER] = "never", @@ -319,3 +322,49 @@ bool device_for_action(sd_device *dev, DeviceAction action) { return a == action; } + +int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) { + char *i, *j; + int r; + bool is_escaped; + + /* value must be double quotated */ + is_escaped = str[0] == 'e'; + str += is_escaped; + if (str[0] != '"') + return -EINVAL; + str++; + + if (!is_escaped) { + /* unescape double quotation '\"'->'"' */ + for (i = j = str; *i != '"'; i++, j++) { + if (*i == '\0') + return -EINVAL; + if (i[0] == '\\' && i[1] == '"') + i++; + *j = *i; + } + j[0] = '\0'; + } else { + _cleanup_free_ char *unescaped = NULL; + + /* find the end position of value */ + for (i = str; *i != '"'; i++) { + if (i[0] == '\\') + i++; + if (*i == '\0') + return -EINVAL; + } + i[0] = '\0'; + + r = cunescape_length(str, i - str, 0, &unescaped); + if (r < 0) + return r; + assert(r <= i - str); + memcpy(str, unescaped, r + 1); + } + + *ret_value = str; + *ret_endpos = i + 1; + return 0; +} diff --git a/src/shared/udev-util.h b/src/shared/udev-util.h index 04c7ce5520..427808c63b 100644 --- a/src/shared/udev-util.h +++ b/src/shared/udev-util.h @@ -32,3 +32,5 @@ int device_wait_for_initialization(sd_device *device, const char *subsystem, use int device_wait_for_devlink(const char *path, const char *subsystem, usec_t timeout, sd_device **ret); int device_is_renaming(sd_device *dev); bool device_for_action(sd_device *dev, DeviceAction action); + +int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos); diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 7e029927fd..e01d75580a 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -990,8 +990,9 @@ static UdevRuleOperatorType parse_operator(const char *op) { } static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOperatorType *ret_op, char **ret_value) { - char *key_begin, *key_end, *attr, *tmp, *value, *i, *j; + char *key_begin, *key_end, *attr, *tmp; UdevRuleOperatorType op; + int r; assert(line); assert(*line); @@ -1031,30 +1032,14 @@ static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOper key_end[0] = '\0'; tmp += op == OP_ASSIGN ? 1 : 2; - value = skip_leading_chars(tmp, NULL); + tmp = skip_leading_chars(tmp, NULL); + r = udev_rule_parse_value(tmp, ret_value, line); + if (r < 0) + return r; - /* value must be double quotated */ - if (value[0] != '"') - return -EINVAL; - value++; - - /* unescape double quotation '\"' -> '"' */ - for (i = j = value; ; i++, j++) { - if (*i == '"') - break; - if (*i == '\0') - return -EINVAL; - if (i[0] == '\\' && i[1] == '"') - i++; - *j = *i; - } - j[0] = '\0'; - - *line = i+1; *ret_key = key_begin; *ret_attr = attr; *ret_op = op; - *ret_value = value; return 1; }