conf.set_quoted('SYSTEMD_BINARY_PATH', libexecdir / 'systemd')
conf.set_quoted('SYSTEMD_EXECUTOR_BINARY_PATH', libexecdir / 'systemd-executor')
conf.set_quoted('SYSTEMD_CATALOG_DIR', catalogdir)
-conf.set_quoted('SYSTEMD_CGROUPS_AGENT_PATH', libexecdir / 'systemd-cgroups-agent')
conf.set_quoted('SYSTEMD_CRYPTSETUP_PATH', bindir / 'systemd-cryptsetup')
conf.set_quoted('SYSTEMD_EXPORT_PATH', libexecdir / 'systemd-export')
conf.set_quoted('SYSTEMD_FSCK_PATH', libexecdir / 'systemd-fsck')
subdir('src/bootctl')
subdir('src/busctl')
subdir('src/cgls')
-subdir('src/cgroups-agent')
subdir('src/cgtop')
subdir('src/coredump')
subdir('src/creds')
# The openSUSE filelists hardcode the manpage compression extension. This causes rpmbuild errors since we
# disable manpage compression as the files cannot be found. Fix the issue by removing the compression
# extension.
+#
+# TODO: remove manual cgroups-agent patch when the upstream spec is updated
while read -r filelist; do
- sed 's/\.gz$//' "$filelist" >"/tmp/$(basename "$filelist")"
+ sed 's/\.gz$//; /systemd-cgroups-agent/d' "$filelist" >"/tmp/$(basename "$filelist")"
mount --bind "/tmp/$(basename "$filelist")" "$filelist"
done < <(find "pkg/$PKG_SUBDIR${GIT_SUBDIR:+/$GIT_SUBDIR}" -name "files.*")
+++ /dev/null
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include <stdlib.h>
-
-#include "fd-util.h"
-#include "log.h"
-#include "socket-util.h"
-
-int main(int argc, char *argv[]) {
-
- static const union sockaddr_union sa = {
- .un.sun_family = AF_UNIX,
- .un.sun_path = "/run/systemd/cgroups-agent",
- };
-
- _cleanup_close_ int fd = -EBADF;
- ssize_t n;
- size_t l;
- int r;
-
- r = make_null_stdio();
- if (r < 0) {
- log_error_errno(r, "Failed to connect stdin/stdout/stderr with /dev/null: %m");
- return EXIT_FAILURE;
- }
-
- if (argc != 2) {
- log_error("Incorrect number of arguments.");
- return EXIT_FAILURE;
- }
-
- log_setup();
-
- fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
- if (fd < 0) {
- log_debug_errno(errno, "Failed to allocate socket: %m");
- return EXIT_FAILURE;
- }
-
- l = strlen(argv[1]);
-
- n = sendto(fd, argv[1], l, 0, &sa.sa, SOCKADDR_UN_LEN(sa.un));
- if (n < 0) {
- log_debug_errno(errno, "Failed to send cgroups agent message: %m");
- return EXIT_FAILURE;
- }
-
- if ((size_t) n != l) {
- log_debug("Datagram size mismatch");
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
+++ /dev/null
-# SPDX-License-Identifier: LGPL-2.1-or-later
-
-executables += [
- libexec_template + {
- 'name' : 'systemd-cgroups-agent',
- 'sources' : files('cgroups-agent.c'),
- },
-]
(void) sd_event_source_set_description(m->cgroup_empty_event_source, "cgroup-empty");
- /* 4. Install notifier inotify object, or agent */
- if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) > 0) {
-
- /* In the unified hierarchy we can get cgroup empty notifications via inotify. */
-
- m->cgroup_inotify_event_source = sd_event_source_disable_unref(m->cgroup_inotify_event_source);
- safe_close(m->cgroup_inotify_fd);
-
- m->cgroup_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
- if (m->cgroup_inotify_fd < 0)
- return log_error_errno(errno, "Failed to create control group inotify object: %m");
-
- r = sd_event_add_io(m->event, &m->cgroup_inotify_event_source, m->cgroup_inotify_fd, EPOLLIN, on_cgroup_inotify_event, m);
- if (r < 0)
- return log_error_errno(r, "Failed to watch control group inotify object: %m");
-
- /* Process cgroup empty notifications early. Note that when this event is dispatched it'll
- * just add the unit to a cgroup empty queue, hence let's run earlier than that. Also see
- * handling of cgroup agent notifications, for the classic cgroup hierarchy support. */
- r = sd_event_source_set_priority(m->cgroup_inotify_event_source, EVENT_PRIORITY_CGROUP_INOTIFY);
- if (r < 0)
- return log_error_errno(r, "Failed to set priority of inotify event source: %m");
+ /* 4. Install cgroup empty event notifier inotify object */
+ m->cgroup_inotify_event_source = sd_event_source_disable_unref(m->cgroup_inotify_event_source);
+ safe_close(m->cgroup_inotify_fd);
- (void) sd_event_source_set_description(m->cgroup_inotify_event_source, "cgroup-inotify");
+ m->cgroup_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
+ if (m->cgroup_inotify_fd < 0)
+ return log_error_errno(errno, "Failed to create control group inotify object: %m");
- } else if (MANAGER_IS_SYSTEM(m) && manager_owns_host_root_cgroup(m) && !MANAGER_IS_TEST_RUN(m)) {
+ r = sd_event_add_io(m->event, &m->cgroup_inotify_event_source, m->cgroup_inotify_fd, EPOLLIN, on_cgroup_inotify_event, m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to watch control group inotify object: %m");
- /* On the legacy hierarchy we only get notifications via cgroup agents. (Which isn't really reliable,
- * since it does not generate events when control groups with children run empty. */
+ /* Process cgroup empty notifications early. Note that when this event is dispatched it'll
+ * just add the unit to a cgroup empty queue, hence let's run earlier than that. Also see
+ * handling of cgroup agent notifications, for the classic cgroup hierarchy support. */
+ r = sd_event_source_set_priority(m->cgroup_inotify_event_source, EVENT_PRIORITY_CGROUP_INOTIFY);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set priority of inotify event source: %m");
- r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUPS_AGENT_PATH);
- if (r < 0)
- log_warning_errno(r, "Failed to install release agent, ignoring: %m");
- else if (r > 0)
- log_debug("Installed release agent.");
- else if (r == 0)
- log_debug("Release agent already installed.");
- }
+ (void) sd_event_source_set_description(m->cgroup_inotify_event_source, "cgroup-inotify");
/* 5. Make sure we are in the special "init.scope" unit in the root slice. */
scope_path = strjoina(m->cgroup_root, "/" SPECIAL_INIT_SCOPE);
return;
}
-int bus_forward_agent_released(Manager *m, const char *path) {
- int r;
-
- assert(m);
- assert(path);
-
- if (!MANAGER_IS_SYSTEM(m))
- return 0;
-
- if (!m->system_bus)
- return 0;
-
- /* If we are running a system instance we forward the agent message on the system bus, so that the user
- * instances get notified about this, too */
-
- r = sd_bus_emit_signal(m->system_bus,
- "/org/freedesktop/systemd1/agent",
- "org.freedesktop.systemd1.Agent",
- "Released",
- "s", path);
- if (r < 0)
- return log_debug_errno(r, "Failed to propagate agent release message: %m");
-
- return 1;
-}
-
-static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- Manager *m = ASSERT_PTR(userdata);
- const char *cgroup;
- uid_t sender_uid;
- int r;
-
- assert(message);
-
- /* only accept org.freedesktop.systemd1.Agent from UID=0 */
- r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
- if (r < 0)
- return r;
-
- r = sd_bus_creds_get_euid(creds, &sender_uid);
- if (r < 0 || sender_uid != 0)
- return 0;
-
- /* parse 'cgroup-empty' notification */
- r = sd_bus_message_read(message, "s", &cgroup);
- if (r < 0) {
- bus_log_parse_error(r);
- return 0;
- }
-
- manager_notify_cgroup_empty(m, cgroup);
- return 0;
-}
-
static int signal_disconnected(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = ASSERT_PTR(userdata);
sd_bus *bus;
return 0;
}
-static void bus_setup_system(Manager *m, sd_bus *bus) {
- int r;
-
- assert(m);
- assert(bus);
-
- /* if we are a user instance we get the Released message via the system bus */
- if (MANAGER_IS_USER(m)) {
- r = sd_bus_match_signal_async(
- bus,
- NULL,
- NULL,
- "/org/freedesktop/systemd1/agent",
- "org.freedesktop.systemd1.Agent",
- "Released",
- signal_agent_released, NULL, m);
- if (r < 0)
- log_warning_errno(r, "Failed to request Released match on system bus: %m");
- }
-
- log_debug("Successfully connected to system bus.");
- return;
-}
-
int bus_init_system(Manager *m) {
_cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
int r;
return r;
}
- bus_setup_system(m, bus);
-
m->system_bus = TAKE_PTR(bus);
+ log_debug("Successfully connected to system bus.");
+
return 0;
}
int bus_foreach_bus(Manager *m, sd_bus_track *subscribed2, int (*send_message)(sd_bus *bus, void *userdata), void *userdata);
-int bus_forward_agent_released(Manager *m, const char *path);
-
uint64_t manager_bus_n_queued_write(Manager *m);
void dump_bus_properties(FILE *f);
if (arg_watchdog_device)
(void) strv_extendf(&env_block, "WATCHDOG_DEVICE=%s", arg_watchdog_device);
- /* Avoid the creation of new processes forked by the kernel; at this
- * point, we will not listen to the signals anyway */
- if (detect_container() <= 0)
- (void) cg_uninstall_release_agent(SYSTEMD_CGROUP_CONTROLLER);
-
(void) write_boot_or_shutdown_osc("shutdown");
execve(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line, env_block);
(void) serialize_item(f, "notify-socket", m->notify_socket);
}
- if (m->cgroups_agent_fd >= 0) {
- r = serialize_fd(f, fds, "cgroups-agent-fd", m->cgroups_agent_fd);
- if (r < 0)
- return r;
- }
-
if (m->user_lookup_fds[0] >= 0) {
r = serialize_fd_many(f, fds, "user-lookup", m->user_lookup_fds, 2);
if (r < 0)
if (r < 0)
return r;
- } else if ((val = startswith(l, "cgroups-agent-fd="))) {
- int fd;
-
- fd = deserialize_fd(fds, val);
- if (fd >= 0) {
- m->cgroups_agent_event_source = sd_event_source_disable_unref(m->cgroups_agent_event_source);
- close_and_replace(m->cgroups_agent_fd, fd);
- }
-
} else if ((val = startswith(l, "user-lookup="))) {
m->user_lookup_event_source = sd_event_source_disable_unref(m->user_lookup_event_source);
if (q < _MANAGER_TIMESTAMP_MAX) /* found it */
(void) deserialize_dual_timestamp(val, m->timestamps + q);
- else if (!STARTSWITH_SET(l, "kdbus-fd=", "honor-device-enumeration=", "ready-sent=")) /* ignore deprecated values */
+ else if (!STARTSWITH_SET(l, "kdbus-fd=", "honor-device-enumeration=", "ready-sent=", "cgroups-agent-fd=")) /* ignore deprecated values */
log_notice("Unknown serialization item '%s', ignoring.", l);
}
}
#define DEFAULT_TASKS_MAX ((CGroupTasksMax) { 15U, 100U }) /* 15% */
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
-static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
.show_status_overridden = _SHOW_STATUS_INVALID,
.notify_fd = -EBADF,
- .cgroups_agent_fd = -EBADF,
.signal_fd = -EBADF,
.user_lookup_fds = EBADF_PAIR,
.handoff_timestamp_fds = EBADF_PAIR,
return 0;
}
-static int manager_setup_cgroups_agent(Manager *m) {
-
- static const union sockaddr_union sa = {
- .un.sun_family = AF_UNIX,
- .un.sun_path = "/run/systemd/cgroups-agent",
- };
- int r;
-
- /* This creates a listening socket we receive cgroups agent messages on. We do not use D-Bus for delivering
- * these messages from the cgroups agent binary to PID 1, as the cgroups agent binary is very short-living, and
- * each instance of it needs a new D-Bus connection. Since D-Bus connections are SOCK_STREAM/AF_UNIX, on
- * overloaded systems the backlog of the D-Bus socket becomes relevant, as not more than the configured number
- * of D-Bus connections may be queued until the kernel will start dropping further incoming connections,
- * possibly resulting in lost cgroups agent messages. To avoid this, we'll use a private SOCK_DGRAM/AF_UNIX
- * socket, where no backlog is relevant as communication may take place without an actual connect() cycle, and
- * we thus won't lose messages.
- *
- * Note that PID 1 will forward the agent message to system bus, so that the user systemd instance may listen
- * to it. The system instance hence listens on this special socket, but the user instances listen on the system
- * bus for these messages. */
-
- if (MANAGER_IS_TEST_RUN(m))
- return 0;
-
- if (!MANAGER_IS_SYSTEM(m))
- return 0;
-
- r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
- if (r < 0)
- return log_error_errno(r, "Failed to determine whether unified cgroups hierarchy is used: %m");
- if (r > 0) /* We don't need this anymore on the unified hierarchy */
- return 0;
-
- if (m->cgroups_agent_fd < 0) {
- _cleanup_close_ int fd = -EBADF;
-
- /* First free all secondary fields */
- m->cgroups_agent_event_source = sd_event_source_disable_unref(m->cgroups_agent_event_source);
-
- fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (fd < 0)
- return log_error_errno(errno, "Failed to allocate cgroups agent socket: %m");
-
- (void) fd_increase_rxbuf(fd, MANAGER_SOCKET_RCVBUF_SIZE);
-
- (void) sockaddr_un_unlink(&sa.un);
-
- /* Only allow root to connect to this socket */
- WITH_UMASK(0077)
- r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
- if (r < 0)
- return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
-
- m->cgroups_agent_fd = TAKE_FD(fd);
- }
-
- if (!m->cgroups_agent_event_source) {
- r = sd_event_add_io(m->event, &m->cgroups_agent_event_source, m->cgroups_agent_fd, EPOLLIN, manager_dispatch_cgroups_agent_fd, m);
- if (r < 0)
- return log_error_errno(r, "Failed to allocate cgroups agent event source: %m");
-
- /* Process cgroups notifications early. Note that when the agent notification is received
- * we'll just enqueue the unit in the cgroup empty queue, hence pick a high priority than
- * that. Also see handling of cgroup inotify for the unified cgroup stuff. */
- r = sd_event_source_set_priority(m->cgroups_agent_event_source, EVENT_PRIORITY_CGROUP_AGENT);
- if (r < 0)
- return log_error_errno(r, "Failed to set priority of cgroups agent event source: %m");
-
- (void) sd_event_source_set_description(m->cgroups_agent_event_source, "manager-cgroups-agent");
- }
-
- return 0;
-}
-
static int manager_setup_user_lookup_fd(Manager *m) {
int r;
sd_event_source_unref(m->signal_event_source);
sd_event_source_unref(m->sigchld_event_source);
sd_event_source_unref(m->notify_event_source);
- sd_event_source_unref(m->cgroups_agent_event_source);
sd_event_source_unref(m->time_change_event_source);
sd_event_source_unref(m->timezone_change_event_source);
sd_event_source_unref(m->jobs_in_progress_event_source);
safe_close(m->signal_fd);
safe_close(m->notify_fd);
- safe_close(m->cgroups_agent_fd);
safe_close_pair(m->user_lookup_fds);
safe_close_pair(m->handoff_timestamp_fds);
safe_close_pair(m->pidref_transport_fds);
/* No sense to continue without notifications, our children would fail anyway. */
return r;
- r = manager_setup_cgroups_agent(m);
- if (r < 0)
- /* Likewise, no sense to continue without empty cgroup notifications. */
- return r;
-
r = manager_setup_user_lookup_fd(m);
if (r < 0)
/* This shouldn't fail, except if things are really broken. */
return n;
}
-static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- Manager *m = userdata;
- char buf[PATH_MAX];
- ssize_t n;
-
- n = recv(fd, buf, sizeof(buf), 0);
- if (n < 0)
- return log_error_errno(errno, "Failed to read cgroups agent message: %m");
- if (n == 0) {
- log_error("Got zero-length cgroups agent message, ignoring.");
- return 0;
- }
- if ((size_t) n >= sizeof(buf)) {
- log_error("Got overly long cgroups agent message, ignoring.");
- return 0;
- }
-
- if (memchr(buf, 0, n)) {
- log_error("Got cgroups agent message with embedded NUL byte, ignoring.");
- return 0;
- }
- buf[n] = 0;
-
- manager_notify_cgroup_empty(m, buf);
- (void) bus_forward_agent_released(m, buf);
-
- return 0;
-}
-
static bool manager_process_barrier_fd(char * const *tags, FDSet *fds) {
/* nothing else must be sent when using BARRIER=1 */
/* Re-register notify_fd as event source, and set up other sockets/communication channels we might need */
(void) manager_setup_notify(m);
- (void) manager_setup_cgroups_agent(m);
(void) manager_setup_user_lookup_fd(m);
(void) manager_setup_handoff_timestamp_fd(m);
(void) manager_setup_pidref_transport_fd(m);
int notify_fd;
sd_event_source *notify_event_source;
- int cgroups_agent_fd;
- sd_event_source *cgroups_agent_event_source;
-
int signal_fd;
sd_event_source *signal_event_source;
EVENT_PRIORITY_USER_LOOKUP = SD_EVENT_PRIORITY_NORMAL-12,
EVENT_PRIORITY_MOUNT_TABLE = SD_EVENT_PRIORITY_NORMAL-11,
EVENT_PRIORITY_SWAP_TABLE = SD_EVENT_PRIORITY_NORMAL-11,
- EVENT_PRIORITY_CGROUP_AGENT = SD_EVENT_PRIORITY_NORMAL-10, /* cgroupv1 */
- EVENT_PRIORITY_CGROUP_INOTIFY = SD_EVENT_PRIORITY_NORMAL-10, /* cgroupv2 */
+ EVENT_PRIORITY_CGROUP_INOTIFY = SD_EVENT_PRIORITY_NORMAL-10,
EVENT_PRIORITY_CGROUP_OOM = SD_EVENT_PRIORITY_NORMAL-9,
EVENT_PRIORITY_PIDREF = SD_EVENT_PRIORITY_NORMAL-8,
EVENT_PRIORITY_HANDOFF_TIMESTAMP = SD_EVENT_PRIORITY_NORMAL-7,
return r;
}
-int cg_install_release_agent(const char *controller, const char *agent) {
- _cleanup_free_ char *fs = NULL, *contents = NULL;
- const char *sc;
- int r;
-
- assert(agent);
-
- r = cg_unified_controller(controller);
- if (r < 0)
- return r;
- if (r > 0) /* doesn't apply to unified hierarchy */
- return -EOPNOTSUPP;
-
- r = cg_get_path(controller, NULL, "release_agent", &fs);
- if (r < 0)
- return r;
-
- r = read_one_line_file(fs, &contents);
- if (r < 0)
- return r;
-
- sc = strstrip(contents);
- if (isempty(sc)) {
- r = write_string_file(fs, agent, WRITE_STRING_FILE_DISABLE_BUFFER);
- if (r < 0)
- return r;
- } else if (!path_equal(sc, agent))
- return -EEXIST;
-
- fs = mfree(fs);
- r = cg_get_path(controller, NULL, "notify_on_release", &fs);
- if (r < 0)
- return r;
-
- contents = mfree(contents);
- r = read_one_line_file(fs, &contents);
- if (r < 0)
- return r;
-
- sc = strstrip(contents);
- if (streq(sc, "0")) {
- r = write_string_file(fs, "1", WRITE_STRING_FILE_DISABLE_BUFFER);
- if (r < 0)
- return r;
-
- return 1;
- }
-
- if (!streq(sc, "1"))
- return -EIO;
-
- return 0;
-}
-
-int cg_uninstall_release_agent(const char *controller) {
- _cleanup_free_ char *fs = NULL;
- int r;
-
- r = cg_unified_controller(controller);
- if (r < 0)
- return r;
- if (r > 0) /* Doesn't apply to unified hierarchy */
- return -EOPNOTSUPP;
-
- r = cg_get_path(controller, NULL, "notify_on_release", &fs);
- if (r < 0)
- return r;
-
- r = write_string_file(fs, "0", WRITE_STRING_FILE_DISABLE_BUFFER);
- if (r < 0)
- return r;
-
- fs = mfree(fs);
-
- r = cg_get_path(controller, NULL, "release_agent", &fs);
- if (r < 0)
- return r;
-
- r = write_string_file(fs, "", WRITE_STRING_FILE_DISABLE_BUFFER);
- if (r < 0)
- return r;
-
- return 0;
-}
-
int cg_has_legacy(void) {
struct statfs fs;
int cg_migrate_v1_controllers(CGroupMask supported, CGroupMask mask, const char *from, cg_migrate_callback_t to_callback, void *userdata);
int cg_trim_v1_controllers(CGroupMask supported, CGroupMask mask, const char *path, bool delete_root);
-int cg_install_release_agent(const char *controller, const char *agent);
-int cg_uninstall_release_agent(const char *controller);
-
int cg_has_legacy(void);