1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include "alloc-util.h"
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, 0),
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 sd_bus_message
*message
;
338 message
= sd_bus_get_current_message(bus
);
342 r
= manager_get_seat_from_creds(m
, message
, NULL
, error
, &seat
);
346 _cleanup_free_
char *e
= NULL
;
349 p
= startswith(path
, "/org/freedesktop/login1/seat/");
353 e
= bus_label_unescape(p
);
357 seat
= hashmap_get(m
->seats
, e
);
366 char *seat_bus_path(Seat
*s
) {
367 _cleanup_free_
char *t
= NULL
;
371 t
= bus_label_escape(s
->id
);
375 return strappend("/org/freedesktop/login1/seat/", t
);
378 int seat_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
379 _cleanup_strv_free_
char **l
= NULL
;
380 sd_bus_message
*message
;
381 Manager
*m
= userdata
;
390 HASHMAP_FOREACH(seat
, m
->seats
, i
) {
393 p
= seat_bus_path(seat
);
397 r
= strv_consume(&l
, p
);
402 message
= sd_bus_get_current_message(bus
);
404 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
408 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_SESSION
|SD_BUS_CREDS_AUGMENT
, &creds
);
410 r
= sd_bus_creds_get_session(creds
, &name
);
412 session
= hashmap_get(m
->sessions
, name
);
413 if (session
&& session
->seat
) {
414 r
= strv_extend(&l
, "/org/freedesktop/login1/seat/self");
422 *nodes
= TAKE_PTR(l
);
427 int seat_send_signal(Seat
*s
, bool new_seat
) {
428 _cleanup_free_
char *p
= NULL
;
432 p
= seat_bus_path(s
);
436 return sd_bus_emit_signal(
438 "/org/freedesktop/login1",
439 "org.freedesktop.login1.Manager",
440 new_seat
? "SeatNew" : "SeatRemoved",
444 int seat_send_changed(Seat
*s
, const char *properties
, ...) {
445 _cleanup_free_
char *p
= NULL
;
453 p
= seat_bus_path(s
);
457 l
= strv_from_stdarg_alloca(properties
);
459 return sd_bus_emit_properties_changed_strv(s
->manager
->bus
, p
, "org.freedesktop.login1.Seat", l
);