mirror of
https://github.com/systemd/systemd.git
synced 2025-03-19 22:50:17 +03:00
logind: implement idle hint logic
This commit is contained in:
parent
91f9dcaf92
commit
a185c5aa2d
@ -19,6 +19,9 @@
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "logind.h"
|
||||
#include "dbus-common.h"
|
||||
|
||||
@ -62,6 +65,9 @@
|
||||
" <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
|
||||
" <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <method name=\"ActivateSession\">\n" \
|
||||
" <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <method name=\"TerminateSession\">\n" \
|
||||
" <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
|
||||
" </method>\n" \
|
||||
@ -102,6 +108,9 @@
|
||||
" <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
|
||||
" <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
|
||||
" <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
|
||||
" <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
|
||||
" <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
|
||||
" <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
|
||||
" </interface>\n"
|
||||
|
||||
#define INTROSPECTION_BEGIN \
|
||||
@ -119,6 +128,39 @@
|
||||
BUS_GENERIC_INTERFACES_LIST \
|
||||
"org.freedesktop.login1.Manager\0"
|
||||
|
||||
static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
|
||||
Manager *m = data;
|
||||
bool b;
|
||||
|
||||
assert(i);
|
||||
assert(property);
|
||||
assert(m);
|
||||
|
||||
b = manager_get_idle_hint(m, NULL);
|
||||
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
|
||||
Manager *m = data;
|
||||
dual_timestamp t;
|
||||
uint64_t u;
|
||||
|
||||
assert(i);
|
||||
assert(property);
|
||||
assert(m);
|
||||
|
||||
manager_get_idle_hint(m, &t);
|
||||
u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
|
||||
|
||||
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DBusHandlerResult manager_message_handler(
|
||||
DBusConnection *connection,
|
||||
DBusMessage *message,
|
||||
@ -127,13 +169,16 @@ static DBusHandlerResult manager_message_handler(
|
||||
Manager *m = userdata;
|
||||
|
||||
const BusProperty properties[] = {
|
||||
{ "org.freedesktop.login1.Manager", "ControlGroupHierarchy", bus_property_append_string, "s", m->cgroup_path },
|
||||
{ "org.freedesktop.login1.Manager", "Controllers", bus_property_append_strv, "as", m->controllers },
|
||||
{ "org.freedesktop.login1.Manager", "ResetControllers", bus_property_append_strv, "as", m->reset_controllers },
|
||||
{ "org.freedesktop.login1.Manager", "NAutoVTs", bus_property_append_unsigned, "u", &m->n_autovts },
|
||||
{ "org.freedesktop.login1.Manager", "KillOnlyUsers", bus_property_append_strv, "as", m->kill_only_users },
|
||||
{ "org.freedesktop.login1.Manager", "KillExcludeUsers", bus_property_append_strv, "as", m->kill_exclude_users },
|
||||
{ "org.freedesktop.login1.Manager", "KillUserProcesses", bus_property_append_bool, "b", &m->kill_user_processes },
|
||||
{ "org.freedesktop.login1.Manager", "ControlGroupHierarchy", bus_property_append_string, "s", m->cgroup_path },
|
||||
{ "org.freedesktop.login1.Manager", "Controllers", bus_property_append_strv, "as", m->controllers },
|
||||
{ "org.freedesktop.login1.Manager", "ResetControllers", bus_property_append_strv, "as", m->reset_controllers },
|
||||
{ "org.freedesktop.login1.Manager", "NAutoVTs", bus_property_append_unsigned, "u", &m->n_autovts },
|
||||
{ "org.freedesktop.login1.Manager", "KillOnlyUsers", bus_property_append_strv, "as", m->kill_only_users },
|
||||
{ "org.freedesktop.login1.Manager", "KillExcludeUsers", bus_property_append_strv, "as", m->kill_exclude_users },
|
||||
{ "org.freedesktop.login1.Manager", "KillUserProcesses", bus_property_append_bool, "b", &m->kill_user_processes },
|
||||
{ "org.freedesktop.login1.Manager", "IdleHint", bus_manager_append_idle_hint, "b", m },
|
||||
{ "org.freedesktop.login1.Manager", "IdleSinceHint", bus_manager_append_idle_hint_since, "t", m },
|
||||
{ "org.freedesktop.login1.Manager", "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", m },
|
||||
{ NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "logind.h"
|
||||
#include "logind-seat.h"
|
||||
@ -36,6 +37,9 @@
|
||||
" <property name=\"ActiveSession\" type=\"so\" access=\"read\"/>\n" \
|
||||
" <property name=\"CanActivateSessions\" type=\"b\" access=\"read\"/>\n" \
|
||||
" <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
|
||||
" <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
|
||||
" <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
|
||||
" <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
|
||||
" </interface>\n" \
|
||||
|
||||
#define INTROSPECTION \
|
||||
@ -129,7 +133,6 @@ static int bus_seat_append_sessions(DBusMessageIter *i, const char *property, vo
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int bus_seat_append_can_activate(DBusMessageIter *i, const char *property, void *data) {
|
||||
Seat *s = data;
|
||||
dbus_bool_t b;
|
||||
@ -138,7 +141,7 @@ static int bus_seat_append_can_activate(DBusMessageIter *i, const char *property
|
||||
assert(property);
|
||||
assert(s);
|
||||
|
||||
b = s->manager->vtconsole == s;
|
||||
b = seat_is_vtconsole(s);
|
||||
|
||||
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
|
||||
return -ENOMEM;
|
||||
@ -146,6 +149,39 @@ static int bus_seat_append_can_activate(DBusMessageIter *i, const char *property
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bus_seat_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
|
||||
Seat *s = data;
|
||||
bool b;
|
||||
|
||||
assert(i);
|
||||
assert(property);
|
||||
assert(s);
|
||||
|
||||
b = seat_get_idle_hint(s, NULL);
|
||||
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bus_seat_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
|
||||
Seat *s = data;
|
||||
dual_timestamp t;
|
||||
uint64_t k;
|
||||
|
||||
assert(i);
|
||||
assert(property);
|
||||
assert(s);
|
||||
|
||||
seat_get_idle_hint(s, &t);
|
||||
k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
|
||||
|
||||
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &k))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_seat_for_path(Manager *m, const char *path, Seat **_s) {
|
||||
Seat *s;
|
||||
char *id;
|
||||
@ -181,14 +217,73 @@ static DBusHandlerResult seat_message_dispatch(
|
||||
{ "org.freedesktop.login1.Seat", "ActiveSession", bus_seat_append_active, "(so)", s },
|
||||
{ "org.freedesktop.login1.Seat", "CanActivateSessions", bus_seat_append_can_activate, "b", s },
|
||||
{ "org.freedesktop.login1.Seat", "Sessions", bus_seat_append_sessions, "a(so)", s },
|
||||
{ "org.freedesktop.login1.Seat", "IdleHint", bus_seat_append_idle_hint, "b", s },
|
||||
{ "org.freedesktop.login1.Seat", "IdleSinceHint", bus_seat_append_idle_hint_since, "t", s },
|
||||
{ "org.freedesktop.login1.Seat", "IdleSinceHintMonotonic", bus_seat_append_idle_hint_since, "t", s },
|
||||
{ NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
DBusError error;
|
||||
DBusMessage *reply = NULL;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(connection);
|
||||
assert(message);
|
||||
|
||||
return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
|
||||
dbus_error_init(&error);
|
||||
|
||||
if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "Terminate")) {
|
||||
|
||||
r = seat_stop_sessions(s);
|
||||
if (r < 0)
|
||||
return bus_send_error_reply(connection, message, NULL, r);
|
||||
|
||||
reply = dbus_message_new_method_return(message);
|
||||
if (!reply)
|
||||
goto oom;
|
||||
|
||||
} else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "ActivateSession")) {
|
||||
const char *name;
|
||||
Session *session;
|
||||
|
||||
if (!dbus_message_get_args(
|
||||
message,
|
||||
&error,
|
||||
DBUS_TYPE_STRING, &name,
|
||||
DBUS_TYPE_INVALID))
|
||||
return bus_send_error_reply(connection, message, &error, -EINVAL);
|
||||
|
||||
session = hashmap_get(s->manager->sessions, name);
|
||||
if (!session || session->seat != s)
|
||||
return bus_send_error_reply(connection, message, &error, -ENOENT);
|
||||
|
||||
r = session_activate(session);
|
||||
if (r < 0)
|
||||
return bus_send_error_reply(connection, message, NULL, r);
|
||||
|
||||
reply = dbus_message_new_method_return(message);
|
||||
if (!reply)
|
||||
goto oom;
|
||||
} else
|
||||
return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
|
||||
|
||||
if (reply) {
|
||||
if (!dbus_connection_send(connection, reply, NULL))
|
||||
goto oom;
|
||||
|
||||
dbus_message_unref(reply);
|
||||
}
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
|
||||
oom:
|
||||
if (reply)
|
||||
dbus_message_unref(reply);
|
||||
|
||||
dbus_error_free(&error);
|
||||
|
||||
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
||||
}
|
||||
|
||||
static DBusHandlerResult seat_message_handler(
|
||||
|
@ -99,7 +99,7 @@ int seat_save(Seat *s) {
|
||||
fprintf(f,
|
||||
"# This is private data. Do not parse.\n"
|
||||
"IS_VTCONSOLE=%i\n",
|
||||
s->manager->vtconsole == s);
|
||||
seat_is_vtconsole(s));
|
||||
|
||||
if (s->active) {
|
||||
assert(s->active->user);
|
||||
@ -158,6 +158,8 @@ finish:
|
||||
int seat_load(Seat *s) {
|
||||
assert(s);
|
||||
|
||||
/* There isn't actually anything to read here ... */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -191,7 +193,7 @@ static int seat_preallocate_vts(Seat *s) {
|
||||
if (s->manager->n_autovts <= 0)
|
||||
return 0;
|
||||
|
||||
if (s->manager->vtconsole != s)
|
||||
if (!seat_is_vtconsole(s))
|
||||
return 0;
|
||||
|
||||
for (i = 1; i < s->manager->n_autovts; i++) {
|
||||
@ -230,7 +232,7 @@ int seat_active_vt_changed(Seat *s, int vtnr) {
|
||||
assert(s);
|
||||
assert(vtnr >= 1);
|
||||
|
||||
if (s->manager->vtconsole != s)
|
||||
if (!seat_is_vtconsole(s))
|
||||
return -EINVAL;
|
||||
|
||||
log_debug("VT changed to %i", vtnr);
|
||||
@ -260,7 +262,7 @@ int seat_read_active_vt(Seat *s) {
|
||||
|
||||
assert(s);
|
||||
|
||||
if (s->manager->vtconsole != s)
|
||||
if (!seat_is_vtconsole(s))
|
||||
return 0;
|
||||
|
||||
lseek(s->manager->console_active_fd, SEEK_SET, 0);
|
||||
@ -316,8 +318,7 @@ int seat_start(Seat *s) {
|
||||
}
|
||||
|
||||
int seat_stop(Seat *s) {
|
||||
Session *session;
|
||||
int r = 0, k;
|
||||
int r = 0;
|
||||
|
||||
assert(s);
|
||||
|
||||
@ -326,11 +327,7 @@ int seat_stop(Seat *s) {
|
||||
|
||||
log_info("Removed seat %s.", s->id);
|
||||
|
||||
LIST_FOREACH(sessions_by_seat, session, s->sessions) {
|
||||
k = session_stop(session);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
seat_stop_sessions(s);
|
||||
|
||||
unlink(s->state_file);
|
||||
seat_add_to_gc_queue(s);
|
||||
@ -340,10 +337,86 @@ int seat_stop(Seat *s) {
|
||||
return r;
|
||||
}
|
||||
|
||||
int seat_stop_sessions(Seat *s) {
|
||||
Session *session;
|
||||
int r = 0, k;
|
||||
|
||||
assert(s);
|
||||
|
||||
LIST_FOREACH(sessions_by_seat, session, s->sessions) {
|
||||
k = session_stop(session);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int seat_attach_session(Seat *s, Session *session) {
|
||||
assert(s);
|
||||
assert(session);
|
||||
assert(!session->seat);
|
||||
|
||||
if (!seat_is_vtconsole(s)) {
|
||||
if (s->sessions)
|
||||
return -EEXIST;
|
||||
|
||||
assert(!s->active);
|
||||
s->active = session;
|
||||
}
|
||||
|
||||
session->seat = s;
|
||||
LIST_PREPEND(Session, sessions_by_seat, s->sessions, session);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool seat_is_vtconsole(Seat *s) {
|
||||
assert(s);
|
||||
|
||||
return s->manager->vtconsole == s;
|
||||
}
|
||||
|
||||
int seat_get_idle_hint(Seat *s, dual_timestamp *t) {
|
||||
Session *session;
|
||||
bool idle_hint = true;
|
||||
dual_timestamp ts = { 0, 0 };
|
||||
|
||||
assert(s);
|
||||
|
||||
LIST_FOREACH(sessions_by_seat, session, s->sessions) {
|
||||
dual_timestamp k;
|
||||
int ih;
|
||||
|
||||
ih = session_get_idle_hint(session, &k);
|
||||
if (ih < 0)
|
||||
return ih;
|
||||
|
||||
if (!ih) {
|
||||
if (!idle_hint) {
|
||||
if (k.monotonic < ts.monotonic)
|
||||
ts = k;
|
||||
} else {
|
||||
idle_hint = false;
|
||||
ts = k;
|
||||
}
|
||||
} else if (idle_hint) {
|
||||
|
||||
if (k.monotonic > ts.monotonic)
|
||||
ts = k;
|
||||
}
|
||||
}
|
||||
|
||||
if (t)
|
||||
*t = ts;
|
||||
|
||||
return idle_hint;
|
||||
}
|
||||
|
||||
int seat_check_gc(Seat *s) {
|
||||
assert(s);
|
||||
|
||||
if (s->manager->vtconsole == s)
|
||||
if (seat_is_vtconsole(s))
|
||||
return 1;
|
||||
|
||||
return !!s->devices;
|
||||
|
@ -57,8 +57,14 @@ int seat_apply_acls(Seat *s, Session *old_active);
|
||||
int seat_active_vt_changed(Seat *s, int vtnr);
|
||||
int seat_read_active_vt(Seat *s);
|
||||
|
||||
int seat_attach_session(Seat *s, Session *session);
|
||||
|
||||
bool seat_is_vtconsole(Seat *s);
|
||||
int seat_get_idle_hint(Seat *s, dual_timestamp *t);
|
||||
|
||||
int seat_start(Seat *s);
|
||||
int seat_stop(Seat *s);
|
||||
int seat_stop_sessions(Seat *s);
|
||||
|
||||
int seat_check_gc(Seat *s);
|
||||
void seat_add_to_gc_queue(Seat *s);
|
||||
|
@ -20,6 +20,7 @@
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "logind.h"
|
||||
#include "logind-session.h"
|
||||
@ -156,6 +157,39 @@ static int bus_session_append_active(DBusMessageIter *i, const char *property, v
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bus_session_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
|
||||
Session *s = data;
|
||||
bool b;
|
||||
|
||||
assert(i);
|
||||
assert(property);
|
||||
assert(s);
|
||||
|
||||
b = session_get_idle_hint(s, NULL);
|
||||
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bus_session_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
|
||||
Session *s = data;
|
||||
dual_timestamp t;
|
||||
uint64_t u;
|
||||
|
||||
assert(i);
|
||||
assert(property);
|
||||
assert(s);
|
||||
|
||||
session_get_idle_hint(s, &t);
|
||||
u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
|
||||
|
||||
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_type, session_type, SessionType);
|
||||
|
||||
static int get_session_for_path(Manager *m, const char *path, Session **_s) {
|
||||
@ -189,24 +223,29 @@ static DBusHandlerResult session_message_dispatch(
|
||||
DBusMessage *message) {
|
||||
|
||||
const BusProperty properties[] = {
|
||||
{ "org.freedesktop.login1.Session", "Id", bus_property_append_string, "s", s->id },
|
||||
{ "org.freedesktop.login1.Session", "User", bus_session_append_user, "(uo)", s },
|
||||
{ "org.freedesktop.login1.Session", "Name", bus_property_append_string, "s", s->user->name },
|
||||
{ "org.freedesktop.login1.Session", "ControlGroupPath", bus_property_append_string, "s", s->cgroup_path },
|
||||
{ "org.freedesktop.login1.Session", "VTNr", bus_property_append_uint32, "u", &s->vtnr },
|
||||
{ "org.freedesktop.login1.Session", "Seat", bus_session_append_seat, "(so)", s },
|
||||
{ "org.freedesktop.login1.Session", "TTY", bus_property_append_string, "s", s->tty },
|
||||
{ "org.freedesktop.login1.Session", "Display", bus_property_append_string, "s", s->display },
|
||||
{ "org.freedesktop.login1.Session", "Remote", bus_property_append_bool, "b", &s->remote },
|
||||
{ "org.freedesktop.login1.Session", "RemoteUser", bus_property_append_string, "s", s->remote_user },
|
||||
{ "org.freedesktop.login1.Session", "RemoteHost", bus_property_append_string, "s", s->remote_host },
|
||||
{ "org.freedesktop.login1.Session", "Leader", bus_property_append_pid, "u", &s->leader },
|
||||
{ "org.freedesktop.login1.Session", "Audit", bus_property_append_uint32, "u", &s->audit_id },
|
||||
{ "org.freedesktop.login1.Session", "Type", bus_session_append_type, "s", &s->type },
|
||||
{ "org.freedesktop.login1.Session", "Active", bus_session_append_active, "b", s },
|
||||
{ "org.freedesktop.login1.Session", "Controllers", bus_property_append_strv, "as", s->controllers },
|
||||
{ "org.freedesktop.login1.Session", "ResetControllers", bus_property_append_strv, "as", s->reset_controllers },
|
||||
{ "org.freedesktop.login1.Session", "KillProcesses", bus_property_append_bool, "b", &s->kill_processes },
|
||||
{ "org.freedesktop.login1.Session", "Id", bus_property_append_string, "s", s->id },
|
||||
{ "org.freedesktop.login1.Session", "User", bus_session_append_user, "(uo)", s },
|
||||
{ "org.freedesktop.login1.Session", "Name", bus_property_append_string, "s", s->user->name },
|
||||
{ "org.freedesktop.login1.Session", "Timestamp", bus_property_append_usec, "t", &s->timestamp.realtime },
|
||||
{ "org.freedesktop.login1.Session", "TimestampMonotonic", bus_property_append_usec, "t", &s->timestamp.monotonic },
|
||||
{ "org.freedesktop.login1.Session", "ControlGroupPath", bus_property_append_string, "s", s->cgroup_path },
|
||||
{ "org.freedesktop.login1.Session", "VTNr", bus_property_append_uint32, "u", &s->vtnr },
|
||||
{ "org.freedesktop.login1.Session", "Seat", bus_session_append_seat, "(so)", s },
|
||||
{ "org.freedesktop.login1.Session", "TTY", bus_property_append_string, "s", s->tty },
|
||||
{ "org.freedesktop.login1.Session", "Display", bus_property_append_string, "s", s->display },
|
||||
{ "org.freedesktop.login1.Session", "Remote", bus_property_append_bool, "b", &s->remote },
|
||||
{ "org.freedesktop.login1.Session", "RemoteUser", bus_property_append_string, "s", s->remote_user },
|
||||
{ "org.freedesktop.login1.Session", "RemoteHost", bus_property_append_string, "s", s->remote_host },
|
||||
{ "org.freedesktop.login1.Session", "Leader", bus_property_append_pid, "u", &s->leader },
|
||||
{ "org.freedesktop.login1.Session", "Audit", bus_property_append_uint32, "u", &s->audit_id },
|
||||
{ "org.freedesktop.login1.Session", "Type", bus_session_append_type, "s", &s->type },
|
||||
{ "org.freedesktop.login1.Session", "Active", bus_session_append_active, "b", s },
|
||||
{ "org.freedesktop.login1.Session", "Controllers", bus_property_append_strv, "as", s->controllers },
|
||||
{ "org.freedesktop.login1.Session", "ResetControllers", bus_property_append_strv, "as", s->reset_controllers },
|
||||
{ "org.freedesktop.login1.Session", "KillProcesses", bus_property_append_bool, "b", &s->kill_processes },
|
||||
{ "org.freedesktop.login1.Session", "IdleHint", bus_session_append_idle_hint, "b", s },
|
||||
{ "org.freedesktop.login1.Session", "IdleSinceHint", bus_session_append_idle_hint_since, "t", s },
|
||||
{ "org.freedesktop.login1.Session", "IdleSinceHintMonotonic", bus_session_append_idle_hint_since, "t", s },
|
||||
{ NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include "util.h"
|
||||
#include "cgroup-util.h"
|
||||
|
||||
#define IDLE_THRESHOLD_USEC (5*USEC_PER_MINUTE)
|
||||
|
||||
Session* session_new(Manager *m, User *u, const char *id) {
|
||||
Session *s;
|
||||
|
||||
@ -153,7 +155,7 @@ int session_save(Session *s) {
|
||||
"REMOTE_USER=%s\n",
|
||||
s->remote_user);
|
||||
|
||||
if (s->seat && s->seat->manager->vtconsole == s->seat)
|
||||
if (s->seat && seat_is_vtconsole(s->seat))
|
||||
fprintf(f,
|
||||
"VTNR=%i\n",
|
||||
s->vtnr);
|
||||
@ -187,9 +189,87 @@ finish:
|
||||
}
|
||||
|
||||
int session_load(Session *s) {
|
||||
char *remote = NULL,
|
||||
*kill_processes = NULL,
|
||||
*seat = NULL,
|
||||
*vtnr = NULL,
|
||||
*leader = NULL,
|
||||
*audit_id = NULL;
|
||||
|
||||
int k, r;
|
||||
|
||||
assert(s);
|
||||
|
||||
return 0;
|
||||
r = parse_env_file(s->state_file, NEWLINE,
|
||||
"REMOTE", &remote,
|
||||
"KILL_PROCESSES", &kill_processes,
|
||||
"CGROUP", &s->cgroup_path,
|
||||
"SEAT", &seat,
|
||||
"TTY", &s->tty,
|
||||
"DISPLAY", &s->display,
|
||||
"REMOTE_HOST", &s->remote_host,
|
||||
"REMOTE_USER", &s->remote_user,
|
||||
"VTNR", &vtnr,
|
||||
"LEADER", &leader,
|
||||
"AUDIT_ID", &audit_id,
|
||||
NULL);
|
||||
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
if (remote) {
|
||||
k = parse_boolean(remote);
|
||||
if (k >= 0)
|
||||
s->remote = k;
|
||||
}
|
||||
|
||||
if (kill_processes) {
|
||||
k = parse_boolean(kill_processes);
|
||||
if (k >= 0)
|
||||
s->kill_processes = k;
|
||||
}
|
||||
|
||||
if (seat) {
|
||||
Seat *o;
|
||||
|
||||
o = hashmap_get(s->manager->seats, seat);
|
||||
if (o)
|
||||
seat_attach_session(o, s);
|
||||
}
|
||||
|
||||
if (vtnr && s->seat && seat_is_vtconsole(s->seat)) {
|
||||
int v;
|
||||
|
||||
k = safe_atoi(vtnr, &v);
|
||||
if (k >= 0 && v >= 1)
|
||||
s->vtnr = v;
|
||||
}
|
||||
|
||||
if (leader) {
|
||||
pid_t pid;
|
||||
|
||||
k = parse_pid(leader, &pid);
|
||||
if (k >= 0 && pid >= 1)
|
||||
s->leader = pid;
|
||||
}
|
||||
|
||||
if (audit_id) {
|
||||
uint32_t l;
|
||||
|
||||
k = safe_atou32(audit_id, &l);
|
||||
if (k >= 0 && l >= l)
|
||||
s->audit_id = l;
|
||||
}
|
||||
|
||||
finish:
|
||||
free(remote);
|
||||
free(kill_processes);
|
||||
free(seat);
|
||||
free(vtnr);
|
||||
free(leader);
|
||||
free(audit_id);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int session_activate(Session *s) {
|
||||
@ -207,7 +287,7 @@ int session_activate(Session *s) {
|
||||
if (s->seat->active == s)
|
||||
return 0;
|
||||
|
||||
assert(s->manager->vtconsole == s->seat);
|
||||
assert(seat_is_vtconsole(s->seat));
|
||||
|
||||
r = chvt(s->vtnr);
|
||||
if (r < 0)
|
||||
@ -462,6 +542,59 @@ bool session_is_active(Session *s) {
|
||||
return s->seat->active == s;
|
||||
}
|
||||
|
||||
int session_get_idle_hint(Session *s, dual_timestamp *t) {
|
||||
char *p;
|
||||
struct stat st;
|
||||
usec_t u, n;
|
||||
bool b;
|
||||
int k;
|
||||
|
||||
assert(s);
|
||||
|
||||
if (s->idle_hint) {
|
||||
if (t)
|
||||
*t = s->idle_hint_timestamp;
|
||||
|
||||
return s->idle_hint;
|
||||
}
|
||||
|
||||
if (isempty(s->tty))
|
||||
goto dont_know;
|
||||
|
||||
if (s->tty[0] != '/') {
|
||||
p = strappend("/dev/", s->tty);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
} else
|
||||
p = NULL;
|
||||
|
||||
if (!startswith(p ? p : s->tty, "/dev/")) {
|
||||
free(p);
|
||||
goto dont_know;
|
||||
}
|
||||
|
||||
k = lstat(p ? p : s->tty, &st);
|
||||
free(p);
|
||||
|
||||
if (k < 0)
|
||||
goto dont_know;
|
||||
|
||||
u = timespec_load(&st.st_atim);
|
||||
n = now(CLOCK_REALTIME);
|
||||
b = u + IDLE_THRESHOLD_USEC < n;
|
||||
|
||||
if (t)
|
||||
dual_timestamp_from_realtime(t, u + b ? IDLE_THRESHOLD_USEC : 0);
|
||||
|
||||
return b;
|
||||
|
||||
dont_know:
|
||||
if (t)
|
||||
*t = s->idle_hint_timestamp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int session_check_gc(Session *s) {
|
||||
int r;
|
||||
|
||||
|
@ -67,6 +67,9 @@ struct Session {
|
||||
char *cgroup_path;
|
||||
char **controllers, **reset_controllers;
|
||||
|
||||
bool idle_hint;
|
||||
dual_timestamp idle_hint_timestamp;
|
||||
|
||||
bool kill_processes;
|
||||
bool in_gc_queue:1;
|
||||
|
||||
@ -82,6 +85,7 @@ int session_check_gc(Session *s);
|
||||
void session_add_to_gc_queue(Session *s);
|
||||
int session_activate(Session *s);
|
||||
bool session_is_active(Session *s);
|
||||
int session_get_idle_hint(Session *s, dual_timestamp *t);
|
||||
int session_start(Session *s);
|
||||
int session_stop(Session *s);
|
||||
int session_save(Session *s);
|
||||
|
@ -20,6 +20,7 @@
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "logind.h"
|
||||
#include "logind-user.h"
|
||||
@ -31,12 +32,17 @@
|
||||
" <property name=\"UID\" type=\"u\" access=\"read\"/>\n" \
|
||||
" <property name=\"GID\" type=\"u\" access=\"read\"/>\n" \
|
||||
" <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
|
||||
" <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
|
||||
" <property name=\"RuntimePath\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"Service\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"ControlGroupPath\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"Service\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"Display\" type=\"(so)\" access=\"read\"/>\n" \
|
||||
" <property name=\"State\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
|
||||
" <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
|
||||
" <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
|
||||
" <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
|
||||
" </interface>\n" \
|
||||
|
||||
#define INTROSPECTION \
|
||||
@ -146,6 +152,39 @@ static int bus_user_append_sessions(DBusMessageIter *i, const char *property, vo
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bus_user_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
|
||||
User *u = data;
|
||||
bool b;
|
||||
|
||||
assert(i);
|
||||
assert(property);
|
||||
assert(u);
|
||||
|
||||
b = user_get_idle_hint(u, NULL);
|
||||
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bus_user_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
|
||||
User *u = data;
|
||||
dual_timestamp t;
|
||||
uint64_t k;
|
||||
|
||||
assert(i);
|
||||
assert(property);
|
||||
assert(u);
|
||||
|
||||
user_get_idle_hint(u, &t);
|
||||
k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
|
||||
|
||||
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &k))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_user_for_path(Manager *m, const char *path, User **_u) {
|
||||
User *u;
|
||||
unsigned long lu;
|
||||
@ -176,23 +215,59 @@ static DBusHandlerResult user_message_dispatch(
|
||||
DBusMessage *message) {
|
||||
|
||||
const BusProperty properties[] = {
|
||||
{ "org.freedesktop.login1.User", "UID", bus_property_append_uid, "u", &u->uid },
|
||||
{ "org.freedesktop.login1.User", "GID", bus_property_append_gid, "u", &u->gid },
|
||||
{ "org.freedesktop.login1.User", "Name", bus_property_append_string, "s", u->name },
|
||||
{ "org.freedesktop.login1.User", "RuntimePath", bus_property_append_string, "s", u->runtime_path },
|
||||
{ "org.freedesktop.login1.User", "ControlGroupPath", bus_property_append_string, "s", u->cgroup_path },
|
||||
{ "org.freedesktop.login1.User", "Service", bus_property_append_string, "s", u->service },
|
||||
{ "org.freedesktop.login1.User", "Display", bus_user_append_display, "(so)", u },
|
||||
{ "org.freedesktop.login1.User", "State", bus_user_append_state, "s", u },
|
||||
{ "org.freedesktop.login1.User", "Sessions", bus_user_append_sessions, "a(so)", u },
|
||||
{ "org.freedesktop.login1.User", "UID", bus_property_append_uid, "u", &u->uid },
|
||||
{ "org.freedesktop.login1.User", "GID", bus_property_append_gid, "u", &u->gid },
|
||||
{ "org.freedesktop.login1.User", "Name", bus_property_append_string, "s", u->name },
|
||||
{ "org.freedesktop.login1.User", "Timestamp", bus_property_append_usec, "t", &u->timestamp.realtime },
|
||||
{ "org.freedesktop.login1.User", "TimestampMonotonic", bus_property_append_usec, "t", &u->timestamp.monotonic },
|
||||
{ "org.freedesktop.login1.User", "RuntimePath", bus_property_append_string, "s", u->runtime_path },
|
||||
{ "org.freedesktop.login1.User", "ControlGroupPath", bus_property_append_string, "s", u->cgroup_path },
|
||||
{ "org.freedesktop.login1.User", "Service", bus_property_append_string, "s", u->service },
|
||||
{ "org.freedesktop.login1.User", "Display", bus_user_append_display, "(so)", u },
|
||||
{ "org.freedesktop.login1.User", "State", bus_user_append_state, "s", u },
|
||||
{ "org.freedesktop.login1.User", "Sessions", bus_user_append_sessions, "a(so)", u },
|
||||
{ "org.freedesktop.login1.User", "IdleHint", bus_user_append_idle_hint, "b", u },
|
||||
{ "org.freedesktop.login1.User", "IdleSinceHint", bus_user_append_idle_hint_since, "t", u },
|
||||
{ "org.freedesktop.login1.User", "IdleSinceHintMonotonic", bus_user_append_idle_hint_since, "t", u },
|
||||
{ NULL, NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
DBusError error;
|
||||
DBusMessage *reply = NULL;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(connection);
|
||||
assert(message);
|
||||
|
||||
return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
|
||||
if (dbus_message_is_method_call(message, "org.freedesktop.login1.User", "Terminate")) {
|
||||
|
||||
r = user_stop(u);
|
||||
if (r < 0)
|
||||
return bus_send_error_reply(connection, message, NULL, r);
|
||||
|
||||
reply = dbus_message_new_method_return(message);
|
||||
if (!reply)
|
||||
goto oom;
|
||||
} else
|
||||
return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
|
||||
|
||||
if (reply) {
|
||||
if (!dbus_connection_send(connection, reply, NULL))
|
||||
goto oom;
|
||||
|
||||
dbus_message_unref(reply);
|
||||
}
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
|
||||
oom:
|
||||
if (reply)
|
||||
dbus_message_unref(reply);
|
||||
|
||||
dbus_error_free(&error);
|
||||
|
||||
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
||||
}
|
||||
|
||||
static DBusHandlerResult user_message_handler(
|
||||
|
@ -156,7 +156,7 @@ int user_load(User *u) {
|
||||
|
||||
assert(u);
|
||||
|
||||
r = parse_env_file(u->state_file, "r",
|
||||
r = parse_env_file(u->state_file, NEWLINE,
|
||||
"CGROUP", &u->cgroup_path,
|
||||
"RUNTIME", &u->runtime_path,
|
||||
"SERVICE", &u->service,
|
||||
@ -386,6 +386,42 @@ int user_stop(User *u) {
|
||||
return r;
|
||||
}
|
||||
|
||||
int user_get_idle_hint(User *u, dual_timestamp *t) {
|
||||
Session *s;
|
||||
bool idle_hint = true;
|
||||
dual_timestamp ts = { 0, 0 };
|
||||
|
||||
assert(u);
|
||||
|
||||
LIST_FOREACH(sessions_by_user, s, u->sessions) {
|
||||
dual_timestamp k;
|
||||
int ih;
|
||||
|
||||
ih = session_get_idle_hint(s, &k);
|
||||
if (ih < 0)
|
||||
return ih;
|
||||
|
||||
if (!ih) {
|
||||
if (!idle_hint) {
|
||||
if (k.monotonic < ts.monotonic)
|
||||
ts = k;
|
||||
} else {
|
||||
idle_hint = false;
|
||||
ts = k;
|
||||
}
|
||||
} else if (idle_hint) {
|
||||
|
||||
if (k.monotonic > ts.monotonic)
|
||||
ts = k;
|
||||
}
|
||||
}
|
||||
|
||||
if (t)
|
||||
*t = ts;
|
||||
|
||||
return idle_hint;
|
||||
}
|
||||
|
||||
int user_check_gc(User *u) {
|
||||
int r;
|
||||
char *p;
|
||||
|
@ -67,6 +67,7 @@ void user_add_to_gc_queue(User *u);
|
||||
int user_start(User *u);
|
||||
int user_stop(User *u);
|
||||
UserState user_get_state(User *u);
|
||||
int user_get_idle_hint(User *u, dual_timestamp *t);
|
||||
int user_save(User *u);
|
||||
int user_load(User *u);
|
||||
|
||||
|
38
src/logind.c
38
src/logind.c
@ -853,6 +853,44 @@ void manager_gc(Manager *m) {
|
||||
}
|
||||
}
|
||||
|
||||
int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
|
||||
Session *s;
|
||||
bool idle_hint = true;
|
||||
dual_timestamp ts = { 0, 0 };
|
||||
Iterator i;
|
||||
|
||||
assert(m);
|
||||
|
||||
HASHMAP_FOREACH(s, m->sessions, i) {
|
||||
dual_timestamp k;
|
||||
int ih;
|
||||
|
||||
ih = session_get_idle_hint(s, &k);
|
||||
if (ih < 0)
|
||||
return ih;
|
||||
|
||||
if (!ih) {
|
||||
if (!idle_hint) {
|
||||
if (k.monotonic < ts.monotonic)
|
||||
ts = k;
|
||||
} else {
|
||||
idle_hint = false;
|
||||
ts = k;
|
||||
}
|
||||
} else if (idle_hint) {
|
||||
|
||||
if (k.monotonic > ts.monotonic)
|
||||
ts = k;
|
||||
}
|
||||
}
|
||||
|
||||
if (t)
|
||||
*t = ts;
|
||||
|
||||
return idle_hint;
|
||||
}
|
||||
|
||||
|
||||
int manager_startup(Manager *m) {
|
||||
int r;
|
||||
Seat *seat;
|
||||
|
@ -108,6 +108,8 @@ int manager_spawn_autovt(Manager *m, int vtnr);
|
||||
|
||||
void manager_gc(Manager *m);
|
||||
|
||||
int manager_get_idle_hint(Manager *m, dual_timestamp *t);
|
||||
|
||||
bool x11_display_is_local(const char *display);
|
||||
|
||||
extern const DBusObjectPathVTable bus_manager_vtable;
|
||||
|
22
src/util.c
22
src/util.c
@ -108,6 +108,28 @@ dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
|
||||
return ts;
|
||||
}
|
||||
|
||||
dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
|
||||
int64_t delta;
|
||||
assert(ts);
|
||||
|
||||
ts->realtime = u;
|
||||
|
||||
if (u == 0)
|
||||
ts->monotonic = 0;
|
||||
else {
|
||||
delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
|
||||
|
||||
ts->monotonic = now(CLOCK_MONOTONIC);
|
||||
|
||||
if ((int64_t) ts->monotonic > delta)
|
||||
ts->monotonic -= delta;
|
||||
else
|
||||
ts->monotonic = 0;
|
||||
}
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
usec_t timespec_load(const struct timespec *ts) {
|
||||
assert(ts);
|
||||
|
||||
|
@ -75,6 +75,7 @@ typedef struct dual_timestamp {
|
||||
usec_t now(clockid_t clock);
|
||||
|
||||
dual_timestamp* dual_timestamp_get(dual_timestamp *ts);
|
||||
dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u);
|
||||
|
||||
#define dual_timestamp_is_set(ts) ((ts)->realtime > 0)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user