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