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.
This commit is contained in:
Yu Watanabe 2019-01-26 00:27:26 +09:00
parent 204e9c3e29
commit d02c6f5461
3 changed files with 244 additions and 290 deletions

View file

@ -17,6 +17,8 @@
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#include "sd-event.h"
#include "alloc-util.h" #include "alloc-util.h"
#include "fd-util.h" #include "fd-util.h"
#include "format-util.h" #include "format-util.h"
@ -29,48 +31,27 @@
/* wire protocol magic must match */ /* wire protocol magic must match */
#define UDEV_CTRL_MAGIC 0xdead1dea #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 { struct udev_ctrl_msg_wire {
char version[16]; char version[16];
unsigned magic; unsigned magic;
enum udev_ctrl_msg_type type; enum udev_ctrl_msg_type type;
union { union udev_ctrl_msg_value value;
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;
}; };
struct udev_ctrl { struct udev_ctrl {
unsigned n_ref; unsigned n_ref;
int sock; int sock;
int sock_connect;
union sockaddr_union saddr; union sockaddr_union saddr;
socklen_t addrlen; socklen_t addrlen;
bool bound; bool bound:1;
bool cleanup_socket; bool cleanup_socket:1;
bool connected; bool connected:1;
}; sd_event *event;
sd_event_source *event_source;
struct udev_ctrl_connection { sd_event_source *event_source_connect;
unsigned n_ref; udev_ctrl_handler_t callback;
struct udev_ctrl *uctrl; void *userdata;
int sock;
}; };
int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) { 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; 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) { static struct udev_ctrl *udev_ctrl_free(struct udev_ctrl *uctrl) {
assert(uctrl); assert(uctrl);
udev_ctrl_disconnect(uctrl);
sd_event_source_unref(uctrl->event_source);
safe_close(uctrl->sock); safe_close(uctrl->sock);
sd_event_unref(uctrl->event);
return mfree(uctrl); return mfree(uctrl);
} }
DEFINE_PRIVATE_TRIVIAL_REF_FUNC(struct udev_ctrl, udev_ctrl); DEFINE_TRIVIAL_REF_UNREF_FUNC(struct udev_ctrl, udev_ctrl, udev_ctrl_free);
DEFINE_TRIVIAL_UNREF_FUNC(struct udev_ctrl, udev_ctrl, udev_ctrl_free);
int udev_ctrl_cleanup(struct udev_ctrl *uctrl) { int udev_ctrl_cleanup(struct udev_ctrl *uctrl) {
if (!uctrl) if (!uctrl)
@ -159,63 +152,173 @@ int udev_ctrl_cleanup(struct udev_ctrl *uctrl) {
return 0; return 0;
} }
int udev_ctrl_get_fd(struct udev_ctrl *uctrl) { int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event) {
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 r; int r;
conn = new(struct udev_ctrl_connection, 1); assert_return(uctrl, -EINVAL);
if (!conn) assert_return(!uctrl->event, -EBUSY);
return NULL;
conn->n_ref = 1;
conn->uctrl = uctrl;
conn->sock = accept4(uctrl->sock, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK); if (event)
if (conn->sock < 0) { 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) if (errno != EINTR)
log_error_errno(errno, "Failed to receive ctrl connection: %m"); return log_error_errno(errno, "Failed to receive ctrl message: %m");
goto err;
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 */ /* check peer credential of connection */
r = getpeercred(conn->sock, &ucred); r = getpeercred(sock, &ucred);
if (r < 0) { if (r < 0) {
log_error_errno(r, "Failed to receive credentials of ctrl connection: %m"); log_error_errno(r, "Failed to receive credentials of ctrl connection: %m");
goto err; return 0;
} }
if (ucred.uid > 0) { if (ucred.uid > 0) {
log_error("Sender uid="UID_FMT", message ignored", ucred.uid); log_error("Invalid sender uid "UID_FMT", closing connection", ucred.uid);
goto err; return 0;
} }
/* enable receiving of the sender credentials in the messages */ /* 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) 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); r = sd_event_add_io(uctrl->event, &uctrl->event_source_connect, sock, EPOLLIN, udev_ctrl_connection_event_handler, uctrl);
return conn; if (r < 0) {
err: log_error_errno(r, "Failed to create event source for udev control connection: %m");
safe_close(conn->sock); return 0;
return mfree(conn); }
(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) { int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void *userdata) {
assert(conn); int r;
safe_close(conn->sock); assert(uctrl);
udev_ctrl_unref(conn->uctrl);
return mfree(conn); 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) { 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 = { struct udev_ctrl_msg_wire ctrl_msg_wire = {
.version = "udev-" STRINGIFY(PROJECT_VERSION), .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) 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 else
ctrl_msg_wire.intval = intval; ctrl_msg_wire.value.intval = intval;
if (!uctrl->connected) { if (!uctrl->connected) {
if (connect(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen) < 0) 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) { int udev_ctrl_send_exit(struct udev_ctrl *uctrl, usec_t timeout) {
return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, 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;
}

View file

@ -1,20 +1,46 @@
/* SPDX-License-Identifier: GPL-2.0+ */ /* SPDX-License-Identifier: GPL-2.0+ */
#pragma once #pragma once
#include "sd-event.h"
#include "macro.h" #include "macro.h"
#include "time-util.h" #include "time-util.h"
struct udev_ctrl; 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); int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd);
static inline int udev_ctrl_new(struct udev_ctrl **ret) { static inline int udev_ctrl_new(struct udev_ctrl **ret) {
return udev_ctrl_new_from_fd(ret, -1); return udev_ctrl_new_from_fd(ret, -1);
} }
int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl); 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); struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl);
int udev_ctrl_cleanup(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_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_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_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_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_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*, 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);

