From 100bc5bf98ed051e94667c9581f7098856527ee9 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 24 Jan 2019 15:00:06 +0900 Subject: [PATCH 1/7] udev-ctrl: make udev_ctrl_new() return negative errno on failure --- src/udev/udev-ctrl.c | 36 ++++++++++++++++++------------------ src/udev/udev-ctrl.h | 8 ++++++-- src/udev/udevadm-control.c | 6 +++--- src/udev/udevadm-settle.c | 3 +-- src/udev/udevadm-trigger.c | 6 +++--- src/udev/udevd.c | 6 +++--- 6 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index c217815ac6..0ed59c0c70 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -73,27 +73,29 @@ struct udev_ctrl_connection { int sock; }; -struct udev_ctrl *udev_ctrl_new_from_fd(int fd) { +int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) { + _cleanup_close_ int sock = -1; struct udev_ctrl *uctrl; int r; - uctrl = new0(struct udev_ctrl, 1); - if (!uctrl) - return NULL; - uctrl->n_ref = 1; + assert(ret); if (fd < 0) { - uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0); - if (uctrl->sock < 0) { - log_error_errno(errno, "Failed to create socket: %m"); - udev_ctrl_unref(uctrl); - return NULL; - } - } else { - uctrl->bound = true; - uctrl->sock = fd; + sock = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0); + if (sock < 0) + return log_error_errno(errno, "Failed to create socket: %m"); } + uctrl = new(struct udev_ctrl, 1); + if (!uctrl) + return -ENOMEM; + + *uctrl = (struct udev_ctrl) { + .n_ref = 1, + .sock = fd >= 0 ? fd : TAKE_FD(sock), + .bound = fd >= 0, + }; + /* * FIXME: remove it as soon as we can depend on this: * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=90c6bd34f884cd9cee21f1d152baf6c18bcac949 @@ -108,11 +110,9 @@ struct udev_ctrl *udev_ctrl_new_from_fd(int fd) { }; uctrl->addrlen = SOCKADDR_UN_LEN(uctrl->saddr.un); - return uctrl; -} -struct udev_ctrl *udev_ctrl_new(void) { - return udev_ctrl_new_from_fd(-1); + *ret = TAKE_PTR(uctrl); + return 0; } int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) { diff --git a/src/udev/udev-ctrl.h b/src/udev/udev-ctrl.h index 8e452a4249..7ea0de41d4 100644 --- a/src/udev/udev-ctrl.h +++ b/src/udev/udev-ctrl.h @@ -5,8 +5,12 @@ #include "time-util.h" struct udev_ctrl; -struct udev_ctrl *udev_ctrl_new(void); -struct udev_ctrl *udev_ctrl_new_from_fd(int fd); + +int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd); +static inline int udev_ctrl_new(struct udev_ctrl **ret) { + return udev_ctrl_new_from_fd(ret, -1); +} + int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl); struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl); int udev_ctrl_cleanup(struct udev_ctrl *uctrl); diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c index 7cfc4c929d..b2fe69a1fd 100644 --- a/src/udev/udevadm-control.c +++ b/src/udev/udevadm-control.c @@ -86,9 +86,9 @@ int control_main(int argc, char *argv[], void *userdata) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This command expects one or more options."); - uctrl = udev_ctrl_new(); - if (!uctrl) - return log_oom(); + r = udev_ctrl_new(&uctrl); + if (r < 0) + return log_error_errno(r, "Failed to initialize udev control: %m"); while ((c = getopt_long(argc, argv, "el:sSRp:m:t:Vh", options, NULL)) >= 0) switch (c) { diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c index 8d9c4509ff..b4ea5a36a5 100644 --- a/src/udev/udevadm-settle.c +++ b/src/udev/udevadm-settle.c @@ -100,8 +100,7 @@ int settle_main(int argc, char *argv[], void *userdata) { if (getuid() == 0) { _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL; - uctrl = udev_ctrl_new(); - if (uctrl) { + if (udev_ctrl_new(&uctrl) >= 0) { r = udev_ctrl_send_ping(uctrl, MAX(5 * USEC_PER_SEC, arg_timeout)); if (r < 0) { log_debug_errno(r, "Failed to connect to udev daemon: %m"); diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index 2a658158e6..14c70e4009 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -308,9 +308,9 @@ int trigger_main(int argc, char *argv[], void *userdata) { if (ping) { _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL; - uctrl = udev_ctrl_new(); - if (!uctrl) - return log_oom(); + 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, ping_timeout_usec); if (r < 0) diff --git a/src/udev/udevd.c b/src/udev/udevd.c index a5c24a70f4..dd100dd92a 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -1596,9 +1596,9 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg .cgroup = cgroup, }; - manager->ctrl = udev_ctrl_new_from_fd(fd_ctrl); - if (!manager->ctrl) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to initialize udev control socket"); + r = udev_ctrl_new_from_fd(&manager->ctrl, fd_ctrl); + if (r < 0) + return log_error_errno(r, "Failed to initialize udev control socket: %m"); r = udev_ctrl_enable_receiving(manager->ctrl); if (r < 0) From 53bba2fb1da3ca26b1cf96c461598d53df2040cc Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 24 Jan 2019 15:09:40 +0900 Subject: [PATCH 2/7] udev-ctrl: refactor udev_ctrl_enable_receiving() --- src/udev/udev-ctrl.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index 0ed59c0c70..7d8ff6d1ce 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -116,25 +116,28 @@ int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) { } int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) { - int err; + int r; - if (!uctrl->bound) { - err = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen); - if (err < 0 && errno == EADDRINUSE) { - (void) sockaddr_un_unlink(&uctrl->saddr.un); - err = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen); - } + assert(uctrl); - if (err < 0) - return log_error_errno(errno, "Failed to bind socket: %m"); + if (uctrl->bound) + return 0; - err = listen(uctrl->sock, 0); - if (err < 0) - return log_error_errno(errno, "Failed to listen: %m"); - - uctrl->bound = true; - uctrl->cleanup_socket = true; + r = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen); + if (r < 0 && errno == EADDRINUSE) { + (void) sockaddr_un_unlink(&uctrl->saddr.un); + r = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen); } + + if (r < 0) + return log_error_errno(errno, "Failed to bind udev control socket: %m"); + + if (listen(uctrl->sock, 0) < 0) + return log_error_errno(errno, "Failed to listen udev control socket: %m"); + + uctrl->bound = true; + uctrl->cleanup_socket = true; + return 0; } From 204e9c3e29c08386f8dfd58c0133e3cc73774365 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 26 Jan 2019 00:13:16 +0900 Subject: [PATCH 3/7] udev: drop unused Manager::uevent_event --- src/udev/udevd.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/udev/udevd.c b/src/udev/udevd.c index dd100dd92a..d1a0b9bd94 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -94,7 +94,6 @@ typedef struct Manager { int worker_watch[2]; sd_event_source *ctrl_event; - sd_event_source *uevent_event; sd_event_source *inotify_event; sd_event_source *kill_workers_event; @@ -279,7 +278,6 @@ static void manager_clear_for_worker(Manager *manager) { assert(manager); manager->ctrl_event = sd_event_source_unref(manager->ctrl_event); - manager->uevent_event = sd_event_source_unref(manager->uevent_event); manager->inotify_event = sd_event_source_unref(manager->inotify_event); manager->kill_workers_event = sd_event_source_unref(manager->kill_workers_event); @@ -805,7 +803,6 @@ static void manager_exit(Manager *manager) { manager->inotify_event = sd_event_source_unref(manager->inotify_event); manager->fd_inotify = safe_close(manager->fd_inotify); - manager->uevent_event = sd_event_source_unref(manager->uevent_event); manager->monitor = sd_device_monitor_unref(manager->monitor); /* discard queued events and kill workers */ From d02c6f546167d5f076a8940470db3a75ff12e814 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 26 Jan 2019 00:27:26 +0900 Subject: [PATCH 4/7] udev-ctrl: use sd_event and introduce udev_ctrl_start() Now the new callback function get enum udev_ctrl_msg_type. So, this commit also drops udev_ctrl_connection and udev_ctrl_msg. --- src/udev/udev-ctrl.c | 384 ++++++++++++++++++++----------------------- src/udev/udev-ctrl.h | 47 +++--- src/udev/udevd.c | 103 +++++------- 3 files changed, 244 insertions(+), 290 deletions(-) diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index 7d8ff6d1ce..7b0a556d70 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -17,6 +17,8 @@ #include #include +#include "sd-event.h" + #include "alloc-util.h" #include "fd-util.h" #include "format-util.h" @@ -29,48 +31,27 @@ /* wire protocol magic must match */ #define UDEV_CTRL_MAGIC 0xdead1dea -enum udev_ctrl_msg_type { - UDEV_CTRL_UNKNOWN, - UDEV_CTRL_SET_LOG_LEVEL, - UDEV_CTRL_STOP_EXEC_QUEUE, - UDEV_CTRL_START_EXEC_QUEUE, - UDEV_CTRL_RELOAD, - UDEV_CTRL_SET_ENV, - UDEV_CTRL_SET_CHILDREN_MAX, - UDEV_CTRL_PING, - UDEV_CTRL_EXIT, -}; - struct udev_ctrl_msg_wire { char version[16]; unsigned magic; enum udev_ctrl_msg_type type; - union { - int intval; - char buf[256]; - }; -}; - -struct udev_ctrl_msg { - unsigned n_ref; - struct udev_ctrl_connection *conn; - struct udev_ctrl_msg_wire ctrl_msg_wire; + union udev_ctrl_msg_value value; }; struct udev_ctrl { unsigned n_ref; int sock; + int sock_connect; union sockaddr_union saddr; socklen_t addrlen; - bool bound; - bool cleanup_socket; - bool connected; -}; - -struct udev_ctrl_connection { - unsigned n_ref; - struct udev_ctrl *uctrl; - int sock; + bool bound:1; + bool cleanup_socket:1; + bool connected:1; + sd_event *event; + sd_event_source *event_source; + sd_event_source *event_source_connect; + udev_ctrl_handler_t callback; + void *userdata; }; int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) { @@ -141,15 +122,27 @@ int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) { return 0; } +static void udev_ctrl_disconnect(struct udev_ctrl *uctrl) { + if (!uctrl) + return; + + uctrl->event_source_connect = sd_event_source_unref(uctrl->event_source_connect); + uctrl->sock_connect = safe_close(uctrl->sock_connect); +} + static struct udev_ctrl *udev_ctrl_free(struct udev_ctrl *uctrl) { assert(uctrl); + udev_ctrl_disconnect(uctrl); + + sd_event_source_unref(uctrl->event_source); safe_close(uctrl->sock); + + sd_event_unref(uctrl->event); return mfree(uctrl); } -DEFINE_PRIVATE_TRIVIAL_REF_FUNC(struct udev_ctrl, udev_ctrl); -DEFINE_TRIVIAL_UNREF_FUNC(struct udev_ctrl, udev_ctrl, udev_ctrl_free); +DEFINE_TRIVIAL_REF_UNREF_FUNC(struct udev_ctrl, udev_ctrl, udev_ctrl_free); int udev_ctrl_cleanup(struct udev_ctrl *uctrl) { if (!uctrl) @@ -159,63 +152,173 @@ int udev_ctrl_cleanup(struct udev_ctrl *uctrl) { return 0; } -int udev_ctrl_get_fd(struct udev_ctrl *uctrl) { - if (!uctrl) - return -EINVAL; - return uctrl->sock; -} - -struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl) { - struct udev_ctrl_connection *conn; - struct ucred ucred = {}; +int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event) { int r; - conn = new(struct udev_ctrl_connection, 1); - if (!conn) - return NULL; - conn->n_ref = 1; - conn->uctrl = uctrl; + assert_return(uctrl, -EINVAL); + assert_return(!uctrl->event, -EBUSY); - conn->sock = accept4(uctrl->sock, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK); - if (conn->sock < 0) { + if (event) + uctrl->event = sd_event_ref(event); + else { + r = sd_event_default(&uctrl->event); + if (r < 0) + return r; + } + + return 0; +} + +sd_event_source *udev_ctrl_get_event_source(struct udev_ctrl *uctrl) { + assert(uctrl); + + return uctrl->event_source; +} + +static void udev_ctrl_disconnect_and_listen_again(struct udev_ctrl *uctrl) { + udev_ctrl_disconnect(uctrl); + udev_ctrl_unref(uctrl); + (void) sd_event_source_set_enabled(uctrl->event_source, SD_EVENT_ON); +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl *, udev_ctrl_disconnect_and_listen_again); + +static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_(udev_ctrl_disconnect_and_listen_againp) struct udev_ctrl *uctrl = NULL; + struct udev_ctrl_msg_wire msg_wire; + struct iovec iov = IOVEC_MAKE(&msg_wire, sizeof(struct udev_ctrl_msg_wire)); + char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; + struct msghdr smsg = { + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = cred_msg, + .msg_controllen = sizeof(cred_msg), + }; + struct cmsghdr *cmsg; + struct ucred *cred; + ssize_t size; + + assert(userdata); + + /* When UDEV_CTRL_EXIT is received, manager unref udev_ctrl object. + * To avoid the object freed, let's increment the refcount. */ + uctrl = udev_ctrl_ref(userdata); + + size = next_datagram_size_fd(fd); + if (size < 0) + return log_error_errno(size, "Failed to get size of message: %m"); + if (size == 0) + return 0; /* Client disconnects? */ + + size = recvmsg(fd, &smsg, 0); + if (size < 0) { if (errno != EINTR) - log_error_errno(errno, "Failed to receive ctrl connection: %m"); - goto err; + return log_error_errno(errno, "Failed to receive ctrl message: %m"); + + return 0; + } + + cmsg_close_all(&smsg); + + cmsg = CMSG_FIRSTHDR(&smsg); + + if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) { + log_error("No sender credentials received, ignoring message"); + return 0; + } + + cred = (struct ucred *) CMSG_DATA(cmsg); + + if (cred->uid != 0) { + log_error("Invalid sender uid "UID_FMT", ignoring message", cred->uid); + return 0; + } + + if (msg_wire.magic != UDEV_CTRL_MAGIC) { + log_error("Message magic 0x%08x doesn't match, ignoring message", msg_wire.magic); + return 0; + } + + if (uctrl->callback) + (void) uctrl->callback(uctrl, msg_wire.type, &msg_wire.value, uctrl->userdata); + + return 0; +} + +static int udev_ctrl_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + struct udev_ctrl *uctrl = userdata; + _cleanup_close_ int sock = -1; + struct ucred ucred; + int r; + + assert(uctrl); + + sock = accept4(fd, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK); + if (sock < 0) { + if (errno != EINTR) + log_error_errno(errno, "Failed to accept ctrl connection: %m"); + return 0; } /* check peer credential of connection */ - r = getpeercred(conn->sock, &ucred); + r = getpeercred(sock, &ucred); if (r < 0) { log_error_errno(r, "Failed to receive credentials of ctrl connection: %m"); - goto err; + return 0; } + if (ucred.uid > 0) { - log_error("Sender uid="UID_FMT", message ignored", ucred.uid); - goto err; + log_error("Invalid sender uid "UID_FMT", closing connection", ucred.uid); + return 0; } /* enable receiving of the sender credentials in the messages */ - r = setsockopt_int(conn->sock, SOL_SOCKET, SO_PASSCRED, true); + r = setsockopt_int(sock, SOL_SOCKET, SO_PASSCRED, true); if (r < 0) - log_warning_errno(r, "Failed to set SO_PASSCRED: %m"); + log_warning_errno(r, "Failed to set SO_PASSCRED, ignoring: %m"); - udev_ctrl_ref(uctrl); - return conn; -err: - safe_close(conn->sock); - return mfree(conn); + r = sd_event_add_io(uctrl->event, &uctrl->event_source_connect, sock, EPOLLIN, udev_ctrl_connection_event_handler, uctrl); + if (r < 0) { + log_error_errno(r, "Failed to create event source for udev control connection: %m"); + return 0; + } + + (void) sd_event_source_set_description(uctrl->event_source_connect, "udev-ctrl-connection"); + + /* Do not accept multiple connection. */ + (void) sd_event_source_set_enabled(uctrl->event_source, SD_EVENT_OFF); + + uctrl->sock_connect = TAKE_FD(sock); + return 0; } -static struct udev_ctrl_connection *udev_ctrl_connection_free(struct udev_ctrl_connection *conn) { - assert(conn); +int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void *userdata) { + int r; - safe_close(conn->sock); - udev_ctrl_unref(conn->uctrl); - return mfree(conn); + assert(uctrl); + + if (!uctrl->event) { + r = udev_ctrl_attach_event(uctrl, NULL); + if (r < 0) + return r; + } + + r = udev_ctrl_enable_receiving(uctrl); + if (r < 0) + return r; + + uctrl->callback = callback; + uctrl->userdata = userdata; + + r = sd_event_add_io(uctrl->event, &uctrl->event_source, uctrl->sock, EPOLLIN, udev_ctrl_event_handler, uctrl); + if (r < 0) + return r; + + (void) sd_event_source_set_description(uctrl->event_source, "udev-ctrl"); + + return 0; } -DEFINE_TRIVIAL_REF_UNREF_FUNC(struct udev_ctrl_connection, udev_ctrl_connection, udev_ctrl_connection_free); - static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, usec_t timeout) { struct udev_ctrl_msg_wire ctrl_msg_wire = { .version = "udev-" STRINGIFY(PROJECT_VERSION), @@ -224,9 +327,9 @@ static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int }; if (buf) - strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf); + strscpy(ctrl_msg_wire.value.buf, sizeof(ctrl_msg_wire.value.buf), buf); else - ctrl_msg_wire.intval = intval; + ctrl_msg_wire.value.intval = intval; if (!uctrl->connected) { if (connect(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen) < 0) @@ -289,142 +392,3 @@ int udev_ctrl_send_ping(struct udev_ctrl *uctrl, usec_t timeout) { int udev_ctrl_send_exit(struct udev_ctrl *uctrl, usec_t timeout) { return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout); } - -struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn) { - struct udev_ctrl_msg *uctrl_msg; - ssize_t size; - struct cmsghdr *cmsg; - struct iovec iov; - char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; - struct msghdr smsg = { - .msg_iov = &iov, - .msg_iovlen = 1, - .msg_control = cred_msg, - .msg_controllen = sizeof(cred_msg), - }; - struct ucred *cred; - - uctrl_msg = new0(struct udev_ctrl_msg, 1); - if (!uctrl_msg) - return NULL; - uctrl_msg->n_ref = 1; - uctrl_msg->conn = conn; - udev_ctrl_connection_ref(conn); - - /* wait for the incoming message */ - for (;;) { - struct pollfd pfd[1]; - int r; - - pfd[0].fd = conn->sock; - pfd[0].events = POLLIN; - - r = poll(pfd, 1, 10000); - if (r < 0) { - if (errno == EINTR) - continue; - goto err; - } else if (r == 0) { - log_error("Timeout waiting for ctrl message"); - goto err; - } else { - if (!(pfd[0].revents & POLLIN)) { - log_error("Invalid ctrl connection: %m"); - goto err; - } - } - - break; - } - - iov = IOVEC_MAKE(&uctrl_msg->ctrl_msg_wire, sizeof(struct udev_ctrl_msg_wire)); - - size = recvmsg(conn->sock, &smsg, 0); - if (size < 0) { - log_error_errno(errno, "Failed to receive ctrl message: %m"); - goto err; - } - - cmsg_close_all(&smsg); - - cmsg = CMSG_FIRSTHDR(&smsg); - - if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) { - log_error("No sender credentials received, ignoring message"); - goto err; - } - - cred = (struct ucred *) CMSG_DATA(cmsg); - - if (cred->uid != 0) { - log_error("Sender uid="UID_FMT", ignoring message", cred->uid); - goto err; - } - - if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) { - log_error("Message magic 0x%08x doesn't match, ignoring", uctrl_msg->ctrl_msg_wire.magic); - goto err; - } - - return uctrl_msg; -err: - udev_ctrl_msg_unref(uctrl_msg); - return NULL; -} - -static struct udev_ctrl_msg *udev_ctrl_msg_free(struct udev_ctrl_msg *ctrl_msg) { - assert(ctrl_msg); - - udev_ctrl_connection_unref(ctrl_msg->conn); - return mfree(ctrl_msg); -} - -DEFINE_TRIVIAL_UNREF_FUNC(struct udev_ctrl_msg, udev_ctrl_msg, udev_ctrl_msg_free); - -int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg) { - if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_LOG_LEVEL) - return ctrl_msg->ctrl_msg_wire.intval; - return -1; -} - -int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg) { - if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_STOP_EXEC_QUEUE) - return 1; - return -1; -} - -int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg) { - if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_START_EXEC_QUEUE) - return 1; - return -1; -} - -int udev_ctrl_get_reload(struct udev_ctrl_msg *ctrl_msg) { - if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_RELOAD) - return 1; - return -1; -} - -const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg) { - if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_ENV) - return ctrl_msg->ctrl_msg_wire.buf; - return NULL; -} - -int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg) { - if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_CHILDREN_MAX) - return ctrl_msg->ctrl_msg_wire.intval; - return -1; -} - -int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg) { - if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_PING) - return 1; - return -1; -} - -int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg) { - if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_EXIT) - return 1; - return -1; -} diff --git a/src/udev/udev-ctrl.h b/src/udev/udev-ctrl.h index 7ea0de41d4..4e8c00bdad 100644 --- a/src/udev/udev-ctrl.h +++ b/src/udev/udev-ctrl.h @@ -1,20 +1,46 @@ /* SPDX-License-Identifier: GPL-2.0+ */ #pragma once +#include "sd-event.h" + #include "macro.h" #include "time-util.h" struct udev_ctrl; +enum udev_ctrl_msg_type { + UDEV_CTRL_UNKNOWN, + UDEV_CTRL_SET_LOG_LEVEL, + UDEV_CTRL_STOP_EXEC_QUEUE, + UDEV_CTRL_START_EXEC_QUEUE, + UDEV_CTRL_RELOAD, + UDEV_CTRL_SET_ENV, + UDEV_CTRL_SET_CHILDREN_MAX, + UDEV_CTRL_PING, + UDEV_CTRL_EXIT, +}; + +union udev_ctrl_msg_value { + int intval; + char buf[256]; +}; + +typedef int (*udev_ctrl_handler_t)(struct udev_ctrl *udev_ctrl, enum udev_ctrl_msg_type type, + const union udev_ctrl_msg_value *value, void *userdata); + int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd); static inline int udev_ctrl_new(struct udev_ctrl **ret) { return udev_ctrl_new_from_fd(ret, -1); } int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl); +struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl); struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl); int udev_ctrl_cleanup(struct udev_ctrl *uctrl); -int udev_ctrl_get_fd(struct udev_ctrl *uctrl); +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); @@ -24,23 +50,4 @@ 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); -struct udev_ctrl_connection; -struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl); -struct udev_ctrl_connection *udev_ctrl_connection_ref(struct udev_ctrl_connection *conn); -struct udev_ctrl_connection *udev_ctrl_connection_unref(struct udev_ctrl_connection *conn); - -struct udev_ctrl_msg; -struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn); -struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg); -int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg); -int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg); -int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg); -int udev_ctrl_get_reload(struct udev_ctrl_msg *ctrl_msg); -int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg); -int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg); -const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg); -int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg); - DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl_connection*, udev_ctrl_connection_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl_msg*, udev_ctrl_msg_unref); diff --git a/src/udev/udevd.c b/src/udev/udevd.c index d1a0b9bd94..2e31994b58 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -89,11 +89,9 @@ typedef struct Manager { sd_device_monitor *monitor; struct udev_ctrl *ctrl; - struct udev_ctrl_connection *ctrl_conn_blocking; int fd_inotify; int worker_watch[2]; - sd_event_source *ctrl_event; sd_event_source *inotify_event; sd_event_source *kill_workers_event; @@ -277,7 +275,6 @@ static void worker_attach_event(struct worker *worker, struct event *event) { static void manager_clear_for_worker(Manager *manager) { assert(manager); - manager->ctrl_event = sd_event_source_unref(manager->ctrl_event); manager->inotify_event = sd_event_source_unref(manager->inotify_event); manager->kill_workers_event = sd_event_source_unref(manager->kill_workers_event); @@ -287,7 +284,6 @@ static void manager_clear_for_worker(Manager *manager) { event_queue_cleanup(manager, EVENT_UNDEF); manager->monitor = sd_device_monitor_unref(manager->monitor); - manager->ctrl_conn_blocking = udev_ctrl_connection_unref(manager->ctrl_conn_blocking); manager->ctrl = udev_ctrl_unref(manager->ctrl); manager->worker_watch[READ_END] = safe_close(manager->worker_watch[READ_END]); @@ -797,7 +793,6 @@ static void manager_exit(Manager *manager) { "STATUS=Starting shutdown..."); /* close sources of new events and discard buffered events */ - manager->ctrl_event = sd_event_source_unref(manager->ctrl_event); manager->ctrl = udev_ctrl_unref(manager->ctrl); manager->inotify_event = sd_event_source_unref(manager->inotify_event); @@ -997,59 +992,44 @@ static int on_uevent(sd_device_monitor *monitor, sd_device *dev, void *userdata) } /* receive the udevd message from userspace */ -static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userdata) { +static int on_ctrl_msg(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, const union udev_ctrl_msg_value *value, void *userdata) { Manager *manager = userdata; - _cleanup_(udev_ctrl_connection_unrefp) struct udev_ctrl_connection *ctrl_conn = NULL; - _cleanup_(udev_ctrl_msg_unrefp) struct udev_ctrl_msg *ctrl_msg = NULL; - const char *str; - int i, r; + int r; + assert(value); assert(manager); - ctrl_conn = udev_ctrl_get_connection(manager->ctrl); - if (!ctrl_conn) - return 1; - - ctrl_msg = udev_ctrl_receive_msg(ctrl_conn); - if (!ctrl_msg) - return 1; - - i = udev_ctrl_get_set_log_level(ctrl_msg); - if (i >= 0) { - log_debug("Received udev control message (SET_LOG_LEVEL), setting log_priority=%i", i); - log_set_max_level_realm(LOG_REALM_UDEV, i); - log_set_max_level_realm(LOG_REALM_SYSTEMD, i); + switch (type) { + case UDEV_CTRL_SET_LOG_LEVEL: + log_debug("Received udev control message (SET_LOG_LEVEL), setting log_priority=%i", value->intval); + log_set_max_level_realm(LOG_REALM_UDEV, value->intval); + log_set_max_level_realm(LOG_REALM_SYSTEMD, value->intval); manager_kill_workers(manager); - } - - if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) { + break; + case UDEV_CTRL_STOP_EXEC_QUEUE: log_debug("Received udev control message (STOP_EXEC_QUEUE)"); manager->stop_exec_queue = true; - } - - if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) { + break; + case UDEV_CTRL_START_EXEC_QUEUE: log_debug("Received udev control message (START_EXEC_QUEUE)"); manager->stop_exec_queue = false; event_queue_start(manager); - } - - if (udev_ctrl_get_reload(ctrl_msg) > 0) { + break; + case UDEV_CTRL_RELOAD: log_debug("Received udev control message (RELOAD)"); manager_reload(manager); - } - - str = udev_ctrl_get_set_env(ctrl_msg); - if (str) { + break; + case UDEV_CTRL_SET_ENV: { _cleanup_free_ char *key = NULL, *val = NULL, *old_key = NULL, *old_val = NULL; - char *eq; + const char *eq; - eq = strchr(str, '='); + eq = strchr(value->buf, '='); if (!eq) { - log_error("Invalid key format '%s'", str); + log_error("Invalid key format '%s'", value->buf); return 1; } - key = strndup(str, eq - str); + key = strndup(value->buf, eq - value->buf); if (!key) { log_oom(); return 1; @@ -1090,27 +1070,30 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd key = val = NULL; manager_kill_workers(manager); + break; } + case UDEV_CTRL_SET_CHILDREN_MAX: + if (value->intval <= 0) { + log_debug("Received invalid udev control message (SET_MAX_CHILDREN, %i), ignoring.", value->intval); + return 0; + } - i = udev_ctrl_get_set_children_max(ctrl_msg); - if (i >= 0) { - log_debug("Receivd udev control message (SET_MAX_CHILDREN), setting children_max=%i", i); - arg_children_max = i; + log_debug("Received udev control message (SET_MAX_CHILDREN), setting children_max=%i", value->intval); + arg_children_max = value->intval; (void) sd_notifyf(false, "READY=1\n" "STATUS=Processing with %u children at max", arg_children_max); - } - - if (udev_ctrl_get_ping(ctrl_msg) > 0) + break; + case UDEV_CTRL_PING: log_debug("Received udev control message (PING)"); - - if (udev_ctrl_get_exit(ctrl_msg) > 0) { + break; + case UDEV_CTRL_EXIT: log_debug("Received udev control message (EXIT)"); manager_exit(manager); - /* keep reference to block the client until we exit - TODO: deal with several blocking exit requests */ - manager->ctrl_conn_blocking = udev_ctrl_connection_ref(ctrl_conn); + break; + default: + log_debug("Received unknown udev control message, ignoring"); } return 1; @@ -1617,7 +1600,7 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg } static int main_loop(Manager *manager) { - int fd_worker, fd_ctrl, r; + int fd_worker, r; /* unnamed socket from workers to the main daemon */ r = socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, manager->worker_watch); @@ -1664,19 +1647,19 @@ static int main_loop(Manager *manager) { if (r < 0) return log_error_errno(r, "Failed to create watchdog event source: %m"); - fd_ctrl = udev_ctrl_get_fd(manager->ctrl); - if (fd_ctrl < 0) - return log_error_errno(fd_ctrl, "Failed to get udev control socket fd: %m"); - - r = sd_event_add_io(manager->event, &manager->ctrl_event, fd_ctrl, EPOLLIN, on_ctrl_msg, manager); + r = udev_ctrl_attach_event(manager->ctrl, manager->event); if (r < 0) - return log_error_errno(r, "Failed to create udev control event source: %m"); + return log_error_errno(r, "Failed to attach event to udev control: %m"); + + r = udev_ctrl_start(manager->ctrl, on_ctrl_msg, manager); + if (r < 0) + return log_error_errno(r, "Failed to start device monitor: %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_event_source_set_priority(manager->ctrl_event, SD_EVENT_PRIORITY_IDLE); + r = sd_event_source_set_priority(udev_ctrl_get_event_source(manager->ctrl), SD_EVENT_PRIORITY_IDLE); if (r < 0) return log_error_errno(r, "Failed to set IDLE event priority for udev control event source: %m"); From a0b60b8a1b16217d9167d03c1c0ee7e4a362514f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 18 Jan 2019 16:39:58 +0100 Subject: [PATCH 5/7] udevadm: print error if the commands fail We'd exit with an error but no output. Print the error in the usual fashion. --- src/udev/udevadm-control.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c index b2fe69a1fd..01f6794297 100644 --- a/src/udev/udevadm-control.c +++ b/src/udev/udevadm-control.c @@ -95,7 +95,7 @@ int control_main(int argc, char *argv[], void *userdata) { case 'e': r = udev_ctrl_send_exit(uctrl, timeout); if (r < 0) - return r; + return log_error_errno(r, "Failed to send exit request: %m"); break; case 'l': r = log_level_from_string(optarg); @@ -104,22 +104,22 @@ int control_main(int argc, char *argv[], void *userdata) { r = udev_ctrl_send_set_log_level(uctrl, r, timeout); if (r < 0) - return r; + 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) - return r; + 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) - return r; + 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) - return r; + return log_error_errno(r, "Failed to send reload request: %m"); break; case 'p': if (!strchr(optarg, '=')) @@ -127,7 +127,7 @@ int control_main(int argc, char *argv[], void *userdata) { r = udev_ctrl_send_set_env(uctrl, optarg, timeout); if (r < 0) - return r; + return log_error_errno(r, "Failed to send request to update environment: %m"); break; case 'm': { unsigned i; @@ -138,7 +138,7 @@ int control_main(int argc, char *argv[], void *userdata) { r = udev_ctrl_send_set_children_max(uctrl, i, timeout); if (r < 0) - return r; + return log_error_errno(r, "Failed to send request to set number of children: %m"); break; } case ARG_PING: From 78467aeb9578bee56211a64190b3293616647aee Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 26 Jan 2019 00:33:08 +0900 Subject: [PATCH 6/7] 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 | 96 +++++++++++++++++++++----------------- 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, 136 insertions(+), 70 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; + if (type == UDEV_CTRL_EXIT) + uctrl->maybe_disconnected = true; - 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; +} + +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_wait(struct udev_ctrl *uctrl, usec_t timeout) { + _cleanup_(sd_event_source_unrefp) sd_event_source *source_io = NULL, *source_timeout = NULL; + int r; + + assert(uctrl); + + if (uctrl->sock < 0) return 0; + if (!uctrl->connected) + return 0; + + if (!uctrl->maybe_disconnected) { + r = udev_ctrl_send(uctrl, _UDEV_CTRL_END_MESSAGES, 0, NULL); + if (r < 0) + return r; } -} -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); -} + if (timeout == 0) + 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); -} + if (!uctrl->event) { + r = udev_ctrl_attach_event(uctrl, NULL); + if (r < 0) + return r; + } -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); -} + r = sd_event_add_io(uctrl->event, &source_io, uctrl->sock, EPOLLIN, udev_ctrl_wait_io_handler, NULL); + if (r < 0) + return r; -int udev_ctrl_send_reload(struct udev_ctrl *uctrl, usec_t timeout) { - return ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL, timeout); -} + (void) sd_event_source_set_description(uctrl->event_source, "udev-ctrl-wait-io"); -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 (timeout != USEC_INFINITY) { + usec_t usec; -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); -} + 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; -int udev_ctrl_send_ping(struct udev_ctrl *uctrl, usec_t timeout) { - return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout); -} + (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++) { From 6371db935851cde55a21ddcfb47c48de261d008d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 26 Jan 2019 01:16:00 +0900 Subject: [PATCH 7/7] man: udevadm: mention that no control command can be specified after --exit --- man/udevadm.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/man/udevadm.xml b/man/udevadm.xml index 0107c57576..f25a1dfb48 100644 --- a/man/udevadm.xml +++ b/man/udevadm.xml @@ -372,8 +372,10 @@ - Signal and wait for systemd-udevd to exit. Note that systemd-udevd.service - contains and so as a result, this option restarts systemd-udevd. + Signal and wait for systemd-udevd to exit. No option except for + can be specified after this option. + 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