1
0
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:
Lennart Poettering 2011-06-17 15:59:18 +02:00
parent 91f9dcaf92
commit a185c5aa2d
14 changed files with 625 additions and 55 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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