]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev-event: add replace_whitespace param to udev_event_apply_format
authorDan Streetman <ddstreet@ieee.org>
Tue, 3 Jan 2017 19:37:59 +0000 (14:37 -0500)
committerDan Streetman <ddstreet@ieee.org>
Tue, 3 Jan 2017 22:12:00 +0000 (17:12 -0500)
If replace_whitespace is true, each substitution value has all its
whitespace removed/replaced by util_replace_whitespace (except the
SUBST_RESULT substitution - $result{} or %c{} - which handles spaces
itself as field separators).  All existing callers are updated to
pass false, so no functional change is made by this patch.

This is needed so the SYMLINK assignment can replace any spaces
introduced through variable substitution, becuase the SYMLINK value is
a space-separated list of symlinks to create.  Any variables that
contain spaces will thus unexpectedly change the symlink value from
a single symlink to multiple incorrectly-named symlinks.

This is used in the next patch, which enables the whitespace
replacement for SYMLINK variable substitution.

src/udev/udev-event.c
src/udev/udev-rules.c
src/udev/udev.h
src/udev/udevadm-test.c

index 304a28777b4bbe27110bbed2b140fce173c232fa..be7c7367ffaa7c7bbf33737d695f7721cdb690c5 100644 (file)
@@ -73,7 +73,9 @@ void udev_event_unref(struct udev_event *event) {
         free(event);
 }
 
-size_t udev_event_apply_format(struct udev_event *event, const char *src, char *dest, size_t size) {
+size_t udev_event_apply_format(struct udev_event *event,
+                               const char *src, char *dest, size_t size,
+                               bool replace_whitespace) {
         struct udev_device *dev = event->dev;
         enum subst_type {
                 SUBST_UNKNOWN,
@@ -130,8 +132,10 @@ size_t udev_event_apply_format(struct udev_event *event, const char *src, char *
 
         for (;;) {
                 enum subst_type type = SUBST_UNKNOWN;
-                char attrbuf[UTIL_PATH_SIZE];
-                char *attr = NULL;
+                char attrbuf[UTIL_PATH_SIZE], sbuf[UTIL_PATH_SIZE];
+                char *attr = NULL, *_s;
+                size_t _l;
+                bool replws = replace_whitespace;
 
                 while (from[0] != '\0') {
                         if (from[0] == '$') {
@@ -200,6 +204,19 @@ subst:
                         attr = NULL;
                 }
 
+                /* result subst handles space as field separator */
+                if (type == SUBST_RESULT)
+                        replws = false;
+
+                if (replws) {
+                        /* store dest string ptr and remaining len */
+                        _s = s;
+                        _l = l;
+                        /* temporarily use sbuf */
+                        s = &sbuf;
+                        l = UTIL_PATH_SIZE;
+                }
+
                 switch (type) {
                 case SUBST_DEVPATH:
                         l = strpcpy(&s, l, udev_device_get_devpath(dev));
@@ -380,6 +397,20 @@ subst:
                         log_error("unknown substitution type=%i", type);
                         break;
                 }
+
+                /* replace whitespace in sbuf and copy to dest */
+                if (replws) {
+                        size_t tmplen = UTIL_PATH_SIZE - l;
+
+                        /* restore s and l to dest string values */
+                        s = _s;
+                        l = _l;
+
+                        /* copy ws-replaced value to s */
+                        tmplen = util_replace_whitespace(sbuf, s, MIN(tmplen, l));
+                        l -= tmplen;
+                        s += tmplen;
+                }
         }
 
 out:
@@ -927,7 +958,7 @@ void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_
                 const char *cmd = udev_list_entry_get_name(list_entry);
                 enum udev_builtin_cmd builtin_cmd = udev_list_entry_get_num(list_entry);
 
-                udev_event_apply_format(event, cmd, command, sizeof(command));
+                udev_event_apply_format(event, cmd, command, sizeof(command), false);
 
                 if (builtin_cmd < UDEV_BUILTIN_MAX)
                         udev_builtin_run(event->dev, builtin_cmd, command, false);
index b0238220e47065ae30e307e8a3f4185cb855db89..c688120552d33fdc78d14d60f472d076554a558f 100644 (file)
@@ -1676,7 +1676,7 @@ static int match_attr(struct udev_rules *rules, struct udev_device *dev, struct
         name = rules_str(rules, cur->key.attr_off);
         switch (cur->key.attrsubst) {
         case SB_FORMAT:
-                udev_event_apply_format(event, name, nbuf, sizeof(nbuf));
+                udev_event_apply_format(event, name, nbuf, sizeof(nbuf), false);
                 name = nbuf;
                 /* fall through */
         case SB_NONE:
@@ -1838,7 +1838,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
                         _cleanup_free_ char *value = NULL;
                         size_t len;
 
-                        udev_event_apply_format(event, rules_str(rules, cur->key.attr_off), filename, sizeof(filename));
+                        udev_event_apply_format(event, rules_str(rules, cur->key.attr_off), filename, sizeof(filename), false);
                         sysctl_normalize(filename);
                         if (sysctl_read(filename, &value) < 0)
                                 goto nomatch;
@@ -1916,7 +1916,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
                         struct stat statbuf;
                         int match;
 
-                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), filename, sizeof(filename));
+                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), filename, sizeof(filename), false);
                         if (util_resolve_subsys_kernel(event->udev, filename, filename, sizeof(filename), 0) != 0) {
                                 if (filename[0] != '/') {
                                         char tmp[UTIL_PATH_SIZE];
@@ -1942,7 +1942,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
                         char result[UTIL_LINE_SIZE];
 
                         event->program_result = mfree(event->program_result);
-                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), program, sizeof(program));
+                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), program, sizeof(program), false);
                         log_debug("PROGRAM '%s' %s:%u",
                                   program,
                                   rules_str(rules, rule->rule.filename_off),
@@ -1969,7 +1969,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
                 case TK_M_IMPORT_FILE: {
                         char import[UTIL_PATH_SIZE];
 
-                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import));
+                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import), false);
                         if (import_file_into_properties(event->dev, import) != 0)
                                 if (cur->key.op != OP_NOMATCH)
                                         goto nomatch;
