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 char _cleanup_free_ *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 char _cleanup_free_ *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) {
219 if (!startswith(path, "/org/freedesktop/login1/seat/"))
222 id = bus_path_unescape(path + 29);
226 s = hashmap_get(m->seats, id);
236 static const BusProperty bus_login_seat_properties[] = {
237 { "Id", bus_property_append_string, "s", offsetof(Seat, id), true },
238 { "ActiveSession", bus_seat_append_active, "(so)", 0 },
239 { "CanMultiSession", bus_seat_append_can_multi_session, "b", 0 },
240 { "CanTTY", bus_seat_append_can_tty, "b", 0 },
241 { "CanGraphical", bus_seat_append_can_graphical, "b", 0 },
242 { "Sessions", bus_seat_append_sessions, "a(so)", 0 },
243 { "IdleHint", bus_seat_append_idle_hint, "b", 0 },
244 { "IdleSinceHint", bus_seat_append_idle_hint_since, "t", 0 },
245 { "IdleSinceHintMonotonic", bus_seat_append_idle_hint_since, "t", 0 },
249 static DBusHandlerResult seat_message_dispatch(
251 DBusConnection *connection,
252 DBusMessage *message) {
255 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
262 dbus_error_init(&error);
264 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "Terminate")) {
266 r = seat_stop_sessions(s);
268 return bus_send_error_reply(connection, message, NULL, r);
270 reply = dbus_message_new_method_return(message);
274 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "ActivateSession")) {
278 if (!dbus_message_get_args(
281 DBUS_TYPE_STRING, &name,
283 return bus_send_error_reply(connection, message, &error, -EINVAL);
285 session = hashmap_get(s->manager->sessions, name);
286 if (!session || session->seat != s)
287 return bus_send_error_reply(connection, message, &error, -ENOENT);
289 r = session_activate(session);
291 return bus_send_error_reply(connection, message, NULL, r);
293 reply = dbus_message_new_method_return(message);
297 const BusBoundProperties bps[] = {
298 { "org.freedesktop.login1.Seat", bus_login_seat_properties, s },
301 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
305 if (!bus_maybe_send_reply(connection, message, reply))
309 return DBUS_HANDLER_RESULT_HANDLED;
312 dbus_error_free(&error);
314 return DBUS_HANDLER_RESULT_NEED_MEMORY;
317 static DBusHandlerResult seat_message_handler(
318 DBusConnection *connection,
319 DBusMessage *message,
322 Manager *m = userdata;
326 r = get_seat_for_path(m, dbus_message_get_path(message), &s);
330 return DBUS_HANDLER_RESULT_NEED_MEMORY;
336 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown seat");
337 return bus_send_error_reply(connection, message, &e, r);
340 return bus_send_error_reply(connection, message, NULL, r);
343 return seat_message_dispatch(s, connection, message);
346 const DBusObjectPathVTable bus_seat_vtable = {
347 .message_function = seat_message_handler
350 char *seat_bus_path(Seat *s) {
351 char _cleanup_free_ *t;
355 t = bus_path_escape(s->id);
359 return strappend("/org/freedesktop/login1/seat/", t);
362 int seat_send_signal(Seat *s, bool new_seat) {
363 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
364 _cleanup_free_ char *p = NULL;
368 m = dbus_message_new_signal("/org/freedesktop/login1",
369 "org.freedesktop.login1.Manager",
370 new_seat ? "SeatNew" : "SeatRemoved");
374 p = seat_bus_path(s);
378 if (!dbus_message_append_args(
380 DBUS_TYPE_STRING, &s->id,
381 DBUS_TYPE_OBJECT_PATH, &p,
385 if (!dbus_connection_send(s->manager->bus, m, NULL))
391 int seat_send_changed(Seat *s, const char *properties) {
392 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
393 _cleanup_free_ char *p = NULL;
400 p = seat_bus_path(s);
404 m = bus_properties_changed_new(p, "org.freedesktop.login1.Seat", properties);
408 if (!dbus_connection_send(s->manager->bus, m, NULL))