diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/basic/util.c | 69 | ||||
-rw-r--r-- | src/basic/util.h | 3 | ||||
-rw-r--r-- | src/core/manager.c | 4 | ||||
-rw-r--r-- | src/core/manager.h | 5 | ||||
-rw-r--r-- | src/core/mount.c | 106 | ||||
-rw-r--r-- | src/machine/machine-dbus.c | 18 | ||||
-rw-r--r-- | src/nspawn/nspawn-expose-ports.c | 48 | ||||
-rw-r--r-- | src/nspawn/nspawn.c | 31 |
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; } |