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;
407 if (!dbus_message_iter_init(message, &iter) ||
408 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
409 return bus_send_error_reply(c, message, NULL, -EINVAL);
411 dbus_message_iter_get_basic(&iter, &interface);
413 if (!dbus_message_iter_next(&iter) ||
414 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
415 return bus_send_error_reply(c, message, NULL, -EINVAL);
417 dbus_message_iter_get_basic(&iter, &property);
419 if (!dbus_message_iter_next(&iter) ||
420 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT ||
421 dbus_message_iter_has_next(&iter))
422 return bus_send_error_reply(c, message, NULL, -EINVAL);
424 for (bp = bound_properties; bp->interface; bp++) {
425 if (!streq(bp->interface, interface))
428 for (p = bp->properties; p->property; p++)
429 if (streq(p->property, property))
434 if (!nulstr_contains(interfaces, interface))
435 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
437 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
439 return bus_send_error_reply(c, message, &error, -EINVAL);
443 dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only");
444 return bus_send_error_reply(c, message, &error, -EINVAL);
447 dbus_message_iter_recurse(&iter, &sub);
449 sig = dbus_message_iter_get_signature(&sub);
453 if (!streq(sig, p->signature)) {
455 return bus_send_error_reply(c, message, NULL, -EINVAL);
460 data = (char*)bp->base + p->offset;
462 data = *(void**)data;
463 r = p->set(&sub, property, data);
467 return bus_send_error_reply(c, message, NULL, r);
470 reply = dbus_message_new_method_return(message);
474 const char *interface = dbus_message_get_interface(message);
476 if (!interface || !nulstr_contains(interfaces, interface)) {
477 dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
478 return bus_send_error_reply(c, message, &error, -EINVAL);
483 if (!dbus_connection_send(c, reply, NULL))
486 dbus_message_unref(reply);
487 return DBUS_HANDLER_RESULT_HANDLED;
490 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
494 dbus_message_unref(reply);
496 dbus_error_free(&error);
498 return DBUS_HANDLER_RESULT_NEED_MEMORY;
501 int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) {
502 const char *t = data;
510 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
516 int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) {
522 return bus_append_strv_iter(i, t);
525 int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) {
535 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
541 int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data) {
551 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
557 int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) {
562 /* Let's ensure that usec_t is actually 64bit, and hence this
563 * function can be used for usec_t */
564 assert_cc(sizeof(uint64_t) == sizeof(usec_t));
566 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data))
572 int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) {
577 /* Let's ensure that pid_t, mode_t, uid_t, gid_t are actually
578 * 32bit, and hence this function can be used for
579 * pid_t/mode_t/uid_t/gid_t */
580 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
581 assert_cc(sizeof(uint32_t) == sizeof(mode_t));
582 assert_cc(sizeof(uint32_t) == sizeof(unsigned));
583 assert_cc(sizeof(uint32_t) == sizeof(uid_t));
584 assert_cc(sizeof(uint32_t) == sizeof(gid_t));
586 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data))
592 int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) {
597 assert_cc(sizeof(int32_t) == sizeof(int));
599 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data))
605 int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) {
612 u = (uint64_t) *(size_t*) data;
614 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
620 int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) {
627 u = (uint64_t) *(unsigned long*) data;
629 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
635 int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) {
642 l = (int64_t) *(long*) data;
644 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &l))
650 const char *bus_errno_to_dbus(int error) {
655 return DBUS_ERROR_INVALID_ARGS;
658 return DBUS_ERROR_NO_MEMORY;
662 return DBUS_ERROR_ACCESS_DENIED;
665 return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN;
668 return DBUS_ERROR_FILE_NOT_FOUND;
671 return DBUS_ERROR_FILE_EXISTS;
675 return DBUS_ERROR_TIMEOUT;
678 return DBUS_ERROR_IO_ERROR;
683 return DBUS_ERROR_DISCONNECTED;
686 return DBUS_ERROR_FAILED;
689 DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) {
690 DBusMessage *reply = NULL;
691 const char *name, *text;
693 if (berror && dbus_error_is_set(berror)) {
695 text = berror->message;
697 name = bus_errno_to_dbus(error);
698 text = strerror(-error);
701 if (!(reply = dbus_message_new_error(message, name, text)))
704 if (!dbus_connection_send(c, reply, NULL))
707 dbus_message_unref(reply);
710 dbus_error_free(berror);
712 return DBUS_HANDLER_RESULT_HANDLED;
716 dbus_message_unref(reply);
719 dbus_error_free(berror);
721 return DBUS_HANDLER_RESULT_NEED_MEMORY;
724 DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) {
726 DBusMessageIter iter, sub;
732 if (!(m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged")))
735 dbus_message_iter_init_append(m, &iter);
737 /* We won't send any property values, since they might be
738 * large and sometimes not cheap to generated */
740 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
741 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) ||
742 !dbus_message_iter_close_container(&iter, &sub) ||
743 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub))
746 NULSTR_FOREACH(i, properties)
747 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i))
750 if (!dbus_message_iter_close_container(&iter, &sub))
757 dbus_message_unref(m);
762 uint32_t bus_flags_to_events(DBusWatch *bus_watch) {
768 /* no watch flags for disabled watches */
769 if (!dbus_watch_get_enabled(bus_watch))
772 flags = dbus_watch_get_flags(bus_watch);
774 if (flags & DBUS_WATCH_READABLE)
776 if (flags & DBUS_WATCH_WRITABLE)
779 return events | EPOLLHUP | EPOLLERR;
782 unsigned bus_events_to_flags(uint32_t events) {
785 if (events & EPOLLIN)
786 flags |= DBUS_WATCH_READABLE;
787 if (events & EPOLLOUT)
788 flags |= DBUS_WATCH_WRITABLE;
789 if (events & EPOLLHUP)
790 flags |= DBUS_WATCH_HANGUP;
791 if (events & EPOLLERR)
792 flags |= DBUS_WATCH_ERROR;
797 int bus_parse_strv(DBusMessage *m, char ***_l) {
798 DBusMessageIter iter;
803 if (!dbus_message_iter_init(m, &iter))
806 return bus_parse_strv_iter(&iter, _l);
809 int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) {
811 unsigned n = 0, i = 0;
817 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
818 dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING)
821 dbus_message_iter_recurse(iter, &sub);
823 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
825 dbus_message_iter_next(&sub);
828 if (!(l = new(char*, n+1)))
831 dbus_message_iter_recurse(iter, &sub);
833 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
836 assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
837 dbus_message_iter_get_basic(&sub, &s);
839 if (!(l[i++] = strdup(s))) {
844 dbus_message_iter_next(&sub);
856 int bus_append_strv_iter(DBusMessageIter *iter, char **l) {
861 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub))
865 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l))
868 if (!dbus_message_iter_close_container(iter, &sub))
874 int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
879 if (dbus_message_iter_get_arg_type(iter) != type)
882 dbus_message_iter_get_basic(iter, data);
884 if (!dbus_message_iter_next(iter) != !next)
890 int generic_print_property(const char *name, DBusMessageIter *iter, bool all) {
894 switch (dbus_message_iter_get_arg_type(iter)) {
896 case DBUS_TYPE_STRING: {
898 dbus_message_iter_get_basic(iter, &s);
900 if (all || !isempty(s))
901 printf("%s=%s\n", name, s);
906 case DBUS_TYPE_BOOLEAN: {
909 dbus_message_iter_get_basic(iter, &b);
910 printf("%s=%s\n", name, yes_no(b));
915 case DBUS_TYPE_UINT64: {
917 dbus_message_iter_get_basic(iter, &u);
919 /* Yes, heuristics! But we can change this check
920 * should it turn out to not be sufficient */
922 if (endswith(name, "Timestamp")) {
923 char timestamp[FORMAT_TIMESTAMP_MAX], *t;
925 t = format_timestamp(timestamp, sizeof(timestamp), u);
927 printf("%s=%s\n", name, strempty(t));
929 } else if (strstr(name, "USec")) {
930 char timespan[FORMAT_TIMESPAN_MAX];
932 printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
934 printf("%s=%llu\n", name, (unsigned long long) u);
939 case DBUS_TYPE_UINT32: {
941 dbus_message_iter_get_basic(iter, &u);
943 if (strstr(name, "UMask") || strstr(name, "Mode"))
944 printf("%s=%04o\n", name, u);
946 printf("%s=%u\n", name, (unsigned) u);
951 case DBUS_TYPE_INT32: {
953 dbus_message_iter_get_basic(iter, &i);
955 printf("%s=%i\n", name, (int) i);
959 case DBUS_TYPE_DOUBLE: {
961 dbus_message_iter_get_basic(iter, &d);
963 printf("%s=%g\n", name, d);
967 case DBUS_TYPE_ARRAY:
969 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
973 dbus_message_iter_recurse(iter, &sub);
975 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
978 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
981 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
982 dbus_message_iter_get_basic(&sub, &s);
983 printf("%s%s", space ? " " : "", s);
986 dbus_message_iter_next(&sub);
994 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
997 dbus_message_iter_recurse(iter, &sub);
999 dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1000 printf("%s=", name);
1002 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1005 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
1006 dbus_message_iter_get_basic(&sub, &u);
1009 dbus_message_iter_next(&sub);
1024 static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) {
1026 DBusConnection *bus = userdata;
1028 assert_se(reply = dbus_pending_call_steal_reply(pending));
1029 dbus_message_unref(reply);
1031 dbus_connection_close(bus);
1034 void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) {
1035 DBusMessage *m = NULL;
1036 DBusPendingCall *pending = NULL;
1040 /* We unregister the name here, but we continue to process
1041 * requests, until we get the response for it, so that all
1042 * requests are guaranteed to be processed. */
1044 m = dbus_message_new_method_call(
1047 DBUS_INTERFACE_DBUS,
1052 if (!dbus_message_append_args(
1059 if (!dbus_connection_send_with_reply(bus, m, &pending, -1))
1062 if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL))
1065 dbus_message_unref(m);
1066 dbus_pending_call_unref(pending);
1071 log_error("Out of memory");
1074 dbus_pending_call_cancel(pending);
1075 dbus_pending_call_unref(pending);
1079 dbus_message_unref(m);
1082 DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) {
1083 usec_t *remain_until = userdata;
1087 assert(remain_until);
1089 /* Everytime we get a new message we reset out timeout */
1090 *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
1092 if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected"))
1093 dbus_connection_close(bus);
1095 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;