]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-seat-dbus.c
bus: decorate the various object vtables with SD_BUS_VTABLE_PROPERTY_CONST where...
[thirdparty/systemd.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 #include <sys/capability.h>
25
26 #include "util.h"
27 #include "bus-util.h"
28 #include "strv.h"
29 #include "bus-errors.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);
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 const sd_bus_vtable seat_vtable[] = {
240 SD_BUS_VTABLE_START(0),
241
242 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST),
243 SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
244 SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST),
245 SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
246 SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
247 SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
248 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
249 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
250 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
251
252 SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
253 SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED),
254
255 SD_BUS_VTABLE_END
256 };
257
258 int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
259 Manager *m = userdata;
260 Seat *seat;
261 int r;
262
263 assert(bus);
264 assert(path);
265 assert(interface);
266 assert(found);
267 assert(m);
268
269 if (streq(path, "/org/freedesktop/login1/seat/self")) {
270 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
271 sd_bus_message *message;
272 Session *session;
273 pid_t pid;
274
275 message = sd_bus_get_current(bus);
276 if (!message)
277 return 0;
278
279 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
280 if (r < 0)
281 return r;
282
283 r = sd_bus_creds_get_pid(creds, &pid);
284 if (r < 0)
285 return r;
286
287 r = manager_get_session_by_pid(m, pid, &session);
288 if (r <= 0)
289 return 0;
290
291 if (!session->seat)
292 return 0;
293
294 seat = session->seat;
295 } else {
296 _cleanup_free_ char *e = NULL;
297 const char *p;
298
299 p = startswith(path, "/org/freedesktop/login1/seat/");
300 if (!p)
301 return 0;
302
303 e = sd_bus_label_unescape(p);
304 if (!e)
305 return -ENOMEM;
306
307 seat = hashmap_get(m->seats, e);
308 if (!seat)
309 return 0;
310 }
311
312 *found = seat;
313 return 1;
314 }
315
316 char *seat_bus_path(Seat *s) {
317 _cleanup_free_ char *t = NULL;
318
319 assert(s);
320
321 t = sd_bus_label_escape(s->id);
322 if (!t)
323 return NULL;
324
325 return strappend("/org/freedesktop/login1/seat/", t);
326 }
327
328 int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
329 _cleanup_strv_free_ char **l = NULL;
330 Manager *m = userdata;
331 Seat *seat;
332 Iterator i;
333 int r;
334
335 assert(bus);
336 assert(path);
337 assert(nodes);
338
339 HASHMAP_FOREACH(seat, m->seats, i) {
340 char *p;
341
342 p = seat_bus_path(seat);
343 if (!p)
344 return -ENOMEM;
345
346 r = strv_push(&l, p);
347 if (r < 0) {
348 free(p);
349 return r;
350 }
351 }
352
353 *nodes = l;
354 l = NULL;
355
356 return 1;
357 }
358
359 int seat_send_signal(Seat *s, bool new_seat) {
360 _cleanup_free_ char *p = NULL;
361
362 assert(s);
363
364 p = seat_bus_path(s);
365 if (!p)
366 return -ENOMEM;
367
368 return sd_bus_emit_signal(
369 s->manager->bus,
370 "/org/freedesktop/login1",
371 "org.freedesktop.login1.Manager",
372 new_seat ? "SeatNew" : "SeatRemoved",
373 "so", s->id, p);
374 }
375
376 int seat_send_changed(Seat *s, const char *properties, ...) {
377 _cleanup_free_ char *p = NULL;
378 char **l;
379
380 assert(s);
381
382 if (!s->started)
383 return 0;
384
385 p = seat_bus_path(s);
386 if (!p)
387 return -ENOMEM;
388
389 l = strv_from_stdarg_alloca(properties);
390
391 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);
392 }