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_message_or_strerror(const DBusError *error, int err) {
263 if (error && dbus_error_is_set(error))
264 return bus_error_message(error);
266 return strerror(err);
269 DBusHandlerResult bus_default_message_handler(
271 DBusMessage *message,
272 const char *introspection,
273 const char *interfaces,
274 const BusBoundProperties *bound_properties) {
277 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
283 dbus_error_init(&error);
285 if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
287 reply = dbus_message_new_method_return(message);
291 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID))
294 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && bound_properties) {
295 const char *interface, *property;
296 const BusBoundProperties *bp;
297 const BusProperty *p;
299 DBusMessageIter iter, sub;
301 if (!dbus_message_get_args(
304 DBUS_TYPE_STRING, &interface,
305 DBUS_TYPE_STRING, &property,
307 return bus_send_error_reply(c, message, &error, -EINVAL);
309 for (bp = bound_properties; bp->interface; bp++) {
310 if (!streq(bp->interface, interface))
313 for (p = bp->properties; p->property; p++)
314 if (streq(p->property, property))
319 if (!nulstr_contains(interfaces, interface))
320 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
322 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
324 return bus_send_error_reply(c, message, &error, -EINVAL);
327 reply = dbus_message_new_method_return(message);
331 dbus_message_iter_init_append(reply, &iter);
333 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
336 data = (char*)bp->base + p->offset;
338 data = *(void**)data;
340 r = p->append(&sub, property, data);
344 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 reply = dbus_message_new_method_return(message);
371 dbus_message_iter_init_append(reply, &iter);
373 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
376 for (bp = bound_properties; bp->interface; bp++) {
377 if (interface[0] && !streq(bp->interface, interface))
380 for (p = bp->properties; p->property; p++) {
383 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) ||
384 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) ||
385 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3))
388 data = (char*)bp->base + p->offset;
390 data = *(void**)data;
391 r = p->append(&sub3, p->property, data);
395 return bus_send_error_reply(c, message, NULL, r);
397 if (!dbus_message_iter_close_container(&sub2, &sub3) ||
398 !dbus_message_iter_close_container(&sub, &sub2))
403 if (!dbus_message_iter_close_container(&iter, &sub))
406 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && bound_properties) {
407 const char *interface, *property;
408 DBusMessageIter iter;
409 const BusBoundProperties *bp;
410 const BusProperty *p;
414 DBusMessage *changed;
416 if (!dbus_message_iter_init(message, &iter) ||
417 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
418 return bus_send_error_reply(c, message, NULL, -EINVAL);
420 dbus_message_iter_get_basic(&iter, &interface);
422 if (!dbus_message_iter_next(&iter) ||
423 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
424 return bus_send_error_reply(c, message, NULL, -EINVAL);
426 dbus_message_iter_get_basic(&iter, &property);
428 if (!dbus_message_iter_next(&iter) ||
429 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT ||
430 dbus_message_iter_has_next(&iter))
431 return bus_send_error_reply(c, message, NULL, -EINVAL);
433 for (bp = bound_properties; bp->interface; bp++) {
434 if (!streq(bp->interface, interface))
437 for (p = bp->properties; p->property; p++)
438 if (streq(p->property, property))
443 if (!nulstr_contains(interfaces, interface))
444 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
446 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
448 return bus_send_error_reply(c, message, &error, -EINVAL);
452 dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only");
453 return bus_send_error_reply(c, message, &error, -EINVAL);
456 dbus_message_iter_recurse(&iter, &sub);
458 sig = dbus_message_iter_get_signature(&sub);
462 if (!streq(sig, p->signature)) {
464 return bus_send_error_reply(c, message, NULL, -EINVAL);
468 data = (uint8_t*) bp->base + p->offset;
470 data = *(void**)data;
472 r = p->set(&sub, property, data);
476 return bus_send_error_reply(c, message, NULL, r);
478 reply = dbus_message_new_method_return(message);
482 /* Send out a signal about this, but it doesn't really
483 * matter if this fails, so eat all errors */
484 changed = bus_properties_changed_one_new(
485 dbus_message_get_path(message),
489 dbus_connection_send(c, changed, NULL);
490 dbus_message_unref(changed);
495 const char *interface = dbus_message_get_interface(message);
497 if (!interface || !nulstr_contains(interfaces, interface)) {
498 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
499 return bus_send_error_reply(c, message, &error, -EINVAL);
504 if (!bus_maybe_send_reply(c, message, reply))
507 return DBUS_HANDLER_RESULT_HANDLED;
510 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
513 dbus_error_free(&error);
515 return DBUS_HANDLER_RESULT_NEED_MEMORY;
518 int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) {
519 const char *t = data;
527 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
533 int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) {
539 return bus_append_strv_iter(i, t);
542 int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) {
552 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
558 int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data) {
568 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
574 int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) {
579 /* Let's ensure that usec_t is actually 64bit, and hence this
580 * function can be used for usec_t */
581 assert_cc(sizeof(uint64_t) == sizeof(usec_t));
583 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
589 int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) {
594 /* Let's ensure that pid_t, mode_t, uid_t, gid_t are actually
595 * 32bit, and hence this function can be used for
596 * pid_t/mode_t/uid_t/gid_t */
597 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
598 assert_cc(sizeof(uint32_t) == sizeof(mode_t));
599 assert_cc(sizeof(uint32_t) == sizeof(unsigned));
600 assert_cc(sizeof(uint32_t) == sizeof(uid_t));
601 assert_cc(sizeof(uint32_t) == sizeof(gid_t));
603 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
609 int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) {
614 assert_cc(sizeof(int32_t) == sizeof(int));
616 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
622 int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) {
629 u = (uint64_t) *(size_t*) data;
631 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
637 int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) {
644 u = (uint64_t) *(unsigned long*) data;
646 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
652 int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) {
659 l = (int64_t) *(long*) data;
661 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &l))
667 int bus_property_set_uint64(DBusMessageIter *i, const char *property, void *data) {
673 dbus_message_iter_get_basic(i, t);
677 const char *bus_errno_to_dbus(int error) {
682 return DBUS_ERROR_INVALID_ARGS;
685 return DBUS_ERROR_NO_MEMORY;
689 return DBUS_ERROR_ACCESS_DENIED;
692 return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
695 return DBUS_ERROR_FILE_NOT_FOUND;
698 return DBUS_ERROR_FILE_EXISTS;
702 return DBUS_ERROR_TIMEOUT;
705 return DBUS_ERROR_IO_ERROR;
710 return DBUS_ERROR_DISCONNECTED;
713 return DBUS_ERROR_FAILED;
716 dbus_bool_t bus_maybe_send_reply (DBusConnection *c,
717 DBusMessage *message,
720 /* Some parts of systemd "reply" to signals, which of course
721 * have the no-reply flag set. We will be defensive here and
722 * still send out a reply if we're passed a signal.
724 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL &&
725 dbus_message_get_no_reply(message))
727 return dbus_connection_send(c, reply, NULL);
730 DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) {
731 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
732 const char *name, *text;
734 if (berror && dbus_error_is_set(berror)) {
736 text = berror->message;
738 name = bus_errno_to_dbus(error);
739 text = strerror(-error);
742 reply = dbus_message_new_error(message, name, text);
746 if (!bus_maybe_send_reply(c, message, reply))
750 dbus_error_free(berror);
752 return DBUS_HANDLER_RESULT_HANDLED;
756 dbus_message_unref(reply);
759 dbus_error_free(berror);
761 return DBUS_HANDLER_RESULT_NEED_MEMORY;
764 DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) {
766 DBusMessageIter iter, sub;
772 m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
776 dbus_message_iter_init_append(m, &iter);
778 /* We won't send any property values, since they might be
779 * large and sometimes not cheap to generated */
781 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
782 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
783 !dbus_message_iter_close_container(&iter, &sub) ||
784 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
787 NULSTR_FOREACH(i, properties)
788 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i))
791 if (!dbus_message_iter_close_container(&iter, &sub))
798 dbus_message_unref(m);
803 DBusMessage* bus_properties_changed_one_new(const char *path, const char *interface, const char *property) {
805 DBusMessageIter iter, sub;
810 m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
814 dbus_message_iter_init_append(m, &iter);
816 /* We won't send any property values, since they might be
817 * large and sometimes not cheap to generated */
819 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
820 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
821 !dbus_message_iter_close_container(&iter, &sub) ||
822 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
825 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &property))
828 if (!dbus_message_iter_close_container(&iter, &sub))
835 dbus_message_unref(m);
840 uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
846 /* no watch flags for disabled watches */
847 if (!dbus_watch_get_enabled(bus_watch))
850 flags = dbus_watch_get_flags(bus_watch);
852 if (flags & DBUS_WATCH_READABLE)
854 if (flags & DBUS_WATCH_WRITABLE)
857 return events | EPOLLHUP | EPOLLERR;
860 unsigned bus_events_to_flags(uint32_t events) {
863 if (events & EPOLLIN)
864 flags |= DBUS_WATCH_READABLE;
865 if (events & EPOLLOUT)
866 flags |= DBUS_WATCH_WRITABLE;
867 if (events & EPOLLHUP)
868 flags |= DBUS_WATCH_HANGUP;
869 if (events & EPOLLERR)
870 flags |= DBUS_WATCH_ERROR;
875 int bus_parse_strv(DBusMessage *m, char ***_l) {
876 DBusMessageIter iter;
881 if (!dbus_message_iter_init(m, &iter))
884 return bus_parse_strv_iter(&iter, _l);
887 int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
889 unsigned n = 0, i = 0;
895 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
896 dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING)
899 dbus_message_iter_recurse(iter, &sub);
901 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
903 dbus_message_iter_next(&sub);
910 dbus_message_iter_recurse(iter, &sub);
912 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
915 assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
916 dbus_message_iter_get_basic(&sub, &s);
918 if (!(l[i++] = strdup(s))) {
923 dbus_message_iter_next(&sub);
935 int bus_parse_strv_pairs_iter(DBusMessageIter *iter, char ***_l) {
936 DBusMessageIter sub, sub2;
937 unsigned n = 0, i = 0;
943 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
944 dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRUCT)
947 dbus_message_iter_recurse(iter, &sub);
949 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
951 dbus_message_iter_next(&sub);
954 l = new(char*, n*2+1);
958 dbus_message_iter_recurse(iter, &sub);
960 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
963 assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT);
965 dbus_message_iter_recurse(&sub, &sub2);
967 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &a, true) < 0 ||
968 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &b, false) < 0)
984 dbus_message_iter_next(&sub);
996 int bus_parse_unit_info(DBusMessageIter *iter, struct unit_info *u) {
1002 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT)
1005 dbus_message_iter_recurse(iter, &sub);
1007 if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->id, true) < 0 ||
1008 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->description, true) < 0 ||
1009 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->load_state, true) < 0 ||
1010 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->active_state, true) < 0 ||
1011 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->sub_state, true) < 0 ||
1012 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->following, true) < 0 ||
1013 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_OBJECT_PATH, &u->unit_path, true) < 0 ||
1014 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_UINT32, &u->job_id, true) < 0 ||
1015 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &u->job_type, true) < 0 ||
1016 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) {
1017 log_error("Failed to parse reply.");
1024 int bus_append_strv_iter(DBusMessageIter *iter, char **l) {
1025 DBusMessageIter sub;
1029 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub))
1033 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l))
1036 if (!dbus_message_iter_close_container(iter, &sub))
1042 int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
1047 if (dbus_message_iter_get_arg_type(iter) != type)
1050 dbus_message_iter_get_basic(iter, data);
1052 if (!dbus_message_iter_next(iter) != !next)
1058 int generic_print_property(const char *name, DBusMessageIter *iter, bool all) {
1062 switch (dbus_message_iter_get_arg_type(iter)) {
1064 case DBUS_TYPE_STRING: {
1066 dbus_message_iter_get_basic(iter, &s);
1068 if (all || !isempty(s))
1069 printf("%s=%s\n", name, s);
1074 case DBUS_TYPE_BOOLEAN: {
1077 dbus_message_iter_get_basic(iter, &b);
1078 printf("%s=%s\n", name, yes_no(b));
1083 case DBUS_TYPE_UINT64: {
1085 dbus_message_iter_get_basic(iter, &u);
1087 /* Yes, heuristics! But we can change this check
1088 * should it turn out to not be sufficient */
1090 if (endswith(name, "Timestamp")) {
1091 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
1093 t = format_timestamp(timestamp, sizeof(timestamp), u);
1095 printf("%s=%s\n", name, strempty(t));
1097 } else if (strstr(name, "USec")) {
1098 char timespan[FORMAT_TIMESPAN_MAX];
1100 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
1102 printf("%s=%llu\n", name, (unsigned long long) u);
1107 case DBUS_TYPE_UINT32: {
1109 dbus_message_iter_get_basic(iter, &u);
1111 if (strstr(name, "UMask") || strstr(name, "Mode"))
1112 printf("%s=%04o\n", name, u);
1114 printf("%s=%u\n", name, (unsigned) u);
1119 case DBUS_TYPE_INT32: {
1121 dbus_message_iter_get_basic(iter, &i);
1123 printf("%s=%i\n", name, (int) i);
1127 case DBUS_TYPE_DOUBLE: {
1129 dbus_message_iter_get_basic(iter, &d);
1131 printf("%s=%g\n", name, d);
1135 case DBUS_TYPE_ARRAY:
1137 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
1138 DBusMessageIter sub;
1141 dbus_message_iter_recurse(iter, &sub);
1143 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1144 printf("%s=", name);
1146 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1149 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
1150 dbus_message_iter_get_basic(&sub, &s);
1151 printf("%s%s", space ? " " : "", s);
1154 dbus_message_iter_next(&sub);
1162 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
1163 DBusMessageIter sub;
1165 dbus_message_iter_recurse(iter, &sub);
1167 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1168 printf("%s=", name);
1170 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1173 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
1174 dbus_message_iter_get_basic(&sub, &u);
1177 dbus_message_iter_next(&sub);
1185 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_UINT32) {
1186 DBusMessageIter sub;
1188 dbus_message_iter_recurse(iter, &sub);
1190 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1191 printf("%s=", name);
1193 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1196 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32);
1197 dbus_message_iter_get_basic(&sub, &u);
1200 dbus_message_iter_next(&sub);
1215 static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) {
1217 DBusConnection *bus = userdata;
1219 assert_se(reply = dbus_pending_call_steal_reply(pending));
1220 dbus_message_unref(reply);
1222 dbus_connection_close(bus);
1225 void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) {
1226 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
1227 DBusPendingCall *pending = NULL;
1231 /* We unregister the name here, but we continue to process
1232 * requests, until we get the response for it, so that all
1233 * requests are guaranteed to be processed. */
1235 m = dbus_message_new_method_call(
1238 DBUS_INTERFACE_DBUS,
1243 if (!dbus_message_append_args(
1250 if (!dbus_connection_send_with_reply(bus, m, &pending, -1))
1253 if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL))
1256 dbus_pending_call_unref(pending);
1264 dbus_pending_call_cancel(pending);
1265 dbus_pending_call_unref(pending);
1269 DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) {
1270 usec_t *remain_until = userdata;
1274 assert(remain_until);
1276 /* Every time we get a new message we reset out timeout */
1277 *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
1279 if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected"))
1280 dbus_connection_close(bus);
1282 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1285 /* This mimics dbus_bus_get_unix_user() */
1286 pid_t bus_get_unix_process_id(
1287 DBusConnection *connection,
1291 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
1294 m = dbus_message_new_method_call(
1297 DBUS_INTERFACE_DBUS,
1298 "GetConnectionUnixProcessID");
1300 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
1304 if (!dbus_message_append_args(
1306 DBUS_TYPE_STRING, &name,
1307 DBUS_TYPE_INVALID)) {
1308 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
1312 reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error);
1316 if (dbus_set_error_from_message(error, reply))
1319 if (!dbus_message_get_args(
1321 DBUS_TYPE_UINT32, &pid,
1328 bool bus_error_is_no_service(const DBusError *error) {
1331 if (!dbus_error_is_set(error))
1334 if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER))
1337 if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN))
1340 return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
1343 int bus_method_call_with_reply(
1344 DBusConnection *bus,
1345 const char *destination,
1347 const char *interface,
1349 DBusMessage **return_reply,
1350 DBusError *return_error,
1351 int first_arg_type, ...) {
1354 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
1359 dbus_error_init(&error);
1362 m = dbus_message_new_method_call(destination, path, interface, method);
1368 va_start(ap, first_arg_type);
1369 if (!dbus_message_append_args_valist(m, first_arg_type, ap)) {
1376 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1379 log_error("Failed to issue method call: %s", bus_error_message(&error));
1381 if (bus_error_is_no_service(&error))
1383 else if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED))
1385 else if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY))
1393 *return_reply = reply;
1395 dbus_message_unref(reply);
1399 *return_error = error;
1401 dbus_error_free(&error);
1406 void bus_message_unrefp(DBusMessage **reply) {
1413 dbus_message_unref(*reply);
1416 const char *bus_message_get_sender_with_fallback(DBusMessage *m) {
1421 s = dbus_message_get_sender(m);
1425 /* When the message came in from a direct connection the
1426 * message will have no sender. We fix that here. */
1428 return ":no-sender";