]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/dbus-common.c
relicense to LGPLv2.1 (with exceptions)
[thirdparty/systemd.git] / src / dbus-common.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
9a1ac7b9
LP
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 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
9a1ac7b9
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.
9a1ac7b9 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
9a1ac7b9
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <assert.h>
23#include <sys/socket.h>
24#include <errno.h>
25#include <unistd.h>
a8f11321
LP
26#include <stdio.h>
27#include <stdlib.h>
9a1ac7b9 28#include <dbus/dbus.h>
bfebab7f 29#include <string.h>
3df5bf61 30#include <sys/epoll.h>
9a1ac7b9
LP
31
32#include "log.h"
33#include "dbus-common.h"
b9978121 34#include "util.h"
f6a6225e 35#include "def.h"
bfebab7f 36#include "strv.h"
9a1ac7b9
LP
37
38int bus_check_peercred(DBusConnection *c) {
39 int fd;
40 struct ucred ucred;
41 socklen_t l;
42
43 assert(c);
44
45 assert_se(dbus_connection_get_unix_fd(c, &fd));
46
47 l = sizeof(struct ucred);
48 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) {
49 log_error("SO_PEERCRED failed: %m");
50 return -errno;
51 }
52
53 if (l != sizeof(struct ucred)) {
54 log_error("SO_PEERCRED returned wrong size.");
55 return -E2BIG;
56 }
57
be81bfc4 58 if (ucred.uid != 0 && ucred.uid != geteuid())
9a1ac7b9
LP
59 return -EPERM;
60
61 return 1;
62}
63
a8f11321
LP
64static int sync_auth(DBusConnection *bus, DBusError *error) {
65 usec_t begin, tstamp;
9a1ac7b9 66
a8f11321 67 assert(bus);
b9978121 68
a8f11321
LP
69 /* This complexity should probably move into D-Bus itself:
70 *
71 * https://bugs.freedesktop.org/show_bug.cgi?id=35189 */
9a1ac7b9 72
a8f11321
LP
73 begin = tstamp = now(CLOCK_MONOTONIC);
74 for (;;) {
9a1ac7b9 75
f6a6225e 76 if (tstamp > begin + DEFAULT_TIMEOUT_USEC)
a8f11321 77 break;
9a1ac7b9 78
a8f11321
LP
79 if (dbus_connection_get_is_authenticated(bus))
80 break;
f4579ce7 81
f6a6225e 82 if (!dbus_connection_read_write_dispatch(bus, ((begin + DEFAULT_TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC))
a8f11321 83 break;
b9978121 84
a8f11321
LP
85 tstamp = now(CLOCK_MONOTONIC);
86 }
b9978121 87
a8f11321
LP
88 if (!dbus_connection_get_is_connected(bus)) {
89 dbus_set_error_const(error, DBUS_ERROR_NO_SERVER, "Connection terminated during authentication.");
90 return -ECONNREFUSED;
91 }
b9978121 92
a8f11321
LP
93 if (!dbus_connection_get_is_authenticated(bus)) {
94 dbus_set_error_const(error, DBUS_ERROR_TIMEOUT, "Failed to authenticate in time.");
95 return -EACCES;
96 }
b9978121 97
a8f11321
LP
98 return 0;
99}
b9978121 100
be81bfc4
LP
101int bus_connect(DBusBusType t, DBusConnection **_bus, bool *_private, DBusError *error) {
102 DBusConnection *bus = NULL;
a8f11321 103 int r;
be81bfc4 104 bool private = true;
b9978121 105
a8f11321 106 assert(_bus);
b9978121 107
a8f11321 108 if (geteuid() == 0 && t == DBUS_BUS_SYSTEM) {
be81bfc4
LP
109 /* If we are root, then let's talk directly to the
110 * system instance, instead of going via the bus */
111
112 bus = dbus_connection_open_private("unix:path=/run/systemd/private", error);
113 if (!bus)
114 return -EIO;
115
116 } else {
117 if (t == DBUS_BUS_SESSION) {
118 const char *e;
91b22f21 119
be81bfc4
LP
120 /* If we are supposed to talk to the instance,
121 * try via XDG_RUNTIME_DIR first, then
122 * fallback to normal bus access */
123
124 e = getenv("XDG_RUNTIME_DIR");
125 if (e) {
126 char *p;
127
128 if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0)
129 return -ENOMEM;
130
131 bus = dbus_connection_open_private(p, NULL);
132 free(p);
133 }
134 }
91b22f21 135
be81bfc4
LP
136 if (!bus) {
137 bus = dbus_bus_get_private(t, error);
138 if (!bus)
91b22f21 139 return -EIO;
be81bfc4
LP
140
141 private = false;
91b22f21 142 }
be81bfc4 143 }
a8f11321 144
be81bfc4 145 dbus_connection_set_exit_on_disconnect(bus, FALSE);
a8f11321 146
be81bfc4 147 if (private) {
a8f11321 148 if (bus_check_peercred(bus) < 0) {
b9978121
LP
149 dbus_connection_close(bus);
150 dbus_connection_unref(bus);
151
a8f11321 152 dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus.");
b9978121
LP
153 return -EACCES;
154 }
9a1ac7b9
LP
155 }
156
be81bfc4
LP
157 r = sync_auth(bus, error);
158 if (r < 0) {
a8f11321
LP
159 dbus_connection_close(bus);
160 dbus_connection_unref(bus);
161 return r;
162 }
163
be81bfc4
LP
164 if (_private)
165 *_private = private;
166
a8f11321
LP
167 *_bus = bus;
168 return 0;
169}
170
171int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error) {
172 DBusConnection *bus;
173 char *p = NULL;
174 int r;
175
176 assert(_bus);
177 assert(user || host);
178
179 if (user && host)
72e764a6 180 asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@%s,argv3=systemd-stdio-bridge", user, host);
a8f11321 181 else if (user)
72e764a6 182 asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@localhost,argv3=systemd-stdio-bridge", user);
a8f11321 183 else if (host)
72e764a6 184 asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s,argv3=systemd-stdio-bridge", host);
a8f11321
LP
185
186 if (!p) {
187 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
188 return -ENOMEM;
189 }
190
191 bus = dbus_connection_open_private(p, error);
192 free(p);
193
194 if (!bus)
195 return -EIO;
196
197 dbus_connection_set_exit_on_disconnect(bus, FALSE);
198
199 if ((r = sync_auth(bus, error)) < 0) {
200 dbus_connection_close(bus);
201 dbus_connection_unref(bus);
202 return r;
203 }
204
205 if (!dbus_bus_register(bus, error)) {
206 dbus_connection_close(bus);
207 dbus_connection_unref(bus);
208 return r;
209 }
210
211 *_bus = bus;
212 return 0;
213}
214
215int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error) {
216 DBusConnection *bus;
217 int r;
218
219 assert(_bus);
220
221 /* Don't bother with PolicyKit if we are root */
222 if (geteuid() == 0)
223 return bus_connect(DBUS_BUS_SYSTEM, _bus, NULL, error);
224
72e764a6
LP
225 bus = dbus_connection_open_private("unixexec:path=pkexec,argv1=" SYSTEMD_STDIO_BRIDGE_BINARY_PATH, error);
226 if (!bus)
a8f11321
LP
227 return -EIO;
228
9a1ac7b9
LP
229 dbus_connection_set_exit_on_disconnect(bus, FALSE);
230
a8f11321
LP
231 if ((r = sync_auth(bus, error)) < 0) {
232 dbus_connection_close(bus);
233 dbus_connection_unref(bus);
234 return r;
235 }
236
237 if (!dbus_bus_register(bus, error)) {
238 dbus_connection_close(bus);
239 dbus_connection_unref(bus);
240 return r;
241 }
242
9a1ac7b9
LP
243 *_bus = bus;
244 return 0;
245}
4cf5d675
LP
246
247const char *bus_error_message(const DBusError *error) {
248 assert(error);
249
250 /* Sometimes the D-Bus server is a little bit too verbose with
251 * its error messages, so let's override them here */
252 if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED))
253 return "Access denied";
254
255 return error->message;
256}
bfebab7f
LP
257
258DBusHandlerResult bus_default_message_handler(
259 DBusConnection *c,
260 DBusMessage *message,
261 const char *introspection,
262 const char *interfaces,
d200735e 263 const BusBoundProperties *bound_properties) {
bfebab7f
LP
264
265 DBusError error;
266 DBusMessage *reply = NULL;
267 int r;
268
269 assert(c);
270 assert(message);
271
272 dbus_error_init(&error);
273
274 if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
275
276 if (!(reply = dbus_message_new_method_return(message)))
277 goto oom;
278
279 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID))
280 goto oom;
281
d200735e 282 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && bound_properties) {
bfebab7f 283 const char *interface, *property;
d200735e 284 const BusBoundProperties *bp;
bfebab7f 285 const BusProperty *p;
d200735e
MS
286 void *data;
287 DBusMessageIter iter, sub;
bfebab7f
LP
288
289 if (!dbus_message_get_args(
290 message,
291 &error,
292 DBUS_TYPE_STRING, &interface,
293 DBUS_TYPE_STRING, &property,
294 DBUS_TYPE_INVALID))
295 return bus_send_error_reply(c, message, &error, -EINVAL);
296
d200735e
MS
297 for (bp = bound_properties; bp->interface; bp++) {
298 if (!streq(bp->interface, interface))
299 continue;
bfebab7f 300
d200735e
MS
301 for (p = bp->properties; p->property; p++)
302 if (streq(p->property, property))
303 goto get_prop;
304 }
bfebab7f 305
d200735e
MS
306 /* no match */
307 if (!nulstr_contains(interfaces, interface))
308 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
309 else
310 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
bfebab7f 311
d200735e 312 return bus_send_error_reply(c, message, &error, -EINVAL);
bfebab7f 313
d200735e
MS
314get_prop:
315 reply = dbus_message_new_method_return(message);
316 if (!reply)
317 goto oom;
bfebab7f 318
d200735e 319 dbus_message_iter_init_append(reply, &iter);
bfebab7f 320
d200735e
MS
321 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
322 goto oom;
bfebab7f 323
d200735e
MS
324 data = (char*)bp->base + p->offset;
325 if (p->indirect)
326 data = *(void**)data;
327 r = p->append(&sub, property, data);
328 if (r < 0) {
329 if (r == -ENOMEM)
bfebab7f 330 goto oom;
bfebab7f 331
d200735e
MS
332 dbus_message_unref(reply);
333 return bus_send_error_reply(c, message, NULL, r);
bfebab7f
LP
334 }
335
d200735e
MS
336 if (!dbus_message_iter_close_container(&iter, &sub))
337 goto oom;
338
339 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && bound_properties) {
bfebab7f 340 const char *interface;
d200735e 341 const BusBoundProperties *bp;
bfebab7f
LP
342 const BusProperty *p;
343 DBusMessageIter iter, sub, sub2, sub3;
344
345 if (!dbus_message_get_args(
346 message,
347 &error,
348 DBUS_TYPE_STRING, &interface,
349 DBUS_TYPE_INVALID))
350 return bus_send_error_reply(c, message, &error, -EINVAL);
351
352 if (interface[0] && !nulstr_contains(interfaces, interface)) {
353 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
354 return bus_send_error_reply(c, message, &error, -EINVAL);
355 }
356
357 if (!(reply = dbus_message_new_method_return(message)))
358 goto oom;
359
360 dbus_message_iter_init_append(reply, &iter);
361
362 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
363 goto oom;
364
d200735e
MS
365 for (bp = bound_properties; bp->interface; bp++) {
366 if (interface[0] && !streq(bp->interface, interface))
bfebab7f
LP
367 continue;
368
d200735e
MS
369 for (p = bp->properties; p->property; p++) {
370 void *data;
bfebab7f 371
d200735e
MS
372 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) ||
373 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) ||
374 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3))
bfebab7f
LP
375 goto oom;
376
d200735e
MS
377 data = (char*)bp->base + p->offset;
378 if (p->indirect)
379 data = *(void**)data;
380 r = p->append(&sub3, p->property, data);
381 if (r < 0) {
382 if (r == -ENOMEM)
383 goto oom;
bfebab7f 384
d200735e
MS
385 dbus_message_unref(reply);
386 return bus_send_error_reply(c, message, NULL, r);
387 }
388
389 if (!dbus_message_iter_close_container(&sub2, &sub3) ||
390 !dbus_message_iter_close_container(&sub, &sub2))
391 goto oom;
392 }
bfebab7f
LP
393 }
394
395 if (!dbus_message_iter_close_container(&iter, &sub))
396 goto oom;
397
d200735e 398 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && bound_properties) {
bfebab7f
LP
399 const char *interface, *property;
400 DBusMessageIter iter;
d200735e 401 const BusBoundProperties *bp;
bfebab7f 402 const BusProperty *p;
d200735e
MS
403 DBusMessageIter sub;
404 char *sig;
9612f07c 405 void *data;
bfebab7f
LP
406
407 if (!dbus_message_iter_init(message, &iter) ||
408 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
409 return bus_send_error_reply(c, message, NULL, -EINVAL);
410
411 dbus_message_iter_get_basic(&iter, &interface);
412
413 if (!dbus_message_iter_next(&iter) ||
414 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
415 return bus_send_error_reply(c, message, NULL, -EINVAL);
416
417 dbus_message_iter_get_basic(&iter, &property);
418
419 if (!dbus_message_iter_next(&iter) ||
420 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT ||
421 dbus_message_iter_has_next(&iter))
422 return bus_send_error_reply(c, message, NULL, -EINVAL);
423
d200735e
MS
424 for (bp = bound_properties; bp->interface; bp++) {
425 if (!streq(bp->interface, interface))
426 continue;
427
428 for (p = bp->properties; p->property; p++)
429 if (streq(p->property, property))
430 goto set_prop;
431 }
bfebab7f 432
d200735e
MS
433 /* no match */
434 if (!nulstr_contains(interfaces, interface))
435 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
436 else
437 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
bfebab7f 438
d200735e 439 return bus_send_error_reply(c, message, &error, -EINVAL);
bfebab7f 440
d200735e
MS
441set_prop:
442 if (!p->set) {
443 dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only");
444 return bus_send_error_reply(c, message, &error, -EINVAL);
445 }
bfebab7f 446
d200735e 447 dbus_message_iter_recurse(&iter, &sub);
bfebab7f 448
d200735e
MS
449 sig = dbus_message_iter_get_signature(&sub);
450 if (!sig)
451 goto oom;
452
453 if (!streq(sig, p->signature)) {
bfebab7f 454 dbus_free(sig);
d200735e
MS
455 return bus_send_error_reply(c, message, NULL, -EINVAL);
456 }
bfebab7f 457
d200735e 458 dbus_free(sig);
bfebab7f 459
9612f07c
MO
460 data = (char*)bp->base + p->offset;
461 if (p->indirect)
462 data = *(void**)data;
463 r = p->set(&sub, property, data);
d200735e
MS
464 if (r < 0) {
465 if (r == -ENOMEM)
bfebab7f 466 goto oom;
d200735e 467 return bus_send_error_reply(c, message, NULL, r);
bfebab7f
LP
468 }
469
d200735e
MS
470 reply = dbus_message_new_method_return(message);
471 if (!reply)
472 goto oom;
cda2b84a
MS
473 } else {
474 const char *interface = dbus_message_get_interface(message);
475
476 if (!interface || !nulstr_contains(interfaces, interface)) {
477 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
478 return bus_send_error_reply(c, message, &error, -EINVAL);
479 }
bfebab7f
LP
480 }
481
482 if (reply) {
483 if (!dbus_connection_send(c, reply, NULL))
484 goto oom;
485
486 dbus_message_unref(reply);
487 return DBUS_HANDLER_RESULT_HANDLED;
488 }
489
490 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
491
492oom:
493 if (reply)
494 dbus_message_unref(reply);
495
496 dbus_error_free(&error);
497
498 return DBUS_HANDLER_RESULT_NEED_MEMORY;
499}
500
501int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) {
502 const char *t = data;
503
504 assert(i);
505 assert(property);
506
507 if (!t)
508 t = "";
509
510 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
511 return -ENOMEM;
512
513 return 0;
514}
515
516int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) {
bfebab7f
LP
517 char **t = data;
518
519 assert(i);
520 assert(property);
521
98a28fef 522 return bus_append_strv_iter(i, t);
bfebab7f
LP
523}
524
525int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) {
526 bool *b = data;
527 dbus_bool_t db;
528
529 assert(i);
530 assert(property);
531 assert(b);
532
533 db = *b;
534
535 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
536 return -ENOMEM;
537
538 return 0;
539}
540
aa001cd6
LP
541int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data) {
542 int *b = data;
543 dbus_bool_t db;
544
545 assert(i);
546 assert(property);
547 assert(b);
548
549 db = *b > 0;
550
551 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
552 return -ENOMEM;
553
554 return 0;
555}
556
bfebab7f
LP
557int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) {
558 assert(i);
559 assert(property);
560 assert(data);
561
bd253d1b 562 /* Let's ensure that usec_t is actually 64bit, and hence this
bfebab7f
LP
563 * function can be used for usec_t */
564 assert_cc(sizeof(uint64_t) == sizeof(usec_t));
565
566 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
567 return -ENOMEM;
568
569 return 0;
570}
571
572int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) {
573 assert(i);
574 assert(property);
575 assert(data);
576
bd253d1b
LP
577 /* Let's ensure that pid_t, mode_t, uid_t, gid_t are actually
578 * 32bit, and hence this function can be used for
579 * pid_t/mode_t/uid_t/gid_t */
bfebab7f
LP
580 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
581 assert_cc(sizeof(uint32_t) == sizeof(mode_t));
582 assert_cc(sizeof(uint32_t) == sizeof(unsigned));
bd253d1b
LP
583 assert_cc(sizeof(uint32_t) == sizeof(uid_t));
584 assert_cc(sizeof(uint32_t) == sizeof(gid_t));
bfebab7f
LP
585
586 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
587 return -ENOMEM;
588
589 return 0;
590}
591
592int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) {
593 assert(i);
594 assert(property);
595 assert(data);
596
597 assert_cc(sizeof(int32_t) == sizeof(int));
598
599 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
600 return -ENOMEM;
601
602 return 0;
603}
604
605int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) {
606 uint64_t u;
607
608 assert(i);
609 assert(property);
610 assert(data);
611
612 u = (uint64_t) *(size_t*) data;
613
614 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
615 return -ENOMEM;
616
617 return 0;
618}
619
620int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) {
621 uint64_t u;
622
623 assert(i);
624 assert(property);
625 assert(data);
626
627 u = (uint64_t) *(unsigned long*) data;
628
629 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
630 return -ENOMEM;
916abb21
LP
631
632 return 0;
633}
634
635int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) {
572481b9 636 int64_t l;
916abb21
LP
637
638 assert(i);
639 assert(property);
640 assert(data);
641
572481b9 642 l = (int64_t) *(long*) data;
916abb21 643
572481b9 644 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &l))
916abb21 645 return -ENOMEM;
bfebab7f
LP
646
647 return 0;
648}
649
650const char *bus_errno_to_dbus(int error) {
651
652 switch(error) {
653
654 case -EINVAL:
655 return DBUS_ERROR_INVALID_ARGS;
656
657 case -ENOMEM:
658 return DBUS_ERROR_NO_MEMORY;
659
660 case -EPERM:
661 case -EACCES:
662 return DBUS_ERROR_ACCESS_DENIED;
663
664 case -ESRCH:
665 return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
666
667 case -ENOENT:
668 return DBUS_ERROR_FILE_NOT_FOUND;
669
670 case -EEXIST:
671 return DBUS_ERROR_FILE_EXISTS;
672
673 case -ETIMEDOUT:
674 case -ETIME:
675 return DBUS_ERROR_TIMEOUT;
676
677 case -EIO:
678 return DBUS_ERROR_IO_ERROR;
679
680 case -ENETRESET:
681 case -ECONNABORTED:
682 case -ECONNRESET:
683 return DBUS_ERROR_DISCONNECTED;
684 }
685
686 return DBUS_ERROR_FAILED;
687}
688
689DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) {
690 DBusMessage *reply = NULL;
691 const char *name, *text;
692
693 if (berror && dbus_error_is_set(berror)) {
694 name = berror->name;
695 text = berror->message;
696 } else {
697 name = bus_errno_to_dbus(error);
698 text = strerror(-error);
699 }
700
701 if (!(reply = dbus_message_new_error(message, name, text)))
702 goto oom;
703
704 if (!dbus_connection_send(c, reply, NULL))
705 goto oom;
706
707 dbus_message_unref(reply);
708
709 if (berror)
710 dbus_error_free(berror);
711
712 return DBUS_HANDLER_RESULT_HANDLED;
713
714oom:
715 if (reply)
716 dbus_message_unref(reply);
717
718 if (berror)
719 dbus_error_free(berror);
720
721 return DBUS_HANDLER_RESULT_NEED_MEMORY;
722}
723
724DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) {
725 DBusMessage *m;
726 DBusMessageIter iter, sub;
727 const char *i;
728
729 assert(interface);
730 assert(properties);
731
732 if (!(m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged")))
733 goto oom;
734
735 dbus_message_iter_init_append(m, &iter);
736
737 /* We won't send any property values, since they might be
738 * large and sometimes not cheap to generated */
739
740 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
741 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
742 !dbus_message_iter_close_container(&iter, &sub) ||
743 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
744 goto oom;
745
746 NULSTR_FOREACH(i, properties)
747 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i))
748 goto oom;
749
750 if (!dbus_message_iter_close_container(&iter, &sub))
751 goto oom;
752
753 return m;
754
755oom:
756 if (m)
757 dbus_message_unref(m);
758
759 return NULL;
760}
3df5bf61
LP
761
762uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
763 unsigned flags;
764 uint32_t events = 0;
765
766 assert(bus_watch);
767
768 /* no watch flags for disabled watches */
769 if (!dbus_watch_get_enabled(bus_watch))
770 return 0;
771
772 flags = dbus_watch_get_flags(bus_watch);
773
774 if (flags & DBUS_WATCH_READABLE)
775 events |= EPOLLIN;
776 if (flags & DBUS_WATCH_WRITABLE)
777 events |= EPOLLOUT;
778
779 return events | EPOLLHUP | EPOLLERR;
780}
781
782unsigned bus_events_to_flags(uint32_t events) {
783 unsigned flags = 0;
784
785 if (events & EPOLLIN)
786 flags |= DBUS_WATCH_READABLE;
787 if (events & EPOLLOUT)
788 flags |= DBUS_WATCH_WRITABLE;
789 if (events & EPOLLHUP)
790 flags |= DBUS_WATCH_HANGUP;
791 if (events & EPOLLERR)
792 flags |= DBUS_WATCH_ERROR;
793
794 return flags;
795}
8d0e38a2
LP
796
797int bus_parse_strv(DBusMessage *m, char ***_l) {
798 DBusMessageIter iter;
799
800 assert(m);
801 assert(_l);
802
803 if (!dbus_message_iter_init(m, &iter))
804 return -EINVAL;
805
806 return bus_parse_strv_iter(&iter, _l);
807}
808
809int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
810 DBusMessageIter sub;
811 unsigned n = 0, i = 0;
812 char **l;
813
814 assert(iter);
815 assert(_l);
816
817 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
818 dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING)
819 return -EINVAL;
820
821 dbus_message_iter_recurse(iter, &sub);
822
823 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
824 n++;
825 dbus_message_iter_next(&sub);
826 }
827
828 if (!(l = new(char*, n+1)))
829 return -ENOMEM;
830
831 dbus_message_iter_recurse(iter, &sub);
832
833 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
834 const char *s;
835
836 assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
837 dbus_message_iter_get_basic(&sub, &s);
838
839 if (!(l[i++] = strdup(s))) {
840 strv_free(l);
841 return -ENOMEM;
842 }
843
844 dbus_message_iter_next(&sub);
845 }
846
847 assert(i == n);
848 l[i] = NULL;
849
850 if (_l)
851 *_l = l;
852
853 return 0;
854}
98a28fef
LP
855
856int bus_append_strv_iter(DBusMessageIter *iter, char **l) {
857 DBusMessageIter sub;
858
859 assert(iter);
860
861 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub))
862 return -ENOMEM;
863
864 STRV_FOREACH(l, l)
865 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l))
866 return -ENOMEM;
867
868 if (!dbus_message_iter_close_container(iter, &sub))
869 return -ENOMEM;
870
871 return 0;
872}
abca4822
LP
873
874int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
875
876 assert(iter);
877 assert(data);
878
879 if (dbus_message_iter_get_arg_type(iter) != type)
880 return -EIO;
881
882 dbus_message_iter_get_basic(iter, data);
883
884 if (!dbus_message_iter_next(iter) != !next)
885 return -EIO;
886
887 return 0;
888}
a4c279f8
LP
889
890int generic_print_property(const char *name, DBusMessageIter *iter, bool all) {
891 assert(name);
892 assert(iter);
893
894 switch (dbus_message_iter_get_arg_type(iter)) {
895
896 case DBUS_TYPE_STRING: {
897 const char *s;
898 dbus_message_iter_get_basic(iter, &s);
899
900 if (all || !isempty(s))
901 printf("%s=%s\n", name, s);
902
903 return 1;
904 }
905
906 case DBUS_TYPE_BOOLEAN: {
907 dbus_bool_t b;
908
909 dbus_message_iter_get_basic(iter, &b);
910 printf("%s=%s\n", name, yes_no(b));
911
912 return 1;
913 }
914
915 case DBUS_TYPE_UINT64: {
916 uint64_t u;
917 dbus_message_iter_get_basic(iter, &u);
918
919 /* Yes, heuristics! But we can change this check
920 * should it turn out to not be sufficient */
921
922 if (endswith(name, "Timestamp")) {
923 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
924
925 t = format_timestamp(timestamp, sizeof(timestamp), u);
926 if (t || all)
927 printf("%s=%s\n", name, strempty(t));
928
929 } else if (strstr(name, "USec")) {
930 char timespan[FORMAT_TIMESPAN_MAX];
931
932 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
933 } else
934 printf("%s=%llu\n", name, (unsigned long long) u);
935
936 return 1;
937 }
938
939 case DBUS_TYPE_UINT32: {
940 uint32_t u;
941 dbus_message_iter_get_basic(iter, &u);
942
943 if (strstr(name, "UMask") || strstr(name, "Mode"))
944 printf("%s=%04o\n", name, u);
945 else
946 printf("%s=%u\n", name, (unsigned) u);
947
948 return 1;
949 }
950
951 case DBUS_TYPE_INT32: {
952 int32_t i;
953 dbus_message_iter_get_basic(iter, &i);
954
955 printf("%s=%i\n", name, (int) i);
956 return 1;
957 }
958
959 case DBUS_TYPE_DOUBLE: {
960 double d;
961 dbus_message_iter_get_basic(iter, &d);
962
963 printf("%s=%g\n", name, d);
964 return 1;
965 }
966
967 case DBUS_TYPE_ARRAY:
968
969 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
970 DBusMessageIter sub;
971 bool space = false;
972
973 dbus_message_iter_recurse(iter, &sub);
974 if (all ||
975 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
976 printf("%s=", name);
977
978 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
979 const char *s;
980
981 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
982 dbus_message_iter_get_basic(&sub, &s);
983 printf("%s%s", space ? " " : "", s);
984
985 space = true;
986 dbus_message_iter_next(&sub);
987 }
988
989 puts("");
990 }
991
992 return 1;
993
994 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
995 DBusMessageIter sub;
996
997 dbus_message_iter_recurse(iter, &sub);
998 if (all ||
999 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1000 printf("%s=", name);
1001
1002 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1003 uint8_t u;
1004
1005 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
1006 dbus_message_iter_get_basic(&sub, &u);
1007 printf("%02x", u);
1008
1009 dbus_message_iter_next(&sub);
1010 }
1011
1012 puts("");
1013 }
1014
1015 return 1;
1016 }
1017
1018 break;
1019 }
1020
1021 return 0;
1022}
ad740100
LP
1023
1024static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) {
1025 DBusMessage *reply;
1026 DBusConnection *bus = userdata;
1027
1028 assert_se(reply = dbus_pending_call_steal_reply(pending));
1029 dbus_message_unref(reply);
1030
1031 dbus_connection_close(bus);
1032}
1033
1034void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) {
1035 DBusMessage *m = NULL;
1036 DBusPendingCall *pending = NULL;
1037
1038 assert(bus);
1039
1040 /* We unregister the name here, but we continue to process
1041 * requests, until we get the response for it, so that all
1042 * requests are guaranteed to be processed. */
1043
1044 m = dbus_message_new_method_call(
1045 DBUS_SERVICE_DBUS,
1046 DBUS_PATH_DBUS,
1047 DBUS_INTERFACE_DBUS,
1048 "ReleaseName");
1049 if (!m)
1050 goto oom;
1051
1052 if (!dbus_message_append_args(
1053 m,
1054 DBUS_TYPE_STRING,
1055 &name,
1056 DBUS_TYPE_INVALID))
1057 goto oom;
1058
1059 if (!dbus_connection_send_with_reply(bus, m, &pending, -1))
1060 goto oom;
1061
1062 if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL))
1063 goto oom;
1064
1065 dbus_message_unref(m);
1066 dbus_pending_call_unref(pending);
1067
1068 return;
1069
1070oom:
1071 log_error("Out of memory");
1072
1073 if (pending) {
1074 dbus_pending_call_cancel(pending);
1075 dbus_pending_call_unref(pending);
1076 }
1077
1078 if (m)
1079 dbus_message_unref(m);
1080}
1081
1082DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) {
1083 usec_t *remain_until = userdata;
1084
1085 assert(bus);
1086 assert(m);
1087 assert(remain_until);
1088
1089 /* Everytime we get a new message we reset out timeout */
1090 *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
1091
1092 if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected"))
1093 dbus_connection_close(bus);
1094
1095 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1096}