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/>.
24 #include <sys/capability.h>
29 #include "bus-errors.h"
30 #include "bus-label.h"
32 #include "logind-seat.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 static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
205 r = seat_stop_sessions(s, true);
209 return sd_bus_reply_method_return(message, NULL);
212 static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
222 r = sd_bus_message_read(message, "s", &name);
226 session = hashmap_get(s->manager->sessions, name);
228 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
230 if (session->seat != s)
231 return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id);
233 r = session_activate(session);
237 return sd_bus_reply_method_return(message, NULL);
240 static int method_switch_to(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
249 r = sd_bus_message_read(message, "u", &to);
256 r = seat_switch_to(s, to);
260 return sd_bus_reply_method_return(message, NULL);
263 static int method_switch_to_next(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
271 r = seat_switch_to_next(s);
275 return sd_bus_reply_method_return(message, NULL);
278 static int method_switch_to_previous(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
286 r = seat_switch_to_previous(s);
290 return sd_bus_reply_method_return(message, NULL);
293 const sd_bus_vtable seat_vtable[] = {
294 SD_BUS_VTABLE_START(0),
296 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST),
297 SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
298 SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST),
299 SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
300 SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
301 SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
302 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
303 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
304 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
306 SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
307 SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED),
308 SD_BUS_METHOD("SwitchTo", "u", NULL, method_switch_to, SD_BUS_VTABLE_UNPRIVILEGED),
309 SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED),
310 SD_BUS_METHOD("SwitchToPrevious", NULL, NULL, method_switch_to_previous, SD_BUS_VTABLE_UNPRIVILEGED),
315 int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
316 Manager *m = userdata;
326 if (streq(path, "/org/freedesktop/login1/seat/self")) {
327 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
328 sd_bus_message *message;
332 message = sd_bus_get_current_message(bus);
336 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
340 r = sd_bus_creds_get_pid(creds, &pid);
344 r = manager_get_session_by_pid(m, pid, &session);
351 seat = session->seat;
353 _cleanup_free_ char *e = NULL;
356 p = startswith(path, "/org/freedesktop/login1/seat/");
360 e = bus_label_unescape(p);
364 seat = hashmap_get(m->seats, e);
373 char *seat_bus_path(Seat *s) {
374 _cleanup_free_ char *t = NULL;
378 t = bus_label_escape(s->id);
382 return strappend("/org/freedesktop/login1/seat/", t);
385 int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
386 _cleanup_strv_free_ char **l = NULL;
387 Manager *m = userdata;
396 HASHMAP_FOREACH(seat, m->seats, i) {
399 p = seat_bus_path(seat);
403 r = strv_consume(&l, p);
414 int seat_send_signal(Seat *s, bool new_seat) {
415 _cleanup_free_ char *p = NULL;
419 p = seat_bus_path(s);
423 return sd_bus_emit_signal(
425 "/org/freedesktop/login1",
426 "org.freedesktop.login1.Manager",
427 new_seat ? "SeatNew" : "SeatRemoved",
431 int seat_send_changed(Seat *s, const char *properties, ...) {
432 _cleanup_free_ char *p = NULL;
440 p = seat_bus_path(s);
444 l = strv_from_stdarg_alloca(properties);
446 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);