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 if ((r = sync_auth(bus, error)) < 0) {
233 dbus_connection_close(bus);
234 dbus_connection_unref(bus);
238 if (!dbus_bus_register(bus, error)) {
239 dbus_connection_close(bus);
240 dbus_connection_unref(bus);
248 const char *bus_error_message(const DBusError *error) {
252 /* Sometimes the D-Bus server is a little bit too verbose with
253 * its error messages, so let's override them here */
254 if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED))
255 return "Access denied";
257 return error->message;
260 const char *bus_error_message_or_strerror(const DBusError *error, int err) {
262 if (error && dbus_error_is_set(error))
263 return bus_error_message(error);
265 return strerror(err);
268 DBusHandlerResult bus_default_message_handler(
270 DBusMessage *message,
271 const char *introspection,
272 const char *interfaces,
273 const BusBoundProperties *bound_properties) {
276 DBusMessage *reply = NULL;
282 dbus_error_init(&error);
284 if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
286 if (!(reply = dbus_message_new_method_return(message)))
289 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID))
292 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && bound_properties) {
293 const char *interface, *property;
294 const BusBoundProperties *bp;
295 const BusProperty *p;
297 DBusMessageIter iter, sub;
299 if (!dbus_message_get_args(
302 DBUS_TYPE_STRING, &interface,
303 DBUS_TYPE_STRING, &property,
305 return bus_send_error_reply(c, message, &error, -EINVAL);
307 for (bp = bound_properties; bp->interface; bp++) {
308 if (!streq(bp->interface, interface))
311 for (p = bp->properties; p->property; p++)
312 if (streq(p->property, property))
317 if (!nulstr_contains(interfaces, interface))
318 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
320 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
322 return bus_send_error_reply(c, message, &error, -EINVAL);
325 reply = dbus_message_new_method_return(message);
329 dbus_message_iter_init_append(reply, &iter);
331 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
334 data = (char*)bp->base + p->offset;
336 data = *(void**)data;
337 r = p->append(&sub, property, data);
342 dbus_message_unref(reply);
343 return bus_send_error_reply(c, message, NULL, r);
346 if (!dbus_message_iter_close_container(&iter, &sub))
349 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && bound_properties) {
350 const char *interface;
351 const BusBoundProperties *bp;
352 const BusProperty *p;
353 DBusMessageIter iter, sub, sub2, sub3;
355 if (!dbus_message_get_args(
358 DBUS_TYPE_STRING, &interface,
360 return bus_send_error_reply(c, message, &error, -EINVAL);
362 if (interface[0] && !nulstr_contains(interfaces, interface)) {
363 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
364 return bus_send_error_reply(c, message, &error, -EINVAL);
367 if (!(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);
395 dbus_message_unref(reply);
396 return bus_send_error_reply(c, message, NULL, r);
399 if (!dbus_message_iter_close_container(&sub2, &sub3) ||
400 !dbus_message_iter_close_container(&sub, &sub2))
405 if (!dbus_message_iter_close_container(&iter, &sub))
408 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && bound_properties) {
409 const char *interface, *property;
410 DBusMessageIter iter;
411 const BusBoundProperties *bp;
412 const BusProperty *p;
416 DBusMessage *changed;
418 if (!dbus_message_iter_init(message, &iter) ||
419 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
420 return bus_send_error_reply(c, message, NULL, -EINVAL);
422 dbus_message_iter_get_basic(&iter, &interface);
424 if (!dbus_message_iter_next(&iter) ||
425 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
426 return bus_send_error_reply(c, message, NULL, -EINVAL);
428 dbus_message_iter_get_basic(&iter, &property);
430 if (!dbus_message_iter_next(&iter) ||
431 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT ||
432 dbus_message_iter_has_next(&iter))
433 return bus_send_error_reply(c, message, NULL, -EINVAL);
435 for (bp = bound_properties; bp->interface; bp++) {
436 if (!streq(bp->interface, interface))
439 for (p = bp->properties; p->property; p++)
440 if (streq(p->property, property))
445 if (!nulstr_contains(interfaces, interface))
446 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
448 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
450 return bus_send_error_reply(c, message, &error, -EINVAL);
454 dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only");
455 return bus_send_error_reply(c, message, &error, -EINVAL);
458 dbus_message_iter_recurse(&iter, &sub);
460 sig = dbus_message_iter_get_signature(&sub);
464 if (!streq(sig, p->signature)) {
466 return bus_send_error_reply(c, message, NULL, -EINVAL);
470 data = (uint8_t*) bp->base + p->offset;
472 data = *(void**)data;
474 r = p->set(&sub, property, data);
478 return bus_send_error_reply(c, message, NULL, r);
480 reply = dbus_message_new_method_return(message);
484 /* Send out a signal about this, but it doesn't really
485 * matter if this fails, so eat all errors */
486 changed = bus_properties_changed_one_new(
487 dbus_message_get_path(message),
491 dbus_connection_send(c, changed, NULL);
492 dbus_message_unref(changed);
497 const char *interface = dbus_message_get_interface(message);
499 if (!interface || !nulstr_contains(interfaces, interface)) {
500 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
501 return bus_send_error_reply(c, message, &error, -EINVAL);
506 if (!dbus_connection_send(c, reply, NULL))
509 dbus_message_unref(reply);
510 return DBUS_HANDLER_RESULT_HANDLED;
513 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
517 dbus_message_unref(reply);
519 dbus_error_free(&error);
521 return DBUS_HANDLER_RESULT_NEED_MEMORY;
524 int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) {
525 const char *t = data;
533 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
539 int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) {
545 return bus_append_strv_iter(i, t);
548 int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) {
558 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
564 int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data) {
574 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
580 int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) {
585 /* Let's ensure that usec_t is actually 64bit, and hence this
586 * function can be used for usec_t */
587 assert_cc(sizeof(uint64_t) == sizeof(usec_t));
589 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
595 int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) {
600 /* Let's ensure that pid_t, mode_t, uid_t, gid_t are actually
601 * 32bit, and hence this function can be used for
602 * pid_t/mode_t/uid_t/gid_t */
603 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
604 assert_cc(sizeof(uint32_t) == sizeof(mode_t));
605 assert_cc(sizeof(uint32_t) == sizeof(unsigned));
606 assert_cc(sizeof(uint32_t) == sizeof(uid_t));
607 assert_cc(sizeof(uint32_t) == sizeof(gid_t));
609 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
615 int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) {
620 assert_cc(sizeof(int32_t) == sizeof(int));
622 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
628 int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) {
635 u = (uint64_t) *(size_t*) data;
637 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
643 int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) {
650 u = (uint64_t) *(unsigned long*) data;
652 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
658 int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) {
665 l = (int64_t) *(long*) data;
667 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &l))
673 int bus_property_set_uint64(DBusMessageIter *i, const char *property, void *data) {
679 dbus_message_iter_get_basic(i, t);
683 const char *bus_errno_to_dbus(int error) {
688 return DBUS_ERROR_INVALID_ARGS;
691 return DBUS_ERROR_NO_MEMORY;
695 return DBUS_ERROR_ACCESS_DENIED;
698 return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
701 return DBUS_ERROR_FILE_NOT_FOUND;
704 return DBUS_ERROR_FILE_EXISTS;
708 return DBUS_ERROR_TIMEOUT;
711 return DBUS_ERROR_IO_ERROR;
716 return DBUS_ERROR_DISCONNECTED;
719 return DBUS_ERROR_FAILED;
722 DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) {
723 DBusMessage *reply = NULL;
724 const char *name, *text;
726 if (berror && dbus_error_is_set(berror)) {
728 text = berror->message;
730 name = bus_errno_to_dbus(error);
731 text = strerror(-error);
734 if (!(reply = dbus_message_new_error(message, name, text)))
737 if (!dbus_connection_send(c, reply, NULL))
740 dbus_message_unref(reply);
743 dbus_error_free(berror);
745 return DBUS_HANDLER_RESULT_HANDLED;
749 dbus_message_unref(reply);
752 dbus_error_free(berror);
754 return DBUS_HANDLER_RESULT_NEED_MEMORY;
757 DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) {
759 DBusMessageIter iter, sub;
765 m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
769 dbus_message_iter_init_append(m, &iter);
771 /* We won't send any property values, since they might be
772 * large and sometimes not cheap to generated */
774 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
775 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
776 !dbus_message_iter_close_container(&iter, &sub) ||
777 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
780 NULSTR_FOREACH(i, properties)
781 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i))
784 if (!dbus_message_iter_close_container(&iter, &sub))
791 dbus_message_unref(m);
796 DBusMessage* bus_properties_changed_one_new(const char *path, const char *interface, const char *property) {
798 DBusMessageIter iter, sub;
803 m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
807 dbus_message_iter_init_append(m, &iter);
809 /* We won't send any property values, since they might be
810 * large and sometimes not cheap to generated */
812 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
813 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
814 !dbus_message_iter_close_container(&iter, &sub) ||
815 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
818 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &property))
821 if (!dbus_message_iter_close_container(&iter, &sub))
828 dbus_message_unref(m);
833 uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
839 /* no watch flags for disabled watches */
840 if (!dbus_watch_get_enabled(bus_watch))
843 flags = dbus_watch_get_flags(bus_watch);
845 if (flags & DBUS_WATCH_READABLE)
847 if (flags & DBUS_WATCH_WRITABLE)
850 return events | EPOLLHUP | EPOLLERR;
853 unsigned bus_events_to_flags(uint32_t events) {
856 if (events & EPOLLIN)
857 flags |= DBUS_WATCH_READABLE;
858 if (events & EPOLLOUT)
859 flags |= DBUS_WATCH_WRITABLE;
860 if (events & EPOLLHUP)
861 flags |= DBUS_WATCH_HANGUP;
862 if (events & EPOLLERR)
863 flags |= DBUS_WATCH_ERROR;
868 int bus_parse_strv(DBusMessage *m, char ***_l) {
869 DBusMessageIter iter;
874 if (!dbus_message_iter_init(m, &iter))
877 return bus_parse_strv_iter(&iter, _l);
880 int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
882 unsigned n = 0, i = 0;
888 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
889 dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING)
892 dbus_message_iter_recurse(iter, &sub);
894 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
896 dbus_message_iter_next(&sub);
899 if (!(l = new(char*, n+1)))
902 dbus_message_iter_recurse(iter, &sub);
904 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
907 assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
908 dbus_message_iter_get_basic(&sub, &s);
910 if (!(l[i++] = strdup(s))) {
915 dbus_message_iter_next(&sub);
927 int bus_append_strv_iter(DBusMessageIter *iter, char **l) {
932 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub))
936 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l))
939 if (!dbus_message_iter_close_container(iter, &sub))
945 int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
950 if (dbus_message_iter_get_arg_type(iter) != type)
953 dbus_message_iter_get_basic(iter, data);
955 if (!dbus_message_iter_next(iter) != !next)
961 int generic_print_property(const char *name, DBusMessageIter *iter, bool all) {
965 switch (dbus_message_iter_get_arg_type(iter)) {
967 case DBUS_TYPE_STRING: {
969 dbus_message_iter_get_basic(iter, &s);
971 if (all || !isempty(s))
972 printf("%s=%s\n", name, s);
977 case DBUS_TYPE_BOOLEAN: {
980 dbus_message_iter_get_basic(iter, &b);
981 printf("%s=%s\n", name, yes_no(b));
986 case DBUS_TYPE_UINT64: {
988 dbus_message_iter_get_basic(iter, &u);
990 /* Yes, heuristics! But we can change this check
991 * should it turn out to not be sufficient */
993 if (endswith(name, "Timestamp")) {
994 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
996 t = format_timestamp(timestamp, sizeof(timestamp), u);
998 printf("%s=%s\n", name, strempty(t));
1000 } else if (strstr(name, "USec")) {
1001 char timespan[FORMAT_TIMESPAN_MAX];
1003 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
1005 printf("%s=%llu\n", name, (unsigned long long) u);
1010 case DBUS_TYPE_UINT32: {
1012 dbus_message_iter_get_basic(iter, &u);
1014 if (strstr(name, "UMask") || strstr(name, "Mode"))
1015 printf("%s=%04o\n", name, u);
1017 printf("%s=%u\n", name, (unsigned) u);
1022 case DBUS_TYPE_INT32: {
1024 dbus_message_iter_get_basic(iter, &i);
1026 printf("%s=%i\n", name, (int) i);
1030 case DBUS_TYPE_DOUBLE: {
1032 dbus_message_iter_get_basic(iter, &d);
1034 printf("%s=%g\n", name, d);
1038 case DBUS_TYPE_ARRAY:
1040 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
1041 DBusMessageIter sub;
1044 dbus_message_iter_recurse(iter, &sub);
1046 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1047 printf("%s=", name);
1049 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1052 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
1053 dbus_message_iter_get_basic(&sub, &s);
1054 printf("%s%s", space ? " " : "", s);
1057 dbus_message_iter_next(&sub);
1065 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
1066 DBusMessageIter sub;
1068 dbus_message_iter_recurse(iter, &sub);
1070 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1071 printf("%s=", name);
1073 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1076 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
1077 dbus_message_iter_get_basic(&sub, &u);
1080 dbus_message_iter_next(&sub);
1088 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_UINT32) {
1089 DBusMessageIter sub;
1091 dbus_message_iter_recurse(iter, &sub);
1093 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1094 printf("%s=", name);
1096 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1099 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32);
1100 dbus_message_iter_get_basic(&sub, &u);
1103 dbus_message_iter_next(&sub);
1118 static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) {
1120 DBusConnection *bus = userdata;
1122 assert_se(reply = dbus_pending_call_steal_reply(pending));
1123 dbus_message_unref(reply);
1125 dbus_connection_close(bus);
1128 void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) {
1129 DBusMessage *m = NULL;
1130 DBusPendingCall *pending = NULL;
1134 /* We unregister the name here, but we continue to process
1135 * requests, until we get the response for it, so that all
1136 * requests are guaranteed to be processed. */
1138 m = dbus_message_new_method_call(
1141 DBUS_INTERFACE_DBUS,
1146 if (!dbus_message_append_args(
1153 if (!dbus_connection_send_with_reply(bus, m, &pending, -1))
1156 if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL))
1159 dbus_message_unref(m);
1160 dbus_pending_call_unref(pending);
1168 dbus_pending_call_cancel(pending);
1169 dbus_pending_call_unref(pending);
1173 dbus_message_unref(m);
1176 DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) {
1177 usec_t *remain_until = userdata;
1181 assert(remain_until);
1183 /* Every time we get a new message we reset out timeout */
1184 *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
1186 if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected"))
1187 dbus_connection_close(bus);
1189 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1192 /* This mimics dbus_bus_get_unix_user() */
1193 pid_t bus_get_unix_process_id(
1194 DBusConnection *connection,
1198 DBusMessage *m = NULL, *reply = NULL;
1201 m = dbus_message_new_method_call(
1204 DBUS_INTERFACE_DBUS,
1205 "GetConnectionUnixProcessID");
1207 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
1211 if (!dbus_message_append_args(
1213 DBUS_TYPE_STRING, &name,
1214 DBUS_TYPE_INVALID)) {
1215 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
1219 reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error);
1223 if (dbus_set_error_from_message(error, reply))
1226 if (!dbus_message_get_args(
1228 DBUS_TYPE_UINT32, &pid,
1234 dbus_message_unref(m);
1237 dbus_message_unref(reply);
1242 bool bus_error_is_no_service(const DBusError *error) {
1245 if (!dbus_error_is_set(error))
1248 if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER))
1251 if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN))
1254 return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
1257 int bus_method_call_with_reply(
1258 DBusConnection *bus,
1259 const char *destination,
1261 const char *interface,
1263 DBusMessage **return_reply,
1264 DBusError *return_error,
1265 int first_arg_type, ...) {
1268 DBusMessage *m, *reply;
1272 dbus_error_init(&error);
1275 m = dbus_message_new_method_call(destination, path, interface, method);
1281 va_start(ap, first_arg_type);
1282 if (!dbus_message_append_args_valist(m, first_arg_type, ap)) {
1289 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1292 log_error("Failed to issue method call: %s", bus_error_message(&error));
1294 if (bus_error_is_no_service(&error))
1296 else if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED))
1298 else if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY))
1306 *return_reply = reply;
1308 dbus_message_unref(reply);
1312 dbus_message_unref(m);
1315 *return_error = error;
1317 dbus_error_free(&error);
1323 void dbus_message_unref_p(DBusMessage **reply) {
1325 dbus_message_unref(*reply);