View file

@ -89,11 +89,9 @@ typedef struct Manager {
sd_device_monitor *monitor; sd_device_monitor *monitor;
struct udev_ctrl *ctrl; struct udev_ctrl *ctrl;
struct udev_ctrl_connection *ctrl_conn_blocking;
int fd_inotify; int fd_inotify;
int worker_watch[2]; int worker_watch[2];
sd_event_source *ctrl_event;
sd_event_source *inotify_event; sd_event_source *inotify_event;
sd_event_source *kill_workers_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) { static void manager_clear_for_worker(Manager *manager) {
assert(manager); assert(manager);
manager->ctrl_event = sd_event_source_unref(manager->ctrl_event);
manager->inotify_event = sd_event_source_unref(manager->inotify_event); manager->inotify_event = sd_event_source_unref(manager->inotify_event);
manager->kill_workers_event = sd_event_source_unref(manager->kill_workers_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); event_queue_cleanup(manager, EVENT_UNDEF);
manager->monitor = sd_device_monitor_unref(manager->monitor); 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->ctrl = udev_ctrl_unref(manager->ctrl);
manager->worker_watch[READ_END] = safe_close(manager->worker_watch[READ_END]); 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..."); "STATUS=Starting shutdown...");
/* close sources of new events and discard buffered events */ /* 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->ctrl = udev_ctrl_unref(manager->ctrl);
manager->inotify_event = sd_event_source_unref(manager->inotify_event); 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 */ /* 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; Manager *manager = userdata;
_cleanup_(udev_ctrl_connection_unrefp) struct udev_ctrl_connection *ctrl_conn = NULL; int r;
_cleanup_(udev_ctrl_msg_unrefp) struct udev_ctrl_msg *ctrl_msg = NULL;
const char *str;
int i, r;
assert(value);
assert(manager); assert(manager);
ctrl_conn = udev_ctrl_get_connection(manager->ctrl); switch (type) {
if (!ctrl_conn) case UDEV_CTRL_SET_LOG_LEVEL:
return 1; 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);
ctrl_msg = udev_ctrl_receive_msg(ctrl_conn); log_set_max_level_realm(LOG_REALM_SYSTEMD, value->intval);
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);
manager_kill_workers(manager); manager_kill_workers(manager);
} break;
case UDEV_CTRL_STOP_EXEC_QUEUE:
if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) {
log_debug("Received udev control message (STOP_EXEC_QUEUE)"); log_debug("Received udev control message (STOP_EXEC_QUEUE)");
manager->stop_exec_queue = true; manager->stop_exec_queue = true;
} break;
case UDEV_CTRL_START_EXEC_QUEUE:
if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) {
log_debug("Received udev control message (START_EXEC_QUEUE)"); log_debug("Received udev control message (START_EXEC_QUEUE)");
manager->stop_exec_queue = false; manager->stop_exec_queue = false;
event_queue_start(manager); event_queue_start(manager);
} break;
case UDEV_CTRL_RELOAD:
if (udev_ctrl_get_reload(ctrl_msg) > 0) {
log_debug("Received udev control message (RELOAD)"); log_debug("Received udev control message (RELOAD)");
manager_reload(manager); manager_reload(manager);
} break;
case UDEV_CTRL_SET_ENV: {
str = udev_ctrl_get_set_env(ctrl_msg);
if (str) {
_cleanup_free_ char *key = NULL, *val = NULL, *old_key = NULL, *old_val = NULL; _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) { if (!eq) {
log_error("Invalid key format '%s'", str); log_error("Invalid key format '%s'", value->buf);
return 1; return 1;
} }
key = strndup(str, eq - str); key = strndup(value->buf, eq - value->buf);
if (!key) { if (!key) {
log_oom(); log_oom();
return 1; 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; key = val = NULL;
manager_kill_workers(manager); 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); log_debug("Received udev control message (SET_MAX_CHILDREN), setting children_max=%i", value->intval);
if (i >= 0) { arg_children_max = value->intval;
log_debug("Receivd udev control message (SET_MAX_CHILDREN), setting children_max=%i", i);
arg_children_max = i;
(void) sd_notifyf(false, (void) sd_notifyf(false,
"READY=1\n" "READY=1\n"
"STATUS=Processing with %u children at max", arg_children_max); "STATUS=Processing with %u children at max", arg_children_max);
} break;
case UDEV_CTRL_PING:
if (udev_ctrl_get_ping(ctrl_msg) > 0)
log_debug("Received udev control message (PING)"); log_debug("Received udev control message (PING)");
break;
if (udev_ctrl_get_exit(ctrl_msg) > 0) { case UDEV_CTRL_EXIT:
log_debug("Received udev control message (EXIT)"); log_debug("Received udev control message (EXIT)");
manager_exit(manager); manager_exit(manager);
/* keep reference to block the client until we exit break;
TODO: deal with several blocking exit requests */ default:
manager->ctrl_conn_blocking = udev_ctrl_connection_ref(ctrl_conn); log_debug("Received unknown udev control message, ignoring");
} }
return 1; 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) { static int main_loop(Manager *manager) {
int fd_worker, fd_ctrl, r; int fd_worker, r;
/* unnamed socket from workers to the main daemon */ /* unnamed socket from workers to the main daemon */
r = socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, manager->worker_watch); 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) if (r < 0)
return log_error_errno(r, "Failed to create watchdog event source: %m"); return log_error_errno(r, "Failed to create watchdog event source: %m");
fd_ctrl = udev_ctrl_get_fd(manager->ctrl); r = udev_ctrl_attach_event(manager->ctrl, manager->event);
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);
if (r < 0) 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 /* 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 * that the ping is send back after fully processing the pending uevents
* (including the synthetic ones we may create due to inotify events). * (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) if (r < 0)
return log_error_errno(r, "Failed to set IDLE event priority for udev control event source: %m"); return log_error_errno(r, "Failed to set IDLE event priority for udev control event source: %m");