1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-16 03:24:49 +03:00

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.
This commit is contained in:
Michal Sekletar 2022-08-08 09:13:50 +02:00
parent 4ee8176fe3
commit 82325af3ae
9 changed files with 90 additions and 3 deletions

View File

@ -344,6 +344,17 @@
are excluded from the effect of this setting. Defaults to <literal>yes</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>

View File

@ -245,6 +245,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 { ... };
@ -262,6 +264,8 @@ node /org/freedesktop/login1 {
<!--property HandleHibernateKeyLongPress is not documented!-->
<!--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"/>
@ -490,6 +494,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>

View File

@ -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) {

View File

@ -3402,6 +3402,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),

View File

@ -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)

View File

@ -152,6 +152,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);
}
@ -697,6 +699,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;
@ -719,6 +770,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,
@ -959,7 +1014,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);
@ -996,10 +1051,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) {

View File

@ -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);

View File

@ -46,3 +46,4 @@
#RemoveIPC=yes
#InhibitorsMax=8192
#SessionsMax=8192
#StopIdleSessionSec=infinity

View File

@ -96,6 +96,8 @@ struct Manager {
HandleAction idle_action;
bool was_idle;
usec_t stop_idle_session_usec;
HandleAction handle_power_key;
HandleAction handle_power_key_long_press;
HandleAction handle_reboot_key;