chiark / gitweb /
c59dfd93388bc4b9d908cd0210ec20717513bd5d
[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         Manager *m = userdata;
258         Seat *seat;
259         int r;
260
261         assert(bus);
262         assert(path);
263         assert(interface);
264         assert(found);
265         assert(m);
266
267         if (streq(path, "/org/freedesktop/login1/seat/self")) {
268                 sd_bus_message *message;
269                 Session *session;
270                 pid_t pid;
271
272                 message = sd_bus_get_current(bus);
273                 if (!message)
274                         return 0;
275
276                 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
277                 if (r < 0)
278                         return 0;
279
280                 r = manager_get_session_by_pid(m, pid, &session);
281                 if (r <= 0)
282                         return 0;
283
284                 if (!session->seat)
285                         return 0;
286
287                 seat = session->seat;
288         } else {
289                 _cleanup_free_ char *e = NULL;
290                 const char *p;
291
292                 p = startswith(path, "/org/freedesktop/login1/seat/");
293                 if (!p)
294                         return 0;
295
296                 e = bus_path_unescape(p);
297                 if (!e)
298                         return -ENOMEM;
299
300                 seat = hashmap_get(m->seats, e);
301                 if (!seat)
302                         return 0;
303         }
304
305         *found = seat;
306         return 1;
307 }
308
309 char *seat_bus_path(Seat *s) {
310         _cleanup_free_ char *t = NULL;
311
312         assert(s);
313
314         t = bus_path_escape(s->id);
315         if (!t)
316                 return NULL;
317
318         return strappend("/org/freedesktop/login1/seat/", t);
319 }
320
321 int seat_node_enumerator(sd_bus *bus, const char *path, char ***nodes, void *userdata) {
322         _cleanup_strv_free_ char **l = NULL;
323         Manager *m = userdata;
324         Seat *seat;
325         Iterator i;
326         int r;
327
328         assert(bus);
329         assert(path);
330         assert(nodes);
331
332         HASHMAP_FOREACH(seat, m->seats, i) {
333                 char *p;
334
335                 p = seat_bus_path(seat);
336                 if (!p)
337                         return -ENOMEM;
338
339                 r = strv_push(&l, p);
340                 if (r < 0) {
341                         free(p);
342                         return r;
343                 }
344         }
345
346         *nodes = l;
347         l = NULL;
348
349         return 1;
350 }
351
352 int seat_send_signal(Seat *s, bool new_seat) {
353         _cleanup_free_ char *p = NULL;
354
355         assert(s);
356
357         p = seat_bus_path(s);
358         if (!p)
359                 return -ENOMEM;
360
361         return sd_bus_emit_signal(
362                         s->manager->bus,
363                         "/org/freedesktop/login1",
364                         "org.freedesktop.login1.Manager",
365                         new_seat ? "SeatNew" : "SeatRemoved",
366                         "so", s->id, p);
367 }
368
369 int seat_send_changed(Seat *s, const char *properties, ...) {
370         _cleanup_free_ char *p = NULL;
371         char **l;
372
373         assert(s);
374
375         if (!s->started)
376                 return 0;
377
378         p = seat_bus_path(s);
379         if (!p)
380                 return -ENOMEM;
381
382         l = strv_from_stdarg_alloca(properties);
383
384         return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);
385 }