X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flogin%2Flogind-session.c;h=71c79127e9a57c96b0441445fb9952923a5e200d;hb=bfa00bc6c05d0f896e9632eccd47d442fea556b9;hp=f670db853c9e65709ab6b420c8b2c34c013b7cc0;hpb=4a271908f1d46e0549a4d9bfc5d0e34266887695;p=elogind.git diff --git a/src/login/logind-session.c b/src/login/logind-session.c index f670db853..71c79127e 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -33,8 +33,7 @@ #include "path-util.h" #include "cgroup-util.h" #include "logind-session.h" - -#define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE) +#include "fileio.h" Session* session_new(Manager *m, User *u, const char *id) { Session *s; @@ -526,7 +525,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; } @@ -545,7 +546,7 @@ int session_start(Session *s) { return r; log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG, - "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_SESSION_START), + MESSAGE_ID(SD_MESSAGE_SESSION_START), "SESSION_ID=%s", s->id, "USER_ID=%s", s->user->name, "LEADER=%lu", (unsigned long) s->leader, @@ -687,7 +688,7 @@ int session_stop(Session *s) { if (s->started) log_struct(s->type == SESSION_TTY || s->type == SESSION_X11 ? LOG_INFO : LOG_DEBUG, - "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_SESSION_STOP), + MESSAGE_ID(SD_MESSAGE_SESSION_STOP), "SESSION_ID=%s", s->id, "USER_ID=%s", s->user->name, "LEADER=%lu", (unsigned long) s->leader, @@ -734,14 +735,50 @@ 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; - 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) { + 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; @@ -749,40 +786,65 @@ int session_get_idle_hint(Session *s, dual_timestamp *t) { return s->idle_hint; } - if (isempty(s->tty)) + /* Graphical sessions 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); + atime = 0; + while (cg_read_pid(f, &pid) > 0) { + usec_t a; - if (t) - dual_timestamp_from_realtime(t, u); + if (get_process_ctty_atime(pid, &a) >= 0) + if (atime == 0 || atime < a) + atime = a; + } - return u + IDLE_THRESHOLD_USEC < n; + 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) {