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/>.
25 #include "alloc-util.h"
26 #include "bus-common-errors.h"
27 #include "bus-label.h"
29 #include "logind-seat.h"
32 #include "user-util.h"
35 static int property_get_active_session(
38 const char *interface,
40 sd_bus_message *reply,
42 sd_bus_error *error) {
44 _cleanup_free_ char *p = NULL;
51 p = s->active ? session_bus_path(s->active) : strdup("/");
55 return sd_bus_message_append(reply, "(so)", s->active ? s->active->id : "", p);
58 static int property_get_can_multi_session(
61 const char *interface,
63 sd_bus_message *reply,
65 sd_bus_error *error) {
73 return sd_bus_message_append(reply, "b", seat_can_multi_session(s));
76 static int property_get_can_tty(
79 const char *interface,
81 sd_bus_message *reply,
83 sd_bus_error *error) {
91 return sd_bus_message_append(reply, "b", seat_can_tty(s));
94 static int property_get_can_graphical(
97 const char *interface,
99 sd_bus_message *reply,
101 sd_bus_error *error) {
109 return sd_bus_message_append(reply, "b", seat_can_graphical(s));
112 static int property_get_sessions(
115 const char *interface,
116 const char *property,
117 sd_bus_message *reply,
119 sd_bus_error *error) {
129 r = sd_bus_message_open_container(reply, 'a', "(so)");
133 LIST_FOREACH(sessions_by_seat, session, s->sessions) {
134 _cleanup_free_ char *p = NULL;
136 p = session_bus_path(session);
140 r = sd_bus_message_append(reply, "(so)", session->id, p);
146 r = sd_bus_message_close_container(reply);
153 static int property_get_idle_hint(
156 const char *interface,
157 const char *property,
158 sd_bus_message *reply,
160 sd_bus_error *error) {
168 return sd_bus_message_append(reply, "b", seat_get_idle_hint(s, NULL) > 0);
171 static int property_get_idle_since_hint(
174 const char *interface,
175 const char *property,
176 sd_bus_message *reply,
178 sd_bus_error *error) {
189 r = seat_get_idle_hint(s, &t);
193 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
195 return sd_bus_message_append(reply, "t", u);
198 int bus_seat_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
205 r = bus_verify_polkit_async(
208 "org.freedesktop.login1.manage",
212 &s->manager->polkit_registry,
217 return 1; /* Will call us back */
219 r = seat_stop_sessions(s, true);
223 return sd_bus_reply_method_return(message, NULL);
226 static int method_activate_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
235 r = sd_bus_message_read(message, "s", &name);
239 session = hashmap_get(s->manager->sessions, name);
241 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
243 if (session->seat != s)
244 return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id);
246 r = session_activate(session);
250 return sd_bus_reply_method_return(message, NULL);
253 static int method_switch_to(sd_bus_message *message, void *userdata, sd_bus_error *error) {
261 r = sd_bus_message_read(message, "u", &to);
268 r = seat_switch_to(s, to);
272 return sd_bus_reply_method_return(message, NULL);
275 static int method_switch_to_next(sd_bus_message *message, void *userdata, sd_bus_error *error) {
282 r = seat_switch_to_next(s);
286 return sd_bus_reply_method_return(message, NULL);
289 static int method_switch_to_previous(sd_bus_message *message, void *userdata, sd_bus_error *error) {
296 r = seat_switch_to_previous(s);
300 return sd_bus_reply_method_return(message, NULL);
303 const sd_bus_vtable seat_vtable[] = {
304 SD_BUS_VTABLE_START(0),
306 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST),
307 SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
308 SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST),
309 SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
310 SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
311 SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
312 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
313 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
314 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
316 SD_BUS_METHOD("Terminate", NULL, NULL, bus_seat_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
317 SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED),
318 SD_BUS_METHOD("SwitchTo", "u", NULL, method_switch_to, SD_BUS_VTABLE_UNPRIVILEGED),
319 SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED),
320 SD_BUS_METHOD("SwitchToPrevious", NULL, NULL, method_switch_to_previous, SD_BUS_VTABLE_UNPRIVILEGED),
325 int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
326 Manager *m = userdata;
336 if (streq(path, "/org/freedesktop/login1/seat/self")) {
337 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
338 sd_bus_message *message;
342 message = sd_bus_get_current_message(bus);
346 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
350 r = sd_bus_creds_get_session(creds, &name);
354 session = hashmap_get(m->sessions, name);
358 seat = session->seat;
360 _cleanup_free_ char *e = NULL;
363 p = startswith(path, "/org/freedesktop/login1/seat/");
367 e = bus_label_unescape(p);
371 seat = hashmap_get(m->seats, e);
381 char *seat_bus_path(Seat *s) {
382 _cleanup_free_ char *t = NULL;
386 t = bus_label_escape(s->id);
390 return strappend("/org/freedesktop/login1/seat/", t);
393 int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
394 _cleanup_strv_free_ char **l = NULL;
395 sd_bus_message *message;
396 Manager *m = userdata;
405 HASHMAP_FOREACH(seat, m->seats, i) {
408 p = seat_bus_path(seat);
412 r = strv_consume(&l, p);
417 message = sd_bus_get_current_message(bus);
419 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
423 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
425 r = sd_bus_creds_get_session(creds, &name);
427 session = hashmap_get(m->sessions, name);
428 if (session && session->seat) {
429 r = strv_extend(&l, "/org/freedesktop/login1/seat/self");
443 int seat_send_signal(Seat *s, bool new_seat) {
444 _cleanup_free_ char *p = NULL;
448 p = seat_bus_path(s);
452 return sd_bus_emit_signal(
454 "/org/freedesktop/login1",
455 "org.freedesktop.login1.Manager",
456 new_seat ? "SeatNew" : "SeatRemoved",
460 int seat_send_changed(Seat *s, const char *properties, ...) {
461 _cleanup_free_ char *p = NULL;
469 p = seat_bus_path(s);
473 l = strv_from_stdarg_alloca(properties);
475 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);