chiark / gitweb /
Remove src/fstab-generator
[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 int bus_seat_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 = bus_verify_polkit_async(
205                         message,
206                         CAP_KILL,
207                         "org.freedesktop.login1.manage",
208                         false,
209                         UID_INVALID,
210                         &s->manager->polkit_registry,
211                         error);
212         if (r < 0)
213                 return r;
214         if (r == 0)
215                 return 1; /* Will call us back */
216
217         r = seat_stop_sessions(s, true);
218         if (r < 0)
219                 return r;
220
221         return sd_bus_reply_method_return(message, NULL);
222 }
223
224 static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
225         Seat *s = userdata;
226         const char *name;
227         Session *session;
228         int r;
229
230         assert(bus);
231         assert(message);
232         assert(s);
233
234         r = sd_bus_message_read(message, "s", &name);
235         if (r < 0)
236                 return r;
237
238         session = hashmap_get(s->manager->sessions, name);
239         if (!session)
240                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
241
242         if (session->seat != s)
243                 return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id);
244
245         r = session_activate(session);
246         if (r < 0)
247                 return r;
248
249         return sd_bus_reply_method_return(message, NULL);
250 }
251
252 static int method_switch_to(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
253         Seat *s = userdata;
254         unsigned int to;
255         int r;
256
257         assert(bus);
258         assert(message);
259         assert(s);
260
261         r = sd_bus_message_read(message, "u", &to);
262         if (r < 0)
263                 return r;
264
265         if (to <= 0)
266                 return -EINVAL;
267
268         r = seat_switch_to(s, to);
269         if (r < 0)
270                 return r;
271
272         return sd_bus_reply_method_return(message, NULL);
273 }
274
275 static int method_switch_to_next(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
276         Seat *s = userdata;
277         int r;
278
279         assert(bus);
280         assert(message);
281         assert(s);
282
283         r = seat_switch_to_next(s);
284         if (r < 0)
285                 return r;
286
287         return sd_bus_reply_method_return(message, NULL);
288 }
289
290 static int method_switch_to_previous(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
291         Seat *s = userdata;
292         int r;
293
294         assert(bus);
295         assert(message);
296         assert(s);
297
298         r = seat_switch_to_previous(s);
299         if (r < 0)
300                 return r;
301
302         return sd_bus_reply_method_return(message, NULL);
303 }
304
305 const sd_bus_vtable seat_vtable[] = {
306         SD_BUS_VTABLE_START(0),
307
308         SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST),
309         SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
310         SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST),
311         SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
312         SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
313         SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
314         SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
315         SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
316         SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
317
318         SD_BUS_METHOD("Terminate", NULL, NULL, bus_seat_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
319         SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED),
320         SD_BUS_METHOD("SwitchTo", "u", NULL, method_switch_to, SD_BUS_VTABLE_UNPRIVILEGED),
321         SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED),
322         SD_BUS_METHOD("SwitchToPrevious", NULL, NULL, method_switch_to_previous, SD_BUS_VTABLE_UNPRIVILEGED),
323
324         SD_BUS_VTABLE_END
325 };
326
327 int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
328         Manager *m = userdata;
329         Seat *seat;
330         int r;
331
332         assert(bus);
333         assert(path);
334         assert(interface);
335         assert(found);
336         assert(m);
337
338         if (streq(path, "/org/freedesktop/login1/seat/self")) {
339                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
340                 sd_bus_message *message;
341                 Session *session;
342                 const char *name;
343
344                 message = sd_bus_get_current_message(bus);
345                 if (!message)
346                         return 0;
347
348                 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
349                 if (r < 0)
350                         return r;
351
352                 r = sd_bus_creds_get_session(creds, &name);
353                 if (r < 0)
354                         return r;
355
356                 session = hashmap_get(m->sessions, name);
357                 if (!session)
358                         return 0;
359
360                 seat = session->seat;
361         } else {
362                 _cleanup_free_ char *e = NULL;
363                 const char *p;
364
365                 p = startswith(path, "/org/freedesktop/login1/seat/");
366                 if (!p)
367                         return 0;
368
369                 e = bus_label_unescape(p);
370                 if (!e)
371                         return -ENOMEM;
372
373                 seat = hashmap_get(m->seats, e);
374         }
375
376         if (!seat)
377                 return 0;
378
379         *found = seat;
380         return 1;
381 }
382
383 char *seat_bus_path(Seat *s) {
384         _cleanup_free_ char *t = NULL;
385
386         assert(s);
387
388         t = bus_label_escape(s->id);
389         if (!t)
390                 return NULL;
391
392         return strappend("/org/freedesktop/login1/seat/", t);
393 }
394
395 int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
396         _cleanup_strv_free_ char **l = NULL;
397         sd_bus_message *message;
398         Manager *m = userdata;
399         Seat *seat;
400         Iterator i;
401         int r;
402
403         assert(bus);
404         assert(path);
405         assert(nodes);
406
407         HASHMAP_FOREACH(seat, m->seats, i) {
408                 char *p;
409
410                 p = seat_bus_path(seat);
411                 if (!p)
412                         return -ENOMEM;
413
414                 r = strv_consume(&l, p);
415                 if (r < 0)
416                         return r;
417         }
418
419         message = sd_bus_get_current_message(bus);
420         if (message) {
421                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
422                 const char *name;
423                 Session *session;
424
425                 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
426                 if (r >= 0) {
427                         r = sd_bus_creds_get_session(creds, &name);
428                         if (r >= 0) {
429                                 session = hashmap_get(m->sessions, name);
430                                 if (session && session->seat) {
431                                         r = strv_extend(&l, "/org/freedesktop/login1/seat/self");
432                                         if (r < 0)
433                                                 return r;
434                                 }
435                         }
436                 }
437         }
438
439         *nodes = l;
440         l = NULL;
441
442         return 1;
443 }
444
445 int seat_send_signal(Seat *s, bool new_seat) {
446         _cleanup_free_ char *p = NULL;
447
448         assert(s);
449
450         p = seat_bus_path(s);
451         if (!p)
452                 return -ENOMEM;
453
454         return sd_bus_emit_signal(
455                         s->manager->bus,
456                         "/org/freedesktop/login1",
457                         "org.freedesktop.login1.Manager",
458                         new_seat ? "SeatNew" : "SeatRemoved",
459                         "so", s->id, p);
460 }
461
462 int seat_send_changed(Seat *s, const char *properties, ...) {
463         _cleanup_free_ char *p = NULL;
464         char **l;
465
466         assert(s);
467
468         if (!s->started)
469                 return 0;
470
471         p = seat_bus_path(s);
472         if (!p)
473                 return -ENOMEM;
474
475         l = strv_from_stdarg_alloca(properties);
476
477         return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);
478 }