From d5c4c4d45c6075f5a1dde024d7a4717b71f369a2 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 7 Jan 2025 20:23:02 +0900 Subject: [PATCH 1/5] TEST-17-UDEV: wait for udevd being restarted after exit control command Also wait for created devices being processed before running tests. --- test/units/TEST-17-UDEV.10.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/units/TEST-17-UDEV.10.sh b/test/units/TEST-17-UDEV.10.sh index 7ca05f5287..afa05909c4 100755 --- a/test/units/TEST-17-UDEV.10.sh +++ b/test/units/TEST-17-UDEV.10.sh @@ -28,9 +28,15 @@ blk="$(mktemp)" dd if=/dev/zero of="$blk" bs=1M count=1 loopdev="$(losetup --show -f "$blk")" +# Wait for devices created in the above being processed. +udevadm settle --timeout 30 + udevadm -h +INVOCATION_ID=$(systemctl show --property InvocationID --value systemd-udevd.service) udevadm control -e +# Wait for systemd-udevd.service being restarted. +timeout 30 bash -ec "while [[ \"\$(systemctl show --property InvocationID --value systemd-udevd.service)\" == \"$INVOCATION_ID\" ]]; do sleep .5; done" udevadm control -l emerg udevadm control -l alert udevadm control -l crit From 2f0aa9a80445ef18086260a60fad71920ad9486c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 22 Dec 2024 01:58:09 +0900 Subject: [PATCH 2/5] udev-varlink: introduce io.systemd.Udev varlink interface Co-authored-by: David Tardon --- src/shared/meson.build | 1 + src/shared/varlink-io.systemd.Udev.c | 34 ++++++ src/shared/varlink-io.systemd.Udev.h | 7 ++ src/test/test-varlink-idl.c | 3 + src/udev/meson.build | 1 + src/udev/udev-manager.c | 15 ++- src/udev/udev-manager.h | 4 + src/udev/udev-varlink.c | 165 +++++++++++++++++++++++++++ src/udev/udev-varlink.h | 6 + 9 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 src/shared/varlink-io.systemd.Udev.c create mode 100644 src/shared/varlink-io.systemd.Udev.h create mode 100644 src/udev/udev-varlink.c create mode 100644 src/udev/udev-varlink.h diff --git a/src/shared/meson.build b/src/shared/meson.build index 29bf974a71..403c304338 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -194,6 +194,7 @@ shared_sources = files( 'varlink-io.systemd.PCRLock.c', 'varlink-io.systemd.Resolve.c', 'varlink-io.systemd.Resolve.Monitor.c', + 'varlink-io.systemd.Udev.c', 'varlink-io.systemd.UserDatabase.c', 'varlink-io.systemd.oom.c', 'varlink-io.systemd.service.c', diff --git a/src/shared/varlink-io.systemd.Udev.c b/src/shared/varlink-io.systemd.Udev.c new file mode 100644 index 0000000000..fb34036b42 --- /dev/null +++ b/src/shared/varlink-io.systemd.Udev.c @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "varlink-io.systemd.Udev.h" + +static SD_VARLINK_DEFINE_METHOD( + SetChildrenMax, + SD_VARLINK_FIELD_COMMENT("The maximum number of child processes. When 0 is specified, the maximum is determined based on the system resources."), + SD_VARLINK_DEFINE_INPUT(number, SD_VARLINK_INT, 0)); + +static SD_VARLINK_DEFINE_METHOD( + SetEnvironment, + SD_VARLINK_FIELD_COMMENT("An array of global udev property assignments. Each string must be in KEY=VALUE style."), + SD_VARLINK_DEFINE_INPUT(assignments, SD_VARLINK_STRING, SD_VARLINK_ARRAY)); + +static SD_VARLINK_DEFINE_METHOD(StartExecQueue); + +static SD_VARLINK_DEFINE_METHOD(StopExecQueue); + +static SD_VARLINK_DEFINE_METHOD(Exit); + +SD_VARLINK_DEFINE_INTERFACE( + io_systemd_Udev, + "io.systemd.Udev", + SD_VARLINK_INTERFACE_COMMENT("An interface for controlling systemd-udevd."), + SD_VARLINK_SYMBOL_COMMENT("Sets the maximum number of child processes."), + &vl_method_SetChildrenMax, + SD_VARLINK_SYMBOL_COMMENT("Sets the global udev properties."), + &vl_method_SetEnvironment, + SD_VARLINK_SYMBOL_COMMENT("Starts processing of queued events."), + &vl_method_StartExecQueue, + SD_VARLINK_SYMBOL_COMMENT("Stops processing of queued events."), + &vl_method_StopExecQueue, + SD_VARLINK_SYMBOL_COMMENT("Terminates systemd-udevd. This exists for backward compatibility. Please consider to use 'systemctl stop systemd-udevd.service'."), + &vl_method_Exit); diff --git a/src/shared/varlink-io.systemd.Udev.h b/src/shared/varlink-io.systemd.Udev.h new file mode 100644 index 0000000000..d56f613eff --- /dev/null +++ b/src/shared/varlink-io.systemd.Udev.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#pragma once + +#include "sd-varlink.h" +#include "sd-varlink-idl.h" + +extern const sd_varlink_interface vl_interface_io_systemd_Udev; diff --git a/src/test/test-varlink-idl.c b/src/test/test-varlink-idl.c index 74c64d392a..2426779505 100644 --- a/src/test/test-varlink-idl.c +++ b/src/test/test-varlink-idl.c @@ -25,6 +25,7 @@ #include "varlink-io.systemd.PCRLock.h" #include "varlink-io.systemd.Resolve.h" #include "varlink-io.systemd.Resolve.Monitor.h" +#include "varlink-io.systemd.Udev.h" #include "varlink-io.systemd.UserDatabase.h" #include "varlink-io.systemd.oom.h" #include "varlink-io.systemd.service.h" @@ -197,6 +198,8 @@ TEST(parse_format) { print_separator(); test_parse_format_one(&vl_interface_io_systemd_AskPassword); print_separator(); + test_parse_format_one(&vl_interface_io_systemd_Udev); + print_separator(); test_parse_format_one(&vl_interface_xyz_test); } diff --git a/src/udev/meson.build b/src/udev/meson.build index b4af60255c..5d5cc33a49 100644 --- a/src/udev/meson.build +++ b/src/udev/meson.build @@ -37,6 +37,7 @@ libudevd_core_sources = files( 'udev-node.c', 'udev-rules.c', 'udev-spawn.c', + 'udev-varlink.c', 'udev-watch.c', 'udev-worker.c', ) diff --git a/src/udev/udev-manager.c b/src/udev/udev-manager.c index 1768da5a38..b7f2b185c9 100644 --- a/src/udev/udev-manager.c +++ b/src/udev/udev-manager.c @@ -32,6 +32,7 @@ #include "udev-spawn.h" #include "udev-trace.h" #include "udev-util.h" +#include "udev-varlink.h" #include "udev-watch.h" #include "udev-worker.h" @@ -148,6 +149,7 @@ Manager* manager_free(Manager *manager) { sd_device_monitor_unref(manager->monitor); udev_ctrl_unref(manager->ctrl); + sd_varlink_server_unref(manager->varlink_server); sd_event_source_unref(manager->inotify_event); sd_event_source_unref(manager->kill_workers_event); @@ -213,7 +215,7 @@ void manager_kill_workers(Manager *manager, bool force) { } } -static void manager_exit(Manager *manager) { +void manager_exit(Manager *manager) { assert(manager); manager->exit = true; @@ -222,7 +224,7 @@ static void manager_exit(Manager *manager) { /* close sources of new events and discard buffered events */ manager->ctrl = udev_ctrl_unref(manager->ctrl); - + manager->varlink_server = sd_varlink_server_unref(manager->varlink_server); manager->inotify_event = sd_event_source_disable_unref(manager->inotify_event); manager->inotify_fd = safe_close(manager->inotify_fd); @@ -246,7 +248,7 @@ void notify_ready(Manager *manager) { } /* reload requested, HUP signal received, rules changed, builtin changed */ -static void manager_reload(Manager *manager, bool force) { +void manager_reload(Manager *manager, bool force) { _cleanup_(udev_rules_freep) UdevRules *rules = NULL; usec_t now_usec; int r; @@ -1150,6 +1152,9 @@ static int listen_fds(int *ret_ctrl, int *ret_netlink) { for (int i = 0; i < n; i++) { int fd = SD_LISTEN_FDS_START + i; + if (streq(names[i], "varlink")) + continue; /* The fd will be handled by sd_varlink_server_listen_auto(). */ + if (sd_is_socket(fd, AF_UNIX, SOCK_SEQPACKET, -1) > 0) { if (ctrl_fd >= 0) { log_debug("Received multiple seqpacket socket (%s), ignoring.", names[i]); @@ -1417,6 +1422,10 @@ int manager_main(Manager *manager) { if (r < 0) return r; + r = manager_start_varlink_server(manager); + if (r < 0) + return r; + r = manager_start_device_monitor(manager); if (r < 0) return r; diff --git a/src/udev/udev-manager.h b/src/udev/udev-manager.h index 2690d59bf3..808f75d3e1 100644 --- a/src/udev/udev-manager.h +++ b/src/udev/udev-manager.h @@ -5,6 +5,7 @@ #include "sd-device.h" #include "sd-event.h" +#include "sd-varlink.h" #include "hashmap.h" #include "macro.h" @@ -28,6 +29,7 @@ typedef struct Manager { sd_device_monitor *monitor; UdevCtrl *ctrl; + sd_varlink_server *varlink_server; int worker_notify_fd; /* used by udev-watch */ @@ -54,6 +56,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); int manager_init(Manager *manager); int manager_main(Manager *manager); +void manager_reload(Manager *manager, bool force); +void manager_exit(Manager *manager); void notify_ready(Manager *manager); diff --git a/src/udev/udev-varlink.c b/src/udev/udev-varlink.c new file mode 100644 index 0000000000..8a7b48817a --- /dev/null +++ b/src/udev/udev-varlink.c @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "json-util.h" +#include "strv.h" +#include "udev-manager.h" +#include "udev-varlink.h" +#include "varlink-io.systemd.Udev.h" +#include "varlink-io.systemd.service.h" +#include "varlink-util.h" + +#define UDEV_VARLINK_ADDRESS "/run/udev/io.systemd.Udev" + +static int vl_method_reload(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { + assert(link); + + if (sd_json_variant_elements(parameters) > 0) + return sd_varlink_error_invalid_parameter(link, parameters); + + log_debug("Received io.systemd.service.Reload()"); + manager_reload(userdata, /* force = */ true); + return sd_varlink_reply(link, NULL); +} + +static int vl_method_set_log_level(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { + int r, level; + + static const sd_json_dispatch_field dispatch_table[] = { + { "level", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_log_level, 0, SD_JSON_MANDATORY }, + {} + }; + + assert(link); + + r = sd_varlink_dispatch(link, parameters, dispatch_table, &level); + if (r != 0) + return r; + + log_debug("Received io.systemd.service.SetLogLevel(%i)", level); + manager_set_log_level(userdata, level); + return sd_varlink_reply(link, NULL); +} + +static int vl_method_set_children_max(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { + unsigned n; + int r; + + static const sd_json_dispatch_field dispatch_table[] = { + { "number", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint, 0, SD_JSON_MANDATORY }, + {} + }; + + assert(link); + + r = sd_varlink_dispatch(link, parameters, dispatch_table, &n); + if (r != 0) + return r; + + log_debug("Received io.systemd.Udev.SetChildrenMax(%u)", n); + manager_set_children_max(userdata, n); + return sd_varlink_reply(link, NULL); +} + +static int vl_method_set_environment(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { + int r; + + static const sd_json_dispatch_field dispatch_table[] = { + { "assignments", SD_JSON_VARIANT_ARRAY, json_dispatch_strv_environment, 0, SD_JSON_MANDATORY }, + {} + }; + + assert(link); + + _cleanup_strv_free_ char **v = NULL; + r = sd_varlink_dispatch(link, parameters, dispatch_table, &v); + if (r != 0) + return r; + + log_debug("Received io.systemd.Udev.SetEnvironment()"); + manager_set_environment(userdata, v); + return sd_varlink_reply(link, NULL); +} + +static int vl_method_start_stop_exec_queue(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { + Manager *manager = ASSERT_PTR(userdata); + const char *method; + int r; + + assert(link); + + if (sd_json_variant_elements(parameters) > 0) + return sd_varlink_error_invalid_parameter(link, parameters); + + r = sd_varlink_get_current_method(link, &method); + if (r < 0) + return r; + + log_debug("Received %s()", method); + manager->stop_exec_queue = streq(method, "io.systemd.Udev.StopExecQueue"); + return sd_varlink_reply(link, NULL); +} + +static int vl_method_exit(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { + assert(link); + + if (sd_json_variant_elements(parameters) > 0) + return sd_varlink_error_invalid_parameter(link, parameters); + + /* Refuse further connections. */ + _unused_ _cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *v = sd_varlink_ref(link); + + log_debug("Received io.systemd.udev.Exit()"); + manager_exit(userdata); + return sd_varlink_reply(link, NULL); +} + +int manager_start_varlink_server(Manager *manager) { + _cleanup_(sd_varlink_server_unrefp) sd_varlink_server *v = NULL; + int r; + + assert(manager); + assert(manager->event); + + r = varlink_server_new(&v, SD_VARLINK_SERVER_ROOT_ONLY | SD_VARLINK_SERVER_INHERIT_USERDATA, manager); + if (r < 0) + return log_error_errno(r, "Failed to allocate Varlink server: %m"); + + /* This needs to be after the inotify and uevent handling, to make sure that the ping is send back + * after fully processing the pending uevents (including the synthetic ones we may create due to + * inotify events). */ + r = sd_varlink_server_attach_event(v, manager->event, SD_EVENT_PRIORITY_IDLE); + if (r < 0) + return log_error_errno(r, "Failed to attach Varlink connection to event loop: %m"); + + r = sd_varlink_server_listen_auto(v); + if (r < 0) + return log_error_errno(r, "Failed to bind to passed Varlink socket: %m"); + if (r == 0) { + r = sd_varlink_server_listen_address(v, UDEV_VARLINK_ADDRESS, 0600); + if (r < 0) + return log_error_errno(r, "Failed to bind to Varlink socket: %m"); + } + + r = sd_varlink_server_add_interface_many( + v, + &vl_interface_io_systemd_service, + &vl_interface_io_systemd_Udev); + if (r < 0) + return log_error_errno(r, "Failed to add Varlink interface: %m"); + + r = sd_varlink_server_bind_method_many( + v, + "io.systemd.service.Ping", varlink_method_ping, + "io.systemd.service.Reload", vl_method_reload, + "io.systemd.service.SetLogLevel", vl_method_set_log_level, + "io.systemd.Udev.SetChildrenMax", vl_method_set_children_max, + "io.systemd.Udev.SetEnvironment", vl_method_set_environment, + "io.systemd.Udev.StartExecQueue", vl_method_start_stop_exec_queue, + "io.systemd.Udev.StopExecQueue", vl_method_start_stop_exec_queue, + "io.systemd.Udev.Exit", vl_method_exit); + if (r < 0) + return log_error_errno(r, "Failed to bind Varlink methods: %m"); + + manager->varlink_server = TAKE_PTR(v); + return 0; +} diff --git a/src/udev/udev-varlink.h b/src/udev/udev-varlink.h new file mode 100644 index 0000000000..c4e3251768 --- /dev/null +++ b/src/udev/udev-varlink.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +typedef struct Manager Manager; + +int manager_start_varlink_server(Manager *manager); From 4e4c2fcfb63fe58b234a089d57c87db038157db0 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 22 Dec 2024 06:03:52 +0900 Subject: [PATCH 3/5] udevadm-control: use varlink to send commands --- src/udev/udev-varlink.c | 20 ++++++++++++ src/udev/udev-varlink.h | 5 +++ src/udev/udevadm-control.c | 63 +++++++++++++++++++++++++++++++++++++- 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/src/udev/udev-varlink.c b/src/udev/udev-varlink.c index 8a7b48817a..8faadb8bcf 100644 --- a/src/udev/udev-varlink.c +++ b/src/udev/udev-varlink.c @@ -163,3 +163,23 @@ int manager_start_varlink_server(Manager *manager) { manager->varlink_server = TAKE_PTR(v); return 0; } + +int udev_varlink_connect(sd_varlink **ret, usec_t timeout) { + _cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *link = NULL; + int r; + + assert(ret); + + r = sd_varlink_connect_address(&link, UDEV_VARLINK_ADDRESS); + if (r < 0) + return r; + + (void) sd_varlink_set_description(link, "udev"); + + r = sd_varlink_set_relative_timeout(link, timeout); + if (r < 0) + return r; + + *ret = TAKE_PTR(link); + return 0; +} diff --git a/src/udev/udev-varlink.h b/src/udev/udev-varlink.h index c4e3251768..759a4460ab 100644 --- a/src/udev/udev-varlink.h +++ b/src/udev/udev-varlink.h @@ -1,6 +1,11 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include "sd-varlink.h" + +#include "time-util.h" + typedef struct Manager Manager; int manager_start_varlink_server(Manager *manager); +int udev_varlink_connect(sd_varlink **ret, usec_t timeout); diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c index 29dc88330c..3ccc621357 100644 --- a/src/udev/udevadm-control.c +++ b/src/udev/udevadm-control.c @@ -9,6 +9,7 @@ #include #include "creds-util.h" +#include "errno-util.h" #include "parse-util.h" #include "process-util.h" #include "static-destruct.h" @@ -17,6 +18,8 @@ #include "time-util.h" #include "udevadm.h" #include "udev-ctrl.h" +#include "udev-varlink.h" +#include "varlink-util.h" #include "virt.h" static char **arg_env = NULL; @@ -174,7 +177,7 @@ static int parse_argv(int argc, char *argv[]) { return 1; } -static int send_control_commands(void) { +static int send_control_commands_via_ctrl(void) { _cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL; int r; @@ -238,6 +241,64 @@ static int send_control_commands(void) { return 0; } +static int send_control_commands(void) { + _cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *link = NULL; + int r; + + r = udev_varlink_connect(&link, arg_timeout); + if (ERRNO_IS_NEG_DISCONNECT(r) || r == -ENOENT) { + log_debug_errno(r, "Failed to connect to udev via varlink, falling back to use legacy control socket, ignoring: %m"); + return send_control_commands_via_ctrl(); + } + if (r < 0) + return log_error_errno(r, "Failed to connect to udev via varlink: %m"); + + if (arg_exit) + return varlink_call_and_log(link, "io.systemd.Udev.Exit", /* parameters = */ NULL, /* reply = */ NULL); + + if (arg_log_level >= 0) { + r = varlink_callbo_and_log(link, "io.systemd.service.SetLogLevel", /* reply = */ NULL, + SD_JSON_BUILD_PAIR_INTEGER("level", arg_log_level)); + if (r < 0) + return r; + } + + if (arg_start_exec_queue >= 0) { + r = varlink_call_and_log(link, arg_start_exec_queue ? "io.systemd.Udev.StartExecQueue" : "io.systemd.Udev.StopExecQueue", + /* parameters = */ NULL, /* reply = */ NULL); + if (r < 0) + return r; + } + + if (arg_reload) { + r = varlink_call_and_log(link, "io.systemd.service.Reload", /* parameters = */ NULL, /* reply = */ NULL); + if (r < 0) + return r; + } + + if (!strv_isempty(arg_env)) { + r = varlink_callbo_and_log(link, "io.systemd.Udev.SetEnvironment", /* reply = */ NULL, + SD_JSON_BUILD_PAIR_STRV("assignments", arg_env)); + if (r < 0) + return r; + } + + if (arg_max_children >= 0) { + r = varlink_callbo_and_log(link, "io.systemd.Udev.SetChildrenMax", /* reply = */ NULL, + SD_JSON_BUILD_PAIR_UNSIGNED("number", arg_max_children)); + if (r < 0) + return r; + } + + if (arg_ping) { + r = varlink_call_and_log(link, "io.systemd.service.Ping", /* parameters = */ NULL, /* reply = */ NULL); + if (r < 0) + return r; + } + + return 0; +} + int control_main(int argc, char *argv[], void *userdata) { int r; From 3fed28b8cb6323b4aee6e42ecb37bc2657bac50a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 22 Dec 2024 06:53:43 +0900 Subject: [PATCH 4/5] udevadm: use varlink connection to send ping --- src/udev/udevadm-settle.c | 22 ++++-------------- src/udev/udevadm-trigger.c | 16 +++---------- src/udev/udevadm-util.c | 46 ++++++++++++++++++++++++++++++++++++++ src/udev/udevadm-util.h | 1 + 4 files changed, 54 insertions(+), 31 deletions(-) diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c index d47a9c3a07..72e09e0fc5 100644 --- a/src/udev/udevadm-settle.c +++ b/src/udev/udevadm-settle.c @@ -16,8 +16,8 @@ #include "path-util.h" #include "strv.h" #include "time-util.h" -#include "udev-ctrl.h" #include "udev-util.h" +#include "udevadm-util.h" #include "udevadm.h" #include "unit-def.h" #include "virt.h" @@ -198,23 +198,9 @@ int settle_main(int argc, char *argv[], void *userdata) { (void) emit_deprecation_warning(); if (getuid() == 0) { - _cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL; - - /* guarantee that the udev daemon isn't pre-processing */ - - r = udev_ctrl_new(&uctrl); - if (r < 0) - return log_error_errno(r, "Failed to create control socket for udev daemon: %m"); - - r = udev_ctrl_send_ping(uctrl); - if (r < 0) { - log_debug_errno(r, "Failed to connect to udev daemon, ignoring: %m"); - return 0; - } - - r = udev_ctrl_wait(uctrl, MAX(5 * USEC_PER_SEC, arg_timeout_usec)); - if (r < 0) - return log_error_errno(r, "Failed to wait for daemon to reply: %m"); + r = udev_ping(MAX(5 * USEC_PER_SEC, arg_timeout_usec), /* ignore_connection_failure = */ true); + if (r <= 0) + return r; } else { /* For non-privileged users, at least check if udevd is running. */ if (access("/run/udev/control", F_OK) < 0) diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index 695f440b8f..808c383e21 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -21,7 +21,6 @@ #include "strv.h" #include "udevadm.h" #include "udevadm-util.h" -#include "udev-ctrl.h" #include "virt.h" static bool arg_verbose = false; @@ -498,19 +497,10 @@ int trigger_main(int argc, char *argv[], void *userdata) { } if (ping) { - _cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL; - - r = udev_ctrl_new(&uctrl); + r = udev_ping(ping_timeout_usec, /* ignore_connection_failure = */ false); if (r < 0) - return log_error_errno(r, "Failed to initialize udev control: %m"); - - r = udev_ctrl_send_ping(uctrl); - if (r < 0) - return log_error_errno(r, "Failed to connect to udev daemon: %m"); - - r = udev_ctrl_wait(uctrl, ping_timeout_usec); - if (r < 0) - return log_error_errno(r, "Failed to wait for daemon to reply: %m"); + return r; + assert(r > 0); } for (; optind < argc; optind++) { diff --git a/src/udev/udevadm-util.c b/src/udev/udevadm-util.c index 2447edad19..2a3e974d04 100644 --- a/src/udev/udevadm-util.c +++ b/src/udev/udevadm-util.c @@ -7,8 +7,11 @@ #include "bus-util.h" #include "device-private.h" #include "path-util.h" +#include "udev-ctrl.h" +#include "udev-varlink.h" #include "udevadm-util.h" #include "unit-name.h" +#include "varlink-util.h" static int find_device_from_unit(const char *unit_name, sd_device **ret) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -122,3 +125,46 @@ int parse_device_action(const char *str, sd_device_action_t *action) { *action = a; return 1; } + +static int udev_ping_via_ctrl(usec_t timeout_usec, bool ignore_connection_failure) { + _cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL; + int r; + + r = udev_ctrl_new(&uctrl); + if (r < 0) + return log_error_errno(r, "Failed to initialize udev control: %m"); + + r = udev_ctrl_send_ping(uctrl); + if (r < 0) { + bool ignore = ignore_connection_failure && (ERRNO_IS_NEG_DISCONNECT(r) || r == -ENOENT); + log_full_errno(ignore ? LOG_DEBUG : LOG_ERR, r, + "Failed to connect to udev daemon%s: %m", + ignore ? ", ignoring" : ""); + return ignore ? 0 : r; + } + + r = udev_ctrl_wait(uctrl, timeout_usec); + if (r < 0) + return log_error_errno(r, "Failed to wait for daemon to reply: %m"); + + return 1; /* received reply */ +} + +int udev_ping(usec_t timeout_usec, bool ignore_connection_failure) { + _cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *link = NULL; + int r; + + r = udev_varlink_connect(&link, timeout_usec); + if (ERRNO_IS_NEG_DISCONNECT(r) || r == -ENOENT) { + log_debug_errno(r, "Failed to connect to udev via varlink, falling back to use legacy control socket, ignoring: %m"); + return udev_ping_via_ctrl(timeout_usec, ignore_connection_failure); + } + if (r < 0) + return log_error_errno(r, "Failed to connect to udev via varlink: %m"); + + r = varlink_call_and_log(link, "io.systemd.service.Ping", /* parameters = */ NULL, /* reply = */ NULL); + if (r < 0) + return r; + + return 1; /* received reply */ +} diff --git a/src/udev/udevadm-util.h b/src/udev/udevadm-util.h index 7fb4556413..4b58efbe97 100644 --- a/src/udev/udevadm-util.h +++ b/src/udev/udevadm-util.h @@ -6,3 +6,4 @@ int find_device(const char *id, const char *prefix, sd_device **ret); int find_device_with_action(const char *id, sd_device_action_t action, sd_device **ret); int parse_device_action(const char *str, sd_device_action_t *action); +int udev_ping(usec_t timeout, bool ignore_connection_failure); From 2bc733d9b0e9c0b850ed523f5d1695cddb0c23d7 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 22 Dec 2024 07:07:50 +0900 Subject: [PATCH 5/5] units: introduce systemd-udevd-varlink.socket Co-authored-by: David Tardon --- man/rules/meson.build | 3 ++- man/systemd-udevd.service.xml | 2 ++ man/udevadm.xml | 2 +- units/initrd-udevadm-cleanup-db.service | 4 ++-- units/meson.build | 4 ++++ units/systemd-udev-trigger.service | 2 +- units/systemd-udevd-varlink.socket | 22 ++++++++++++++++++++++ units/systemd-udevd.service.in | 2 +- 8 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 units/systemd-udevd-varlink.socket diff --git a/man/rules/meson.build b/man/rules/meson.build index d281842396..4fe9ca17b8 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -1143,7 +1143,8 @@ manpages = [ '8', ['systemd-udevd', 'systemd-udevd-control.socket', - 'systemd-udevd-kernel.socket'], + 'systemd-udevd-kernel.socket', + 'systemd-udevd-varlink.socket'], ''], ['systemd-update-done.service', '8', ['systemd-update-done'], ''], ['systemd-update-utmp.service', diff --git a/man/systemd-udevd.service.xml b/man/systemd-udevd.service.xml index c781765e1c..ad0be5bdab 100644 --- a/man/systemd-udevd.service.xml +++ b/man/systemd-udevd.service.xml @@ -20,6 +20,7 @@ systemd-udevd.service systemd-udevd-control.socket systemd-udevd-kernel.socket + systemd-udevd-varlink.socket systemd-udevd Device event managing daemon @@ -28,6 +29,7 @@ systemd-udevd.service systemd-udevd-control.socket systemd-udevd-kernel.socket + systemd-udevd-varlink.socket /usr/lib/systemd/systemd-udevd diff --git a/man/udevadm.xml b/man/udevadm.xml index 8923bc70fe..13cf106d87 100644 --- a/man/udevadm.xml +++ b/man/udevadm.xml @@ -677,7 +677,7 @@ Note that systemd-udevd.service contains and so as a result, this option restarts systemd-udevd. If you want to stop systemd-udevd.service, please use the following: - systemctl stop systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udevd.service + systemctl stop systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udevd-varlink.socket systemd-udevd.service diff --git a/units/initrd-udevadm-cleanup-db.service b/units/initrd-udevadm-cleanup-db.service index bc444736fd..6c0a1e16ae 100644 --- a/units/initrd-udevadm-cleanup-db.service +++ b/units/initrd-udevadm-cleanup-db.service @@ -11,8 +11,8 @@ Description=Cleanup udev Database DefaultDependencies=no AssertPathExists=/etc/initrd-release -Conflicts=systemd-udevd.service systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udev-trigger.service systemd-udev-settle.service -After=systemd-udevd.service systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udev-trigger.service systemd-udev-settle.service +Conflicts=systemd-udevd.service systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udevd-varlink.socket systemd-udev-trigger.service systemd-udev-settle.service +After=systemd-udevd.service systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udevd-varlink.socket systemd-udev-trigger.service systemd-udev-settle.service Before=initrd-switch-root.target [Service] diff --git a/units/meson.build b/units/meson.build index f6d661da97..805991dfe4 100644 --- a/units/meson.build +++ b/units/meson.build @@ -732,6 +732,10 @@ units = [ 'file' : 'systemd-udevd-kernel.socket', 'symlinks' : ['sockets.target.wants/'], }, + { + 'file' : 'systemd-udevd-varlink.socket', + 'symlinks' : ['sockets.target.wants/'], + }, { 'file' : 'systemd-udevd.service.in', 'symlinks' : ['sysinit.target.wants/'], diff --git a/units/systemd-udev-trigger.service b/units/systemd-udev-trigger.service index cb1e4f9fea..0ea1a4bd49 100644 --- a/units/systemd-udev-trigger.service +++ b/units/systemd-udev-trigger.service @@ -12,7 +12,7 @@ Description=Coldplug All udev Devices Documentation=man:udev(7) man:systemd-udevd.service(8) DefaultDependencies=no Wants=systemd-udevd.service -After=systemd-udevd-kernel.socket systemd-udevd-control.socket +After=systemd-udevd-kernel.socket systemd-udevd-control.socket systemd-udevd-varlink.socket Before=sysinit.target ConditionPathIsReadWrite=/sys diff --git a/units/systemd-udevd-varlink.socket b/units/systemd-udevd-varlink.socket new file mode 100644 index 0000000000..94fee15b08 --- /dev/null +++ b/units/systemd-udevd-varlink.socket @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=udev Varlink Socket +Documentation=man:systemd-udevd-varlink.socket(8) man:udev(7) +DefaultDependencies=no +Before=sockets.target +ConditionPathIsReadWrite=/sys + +[Socket] +Service=systemd-udevd.service +ListenStream=/run/udev/io.systemd.Udev +FileDescriptorName=varlink +SocketMode=0600 +RemoveOnStop=yes diff --git a/units/systemd-udevd.service.in b/units/systemd-udevd.service.in index f4a4482088..13ec7088da 100644 --- a/units/systemd-udevd.service.in +++ b/units/systemd-udevd.service.in @@ -23,7 +23,7 @@ DelegateSubgroup=udev Type=notify-reload # Note that udev will reset the value internally for its workers OOMScoreAdjust=-1000 -Sockets=systemd-udevd-control.socket systemd-udevd-kernel.socket +Sockets=systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udevd-varlink.socket Restart=always RestartSec=0 ExecStart={{LIBEXECDIR}}/systemd-udevd