chiark / gitweb /
logind: port logind to libsystemd-bus
[elogind.git] / src / login / logind-seat-dbus.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <errno.h>
23 #include <string.h>
24
25 #include "util.h"
26 #include "bus-util.h"
27 #include "strv.h"
28 #include "logind.h"
29 #include "logind-seat.h"
30
31 static int property_get_active_session(
32                 sd_bus *bus,
33                 const char *path,
34                 const char *interface,
35                 const char *property,
36                 sd_bus_message *reply,
37                 sd_bus_error *error,
38                 void *userdata) {
39
40         _cleanup_free_ char *p = NULL;
41         Seat *s = userdata;
42
43         assert(bus);
44         assert(reply);
45         assert(s);
46
47         p = s->active ? session_bus_path(s->active) : strdup("/");
48         if (!p)
49                 return -ENOMEM;
50
51         return sd_bus_message_append(reply, "(so)", s->active ? s->active->id : "", p);
52 }
53
54 static int property_get_can_multi_session(
55                 sd_bus *bus,
56                 const char *path,
57                 const char *interface,
58                 const char *property,
59                 sd_bus_message *reply,
60                 sd_bus_error *error,
61                 void *userdata) {
62
63         Seat *s = userdata;
64
65         assert(bus);
66         assert(reply);
67         assert(s);
68
69         return sd_bus_message_append(reply, "b", seat_can_multi_session(s));
70 }
71
72 static int property_get_can_tty(
73                 sd_bus *bus,
74                 const char *path,
75                 const char *interface,
76                 const char *property,
77                 sd_bus_message *reply,
78                 sd_bus_error *error,
79                 void *userdata) {
80
81         Seat *s = userdata;
82
83         assert(bus);
84         assert(reply);
85         assert(s);
86
87         return sd_bus_message_append(reply, "b", seat_can_tty(s));
88 }
89
90 static int property_get_can_graphical(
91                 sd_bus *bus,
92                 const char *path,
93                 const char *interface,
94                 const char *property,
95                 sd_bus_message *reply,
96                 sd_bus_error *error,
97                 void *userdata) {
98
99         Seat *s = userdata;
100
101         assert(bus);
102         assert(reply);
103         assert(s);
104
105         return sd_bus_message_append(reply, "b", seat_can_tty(s));
106 }
107
108 static int property_get_sessions(
109                 sd_bus *bus,
110                 const char *path,
111                 const char *interface,
112                 const char *property,
113                 sd_bus_message *reply,
114                 sd_bus_error *error,
115                 void *userdata) {
116
117         Seat *s = userdata;
118         Session *session;
119         int r;
120
121         assert(bus);
122         assert(reply);
123         assert(s);
124
125         r = sd_bus_message_open_container(reply, 'a', "(so)");
126         if (r < 0)
127                 return r;
128
129         LIST_FOREACH(sessions_by_seat, session, s->sessions) {
130                 _cleanup_free_ char *p = NULL;
131
132                 p = session_bus_path(session);
133                 if (!p)
134                         return -ENOMEM;
135
136                 r = sd_bus_message_append(reply, "(so)", session->id, p);
137                 if (r < 0)
138                         return r;
139
140         }
141
142         r = sd_bus_message_close_container(reply);
143         if (r < 0)
144                 return r;
145
146         return 1;
147 }
148
149 static int property_get_idle_hint(
150                 sd_bus *bus,
151                 const char *path,
152                 const char *interface,
153                 const char *property,
154                 sd_bus_message *reply,
155                 sd_bus_error *error,
156                 void *userdata) {
157
158         Seat *s = userdata;
159
160         assert(bus);
161         assert(reply);
162         assert(s);
163
164         return sd_bus_message_append(reply, "b", seat_get_idle_hint(s, NULL) > 0);
165 }
166
167 static int property_get_idle_since_hint(
168                 sd_bus *bus,
169                 const char *path,
170                 const char *interface,
171                 const char *property,
172                 sd_bus_message *reply,
173                 sd_bus_error *error,
174                 void *userdata) {
175
176         Seat *s = userdata;
177         dual_timestamp t;
178         uint64_t u;
179         int r;
180
181         assert(bus);
182         assert(reply);
183         assert(s);
184
185         r = seat_get_idle_hint(s, &t);
186         if (r < 0)
187                 return r;
188
189         u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
190
191         return sd_bus_message_append(reply, "t", u);
192 }
193
194 static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata) {
195         Seat *s = userdata;
196         int r;
197
198         assert(bus);
199         assert(message);
200         assert(s);
201
202         r = seat_stop_sessions(s);
203         if (r < 0)
204                 return sd_bus_reply_method_errno(bus, message, r, NULL);
205
206         return sd_bus_reply_method_return(bus, message, NULL);
207 }
208
209 static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata) {
210         Seat *s = userdata;
211         const char *name;
212         Session *session;
213         int r;
214
215         assert(bus);
216         assert(message);
217         assert(s);
218
219         r = sd_bus_message_read(message, "s", &name);
220         if (r < 0)
221                 return sd_bus_reply_method_errno(bus, message, r, NULL);
222
223         session = hashmap_get(s->manager->sessions, name);
224         if (!session)
225                 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
226
227         if (session->seat != s)
228                 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id);
229
230         r = session_activate(session);
231         if (r < 0)
232                 return sd_bus_reply_method_errno(bus, message, r, NULL);
233
234         return sd_bus_reply_method_return(bus, message, NULL);
235 }
236
237 const sd_bus_vtable seat_vtable[] = {
238         SD_BUS_VTABLE_START(0),
239
240         SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), 0),
241         SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
242         SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, 0),
243         SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, 0),
244         SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
245         SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
246         SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
247         SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
248         SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
249
250         SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, 0),
251         SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, 0),
252
253         SD_BUS_VTABLE_END
254 };
255
256 int seat_object_find(sd_bus *bus, const char *path, const char *interface, void **found, void *userdata) {
257         _cleanup_free_ char *e = NULL;
258         Manager *m = userdata;
259         Seat *seat;
260         const char *p;
261
262         assert(bus);
263         assert(path);
264         assert(interface);
265         assert(found);
266         assert(m);
267
268         p = startswith(path, "/org/freedesktop/login1/seat/");
269         if (!p)
270                 return 0;
271
272         e = bus_path_unescape(p);
273         if (!e)
274                 return -ENOMEM;
275
276         seat = hashmap_get(m->seats, e);
277         if (!seat)
278                 return 0;
279
280         *found = seat;
281         return 1;
282 }
283
284 char *seat_bus_path(Seat *s) {
285         _cleanup_free_ char *t = NULL;
286
287         assert(s);
288
289         t = bus_path_escape(s->id);
290         if (!t)
291                 return NULL;
292
293         return strappend("/org/freedesktop/login1/seat/", t);
294 }
295
296 int seat_node_enumerator(sd_bus *bus, const char *path, char ***nodes, void *userdata) {
297         _cleanup_strv_free_ char **l = NULL;
298         Manager *m = userdata;
299         Seat *seat;
300         Iterator i;
301         int r;
302
303         assert(bus);
304         assert(path);
305         assert(nodes);
306
307         HASHMAP_FOREACH(seat, m->seats, i) {
308                 char *p;
309
310                 p = seat_bus_path(seat);
311                 if (!p)
312                         return -ENOMEM;
313
314                 r = strv_push(&l, p);
315                 if (r < 0) {
316                         free(p);
317                         return r;
318                 }
319         }
320
321         *nodes = l;
322         l = NULL;
323
324         return 1;
325 }
326
327 int seat_send_signal(Seat *s, bool new_seat) {
328         _cleanup_free_ char *p = NULL;
329
330         assert(s);
331
332         p = seat_bus_path(s);
333         if (!p)
334                 return -ENOMEM;
335
336         return sd_bus_emit_signal(
337                         s->manager->bus,
338                         "/org/freedesktop/login1",
339                         "org.freedesktop.login1.Manager",
340                         new_seat ? "SeatNew" : "SeatRemoved",
341                         "so", s->id, p);
342 }
343
344 int seat_send_changed(Seat *s, const char *properties, ...) {
345         _cleanup_free_ char *p = NULL;
346         char **l;
347
348         assert(s);
349
350         if (!s->started)
351                 return 0;
352
353         p = seat_bus_path(s);
354         if (!p)
355                 return -ENOMEM;
356
357         l = strv_from_stdarg_alloca(properties);
358
359         return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);
360 }