From 78467aeb9578bee56211a64190b3293616647aee Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 26 Jan 2019 00:33:08 +0900 Subject: [PATCH] udev-ctrl: split out logic of waiting for reply to udev_ctrl_wait() This makes `udevadm control` can send multiple commands in one connection. --- src/udev/udev-ctrl.c | 98 +++++++++++++++++++++----------------- src/udev/udev-ctrl.h | 44 +++++++++++++---- src/udev/udevadm-control.c | 54 ++++++++++++++------- src/udev/udevadm-settle.c | 6 ++- src/udev/udevadm-trigger.c | 6 ++- 5 files changed, 137 insertions(+), 71 deletions(-) diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index 7b0a556d70..59ce5c1f80 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -47,6 +47,7 @@ struct udev_ctrl { bool bound:1; bool cleanup_socket:1; bool connected:1; + bool maybe_disconnected:1; sd_event *event; sd_event_source *event_source; sd_event_source *event_source_connect; @@ -239,9 +240,14 @@ static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32 return 0; } + if (msg_wire.type == _UDEV_CTRL_END_MESSAGES) + return 0; + if (uctrl->callback) (void) uctrl->callback(uctrl, msg_wire.type, &msg_wire.value, uctrl->userdata); + /* Do not disconnect and wait for next message. */ + uctrl = udev_ctrl_unref(uctrl); return 0; } @@ -319,13 +325,16 @@ int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void return 0; } -static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, usec_t timeout) { +int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf) { struct udev_ctrl_msg_wire ctrl_msg_wire = { .version = "udev-" STRINGIFY(PROJECT_VERSION), .magic = UDEV_CTRL_MAGIC, .type = type, }; + if (uctrl->maybe_disconnected) + return -ENOANO; /* to distinguish this from other errors. */ + if (buf) strscpy(ctrl_msg_wire.value.buf, sizeof(ctrl_msg_wire.value.buf), buf); else @@ -336,59 +345,62 @@ static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int return -errno; uctrl->connected = true; } + if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0) return -errno; - /* wait for peer message handling or disconnect */ - for (;;) { - struct pollfd pfd = { - .fd = uctrl->sock, - .events = POLLIN, - }; - int r; - - r = poll(&pfd, 1, DIV_ROUND_UP(timeout, USEC_PER_MSEC)); - if (r < 0) { - if (errno == EINTR) - continue; - return -errno; - } - if (r == 0) - return -ETIMEDOUT; - if (pfd.revents & POLLERR) - return -EIO; - return 0; - } -} + if (type == UDEV_CTRL_EXIT) + uctrl->maybe_disconnected = true; -int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, usec_t timeout) { - return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL, timeout); + return 0; } -int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, usec_t timeout) { - return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL, timeout); +static int udev_ctrl_wait_io_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + return sd_event_exit(sd_event_source_get_event(s), 0); } -int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, usec_t timeout) { - return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL, timeout); -} +int udev_ctrl_wait(struct udev_ctrl *uctrl, usec_t timeout) { + _cleanup_(sd_event_source_unrefp) sd_event_source *source_io = NULL, *source_timeout = NULL; + int r; -int udev_ctrl_send_reload(struct udev_ctrl *uctrl, usec_t timeout) { - return ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL, timeout); -} + assert(uctrl); -int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, usec_t timeout) { - return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key, timeout); -} + if (uctrl->sock < 0) + return 0; + if (!uctrl->connected) + return 0; -int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, usec_t timeout) { - return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL, timeout); -} + if (!uctrl->maybe_disconnected) { + r = udev_ctrl_send(uctrl, _UDEV_CTRL_END_MESSAGES, 0, NULL); + if (r < 0) + return r; + } -int udev_ctrl_send_ping(struct udev_ctrl *uctrl, usec_t timeout) { - return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout); -} + if (timeout == 0) + return 0; + + if (!uctrl->event) { + r = udev_ctrl_attach_event(uctrl, NULL); + if (r < 0) + return r; + } + + r = sd_event_add_io(uctrl->event, &source_io, uctrl->sock, EPOLLIN, udev_ctrl_wait_io_handler, NULL); + if (r < 0) + return r; + + (void) sd_event_source_set_description(uctrl->event_source, "udev-ctrl-wait-io"); + + if (timeout != USEC_INFINITY) { + usec_t usec; + + usec = now(clock_boottime_or_monotonic()) + timeout; + r = sd_event_add_time(uctrl->event, &source_timeout, clock_boottime_or_monotonic(), usec, 0, NULL, INT_TO_PTR(-ETIMEDOUT)); + if (r < 0) + return r; + + (void) sd_event_source_set_description(source_timeout, "udev-ctrl-wait-io"); + } -int udev_ctrl_send_exit(struct udev_ctrl *uctrl, usec_t timeout) { - return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout); + return sd_event_loop(uctrl->event); } diff --git a/src/udev/udev-ctrl.h b/src/udev/udev-ctrl.h index 4e8c00bdad..2c84a8b16d 100644 --- a/src/udev/udev-ctrl.h +++ b/src/udev/udev-ctrl.h @@ -9,7 +9,7 @@ struct udev_ctrl; enum udev_ctrl_msg_type { - UDEV_CTRL_UNKNOWN, + _UDEV_CTRL_END_MESSAGES, UDEV_CTRL_SET_LOG_LEVEL, UDEV_CTRL_STOP_EXEC_QUEUE, UDEV_CTRL_START_EXEC_QUEUE, @@ -41,13 +41,39 @@ int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event); int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void *userdata); sd_event_source *udev_ctrl_get_event_source(struct udev_ctrl *uctrl); -int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, usec_t timeout); -int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, usec_t timeout); -int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, usec_t timeout); -int udev_ctrl_send_reload(struct udev_ctrl *uctrl, usec_t timeout); -int udev_ctrl_send_ping(struct udev_ctrl *uctrl, usec_t timeout); -int udev_ctrl_send_exit(struct udev_ctrl *uctrl, usec_t timeout); -int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, usec_t timeout); -int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, usec_t timeout); +int udev_ctrl_wait(struct udev_ctrl *uctrl, usec_t timeout); + +int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf); +static inline int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority) { + return udev_ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL); +} + +static inline int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl) { + return udev_ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL); +} + +static inline int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl) { + return udev_ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL); +} + +static inline int udev_ctrl_send_reload(struct udev_ctrl *uctrl) { + return udev_ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL); +} + +static inline int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key) { + return udev_ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key); +} + +static inline int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count) { + return udev_ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL); +} + +static inline int udev_ctrl_send_ping(struct udev_ctrl *uctrl) { + return udev_ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL); +} + +static inline int udev_ctrl_send_exit(struct udev_ctrl *uctrl) { + return udev_ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL); +} DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref); diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c index 01f6794297..f9b3e95794 100644 --- a/src/udev/udevadm-control.c +++ b/src/udev/udevadm-control.c @@ -93,8 +93,10 @@ int control_main(int argc, char *argv[], void *userdata) { while ((c = getopt_long(argc, argv, "el:sSRp:m:t:Vh", options, NULL)) >= 0) switch (c) { case 'e': - r = udev_ctrl_send_exit(uctrl, timeout); - if (r < 0) + r = udev_ctrl_send_exit(uctrl); + if (r == -ENOANO) + log_warning("Cannot specify --exit after --exit, ignoring."); + else if (r < 0) return log_error_errno(r, "Failed to send exit request: %m"); break; case 'l': @@ -102,31 +104,41 @@ int control_main(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to parse log priority '%s': %m", optarg); - r = udev_ctrl_send_set_log_level(uctrl, r, timeout); - if (r < 0) + r = udev_ctrl_send_set_log_level(uctrl, r); + if (r == -ENOANO) + log_warning("Cannot specify --log-priority after --exit, ignoring."); + else if (r < 0) return log_error_errno(r, "Failed to send request to set log level: %m"); break; case 's': - r = udev_ctrl_send_stop_exec_queue(uctrl, timeout); - if (r < 0) + r = udev_ctrl_send_stop_exec_queue(uctrl); + if (r == -ENOANO) + log_warning("Cannot specify --stop-exec-queue after --exit, ignoring."); + else if (r < 0) return log_error_errno(r, "Failed to send request to stop exec queue: %m"); break; case 'S': - r = udev_ctrl_send_start_exec_queue(uctrl, timeout); - if (r < 0) + r = udev_ctrl_send_start_exec_queue(uctrl); + if (r == -ENOANO) + log_warning("Cannot specify --start-exec-queue after --exit, ignoring."); + else if (r < 0) return log_error_errno(r, "Failed to send request to start exec queue: %m"); break; case 'R': - r = udev_ctrl_send_reload(uctrl, timeout); - if (r < 0) + r = udev_ctrl_send_reload(uctrl); + if (r == -ENOANO) + log_warning("Cannot specify --reload after --exit, ignoring."); + else if (r < 0) return log_error_errno(r, "Failed to send reload request: %m"); break; case 'p': if (!strchr(optarg, '=')) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "expect = instead of '%s'", optarg); - r = udev_ctrl_send_set_env(uctrl, optarg, timeout); - if (r < 0) + r = udev_ctrl_send_set_env(uctrl, optarg); + if (r == -ENOANO) + log_warning("Cannot specify --property after --exit, ignoring."); + else if (r < 0) return log_error_errno(r, "Failed to send request to update environment: %m"); break; case 'm': { @@ -136,15 +148,19 @@ int control_main(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to parse maximum number of events '%s': %m", optarg); - r = udev_ctrl_send_set_children_max(uctrl, i, timeout); - if (r < 0) + r = udev_ctrl_send_set_children_max(uctrl, i); + if (r == -ENOANO) + log_warning("Cannot specify --children-max after --exit, ignoring."); + else if (r < 0) return log_error_errno(r, "Failed to send request to set number of children: %m"); break; } case ARG_PING: - r = udev_ctrl_send_ping(uctrl, timeout); - if (r < 0) - return log_error_errno(r, "Failed to connect to udev daemon: %m"); + r = udev_ctrl_send_ping(uctrl); + if (r == -ENOANO) + log_error("Cannot specify --ping after --exit, ignoring."); + else if (r < 0) + return log_error_errno(r, "Failed to send a ping message: %m"); break; case 't': r = parse_sec(optarg, &timeout); @@ -165,5 +181,9 @@ int control_main(int argc, char *argv[], void *userdata) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Extraneous argument: %s", argv[optind]); + r = udev_ctrl_wait(uctrl, timeout); + if (r < 0) + return log_error_errno(r, "Failed to wait for daemon to reply: %m"); + return 0; } diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c index b4ea5a36a5..9cf88b245c 100644 --- a/src/udev/udevadm-settle.c +++ b/src/udev/udevadm-settle.c @@ -101,11 +101,15 @@ int settle_main(int argc, char *argv[], void *userdata) { _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL; if (udev_ctrl_new(&uctrl) >= 0) { - r = udev_ctrl_send_ping(uctrl, MAX(5 * USEC_PER_SEC, arg_timeout)); + r = udev_ctrl_send_ping(uctrl); if (r < 0) { log_debug_errno(r, "Failed to connect to udev daemon: %m"); return 0; } + + r = udev_ctrl_wait(uctrl, MAX(5 * USEC_PER_SEC, arg_timeout)); + if (r < 0) + return log_error_errno(r, "Failed to wait for daemon to reply: %m"); } } diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index 14c70e4009..63ceaaf957 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -312,9 +312,13 @@ int trigger_main(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to initialize udev control: %m"); - r = udev_ctrl_send_ping(uctrl, ping_timeout_usec); + 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"); } for (; optind < argc; optind++) { -- 2.25.1