@@ -1978,7 +1978,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
                 case TK_M_IMPORT_PROG: {
                         char import[UTIL_PATH_SIZE];
 
-                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import));
+                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import), false);
                         log_debug("IMPORT '%s' %s:%u",
                                   import,
                                   rules_str(rules, rule->rule.filename_off),
@@ -2009,7 +2009,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
                                 event->builtin_run |= (1 << cur->key.builtin_cmd);
                         }
 
-                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), command, sizeof(command));
+                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), command, sizeof(command), false);
                         log_debug("IMPORT builtin '%s' %s:%u",
                                   udev_builtin_name(cur->key.builtin_cmd),
                                   rules_str(rules, rule->rule.filename_off),
@@ -2077,7 +2077,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
                 case TK_M_IMPORT_PARENT: {
                         char import[UTIL_PATH_SIZE];
 
-                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import));
+                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import), false);
                         if (import_parent_into_properties(event->dev, import) != 0)
                                 if (cur->key.op != OP_NOMATCH)
                                         goto nomatch;
@@ -2115,7 +2115,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
                                 break;
                         if (cur->key.op == OP_ASSIGN_FINAL)
                                 event->owner_final = true;
-                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), owner, sizeof(owner));
+                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), owner, sizeof(owner), false);
                         event->owner_set = true;
                         r = get_user_creds(&ow, &event->uid, NULL, NULL, NULL);
                         if (r < 0) {
@@ -2141,7 +2141,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
                                 break;
                         if (cur->key.op == OP_ASSIGN_FINAL)
                                 event->group_final = true;
-                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), group, sizeof(group));
+                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), group, sizeof(group), false);
                         event->group_set = true;
                         r = get_group_creds(&gr, &event->gid);
                         if (r < 0) {
@@ -2165,7 +2165,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
 
                         if (event->mode_final)
                                 break;
-                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), mode_str, sizeof(mode_str));
+                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), mode_str, sizeof(mode_str), false);
                         mode = strtol(mode_str, &endptr, 8);
                         if (endptr[0] != '\0') {
                                 log_error("ignoring invalid mode '%s'", mode_str);
@@ -2222,7 +2222,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
                         const char *name, *label;
 
                         name = rules_str(rules, cur->key.attr_off);
-                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), label_str, sizeof(label_str));
+                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), label_str, sizeof(label_str), false);
                         if (label_str[0] != '\0')
                                 label = label_str;
                         else
@@ -2256,10 +2256,10 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
                                 char temp[UTIL_NAME_SIZE];
 
                                 /* append value separated by space */
