summaryrefslogtreecommitdiff
path: root/src/login/logind-session.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/login/logind-session.c')
-rw-r--r--src/login/logind-session.c141
1 files changed, 109 insertions, 32 deletions
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 16d4955d5d..b64a5d302d 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -25,6 +25,8 @@
#include <sys/epoll.h>
#include <fcntl.h>
+#include "systemd/sd-id128.h"
+#include "systemd/sd-messages.h"
#include "strv.h"
#include "util.h"
#include "mkdir.h"
@@ -32,8 +34,6 @@
#include "cgroup-util.h"
#include "logind-session.h"
-#define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
-
Session* session_new(Manager *m, User *u, const char *id) {
Session *s;
@@ -524,7 +524,9 @@ static int session_create_cgroup(Session *s) {
}
}
- hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
+ r = hashmap_put(s->manager->session_cgroups, s->cgroup_path, s);
+ if (r < 0)
+ log_warning("Failed to create mapping between cgroup and session");
return 0;
}
@@ -542,8 +544,13 @@ int session_start(Session *s) {
if (r < 0)
return r;
- log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
- "New session %s of user %s.", s->id, s->user->name);
+ log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
+ MESSAGE_ID(SD_MESSAGE_SESSION_START),
+ "SESSION_ID=%s", s->id,
+ "USER_ID=%s", s->user->name,
+ "LEADER=%lu", (unsigned long) s->leader,
+ "MESSAGE=New session %s of user %s.", s->id, s->user->name,
+ NULL);
/* Create cgroup */
r = session_create_cgroup(s);
@@ -679,8 +686,13 @@ int session_stop(Session *s) {
assert(s);
if (s->started)
- log_full(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
- "Removed session %s.", s->id);
+ log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG,
+ MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
+ "SESSION_ID=%s", s->id,
+ "USER_ID=%s", s->user->name,
+ "LEADER=%lu", (unsigned long) s->leader,
+ "MESSAGE=Removed session %s.", s->id,
+ NULL);
/* Kill cgroup */
k = session_terminate_cgroup(s);
@@ -702,9 +714,11 @@ int session_stop(Session *s) {
seat_set_active(s->seat, NULL);
seat_send_changed(s->seat, "Sessions\0");
+ seat_save(s->seat);
}
user_send_changed(s->user, "Sessions\0");
+ user_save(s->user);
s->started = false;
@@ -720,15 +734,51 @@ bool session_is_active(Session *s) {
return s->seat->active == s;
}
-int session_get_idle_hint(Session *s, dual_timestamp *t) {
- char *p;
+static int get_tty_atime(const char *tty, usec_t *atime) {
+ _cleanup_free_ char *p = NULL;
struct stat st;
- usec_t u, n;
- bool b;
- int k;
+
+ assert(tty);
+ assert(atime);
+
+ if (!path_is_absolute(tty)) {
+ p = strappend("/dev/", tty);
+ if (!p)
+ return -ENOMEM;
+
+ tty = p;
+ } else if (!path_startswith(tty, "/dev/"))
+ return -ENOENT;
+
+ if (lstat(tty, &st) < 0)
+ return -errno;
+
+ *atime = timespec_load(&st.st_atim);
+ return 0;
+}
+
+static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
+ _cleanup_free_ char *p = NULL;
+ int r;
+
+ assert(pid > 0);
+ assert(atime);
+
+ r = get_ctty(pid, NULL, &p);
+ if (r < 0)
+ return r;
+
+ return get_tty_atime(p, atime);
+}
+
+int session_get_idle_hint(Session *s, dual_timestamp *t) {
+ _cleanup_free_ char *p = NULL;
+ usec_t atime = 0, n;
+ int r;
assert(s);
+ /* Explicit idle hint is set */
if (s->idle_hint) {
if (t)
*t = s->idle_hint_timestamp;
@@ -736,41 +786,65 @@ int session_get_idle_hint(Session *s, dual_timestamp *t) {
return s->idle_hint;
}
- if (isempty(s->tty))
+ /* Graphical sessions really should really implement a real
+ * idle hint logic */
+ if (s->display)
goto dont_know;
- if (s->tty[0] != '/') {
- p = strappend("/dev/", s->tty);
- if (!p)
- return -ENOMEM;
- } else
- p = NULL;
+ /* For sessions with an explicitly configured tty, let's check
+ * its atime */
+ if (s->tty) {
+ r = get_tty_atime(s->tty, &atime);
+ if (r >= 0)
+ goto found_atime;
+ }
- if (!startswith(p ? p : s->tty, "/dev/")) {
- free(p);
- goto dont_know;
+ /* For sessions with a leader but no explicitly configured
+ * tty, let's check the controlling tty of the leader */
+ if (s->leader > 0) {
+ r = get_process_ctty_atime(s->leader, &atime);
+ if (r >= 0)
+ goto found_atime;
}
- k = lstat(p ? p : s->tty, &st);
- free(p);
+ /* For other TTY sessions, let's find the most recent atime of
+ * the ttys of any of the processes of the session */
+ if (s->cgroup_path) {
+ _cleanup_fclose_ FILE *f = NULL;
- if (k < 0)
- goto dont_know;
+ if (cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &f) >= 0) {
+ pid_t pid;
- u = timespec_load(&st.st_atim);
- n = now(CLOCK_REALTIME);
- b = u + IDLE_THRESHOLD_USEC < n;
+ atime = 0;
+ while (cg_read_pid(f, &pid) > 0) {
+ usec_t a;
- if (t)
- dual_timestamp_from_realtime(t, u + b*IDLE_THRESHOLD_USEC);
+ if (get_process_ctty_atime(pid, &a) >= 0)
+ if (atime == 0 || atime < a)
+ atime = a;
+ }
- return b;
+ if (atime != 0)
+ goto found_atime;
+ }
+ }
dont_know:
if (t)
*t = s->idle_hint_timestamp;
return 0;
+
+found_atime:
+ if (t)
+ dual_timestamp_from_realtime(t, atime);
+
+ n = now(CLOCK_REALTIME);
+
+ if (s->manager->idle_action_usec <= 0)
+ return 0;
+
+ return atime + s->manager->idle_action_usec <= n;
}
void session_set_idle_hint(Session *s, bool b) {
@@ -858,6 +932,9 @@ void session_remove_fifo(Session *s) {
assert_se(epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->fifo_fd, NULL) == 0);
close_nointr_nofail(s->fifo_fd);
s->fifo_fd = -1;
+
+ session_save(s);
+ user_save(s->user);
}
if (s->fifo_path) {