summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/logind-dbus.c59
-rw-r--r--src/logind-seat-dbus.c101
-rw-r--r--src/logind-seat.c95
-rw-r--r--src/logind-seat.h6
-rw-r--r--src/logind-session-dbus.c75
-rw-r--r--src/logind-session.c139
-rw-r--r--src/logind-session.h4
-rw-r--r--src/logind-user-dbus.c97
-rw-r--r--src/logind-user.c38
-rw-r--r--src/logind-user.h1
-rw-r--r--src/logind.c38
-rw-r--r--src/logind.h2
-rw-r--r--src/util.c22
-rw-r--r--src/util.h1
14 files changed, 624 insertions, 54 deletions
diff --git a/src/logind-dbus.c b/src/logind-dbus.c
index 90db94184f..42374d7fdb 100644
--- a/src/logind-dbus.c
+++ b/src/logind-dbus.c
@@ -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 }
};
diff --git a/src/logind-seat-dbus.c b/src/logind-seat-dbus.c
index 4937d65f74..32171ce401 100644
--- a/src/logind-seat-dbus.c
+++ b/src/logind-seat-dbus.c
@@ -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(
diff --git a/src/logind-seat.c b/src/logind-seat.c
index 2ba3060be3..751f59a48d 100644
--- a/src/logind-seat.c
+++ b/src/logind-seat.c
@@ -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,24 +327,96 @@ int seat_stop(Seat *s) {
log_info("Removed seat %s.", s->id);
+ seat_stop_sessions(s);
+
+ unlink(s->state_file);
+ seat_add_to_gc_queue(s);
+
+ s->started = false;
+
+ 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;
}
- unlink(s->state_file);
- seat_add_to_gc_queue(s);
+ return r;
+}
- s->started = false;
+int seat_attach_session(Seat *s, Session *session) {
+ assert(s);
+ assert(session);
+ assert(!session->seat);
- return r;
+ 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;
diff --git a/src/logind-seat.h b/src/logind-seat.h
index b045bde931..dfbb2a2a0a 100644
--- a/src/logind-seat.h
+++ b/src/logind-seat.h
@@ -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);
diff --git a/src/logind-session-dbus.c b/src/logind-session-dbus.c
index 539384b7d4..8b5b3ad51f 100644
--- a/src/logind-session-dbus.c
+++ b/src/logind-session-dbus.c
@@ -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 }
};
diff --git a/src/logind-session.c b/src/logind-session.c
index 6b3b277897..89fe02c061 100644
--- a/src/logind-session.c
+++ b/src/logind-session.c
@@ -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;
diff --git a/src/logind-session.h b/src/logind-session.h
index 60ac1c54e6..76823931da 100644
--- a/src/logind-session.h
+++ b/src/logind-session.h
@@ -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);
diff --git a/src/logind-user-dbus.c b/src/logind-user-dbus.c
index 7c8bb27c6d..3be2c05d26 100644
--- a/src/logind-user-dbus.c
+++ b/src/logind-user-dbus.c
@@ -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(
diff --git a/src/logind-user.c b/src/logind-user.c
index 7d6df8db7a..206064f103 100644
--- a/src/logind-user.c
+++ b/src/logind-user.c
@@ -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;
diff --git a/src/logind-user.h b/src/logind-user.h
index 7f58aa2b07..c891119e27 100644
--- a/src/logind-user.h
+++ b/src/logind-user.h
@@ -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);
diff --git a/src/logind.c b/src/logind.c
index a62802895c..d72a5bfa8b 100644
--- a/src/logind.c
+++ b/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;
diff --git a/src/logind.h b/src/logind.h
index fdc780feb6..e18a357c9a 100644
--- a/src/logind.h
+++ b/src/logind.h
@@ -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;
diff --git a/src/util.c b/src/util.c
index 2047ebd7bd..08529cc235 100644
--- a/src/util.c
+++ b/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);
diff --git a/src/util.h b/src/util.h
index 3863a08b63..76e1d4faa0 100644
--- a/src/util.h
+++ b/src/util.h
@@ -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)