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