summaryrefslogtreecommitdiff
path: root/src/udev/udev-ctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/udev/udev-ctrl.c')
-rw-r--r--src/udev/udev-ctrl.c380
1 files changed, 172 insertions, 208 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 <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,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;
-}