]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-seat-dbus.c
logind: expose CanGraphical and CanTTY properties on seat objects
[thirdparty/systemd.git] / src / login / logind-seat-dbus.c
CommitLineData
3f49d45a
LP
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
5430f7f2
LP
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
3f49d45a
LP
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
5430f7f2 16 Lesser General Public License for more details.
3f49d45a 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
3f49d45a
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
a185c5aa 23#include <string.h>
3f49d45a
LP
24
25#include "logind.h"
26#include "logind-seat.h"
27#include "dbus-common.h"
28#include "util.h"
29
30#define BUS_SEAT_INTERFACE \
31 " <interface name=\"org.freedesktop.login1.Seat\">\n" \
32 " <method name=\"Terminate\"/>\n" \
f401e48c
LP
33 " <method name=\"ActivateSession\">\n" \
34 " <arg name=\"id\" type=\"s\"/>\n" \
35 " </method>\n" \
3f49d45a 36 " <property name=\"Id\" type=\"s\" access=\"read\"/>\n" \
f401e48c 37 " <property name=\"ActiveSession\" type=\"so\" access=\"read\"/>\n" \
64559e8b 38 " <property name=\"CanMultiSession\" type=\"b\" access=\"read\"/>\n" \
f1a8e221
LP
39 " <property name=\"CanTTY\" type=\"b\" access=\"read\"/>\n" \
40 " <property name=\"CanGraphical\" type=\"b\" access=\"read\"/>\n" \
3f49d45a 41 " <property name=\"Sessions\" type=\"a(so)\" access=\"read\"/>\n" \
a185c5aa
LP
42 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
43 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
44 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
3f49d45a
LP
45 " </interface>\n" \
46
47#define INTROSPECTION \
48 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
49 "<node>\n" \
50 BUS_SEAT_INTERFACE \
51 BUS_PROPERTIES_INTERFACE \
52 BUS_PEER_INTERFACE \
53 BUS_INTROSPECTABLE_INTERFACE \
54 "</node>\n"
55
56#define INTERFACES_LIST \
57 BUS_GENERIC_INTERFACES_LIST \
58 "org.freedesktop.login1.Seat\0"
59
60static int bus_seat_append_active(DBusMessageIter *i, const char *property, void *data) {
61 DBusMessageIter sub;
62 Seat *s = data;
63 const char *id, *path;
64 char *p = NULL;
65
66 assert(i);
67 assert(property);
68 assert(s);
69
70 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
71 return -ENOMEM;
72
73 if (s->active) {
74 id = s->active->id;
75 path = p = session_bus_path(s->active);
76
77 if (!p)
78 return -ENOMEM;
79 } else {
80 id = "";
81 path = "/";
82 }
83
84 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
85 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
86 free(p);
87 return -ENOMEM;
88 }
89
90 free(p);
91
92 if (!dbus_message_iter_close_container(i, &sub))
93 return -ENOMEM;
94
95 return 0;
96}
97
98static int bus_seat_append_sessions(DBusMessageIter *i, const char *property, void *data) {
99 DBusMessageIter sub, sub2;
100 Seat *s = data;
101 Session *session;
102
103 assert(i);
104 assert(property);
105 assert(s);
106
dec15e92 107 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(so)", &sub))
3f49d45a
LP
108 return -ENOMEM;
109
110 LIST_FOREACH(sessions_by_seat, session, s->sessions) {
111 char *p;
112
113 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
114 return -ENOMEM;
115
116 p = session_bus_path(session);
117 if (!p)
118 return -ENOMEM;
119
120 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
121 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
122 free(p);
123 return -ENOMEM;
124 }
125
126 free(p);
127
128 if (!dbus_message_iter_close_container(&sub, &sub2))
129 return -ENOMEM;
130 }
131
132 if (!dbus_message_iter_close_container(i, &sub))
133 return -ENOMEM;
134
135 return 0;
136}
137
f1a8e221 138static int bus_seat_append_can_multi_session(DBusMessageIter *i, const char *property, void *data) {
f401e48c
LP
139 Seat *s = data;
140 dbus_bool_t b;
141
142 assert(i);
143 assert(property);
144 assert(s);
145
addedec4 146 b = seat_can_multi_session(s);
f401e48c
LP
147
148 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
149 return -ENOMEM;
150
151 return 0;
152}
153
f1a8e221
LP
154static int bus_seat_append_can_tty(DBusMessageIter *i, const char *property, void *data) {
155 Seat *s = data;
156 dbus_bool_t b;
157
158 assert(i);
159 assert(property);
160 assert(s);
161
162 b = seat_can_tty(s);
163
164 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
165 return -ENOMEM;
166
167 return 0;
168}
169
170static int bus_seat_append_can_graphical(DBusMessageIter *i, const char *property, void *data) {
171 Seat *s = data;
172 dbus_bool_t b;
173
174 assert(i);
175 assert(property);
176 assert(s);
177
178 b = seat_can_graphical(s);
179
180 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
181 return -ENOMEM;
182
183 return 0;
184}
185
a185c5aa
LP
186static int bus_seat_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
187 Seat *s = data;
77527da0 188 dbus_bool_t b;
a185c5aa
LP
189
190 assert(i);
191 assert(property);
192 assert(s);
193
77527da0 194 b = seat_get_idle_hint(s, NULL) > 0;
a185c5aa
LP
195 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
196 return -ENOMEM;
197
198 return 0;
199}
200
201static int bus_seat_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
202 Seat *s = data;
203 dual_timestamp t;
204 uint64_t k;
205
206 assert(i);
207 assert(property);
208 assert(s);
209
210 seat_get_idle_hint(s, &t);
211 k = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
212
213 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &k))
214 return -ENOMEM;
215
216 return 0;
217}
218
3f49d45a
LP
219static int get_seat_for_path(Manager *m, const char *path, Seat **_s) {
220 Seat *s;
221 char *id;
222
223 assert(m);
224 assert(path);
225 assert(_s);
226
227 if (!startswith(path, "/org/freedesktop/login1/seat/"))
228 return -EINVAL;
229
230 id = bus_path_unescape(path + 29);
231 if (!id)
232 return -ENOMEM;
233
234 s = hashmap_get(m->seats, id);
235 free(id);
236
237 if (!s)
238 return -ENOENT;
239
240 *_s = s;
241 return 0;
242}
243
d200735e
MS
244static const BusProperty bus_login_seat_properties[] = {
245 { "Id", bus_property_append_string, "s", offsetof(Seat, id), true },
246 { "ActiveSession", bus_seat_append_active, "(so)", 0 },
f1a8e221
LP
247 { "CanMultiSession", bus_seat_append_can_multi_session, "b", 0 },
248 { "CanTTY", bus_seat_append_can_tty, "b", 0 },
249 { "CanGraphical", bus_seat_append_can_graphical, "b", 0 },
d200735e
MS
250 { "Sessions", bus_seat_append_sessions, "a(so)", 0 },
251 { "IdleHint", bus_seat_append_idle_hint, "b", 0 },
252 { "IdleSinceHint", bus_seat_append_idle_hint_since, "t", 0 },
253 { "IdleSinceHintMonotonic", bus_seat_append_idle_hint_since, "t", 0 },
254 { NULL, }
255};
256
3f49d45a
LP
257static DBusHandlerResult seat_message_dispatch(
258 Seat *s,
259 DBusConnection *connection,
260 DBusMessage *message) {
261
a185c5aa
LP
262 DBusError error;
263 DBusMessage *reply = NULL;
264 int r;
265
3f49d45a
LP
266 assert(s);
267 assert(connection);
268 assert(message);
269
a185c5aa
LP
270 dbus_error_init(&error);
271
272 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "Terminate")) {
273
274 r = seat_stop_sessions(s);
275 if (r < 0)
276 return bus_send_error_reply(connection, message, NULL, r);
277
278 reply = dbus_message_new_method_return(message);
279 if (!reply)
280 goto oom;
281
282 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Seat", "ActivateSession")) {
283 const char *name;
284 Session *session;
285
286 if (!dbus_message_get_args(
287 message,
288 &error,
289 DBUS_TYPE_STRING, &name,
290 DBUS_TYPE_INVALID))
291 return bus_send_error_reply(connection, message, &error, -EINVAL);
292
293 session = hashmap_get(s->manager->sessions, name);
294 if (!session || session->seat != s)
295 return bus_send_error_reply(connection, message, &error, -ENOENT);
296
297 r = session_activate(session);
298 if (r < 0)
299 return bus_send_error_reply(connection, message, NULL, r);
300
301 reply = dbus_message_new_method_return(message);
302 if (!reply)
303 goto oom;
d200735e
MS
304 } else {
305 const BusBoundProperties bps[] = {
306 { "org.freedesktop.login1.Seat", bus_login_seat_properties, s },
307 { NULL, }
308 };
309 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
310 }
a185c5aa
LP
311
312 if (reply) {
313 if (!dbus_connection_send(connection, reply, NULL))
314 goto oom;
315
316 dbus_message_unref(reply);
317 }
318
319 return DBUS_HANDLER_RESULT_HANDLED;
320
321oom:
322 if (reply)
323 dbus_message_unref(reply);
324
325 dbus_error_free(&error);
326
327 return DBUS_HANDLER_RESULT_NEED_MEMORY;
3f49d45a
LP
328}
329
330static DBusHandlerResult seat_message_handler(
331 DBusConnection *connection,
332 DBusMessage *message,
333 void *userdata) {
334
335 Manager *m = userdata;
336 Seat *s;
337 int r;
338
339 r = get_seat_for_path(m, dbus_message_get_path(message), &s);
340 if (r < 0) {
341
342 if (r == -ENOMEM)
343 return DBUS_HANDLER_RESULT_NEED_MEMORY;
344
345 if (r == -ENOENT) {
346 DBusError e;
347
348 dbus_error_init(&e);
349 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown seat");
350 return bus_send_error_reply(connection, message, &e, r);
351 }
352
353 return bus_send_error_reply(connection, message, NULL, r);
354 }
355
356 return seat_message_dispatch(s, connection, message);
357}
358
359const DBusObjectPathVTable bus_seat_vtable = {
360 .message_function = seat_message_handler
361};
362
363char *seat_bus_path(Seat *s) {
364 char *t, *r;
365
366 assert(s);
367
368 t = bus_path_escape(s->id);
369 if (!t)
370 return NULL;
371
372 r = strappend("/org/freedesktop/login1/seat/", t);
373 free(t);
374
375 return r;
376}
da119395
LP
377
378int seat_send_signal(Seat *s, bool new_seat) {
379 DBusMessage *m;
380 int r = -ENOMEM;
381 char *p = NULL;
382
383 assert(s);
384
385 m = dbus_message_new_signal("/org/freedesktop/login1",
386 "org.freedesktop.login1.Manager",
387 new_seat ? "SeatNew" : "SeatRemoved");
388
389 if (!m)
390 return -ENOMEM;
391
392 p = seat_bus_path(s);
393 if (!p)
394 goto finish;
395
396 if (!dbus_message_append_args(
397 m,
398 DBUS_TYPE_STRING, &s->id,
399 DBUS_TYPE_OBJECT_PATH, &p,
400 DBUS_TYPE_INVALID))
401 goto finish;
402
403 if (!dbus_connection_send(s->manager->bus, m, NULL))
404 goto finish;
405
406 r = 0;
407
408finish:
409 dbus_message_unref(m);
410 free(p);
411
412 return r;
413}
9418f147
LP
414
415int seat_send_changed(Seat *s, const char *properties) {
416 DBusMessage *m;
417 int r = -ENOMEM;
418 char *p = NULL;
419
420 assert(s);
421
ed18b08b
LP
422 if (!s->started)
423 return 0;
424
9418f147
LP
425 p = seat_bus_path(s);
426 if (!p)
427 return -ENOMEM;
428
429 m = bus_properties_changed_new(p, "org.freedesktop.login1.Seat", properties);
430 if (!m)
431 goto finish;
432
433 if (!dbus_connection_send(s->manager->bus, m, NULL))
434 goto finish;
435
436 r = 0;
437
438finish:
439 if (m)
440 dbus_message_unref(m);
441 free(p);
442
443 return r;
444}