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 <unistd.h>
#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;
}

View 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);

View 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 = 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");