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;
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)) {
92 if (!dbus_message_iter_close_container(i, &sub))
98 static int bus_seat_append_sessions(DBusMessageIter *i, const char *property, void *data) {
99 DBusMessageIter sub, sub2;
107 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(so)", &sub))
110 LIST_FOREACH(sessions_by_seat, session, s->sessions) {
113 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
116 p = session_bus_path(session);
120 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
121 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
128 if (!dbus_message_iter_close_container(&sub, &sub2))
132 if (!dbus_message_iter_close_container(i, &sub))
138 static int bus_seat_append_can_multi_session(DBusMessageIter *i, const char *property, void *data) {
146 b = seat_can_multi_session(s);
148 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
154 static int bus_seat_append_can_tty(DBusMessageIter *i, const char *property, void *data) {
164 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
170 static int bus_seat_append_can_graphical(DBusMessageIter *i, const char *property, void *data) {
178 b = seat_can_graphical(s);
180 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
186 static int bus_seat_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
194 b = seat_get_idle_hint(s, NULL) > 0;
195 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
201 static int bus_seat_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
210 seat_get_idle_hint(s, &t);
211 k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
213 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &k))
219 static int get_seat_for_path(Manager *m, const char *path, Seat **_s) {
227 if (!startswith(path, "/org/freedesktop/login1/seat/"))
230 id = bus_path_unescape(path + 29);
234 s = hashmap_get(m->seats, id);
244 static const BusProperty bus_login_seat_properties[] = {
245 { "Id", bus_property_append_string, "s", offsetof(Seat, id), true },
246 { "ActiveSession", bus_seat_append_active, "(so)", 0 },
247 { "CanMultiSession", bus_seat_append_can_multi_session, "b", 0 },
248 { "CanTTY", bus_seat_append_can_tty, "b", 0 },
249 { "CanGraphical", bus_seat_append_can_graphical, "b", 0 },
250 { "Sessions", bus_seat_append_sessions, "a(so)", 0 },
251 { "IdleHint", bus_seat_append_idle_hint, "b", 0 },
252 { "IdleSinceHint", bus_seat_append_idle_hint_since, "t", 0 },
253 { "IdleSinceHintMonotonic", bus_seat_append_idle_hint_since, "t", 0 },
257 static DBusHandlerResult seat_message_dispatch(
259 DBusConnection *connection,
260 DBusMessage *message) {
263 DBusMessage *reply = NULL;
270 dbus_error_init(&error);
272 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "Terminate")) {
274 r = seat_stop_sessions(s);
276 return bus_send_error_reply(connection, message, NULL, r);
278 reply = dbus_message_new_method_return(message);
282 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "ActivateSession")) {
286 if (!dbus_message_get_args(
289 DBUS_TYPE_STRING, &name,
291 return bus_send_error_reply(connection, message, &error, -EINVAL);
293 session = hashmap_get(s->manager->sessions, name);
294 if (!session || session->seat != s)
295 return bus_send_error_reply(connection, message, &error, -ENOENT);
297 r = session_activate(session);
299 return bus_send_error_reply(connection, message, NULL, r);
301 reply = dbus_message_new_method_return(message);
305 const BusBoundProperties bps[] = {
306 { "org.freedesktop.login1.Seat", bus_login_seat_properties, s },
309 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
313 if (!dbus_connection_send(connection, reply, NULL))
316 dbus_message_unref(reply);
319 return DBUS_HANDLER_RESULT_HANDLED;
323 dbus_message_unref(reply);
325 dbus_error_free(&error);
327 return DBUS_HANDLER_RESULT_NEED_MEMORY;
330 static DBusHandlerResult seat_message_handler(
331 DBusConnection *connection,
332 DBusMessage *message,
335 Manager *m = userdata;
339 r = get_seat_for_path(m, dbus_message_get_path(message), &s);
343 return DBUS_HANDLER_RESULT_NEED_MEMORY;
349 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown seat");
350 return bus_send_error_reply(connection, message, &e, r);
353 return bus_send_error_reply(connection, message, NULL, r);
356 return seat_message_dispatch(s, connection, message);
359 const DBusObjectPathVTable bus_seat_vtable = {
360 .message_function = seat_message_handler
363 char *seat_bus_path(Seat *s) {
368 t = bus_path_escape(s->id);
372 r = strappend("/org/freedesktop/login1/seat/", t);
378 int seat_send_signal(Seat *s, bool new_seat) {
385 m = dbus_message_new_signal("/org/freedesktop/login1",
386 "org.freedesktop.login1.Manager",
387 new_seat ? "SeatNew" : "SeatRemoved");
392 p = seat_bus_path(s);
396 if (!dbus_message_append_args(
398 DBUS_TYPE_STRING, &s->id,
399 DBUS_TYPE_OBJECT_PATH, &p,
403 if (!dbus_connection_send(s->manager->bus, m, NULL))
409 dbus_message_unref(m);
415 int seat_send_changed(Seat *s, const char *properties) {
425 p = seat_bus_path(s);
429 m = bus_properties_changed_new(p, "org.freedesktop.login1.Seat", properties);
433 if (!dbus_connection_send(s->manager->bus, m, NULL))
440 dbus_message_unref(m);