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