1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "logind-seat.h"
27 #include "dbus-common.h"
30 #define BUS_SEAT_INTERFACE \
31 " <interface name=\"org.freedesktop.login1.Seat\">\n" \
32 " <method name=\"Terminate\"/>\n" \
33 " <method name=\"ActivateSession\">\n" \
34 " <arg name=\"id\" type=\"s\"/>\n" \
36 " <property name=\"Id\" type=\"s\" access=\"read\"/>\n" \
37 " <property name=\"ActiveSession\" type=\"so\" access=\"read\"/>\n" \
38 " <property name=\"CanMultiSession\" type=\"b\" access=\"read\"/>\n" \
39 " <property name=\"CanTTY\" type=\"b\" access=\"read\"/>\n" \
40 " <property name=\"CanGraphical\" type=\"b\" access=\"read\"/>\n" \
41 " <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
42 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
43 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
44 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
47 #define INTROSPECTION \
48 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
51 BUS_PROPERTIES_INTERFACE \
53 BUS_INTROSPECTABLE_INTERFACE \
56 #define INTERFACES_LIST \
57 BUS_GENERIC_INTERFACES_LIST \
58 "org.freedesktop.login1.Seat\0"
60 static int bus_seat_append_active(DBusMessageIter *i, const char *property, void *data) {
63 const char *id, *path;
64 _cleanup_free_ char *p = NULL;
70 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
75 path = p = session_bus_path(s->active);
84 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
85 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path))
88 if (!dbus_message_iter_close_container(i, &sub))
94 static int bus_seat_append_sessions(DBusMessageIter *i, const char *property, void *data) {
95 DBusMessageIter sub, sub2;
103 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(so)", &sub))
106 LIST_FOREACH(sessions_by_seat, session, s->sessions) {
107 _cleanup_free_ char *p = NULL;
109 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
112 p = session_bus_path(session);
116 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
117 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p))
120 if (!dbus_message_iter_close_container(&sub, &sub2))
124 if (!dbus_message_iter_close_container(i, &sub))
130 static int bus_seat_append_can_multi_session(DBusMessageIter *i, const char *property, void *data) {
138 b = seat_can_multi_session(s);
140 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
146 static int bus_seat_append_can_tty(DBusMessageIter *i, const char *property, void *data) {
156 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
162 static int bus_seat_append_can_graphical(DBusMessageIter *i, const char *property, void *data) {
170 b = seat_can_graphical(s);
172 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
178 static int bus_seat_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
186 b = seat_get_idle_hint(s, NULL) > 0;
187 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
193 static int bus_seat_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
202 seat_get_idle_hint(s, &t);
203 k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
205 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &k))
211 static int get_seat_for_path(Manager *m, const char *path, Seat **_s) {
212 _cleanup_free_ char *id = NULL;
219 if (!startswith(path, "/org/freedesktop/login1/seat/"))
222 id = bus_path_unescape(path + 29);
226 s = hashmap_get(m->seats, id);
234 static const BusProperty bus_login_seat_properties[] = {
235 { "Id", bus_property_append_string, "s", offsetof(Seat, id), true },
236 { "ActiveSession", bus_seat_append_active, "(so)", 0 },
237 { "CanMultiSession", bus_seat_append_can_multi_session, "b", 0 },
238 { "CanTTY", bus_seat_append_can_tty, "b", 0 },
239 { "CanGraphical", bus_seat_append_can_graphical, "b", 0 },
240 { "Sessions", bus_seat_append_sessions, "a(so)", 0 },
241 { "IdleHint", bus_seat_append_idle_hint, "b", 0 },
242 { "IdleSinceHint", bus_seat_append_idle_hint_since, "t", 0 },
243 { "IdleSinceHintMonotonic", bus_seat_append_idle_hint_since, "t", 0 },
247 static DBusHandlerResult seat_message_dispatch(
249 DBusConnection *connection,
250 DBusMessage *message) {
253 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
260 dbus_error_init(&error);
262 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "Terminate")) {
264 r = seat_stop_sessions(s);
266 return bus_send_error_reply(connection, message, NULL, r);
268 reply = dbus_message_new_method_return(message);
272 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "ActivateSession")) {
276 if (!dbus_message_get_args(
279 DBUS_TYPE_STRING, &name,
281 return bus_send_error_reply(connection, message, &error, -EINVAL);
283 session = hashmap_get(s->manager->sessions, name);
284 if (!session || session->seat != s)
285 return bus_send_error_reply(connection, message, &error, -ENOENT);
287 r = session_activate(session);
289 return bus_send_error_reply(connection, message, NULL, r);
291 reply = dbus_message_new_method_return(message);
295 const BusBoundProperties bps[] = {
296 { "org.freedesktop.login1.Seat", bus_login_seat_properties, s },
299 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
303 if (!bus_maybe_send_reply(connection, message, reply))
307 return DBUS_HANDLER_RESULT_HANDLED;
310 dbus_error_free(&error);
312 return DBUS_HANDLER_RESULT_NEED_MEMORY;
315 static DBusHandlerResult seat_message_handler(
316 DBusConnection *connection,
317 DBusMessage *message,
320 Manager *m = userdata;
324 r = get_seat_for_path(m, dbus_message_get_path(message), &s);
328 return DBUS_HANDLER_RESULT_NEED_MEMORY;
334 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown seat");
335 return bus_send_error_reply(connection, message, &e, r);
338 return bus_send_error_reply(connection, message, NULL, r);
341 return seat_message_dispatch(s, connection, message);
344 const DBusObjectPathVTable bus_seat_vtable = {
345 .message_function = seat_message_handler
348 char *seat_bus_path(Seat *s) {
349 _cleanup_free_ char *t = NULL;
353 t = bus_path_escape(s->id);
357 return strappend("/org/freedesktop/login1/seat/", t);
360 int seat_send_signal(Seat *s, bool new_seat) {
361 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
362 _cleanup_free_ char *p = NULL;
366 m = dbus_message_new_signal("/org/freedesktop/login1",
367 "org.freedesktop.login1.Manager",
368 new_seat ? "SeatNew" : "SeatRemoved");
372 p = seat_bus_path(s);
376 if (!dbus_message_append_args(
378 DBUS_TYPE_STRING, &s->id,
379 DBUS_TYPE_OBJECT_PATH, &p,
383 if (!dbus_connection_send(s->manager->bus, m, NULL))
389 int seat_send_changed(Seat *s, const char *properties) {
390 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
391 _cleanup_free_ char *p = NULL;
398 p = seat_bus_path(s);
402 m = bus_properties_changed_new(p, "org.freedesktop.login1.Seat", properties);
406 if (!dbus_connection_send(s->manager->bus, m, NULL))