-                                udev_event_apply_format(event, value, temp, sizeof(temp));
+                                udev_event_apply_format(event, value, temp, sizeof(temp), false);
                                 strscpyl(value_new, sizeof(value_new), value_old, " ", temp, NULL);
                         } else
-                                udev_event_apply_format(event, value, value_new, sizeof(value_new));
+                                udev_event_apply_format(event, value, value_new, sizeof(value_new), false);
 
                         udev_device_add_property(event->dev, name, value_new);
                         break;
@@ -2268,7 +2268,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
                         char tag[UTIL_PATH_SIZE];
                         const char *p;
 
-                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), tag, sizeof(tag));
+                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), tag, sizeof(tag), false);
                         if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
                                 udev_device_cleanup_tags_list(event->dev);
                         for (p = tag; *p != '\0'; p++) {
@@ -2296,7 +2296,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
                                 break;
                         if (cur->key.op == OP_ASSIGN_FINAL)
                                 event->name_final = true;
-                        udev_event_apply_format(event, name, name_str, sizeof(name_str));
+                        udev_event_apply_format(event, name, name_str, sizeof(name_str), false);
                         if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) {
                                 count = util_replace_chars(name_str, "/");
                                 if (count > 0)
@@ -2336,7 +2336,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
                                 udev_device_cleanup_devlinks_list(event->dev);
 
                         /* allow  multiple symlinks separated by spaces */
-                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), temp, sizeof(temp));
+                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), temp, sizeof(temp), false);
                         if (esc == ESCAPE_UNSET)
                                 count = util_replace_chars(temp, "/ ");
                         else if (esc == ESCAPE_REPLACE)
@@ -2376,7 +2376,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
                                 strscpyl(attr, sizeof(attr), udev_device_get_syspath(event->dev), "/", key_name, NULL);
                         attr_subst_subdir(attr, sizeof(attr));
 
-                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), value, sizeof(value));
+                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), value, sizeof(value), false);
                         log_debug("ATTR '%s' writing '%s' %s:%u", attr, value,
                                   rules_str(rules, rule->rule.filename_off),
                                   rule->rule.filename_line);
@@ -2392,9 +2392,9 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
                         char value[UTIL_NAME_SIZE];
                         int r;
 
-                        udev_event_apply_format(event, rules_str(rules, cur->key.attr_off), filename, sizeof(filename));
+                        udev_event_apply_format(event, rules_str(rules, cur->key.attr_off), filename, sizeof(filename), false);
                         sysctl_normalize(filename);
-                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), value, sizeof(value));
+                        udev_event_apply_format(event, rules_str(rules, cur->key.value_off), value, sizeof(value), false);
                         log_debug("SYSCTL '%s' writing '%s' %s:%u", filename, value,
                                   rules_str(rules, rule->rule.filename_off), rule->rule.filename_line);
                         r = sysctl_write(filename, value);
index 8433e8d9f2661c5dfd73487da6cbf9f1f44c50e1..c0cb7eae84e74e09231d7b1b049c586e794a319e 100644 (file)
@@ -80,7 +80,9 @@ int udev_rules_apply_static_dev_perms(struct udev_rules *rules);
 /* udev-event.c */
 struct udev_event *udev_event_new(struct udev_device *dev);
 void udev_event_unref(struct udev_event *event);
-size_t udev_event_apply_format(struct udev_event *event, const char *src, char *dest, size_t size);
+size_t udev_event_apply_format(struct udev_event *event,
+                               const char *src, char *dest, size_t size,
+                               bool replace_whitespace);
 int udev_event_apply_subsys_kernel(struct udev_event *event, const char *string,
                                    char *result, size_t maxsize, int read_value);
 int udev_event_spawn(struct udev_event *event,
index 702dbe528299234f178b8f18a8efe460280be9e8..07b667f131965c17ca319c84be61fffa3e6f515e 100644 (file)
@@ -144,7 +144,7 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) {
         udev_list_entry_foreach(entry, udev_list_get_entry(&event->run_list)) {
                 char program[UTIL_PATH_SIZE];
 
-                udev_event_apply_format(event, udev_list_entry_get_name(entry), program, sizeof(program));
+                udev_event_apply_format(event, udev_list_entry_get_name(entry), program, sizeof(program), false);
                 printf("run: '%s'\n", program);
         }
 out: