]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev-ctrl: use sd_event and introduce udev_ctrl_start()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 25 Jan 2019 15:27:26 +0000 (00:27 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 19 Feb 2019 21:17:42 +0000 (06:17 +0900)
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
src/udev/udev-ctrl.h
src/udev/udevd.c

index 7d8ff6d1ce1069de6743a4a9fe76ff7a49e6b7b7..7b0a556d70fed9e76efa7537a377828258078712 100644 (file)
@@ -17,6 +17,8 @@
 #include <sys/un.h>
 #include <unistd.h>
 
+#include "sd-event.h"
+
 #include "alloc-util.h"
 #include "fd-util.h"
 #include "format-util.h"
 /* 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,62 +152,172 @@ 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;
+int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event) {
+        int r;
+
+        assert_return(uctrl, -EINVAL);
+        assert_return(!uctrl->event, -EBUSY);
+
+        if (event)
+                uctrl->event = sd_event_ref(event);
+        else {
+                r = sd_event_default(&uctrl->event);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
 }
 
-struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl) {
-        struct udev_ctrl_connection *conn;
-        struct ucred ucred = {};
+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)
+                        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;
 
-        conn = new(struct udev_ctrl_connection, 1);
-        if (!conn)
-                return NULL;
-        conn->n_ref = 1;
-        conn->uctrl = uctrl;
+        assert(uctrl);
 
-        conn->sock = accept4(uctrl->sock, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
-        if (conn->sock < 0) {
+        sock = accept4(fd, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
+        if (sock < 0) {
                 if (errno != EINTR)
-                        log_error_errno(errno, "Failed to receive ctrl connection: %m");
-                goto err;
+                        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");
 
-static struct udev_ctrl_connection *udev_ctrl_connection_free(struct udev_ctrl_connection *conn) {
-        assert(conn);
+        /* Do not accept multiple connection. */
+        (void) sd_event_source_set_enabled(uctrl->event_source, SD_EVENT_OFF);
 
-        safe_close(conn->sock);
-        udev_ctrl_unref(conn->uctrl);
-        return mfree(conn);
+        uctrl->sock_connect = TAKE_FD(sock);
+        return 0;
 }
 
-DEFINE_TRIVIAL_REF_UNREF_FUNC(struct udev_ctrl_connection, udev_ctrl_connection, udev_ctrl_connection_free);
+int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void *userdata) {
+        int r;
+
+        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;
+}
 
 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 = {
@@ -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;
-}
index 7ea0de41d415dfc650a2311398ae62bf22eb3f3f..4e8c00bdad10958410410ca4504eb74e2beff523 100644 (file)
@@ -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);
index d1a0b9bd94733f3916cca5fc36f95c58d6e7ce7a..2e31994b587241d4ba119b8545e70618ce288773 100644 (file)
@@ -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 = udev_ctrl_attach_event(manager->ctrl, manager->event);
+        if (r < 0)
+                return log_error_errno(r, "Failed to attach event to udev control: %m");
 
-        r = sd_event_add_io(manager->event, &manager->ctrl_event, fd_ctrl, EPOLLIN, on_ctrl_msg, manager);
+        r = udev_ctrl_start(manager->ctrl, on_ctrl_msg, manager);
         if (r < 0)
-                return log_error_errno(r, "Failed to create udev control event source: %m");
+                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");