summaryrefslogtreecommitdiff
path: root/src/login
diff options
context:
space:
mode:
authorAndy Wingo <wingo@pobox.com>2016-03-06 16:02:31 +0100
committerAndy Wingo <wingo@pobox.com>2016-03-06 16:02:31 +0100
commit162255186046fa7a5e82859b7dba5a7909ce6fc4 (patch)
tree8b81f2e7afac4df45ebca6e662d4d2b1d8635e5a /src/login
parent6f5035f2db6ab7b4beae46c44b95e6a8b6d956b5 (diff)
Classify processes from sessions into cgroups
Create a private cgroup tree associated with no controllers, and use it to map PIDs to sessions. Since we use our own path structure, remove internal cgroup-related helpers that interpret the cgroup path structure to pull out users, slices, and scopes.
Diffstat (limited to 'src/login')
-rw-r--r--src/login/logind-core.c33
-rw-r--r--src/login/logind-session.c69
-rw-r--r--src/login/logind-user.c12
-rw-r--r--src/login/logind.c36
4 files changed, 136 insertions, 14 deletions
diff --git a/src/login/logind-core.c b/src/login/logind-core.c
index 67b03623ac..041593c5ab 100644
--- a/src/login/logind-core.c
+++ b/src/login/logind-core.c
@@ -311,24 +311,41 @@ int manager_process_button_device(Manager *m, struct udev_device *d) {
}
int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) {
+ _cleanup_free_ char *session_name = NULL;
+ Session *s;
+ int r;
+
assert(m);
assert(session);
- /* Without cgroups, we have no way to map from pid to
- session. */
- return 0;
+ if (pid < 1)
+ return -EINVAL;
+
+ r = cg_pid_get_session(pid, &session_name);
+ if (r < 0)
+ return 0;
+
+ s = hashmap_get(m->sessions, session_name);
+ if (!s)
+ return 0;
+
+ *session = s;
+ return 1;
}
int manager_get_user_by_pid(Manager *m, pid_t pid, User **user) {
+ Session *s;
+ int r;
+
assert(m);
assert(user);
- if (pid < 1)
- return -EINVAL;
+ r = manager_get_session_by_pid (m, pid, &s);
+ if (r <= 0)
+ return r;
- /* Without cgroups, we have no way to map from pid to
- user. */
- return 0;
+ *user = s->user;
+ return 1;
}
int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 109e3ef133..f03c2e565d 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -36,6 +36,8 @@
#include "audit.h"
#include "bus-util.h"
#include "bus-error.h"
+#include "cgroup-util.h"
+#include "def.h"
#include "logind-session.h"
static void session_remove_fifo(Session *s);
@@ -475,6 +477,25 @@ int session_activate(Session *s) {
return 0;
}
+static int session_start_cgroup(Session *s) {
+ int r;
+
+ assert(s);
+ assert(s->user);
+ assert(s->leader > 0);
+
+ /* First, create our own group */
+ r = cg_create(SYSTEMD_CGROUP_CONTROLLER, s->id);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create cgroup %s: %m", s->id);
+
+ r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, s->id, s->leader);
+ if (r < 0)
+ log_warning_errno(r, "Failed to attach PID %d to cgroup %s: %m", s->leader, s->id);
+
+ return 0;
+}
+
int session_start(Session *s) {
int r;
@@ -490,6 +511,10 @@ int session_start(Session *s) {
if (r < 0)
return r;
+ r = session_start_cgroup(s);
+ if (r < 0)
+ return r;
+
log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_SESSION_START),
"SESSION_ID=%s", s->id,
@@ -527,8 +552,23 @@ int session_start(Session *s) {
return 0;
}
+static int session_stop_cgroup(Session *s, bool force) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r;
+
+ assert(s);
+
+ if (force || manager_shall_kill(s->manager, s->user->name)) {
+ r = session_kill(s, KILL_ALL, SIGTERM);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
int session_stop(Session *s, bool force) {
- int r = 0;
+ int r;
assert(s);
@@ -540,6 +580,9 @@ int session_stop(Session *s, bool force) {
/* We are going down, don't care about FIFOs anymore */
session_remove_fifo(s);
+ /* Kill cgroup */
+ r = session_stop_cgroup(s, force);
+
s->stopping = true;
user_elect_display(s->user);
@@ -609,7 +652,7 @@ int session_release(Session *s) {
/* In systemd, session release is triggered by user jobs
dying. In elogind we don't have that so go ahead and stop
now. */
- session_stop(s, false);
+ return session_stop(s, false);
}
bool session_is_active(Session *s) {
@@ -814,6 +857,9 @@ bool session_check_gc(Session *s, bool drop_not_started) {
return true;
}
+ if (cg_is_empty_recursive (SYSTEMD_CGROUP_CONTROLLER, s->id, false) > 0)
+ return true;
+
return false;
}
@@ -846,8 +892,23 @@ SessionState session_get_state(Session *s) {
int session_kill(Session *s, KillWho who, int signo) {
assert(s);
- /* No way to kill the session without cgroups. */
- return -ESRCH;
+ if (who == KILL_LEADER) {
+ if (s->leader <= 0)
+ return -ESRCH;
+
+ /* FIXME: verify that leader is in cgroup? */
+
+ if (kill(s->leader, signo) < 0) {
+ return log_error_errno(errno, "Failed to kill process leader %d for session %s: %m", s->leader, s->id);
+ }
+ return 0;
+ } else {
+ bool sigcont = false;
+ bool ignore_self = true;
+ bool rem = true;
+ return cg_kill_recursive (SYSTEMD_CGROUP_CONTROLLER, s->id, signo,
+ sigcont, ignore_self, rem, NULL);
+ }
}
static int session_open_vt(Session *s) {
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index 539c316ad6..0aac3bcf52 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -562,10 +562,18 @@ UserState user_get_state(User *u) {
}
int user_kill(User *u, int signo) {
+ Session *s;
+ int res = 0;
+
assert(u);
- /* FIXME: No way to kill a user without systemd. */
- return -ESRCH;
+ LIST_FOREACH(sessions_by_user, s, u->sessions) {
+ int r = session_kill(s, KILL_ALL, signo);
+ if (res == 0 && r < 0)
+ res = r;
+ }
+
+ return res;
}
void user_elect_display(User *u) {
diff --git a/src/login/logind.c b/src/login/logind.c
index 49dae036c4..8e8fe19157 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -542,6 +542,35 @@ static int manager_dispatch_console(sd_event_source *s, int fd, uint32_t revents
return 0;
}
+static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+ Session *s;
+ const char *cgroup;
+ int r;
+
+ assert(bus);
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "s", &cgroup);
+ if (r < 0) {
+ bus_log_parse_error(r);
+ return 0;
+ }
+
+ s = hashmap_get(m->sessions, cgroup);
+
+ if (!s) {
+ log_warning("Session not found: %s", cgroup);
+ return 0;
+ }
+
+ session_finalize(s);
+ session_free(s);
+
+ return 0;
+}
+
static int manager_connect_bus(Manager *m) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
@@ -557,6 +586,13 @@ static int manager_connect_bus(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to add manager object vtable: %m");
+ r = sd_bus_add_match(m->bus, NULL,
+ "type='signal',"
+ "interface='org.freedesktop.systemd1.Agent',"
+ "member='Released',"
+ "path='/org/freedesktop/systemd1/agent'",
+ signal_agent_released, m);
+
r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/seat", "org.freedesktop.login1.Seat", seat_vtable, seat_object_find, m);
if (r < 0)
return log_error_errno(r, "Failed to add seat object vtable: %m");