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"
38 int bus_check_peercred(DBusConnection *c) {
45 assert_se(dbus_connection_get_unix_fd(c, &fd));
47 l = sizeof(struct ucred);
48 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) {
49 log_error("SO_PEERCRED failed: %m");
53 if (l != sizeof(struct ucred)) {
54 log_error("SO_PEERCRED returned wrong size.");
58 if (ucred.uid != 0 && ucred.uid != geteuid())
64 static int sync_auth(DBusConnection *bus, DBusError *error) {
69 /* This complexity should probably move into D-Bus itself:
71 * https://bugs.freedesktop.org/show_bug.cgi?id=35189 */
73 begin = tstamp = now(CLOCK_MONOTONIC);
76 if (tstamp > begin + DEFAULT_TIMEOUT_USEC)
79 if (dbus_connection_get_is_authenticated(bus))
82 if (!dbus_connection_read_write_dispatch(bus, ((begin + DEFAULT_TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC))
85 tstamp = now(CLOCK_MONOTONIC);
88 if (!dbus_connection_get_is_connected(bus)) {
89 dbus_set_error_const(error, DBUS_ERROR_NO_SERVER, "Connection terminated during authentication.");
93 if (!dbus_connection_get_is_authenticated(bus)) {
94 dbus_set_error_const(error, DBUS_ERROR_TIMEOUT, "Failed to authenticate in time.");
101 int bus_connect(DBusBusType t, DBusConnection **_bus, bool *_private, DBusError *error) {
102 DBusConnection *bus = NULL;
108 if (geteuid() == 0 && t == DBUS_BUS_SYSTEM) {
109 /* If we are root, then let's talk directly to the
110 * system instance, instead of going via the bus */
112 bus = dbus_connection_open_private("unix:path=/run/systemd/private", error);
117 if (t == DBUS_BUS_SESSION) {
120 /* If we are supposed to talk to the instance,
121 * try via XDG_RUNTIME_DIR first, then
122 * fallback to normal bus access */
124 e = getenv("XDG_RUNTIME_DIR");
128 if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0)
131 bus = dbus_connection_open_private(p, NULL);
137 bus = dbus_bus_get_private(t, error);
145 dbus_connection_set_exit_on_disconnect(bus, FALSE);
148 if (bus_check_peercred(bus) < 0) {
149 dbus_connection_close(bus);
150 dbus_connection_unref(bus);
152 dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus.");
157 r = sync_auth(bus, error);
159 dbus_connection_close(bus);
160 dbus_connection_unref(bus);
171 int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error) {
177 assert(user || host);
180 asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@%s,argv3=systemd-stdio-bridge", user, host);
182 asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@localhost,argv3=systemd-stdio-bridge", user);
184 asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s,argv3=systemd-stdio-bridge", host);
187 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
191 bus = dbus_connection_open_private(p, error);
197 dbus_connection_set_exit_on_disconnect(bus, FALSE);
199 if ((r = sync_auth(bus, error)) < 0) {
200 dbus_connection_close(bus);
201 dbus_connection_unref(bus);
205 if (!dbus_bus_register(bus, error)) {
206 dbus_connection_close(bus);
207 dbus_connection_unref(bus);
215 int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error) {
221 /* Don't bother with PolicyKit if we are root */
223 return bus_connect(DBUS_BUS_SYSTEM, _bus, NULL, error);
225 bus = dbus_connection_open_private("unixexec:path=pkexec,argv1=" SYSTEMD_STDIO_BRIDGE_BINARY_PATH, error);
229 dbus_connection_set_exit_on_disconnect(bus, FALSE);
231 if ((r = sync_auth(bus, error)) < 0) {
232 dbus_connection_close(bus);
233 dbus_connection_unref(bus);
237 if (!dbus_bus_register(bus, error)) {
238 dbus_connection_close(bus);
239 dbus_connection_unref(bus);
247 const char *bus_error_message(const DBusError *error) {
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";
255 return error->message;
258 DBusHandlerResult bus_default_message_handler(
260 DBusMessage *message,
261 const char *introspection,
262 const char *interfaces,
263 const BusBoundProperties *bound_properties) {
266 DBusMessage *reply = NULL;
272 dbus_error_init(&error);
274 if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) {
276 if (!(reply = dbus_message_new_method_return(message)))
279 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID))
282 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && bound_properties) {
283 const char *interface, *property;
284 const BusBoundProperties *bp;
285 const BusProperty *p;
287 DBusMessageIter iter, sub;
289 if (!dbus_message_get_args(
292 DBUS_TYPE_STRING, &interface,
293 DBUS_TYPE_STRING, &property,
295 return bus_send_error_reply(c, message, &error, -EINVAL);
297 for (bp = bound_properties; bp->interface; bp++) {
298 if (!streq(bp->interface, interface))
301 for (p = bp->properties; p->property; p++)
302 if (streq(p->property, property))
307 if (!nulstr_contains(interfaces, interface))
308 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
310 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
312 return bus_send_error_reply(c, message, &error, -EINVAL);
315 reply = dbus_message_new_method_return(message);
319 dbus_message_iter_init_append(reply, &iter);
321 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub))
324 data = (char*)bp->base + p->offset;
326 data = *(void**)data;
327 r = p->append(&sub, property, data);
332 dbus_message_unref(reply);
333 return bus_send_error_reply(c, message, NULL, r);
336 if (!dbus_message_iter_close_container(&iter, &sub))
339 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && bound_properties) {
340 const char *interface;
341 const BusBoundProperties *bp;
342 const BusProperty *p;
343 DBusMessageIter iter, sub, sub2, sub3;
345 if (!dbus_message_get_args(
348 DBUS_TYPE_STRING, &interface,
350 return bus_send_error_reply(c, message, &error, -EINVAL);
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);
357 if (!(reply = dbus_message_new_method_return(message)))
360 dbus_message_iter_init_append(reply, &iter);
362 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub))
365 for (bp = bound_properties; bp->interface; bp++) {
366 if (interface[0] && !streq(bp->interface, interface))
369 for (p = bp->properties; p->property; p++) {
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))
377 data = (char*)bp->base + p->offset;
379 data = *(void**)data;
380 r = p->append(&sub3, p->property, data);
385 dbus_message_unref(reply);
386 return bus_send_error_reply(c, message, NULL, r);
389 if (!dbus_message_iter_close_container(&sub2, &sub3) ||
390 !dbus_message_iter_close_container(&sub, &sub2))
395 if (!dbus_message_iter_close_container(&iter, &sub))
398 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && bound_properties) {
399 const char *interface, *property;
400 DBusMessageIter iter;
401 const BusBoundProperties *bp;
402 const BusProperty *p;
406 DBusMessage *changed;
408 if (!dbus_message_iter_init(message, &iter) ||
409 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
410 return bus_send_error_reply(c, message, NULL, -EINVAL);
412 dbus_message_iter_get_basic(&iter, &interface);
414 if (!dbus_message_iter_next(&iter) ||
415 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
416 return bus_send_error_reply(c, message, NULL, -EINVAL);
418 dbus_message_iter_get_basic(&iter, &property);
420 if (!dbus_message_iter_next(&iter) ||
421 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT ||
422 dbus_message_iter_has_next(&iter))
423 return bus_send_error_reply(c, message, NULL, -EINVAL);
425 for (bp = bound_properties; bp->interface; bp++) {
426 if (!streq(bp->interface, interface))
429 for (p = bp->properties; p->property; p++)
430 if (streq(p->property, property))
435 if (!nulstr_contains(interfaces, interface))
436 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
438 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
440 return bus_send_error_reply(c, message, &error, -EINVAL);
444 dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only");
445 return bus_send_error_reply(c, message, &error, -EINVAL);
448 dbus_message_iter_recurse(&iter, &sub);
450 sig = dbus_message_iter_get_signature(&sub);
454 if (!streq(sig, p->signature)) {
456 return bus_send_error_reply(c, message, NULL, -EINVAL);
460 data = (uint8_t*) bp->base + p->offset;
462 data = *(void**)data;
464 r = p->set(&sub, property, data);
468 return bus_send_error_reply(c, message, NULL, r);
470 reply = dbus_message_new_method_return(message);
474 /* Send out a signal about this, but it doesn't really
475 * matter if this fails, so eat all errors */
476 changed = bus_properties_changed_one_new(
477 dbus_message_get_path(message),
481 dbus_connection_send(c, changed, NULL);
482 dbus_message_unref(changed);
487 const char *interface = dbus_message_get_interface(message);
489 if (!interface || !nulstr_contains(interfaces, interface)) {
490 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
491 return bus_send_error_reply(c, message, &error, -EINVAL);
496 if (!dbus_connection_send(c, reply, NULL))
499 dbus_message_unref(reply);
500 return DBUS_HANDLER_RESULT_HANDLED;
503 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
507 dbus_message_unref(reply);
509 dbus_error_free(&error);
511 return DBUS_HANDLER_RESULT_NEED_MEMORY;
514 int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) {
515 const char *t = data;
523 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
529 int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) {
535 return bus_append_strv_iter(i, t);
538 int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) {
548 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
554 int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data) {
564 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
570 int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) {
575 /* Let's ensure that usec_t is actually 64bit, and hence this
576 * function can be used for usec_t */
577 assert_cc(sizeof(uint64_t) == sizeof(usec_t));
579 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
585 int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) {
590 /* Let's ensure that pid_t, mode_t, uid_t, gid_t are actually
591 * 32bit, and hence this function can be used for
592 * pid_t/mode_t/uid_t/gid_t */
593 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
594 assert_cc(sizeof(uint32_t) == sizeof(mode_t));
595 assert_cc(sizeof(uint32_t) == sizeof(unsigned));
596 assert_cc(sizeof(uint32_t) == sizeof(uid_t));
597 assert_cc(sizeof(uint32_t) == sizeof(gid_t));
599 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
605 int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) {
610 assert_cc(sizeof(int32_t) == sizeof(int));
612 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
618 int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) {
625 u = (uint64_t) *(size_t*) data;
627 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
633 int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) {
640 u = (uint64_t) *(unsigned long*) data;
642 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
648 int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) {
655 l = (int64_t) *(long*) data;
657 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &l))
663 const char *bus_errno_to_dbus(int error) {
668 return DBUS_ERROR_INVALID_ARGS;
671 return DBUS_ERROR_NO_MEMORY;
675 return DBUS_ERROR_ACCESS_DENIED;
678 return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
681 return DBUS_ERROR_FILE_NOT_FOUND;
684 return DBUS_ERROR_FILE_EXISTS;
688 return DBUS_ERROR_TIMEOUT;
691 return DBUS_ERROR_IO_ERROR;
696 return DBUS_ERROR_DISCONNECTED;
699 return DBUS_ERROR_FAILED;
702 DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) {
703 DBusMessage *reply = NULL;
704 const char *name, *text;
706 if (berror && dbus_error_is_set(berror)) {
708 text = berror->message;
710 name = bus_errno_to_dbus(error);
711 text = strerror(-error);
714 if (!(reply = dbus_message_new_error(message, name, text)))
717 if (!dbus_connection_send(c, reply, NULL))
720 dbus_message_unref(reply);
723 dbus_error_free(berror);
725 return DBUS_HANDLER_RESULT_HANDLED;
729 dbus_message_unref(reply);
732 dbus_error_free(berror);
734 return DBUS_HANDLER_RESULT_NEED_MEMORY;
737 DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) {
739 DBusMessageIter iter, sub;
745 m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
749 dbus_message_iter_init_append(m, &iter);
751 /* We won't send any property values, since they might be
752 * large and sometimes not cheap to generated */
754 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
755 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
756 !dbus_message_iter_close_container(&iter, &sub) ||
757 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
760 NULSTR_FOREACH(i, properties)
761 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i))
764 if (!dbus_message_iter_close_container(&iter, &sub))
771 dbus_message_unref(m);
776 DBusMessage* bus_properties_changed_one_new(const char *path, const char *interface, const char *property) {
778 DBusMessageIter iter, sub;
783 m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
787 dbus_message_iter_init_append(m, &iter);
789 /* We won't send any property values, since they might be
790 * large and sometimes not cheap to generated */
792 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
793 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
794 !dbus_message_iter_close_container(&iter, &sub) ||
795 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
798 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &property))
801 if (!dbus_message_iter_close_container(&iter, &sub))
808 dbus_message_unref(m);
813 uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
819 /* no watch flags for disabled watches */
820 if (!dbus_watch_get_enabled(bus_watch))
823 flags = dbus_watch_get_flags(bus_watch);
825 if (flags & DBUS_WATCH_READABLE)
827 if (flags & DBUS_WATCH_WRITABLE)
830 return events | EPOLLHUP | EPOLLERR;
833 unsigned bus_events_to_flags(uint32_t events) {
836 if (events & EPOLLIN)
837 flags |= DBUS_WATCH_READABLE;
838 if (events & EPOLLOUT)
839 flags |= DBUS_WATCH_WRITABLE;
840 if (events & EPOLLHUP)
841 flags |= DBUS_WATCH_HANGUP;
842 if (events & EPOLLERR)
843 flags |= DBUS_WATCH_ERROR;
848 int bus_parse_strv(DBusMessage *m, char ***_l) {
849 DBusMessageIter iter;
854 if (!dbus_message_iter_init(m, &iter))
857 return bus_parse_strv_iter(&iter, _l);
860 int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
862 unsigned n = 0, i = 0;
868 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
869 dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING)
872 dbus_message_iter_recurse(iter, &sub);
874 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
876 dbus_message_iter_next(&sub);
879 if (!(l = new(char*, n+1)))
882 dbus_message_iter_recurse(iter, &sub);
884 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
887 assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
888 dbus_message_iter_get_basic(&sub, &s);
890 if (!(l[i++] = strdup(s))) {
895 dbus_message_iter_next(&sub);
907 int bus_append_strv_iter(DBusMessageIter *iter, char **l) {
912 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub))
916 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l))
919 if (!dbus_message_iter_close_container(iter, &sub))
925 int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
930 if (dbus_message_iter_get_arg_type(iter) != type)
933 dbus_message_iter_get_basic(iter, data);
935 if (!dbus_message_iter_next(iter) != !next)
941 int generic_print_property(const char *name, DBusMessageIter *iter, bool all) {
945 switch (dbus_message_iter_get_arg_type(iter)) {
947 case DBUS_TYPE_STRING: {
949 dbus_message_iter_get_basic(iter, &s);
951 if (all || !isempty(s))
952 printf("%s=%s\n", name, s);
957 case DBUS_TYPE_BOOLEAN: {
960 dbus_message_iter_get_basic(iter, &b);
961 printf("%s=%s\n", name, yes_no(b));
966 case DBUS_TYPE_UINT64: {
968 dbus_message_iter_get_basic(iter, &u);
970 /* Yes, heuristics! But we can change this check
971 * should it turn out to not be sufficient */
973 if (endswith(name, "Timestamp")) {
974 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
976 t = format_timestamp(timestamp, sizeof(timestamp), u);
978 printf("%s=%s\n", name, strempty(t));
980 } else if (strstr(name, "USec")) {
981 char timespan[FORMAT_TIMESPAN_MAX];
983 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
985 printf("%s=%llu\n", name, (unsigned long long) u);
990 case DBUS_TYPE_UINT32: {
992 dbus_message_iter_get_basic(iter, &u);
994 if (strstr(name, "UMask") || strstr(name, "Mode"))
995 printf("%s=%04o\n", name, u);
997 printf("%s=%u\n", name, (unsigned) u);
1002 case DBUS_TYPE_INT32: {
1004 dbus_message_iter_get_basic(iter, &i);
1006 printf("%s=%i\n", name, (int) i);
1010 case DBUS_TYPE_DOUBLE: {
1012 dbus_message_iter_get_basic(iter, &d);
1014 printf("%s=%g\n", name, d);
1018 case DBUS_TYPE_ARRAY:
1020 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
1021 DBusMessageIter sub;
1024 dbus_message_iter_recurse(iter, &sub);
1026 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1027 printf("%s=", name);
1029 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1032 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
1033 dbus_message_iter_get_basic(&sub, &s);
1034 printf("%s%s", space ? " " : "", s);
1037 dbus_message_iter_next(&sub);
1045 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
1046 DBusMessageIter sub;
1048 dbus_message_iter_recurse(iter, &sub);
1050 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1051 printf("%s=", name);
1053 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1056 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
1057 dbus_message_iter_get_basic(&sub, &u);
1060 dbus_message_iter_next(&sub);
1075 static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) {
1077 DBusConnection *bus = userdata;
1079 assert_se(reply = dbus_pending_call_steal_reply(pending));
1080 dbus_message_unref(reply);
1082 dbus_connection_close(bus);
1085 void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) {
1086 DBusMessage *m = NULL;
1087 DBusPendingCall *pending = NULL;
1091 /* We unregister the name here, but we continue to process
1092 * requests, until we get the response for it, so that all
1093 * requests are guaranteed to be processed. */
1095 m = dbus_message_new_method_call(
1098 DBUS_INTERFACE_DBUS,
1103 if (!dbus_message_append_args(
1110 if (!dbus_connection_send_with_reply(bus, m, &pending, -1))
1113 if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL))
1116 dbus_message_unref(m);
1117 dbus_pending_call_unref(pending);
1122 log_error("Out of memory");
1125 dbus_pending_call_cancel(pending);
1126 dbus_pending_call_unref(pending);
1130 dbus_message_unref(m);
1133 DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) {
1134 usec_t *remain_until = userdata;
1138 assert(remain_until);
1140 /* Everytime we get a new message we reset out timeout */
1141 *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
1143 if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected"))
1144 dbus_connection_close(bus);
1146 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;