summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/basic/util.c69
-rw-r--r--src/basic/util.h3
-rw-r--r--src/core/manager.c4
-rw-r--r--src/core/manager.h5
-rw-r--r--src/core/mount.c106
-rw-r--r--src/machine/machine-dbus.c18
-rw-r--r--src/nspawn/nspawn-expose-ports.c48
-rw-r--r--src/nspawn/nspawn.c31
8 files changed, 137 insertions, 147 deletions
diff --git a/src/basic/util.c b/src/basic/util.c
index e3b2af8e02..40d9e34f85 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -6775,3 +6775,72 @@ int fgetxattr_malloc(int fd, const char *name, char **value) {
return -errno;
}
}
+
+int send_one_fd(int transport_fd, int fd) {
+ union {
+ struct cmsghdr cmsghdr;
+ uint8_t buf[CMSG_SPACE(sizeof(int))];
+ } control = {};
+ struct msghdr mh = {
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
+ struct cmsghdr *cmsg;
+ ssize_t k;
+
+ assert(transport_fd >= 0);
+ assert(fd >= 0);
+
+ cmsg = CMSG_FIRSTHDR(&mh);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
+
+ mh.msg_controllen = CMSG_SPACE(sizeof(int));
+ k = sendmsg(transport_fd, &mh, MSG_NOSIGNAL);
+ if (k < 0)
+ return -errno;
+
+ return 0;
+}
+
+int receive_one_fd(int transport_fd) {
+ union {
+ struct cmsghdr cmsghdr;
+ uint8_t buf[CMSG_SPACE(sizeof(int))];
+ } control = {};
+ struct msghdr mh = {
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
+ struct cmsghdr *cmsg;
+ ssize_t k;
+
+ assert(transport_fd >= 0);
+
+ /*
+ * Receive a single FD via @transport_fd. We don't care for the
+ * transport-type, but the caller must assure that no other CMSG types
+ * than SCM_RIGHTS is enabled. We also retrieve a single FD at most, so
+ * for packet-based transports, the caller must ensure to send only a
+ * single FD per packet.
+ * This is best used in combination with send_one_fd().
+ */
+
+ k = recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC);
+ if (k < 0)
+ return -errno;
+
+ cmsg = CMSG_FIRSTHDR(&mh);
+ if (!cmsg || CMSG_NXTHDR(&mh, cmsg) ||
+ cmsg->cmsg_level != SOL_SOCKET ||
+ cmsg->cmsg_type != SCM_RIGHTS ||
+ cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
+ *(const int *)CMSG_DATA(cmsg) < 0) {
+ cmsg_close_all(&mh);
+ return -EIO;
+ }
+
+ return *(const int *)CMSG_DATA(cmsg);
+}
diff --git a/src/basic/util.h b/src/basic/util.h
index 8abaa740b2..905f375263 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -938,3 +938,6 @@ int reset_uid_gid(void);
int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink);
int fgetxattr_malloc(int fd, const char *name, char **value);
+
+int send_one_fd(int transport_fd, int fd);
+int receive_one_fd(int transport_fd);
diff --git a/src/core/manager.c b/src/core/manager.c
index 4e672a8c48..98ef561aae 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -571,8 +571,8 @@ int manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) {
m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd =
- m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd =
- m->cgroup_inotify_fd = -1;
+ m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->cgroup_inotify_fd = -1;
+
m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
m->ask_password_inotify_fd = -1;
diff --git a/src/core/manager.h b/src/core/manager.h
index 1384eb33a4..cc0e5e3361 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -23,6 +23,7 @@
#include <stdbool.h>
#include <stdio.h>
+#include <libmount.h>
#include "sd-bus.h"
#include "sd-event.h"
@@ -176,10 +177,8 @@ struct Manager {
Hashmap *devices_by_sysfs;
/* Data specific to the mount subsystem */
- FILE *proc_self_mountinfo;
+ struct libmnt_monitor *mount_monitor;
sd_event_source *mount_event_source;
- int utab_inotify_fd;
- sd_event_source *mount_utab_event_source;
/* Data specific to the swap filesystem */
FILE *proc_swaps;
diff --git a/src/core/mount.c b/src/core/mount.c
index 1f02aa5566..e7aae6e19a 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -23,8 +23,6 @@
#include <stdio.h>
#include <sys/epoll.h>
#include <signal.h>
-#include <libmount.h>
-#include <sys/inotify.h>
#include "manager.h"
#include "unit.h"
@@ -1535,13 +1533,13 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
}
static void mount_shutdown(Manager *m) {
+
assert(m);
m->mount_event_source = sd_event_source_unref(m->mount_event_source);
- m->mount_utab_event_source = sd_event_source_unref(m->mount_utab_event_source);
- m->proc_self_mountinfo = safe_fclose(m->proc_self_mountinfo);
- m->utab_inotify_fd = safe_close(m->utab_inotify_fd);
+ mnt_unref_monitor(m->mount_monitor);
+ m->mount_monitor = NULL;
}
static int mount_get_timeout(Unit *u, uint64_t *timeout) {
@@ -1560,53 +1558,41 @@ static int mount_get_timeout(Unit *u, uint64_t *timeout) {
static int mount_enumerate(Manager *m) {
int r;
+
assert(m);
mnt_init_debug(0);
- if (!m->proc_self_mountinfo) {
- m->proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
- if (!m->proc_self_mountinfo)
- return -errno;
+ if (!m->mount_monitor) {
+ int fd;
- r = sd_event_add_io(m->event, &m->mount_event_source, fileno(m->proc_self_mountinfo), EPOLLPRI, mount_dispatch_io, m);
- if (r < 0)
+ m->mount_monitor = mnt_new_monitor();
+ if (!m->mount_monitor) {
+ r = -ENOMEM;
goto fail;
+ }
- /* Dispatch this before we dispatch SIGCHLD, so that
- * we always get the events from /proc/self/mountinfo
- * before the SIGCHLD of /usr/bin/mount. */
- r = sd_event_source_set_priority(m->mount_event_source, -10);
+ r = mnt_monitor_enable_kernel(m->mount_monitor, 1);
if (r < 0)
goto fail;
-
- (void) sd_event_source_set_description(m->mount_event_source, "mount-mountinfo-dispatch");
- }
-
- if (m->utab_inotify_fd < 0) {
- m->utab_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
- if (m->utab_inotify_fd < 0) {
- r = -errno;
+ r = mnt_monitor_enable_userspace(m->mount_monitor, 1, NULL);
+ if (r < 0)
goto fail;
- }
-
- (void) mkdir_p_label("/run/mount", 0755);
- r = inotify_add_watch(m->utab_inotify_fd, "/run/mount", IN_MOVED_TO);
- if (r < 0) {
- r = -errno;
+ /* mnt_unref_monitor() will close the fd */
+ fd = r = mnt_monitor_get_fd(m->mount_monitor);
+ if (r < 0)
goto fail;
- }
- r = sd_event_add_io(m->event, &m->mount_utab_event_source, m->utab_inotify_fd, EPOLLIN, mount_dispatch_io, m);
+ r = sd_event_add_io(m->event, &m->mount_event_source, fd, EPOLLIN, mount_dispatch_io, m);
if (r < 0)
goto fail;
- r = sd_event_source_set_priority(m->mount_utab_event_source, -10);
+ r = sd_event_source_set_priority(m->mount_event_source, -10);
if (r < 0)
goto fail;
- (void) sd_event_source_set_description(m->mount_utab_event_source, "mount-utab-dispatch");
+ (void) sd_event_source_set_description(m->mount_event_source, "mount-monitor-dispatch");
}
r = mount_load_proc_self_mountinfo(m, false);
@@ -1629,45 +1615,27 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
int r;
assert(m);
- assert(revents & (EPOLLPRI | EPOLLIN));
-
- /* The manager calls this for every fd event happening on the
- * /proc/self/mountinfo file, which informs us about mounting
- * table changes, and for /run/mount events which we watch
- * for mount options. */
+ assert(revents & EPOLLIN);
- if (fd == m->utab_inotify_fd) {
+ if (fd == mnt_monitor_get_fd(m->mount_monitor)) {
bool rescan = false;
- /* FIXME: We *really* need to replace this with
- * libmount's own API for this, we should not hardcode
- * internal behaviour of libmount here. */
-
- for (;;) {
- union inotify_event_buffer buffer;
- struct inotify_event *e;
- ssize_t l;
-
- l = read(fd, &buffer, sizeof(buffer));
- if (l < 0) {
- if (errno == EAGAIN || errno == EINTR)
- break;
-
- log_error_errno(errno, "Failed to read utab inotify: %m");
- break;
- }
-
- FOREACH_INOTIFY_EVENT(e, buffer, l) {
- /* Only care about changes to utab,
- * but we have to monitor the
- * directory to reliably get
- * notifications about when utab is
- * replaced using rename(2) */
- if ((e->mask & IN_Q_OVERFLOW) || streq(e->name, "utab"))
- rescan = true;
- }
- }
-
+ /* Drain all events and verify that the event is valid.
+ *
+ * Note that libmount also monitors /run/mount mkdir if the
+ * directory does not exist yet. The mkdir may generate event
+ * which is irrelevant for us.
+ *
+ * error: r < 0; valid: r == 0, false positive: rc == 1 */
+ do {
+ r = mnt_monitor_next_change(m->mount_monitor, NULL, NULL);
+ if (r == 0)
+ rescan = true;
+ else if (r < 0)
+ return log_error_errno(r, "Failed to drain libmount events");
+ } while (r == 0);
+
+ log_debug("libmount event [rescan: %s]", yes_no(rescan));
if (!rescan)
return 0;
}
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
index 6aaaa8aa31..b010c90989 100644
--- a/src/machine/machine-dbus.c
+++ b/src/machine/machine-dbus.c
@@ -353,9 +353,9 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd
r = wait_for_terminate(child, &si);
if (r < 0)
- return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
+ return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
- return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
+ return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
break;
}
@@ -444,9 +444,9 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s
r = wait_for_terminate(child, &si);
if (r < 0)
- return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
+ return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
- return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
+ return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
break;
}
@@ -1040,11 +1040,11 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
r = wait_for_terminate(child, &si);
if (r < 0) {
- r = sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
+ r = sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
goto finish;
}
if (si.si_code != CLD_EXITED) {
- r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
+ r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
goto finish;
}
if (si.si_status != EXIT_SUCCESS) {
@@ -1052,7 +1052,7 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m");
else
- r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client failed.");
+ r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child failed.");
goto finish;
}
@@ -1088,7 +1088,7 @@ static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void
o->pid = 0;
if (si->si_code != CLD_EXITED) {
- r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
+ r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
goto fail;
}
@@ -1096,7 +1096,7 @@ static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void
if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
r = sd_bus_error_set_errnof(&error, r, "%m");
else
- r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Client failed.");
+ r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
goto fail;
}
diff --git a/src/nspawn/nspawn-expose-ports.c b/src/nspawn/nspawn-expose-ports.c
index 38250b6e02..9e63d88b69 100644
--- a/src/nspawn/nspawn-expose-ports.c
+++ b/src/nspawn/nspawn-expose-ports.c
@@ -183,17 +183,8 @@ int expose_port_execute(sd_netlink *rtnl, ExposePort *l, union in_addr_union *ex
}
int expose_port_send_rtnl(int send_fd) {
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
- struct msghdr mh = {
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
_cleanup_close_ int fd = -1;
- ssize_t k;
+ int r;
assert(send_fd >= 0);
@@ -201,19 +192,11 @@ int expose_port_send_rtnl(int send_fd) {
if (fd < 0)
return log_error_errno(errno, "Failed to allocate container netlink: %m");
- cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
-
- mh.msg_controllen = cmsg->cmsg_len;
-
/* Store away the fd in the socket, so that it stays open as
* long as we run the child */
- k = sendmsg(send_fd, &mh, MSG_NOSIGNAL);
- if (k < 0)
- return log_error_errno(errno, "Failed to send netlink fd: %m");
+ r = send_one_fd(send_fd, fd);
+ if (r < 0)
+ return log_error_errno(r, "Failed to send netlink fd: %m");
return 0;
}
@@ -224,33 +207,16 @@ int expose_port_watch_rtnl(
sd_netlink_message_handler_t handler,
union in_addr_union *exposed,
sd_netlink **ret) {
-
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
- struct msghdr mh = {
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
_cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
int fd, r;
- ssize_t k;
assert(event);
assert(recv_fd >= 0);
assert(ret);
- k = recvmsg(recv_fd, &mh, MSG_NOSIGNAL);
- if (k < 0)
- return log_error_errno(errno, "Failed to recv netlink fd: %m");
-
- cmsg = CMSG_FIRSTHDR(&mh);
- assert(cmsg->cmsg_level == SOL_SOCKET);
- assert(cmsg->cmsg_type == SCM_RIGHTS);
- assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int)));
- memcpy(&fd, CMSG_DATA(cmsg), sizeof(int));
+ fd = receive_one_fd(recv_fd);
+ if (fd < 0)
+ return log_error_errno(fd, "Failed to recv netlink fd: %m");
r = sd_netlink_open_fd(&rtnl, fd);
if (r < 0) {
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 5702df8ab4..7451c2bf64 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -1264,16 +1264,7 @@ static int setup_dev_console(const char *dest, const char *console) {
static int setup_kmsg(const char *dest, int kmsg_socket) {
const char *from, *to;
_cleanup_umask_ mode_t u;
- int fd, k;
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
- struct msghdr mh = {
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
+ int fd, r;
assert(kmsg_socket >= 0);
@@ -1298,21 +1289,13 @@ static int setup_kmsg(const char *dest, int kmsg_socket) {
if (fd < 0)
return log_error_errno(errno, "Failed to open fifo: %m");
- cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
-
- mh.msg_controllen = cmsg->cmsg_len;
-
/* Store away the fd in the socket, so that it stays open as
* long as we run the child */
- k = sendmsg(kmsg_socket, &mh, MSG_NOSIGNAL);
+ r = send_one_fd(kmsg_socket, fd);
safe_close(fd);
- if (k < 0)
- return log_error_errno(errno, "Failed to send FIFO fd: %m");
+ if (r < 0)
+ return log_error_errno(r, "Failed to send FIFO fd: %m");
/* And now make the FIFO unavailable as /run/kmsg... */
(void) unlink(from);
@@ -2804,6 +2787,8 @@ static int outer_child(
}
pid_socket = safe_close(pid_socket);
+ kmsg_socket = safe_close(kmsg_socket);
+ rtnl_socket = safe_close(rtnl_socket);
return 0;
}
@@ -3489,8 +3474,8 @@ int main(int argc, char *argv[]) {
}
/* Let the child know that we are ready and wait that the child is completely ready now. */
- if (!barrier_place_and_sync(&barrier)) { /* #5 */
- log_error("Client died too early.");
+ if (!barrier_place_and_sync(&barrier)) { /* #4 */
+ log_error("Child died too early.");
r = -ESRCH;
goto finish;
}