]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/udev/udev-event.c
Merge pull request #17549 from yuwata/tiny-fixes
[thirdparty/systemd.git] / src / udev / udev-event.c
index e1c3e430eaa119bba2d535e39b4e5fe07225be96..fd00a24e991fd09b994ee4f828ab1590be6611a0 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 
 #include <ctype.h>
 #include <errno.h>
@@ -370,7 +370,7 @@ static ssize_t udev_event_subst_format(
         }
         case FORMAT_SUBST_PARENT:
                 r = sd_device_get_parent(dev, &parent);
-                if (r == -ENODEV)
+                if (r == -ENOENT)
                         goto null_terminate;
                 if (r < 0)
                         return r;
@@ -437,9 +437,9 @@ null_terminate:
         return 0;
 }
 
-ssize_t udev_event_apply_format(UdevEvent *event,
-                                const char *src, char *dest, size_t size,
-                                bool replace_whitespace) {
+size_t udev_event_apply_format(UdevEvent *event,
+                               const char *src, char *dest, size_t size,
+                               bool replace_whitespace) {
         const char *s = src;
         int r;
 
@@ -455,9 +455,10 @@ ssize_t udev_event_apply_format(UdevEvent *event,
                 ssize_t subst_len;
 
                 r = get_subst_type(&s, false, &type, attr);
-                if (r < 0)
-                        return log_device_warning_errno(event->dev, r, "Invalid format string, ignoring: %s", src);
-                if (r == 0) {
+                if (r < 0) {
+                        log_device_warning_errno(event->dev, r, "Invalid format string, ignoring: %s", src);
+                        break;
+                } else if (r == 0) {
                         if (size < 2) /* need space for this char and the terminating NUL */
                                 break;
                         *dest++ = *s++;
@@ -466,10 +467,12 @@ ssize_t udev_event_apply_format(UdevEvent *event,
                 }
 
                 subst_len = udev_event_subst_format(event, type, attr, dest, size);
-                if (subst_len < 0)
-                        return log_device_warning_errno(event->dev, subst_len,
-                                                        "Failed to substitute variable '$%s' or apply format '%%%c', ignoring: %m",
-                                                        format_type_to_string(type), format_type_to_char(type));
+                if (subst_len < 0) {
+                        log_device_warning_errno(event->dev, subst_len,
+                                                 "Failed to substitute variable '$%s' or apply format '%%%c', ignoring: %m",
+                                                 format_type_to_string(type), format_type_to_char(type));
+                        break;
+                }
 
                 /* FORMAT_SUBST_RESULT handles spaces itself */
                 if (replace_whitespace && type != FORMAT_SUBST_RESULT)
@@ -630,7 +633,7 @@ static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userd
                 if (si->si_status == 0)
                         log_device_debug(spawn->device, "Process '%s' succeeded.", spawn->cmd);
                 else
-                        log_device_full(spawn->device, spawn->accept_failure ? LOG_DEBUG : LOG_WARNING, 0,
+                        log_device_full(spawn->device, spawn->accept_failure ? LOG_DEBUG : LOG_WARNING,
                                         "Process '%s' failed with exit code %i.", spawn->cmd, si->si_status);
                 ret = si->si_status;
                 break;
@@ -744,9 +747,9 @@ int udev_event_spawn(UdevEvent *event,
                         return log_device_error_errno(event->dev, errno,
                                                       "Failed to create pipe for command '%s': %m", cmd);
 
-        argv = strv_split_full(cmd, NULL, SPLIT_QUOTES|SPLIT_RELAX);
-        if (!argv)
-                return log_oom();
+        r = strv_split_full(&argv, cmd, NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_RETAIN_ESCAPE);
+        if (r < 0)
+                return log_device_error_errno(event->dev, r, "Failed to split command: %m");
 
         if (isempty(argv[0]))
                 return log_device_error_errno(event->dev, SYNTHETIC_ERRNO(EINVAL),
@@ -837,11 +840,6 @@ static int rename_netif(UdevEvent *event) {
         if (r < 0)
                 return log_device_error_errno(dev, r, "Failed to get ifindex: %m");
 
-        r = rtnl_set_link_name(&event->rtnl, ifindex, event->name);
-        if (r < 0)
-                return log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m",
-                                              ifindex, oldname, event->name);
-
         /* Set ID_RENAMING boolean property here, and drop it in the corresponding move uevent later. */
         r = device_add_property(dev, "ID_RENAMING", "1");
         if (r < 0)
@@ -851,6 +849,22 @@ static int rename_netif(UdevEvent *event) {
         if (r < 0)
                 return log_device_warning_errno(dev, r, "Failed to update properties with new name '%s': %m", event->name);
 
+        /* Also set ID_RENAMING boolean property to cloned sd_device object and save it to database
+         * before calling rtnl_set_link_name(). Otherwise, clients (e.g., systemd-networkd) may receive
+         * RTM_NEWLINK netlink message before the database is updated. */
+        r = device_add_property(event->dev_db_clone, "ID_RENAMING", "1");
+        if (r < 0)
+                return log_device_warning_errno(event->dev_db_clone, r, "Failed to add 'ID_RENAMING' property: %m");
+
+        r = device_update_db(event->dev_db_clone);
+        if (r < 0)
+                return log_device_debug_errno(event->dev_db_clone, r, "Failed to update database under /run/udev/data/: %m");
+
+        r = rtnl_set_link_name(&event->rtnl, ifindex, event->name);
+        if (r < 0)
+                return log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m",
+                                              ifindex, oldname, event->name);
+
         log_device_debug(dev, "Network interface %i is renamed from '%s' to '%s'", ifindex, oldname, event->name);
 
         return 1;
@@ -867,8 +881,7 @@ static int update_devnode(UdevEvent *event) {
                 return log_device_error_errno(dev, r, "Failed to get devnum: %m");
 
         /* remove/update possible left-over symlinks from old database entry */
-        if (event->dev_db_clone)
-                (void) udev_node_update_old_links(dev, event->dev_db_clone);
+        (void) udev_node_update_old_links(dev, event->dev_db_clone);
 
         if (!uid_is_valid(event->uid)) {
                 r = device_get_devnode_uid(dev, &event->uid);
@@ -927,17 +940,9 @@ static void event_execute_rules_on_remove(
                 (void) udev_node_remove(dev);
 }
 
-static int udev_event_on_move(UdevEvent *event) {
-        sd_device *dev = event->dev;
+static int udev_event_on_move(sd_device *dev) {
         int r;
 
-        if (event->dev_db_clone &&
-            sd_device_get_devnum(dev, NULL) < 0) {
-                r = device_copy_properties(dev, event->dev_db_clone);
-                if (r < 0)
-                        log_device_debug_errno(dev, r, "Failed to copy properties from cloned sd_device object, ignoring: %m");
-        }
-
         /* Drop previously added property */
         r = device_add_property(dev, "ID_RENAMING", NULL);
         if (r < 0)
@@ -946,6 +951,24 @@ static int udev_event_on_move(UdevEvent *event) {
         return 0;
 }
 
+static int copy_all_tags(sd_device *d, sd_device *s) {
+        const char *tag;
+        int r;
+
+        assert(d);
+
+        if (!s)
+                return 0;
+
+        for (tag = sd_device_get_tag_first(s); tag; tag = sd_device_get_tag_next(s)) {
+                r = device_add_tag(d, tag, false);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
 int udev_event_execute_rules(UdevEvent *event,
                              usec_t timeout_usec,
                              int timeout_signal,
@@ -978,12 +1001,16 @@ int udev_event_execute_rules(UdevEvent *event,
         if (r < 0)
                 return log_device_debug_errno(dev, r, "Failed to clone sd_device object: %m");
 
-        if (event->dev_db_clone && sd_device_get_devnum(dev, NULL) >= 0)
+        r = copy_all_tags(dev, event->dev_db_clone);
+        if (r < 0)
+                log_device_warning_errno(dev, r, "Failed to copy all tags from old database entry, ignoring: %m");
+
+        if (sd_device_get_devnum(dev, NULL) >= 0)
                 /* Disable watch during event processing. */
                 (void) udev_watch_end(event->dev_db_clone);
 
         if (action == DEVICE_ACTION_MOVE) {
-                r = udev_event_on_move(event);
+                r = udev_event_on_move(event->dev);
                 if (r < 0)
                         return r;
         }
@@ -1016,18 +1043,15 @@ int udev_event_execute_rules(UdevEvent *event,
 
         device_set_is_initialized(dev);
 
-        event->dev_db_clone = sd_device_unref(event->dev_db_clone);
-
         return 0;
 }
 
 void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_signal) {
         const char *command;
         void *val;
-        Iterator i;
         int r;
 
-        ORDERED_HASHMAP_FOREACH_KEY(val, command, event->run_list, i) {
+        ORDERED_HASHMAP_FOREACH_KEY(val, command, event->run_list) {
                 UdevBuiltinCommand builtin_cmd = PTR_TO_UDEV_BUILTIN_CMD(val);
 
                 if (builtin_cmd != _UDEV_BUILTIN_INVALID) {