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 "bus-common-errors.h"
26 #include "bus-label.h"
28 #include "logind-seat.h"
31 #include "user-util.h"
34 static int property_get_active_session(
37 const char *interface
,
39 sd_bus_message
*reply
,
41 sd_bus_error
*error
) {
43 _cleanup_free_
char *p
= NULL
;
50 p
= s
->active
? session_bus_path(s
->active
) : strdup("/");
54 return sd_bus_message_append(reply
, "(so)", s
->active
? s
->active
->id
: "", p
);
57 static int property_get_can_multi_session(
60 const char *interface
,
62 sd_bus_message
*reply
,
64 sd_bus_error
*error
) {
72 return sd_bus_message_append(reply
, "b", seat_can_multi_session(s
));
75 static int property_get_can_tty(
78 const char *interface
,
80 sd_bus_message
*reply
,
82 sd_bus_error
*error
) {
90 return sd_bus_message_append(reply
, "b", seat_can_tty(s
));
93 static int property_get_can_graphical(
96 const char *interface
,
98 sd_bus_message
*reply
,
100 sd_bus_error
*error
) {
108 return sd_bus_message_append(reply
, "b", seat_can_graphical(s
));
111 static int property_get_sessions(
114 const char *interface
,
115 const char *property
,
116 sd_bus_message
*reply
,
118 sd_bus_error
*error
) {
128 r
= sd_bus_message_open_container(reply
, 'a', "(so)");
132 LIST_FOREACH(sessions_by_seat
, session
, s
->sessions
) {
133 _cleanup_free_
char *p
= NULL
;
135 p
= session_bus_path(session
);
139 r
= sd_bus_message_append(reply
, "(so)", session
->id
, p
);
145 r
= sd_bus_message_close_container(reply
);
152 static int property_get_idle_hint(
155 const char *interface
,
156 const char *property
,
157 sd_bus_message
*reply
,
159 sd_bus_error
*error
) {
167 return sd_bus_message_append(reply
, "b", seat_get_idle_hint(s
, NULL
) > 0);
170 static int property_get_idle_since_hint(
173 const char *interface
,
174 const char *property
,
175 sd_bus_message
*reply
,
177 sd_bus_error
*error
) {
188 r
= seat_get_idle_hint(s
, &t
);
192 u
= streq(property
, "IdleSinceHint") ? t
.realtime
: t
.monotonic
;
194 return sd_bus_message_append(reply
, "t", u
);
197 int bus_seat_method_terminate(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
204 r
= bus_verify_polkit_async(
207 "org.freedesktop.login1.manage",
211 &s
->manager
->polkit_registry
,
216 return 1; /* Will call us back */
218 r
= seat_stop_sessions(s
, true);
222 return sd_bus_reply_method_return(message
, NULL
);
225 static int method_activate_session(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
234 r
= sd_bus_message_read(message
, "s", &name
);
238 session
= hashmap_get(s
->manager
->sessions
, name
);
240 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_SESSION
, "No session '%s' known", name
);
242 if (session
->seat
!= s
)
243 return sd_bus_error_setf(error
, BUS_ERROR_SESSION_NOT_ON_SEAT
, "Session %s not on seat %s", name
, s
->id
);
245 r
= session_activate(session
);
249 return sd_bus_reply_method_return(message
, NULL
);
252 static int method_switch_to(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
260 r
= sd_bus_message_read(message
, "u", &to
);
267 r
= seat_switch_to(s
, to
);
271 return sd_bus_reply_method_return(message
, NULL
);
274 static int method_switch_to_next(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
281 r
= seat_switch_to_next(s
);
285 return sd_bus_reply_method_return(message
, NULL
);
288 static int method_switch_to_previous(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
295 r
= seat_switch_to_previous(s
);
299 return sd_bus_reply_method_return(message
, NULL
);
302 const sd_bus_vtable seat_vtable
[] = {
303 SD_BUS_VTABLE_START(0),
305 SD_BUS_PROPERTY("Id", "s", NULL
, offsetof(Seat
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
306 SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
307 SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
308 SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
309 SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
310 SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
311 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
312 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
313 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
315 SD_BUS_METHOD("Terminate", NULL
, NULL
, bus_seat_method_terminate
, SD_BUS_VTABLE_UNPRIVILEGED
),
316 SD_BUS_METHOD("ActivateSession", "s", NULL
, method_activate_session
, SD_BUS_VTABLE_UNPRIVILEGED
),
317 SD_BUS_METHOD("SwitchTo", "u", NULL
, method_switch_to
, SD_BUS_VTABLE_UNPRIVILEGED
),
318 SD_BUS_METHOD("SwitchToNext", NULL
, NULL
, method_switch_to_next
, SD_BUS_VTABLE_UNPRIVILEGED
),
319 SD_BUS_METHOD("SwitchToPrevious", NULL
, NULL
, method_switch_to_previous
, SD_BUS_VTABLE_UNPRIVILEGED
),
324 int seat_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
325 Manager
*m
= userdata
;
335 if (streq(path
, "/org/freedesktop/login1/seat/self")) {
336 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
337 sd_bus_message
*message
;
341 message
= sd_bus_get_current_message(bus
);
345 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_SESSION
|SD_BUS_CREDS_AUGMENT
, &creds
);
349 r
= sd_bus_creds_get_session(creds
, &name
);
353 session
= hashmap_get(m
->sessions
, name
);
357 seat
= session
->seat
;
359 _cleanup_free_
char *e
= NULL
;
362 p
= startswith(path
, "/org/freedesktop/login1/seat/");
366 e
= bus_label_unescape(p
);
370 seat
= hashmap_get(m
->seats
, e
);
380 char *seat_bus_path(Seat
*s
) {
381 _cleanup_free_
char *t
= NULL
;
385 t
= bus_label_escape(s
->id
);
389 return strappend("/org/freedesktop/login1/seat/", t
);
392 int seat_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
393 _cleanup_strv_free_
char **l
= NULL
;
394 sd_bus_message
*message
;
395 Manager
*m
= userdata
;
404 HASHMAP_FOREACH(seat
, m
->seats
, i
) {
407 p
= seat_bus_path(seat
);
411 r
= strv_consume(&l
, p
);
416 message
= sd_bus_get_current_message(bus
);
418 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
422 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_SESSION
|SD_BUS_CREDS_AUGMENT
, &creds
);
424 r
= sd_bus_creds_get_session(creds
, &name
);
426 session
= hashmap_get(m
->sessions
, name
);
427 if (session
&& session
->seat
) {
428 r
= strv_extend(&l
, "/org/freedesktop/login1/seat/self");
442 int seat_send_signal(Seat
*s
, bool new_seat
) {
443 _cleanup_free_
char *p
= NULL
;
447 p
= seat_bus_path(s
);
451 return sd_bus_emit_signal(
453 "/org/freedesktop/login1",
454 "org.freedesktop.login1.Manager",
455 new_seat
? "SeatNew" : "SeatRemoved",
459 int seat_send_changed(Seat
*s
, const char *properties
, ...) {
460 _cleanup_free_
char *p
= NULL
;
468 p
= seat_bus_path(s
);
472 l
= strv_from_stdarg_alloca(properties
);
474 return sd_bus_emit_properties_changed_strv(s
->manager
->bus
, p
, "org.freedesktop.login1.Seat", l
);