You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
9.8 KiB
254 lines
9.8 KiB
From a8980738c4ef8fba4fd8995ab69669d438ad7a9f Mon Sep 17 00:00:00 2001 |
|
From: Michal Sekletar <msekleta@redhat.com> |
|
Date: Mon, 8 Aug 2022 09:13:50 +0200 |
|
Subject: [PATCH] logind: add option to stop idle sessions after specified |
|
timeout |
|
|
|
Thanks to Jan Pazdziora <jpazdziora@redhat.com> for providing a patch |
|
which implemeted a PoC of this feature. |
|
|
|
(cherry picked from commit 82325af3ae41bc7efb3d5cd8f56a4652fef498c2) |
|
|
|
Resolves: #2100464 |
|
--- |
|
man/logind.conf.xml | 11 ++++++ |
|
man/org.freedesktop.login1.xml | 6 +++ |
|
src/login/logind-core.c | 2 + |
|
src/login/logind-dbus.c | 1 + |
|
src/login/logind-gperf.gperf | 1 + |
|
src/login/logind-session.c | 67 ++++++++++++++++++++++++++++++++-- |
|
src/login/logind-session.h | 2 + |
|
src/login/logind.conf.in | 1 + |
|
src/login/logind.h | 2 + |
|
9 files changed, 90 insertions(+), 3 deletions(-) |
|
|
|
diff --git a/man/logind.conf.xml b/man/logind.conf.xml |
|
index 96fa076239..c37fd97be1 100644 |
|
--- a/man/logind.conf.xml |
|
+++ b/man/logind.conf.xml |
|
@@ -357,6 +357,17 @@ |
|
are excluded from the effect of this setting. Defaults to <literal>no</literal>.</para></listitem> |
|
</varlistentry> |
|
|
|
+ <varlistentry> |
|
+ <term><varname>StopIdleSessionSec=</varname></term> |
|
+ |
|
+ <listitem><para>Specifies a timeout in seconds, or a time span value after which |
|
+ <filename>systemd-logind</filename> checks the idle state of all sessions. Every session that is idle for |
|
+ longer then the timeout will be stopped. Defaults to <literal>infinity</literal> |
|
+ (<filename>systemd-logind</filename> is not checking the idle state of sessions). For details about the syntax |
|
+ of time spans, see |
|
+ <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>. |
|
+ </para></listitem> |
|
+ </varlistentry> |
|
</variablelist> |
|
</refsect1> |
|
|
|
diff --git a/man/org.freedesktop.login1.xml b/man/org.freedesktop.login1.xml |
|
index c11324ee3b..0ebcfb84ab 100644 |
|
--- a/man/org.freedesktop.login1.xml |
|
+++ b/man/org.freedesktop.login1.xml |
|
@@ -235,6 +235,8 @@ node /org/freedesktop/login1 { |
|
readonly t SessionsMax = ...; |
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false") |
|
readonly t NCurrentSessions = ...; |
|
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const") |
|
+ readonly t StopIdleSessionUSec = ...; |
|
}; |
|
interface org.freedesktop.DBus.Peer { ... }; |
|
interface org.freedesktop.DBus.Introspectable { ... }; |
|
@@ -242,6 +244,8 @@ node /org/freedesktop/login1 { |
|
}; |
|
</programlisting> |
|
|
|
+ <!--property StopIdleSessionUSec is not documented!--> |
|
+ |
|
<!--Autogenerated cross-references for systemd.directives, do not edit--> |
|
|
|
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.login1.Manager"/> |
|
@@ -460,6 +464,8 @@ node /org/freedesktop/login1 { |
|
|
|
<variablelist class="dbus-property" generated="True" extra-ref="NCurrentSessions"/> |
|
|
|
+ <variablelist class="dbus-property" generated="True" extra-ref="StopIdleSessionUSec"/> |
|
+ |
|
<!--End of Autogenerated section--> |
|
|
|
<refsect2> |
|
diff --git a/src/login/logind-core.c b/src/login/logind-core.c |
|
index 616c08132a..9807c85b8c 100644 |
|
--- a/src/login/logind-core.c |
|
+++ b/src/login/logind-core.c |
|
@@ -71,6 +71,8 @@ void manager_reset_config(Manager *m) { |
|
|
|
m->kill_only_users = strv_free(m->kill_only_users); |
|
m->kill_exclude_users = strv_free(m->kill_exclude_users); |
|
+ |
|
+ m->stop_idle_session_usec = USEC_INFINITY; |
|
} |
|
|
|
int manager_parse_config_file(Manager *m) { |
|
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c |
|
index 31a41bd271..c97a89c37d 100644 |
|
--- a/src/login/logind-dbus.c |
|
+++ b/src/login/logind-dbus.c |
|
@@ -3389,6 +3389,7 @@ static const sd_bus_vtable manager_vtable[] = { |
|
SD_BUS_PROPERTY("SessionsMax", "t", NULL, offsetof(Manager, sessions_max), SD_BUS_VTABLE_PROPERTY_CONST), |
|
SD_BUS_PROPERTY("NCurrentSessions", "t", property_get_hashmap_size, offsetof(Manager, sessions), 0), |
|
SD_BUS_PROPERTY("UserTasksMax", "t", property_get_compat_user_tasks_max, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), |
|
+ SD_BUS_PROPERTY("StopIdleSessionUSec", "t", NULL, offsetof(Manager, stop_idle_session_usec), SD_BUS_VTABLE_PROPERTY_CONST), |
|
|
|
SD_BUS_METHOD_WITH_ARGS("GetSession", |
|
SD_BUS_ARGS("s", session_id), |
|
diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf |
|
index 867db36533..300d56542d 100644 |
|
--- a/src/login/logind-gperf.gperf |
|
+++ b/src/login/logind-gperf.gperf |
|
@@ -50,3 +50,4 @@ Login.RemoveIPC, config_parse_bool, 0, offse |
|
Login.InhibitorsMax, config_parse_uint64, 0, offsetof(Manager, inhibitors_max) |
|
Login.SessionsMax, config_parse_uint64, 0, offsetof(Manager, sessions_max) |
|
Login.UserTasksMax, config_parse_compat_user_tasks_max, 0, 0 |
|
+Login.StopIdleSessionSec, config_parse_sec_fix_0, 0, offsetof(Manager, stop_idle_session_usec) |
|
diff --git a/src/login/logind-session.c b/src/login/logind-session.c |
|
index a052596e57..a110b6f1c1 100644 |
|
--- a/src/login/logind-session.c |
|
+++ b/src/login/logind-session.c |
|
@@ -150,6 +150,8 @@ Session* session_free(Session *s) { |
|
free(s->state_file); |
|
free(s->fifo_path); |
|
|
|
+ sd_event_source_unref(s->stop_on_idle_event_source); |
|
+ |
|
return mfree(s); |
|
} |
|
|
|
@@ -687,6 +689,55 @@ static int session_start_scope(Session *s, sd_bus_message *properties, sd_bus_er |
|
return 0; |
|
} |
|
|
|
+static int session_dispatch_stop_on_idle(sd_event_source *source, uint64_t t, void *userdata) { |
|
+ Session *s = userdata; |
|
+ dual_timestamp ts; |
|
+ int r, idle; |
|
+ |
|
+ assert(s); |
|
+ |
|
+ if (s->stopping) |
|
+ return 0; |
|
+ |
|
+ idle = session_get_idle_hint(s, &ts); |
|
+ if (idle) { |
|
+ log_debug("Session \"%s\" of user \"%s\" is idle, stopping.", s->id, s->user->user_record->user_name); |
|
+ |
|
+ return session_stop(s, /* force */ true); |
|
+ } |
|
+ |
|
+ r = sd_event_source_set_time(source, usec_add(ts.monotonic, s->manager->stop_idle_session_usec)); |
|
+ if (r < 0) |
|
+ return log_error_errno(r, "Failed to configure stop on idle session event source: %m"); |
|
+ |
|
+ r = sd_event_source_set_enabled(source, SD_EVENT_ONESHOT); |
|
+ if (r < 0) |
|
+ return log_error_errno(r, "Failed to enable stop on idle session event source: %m"); |
|
+ |
|
+ return 1; |
|
+} |
|
+ |
|
+static int session_setup_stop_on_idle_timer(Session *s) { |
|
+ int r; |
|
+ |
|
+ assert(s); |
|
+ |
|
+ if (s->manager->stop_idle_session_usec == USEC_INFINITY) |
|
+ return 0; |
|
+ |
|
+ r = sd_event_add_time_relative( |
|
+ s->manager->event, |
|
+ &s->stop_on_idle_event_source, |
|
+ CLOCK_MONOTONIC, |
|
+ s->manager->stop_idle_session_usec, |
|
+ 0, |
|
+ session_dispatch_stop_on_idle, s); |
|
+ if (r < 0) |
|
+ return log_error_errno(r, "Failed to add stop on idle session event source: %m"); |
|
+ |
|
+ return 0; |
|
+} |
|
+ |
|
int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error) { |
|
int r; |
|
|
|
@@ -709,6 +760,10 @@ int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error) { |
|
if (r < 0) |
|
return r; |
|
|
|
+ r = session_setup_stop_on_idle_timer(s); |
|
+ if (r < 0) |
|
+ return r; |
|
+ |
|
log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO, |
|
"MESSAGE_ID=" SD_MESSAGE_SESSION_START_STR, |
|
"SESSION_ID=%s", s->id, |
|
@@ -949,7 +1004,7 @@ static int get_process_ctty_atime(pid_t pid, usec_t *atime) { |
|
} |
|
|
|
int session_get_idle_hint(Session *s, dual_timestamp *t) { |
|
- usec_t atime = 0; |
|
+ usec_t atime = 0, dtime = 0; |
|
int r; |
|
|
|
assert(s); |
|
@@ -986,10 +1041,16 @@ found_atime: |
|
if (t) |
|
dual_timestamp_from_realtime(t, atime); |
|
|
|
- if (s->manager->idle_action_usec <= 0) |
|
+ if (s->manager->idle_action_usec > 0 && s->manager->stop_idle_session_usec != USEC_INFINITY) |
|
+ dtime = MIN(s->manager->idle_action_usec, s->manager->stop_idle_session_usec); |
|
+ else if (s->manager->idle_action_usec > 0) |
|
+ dtime = s->manager->idle_action_usec; |
|
+ else if (s->manager->stop_idle_session_usec != USEC_INFINITY) |
|
+ dtime = s->manager->stop_idle_session_usec; |
|
+ else |
|
return false; |
|
|
|
- return usec_add(atime, s->manager->idle_action_usec) <= now(CLOCK_REALTIME); |
|
+ return usec_add(atime, dtime) <= now(CLOCK_REALTIME); |
|
} |
|
|
|
int session_set_idle_hint(Session *s, bool b) { |
|
diff --git a/src/login/logind-session.h b/src/login/logind-session.h |
|
index 6b6ac2d573..4c28607986 100644 |
|
--- a/src/login/logind-session.h |
|
+++ b/src/login/logind-session.h |
|
@@ -115,6 +115,8 @@ struct Session { |
|
Hashmap *devices; |
|
sd_bus_track *track; |
|
|
|
+ sd_event_source *stop_on_idle_event_source; |
|
+ |
|
LIST_FIELDS(Session, sessions_by_user); |
|
LIST_FIELDS(Session, sessions_by_seat); |
|
|
|
diff --git a/src/login/logind.conf.in b/src/login/logind.conf.in |
|
index 79d685b3de..fcdbad58c7 100644 |
|
--- a/src/login/logind.conf.in |
|
+++ b/src/login/logind.conf.in |
|
@@ -43,3 +43,4 @@ |
|
#RemoveIPC=no |
|
#InhibitorsMax=8192 |
|
#SessionsMax=8192 |
|
+#StopIdleSessionSec=infinity |
|
diff --git a/src/login/logind.h b/src/login/logind.h |
|
index 730c14a46a..e5c68a74cb 100644 |
|
--- a/src/login/logind.h |
|
+++ b/src/login/logind.h |
|
@@ -101,6 +101,8 @@ struct Manager { |
|
usec_t idle_action_not_before_usec; |
|
HandleAction idle_action; |
|
|
|
+ usec_t stop_idle_session_usec; |
|
+ |
|
HandleAction handle_power_key; |
|
HandleAction handle_power_key_long_press; |
|
HandleAction handle_reboot_key;
|
|
|