From 7fb3ee51c1b37738fd0ea2c81dfd6c336144698a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 10 Jul 2013 23:39:46 +0200 Subject: [PATCH] user-sessions: rely on PID 1 to kill sessions As we want to centralized cgroup access we should stop killing the user sessions directly from the systemd-user-sessions service. Instead, rely on PID 1 doing this by adding the right ordering dependencies to the session scope units. --- src/core/dbus-unit.c | 57 +++++++++++++++++++ src/login/logind-dbus.c | 15 +++++ src/login/logind-session.c | 2 +- src/login/logind.h | 2 +- src/login/user-sessions.c | 111 +------------------------------------ 5 files changed, 75 insertions(+), 112 deletions(-) diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index e07a28e32..57fac00d1 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -844,6 +844,63 @@ static int bus_unit_set_transient_property( unit_write_drop_in(u, mode, "Slice", contents); } return 1; + + } else if (streq(name, "Requires") || + streq(name, "RequiresOverridable") || + streq(name, "Requisite") || + streq(name, "RequisiteOverridable") || + streq(name, "Wants") || + streq(name, "BindsTo") || + streq(name, "Conflicts") || + streq(name, "Before") || + streq(name, "After") || + streq(name, "OnFailure") || + streq(name, "PropagatesReloadTo") || + streq(name, "ReloadPropagatedFrom") || + streq(name, "PartOf")) { + + UnitDependency d; + DBusMessageIter sub; + + d = unit_dependency_from_string(name); + if (d < 0) + return -EINVAL; + + if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(i) != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_recurse(i, &sub); + while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) { + const char *other; + + dbus_message_iter_get_basic(&sub, &other); + + if (!unit_name_is_valid(other, false)) + return -EINVAL; + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *label = NULL, *contents = NULL; + + r = unit_add_dependency_by_name(u, d, other, NULL, true); + if (r < 0) + return r; + + label = strjoin(name, "-", other, NULL); + if (!label) + return -ENOMEM; + + contents = strjoin("[Unit]\n", name, "=", other, "\n", NULL); + if (!contents) + return -ENOMEM; + + unit_write_drop_in(u, mode, label, contents); + } + + dbus_message_iter_next(&sub); + } + + return 1; } return 0; diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index ec46fdc23..39af637d1 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -2518,6 +2518,7 @@ int manager_start_scope( pid_t pid, const char *slice, const char *description, + const char *after, DBusError *error, char **job) { @@ -2575,6 +2576,20 @@ int manager_start_scope( return log_oom(); } + if (!isempty(after)) { + const char *after_property = "After"; + + if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) || + !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &after_property) || + !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "as", &sub3) || + !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "s", &sub4) || + !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_STRING, &after) || + !dbus_message_iter_close_container(&sub3, &sub4) || + !dbus_message_iter_close_container(&sub2, &sub3) || + !dbus_message_iter_close_container(&sub, &sub2)) + return log_oom(); + } + /* cgroup empty notification is not available in containers * currently. To make this less problematic, let's shorten the * stop timeout for sessions, so that we don't wait diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 3c67f86b1..db2215082 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -474,7 +474,7 @@ static int session_start_scope(Session *s) { description = strjoin("Session ", s->id, " of user ", s->user->name, NULL); - r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, &error, &job); + r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", &error, &job); if (r < 0) { log_error("Failed to start session scope: %s %s", bus_error(&error, r), error.name); dbus_error_free(&error); diff --git a/src/login/logind.h b/src/login/logind.h index f7457c053..9c41cdf70 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -178,7 +178,7 @@ int manager_send_changed(Manager *manager, const char *properties); int manager_dispatch_delayed(Manager *manager); -int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, DBusError *error, char **job); +int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, DBusError *error, char **job); int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job); int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job); int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error); diff --git a/src/login/user-sessions.c b/src/login/user-sessions.c index 18066ccc3..45fb42767 100644 --- a/src/login/user-sessions.c +++ b/src/login/user-sessions.c @@ -25,109 +25,8 @@ #include "log.h" #include "util.h" -#include "cgroup-util.h" #include "fileio.h" -static int kill_all_users(void) { - _cleanup_closedir_ DIR *d = NULL; - struct dirent *de; - int r = 0; - - d = opendir("/run/systemd/users"); - if (!d) { - if (errno == ENOENT) - return 0; - - log_error("Failed to open /run/systemd/users: %m"); - return -errno; - } - - FOREACH_DIRENT(de, d, return -errno) { - _cleanup_free_ char *cgroup = NULL; - char *a; - int k; - - if (!dirent_is_file(de)) - continue; - - a = strappenda("/run/systemd/users/", de->d_name); - - k = parse_env_file(a, NEWLINE, "CGROUP", &cgroup, NULL); - if (k < 0) { - if (k != -ENOENT) { - log_error("Failed to read user data: %s", strerror(-k)); - r = k; - } - - continue; - } - - if (!cgroup) { - log_error("User data did not contain cgroup field."); - r = -ENOENT; - continue; - } - - k = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, cgroup, true); - if (k < 0) { - log_error("Failed to kill cgroup %s: %s", cgroup, strerror(-k)); - r = k; - } - } - - return r; -} - -static int kill_all_sessions(void) { - _cleanup_closedir_ DIR *d = NULL; - struct dirent *de; - int r = 0; - - d = opendir("/run/systemd/sessions"); - if (!d) { - if (errno == ENOENT) - return 0; - - log_error("Failed to open /run/systemd/sessions: %m"); - return -errno; - } - - FOREACH_DIRENT(de, d, return -errno) { - _cleanup_free_ char *cgroup = NULL; - char *a; - int k; - - if (!dirent_is_file(de)) - continue; - - a = strappenda("/run/systemd/sessions/", de->d_name); - - k = parse_env_file(a, NEWLINE, "CGROUP", &cgroup, NULL); - if (k < 0) { - if (k != -ENOENT) { - log_error("Failed to read session data: %s", strerror(-k)); - r = k; - } - - continue; - } - - if (!cgroup) { - log_error("Session data did not contain cgroup field."); - r = -ENOENT; - continue; - } - - k = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, cgroup, true); - if (k < 0) { - log_error("Failed to kill cgroup %s: %s", cgroup, strerror(-k)); - r = k; - } - } - - return r; -} - int main(int argc, char*argv[]) { int ret = EXIT_FAILURE; @@ -167,20 +66,12 @@ int main(int argc, char*argv[]) { goto finish; } else if (streq(argv[1], "stop")) { - int r, q; + int r; r = write_string_file_atomic("/run/nologin", "System is going down."); if (r < 0) log_error("Failed to create /run/nologin: %s", strerror(-r)); - q = kill_all_users(); - if (q < 0 && r >= 0) - r = q; - - q = kill_all_sessions(); - if (q < 0 && r >= 0) - r = q; - } else { log_error("Unknown verb %s.", argv[1]); goto finish; -- 2.30.2