]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev: escaped string syntax e"..." in rule files
authorYu, Li-Yu <afg984@gmail.com>
Tue, 20 Oct 2020 16:38:21 +0000 (00:38 +0800)
committerYu, Li-Yu <afg984@gmail.com>
Thu, 29 Oct 2020 12:15:23 +0000 (20:15 +0800)
* Existing valid rule files written with KEY="value" are not affected
* Now, KEY=e"value\n" becomes valid. Where `\n` is a newline character
* Escape sequences supported by src/basic/escape.h:cunescape() is
  supported

src/shared/udev-util.c
src/shared/udev-util.h
src/udev/udev-rules.c

index 98bbfb2ae3444ebc3b0cc61d930b50061f076b39..500eb13c653d61c5813b5ccb750e78f96394e6cf 100644 (file)
@@ -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;
+}
index 04c7ce55203df2d2ef2467dc275b155f3388856d..427808c63bc2014d355141a030dfa263742d7508 100644 (file)
@@ -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);
index 7e029927fd0d45960f5933c64fe773b36c7efafd..e01d75580a8d5971b1b159244775eb53265a44f1 100644 (file)
@@ -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);
-
-        /* 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';
+        tmp = skip_leading_chars(tmp, NULL);
+        r = udev_rule_parse_value(tmp, ret_value, line);
+        if (r < 0)
+                return r;
 
-        *line = i+1;
         *ret_key = key_begin;
         *ret_attr = attr;
         *ret_op = op;
-        *ret_value = value;
         return 1;
 }