chiark / gitweb /
logind: include "self" object links in dbus introspection
[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 "bus-common-errors.h"
29 #include "bus-label.h"
30 #include "logind.h"
31 #include "logind-seat.h"
32
33 static int property_get_active_session(
34                 sd_bus *bus,
35                 const char *path,
36                 const char *interface,
37                 const char *property,
38                 sd_bus_message *reply,
39                 void *userdata,
40                 sd_bus_error *error) {
41
42         _cleanup_free_ char *p = NULL;
43         Seat *s = userdata;
44
45         assert(bus);
46         assert(reply);
47         assert(s);
48
49         p = s->active ? session_bus_path(s->active) : strdup("/");
50         if (!p)
51                 return -ENOMEM;
52
53         return sd_bus_message_append(reply, "(so)", s->active ? s->active->id : "", p);
54 }
55
56 static int property_get_can_multi_session(
57                 sd_bus *bus,
58                 const char *path,
59                 const char *interface,
60                 const char *property,
61                 sd_bus_message *reply,
62                 void *userdata,
63                 sd_bus_error *error) {
64
65         Seat *s = userdata;
66
67         assert(bus);
68         assert(reply);
69         assert(s);
70
71         return sd_bus_message_append(reply, "b", seat_can_multi_session(s));
72 }
73
74 static int property_get_can_tty(
75                 sd_bus *bus,
76                 const char *path,
77                 const char *interface,
78                 const char *property,
79                 sd_bus_message *reply,
80                 void *userdata,
81                 sd_bus_error *error) {
82
83         Seat *s = userdata;
84
85         assert(bus);
86         assert(reply);
87         assert(s);
88
89         return sd_bus_message_append(reply, "b", seat_can_tty(s));
90 }
91
92 static int property_get_can_graphical(
93                 sd_bus *bus,
94                 const char *path,
95                 const char *interface,
96                 const char *property,
97                 sd_bus_message *reply,
98                 void *userdata,
99                 sd_bus_error *error) {
100
101         Seat *s = userdata;
102
103         assert(bus);
104         assert(reply);
105         assert(s);
106
107         return sd_bus_message_append(reply, "b", seat_can_graphical(s));
108 }
109
110 static int property_get_sessions(
111                 sd_bus *bus,
112                 const char *path,
113                 const char *interface,
114                 const char *property,
115                 sd_bus_message *reply,
116                 void *userdata,
117                 sd_bus_error *error) {
118
119         Seat *s = userdata;
120         Session *session;
121         int r;
122
123         assert(bus);
124         assert(reply);
125         assert(s);
126
127         r = sd_bus_message_open_container(reply, 'a', "(so)");
128         if (r < 0)
129                 return r;
130
131         LIST_FOREACH(sessions_by_seat, session, s->sessions) {
132                 _cleanup_free_ char *p = NULL;
133
134                 p = session_bus_path(session);
135                 if (!p)
136                         return -ENOMEM;
137
138                 r = sd_bus_message_append(reply, "(so)", session->id, p);
139                 if (r < 0)
140                         return r;
141
142         }
143
144         r = sd_bus_message_close_container(reply);
145         if (r < 0)
146                 return r;
147
148         return 1;
149 }
150
151 static int property_get_idle_hint(
152                 sd_bus *bus,
153                 const char *path,
154                 const char *interface,
155                 const char *property,
156                 sd_bus_message *reply,
157                 void *userdata,
158                 sd_bus_error *error) {
159
160         Seat *s = userdata;
161
162         assert(bus);
163         assert(reply);
164         assert(s);
165
166         return sd_bus_message_append(reply, "b", seat_get_idle_hint(s, NULL) > 0);
167 }
168
169 static int property_get_idle_since_hint(
170                 sd_bus *bus,
171                 const char *path,
172                 const char *interface,
173                 const char *property,
174                 sd_bus_message *reply,
175                 void *userdata,
176                 sd_bus_error *error) {
177
178         Seat *s = userdata;
179         dual_timestamp t;
180         uint64_t u;
181         int r;
182
183         assert(bus);
184         assert(reply);
185         assert(s);
186
187         r = seat_get_idle_hint(s, &t);
188         if (r < 0)
189                 return r;
190
191         u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
192
193         return sd_bus_message_append(reply, "t", u);
194 }
195
196 static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
197         Seat *s = userdata;
198         int r;
199
200         assert(bus);
201         assert(message);
202         assert(s);
203
204         r = seat_stop_sessions(s, true);
205         if (r < 0)
206                 return r;
207
208         return sd_bus_reply_method_return(message, NULL);
209 }
210
211 static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
212         Seat *s = userdata;
213         const char *name;
214         Session *session;
215         int r;
216
217         assert(bus);
218         assert(message);
219         assert(s);
220
221         r = sd_bus_message_read(message, "s", &name);
222         if (r < 0)
223                 return r;
224
225         session = hashmap_get(s->manager->sessions, name);
226         if (!session)
227                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
228
229         if (session->seat != s)
230                 return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id);
231
232         r = session_activate(session);
233         if (r < 0)
234                 return r;
235
236         return sd_bus_reply_method_return(message, NULL);
237 }
238
239 static int method_switch_to(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
240         Seat *s = userdata;
241         unsigned int to;
242         int r;
243
244         assert(bus);
245         assert(message);
246         assert(s);
247
248         r = sd_bus_message_read(message, "u", &to);
249         if (r < 0)
250                 return r;
251
252         if (to <= 0)
253                 return -EINVAL;
254
255         r = seat_switch_to(s, to);
256         if (r < 0)
257                 return r;
258
259         return sd_bus_reply_method_return(message, NULL);
260 }
261
262 static int method_switch_to_next(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
263         Seat *s = userdata;
264         int r;
265
266         assert(bus);
267         assert(message);
268         assert(s);
269
270         r = seat_switch_to_next(s);
271         if (r < 0)
272                 return r;
273
274         return sd_bus_reply_method_return(message, NULL);
275 }
276
277 static int method_switch_to_previous(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
278         Seat *s = userdata;
279         int r;
280
281         assert(bus);
282         assert(message);
283         assert(s);
284
285         r = seat_switch_to_previous(s);
286         if (r < 0)
287                 return r;
288
289         return sd_bus_reply_method_return(message, NULL);
290 }
291
292 const sd_bus_vtable seat_vtable[] = {
293         SD_BUS_VTABLE_START(0),
294
295         SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST),
296         SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
297         SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST),
298         SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
299         SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
300         SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
301         SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
302         SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
303         SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
304
305         SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
306         SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED),
307         SD_BUS_METHOD("SwitchTo", "u", NULL, method_switch_to, SD_BUS_VTABLE_UNPRIVILEGED),
308         SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED),
309         SD_BUS_METHOD("SwitchToPrevious", NULL, NULL, method_switch_to_previous, SD_BUS_VTABLE_UNPRIVILEGED),
310
311         SD_BUS_VTABLE_END
312 };
313
314 int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
315         Manager *m = userdata;
316         Seat *seat;
317         int r;
318
319         assert(bus);
320         assert(path);
321         assert(interface);
322         assert(found);
323         assert(m);
324
325         if (streq(path, "/org/freedesktop/login1/seat/self")) {
326                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
327                 sd_bus_message *message;
328                 Session *session;
329                 pid_t pid;
330
331                 message = sd_bus_get_current_message(bus);
332                 if (!message)
333                         return 0;
334
335                 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
336                 if (r < 0)
337                         return r;
338
339                 r = sd_bus_creds_get_pid(creds, &pid);
340                 if (r < 0)
341                         return r;
342
343                 r = manager_get_session_by_pid(m, pid, &session);
344                 if (r <= 0)
345                         return 0;
346
347                 if (!session->seat)
348                         return 0;
349
350                 seat = session->seat;
351         } else {
352                 _cleanup_free_ char *e = NULL;
353                 const char *p;
354
355                 p = startswith(path, "/org/freedesktop/login1/seat/");
356                 if (!p)
357                         return 0;
358
359                 e = bus_label_unescape(p);
360                 if (!e)
361                         return -ENOMEM;
362
363                 seat = hashmap_get(m->seats, e);
364                 if (!seat)
365                         return 0;
366         }
367
368         *found = seat;
369         return 1;
370 }
371
372 char *seat_bus_path(Seat *s) {
373         _cleanup_free_ char *t = NULL;
374
375         assert(s);
376
377         t = bus_label_escape(s->id);
378         if (!t)
379                 return NULL;
380
381         return strappend("/org/freedesktop/login1/seat/", t);
382 }
383
384 int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
385         _cleanup_strv_free_ char **l = NULL;
386         Manager *m = userdata;
387         Seat *seat;
388         Iterator i;
389         int r;
390
391         assert(bus);
392         assert(path);
393         assert(nodes);
394
395         HASHMAP_FOREACH(seat, m->seats, i) {
396                 char *p;
397
398                 p = seat_bus_path(seat);
399                 if (!p)
400                         return -ENOMEM;
401
402                 r = strv_consume(&l, p);
403                 if (r < 0)
404                         return r;
405         }
406
407         r = strv_extend(&l, "/org/freedesktop/login1/seat/self");
408         if (r < 0)
409                 return r;
410
411         *nodes = l;
412         l = NULL;
413
414         return 1;
415 }
416
417 int seat_send_signal(Seat *s, bool new_seat) {
418         _cleanup_free_ char *p = NULL;
419
420         assert(s);
421
422         p = seat_bus_path(s);
423         if (!p)
424                 return -ENOMEM;
425
426         return sd_bus_emit_signal(
427                         s->manager->bus,
428                         "/org/freedesktop/login1",
429                         "org.freedesktop.login1.Manager",
430                         new_seat ? "SeatNew" : "SeatRemoved",
431                         "so", s->id, p);
432 }
433
434 int seat_send_changed(Seat *s, const char *properties, ...) {
435         _cleanup_free_ char *p = NULL;
436         char **l;
437
438         assert(s);
439
440         if (!s->started)
441                 return 0;
442
443         p = seat_bus_path(s);
444         if (!p)
445                 return -ENOMEM;
446
447         l = strv_from_stdarg_alloca(properties);
448
449         return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);
450 }