1
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4
This file is part of systemd.
6
Copyright 2010 Lennart Poettering
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.
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.
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/>.
23
#include <sys/socket.h>
28
#include <dbus/dbus.h>
30
#include <sys/epoll.h>
33
#include "dbus-common.h"
39
int bus_check_peercred(DBusConnection *c) {
46
assert_se(dbus_connection_get_unix_fd(c, &fd));
48
l = sizeof(struct ucred);
49
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) {
50
log_error("SO_PEERCRED failed: %m");
54
if (l != sizeof(struct ucred)) {
55
log_error("SO_PEERCRED returned wrong size.");
59
if (ucred.uid != 0 && ucred.uid != geteuid())
65
static int sync_auth(DBusConnection *bus, DBusError *error) {
70
/* This complexity should probably move into D-Bus itself:
72
* https://bugs.freedesktop.org/show_bug.cgi?id=35189 */
74
begin = tstamp = now(CLOCK_MONOTONIC);
77
if (tstamp > begin + DEFAULT_TIMEOUT_USEC)
80
if (dbus_connection_get_is_authenticated(bus))
83
if (!dbus_connection_read_write_dispatch(bus, ((begin + DEFAULT_TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC))
86
tstamp = now(CLOCK_MONOTONIC);
89
if (!dbus_connection_get_is_connected(bus)) {
90
dbus_set_error_const(error, DBUS_ERROR_NO_SERVER, "Connection terminated during authentication.");
94
if (!dbus_connection_get_is_authenticated(bus)) {
95
dbus_set_error_const(error, DBUS_ERROR_TIMEOUT, "Failed to authenticate in time.");
102
int bus_connect(DBusBusType t, DBusConnection **_bus, bool *_private, DBusError *error) {
103
DBusConnection *bus = NULL;
109
if (geteuid() == 0 && t == DBUS_BUS_SYSTEM) {
110
/* If we are root, then let's talk directly to the
111
* system instance, instead of going via the bus */
113
bus = dbus_connection_open_private("unix:path=/run/systemd/private", error);
118
if (t == DBUS_BUS_SESSION) {
121
/* If we are supposed to talk to the instance,
122
* try via XDG_RUNTIME_DIR first, then
123
* fallback to normal bus access */
125
e = secure_getenv("XDG_RUNTIME_DIR");
129
if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0)
132
bus = dbus_connection_open_private(p, NULL);
138
bus = dbus_bus_get_private(t, error);
146
dbus_connection_set_exit_on_disconnect(bus, FALSE);
149
if (bus_check_peercred(bus) < 0) {
150
dbus_connection_close(bus);
151
dbus_connection_unref(bus);
153
dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus.");
158
r = sync_auth(bus, error);
160
dbus_connection_close(bus);
161
dbus_connection_unref(bus);
172
int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error) {
178
assert(user || host);
181
asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@%s,argv3=systemd-stdio-bridge", user, host);
183
asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@localhost,argv3=systemd-stdio-bridge", user);
185
asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s,argv3=systemd-stdio-bridge", host);
188
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
192
bus = dbus_connection_open_private(p, error);
198
dbus_connection_set_exit_on_disconnect(bus, FALSE);
200
if ((r = sync_auth(bus, error)) < 0) {
201
dbus_connection_close(bus);
202
dbus_connection_unref(bus);
206
if (!dbus_bus_register(bus, error)) {
207
dbus_connection_close(bus);
208
dbus_connection_unref(bus);
216
int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error) {
222
/* Don't bother with PolicyKit if we are root */
224
return bus_connect(DBUS_BUS_SYSTEM, _bus, NULL, error);
226
bus = dbus_connection_open_private("unixexec:path=pkexec,argv1=" SYSTEMD_STDIO_BRIDGE_BINARY_PATH, error);
230
dbus_connection_set_exit_on_disconnect(bus, FALSE);
232
r = sync_auth(bus, error);
234
dbus_connection_close(bus);
235
dbus_connection_unref(bus);
239
if (!dbus_bus_register(bus, error)) {
240
dbus_connection_close(bus);
241
dbus_connection_unref(bus);
249
const char *bus_error_message(const DBusError *error) {
253
/* Sometimes the D-Bus server is a little bit too verbose with
254
* its error messages, so let's override them here */
255
if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED))
256
return "Access denied";
258
return error->message;
261
const char *bus_error(const DBusError *error, int err) {
262
if (error && dbus_error_is_set(error))
263
return bus_error_message(error);
265
return strerror(err < 0 ? -err : err);
268
DBusHandlerResult bus_default_message_handler(
270
DBusMessage *message,
271
const char *introspection,
272
const char *interfaces,
273
const BusBoundProperties *bound_properties) {
276
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
282
dbus_error_init(&error);
284
if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
286
reply = dbus_message_new_method_return(message);
290
if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID))
293
} else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && bound_properties) {
294
const char *interface, *property;
295
const BusBoundProperties *bp;
296
const BusProperty *p;
298
DBusMessageIter iter, sub;
300
if (!dbus_message_get_args(
303
DBUS_TYPE_STRING, &interface,
304
DBUS_TYPE_STRING, &property,
306
return bus_send_error_reply(c, message, &error, -EINVAL);
308
for (bp = bound_properties; bp->interface; bp++) {
309
if (!streq(bp->interface, interface))
312
for (p = bp->properties; p->property; p++)
313
if (streq(p->property, property))
318
if (!nulstr_contains(interfaces, interface))
319
dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
321
dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
323
return bus_send_error_reply(c, message, &error, -EINVAL);
326
reply = dbus_message_new_method_return(message);
330
dbus_message_iter_init_append(reply, &iter);
332
if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
335
data = (char*)bp->base + p->offset;
337
data = *(void**)data;
339
r = p->append(&sub, property, data);
343
return bus_send_error_reply(c, message, NULL, r);
345
if (!dbus_message_iter_close_container(&iter, &sub))
348
} else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && bound_properties) {
349
const char *interface;
350
const BusBoundProperties *bp;
351
const BusProperty *p;
352
DBusMessageIter iter, sub, sub2, sub3;
354
if (!dbus_message_get_args(
357
DBUS_TYPE_STRING, &interface,
359
return bus_send_error_reply(c, message, &error, -EINVAL);
361
if (interface[0] && !nulstr_contains(interfaces, interface)) {
362
dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
363
return bus_send_error_reply(c, message, &error, -EINVAL);
366
reply = dbus_message_new_method_return(message);
370
dbus_message_iter_init_append(reply, &iter);
372
if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
375
for (bp = bound_properties; bp->interface; bp++) {
376
if (interface[0] && !streq(bp->interface, interface))
379
for (p = bp->properties; p->property; p++) {
382
if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) ||
383
!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) ||
384
!dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3))
387
data = (char*)bp->base + p->offset;
389
data = *(void**)data;
390
r = p->append(&sub3, p->property, data);
394
return bus_send_error_reply(c, message, NULL, r);
396
if (!dbus_message_iter_close_container(&sub2, &sub3) ||
397
!dbus_message_iter_close_container(&sub, &sub2))
402
if (!dbus_message_iter_close_container(&iter, &sub))
405
} else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && bound_properties) {
406
const char *interface, *property;
407
DBusMessageIter iter;
408
const BusBoundProperties *bp;
409
const BusProperty *p;
413
DBusMessage *changed;
415
if (!dbus_message_iter_init(message, &iter) ||
416
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
417
return bus_send_error_reply(c, message, NULL, -EINVAL);
419
dbus_message_iter_get_basic(&iter, &interface);
421
if (!dbus_message_iter_next(&iter) ||
422
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
423
return bus_send_error_reply(c, message, NULL, -EINVAL);
425
dbus_message_iter_get_basic(&iter, &property);
427
if (!dbus_message_iter_next(&iter) ||
428
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT ||
429
dbus_message_iter_has_next(&iter))
430
return bus_send_error_reply(c, message, NULL, -EINVAL);
432
for (bp = bound_properties; bp->interface; bp++) {
433
if (!streq(bp->interface, interface))
436
for (p = bp->properties; p->property; p++)
437
if (streq(p->property, property))
442
if (!nulstr_contains(interfaces, interface))
443
dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
445
dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
447
return bus_send_error_reply(c, message, &error, -EINVAL);
451
dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only");
452
return bus_send_error_reply(c, message, &error, -EINVAL);
455
dbus_message_iter_recurse(&iter, &sub);
457
sig = dbus_message_iter_get_signature(&sub);
461
if (!streq(sig, p->signature)) {
463
return bus_send_error_reply(c, message, NULL, -EINVAL);
467
data = (uint8_t*) bp->base + p->offset;
469
data = *(void**)data;
471
r = p->set(&sub, property, data);
475
return bus_send_error_reply(c, message, NULL, r);
477
reply = dbus_message_new_method_return(message);
481
/* Send out a signal about this, but it doesn't really
482
* matter if this fails, so eat all errors */
483
changed = bus_properties_changed_one_new(
484
dbus_message_get_path(message),
488
dbus_connection_send(c, changed, NULL);
489
dbus_message_unref(changed);
494
const char *interface = dbus_message_get_interface(message);
496
if (!interface || !nulstr_contains(interfaces, interface)) {
497
dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
498
return bus_send_error_reply(c, message, &error, -EINVAL);
503
if (!bus_maybe_send_reply(c, message, reply))
506
return DBUS_HANDLER_RESULT_HANDLED;
509
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
512
dbus_error_free(&error);
514
return DBUS_HANDLER_RESULT_NEED_MEMORY;
517
int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) {
518
const char *t = data;
526
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
532
int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) {
538
return bus_append_strv_iter(i, t);
541
int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) {
551
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
557
int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data) {
567
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
573
int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) {
578
/* Let's ensure that usec_t is actually 64bit, and hence this
579
* function can be used for usec_t */
580
assert_cc(sizeof(uint64_t) == sizeof(usec_t));
582
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
588
int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) {
593
/* Let's ensure that pid_t, mode_t, uid_t, gid_t are actually
594
* 32bit, and hence this function can be used for
595
* pid_t/mode_t/uid_t/gid_t */
596
assert_cc(sizeof(uint32_t) == sizeof(pid_t));
597
assert_cc(sizeof(uint32_t) == sizeof(mode_t));
598
assert_cc(sizeof(uint32_t) == sizeof(unsigned));
599
assert_cc(sizeof(uint32_t) == sizeof(uid_t));
600
assert_cc(sizeof(uint32_t) == sizeof(gid_t));
602
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
608
int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) {
613
assert_cc(sizeof(int32_t) == sizeof(int));
615
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
621
int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) {
628
u = (uint64_t) *(size_t*) data;
630
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
636
int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) {
643
u = (uint64_t) *(unsigned long*) data;
645
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
651
int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) {
658
l = (int64_t) *(long*) data;
660
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &l))
666
int bus_property_set_uint64(DBusMessageIter *i, const char *property, void *data) {
672
dbus_message_iter_get_basic(i, t);
676
const char *bus_errno_to_dbus(int error) {
681
return DBUS_ERROR_INVALID_ARGS;
684
return DBUS_ERROR_NO_MEMORY;
688
return DBUS_ERROR_ACCESS_DENIED;
691
return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
694
return DBUS_ERROR_FILE_NOT_FOUND;
697
return DBUS_ERROR_FILE_EXISTS;
701
return DBUS_ERROR_TIMEOUT;
704
return DBUS_ERROR_IO_ERROR;
709
return DBUS_ERROR_DISCONNECTED;
712
return DBUS_ERROR_FAILED;
715
dbus_bool_t bus_maybe_send_reply (DBusConnection *c,
716
DBusMessage *message,
719
/* Some parts of systemd "reply" to signals, which of course
720
* have the no-reply flag set. We will be defensive here and
721
* still send out a reply if we're passed a signal.
723
if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL &&
724
dbus_message_get_no_reply(message))
726
return dbus_connection_send(c, reply, NULL);
729
DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) {
730
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
731
const char *name, *text;
733
if (berror && dbus_error_is_set(berror)) {
735
text = berror->message;
737
name = bus_errno_to_dbus(error);
738
text = strerror(-error);
741
reply = dbus_message_new_error(message, name, text);
745
if (!bus_maybe_send_reply(c, message, reply))
749
dbus_error_free(berror);
751
return DBUS_HANDLER_RESULT_HANDLED;
755
dbus_message_unref(reply);
758
dbus_error_free(berror);
760
return DBUS_HANDLER_RESULT_NEED_MEMORY;
763
DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) {
765
DBusMessageIter iter, sub;
771
m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
775
dbus_message_iter_init_append(m, &iter);
777
/* We won't send any property values, since they might be
778
* large and sometimes not cheap to generated */
780
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
781
!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
782
!dbus_message_iter_close_container(&iter, &sub) ||
783
!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
786
NULSTR_FOREACH(i, properties)
787
if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i))
790
if (!dbus_message_iter_close_container(&iter, &sub))
797
dbus_message_unref(m);
802
DBusMessage* bus_properties_changed_one_new(const char *path, const char *interface, const char *property) {
804
DBusMessageIter iter, sub;
809
m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
813
dbus_message_iter_init_append(m, &iter);
815
/* We won't send any property values, since they might be
816
* large and sometimes not cheap to generated */
818
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
819
!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
820
!dbus_message_iter_close_container(&iter, &sub) ||
821
!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
824
if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &property))
827
if (!dbus_message_iter_close_container(&iter, &sub))
834
dbus_message_unref(m);
839
uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
845
/* no watch flags for disabled watches */
846
if (!dbus_watch_get_enabled(bus_watch))
849
flags = dbus_watch_get_flags(bus_watch);
851
if (flags & DBUS_WATCH_READABLE)
853
if (flags & DBUS_WATCH_WRITABLE)
856
return events | EPOLLHUP | EPOLLERR;
859
unsigned bus_events_to_flags(uint32_t events) {
862
if (events & EPOLLIN)
863
flags |= DBUS_WATCH_READABLE;
864
if (events & EPOLLOUT)
865
flags |= DBUS_WATCH_WRITABLE;
866
if (events & EPOLLHUP)
867
flags |= DBUS_WATCH_HANGUP;
868
if (events & EPOLLERR)
869
flags |= DBUS_WATCH_ERROR;
874
int bus_parse_strv(DBusMessage *m, char ***_l) {
875
DBusMessageIter iter;
880
if (!dbus_message_iter_init(m, &iter))
883
return bus_parse_strv_iter(&iter, _l);
886
int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
888
unsigned n = 0, i = 0;
894
if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
895
dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING)
898
dbus_message_iter_recurse(iter, &sub);
900
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
902
dbus_message_iter_next(&sub);
909
dbus_message_iter_recurse(iter, &sub);
911
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
914
assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
915
dbus_message_iter_get_basic(&sub, &s);
917
if (!(l[i++] = strdup(s))) {
922
dbus_message_iter_next(&sub);
934
int bus_parse_strv_pairs_iter(DBusMessageIter *iter, char ***_l) {
935
DBusMessageIter sub, sub2;
936
unsigned n = 0, i = 0;
942
if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
943
dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRUCT)
946
dbus_message_iter_recurse(iter, &sub);
948
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
950
dbus_message_iter_next(&sub);
953
l = new(char*, n*2+1);
957
dbus_message_iter_recurse(iter, &sub);
959
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
962
assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT);
964
dbus_message_iter_recurse(&sub, &sub2);
966
if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &a, true) < 0 ||
967
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &b, false) < 0)
983
dbus_message_iter_next(&sub);
995
int bus_parse_unit_info(DBusMessageIter *iter, struct unit_info *u) {
1001
if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT)
1004
dbus_message_iter_recurse(iter, &sub);
1006
if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->id, true) < 0 ||
1007
bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->description, true) < 0 ||
1008
bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->load_state, true) < 0 ||
1009
bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->active_state, true) < 0 ||
1010
bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->sub_state, true) < 0 ||
1011
bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->following, true) < 0 ||
1012
bus_iter_get_basic_and_next(&sub, DBUS_TYPE_OBJECT_PATH, &u->unit_path, true) < 0 ||
1013
bus_iter_get_basic_and_next(&sub, DBUS_TYPE_UINT32, &u->job_id, true) < 0 ||
1014
bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->job_type, true) < 0 ||
1015
bus_iter_get_basic_and_next(&sub, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) {
1016
log_error("Failed to parse reply.");
1023
int bus_append_strv_iter(DBusMessageIter *iter, char **l) {
1024
DBusMessageIter sub;
1028
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub))
1032
if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l))
1035
if (!dbus_message_iter_close_container(iter, &sub))
1041
int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
1046
if (dbus_message_iter_get_arg_type(iter) != type)
1049
dbus_message_iter_get_basic(iter, data);
1051
if (!dbus_message_iter_next(iter) != !next)
1057
int generic_print_property(const char *name, DBusMessageIter *iter, bool all) {
1061
switch (dbus_message_iter_get_arg_type(iter)) {
1063
case DBUS_TYPE_STRING: {
1065
dbus_message_iter_get_basic(iter, &s);
1067
if (all || !isempty(s))
1068
printf("%s=%s\n", name, s);
1073
case DBUS_TYPE_BOOLEAN: {
1076
dbus_message_iter_get_basic(iter, &b);
1077
printf("%s=%s\n", name, yes_no(b));
1082
case DBUS_TYPE_UINT64: {
1084
dbus_message_iter_get_basic(iter, &u);
1086
/* Yes, heuristics! But we can change this check
1087
* should it turn out to not be sufficient */
1089
if (endswith(name, "Timestamp")) {
1090
char timestamp[FORMAT_TIMESTAMP_MAX], *t;
1092
t = format_timestamp(timestamp, sizeof(timestamp), u);
1094
printf("%s=%s\n", name, strempty(t));
1096
} else if (strstr(name, "USec")) {
1097
char timespan[FORMAT_TIMESPAN_MAX];
1099
printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
1101
printf("%s=%llu\n", name, (unsigned long long) u);
1106
case DBUS_TYPE_UINT32: {
1108
dbus_message_iter_get_basic(iter, &u);
1110
if (strstr(name, "UMask") || strstr(name, "Mode"))
1111
printf("%s=%04o\n", name, u);
1113
printf("%s=%u\n", name, (unsigned) u);
1118
case DBUS_TYPE_INT32: {
1120
dbus_message_iter_get_basic(iter, &i);
1122
printf("%s=%i\n", name, (int) i);
1126
case DBUS_TYPE_DOUBLE: {
1128
dbus_message_iter_get_basic(iter, &d);
1130
printf("%s=%g\n", name, d);
1134
case DBUS_TYPE_ARRAY:
1136
if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
1137
DBusMessageIter sub;
1140
dbus_message_iter_recurse(iter, &sub);
1142
dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1143
printf("%s=", name);
1145
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1148
assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
1149
dbus_message_iter_get_basic(&sub, &s);
1150
printf("%s%s", space ? " " : "", s);
1153
dbus_message_iter_next(&sub);
1161
} else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
1162
DBusMessageIter sub;
1164
dbus_message_iter_recurse(iter, &sub);
1166
dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1167
printf("%s=", name);
1169
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1172
assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
1173
dbus_message_iter_get_basic(&sub, &u);
1176
dbus_message_iter_next(&sub);
1184
} else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_UINT32) {
1185
DBusMessageIter sub;
1187
dbus_message_iter_recurse(iter, &sub);
1189
dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1190
printf("%s=", name);
1192
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1195
assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32);
1196
dbus_message_iter_get_basic(&sub, &u);
1199
dbus_message_iter_next(&sub);
1214
static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) {
1216
DBusConnection *bus = userdata;
1218
assert_se(reply = dbus_pending_call_steal_reply(pending));
1219
dbus_message_unref(reply);
1221
dbus_connection_close(bus);
1224
void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) {
1225
_cleanup_dbus_message_unref_ DBusMessage *m = NULL;
1226
DBusPendingCall *pending = NULL;
1230
/* We unregister the name here, but we continue to process
1231
* requests, until we get the response for it, so that all
1232
* requests are guaranteed to be processed. */
1234
m = dbus_message_new_method_call(
1237
DBUS_INTERFACE_DBUS,
1242
if (!dbus_message_append_args(
1249
if (!dbus_connection_send_with_reply(bus, m, &pending, -1))
1252
if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL))
1255
dbus_pending_call_unref(pending);
1263
dbus_pending_call_cancel(pending);
1264
dbus_pending_call_unref(pending);
1268
DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) {
1269
usec_t *remain_until = userdata;
1273
assert(remain_until);
1275
/* Every time we get a new message we reset out timeout */
1276
*remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
1278
if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected"))
1279
dbus_connection_close(bus);
1281
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1284
/* This mimics dbus_bus_get_unix_user() */
1285
pid_t bus_get_unix_process_id(
1286
DBusConnection *connection,
1290
_cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
1293
m = dbus_message_new_method_call(
1296
DBUS_INTERFACE_DBUS,
1297
"GetConnectionUnixProcessID");
1299
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
1303
if (!dbus_message_append_args(
1305
DBUS_TYPE_STRING, &name,
1306
DBUS_TYPE_INVALID)) {
1307
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
1311
reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error);
1315
if (dbus_set_error_from_message(error, reply))
1318
if (!dbus_message_get_args(
1320
DBUS_TYPE_UINT32, &pid,
1327
bool bus_error_is_no_service(const DBusError *error) {
1330
if (!dbus_error_is_set(error))
1333
if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER))
1336
if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN))
1339
return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
1342
int bus_method_call_with_reply(
1343
DBusConnection *bus,
1344
const char *destination,
1346
const char *interface,
1348
DBusMessage **return_reply,
1349
DBusError *return_error,
1350
int first_arg_type, ...) {
1353
_cleanup_dbus_message_unref_ DBusMessage *m = NULL;
1358
dbus_error_init(&error);
1361
m = dbus_message_new_method_call(destination, path, interface, method);
1367
va_start(ap, first_arg_type);
1368
if (!dbus_message_append_args_valist(m, first_arg_type, ap)) {
1375
reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1378
log_error("Failed to issue method call: %s", bus_error_message(&error));
1380
if (bus_error_is_no_service(&error))
1382
else if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED))
1384
else if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY))
1392
*return_reply = reply;
1394
dbus_message_unref(reply);
1398
*return_error = error;
1400
dbus_error_free(&error);
1405
void bus_message_unrefp(DBusMessage **reply) {
1412
dbus_message_unref(*reply);
1415
const char *bus_message_get_sender_with_fallback(DBusMessage *m) {
1420
s = dbus_message_get_sender(m);
1424
/* When the message came in from a direct connection the
1425
* message will have no sender. We fix that here. */
1427
return ":no-sender";