From 1dfa960786d147d181c583b76847135ebe512d43 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 25 Oct 2018 09:56:15 +0900 Subject: [PATCH 01/15] sd-device: return positive ifindex when sd_device_get_ifindex() succeeds As valid ifindex is positive value, not non-negative value. Follow-up for dcfbde3a43d632ff6e286c77e1081087eca59d8e. --- src/libsystemd/sd-device/device-enumerator.c | 2 +- src/libsystemd/sd-device/sd-device.c | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index 3ae283e93c..187ea703c9 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -497,7 +497,7 @@ static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator, if (!enumerator->match_allow_uninitialized && !initialized && (sd_device_get_devnum(device, &devnum) >= 0 || - (sd_device_get_ifindex(device, &ifindex) >= 0 && ifindex > 0))) + sd_device_get_ifindex(device, &ifindex) >= 0)) continue; if (!match_parent(enumerator, device)) diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 1eb71e17db..b97c1b9719 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -38,7 +38,6 @@ int device_new_aux(sd_device **ret) { *device = (sd_device) { .n_ref = 1, .watch_handle = -1, - .ifindex = -1, .devmode = (mode_t) -1, .devuid = (uid_t) -1, .devgid = (gid_t) -1, @@ -579,7 +578,7 @@ _public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) { if (r < 0) return r; - if (device->ifindex < 0) + if (device->ifindex <= 0) return -ENOENT; *ifindex = device->ifindex; @@ -1241,9 +1240,9 @@ int device_get_id_filename(sd_device *device, const char **ret) { major(devnum), minor(devnum)); if (r < 0) return -ENOMEM; - } else if (sd_device_get_ifindex(device, &ifindex) >= 0 && ifindex > 0) { + } else if (sd_device_get_ifindex(device, &ifindex) >= 0) { /* use netdev ifindex — n3 */ - r = asprintf(&id, "n%u", ifindex); + r = asprintf(&id, "n%u", (unsigned) ifindex); if (r < 0) return -ENOMEM; } else { From 5d062b4ef0e49136730e1d7d3a268b0ed16214a6 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 25 Oct 2018 10:04:19 +0900 Subject: [PATCH 02/15] test: check sd_device_get_ifindex() returns positive ifindex when it succeeds --- src/libsystemd/sd-device/test-sd-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsystemd/sd-device/test-sd-device.c b/src/libsystemd/sd-device/test-sd-device.c index e2701e0e24..fe49a2012a 100644 --- a/src/libsystemd/sd-device/test-sd-device.c +++ b/src/libsystemd/sd-device/test-sd-device.c @@ -32,7 +32,7 @@ static void test_sd_device_basic(void) { assert_se(r >= 0 || r == -ENOENT); r = sd_device_get_ifindex(d, &i); - assert_se(r >= 0 || r == -ENOENT); + assert_se((r >= 0 && i > 0) || r == -ENOENT); r = sd_device_get_driver(d, &val); assert_se(r >= 0 || r == -ENOENT); From 7606377e2ce156681fb6c51a117846d61c650e9e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 25 Oct 2018 10:09:19 +0900 Subject: [PATCH 03/15] network,udev: drop unnecessary check whether ifindex is positive As sd_device_get_ifindex() now returns positive ifindex when it succeeds. --- src/network/networkd-manager.c | 4 ++-- src/udev/net/link-config.c | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 4a621950ca..f7e9b48609 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -197,8 +197,8 @@ static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *devi return 0; r = sd_device_get_ifindex(device, &ifindex); - if (r < 0 || ifindex <= 0) { - log_debug("Ignoring udev ADD event for device with invalid ifindex"); + if (r < 0) { + log_debug_errno(r, "Ignoring udev ADD event for device without ifindex or with invalid ifindex: %m"); return 0; } diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 2d25f75357..c39d8791f2 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -412,8 +412,6 @@ int link_config_apply(link_config_ctx *ctx, link_config *config, r = sd_device_get_ifindex(device, &ifindex); if (r < 0) return log_device_warning_errno(device, r, "Could not find ifindex: %m"); - if (ifindex <= 0) - return log_device_warning_errno(device, EINVAL, "Invalid ifindex '%d'", ifindex); if (ctx->enable_name_policy && config->name_policy) { NamePolicy *policy; From e9343893f790d8aac4d8013b2110fc5de6bc681a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 25 Oct 2018 06:33:26 +0900 Subject: [PATCH 04/15] udev-event: include device name in error message one more place --- src/udev/udev-event.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index cdfda51f03..2125a6fa0d 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -13,6 +13,7 @@ #include "alloc-util.h" #include "device-private.h" +#include "device-util.h" #include "fd-util.h" #include "format-util.h" #include "libudev-device-internal.h" @@ -613,7 +614,7 @@ int udev_event_spawn(struct udev_event *event, r = device_get_properties_strv(event->dev->device, &envp); if (r < 0) - return log_error_errno(r, "Failed to get device properties"); + return log_device_error_errno(event->dev->device, r, "Failed to get device properties"); log_debug("Starting '%s'", cmd); From dc8aec36a61ef32fa13d0f3823053488a8ec8ab1 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 25 Oct 2018 06:35:16 +0900 Subject: [PATCH 05/15] udev-event: check command is not empty before executing --- src/udev/udev-event.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 2125a6fa0d..125b4005b1 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -586,6 +586,8 @@ int udev_event_spawn(struct udev_event *event, pid_t pid; int r; + assert(event); + assert(event->dev); assert(result || ressize == 0); /* pipes from child to parent */ @@ -601,6 +603,11 @@ int udev_event_spawn(struct udev_event *event, if (!argv) return log_oom(); + if (isempty(argv[0])) { + log_error("Invalid command '%s'", cmd); + return -EINVAL; + } + /* allow programs in /usr/lib/udev/ to be called without the path */ if (!path_is_absolute(argv[0])) { char *program; From a368732bc4a8fa2a632631dc944a65feba695dba Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 25 Oct 2018 06:39:48 +0900 Subject: [PATCH 06/15] udev-event: add more assert() --- src/udev/udev-event.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 125b4005b1..182fb03ada 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -86,9 +86,10 @@ enum subst_type { SUBST_SYS, }; -static size_t subst_format_var(struct udev_event *event, struct udev_device *dev, +static size_t subst_format_var(struct udev_event *event, enum subst_type type, char *attr, char *dest, size_t l) { + struct udev_device *dev = event->dev; char *s = dest; switch (type) { @@ -282,7 +283,6 @@ static size_t subst_format_var(struct udev_event *event, struct udev_device *dev 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; static const struct subst_map { const char *name; const char fmt; @@ -311,7 +311,11 @@ size_t udev_event_apply_format(struct udev_event *event, char *s; size_t l; - assert(dev); + assert(event); + assert(event->dev); + assert(src); + assert(dest); + assert(size > 0); from = src; s = dest; @@ -390,7 +394,7 @@ subst: attr = NULL; } - subst_len = subst_format_var(event, dev, type, attr, s, l); + subst_len = subst_format_var(event, type, attr, s, l); /* SUBST_RESULT handles spaces itself */ if (replace_whitespace && type != SUBST_RESULT) From 89665d0920ec141f49bf3c71d3a055ec33c26adf Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 25 Oct 2018 07:02:03 +0900 Subject: [PATCH 07/15] udev-event: use structured initializer at one more place --- src/udev/udev-event.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 182fb03ada..71031fec78 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -44,11 +44,17 @@ typedef struct Spawn { struct udev_event *udev_event_new(struct udev_device *dev) { struct udev_event *event; - event = new0(struct udev_event, 1); - if (event == NULL) + assert(dev); + + event = new(struct udev_event, 1); + if (!event) return NULL; - event->dev = dev; - event->birth_usec = now(CLOCK_MONOTONIC); + + *event = (struct udev_event) { + .dev = dev, + .birth_usec = now(CLOCK_MONOTONIC), + }; + return event; } From d7371971546e843efd5dea059f246bfbb8eeee70 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 25 Oct 2018 07:03:24 +0900 Subject: [PATCH 08/15] udev-event: fix memleak in udev_event The leak was introduced by 29448498c724da7ade1b5efb20d7472c1b128d2c. --- src/udev/udev-event.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 71031fec78..4dcfe87cff 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -66,6 +66,7 @@ void udev_event_unref(struct udev_event *event) { sd_netlink_unref(event->rtnl); while ((p = hashmap_steal_first_key(event->run_list))) free(p); + hashmap_free(event->run_list); hashmap_free_free_free(event->seclabel_list); free(event->program_result); free(event->name); From c1118ceba4886e32d89e299a0a8501d953a9918c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 25 Oct 2018 07:04:59 +0900 Subject: [PATCH 09/15] udev-event: rename udev_event_unref() to udev_event_free() As struct udev_event does not have a reference counter. --- src/test/test-udev.c | 2 +- src/udev/udev-event.c | 10 ++++++---- src/udev/udev.h | 4 ++-- src/udev/udevadm-test.c | 2 +- src/udev/udevd.c | 4 +--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/test/test-udev.c b/src/test/test-udev.c index 2c67e13833..1285117c32 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -52,7 +52,7 @@ static int fake_filesystems(void) { } int main(int argc, char *argv[]) { - _cleanup_(udev_event_unrefp) struct udev_event *event = NULL; + _cleanup_(udev_event_freep) struct udev_event *event = NULL; _cleanup_(udev_device_unrefp) struct udev_device *dev = NULL; _cleanup_(udev_rules_unrefp) struct udev_rules *rules = NULL; const char *devpath, *action; diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 4dcfe87cff..e29486fe18 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -58,11 +58,12 @@ struct udev_event *udev_event_new(struct udev_device *dev) { return event; } -void udev_event_unref(struct udev_event *event) { +struct udev_event *udev_event_free(struct udev_event *event) { void *p; - if (event == NULL) - return; + if (!event) + return NULL; + sd_netlink_unref(event->rtnl); while ((p = hashmap_steal_first_key(event->run_list))) free(p); @@ -70,7 +71,8 @@ void udev_event_unref(struct udev_event *event) { hashmap_free_free_free(event->seclabel_list); free(event->program_result); free(event->name); - free(event); + + return mfree(event); } enum subst_type { diff --git a/src/udev/udev.h b/src/udev/udev.h index c9250edd9a..ec1662d700 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -61,7 +61,7 @@ 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); +struct udev_event *udev_event_free(struct udev_event *event); size_t udev_event_apply_format(struct udev_event *event, const char *src, char *dest, size_t size, bool replace_whitespace); @@ -79,5 +79,5 @@ void udev_event_execute_rules(struct udev_event *event, void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec); /* Cleanup functions */ -DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_event*, udev_event_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_event*, udev_event_free); DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_rules*, udev_rules_unref); diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c index ea6471b837..20f713d738 100644 --- a/src/udev/udevadm-test.c +++ b/src/udev/udevadm-test.c @@ -89,7 +89,7 @@ static int parse_argv(int argc, char *argv[]) { int test_main(int argc, char *argv[], void *userdata) { _cleanup_(udev_rules_unrefp) struct udev_rules *rules = NULL; _cleanup_(udev_device_unrefp) struct udev_device *dev = NULL; - _cleanup_(udev_event_unrefp) struct udev_event *event = NULL; + _cleanup_(udev_event_freep) struct udev_event *event = NULL; struct udev_list_entry *entry; sigset_t mask, sigmask_orig; const char *cmd; diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 64f7f1ff2d..7ec30b92c3 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -398,7 +398,7 @@ static void worker_spawn(Manager *manager, struct event *event) { write_string_file("/proc/self/oom_score_adj", "0", 0); for (;;) { - struct udev_event *udev_event; + _cleanup_(udev_event_freep) struct udev_event *udev_event = NULL; int fd_lock = -1; assert(dev); @@ -477,8 +477,6 @@ skip: udev_device_unref(dev); dev = NULL; - udev_event_unref(udev_event); - /* wait for more device messages from main udevd, or term signal */ while (dev == NULL) { struct epoll_event ev[4]; From 2740750d40cd37411cbac66c79cb7858ccc7828b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 25 Oct 2018 07:45:48 +0900 Subject: [PATCH 10/15] udev-event: move conditions to rename network interface into rename_netif() Also, replace udev_device by sd_device. --- src/udev/udev-event.c | 61 ++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index e29486fe18..1f9e2fea58 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -678,22 +678,46 @@ int udev_event_spawn(struct udev_event *event, } static int rename_netif(struct udev_event *event) { - struct udev_device *dev = event->dev; + sd_device *dev = event->dev->device; + const char *action, *oldname; char name[IFNAMSIZ]; - const char *oldname; - int r; + int ifindex, r; - oldname = udev_device_get_sysname(dev); + if (!event->name) + return 0; /* No new name is requested. */ + + r = sd_device_get_sysname(dev, &oldname); + if (r < 0) + return log_device_error_errno(dev, r, "Failed to get sysname: %m"); + + if (streq(event->name, oldname)) + return 0; /* The interface name is already requested name. */ + + r = sd_device_get_property_value(dev, "ACTION", &action); + if (r < 0) + return log_device_error_errno(dev, r, "Failed to get property 'ACTION': %m"); + + if (!streq(action, "add")) + return 0; /* Rename the interface only when it is added. */ + + r = sd_device_get_ifindex(dev, &ifindex); + if (r == -ENOENT) + return 0; /* Device is not a network interface. */ + if (r < 0) + return log_device_error_errno(dev, r, "Failed to get ifindex: %m"); strscpy(name, IFNAMSIZ, event->name); - - r = rtnl_set_link_name(&event->rtnl, udev_device_get_ifindex(dev), name); + r = rtnl_set_link_name(&event->rtnl, ifindex, name); if (r < 0) - return log_error_errno(r, "Error changing net interface name '%s' to '%s': %m", oldname, name); + return log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m", ifindex, oldname, name); - log_debug("renamed network interface '%s' to '%s'", oldname, name); + r = device_rename(dev, event->name); + if (r < 0) + return log_warning_errno(r, "Network interface %i is renamed from '%s' to '%s', but could not update sd_device object: %m", ifindex, oldname, name); - return 0; + log_device_debug(dev, "Network interface %i is renamed from '%s' to '%s'", ifindex, oldname, name); + + return 1; } void udev_event_execute_rules(struct udev_event *event, @@ -735,24 +759,7 @@ void udev_event_execute_rules(struct udev_event *event, timeout_usec, timeout_warn_usec, properties_list); - /* rename a new network interface, if needed */ - if (udev_device_get_ifindex(dev) > 0 && streq(udev_device_get_action(dev), "add") && - event->name != NULL && !streq(event->name, udev_device_get_sysname(dev))) { - int r; - - r = rename_netif(event); - if (r < 0) - log_warning_errno(r, "could not rename interface '%d' from '%s' to '%s': %m", udev_device_get_ifindex(dev), - udev_device_get_sysname(dev), event->name); - else { - r = udev_device_rename(dev, event->name); - if (r < 0) - log_warning_errno(r, "renamed interface '%d' from '%s' to '%s', but could not update udev_device: %m", - udev_device_get_ifindex(dev), udev_device_get_sysname(dev), event->name); - else - log_debug("changed devpath to '%s'", udev_device_get_devpath(dev)); - } - } + (void) rename_netif(event); if (major(udev_device_get_devnum(dev)) > 0) { bool apply; From e52eaf5649cd3eb352671989437ea1ed4863f16d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 25 Oct 2018 10:32:35 +0900 Subject: [PATCH 11/15] udev-event: move devnode handling logic to a new function Also, replace udev_device by sd_device. --- src/udev/udev-event.c | 82 +++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 1f9e2fea58..14d97f05e7 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -720,6 +720,57 @@ static int rename_netif(struct udev_event *event) { return 1; } +static int update_devnode(struct udev_event *event) { + sd_device *dev = event->dev->device; + const char *action; + dev_t devnum; + bool apply; + int r; + + r = sd_device_get_devnum(dev, &devnum); + if (r == -ENOENT) + return 0; + if (r < 0) + 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) + (void) udev_node_update_old_links(dev, event->dev_db->device); + + if (!event->owner_set) { + r = device_get_devnode_uid(dev, &event->uid); + if (r < 0 && r != -ENOENT) + return log_device_error_errno(dev, r, "Failed to get devnode UID: %m"); + } + + if (!event->group_set) { + r = device_get_devnode_gid(dev, &event->gid); + if (r < 0 && r != -ENOENT) + return log_device_error_errno(dev, r, "Failed to get devnode GID: %m"); + } + + if (!event->mode_set) { + r = device_get_devnode_mode(dev, &event->mode); + if (r < 0 && r != -ENOENT) + return log_device_error_errno(dev, r, "Failed to get devnode mode: %m"); + if (r == -ENOENT) { + if (event->gid > 0) + /* default 0660 if a group is assigned */ + event->mode = 0660; + else + /* default 0600 */ + event->mode = 0600; + } + } + + r = sd_device_get_property_value(dev, "ACTION", &action); + if (r < 0) + return log_device_error_errno(dev, r, "Failed to get property 'ACTION': %m"); + + apply = streq(action, "add") || event->owner_set || event->group_set || event->mode_set; + return udev_node_add(dev, apply, event->mode, event->uid, event->gid, event->seclabel_list); +} + void udev_event_execute_rules(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec, Hashmap *properties_list, @@ -760,36 +811,7 @@ void udev_event_execute_rules(struct udev_event *event, properties_list); (void) rename_netif(event); - - if (major(udev_device_get_devnum(dev)) > 0) { - bool apply; - - /* remove/update possible left-over symlinks from old database entry */ - if (event->dev_db != NULL) - udev_node_update_old_links(dev->device, event->dev_db->device); - - if (!event->owner_set) - event->uid = udev_device_get_devnode_uid(dev); - - if (!event->group_set) - event->gid = udev_device_get_devnode_gid(dev); - - if (!event->mode_set) { - if (udev_device_get_devnode_mode(dev) > 0) { - /* kernel supplied value */ - event->mode = udev_device_get_devnode_mode(dev); - } else if (event->gid > 0) { - /* default 0660 if a group is assigned */ - event->mode = 0660; - } else { - /* default 0600 */ - event->mode = 0600; - } - } - - apply = streq(udev_device_get_action(dev), "add") || event->owner_set || event->group_set || event->mode_set; - udev_node_add(dev->device, apply, event->mode, event->uid, event->gid, event->seclabel_list); - } + (void) update_devnode(event); /* preserve old, or get new initialization timestamp */ udev_device_ensure_usec_initialized(event->dev, event->dev_db); From eb1f9e30ec603ab34631cc3adba1def49485b505 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 25 Oct 2018 11:14:11 +0900 Subject: [PATCH 12/15] udev-event: replace udev_device in udev_event_execute_rules() by sd_device Also, this adds many logs. --- src/udev/udev-event.c | 141 ++++++++++++++++++++++++++++++------------ src/udev/udev.h | 8 +-- 2 files changed, 105 insertions(+), 44 deletions(-) diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 14d97f05e7..db2e3b733c 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -771,58 +771,119 @@ static int update_devnode(struct udev_event *event) { return udev_node_add(dev, apply, event->mode, event->uid, event->gid, event->seclabel_list); } -void udev_event_execute_rules(struct udev_event *event, - usec_t timeout_usec, usec_t timeout_warn_usec, - Hashmap *properties_list, - struct udev_rules *rules) { - struct udev_device *dev = event->dev; +static void event_execute_rules_on_remove( + struct udev_event *event, + usec_t timeout_usec, usec_t timeout_warn_usec, + Hashmap *properties_list, + struct udev_rules *rules) { - if (udev_device_get_subsystem(dev) == NULL) - return; + sd_device *dev = event->dev->device; + dev_t devnum; + int r; - if (streq(udev_device_get_action(dev), "remove")) { - udev_device_read_db(dev); - udev_device_tag_index(dev, NULL, false); - udev_device_delete_db(dev); + r = device_read_db_force(dev); + if (r < 0) + log_device_debug_errno(dev, r, "Failed to read database under /run/udev/data/: %m"); - if (major(udev_device_get_devnum(dev)) != 0) - udev_watch_end(dev->device); + r = device_tag_index(dev, NULL, false); + if (r < 0) + log_device_debug_errno(dev, r, "Failed to remove corresponding tag files under /run/udev/tag/, ignoring: %m"); - udev_rules_apply_to_event(rules, event, - timeout_usec, timeout_warn_usec, - properties_list); + r = device_delete_db(dev); + if (r < 0) + log_device_debug_errno(dev, r, "Failed to delete database under /run/udev/data/, ignoring: %m"); - if (major(udev_device_get_devnum(dev)) != 0) - udev_node_remove(dev->device); - } else { - event->dev_db = udev_device_clone_with_db(dev); - if (event->dev_db != NULL) { - /* disable watch during event processing */ - if (major(udev_device_get_devnum(dev)) != 0) - udev_watch_end(event->dev_db->device); + r = sd_device_get_devnum(dev, &devnum); + if (r < 0) { + if (r != -ENOENT) + log_device_debug_errno(dev, r, "Failed to get devnum, ignoring: %m"); + } else + (void) udev_watch_end(dev); - if (major(udev_device_get_devnum(dev)) == 0 && - streq(udev_device_get_action(dev), "move")) - udev_device_copy_properties(dev, event->dev_db); - } + (void) udev_rules_apply_to_event(rules, event, + timeout_usec, timeout_warn_usec, + properties_list); - udev_rules_apply_to_event(rules, event, - timeout_usec, timeout_warn_usec, - properties_list); + if (major(devnum) > 0) + (void) udev_node_remove(dev); +} - (void) rename_netif(event); - (void) update_devnode(event); +int udev_event_execute_rules(struct udev_event *event, + usec_t timeout_usec, usec_t timeout_warn_usec, + Hashmap *properties_list, + struct udev_rules *rules) { + _cleanup_(sd_device_unrefp) sd_device *clone = NULL; + sd_device *dev = event->dev->device; + const char *subsystem, *action; + dev_t devnum; + int r; - /* preserve old, or get new initialization timestamp */ - udev_device_ensure_usec_initialized(event->dev, event->dev_db); + assert(event); + assert(rules); - /* (re)write database file */ - udev_device_tag_index(dev, event->dev_db, true); - udev_device_update_db(dev); - udev_device_set_is_initialized(dev); + r = sd_device_get_subsystem(dev, &subsystem); + if (r < 0) + return log_device_error_errno(dev, r, "Failed to get subsystem: %m"); - event->dev_db = udev_device_unref(event->dev_db); + r = sd_device_get_property_value(dev, "ACTION", &action); + if (r < 0) + return log_device_error_errno(dev, r, "Failed to get property 'ACTION': %m"); + + if (streq(action, "remove")) { + event_execute_rules_on_remove(event, timeout_usec, timeout_warn_usec, properties_list, rules); + return 0; } + + r = device_clone_with_db(dev, &clone); + if (r < 0) + log_device_debug_errno(dev, r, "Failed to clone sd_device object, ignoring: %m"); + + if (clone) { + event->dev_db = udev_device_new(NULL, clone); + if (!event->dev_db) + return -ENOMEM; + + r = sd_device_get_devnum(dev, &devnum); + if (r < 0) { + if (r != -ENOENT) + log_device_debug_errno(dev, r, "Failed to get devnum, ignoring: %m"); + + if (streq(action, "move")) { + r = device_copy_properties(dev, clone); + if (r < 0) + log_device_debug_errno(dev, r, "Failed to copy properties from cloned device, ignoring: %m"); + } + } else + /* Disable watch during event processing. */ + (void) udev_watch_end(clone); + } + + (void) udev_rules_apply_to_event(rules, event, + timeout_usec, timeout_warn_usec, + properties_list); + + (void) rename_netif(event); + (void) update_devnode(event); + + /* preserve old, or get new initialization timestamp */ + r = device_ensure_usec_initialized(dev, clone); + if (r < 0) + log_device_debug_errno(dev, r, "Failed to set initialization timestamp, ignoring: %m"); + + /* (re)write database file */ + r = device_tag_index(dev, clone, true); + if (r < 0) + log_device_debug_errno(dev, r, "Failed to update tags under /run/udev/tag/, ignoring: %m"); + + r = device_update_db(dev); + if (r < 0) + log_device_debug_errno(dev, r, "Failed to update database under /run/udev/data/, ignoring: %m"); + + device_set_is_initialized(dev); + + event->dev_db = udev_device_unref(event->dev_db); + + return 0; } void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec) { diff --git a/src/udev/udev.h b/src/udev/udev.h index ec1662d700..add8b569b8 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -72,10 +72,10 @@ int udev_event_spawn(struct udev_event *event, usec_t timeout_warn_usec, bool accept_failure, const char *cmd, char *result, size_t ressize); -void udev_event_execute_rules(struct udev_event *event, - usec_t timeout_usec, usec_t timeout_warn_usec, - Hashmap *properties_list, - struct udev_rules *rules); +int udev_event_execute_rules(struct udev_event *event, + usec_t timeout_usec, usec_t timeout_warn_usec, + Hashmap *properties_list, + struct udev_rules *rules); void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec); /* Cleanup functions */ From 9204d8023fc4c56cfaba925babac3546d54b7ea0 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 25 Oct 2018 13:07:09 +0900 Subject: [PATCH 13/15] udev-event: move definition of struct subst_map --- src/udev/udev-event.c | 71 ++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index db2e3b733c..cdf7a5f6dc 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -76,7 +76,6 @@ struct udev_event *udev_event_free(struct udev_event *event) { } enum subst_type { - SUBST_UNKNOWN, SUBST_DEVNODE, SUBST_ATTR, SUBST_ENV, @@ -95,13 +94,42 @@ enum subst_type { SUBST_SYS, }; +struct subst_map_entry { + const char *name; + const char fmt; + enum subst_type type; +}; + +static const struct subst_map_entry map[] = { + { .name = "devnode", .fmt = 'N', .type = SUBST_DEVNODE }, + { .name = "tempnode", .fmt = 'N', .type = SUBST_DEVNODE }, + { .name = "attr", .fmt = 's', .type = SUBST_ATTR }, + { .name = "sysfs", .fmt = 's', .type = SUBST_ATTR }, + { .name = "env", .fmt = 'E', .type = SUBST_ENV }, + { .name = "kernel", .fmt = 'k', .type = SUBST_KERNEL }, + { .name = "number", .fmt = 'n', .type = SUBST_KERNEL_NUMBER }, + { .name = "driver", .fmt = 'd', .type = SUBST_DRIVER }, + { .name = "devpath", .fmt = 'p', .type = SUBST_DEVPATH }, + { .name = "id", .fmt = 'b', .type = SUBST_ID }, + { .name = "major", .fmt = 'M', .type = SUBST_MAJOR }, + { .name = "minor", .fmt = 'm', .type = SUBST_MINOR }, + { .name = "result", .fmt = 'c', .type = SUBST_RESULT }, + { .name = "parent", .fmt = 'P', .type = SUBST_PARENT }, + { .name = "name", .fmt = 'D', .type = SUBST_NAME }, + { .name = "links", .fmt = 'L', .type = SUBST_LINKS }, + { .name = "root", .fmt = 'r', .type = SUBST_ROOT }, + { .name = "sys", .fmt = 'S', .type = SUBST_SYS }, +}; + static size_t subst_format_var(struct udev_event *event, - enum subst_type type, char *attr, + const struct subst_map_entry *entry, char *attr, char *dest, size_t l) { struct udev_device *dev = event->dev; char *s = dest; - switch (type) { + assert(entry); + + switch (entry->type) { case SUBST_DEVPATH: l = strpcpy(&s, l, udev_device_get_devpath(dev)); break; @@ -282,8 +310,7 @@ static size_t subst_format_var(struct udev_event *event, break; } default: - log_error("unknown substitution type=%i", type); - break; + assert_not_reached("Unknown format substitution type"); } return s - dest; @@ -292,30 +319,6 @@ static size_t subst_format_var(struct udev_event *event, size_t udev_event_apply_format(struct udev_event *event, const char *src, char *dest, size_t size, bool replace_whitespace) { - static const struct subst_map { - const char *name; - const char fmt; - enum subst_type type; - } map[] = { - { .name = "devnode", .fmt = 'N', .type = SUBST_DEVNODE }, - { .name = "tempnode", .fmt = 'N', .type = SUBST_DEVNODE }, - { .name = "attr", .fmt = 's', .type = SUBST_ATTR }, - { .name = "sysfs", .fmt = 's', .type = SUBST_ATTR }, - { .name = "env", .fmt = 'E', .type = SUBST_ENV }, - { .name = "kernel", .fmt = 'k', .type = SUBST_KERNEL }, - { .name = "number", .fmt = 'n', .type = SUBST_KERNEL_NUMBER }, - { .name = "driver", .fmt = 'd', .type = SUBST_DRIVER }, - { .name = "devpath", .fmt = 'p', .type = SUBST_DEVPATH }, - { .name = "id", .fmt = 'b', .type = SUBST_ID }, - { .name = "major", .fmt = 'M', .type = SUBST_MAJOR }, - { .name = "minor", .fmt = 'm', .type = SUBST_MINOR }, - { .name = "result", .fmt = 'c', .type = SUBST_RESULT }, - { .name = "parent", .fmt = 'P', .type = SUBST_PARENT }, - { .name = "name", .fmt = 'D', .type = SUBST_NAME }, - { .name = "links", .fmt = 'L', .type = SUBST_LINKS }, - { .name = "root", .fmt = 'r', .type = SUBST_ROOT }, - { .name = "sys", .fmt = 'S', .type = SUBST_SYS }, - }; const char *from; char *s; size_t l; @@ -331,7 +334,7 @@ size_t udev_event_apply_format(struct udev_event *event, l = size; for (;;) { - enum subst_type type = SUBST_UNKNOWN; + const struct subst_map_entry *entry = NULL; char attrbuf[UTIL_PATH_SIZE]; char *attr = NULL; size_t subst_len; @@ -348,7 +351,7 @@ size_t udev_event_apply_format(struct udev_event *event, for (i = 0; i < ELEMENTSOF(map); i++) { if (startswith(&from[1], map[i].name)) { - type = map[i].type; + entry = &map[i]; from += strlen(map[i].name)+1; goto subst; } @@ -364,7 +367,7 @@ size_t udev_event_apply_format(struct udev_event *event, for (i = 0; i < ELEMENTSOF(map); i++) { if (from[1] == map[i].fmt) { - type = map[i].type; + entry = &map[i]; from += 2; goto subst; } @@ -403,10 +406,10 @@ subst: attr = NULL; } - subst_len = subst_format_var(event, type, attr, s, l); + subst_len = subst_format_var(event, entry, attr, s, l); /* SUBST_RESULT handles spaces itself */ - if (replace_whitespace && type != SUBST_RESULT) + if (replace_whitespace && entry->type != SUBST_RESULT) /* util_replace_whitespace can replace in-place, * and does nothing if subst_len == 0 */ From a315999de64ca172e5849a54989ac2ffa9e0add7 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 25 Oct 2018 14:00:36 +0900 Subject: [PATCH 14/15] udev-event: drop prototype of nonexistent function --- src/udev/udev.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/udev/udev.h b/src/udev/udev.h index add8b569b8..bcacd9b7d8 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -65,8 +65,6 @@ struct udev_event *udev_event_free(struct udev_event *event); 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, usec_t timeout_usec, usec_t timeout_warn_usec, From 4cade7a15b9af5b628c2ae9d0f3e9cefbe4ef4bf Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 25 Oct 2018 13:59:03 +0900 Subject: [PATCH 15/15] udev-event: replace udev_device in subst_format_var() by sd_device --- src/udev/udev-event.c | 215 +++++++++++++++++++++--------------------- src/udev/udev.h | 6 +- 2 files changed, 111 insertions(+), 110 deletions(-) diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index cdf7a5f6dc..70fb190897 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -21,6 +21,7 @@ #include "path-util.h" #include "process-util.h" #include "signal-util.h" +#include "stdio-util.h" #include "string-util.h" #include "udev-builtin.h" #include "udev-node.h" @@ -121,71 +122,76 @@ static const struct subst_map_entry map[] = { { .name = "sys", .fmt = 'S', .type = SUBST_SYS }, }; -static size_t subst_format_var(struct udev_event *event, - const struct subst_map_entry *entry, char *attr, - char *dest, size_t l) { - struct udev_device *dev = event->dev; +static ssize_t subst_format_var(struct udev_event *event, + const struct subst_map_entry *entry, char *attr, + char *dest, size_t l) { + sd_device *parent, *dev = event->dev->device; + const char *val = NULL; char *s = dest; + dev_t devnum; + int r; assert(entry); switch (entry->type) { case SUBST_DEVPATH: - l = strpcpy(&s, l, udev_device_get_devpath(dev)); + r = sd_device_get_devpath(dev, &val); + if (r < 0) + return r; + l = strpcpy(&s, l, val); break; case SUBST_KERNEL: - l = strpcpy(&s, l, udev_device_get_sysname(dev)); + r = sd_device_get_sysname(dev, &val); + if (r < 0) + return r; + l = strpcpy(&s, l, val); break; case SUBST_KERNEL_NUMBER: - if (udev_device_get_sysnum(dev) == NULL) - break; - l = strpcpy(&s, l, udev_device_get_sysnum(dev)); + r = sd_device_get_sysnum(dev, &val); + if (r < 0) + return r == -ENOENT ? 0 : r; + l = strpcpy(&s, l, val); break; case SUBST_ID: - if (event->dev_parent == NULL) - break; - l = strpcpy(&s, l, udev_device_get_sysname(event->dev_parent)); + if (!event->dev_parent) + return 0; + r = sd_device_get_sysname(event->dev_parent->device, &val); + if (r < 0) + return r; + l = strpcpy(&s, l, val); break; - case SUBST_DRIVER: { - const char *driver; - - if (event->dev_parent == NULL) - break; - - driver = udev_device_get_driver(event->dev_parent); - if (driver == NULL) - break; - l = strpcpy(&s, l, driver); + case SUBST_DRIVER: + if (!event->dev_parent) + return 0; + r = sd_device_get_driver(event->dev_parent->device, &val); + if (r < 0) + return r == -ENOENT ? 0 : r; + l = strpcpy(&s, l, val); break; - } - case SUBST_MAJOR: { - char num[UTIL_PATH_SIZE]; - - sprintf(num, "%u", major(udev_device_get_devnum(dev))); - l = strpcpy(&s, l, num); - break; - } + case SUBST_MAJOR: case SUBST_MINOR: { - char num[UTIL_PATH_SIZE]; + char buf[DECIMAL_STR_MAX(unsigned)]; - sprintf(num, "%u", minor(udev_device_get_devnum(dev))); - l = strpcpy(&s, l, num); + r = sd_device_get_devnum(dev, &devnum); + if (r < 0 && r != -ENOENT) + return r; + xsprintf(buf, "%u", r < 0 ? 0 : entry->type == SUBST_MAJOR ? major(devnum) : minor(devnum)); + l = strpcpy(&s, l, buf); break; } case SUBST_RESULT: { char *rest; int i; - if (event->program_result == NULL) - break; + if (!event->program_result) + return 0; + /* get part of the result string */ i = 0; - if (attr != NULL) + if (attr) i = strtoul(attr, &rest, 10); if (i > 0) { - char result[UTIL_PATH_SIZE]; - char tmp[UTIL_PATH_SIZE]; - char *cpos; + char result[UTIL_PATH_SIZE], tmp[UTIL_PATH_SIZE], *cpos; strscpy(result, sizeof(result), event->program_result); cpos = result; @@ -209,88 +215,79 @@ static size_t subst_format_var(struct udev_event *event, cpos[0] = '\0'; } l = strpcpy(&s, l, tmp); - } else { + } else l = strpcpy(&s, l, event->program_result); - } break; } case SUBST_ATTR: { - const char *value = NULL; char vbuf[UTIL_NAME_SIZE]; size_t len; int count; - if (attr == NULL) { - log_error("missing file parameter for attr"); - break; - } + if (!attr) + return -EINVAL; /* try to read the value specified by "[dmi/id]product_name" */ if (util_resolve_subsys_kernel(attr, vbuf, sizeof(vbuf), 1) == 0) - value = vbuf; + val = vbuf; /* try to read the attribute the device */ - if (value == NULL) - value = udev_device_get_sysattr_value(event->dev, attr); + if (!val) + (void) sd_device_get_sysattr_value(dev, attr, &val); /* try to read the attribute of the parent device, other matches have selected */ - if (value == NULL && event->dev_parent != NULL && event->dev_parent != event->dev) - value = udev_device_get_sysattr_value(event->dev_parent, attr); + if (!val && event->dev_parent && event->dev_parent->device != dev) + (void) sd_device_get_sysattr_value(event->dev_parent->device, attr, &val); - if (value == NULL) - break; + if (!val) + return 0; /* strip trailing whitespace, and replace unwanted characters */ - if (value != vbuf) - strscpy(vbuf, sizeof(vbuf), value); + if (val != vbuf) + strscpy(vbuf, sizeof(vbuf), val); len = strlen(vbuf); while (len > 0 && isspace(vbuf[--len])) vbuf[len] = '\0'; count = util_replace_chars(vbuf, UDEV_ALLOWED_CHARS_INPUT); if (count > 0) - log_debug("%i character(s) replaced" , count); + log_device_debug(dev, "%i character(s) replaced", count); l = strpcpy(&s, l, vbuf); break; } - case SUBST_PARENT: { - struct udev_device *dev_parent; - const char *devnode; - - dev_parent = udev_device_get_parent(event->dev); - if (dev_parent == NULL) - break; - devnode = udev_device_get_devnode(dev_parent); - if (devnode != NULL) - l = strpcpy(&s, l, devnode + STRLEN("/dev/")); + case SUBST_PARENT: + r = sd_device_get_parent(dev, &parent); + if (r < 0) + return r == -ENODEV ? 0 : r; + r = sd_device_get_devname(parent, &val); + if (r < 0) + return r == -ENOENT ? 0 : r; + l = strpcpy(&s, l, val + STRLEN("/dev/")); break; - } case SUBST_DEVNODE: - if (udev_device_get_devnode(dev) != NULL) - l = strpcpy(&s, l, udev_device_get_devnode(dev)); + r = sd_device_get_devname(dev, &val); + if (r < 0) + return r == -ENOENT ? 0 : r; + l = strpcpy(&s, l, val); break; case SUBST_NAME: - if (event->name != NULL) + if (event->name) l = strpcpy(&s, l, event->name); - else if (udev_device_get_devnode(dev) != NULL) - l = strpcpy(&s, l, - udev_device_get_devnode(dev) + STRLEN("/dev/")); - else - l = strpcpy(&s, l, udev_device_get_sysname(dev)); + else if (sd_device_get_devname(dev, &val) >= 0) + l = strpcpy(&s, l, val + STRLEN("/dev/")); + else { + r = sd_device_get_sysname(dev, &val); + if (r < 0) + return r; + l = strpcpy(&s, l, val); + } break; - case SUBST_LINKS: { - struct udev_list_entry *list_entry; - - list_entry = udev_device_get_devlinks_list_entry(dev); - if (list_entry == NULL) - break; - l = strpcpy(&s, l, - udev_list_entry_get_name(list_entry) + STRLEN("/dev/")); - udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry)) - l = strpcpyl(&s, l, " ", - udev_list_entry_get_name(list_entry) + STRLEN("/dev/"), - NULL); + case SUBST_LINKS: + FOREACH_DEVICE_DEVLINK(dev, val) + if (s == dest) + l = strpcpy(&s, l, val + STRLEN("/dev/")); + else + l = strpcpyl(&s, l, " ", val + STRLEN("/dev/"), NULL); break; - } case SUBST_ROOT: l = strpcpy(&s, l, "/dev"); break; @@ -298,17 +295,13 @@ static size_t subst_format_var(struct udev_event *event, l = strpcpy(&s, l, "/sys"); break; case SUBST_ENV: - if (attr == NULL) { - break; - } else { - const char *value; - - value = udev_device_get_property_value(event->dev, attr); - if (value == NULL) - break; - l = strpcpy(&s, l, value); - break; - } + if (!attr) + return 0; + r = sd_device_get_property_value(dev, attr, &val); + if (r < 0) + return r == -ENOENT ? 0 : r; + l = strpcpy(&s, l, val); + break; default: assert_not_reached("Unknown format substitution type"); } @@ -316,9 +309,9 @@ static size_t subst_format_var(struct udev_event *event, return s - dest; } -size_t udev_event_apply_format(struct udev_event *event, - const char *src, char *dest, size_t size, - bool replace_whitespace) { +ssize_t udev_event_apply_format(struct udev_event *event, + const char *src, char *dest, size_t size, + bool replace_whitespace) { const char *from; char *s; size_t l; @@ -335,9 +328,9 @@ size_t udev_event_apply_format(struct udev_event *event, for (;;) { const struct subst_map_entry *entry = NULL; - char attrbuf[UTIL_PATH_SIZE]; - char *attr = NULL; - size_t subst_len; + char attrbuf[UTIL_PATH_SIZE], *attr; + bool format_dollar = false; + ssize_t subst_len; while (from[0] != '\0') { if (from[0] == '$') { @@ -353,6 +346,7 @@ size_t udev_event_apply_format(struct udev_event *event, if (startswith(&from[1], map[i].name)) { entry = &map[i]; from += strlen(map[i].name)+1; + format_dollar = true; goto subst; } } @@ -402,11 +396,18 @@ subst: attrbuf[i] = '\0'; from += i+1; attr = attrbuf; - } else { + } else attr = NULL; - } subst_len = subst_format_var(event, entry, attr, s, l); + if (subst_len < 0) { + if (format_dollar) + log_device_warning_errno(event->dev->device, subst_len, "Failed to substitute variable '$%s', ignoring: %m", entry->name); + else + log_device_warning_errno(event->dev->device, subst_len, "Failed to apply format '%%%c', ignoring: %m", entry->fmt); + + continue; + } /* SUBST_RESULT handles spaces itself */ if (replace_whitespace && entry->type != SUBST_RESULT) diff --git a/src/udev/udev.h b/src/udev/udev.h index bcacd9b7d8..f723dd7067 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -62,9 +62,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); struct udev_event *udev_event_free(struct udev_event *event); -size_t udev_event_apply_format(struct udev_event *event, - const char *src, char *dest, size_t size, - bool replace_whitespace); +ssize_t udev_event_apply_format(struct udev_event *event, + const char *src, char *dest, size_t size, + bool replace_whitespace); int udev_event_spawn(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec,