[systemd-commits] 11 commits - Makefile.am rules/99-systemd.rules.in src/core src/journal src/libsystemd-bus src/libudev src/nspawn src/run src/shared src/stdio-bridge src/systemd src/timedate src/udev

Lennart Poettering lennart at kemper.freedesktop.org
Tue Oct 15 21:15:09 PDT 2013


 Makefile.am                                    |   11 
 rules/99-systemd.rules.in                      |   16 
 src/core/execute.c                             |    2 
 src/core/manager.h                             |    2 
 src/core/selinux-access.c                      |    2 
 src/core/unit.h                                |    8 
 src/journal/journal-gatewayd.c                 |    3 
 src/journal/journal-send.c                     |    2 
 src/journal/journald-server.h                  |    2 
 src/journal/microhttpd-util.h                  |    2 
 src/libsystemd-bus/bus-control.c               |    1 
 src/libsystemd-bus/bus-convenience.c           |   76 +
 src/libsystemd-bus/bus-error.c                 |  352 ++++++--
 src/libsystemd-bus/bus-error.h                 |    6 
 src/libsystemd-bus/bus-internal.c              |   16 
 src/libsystemd-bus/bus-internal.h              |   12 
 src/libsystemd-bus/bus-introspect.c            |    4 
 src/libsystemd-bus/bus-message.c               |  117 +-
 src/libsystemd-bus/bus-message.h               |    6 
 src/libsystemd-bus/bus-objects.c               |   23 
 src/libsystemd-bus/bus-util.c                  |  378 +++++++++
 src/libsystemd-bus/bus-util.h                  |   45 +
 src/libsystemd-bus/busctl.c                    |    1 
 src/libsystemd-bus/event-util.h                |   30 
 src/libsystemd-bus/sd-bus.c                    |  222 ++++-
 src/libsystemd-bus/sd-event.c                  |   28 
 src/libsystemd-bus/test-bus-chat.c             |    5 
 src/libsystemd-bus/test-bus-kernel-benchmark.c |    1 
 src/libsystemd-bus/test-bus-kernel-bloom.c     |    1 
 src/libsystemd-bus/test-bus-kernel.c           |    1 
 src/libsystemd-bus/test-bus-marshal.c          |    1 
 src/libsystemd-bus/test-bus-match.c            |    1 
 src/libsystemd-bus/test-bus-objects.c          |    9 
 src/libsystemd-bus/test-bus-server.c           |    3 
 src/libudev/libudev-private.h                  |    6 
 src/nspawn/nspawn.c                            |    5 
 src/run/run.c                                  |    3 
 src/shared/conf-parser.h                       |    2 
 src/shared/log.h                               |   10 
 src/shared/macro.h                             |    2 
 src/shared/strxcpyx.h                          |    8 
 src/shared/util.h                              |    6 
 src/stdio-bridge/stdio-bridge.c                |    1 
 src/systemd/sd-bus-protocol.h                  |   60 +
 src/systemd/sd-bus.h                           |   28 
 src/systemd/sd-event.h                         |    1 
 src/timedate/timedated.c                       | 1003 +++++++++----------------
 src/udev/udev.h                                |    2 
 48 files changed, 1629 insertions(+), 897 deletions(-)

New commits:
commit 40ca29a1370379d43e44c0ed425eecc7218dcbca
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Oct 16 06:10:04 2013 +0200

    timedated: use libsystemd-bus instead of libdbus for bus communication
    
    Among other things this also adds a few things necessary for the change:
    
    - Considerably more powerful error returning APIs in libsystemd-bus
    
    - Adapter for connecting an sd_bus to an sd_event
    
    - As I reworked the PolicyKit logic to the new library I also made it
      asynchronous, so that PolicyKit requests of one user cannot block out
      another user anymore.
    
    - We always use the macro names for common bus error. That way it is
      harder to mistype them since the compiler will notice

diff --git a/Makefile.am b/Makefile.am
index 59c5174..ba27a34 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1983,7 +1983,10 @@ libsystemd_bus_la_SOURCES = \
 	src/libsystemd-bus/bus-convenience.c \
 	src/libsystemd-bus/kdbus.h \
 	src/libsystemd-bus/sd-memfd.c \
-	src/libsystemd-bus/sd-event.c
+	src/libsystemd-bus/sd-event.c \
+	src/libsystemd-bus/bus-util.c \
+	src/libsystemd-bus/bus-util.h \
+	src/libsystemd-bus/event-util.h
 
 libsystemd_bus_la_LIBADD =  \
 	libsystemd-id128-internal.la \
@@ -3655,15 +3658,11 @@ if ENABLE_TIMEDATED
 systemd_timedated_SOURCES = \
 	src/timedate/timedated.c
 
-systemd_timedated_CFLAGS = \
-	$(AM_CFLAGS) \
-	$(DBUS_CFLAGS)
-
 systemd_timedated_LDADD = \
 	libsystemd-label.la \
 	libsystemd-shared.la \
 	libsystemd-daemon.la \
-	libsystemd-dbus.la
+	libsystemd-bus.la
 
 rootlibexec_PROGRAMS += \
 	systemd-timedated
diff --git a/src/journal/journal-gatewayd.c b/src/journal/journal-gatewayd.c
index 06a236d..d4d4b7e 100644
--- a/src/journal/journal-gatewayd.c
+++ b/src/journal/journal-gatewayd.c
@@ -32,8 +32,7 @@
 #include "sd-journal.h"
 #include "sd-daemon.h"
 #include "sd-bus.h"
-#include "bus-message.h"
-#include "bus-internal.h"
+#include "bus-util.h"
 #include "logs-show.h"
 #include "microhttpd-util.h"
 #include "build.h"
diff --git a/src/libsystemd-bus/bus-control.c b/src/libsystemd-bus/bus-control.c
index 0ba8585..836570d 100644
--- a/src/libsystemd-bus/bus-control.c
+++ b/src/libsystemd-bus/bus-control.c
@@ -33,6 +33,7 @@
 #include "bus-message.h"
 #include "bus-control.h"
 #include "bus-bloom.h"
+#include "bus-util.h"
 
 int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
         int r;
diff --git a/src/libsystemd-bus/bus-convenience.c b/src/libsystemd-bus/bus-convenience.c
index ddde5da..95a7577 100644
--- a/src/libsystemd-bus/bus-convenience.c
+++ b/src/libsystemd-bus/bus-convenience.c
@@ -22,6 +22,7 @@
 #include "bus-internal.h"
 #include "bus-message.h"
 #include "bus-signature.h"
+#include "bus-util.h"
 
 int sd_bus_emit_signal(
                 sd_bus *bus,
@@ -99,7 +100,7 @@ int sd_bus_reply_method_return(
         assert_return(bus, -EINVAL);
         assert_return(call, -EINVAL);
         assert_return(call->sealed, -EPERM);
-        assert_return(call->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL, -EINVAL);
+        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
@@ -134,7 +135,7 @@ int sd_bus_reply_method_error(
         assert_return(bus, -EINVAL);
         assert_return(call, -EINVAL);
         assert_return(call->sealed, -EPERM);
-        assert_return(call->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL, -EINVAL);
+        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
         assert_return(sd_bus_error_is_set(e), -EINVAL);
         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
         assert_return(!bus_pid_changed(bus), -ECHILD);
@@ -163,29 +164,74 @@ int sd_bus_reply_method_errorf(
         assert_return(bus, -EINVAL);
         assert_return(call, -EINVAL);
         assert_return(call->sealed, -EPERM);
-        assert_return(call->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL, -EINVAL);
+        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
         if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
                 return 0;
 
-        error.name = strdup(name);
-        if (!error.name)
-                return -ENOMEM;
+        va_start(ap, format);
+        r = bus_error_setfv(&error, name, format, ap);
+        va_end(ap);
 
-        error.need_free = true;
+        if (r < 0)
+                return r;
 
-        if (format) {
-                va_start(ap, format);
-                r = vasprintf((char**) &error.message, format, ap);
-                va_end(ap);
+        return sd_bus_reply_method_error(bus, call, &error);
+}
 
-                if (r < 0)
-                        return -ENOMEM;
-        }
+int sd_bus_reply_method_errno(
+                sd_bus *bus,
+                sd_bus_message *call,
+                int error,
+                const sd_bus_error *p) {
 
-        return sd_bus_reply_method_error(bus, call, &error);
+        _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
+
+        assert_return(bus, -EINVAL);
+        assert_return(call, -EINVAL);
+        assert_return(call->sealed, -EPERM);
+        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
+                return 0;
+
+        if (sd_bus_error_is_set(p))
+                return sd_bus_reply_method_error(bus, call, p);
+
+        sd_bus_error_set_errno(&berror, error);
+
+        return sd_bus_reply_method_error(bus, call, &berror);
+}
+
+int sd_bus_reply_method_errnof(
+                sd_bus *bus,
+                sd_bus_message *call,
+                int error,
+                const char *format,
+                ...) {
+
+        _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
+        va_list ap;
+
+        assert_return(bus, -EINVAL);
+        assert_return(call, -EINVAL);
+        assert_return(call->sealed, -EPERM);
+        assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
+        assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+        assert_return(!bus_pid_changed(bus), -ECHILD);
+
+        if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
+                return 0;
+
+        va_start(ap, format);
+        bus_error_set_errnofv(&berror, error, format, ap);
+        va_end(ap);
+
+        return sd_bus_reply_method_error(bus, call, &berror);
 }
 
 int sd_bus_get_property(
diff --git a/src/libsystemd-bus/bus-error.c b/src/libsystemd-bus/bus-error.c
index 28fe154..c347b10 100644
--- a/src/libsystemd-bus/bus-error.c
+++ b/src/libsystemd-bus/bus-error.c
@@ -56,10 +56,9 @@ int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) {
 
         if (!e)
                 return 0;
-        if (bus_error_is_dirty(e))
-                return -EINVAL;
-        if (!name)
-                return -EINVAL;
+
+        assert_return(!bus_error_is_dirty(e), -EINVAL);
+        assert_return(name, -EINVAL);
 
         n = strdup(name);
         if (!n)
@@ -78,27 +77,22 @@ int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message) {
         return 0;
 }
 
-int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...) {
+int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) {
         char *n, *m = NULL;
-        va_list ap;
         int r;
 
         if (!e)
                 return 0;
-        if (bus_error_is_dirty(e))
-                return -EINVAL;
-        if (!name)
-                return -EINVAL;
+
+        assert_return(!bus_error_is_dirty(e), -EINVAL);
+        assert_return(name, -EINVAL);
 
         n = strdup(name);
         if (!n)
                 return -ENOMEM;
 
         if (format) {
-                va_start(ap, format);
                 r = vasprintf(&m, format, ap);
-                va_end(ap);
-
                 if (r < 0) {
                         free(n);
                         return -ENOMEM;
@@ -112,16 +106,32 @@ int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...
         return 0;
 }
 
+int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...) {
+
+        if (format) {
+                int r;
+                va_list ap;
+
+                va_start(ap, format);
+                r = bus_error_setfv(e, name, format, ap);
+                va_end(ap);
+
+                return r;
+        }
+
+        return sd_bus_error_set(e, name, NULL);
+}
+
 int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) {
         char *x, *y = NULL;
 
         if (!dest)
                 return 0;
-        if (bus_error_is_dirty(dest))
-                return -EINVAL;
         if (!sd_bus_error_is_set(e))
                 return 0;
 
+        assert_return(!bus_error_is_dirty(dest), -EINVAL);
+
         x = strdup(e->name);
         if (!x)
                 return -ENOMEM;
@@ -140,13 +150,15 @@ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) {
         return 0;
 }
 
-void sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) {
+int sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) {
         if (!e)
-                return;
-        if (bus_error_is_dirty(e))
-                return;
+                return 0;
+
+        assert_return(!bus_error_is_dirty(e), -EINVAL);
+        assert_return(name, -EINVAL);
 
         *e = SD_BUS_ERROR_MAKE(name, message);
+        return 0;
 }
 
 int sd_bus_error_is_set(const sd_bus_error *e) {
@@ -163,106 +175,282 @@ int sd_bus_error_has_name(const sd_bus_error *e, const char *name) {
         return streq_ptr(e->name, name);
 }
 
-int bus_error_to_errno(const sd_bus_error* e) {
+int sd_bus_error_get_errno(const sd_bus_error* e) {
 
         /* Better replce this with a gperf table */
 
         if (!e)
-                return -EIO;
+                return EIO;
 
         if (!e->name)
-                return -EIO;
+                return EIO;
 
-        if (streq(e->name, "org.freedesktop.DBus.Error.NoMemory"))
-                return -ENOMEM;
+        if (streq(e->name, SD_BUS_ERROR_NO_MEMORY))
+                return ENOMEM;
+
+        if (streq(e->name, SD_BUS_ERROR_SERVICE_UNKNOWN))
+                return EHOSTUNREACH;
+
+        if (streq(e->name, SD_BUS_ERROR_NAME_HAS_NO_OWNER))
+                return ENXIO;
+
+        if (streq(e->name, SD_BUS_ERROR_NO_REPLY) ||
+            streq(e->name, SD_BUS_ERROR_TIMEOUT) ||
+            streq(e->name, "org.freedesktop.DBus.Error.TimedOut"))
+                return ETIMEDOUT;
+
+        if (streq(e->name, SD_BUS_ERROR_IO_ERROR))
+                return EIO;
+
+        if (streq(e->name, SD_BUS_ERROR_BAD_ADDRESS))
+                return EADDRNOTAVAIL;
 
-        if (streq(e->name, "org.freedesktop.DBus.Error.AuthFailed") ||
-            streq(e->name, "org.freedesktop.DBus.Error.AccessDenied"))
-                return -EPERM;
+        if (streq(e->name, SD_BUS_ERROR_NOT_SUPPORTED))
+                return ENOTSUP;
 
-        if (streq(e->name, "org.freedesktop.DBus.Error.InvalidArgs"))
-                return -EINVAL;
+        if (streq(e->name, SD_BUS_ERROR_LIMITS_EXCEEDED))
+                return ENOBUFS;
 
-        if (streq(e->name, "org.freedesktop.DBus.Error.UnixProcessIdUnknown"))
-                return -ESRCH;
+        if (streq(e->name, SD_BUS_ERROR_ACCESS_DENIED) ||
+            streq(e->name, SD_BUS_ERROR_AUTH_FAILED))
+                return EACCES;
 
-        if (streq(e->name, "org.freedesktop.DBus.Error.FileNotFound"))
-                return -ENOENT;
+        if (streq(e->name, SD_BUS_ERROR_NO_SERVER))
+                return EHOSTDOWN;
 
-        if (streq(e->name, "org.freedesktop.DBus.Error.FileExists"))
-                return -EEXIST;
+        if (streq(e->name, SD_BUS_ERROR_NO_NETWORK))
+                return ENONET;
 
-        if (streq(e->name, "org.freedesktop.DBus.Error.Timeout"))
-                return -ETIMEDOUT;
+        if (streq(e->name, SD_BUS_ERROR_ADDRESS_IN_USE))
+                return EADDRINUSE;
 
-        if (streq(e->name, "org.freedesktop.DBus.Error.IOError"))
-                return -EIO;
+        if (streq(e->name, SD_BUS_ERROR_DISCONNECTED))
+                return ECONNRESET;
 
-        if (streq(e->name, "org.freedesktop.DBus.Error.Disconnected"))
-                return -ECONNRESET;
+        if (streq(e->name, SD_BUS_ERROR_INVALID_ARGS) ||
+            streq(e->name, SD_BUS_ERROR_INVALID_SIGNATURE) ||
+            streq(e->name, "org.freedesktop.DBus.Error.MatchRuleInvalid") ||
+            streq(e->name, "org.freedesktop.DBus.Error.InvalidFileContent"))
+                return EINVAL;
 
-        if (streq(e->name, "org.freedesktop.DBus.Error.NotSupported"))
-                return -ENOTSUP;
+        if (streq(e->name, SD_BUS_ERROR_FILE_NOT_FOUND) ||
+            streq(e->name, "org.freedesktop.DBus.Error.MatchRuleNotFound"))
+                return ENOENT;
 
-        return -EIO;
+        if (streq(e->name, SD_BUS_ERROR_FILE_EXISTS))
+                return EEXIST;
+
+        if (streq(e->name, SD_BUS_ERROR_UNKNOWN_METHOD) ||
+            streq(e->name, SD_BUS_ERROR_UNKNOWN_OBJECT) ||
+            streq(e->name, SD_BUS_ERROR_UNKNOWN_INTERFACE) ||
+            streq(e->name, SD_BUS_ERROR_UNKNOWN_PROPERTY))
+                return EBADR;
+
+        if (streq(e->name, SD_BUS_ERROR_PROPERTY_READ_ONLY))
+                return EROFS;
+
+        if (streq(e->name, SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN) ||
+            streq(e->name, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
+                return ESRCH;
+
+        if (streq(e->name, SD_BUS_ERROR_INCONSISTENT_MESSAGE))
+                return EBADMSG;
+
+        if (streq(e->name, "org.freedesktop.DBus.Error.ObjectPathInUse"))
+                return EBUSY;
+
+        return EIO;
 }
 
-int bus_error_from_errno(sd_bus_error *e, int error) {
+static int bus_error_set_strerror_or_const(sd_bus_error *e, const char *name, int error, const char *fallback) {
+        size_t k = 64;
+        char *n = NULL, *m = NULL;
+
+        if (error < 0)
+                error = -error;
+
         if (!e)
-                return error;
+                return -error;
 
-        switch (error) {
+        assert_return(!bus_error_is_dirty(e), -EINVAL);
+        assert_return(name, -EINVAL);
 
-        case -ENOMEM:
-                sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.NoMemory", "Out of memory");
-                break;
+        for (;;) {
+                char *x;
 
-        case -EPERM:
-        case -EACCES:
-                sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.AccessDenied", "Access denied");
-                break;
+                m = new(char, k);
+                if (!m)
+                        goto use_fallback;
+
+                errno = 0;
+                x = strerror_r(error, m, k);
+                if (errno == ERANGE || strlen(x) >= k - 1) {
+                        free(m);
+                        k *= 2;
+                        continue;
+                }
 
-        case -EINVAL:
-                sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid argument");
-                break;
+                if (!x || errno) {
+                        free(m);
+                        goto use_fallback;
+                }
 
-        case -ESRCH:
-                sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.UnixProcessIdUnknown", "No such process");
-                break;
 
-        case -ENOENT:
-                sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.FileNotFound", "File not found");
-                break;
+                if (x != m) {
+                        free(m);
+                        sd_bus_error_set_const(e, name, x);
+                        return -error;
+                }
 
-        case -EEXIST:
-                sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.FileExists", "File exists");
                 break;
+        }
 
-        case -ETIMEDOUT:
-        case -ETIME:
-                sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.Timeout", "Timed out");
-                break;
 
-        case -EIO:
-                sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.IOError", "Input/output error");
-                break;
+        n = strdup(name);
+        if (!n) {
+                free(m);
+                goto use_fallback;
+        }
 
-        case -ENETRESET:
-        case -ECONNABORTED:
-        case -ECONNRESET:
-                sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.Disconnected", "Disconnected");
-                break;
+        e->name = n;
+        e->message = m;
+        e->need_free = true;
 
-        case -ENOTSUP:
-                sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.NotSupported", "Not supported");
-                break;
+        return -error;
+
+use_fallback:
+        sd_bus_error_set_const(e, name, fallback);
+        return -error;
+}
+
+static sd_bus_error map_from_errno(int error) {
+
+        if (error < 0)
+                error = -error;
+
+        switch (error) {
+
+        case ENOMEM:
+                return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_NO_NETWORK, "Out of memory");
+
+        case EPERM:
+        case EACCES:
+                return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_ACCESS_DENIED, "Access denied");
+
+        case EINVAL:
+                return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_INVALID_ARGS, "Invalid argument");
+
+        case ESRCH:
+                return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, "No such process");
+
+        case ENOENT:
+                return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_FILE_NOT_FOUND, "File not found");
+
+        case EEXIST:
+                return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_FILE_EXISTS, "File exists");
+
+        case ETIMEDOUT:
+        case ETIME:
+                return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_TIMEOUT, "Timed out");
+
+        case EIO:
+                return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_IO_ERROR, "Input/output error");
+
+        case ENETRESET:
+        case ECONNABORTED:
+        case ECONNRESET:
+                return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_DISCONNECTED, "Disconnected");
+
+        case ENOTSUP:
+                return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_NOT_SUPPORTED, "Not supported");
+
+        case EADDRNOTAVAIL:
+                return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_BAD_ADDRESS, "Address not available");
+
+        case ENOBUFS:
+                return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_LIMITS_EXCEEDED, "Limits exceeded");
+
+        case EADDRINUSE:
+                return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_ADDRESS_IN_USE, "Address in use");
+
+        case EBADMSG:
+                return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Inconsistent message");
+        }
+
+        return SD_BUS_ERROR_MAKE(SD_BUS_ERROR_FAILED, "Operation failed");
+}
+
+int sd_bus_error_set_errno(sd_bus_error *e, int error) {
+        sd_bus_error x;
+
+        x = map_from_errno(error);
+
+        return bus_error_set_strerror_or_const(e, x.name, error, x.message);
+}
+
+int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) {
+        sd_bus_error x;
+        int r;
+
+        if (error < 0)
+                error = -error;
+
+        if (!e)
+                return 0;
+
+        assert_return(!bus_error_is_dirty(e), -EINVAL);
+
+        x = map_from_errno(error);
+
+        if (format) {
+                char *n, *m;
+
+                r = vasprintf(&m, format, ap);
+                if (r < 0)
+                        goto fallback;
+
+                n = strdup(x.name);
+                if (!n) {
+                        free(m);
+                        goto fallback;
+                }
+
+                e->name = n;
+                e->message = m;
+                e->need_free = true;
+                return -error;
         }
 
-        sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.Failed", "Operation failed");
-        return error;
+fallback:
+        return bus_error_set_strerror_or_const(e, x.name, error, x.message);
+}
+
+int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *format, ...) {
+        int r;
+
+        if (!e)
+                return 0;
+
+        assert_return(!bus_error_is_dirty(e), -EINVAL);
+
+        if (format) {
+                va_list ap;
+
+                va_start(ap, format);
+                r = bus_error_set_errnofv(e, error, format, ap);
+                va_end(ap);
+
+                return r;
+        }
+
+        return sd_bus_error_set_errno(e, error);
 }
 
 const char *bus_error_message(const sd_bus_error *e, int error) {
+
+        if (error < 0)
+                error = -error;
+
         if (e && e->message)
                 return e->message;
 
diff --git a/src/libsystemd-bus/bus-error.h b/src/libsystemd-bus/bus-error.h
index ceca7d6..5474c8c 100644
--- a/src/libsystemd-bus/bus-error.h
+++ b/src/libsystemd-bus/bus-error.h
@@ -23,9 +23,9 @@
 
 #include "sd-bus.h"
 
-int bus_error_to_errno(const sd_bus_error *e);
-int bus_error_from_errno(sd_bus_error *e, int error);
-
 bool bus_error_is_dirty(sd_bus_error *e);
 
 const char *bus_error_message(const sd_bus_error *e, int error);
+
+int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap);
+int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap);
diff --git a/src/libsystemd-bus/bus-internal.c b/src/libsystemd-bus/bus-internal.c
index afff7bd..942ac2b 100644
--- a/src/libsystemd-bus/bus-internal.c
+++ b/src/libsystemd-bus/bus-internal.c
@@ -252,13 +252,13 @@ bool path_simple_pattern(const char *pattern, const char *value) {
 
 int bus_message_type_from_string(const char *s, uint8_t *u) {
         if (streq(s, "signal"))
-                *u = SD_BUS_MESSAGE_TYPE_SIGNAL;
+                *u = SD_BUS_MESSAGE_SIGNAL;
         else if (streq(s, "method_call"))
-                *u = SD_BUS_MESSAGE_TYPE_METHOD_CALL;
+                *u = SD_BUS_MESSAGE_METHOD_CALL;
         else if (streq(s, "error"))
-                *u = SD_BUS_MESSAGE_TYPE_METHOD_ERROR;
+                *u = SD_BUS_MESSAGE_METHOD_ERROR;
         else if (streq(s, "method_return"))
-                *u = SD_BUS_MESSAGE_TYPE_METHOD_RETURN;
+                *u = SD_BUS_MESSAGE_METHOD_RETURN;
         else
                 return -EINVAL;
 
@@ -266,13 +266,13 @@ int bus_message_type_from_string(const char *s, uint8_t *u) {
 }
 
 const char *bus_message_type_to_string(uint8_t u) {
-        if (u == SD_BUS_MESSAGE_TYPE_SIGNAL)
+        if (u == SD_BUS_MESSAGE_SIGNAL)
                 return "signal";
-        else if (u == SD_BUS_MESSAGE_TYPE_METHOD_CALL)
+        else if (u == SD_BUS_MESSAGE_METHOD_CALL)
                 return "method_call";
-        else if (u == SD_BUS_MESSAGE_TYPE_METHOD_ERROR)
+        else if (u == SD_BUS_MESSAGE_METHOD_ERROR)
                 return "error";
-        else if (u == SD_BUS_MESSAGE_TYPE_METHOD_RETURN)
+        else if (u == SD_BUS_MESSAGE_METHOD_RETURN)
                  return "method_return";
         else
                 return NULL;
diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h
index 31e10b2..1726b61 100644
--- a/src/libsystemd-bus/bus-internal.h
+++ b/src/libsystemd-bus/bus-internal.h
@@ -240,14 +240,12 @@ struct sd_bus {
         uint64_t hello_flags;
 
         uint64_t match_cookie;
-};
-
-static inline void bus_unrefp(sd_bus **b) {
-        sd_bus_unref(*b);
-}
 
-#define _cleanup_bus_unref_ __attribute__((cleanup(bus_unrefp)))
-#define _cleanup_bus_error_free_ __attribute__((cleanup(sd_bus_error_free)))
+        sd_event_source *input_io_event_source;
+        sd_event_source *output_io_event_source;
+        sd_event_source *time_event_source;
+        sd_event *event;
+};
 
 #define BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
 
diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c
index 3f68435..bb339f5 100644
--- a/src/libsystemd-bus/bus-message.c
+++ b/src/libsystemd-bus/bus-message.c
@@ -461,7 +461,7 @@ int sd_bus_message_new_signal(
         if (bus && bus->state == BUS_UNSET)
                 return -ENOTCONN;
 
-        t = message_new(bus, SD_BUS_MESSAGE_TYPE_SIGNAL);
+        t = message_new(bus, SD_BUS_MESSAGE_SIGNAL);
         if (!t)
                 return -ENOMEM;
 
@@ -509,7 +509,7 @@ int sd_bus_message_new_method_call(
         if (bus && bus->state == BUS_UNSET)
                 return -ENOTCONN;
 
-        t = message_new(bus, SD_BUS_MESSAGE_TYPE_METHOD_CALL);
+        t = message_new(bus, SD_BUS_MESSAGE_METHOD_CALL);
         if (!t)
                 return -ENOMEM;
 
@@ -553,7 +553,7 @@ static int message_new_reply(
                 return -EINVAL;
         if (!call->sealed)
                 return -EPERM;
-        if (call->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
+        if (call->header->type != SD_BUS_MESSAGE_METHOD_CALL)
                 return -EINVAL;
         if (!m)
                 return -EINVAL;
@@ -592,7 +592,7 @@ int sd_bus_message_new_method_return(
                 sd_bus_message *call,
                 sd_bus_message **m) {
 
-        return message_new_reply(bus, call, SD_BUS_MESSAGE_TYPE_METHOD_RETURN, m);
+        return message_new_reply(bus, call, SD_BUS_MESSAGE_METHOD_RETURN, m);
 }
 
 int sd_bus_message_new_method_error(
@@ -609,7 +609,7 @@ int sd_bus_message_new_method_error(
         if (!m)
                 return -EINVAL;
 
-        r = message_new_reply(bus, call, SD_BUS_MESSAGE_TYPE_METHOD_ERROR, &t);
+        r = message_new_reply(bus, call, SD_BUS_MESSAGE_METHOD_ERROR, &t);
         if (r < 0)
                 return r;
 
@@ -639,46 +639,60 @@ int sd_bus_message_new_method_errorf(
                 const char *format,
                 ...) {
 
-        sd_bus_message *t;
+        _cleanup_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         va_list ap;
         int r;
 
-        if (!name)
-                return -EINVAL;
-        if (!m)
-                return -EINVAL;
+        assert_return(name, -EINVAL);
+        assert_return(m, -EINVAL);
+
+        va_start(ap, format);
+        r = bus_error_setfv(&error, name, format, ap);
+        va_end(ap);
 
-        r = message_new_reply(bus, call, SD_BUS_MESSAGE_TYPE_METHOD_ERROR, &t);
         if (r < 0)
                 return r;
 
-        r = message_append_field_string(t, SD_BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, name, &t->error.name);
-        if (r < 0)
-                goto fail;
+        return sd_bus_message_new_method_error(bus, call, &error, m);
+}
 
-        if (format) {
-                _cleanup_free_ char *message = NULL;
+int sd_bus_message_new_method_errno(
+                sd_bus *bus,
+                sd_bus_message *call,
+                int error,
+                const sd_bus_error *p,
+                sd_bus_message **m) {
 
-                va_start(ap, format);
-                r = vasprintf(&message, format, ap);
-                va_end(ap);
+        _cleanup_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
 
-                if (r < 0) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
+        if (sd_bus_error_is_set(p))
+                return sd_bus_message_new_method_error(bus, call, p, m);
 
-                r = message_append_basic(t, SD_BUS_TYPE_STRING, message, (const void**) &t->error.message);
-                if (r < 0)
-                        goto fail;
-        }
+        sd_bus_error_set_errno(&berror, error);
 
-        *m = t;
-        return 0;
+        return sd_bus_message_new_method_error(bus, call, &berror, m);
+}
 
-fail:
-        message_free(t);
-        return r;
+int sd_bus_message_new_method_errnof(
+                sd_bus *bus,
+                sd_bus_message *call,
+                sd_bus_message **m,
+                int error,
+                const char *format,
+                ...) {
+
+        _cleanup_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
+        va_list ap;
+        int r;
+
+        va_start(ap, format);
+        r = bus_error_set_errnofv(&berror, error, format, ap);
+        va_end(ap);
+
+        if (r < 0)
+                return r;
+
+        return sd_bus_message_new_method_error(bus, call, &berror, m);
 }
 
 int bus_message_new_synthetic_error(
@@ -693,7 +707,7 @@ int bus_message_new_synthetic_error(
         assert(sd_bus_error_is_set(e));
         assert(m);
 
-        t = message_new(bus, SD_BUS_MESSAGE_TYPE_METHOD_ERROR);
+        t = message_new(bus, SD_BUS_MESSAGE_METHOD_ERROR);
         if (!t)
                 return -ENOMEM;
 
@@ -789,7 +803,7 @@ int sd_bus_message_get_no_reply(sd_bus_message *m) {
         if (!m)
                 return -EINVAL;
 
-        return m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL ? !!(m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) : 0;
+        return m->header->type == SD_BUS_MESSAGE_METHOD_CALL ? !!(m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) : 0;
 }
 
 const char *sd_bus_message_get_path(sd_bus_message *m) {
@@ -1126,7 +1140,7 @@ int sd_bus_message_is_signal(sd_bus_message *m, const char *interface, const cha
         if (!m)
                 return -EINVAL;
 
-        if (m->header->type != SD_BUS_MESSAGE_TYPE_SIGNAL)
+        if (m->header->type != SD_BUS_MESSAGE_SIGNAL)
                 return 0;
 
         if (interface && (!m->interface || !streq(m->interface, interface)))
@@ -1142,7 +1156,7 @@ int sd_bus_message_is_method_call(sd_bus_message *m, const char *interface, cons
         if (!m)
                 return -EINVAL;
 
-        if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
+        if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
                 return 0;
 
         if (interface && (!m->interface || !streq(m->interface, interface)))
@@ -1158,7 +1172,7 @@ int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) {
         if (!m)
                 return -EINVAL;
 
-        if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_ERROR)
+        if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
                 return 0;
 
         if (name && (!m->error.name || !streq(m->error.name, name)))
@@ -1172,7 +1186,7 @@ int sd_bus_message_set_no_reply(sd_bus_message *m, int b) {
                 return -EINVAL;
         if (m->sealed)
                 return -EPERM;
-        if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
+        if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
                 return -EPERM;
 
         if (b)
@@ -3876,25 +3890,25 @@ int bus_message_parse_fields(sd_bus_message *m) {
 
         switch (m->header->type) {
 
-        case SD_BUS_MESSAGE_TYPE_SIGNAL:
+        case SD_BUS_MESSAGE_SIGNAL:
                 if (!m->path || !m->interface || !m->member)
                         return -EBADMSG;
                 break;
 
-        case SD_BUS_MESSAGE_TYPE_METHOD_CALL:
+        case SD_BUS_MESSAGE_METHOD_CALL:
 
                 if (!m->path || !m->member)
                         return -EBADMSG;
 
                 break;
 
-        case SD_BUS_MESSAGE_TYPE_METHOD_RETURN:
+        case SD_BUS_MESSAGE_METHOD_RETURN:
 
                 if (m->reply_serial == 0)
                         return -EBADMSG;
                 break;
 
-        case SD_BUS_MESSAGE_TYPE_METHOD_ERROR:
+        case SD_BUS_MESSAGE_METHOD_ERROR:
 
                 if (m->reply_serial == 0 || !m->error.name)
                         return -EBADMSG;
@@ -3902,7 +3916,7 @@ int bus_message_parse_fields(sd_bus_message *m) {
         }
 
         /* Try to read the error message, but if we can't it's a non-issue */
-        if (m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_ERROR)
+        if (m->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
                 sd_bus_message_read(m, "s", &m->error.message);
 
         return 0;
@@ -4363,24 +4377,21 @@ int bus_header_message_size(struct bus_header *h, size_t *sum) {
         return 0;
 }
 
-int bus_message_to_errno(sd_bus_message *m) {
-        assert(m);
+int sd_bus_message_get_errno(sd_bus_message *m) {
+        assert_return(m, -EINVAL);
 
-        if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_ERROR)
+        if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
                 return 0;
 
-        return bus_error_to_errno(&m->error);
+        return sd_bus_error_get_errno(&m->error);
 }
 
-int sd_bus_message_get_signature(sd_bus_message *m, int complete, const char **signature) {
+const char* sd_bus_message_get_signature(sd_bus_message *m, int complete) {
         struct bus_container *c;
 
         if (!m)
-                return -EINVAL;
-        if (!signature)
-                return -EINVAL;
+                return NULL;
 
         c = complete ? &m->root_container : message_get_container(m);
-        *signature = c->signature ?: "";
-        return 0;
+        return c->signature ?: "";
 }
diff --git a/src/libsystemd-bus/bus-message.h b/src/libsystemd-bus/bus-message.h
index 2fb11ea..c79ff1b 100644
--- a/src/libsystemd-bus/bus-message.h
+++ b/src/libsystemd-bus/bus-message.h
@@ -189,12 +189,6 @@ static inline void* BUS_MESSAGE_FIELDS(sd_bus_message *m) {
         return (uint8_t*) m->header + sizeof(struct bus_header);
 }
 
-static inline void bus_message_unrefp(sd_bus_message **m) {
-        sd_bus_message_unref(*m);
-}
-
-#define _cleanup_bus_message_unref_ __attribute__((cleanup(bus_message_unrefp)))
-
 int bus_message_seal(sd_bus_message *m, uint64_t serial);
 int bus_message_dump(sd_bus_message *m);
 int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz);
diff --git a/src/libsystemd-bus/bus-objects.c b/src/libsystemd-bus/bus-objects.c
index 4091490..0c935e9 100644
--- a/src/libsystemd-bus/bus-objects.c
+++ b/src/libsystemd-bus/bus-objects.c
@@ -27,6 +27,7 @@
 #include "bus-signature.h"
 #include "bus-introspect.h"
 #include "bus-objects.h"
+#include "bus-util.h"
 
 static int node_vtable_get_userdata(
                 sd_bus *bus,
@@ -275,13 +276,13 @@ static int method_callbacks_run(
         if (r < 0)
                 return r;
 
-        r = sd_bus_message_get_signature(m, true, &signature);
-        if (r < 0)
-                return r;
+        signature = sd_bus_message_get_signature(m, true);
+        if (!signature)
+                return -EINVAL;
 
         if (!streq(strempty(c->vtable->x.method.signature), signature)) {
                 r = sd_bus_reply_method_errorf(bus, m,
-                                               "org.freedesktop.DBus.Error.InvalidArgs",
+                                               SD_BUS_ERROR_INVALID_ARGS,
                                                "Invalid arguments '%s' to call %s:%s, expecting '%s'.",
                                                signature, c->interface, c->member, strempty(c->vtable->x.method.signature));
                 if (r < 0)
@@ -475,7 +476,7 @@ static int property_get_set_callbacks_run(
 
         } else {
                 if (c->vtable->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
-                        sd_bus_error_setf(&error, "org.freedesktop.DBus.Error.PropertyReadOnly", "Property '%s' is not writable.", c->member);
+                        sd_bus_error_setf(&error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Property '%s' is not writable.", c->member);
                 else  {
                         /* Avoid that we call the set routine more
                          * than once if the processing of this message
@@ -634,7 +635,7 @@ static int property_get_all_callbacks_run(
         if (!found_interface) {
                 r = sd_bus_reply_method_errorf(
                                 bus, m,
-                                "org.freedesktop.DBus.Error.UnknownInterface",
+                                SD_BUS_ERROR_UNKNOWN_INTERFACE,
                                 "Unknown interface '%s'.", iface);
                 if (r < 0)
                         return r;
@@ -1164,7 +1165,7 @@ int bus_process_object(sd_bus *bus, sd_bus_message *m) {
         assert(bus);
         assert(m);
 
-        if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
+        if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
                 return 0;
 
         if (!m->path)
@@ -1203,12 +1204,12 @@ int bus_process_object(sd_bus *bus, sd_bus_message *m) {
             sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set"))
                 r = sd_bus_reply_method_errorf(
                                 bus, m,
-                                "org.freedesktop.DBus.Error.UnknownProperty",
+                                SD_BUS_ERROR_UNKNOWN_PROPERTY,
                                 "Unknown property or interface.");
         else
                 r = sd_bus_reply_method_errorf(
                                 bus, m,
-                                "org.freedesktop.DBus.Error.UnknownMethod",
+                                SD_BUS_ERROR_UNKNOWN_METHOD,
                                 "Unknown method '%s' or interface '%s'.", m->member, m->interface);
 
         if (r < 0)
@@ -1875,8 +1876,6 @@ static int emit_properties_changed_on_interface(
                 r = invoke_property_get(bus, v->vtable, m->path, interface, *property, m, &error, vtable_property_convert_userdata(v->vtable, u));
                 if (r < 0)
                         return r;
-                if (sd_bus_error_is_set(&error))
-                        return bus_error_to_errno(&error);
                 if (bus->nodes_modified)
                         return 0;
 
@@ -2047,8 +2046,6 @@ static int interfaces_added_append_one_prefix(
         r = vtable_append_all_properties(bus, m,path, c, u, &error);
         if (r < 0)
                 return r;
-        if (sd_bus_error_is_set(&error))
-                return bus_error_to_errno(&error);
         if (bus->nodes_modified)
                 return 0;
 
diff --git a/src/libsystemd-bus/bus-util.c b/src/libsystemd-bus/bus-util.c
new file mode 100644
index 0000000..5a70fae
--- /dev/null
+++ b/src/libsystemd-bus/bus-util.c
@@ -0,0 +1,378 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-event.h"
+#include "sd-bus.h"
+
+#include "util.h"
+#include "macro.h"
+#include "def.h"
+
+#include "bus-util.h"
+
+static int quit_callback(sd_bus *bus, sd_bus_message *m, void *userdata) {
+        sd_event *e = userdata;
+
+        assert(bus);
+        assert(m);
+        assert(e);
+
+        sd_event_request_quit(e);
+        return 1;
+}
+
+int bus_async_unregister_and_quit(sd_event *e, sd_bus *bus, const char *name) {
+        _cleanup_free_ char *match = NULL;
+        int r;
+
+        assert(e);
+        assert(bus);
+        assert(name);
+
+        r = asprintf(&match, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameLost',arg0='%s'", name);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_add_match(bus, match, quit_callback, e);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_release_name(bus, name);
+        if (r < 0)
+                return r;
+
+        if (r != SD_BUS_NAME_RELEASED)
+                return -EIO;
+
+        return 0;
+}
+
+int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout) {
+        bool exiting = false;
+        int r;
+
+        assert(e);
+        assert(bus);
+        assert(name);
+
+        for (;;) {
+                r = sd_event_get_state(e);
+                if (r < 0)
+                        return r;
+
+                if (r == SD_EVENT_FINISHED)
+                        break;
+
+                r = sd_event_run(e, exiting ? (uint64_t) -1 : 5 * USEC_PER_SEC /* DEFAULT_EXIT_USEC */);
+                if (r < 0)
+                        return r;
+
+                if (r == 0 && !exiting) {
+                        r = bus_async_unregister_and_quit(e, bus, name);
+                        if (r < 0)
+                                return r;
+
+                        exiting = true;
+                }
+        }
+
+        return 0;
+}
+
+int bus_property_get_tristate(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                sd_bus_error *error,
+                void *userdata) {
+
+        int *tristate = userdata;
+        int r;
+
+        r = sd_bus_message_append(reply, "b", *tristate > 0);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+int bus_verify_polkit(
+                sd_bus *bus,
+                sd_bus_message *m,
+                const char *action,
+                bool interactive,
+                bool *_challenge,
+                sd_bus_error *e) {
+
+        const char *sender;
+        uid_t uid;
+        int r;
+
+        assert(bus);
+        assert(m);
+        assert(action);
+
+        sender = sd_bus_message_get_sender(m);
+        if (!sender)
+                return -EBADMSG;
+
+        r = sd_bus_get_owner_uid(bus, sender, &uid);
+        if (r < 0)
+                return r;
+
+        if (uid == 0)
+                return 1;
+
+#ifdef ENABLE_POLKIT
+        else {
+                _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+                bool authorized = false, challenge = false;
+
+                r = sd_bus_call_method(
+                                bus,
+                                "org.freedesktop.PolicyKit1",
+                                "/org/freedesktop/PolicyKit1/Authority",
+                                "org.freedesktop.PolicyKit1.Authority",
+                                "CheckAuthorization",
+                                e,
+                                &reply,
+                                "(sa{sv})sa{ss}us",
+                                "system-bus-name", 1, "name", "s", sender,
+                                action,
+                                0,
+                                interactive ? 1 : 0,
+                                "");
+
+                if (r < 0) {
+                        /* Treat no PK available as access denied */
+                        if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
+                                sd_bus_error_free(e);
+                                return -EACCES;
+                        }
+
+                        return r;
+                }
+
+                r = sd_bus_message_read(reply, "(bb)", &authorized, &challenge);
+                if (r < 0)
+                        return r;
+
+                if (authorized)
+                        return 1;
+
+                if (_challenge) {
+                        *_challenge = challenge;
+                        return 0;
+                }
+        }
+#endif
+
+        return -EACCES;
+}
+
+#ifdef ENABLE_POLKIT
+
+typedef struct AsyncPolkitQuery {
+        sd_bus_message *request, *reply;
+        sd_bus_message_handler_t callback;
+        void *userdata;
+        uint64_t serial;
+} AsyncPolkitQuery;
+
+static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata) {
+        AsyncPolkitQuery *q = userdata;
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        int r;
+
+        assert(bus);
+        assert(reply);
+        assert(q);
+
+        q->reply = sd_bus_message_ref(reply);
+        q->serial = 0;
+
+        m = sd_bus_message_ref(q->request);
+
+        r = sd_bus_message_rewind(m, true);
+        if (r < 0)
+                return r;
+
+        r = q->callback(bus, m, q->userdata);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static void async_polkit_query_free(sd_bus *b, AsyncPolkitQuery *q) {
+
+        if (!q)
+                return;
+
+        if (q->serial >  0 && b)
+                sd_bus_send_with_reply_cancel(b, q->serial);
+
+        sd_bus_message_unref(q->request);
+        sd_bus_message_unref(q->reply);
+        free(q);
+}
+
+#endif
+
+int bus_verify_polkit_async(
+                sd_bus *bus,
+                Hashmap **registry,
+                sd_bus_message *m,
+                const char *action,
+                bool interactive,
+                sd_bus_error *error,
+                sd_bus_message_handler_t callback,
+                void *userdata) {
+
+#ifdef ENABLE_POLKIT
+        _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
+        AsyncPolkitQuery *q;
+#endif
+        const char *sender;
+        uid_t uid;
+        int r;
+
+        assert(bus);
+        assert(registry);
+        assert(m);
+        assert(action);
+
+#ifdef ENABLE_POLKIT
+        q = hashmap_remove(*registry, m);
+        if (q) {
+                bool authorized, challenge;
+
+                /* This is the second invocation of this function, and
+                 * there's already a response from polkit, let's
+                 * process it */
+                assert(q->reply);
+
+                if (sd_bus_message_is_method_error(q->reply, NULL)) {
+                        const sd_bus_error *e;
+
+                        /* Treat no PK available as access denied */
+                        if (sd_bus_message_is_method_error(q->reply, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
+                                async_polkit_query_free(bus, q);
+                                return -EACCES;
+                        }
+
+                        e = sd_bus_message_get_error(q->reply);
+                        sd_bus_error_copy(error, e);
+                        r = sd_bus_error_get_errno(e);
+
+                        async_polkit_query_free(bus, q);
+                        return r;
+                }
+
+                r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
+                if (r >= 0)
+                        r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);
+
+                async_polkit_query_free(bus, q);
+
+                if (r < 0)
+                        return r;
+
+                if (authorized)
+                        return 1;
+
+                return -EACCES;
+        }
+#endif
+
+        sender = sd_bus_message_get_sender(m);
+        if (!sender)
+                return -EBADMSG;
+
+        r = sd_bus_get_owner_uid(bus, sender, &uid);
+        if (r < 0)
+                return r;
+
+        if (uid == 0)
+                return 1;
+#ifdef ENABLE_POLKIT
+
+        r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_new_method_call(
+                        bus,
+                        "org.freedesktop.PolicyKit1",
+                        "/org/freedesktop/PolicyKit1/Authority",
+                        "org.freedesktop.PolicyKit1.Authority",
+                        "CheckAuthorization",
+                        &pk);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append(
+                        pk,
+                        "(sa{sv})sa{ss}us",
+                        "system-bus-name", 1, "name", "s", sender,
+                        action,
+                        0,
+                        interactive ? 1 : 0,
+                        "");
+        if (r < 0)
+                return r;
+
+        q = new0(AsyncPolkitQuery, 1);
+        if (!q)
+                return -ENOMEM;
+
+        q->request = sd_bus_message_ref(m);
+        q->callback = callback;
+        q->userdata = userdata;
+
+        r = hashmap_put(*registry, m, q);
+        if (r < 0) {
+                async_polkit_query_free(bus, q);
+                return r;
+        }
+
+        r = sd_bus_send_with_reply(bus, pk, async_polkit_callback, q, 0, &q->serial);
+        if (r < 0)
+                return r;
+
+        return 0;
+#endif
+
+        return -EACCES;
+}
+
+void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) {
+#ifdef ENABLE_POLKIT
+        AsyncPolkitQuery *q;
+
+        while ((q = hashmap_steal_first(registry)))
+                async_polkit_query_free(bus, q);
+
+        hashmap_free(registry);
+#endif
+}
diff --git a/src/libsystemd-bus/bus-util.h b/src/libsystemd-bus/bus-util.h
new file mode 100644
index 0000000..354183f
--- /dev/null
+++ b/src/libsystemd-bus/bus-util.h
@@ -0,0 +1,45 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-event.h"
+#include "sd-bus.h"
+#include "hashmap.h"
+#include "time-util.h"
+#include "util.h"
+
+int bus_async_unregister_and_quit(sd_event *e, sd_bus *bus, const char *name);
+
+int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout);
+int bus_property_get_tristate(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata);
+
+int bus_verify_polkit(sd_bus *bus, sd_bus_message *m, const char *action, bool interactive, bool *_challenge, sd_bus_error *e);
+
+int bus_verify_polkit_async(sd_bus *bus, Hashmap **registry, sd_bus_message *m, const char *action, bool interactive, sd_bus_error *error, sd_bus_message_handler_t callback, void *userdata);
+void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, sd_bus_message_unref);
+
+#define _cleanup_bus_unref_ _cleanup_(sd_bus_unrefp)
+#define _cleanup_bus_error_free_ _cleanup_(sd_bus_error_free)
+#define _cleanup_bus_message_unref_ _cleanup_(sd_bus_message_unrefp)
diff --git a/src/libsystemd-bus/busctl.c b/src/libsystemd-bus/busctl.c
index 220c1eb..b15b41a 100644
--- a/src/libsystemd-bus/busctl.c
+++ b/src/libsystemd-bus/busctl.c
@@ -30,6 +30,7 @@
 #include "sd-bus.h"
 #include "bus-message.h"
 #include "bus-internal.h"
+#include "bus-util.h"
 
 static bool arg_no_pager = false;
 static char *arg_address = NULL;
diff --git a/src/libsystemd-bus/event-util.h b/src/libsystemd-bus/event-util.h
new file mode 100644
index 0000000..e58020d
--- /dev/null
+++ b/src/libsystemd-bus/event-util.h
@@ -0,0 +1,30 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event*, sd_event_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event_source*, sd_event_source_unref);
+
+#define _cleanup_event_unref_ _cleanup_(sd_event_unrefp)
+#define _cleanup_event_source_unref_ _cleanup_(sd_event_source_unrefp)
diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c
index 5d1fcd9..665f1e6 100644
--- a/src/libsystemd-bus/sd-bus.c
+++ b/src/libsystemd-bus/sd-bus.c
@@ -45,6 +45,7 @@
 #include "bus-introspect.h"
 #include "bus-signature.h"
 #include "bus-objects.h"
+#include "bus-util.h"
 
 static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec);
 
@@ -104,6 +105,8 @@ static void bus_free(sd_bus *b) {
 
         assert(b);
 
+        sd_bus_detach_event(b);
+
         bus_close_fds(b);
 
         if (b->kdbus_buffer)
@@ -350,9 +353,11 @@ static int hello_callback(sd_bus *bus, sd_bus_message *reply, void *userdata) {
         assert(bus->state == BUS_HELLO);
         assert(reply);
 
-        r = bus_message_to_errno(reply);
+        r = sd_bus_message_get_errno(reply);
         if (r < 0)
                 return r;
+        if (r > 0)
+                return -r;
 
         r = sd_bus_message_read(reply, "s", &s);
         if (r < 0)
@@ -1038,6 +1043,8 @@ void sd_bus_close(sd_bus *bus) {
 
         bus->state = BUS_CLOSED;
 
+        sd_bus_detach_event(bus);
+
         if (!bus->is_kernel)
                 bus_close_fds(bus);
 
@@ -1318,7 +1325,7 @@ int sd_bus_send_with_reply(
         assert_return(bus, -EINVAL);
         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
         assert_return(m, -EINVAL);
-        assert_return(m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL, -EINVAL);
+        assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
         assert_return(!(m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL);
         assert_return(callback, -EINVAL);
         assert_return(!bus_pid_changed(bus), -ECHILD);
@@ -1428,7 +1435,7 @@ int sd_bus_send_with_reply_and_block(
         assert_return(bus, -EINVAL);
         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
         assert_return(m, -EINVAL);
-        assert_return(m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL, -EINVAL);
+        assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
         assert_return(!(m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL);
         assert_return(!bus_error_is_dirty(error), -EINVAL);
         assert_return(!bus_pid_changed(bus), -ECHILD);
@@ -1475,7 +1482,7 @@ int sd_bus_send_with_reply_and_block(
                         if (incoming->reply_serial == serial) {
                                 /* Found a match! */
 
-                                if (incoming->header->type == SD_BUS_MESSAGE_TYPE_METHOD_RETURN) {
+                                if (incoming->header->type == SD_BUS_MESSAGE_METHOD_RETURN) {
 
                                         if (reply)
                                                 *reply = incoming;
@@ -1485,7 +1492,7 @@ int sd_bus_send_with_reply_and_block(
                                         return 1;
                                 }
 
-                                if (incoming->header->type == SD_BUS_MESSAGE_TYPE_METHOD_ERROR) {
+                                if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) {
                                         int k;
 
                                         r = sd_bus_error_copy(error, &incoming->error);
@@ -1494,9 +1501,9 @@ int sd_bus_send_with_reply_and_block(
                                                 return r;
                                         }
 
-                                        k = bus_error_to_errno(&incoming->error);
+                                        k = sd_bus_error_get_errno(&incoming->error);
                                         sd_bus_message_unref(incoming);
-                                        return k;
+                                        return -k;
                                 }
 
                                 sd_bus_message_unref(incoming);
@@ -1623,7 +1630,7 @@ static int process_timeout(sd_bus *bus) {
         r = bus_message_new_synthetic_error(
                         bus,
                         c->serial,
-                        &SD_BUS_ERROR_MAKE("org.freedesktop.DBus.Error.Timeout", "Timed out"),
+                        &SD_BUS_ERROR_MAKE(SD_BUS_ERROR_NO_REPLY, "Method call timed out"),
                         &m);
         if (r < 0)
                 return r;
@@ -1649,8 +1656,8 @@ static int process_hello(sd_bus *bus, sd_bus_message *m) {
          * here (we leave that to the usual handling), we just verify
          * we don't let any earlier msg through. */
 
-        if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_RETURN &&
-            m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_ERROR)
+        if (m->header->type != SD_BUS_MESSAGE_METHOD_RETURN &&
+            m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
                 return -EIO;
 
         if (m->reply_serial != bus->hello_serial)
@@ -1666,8 +1673,8 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) {
         assert(bus);
         assert(m);
 
-        if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_RETURN &&
-            m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_ERROR)
+        if (m->header->type != SD_BUS_MESSAGE_METHOD_RETURN &&
+            m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
                 return 0;
 
         c = hashmap_remove(bus->reply_callbacks, &m->reply_serial);
@@ -1748,7 +1755,7 @@ static int process_builtin(sd_bus *bus, sd_bus_message *m) {
         assert(bus);
         assert(m);
 
-        if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
+        if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
                 return 0;
 
         if (!streq_ptr(m->interface, "org.freedesktop.DBus.Peer"))
@@ -1775,7 +1782,7 @@ static int process_builtin(sd_bus *bus, sd_bus_message *m) {
         } else {
                 r = sd_bus_message_new_method_errorf(
                                 bus, m, &reply,
-                                "org.freedesktop.DBus.Error.UnknownMethod",
+                                SD_BUS_ERROR_UNKNOWN_METHOD,
                                  "Unknown method '%s' on interface '%s'.", m->member, m->interface);
         }
 
@@ -1797,6 +1804,12 @@ static int process_message(sd_bus *bus, sd_bus_message *m) {
 
         bus->iteration_counter++;
 
+        log_debug("Got message sender=%s object=%s interface=%s member=%s",
+                  strna(sd_bus_message_get_sender(m)),
+                  strna(sd_bus_message_get_path(m)),
+                  strna(sd_bus_message_get_interface(m)),
+                  strna(sd_bus_message_get_member(m)));
+
         r = process_hello(bus, m);
         if (r != 0)
                 return r;
@@ -1855,11 +1868,11 @@ static int process_running(sd_bus *bus, sd_bus_message **ret) {
                 return 1;
         }
 
-        if (m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL) {
+        if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) {
 
                 r = sd_bus_reply_method_errorf(
                                 bus, m,
-                                "org.freedesktop.DBus.Error.UnknownObject",
+                                SD_BUS_ERROR_UNKNOWN_OBJECT,
                                 "Unknown object '%s'.", m->path);
                 if (r < 0)
                         return r;
@@ -2123,3 +2136,143 @@ bool bus_pid_changed(sd_bus *bus) {
 
         return bus->original_pid != getpid();
 }
+
+static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        void *bus = userdata;
+        int r;
+
+        assert(bus);
+
+        r = sd_bus_process(bus, NULL);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
+        void *bus = userdata;
+        int r;
+
+        assert(bus);
+
+        r = sd_bus_process(bus, NULL);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static int prepare_callback(sd_event_source *s, void *userdata) {
+        sd_bus *bus = userdata;
+        int r, e;
+        usec_t until;
+
+        assert(s);
+        assert(bus);
+
+        e = sd_bus_get_events(bus);
+        if (e < 0)
+                return e;
+
+        if (bus->output_fd != bus->input_fd) {
+
+                r = sd_event_source_set_io_events(bus->input_io_event_source, e & POLLIN);
+                if (r < 0)
+                        return r;
+
+                r = sd_event_source_set_io_events(bus->output_io_event_source, e & POLLOUT);
+                if (r < 0)
+                        return r;
+        } else {
+                r = sd_event_source_set_io_events(bus->input_io_event_source, e);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_bus_get_timeout(bus, &until);
+        if (r < 0)
+                return r;
+        if (r > 0) {
+                int j;
+
+                j = sd_event_source_set_time(bus->time_event_source, until);
+                if (j < 0)
+                        return j;
+        }
+
+        r = sd_event_source_set_enabled(bus->time_event_source, r > 0);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) {
+        int r;
+
+        assert_return(bus, -EINVAL);
+        assert_return(event, -EINVAL);
+        assert_return(!bus->event, -EBUSY);
+
+        assert(!bus->input_io_event_source);
+        assert(!bus->output_io_event_source);
+        assert(!bus->time_event_source);
+
+        bus->event = sd_event_ref(event);
+
+        r = sd_event_add_io(event, bus->input_fd, 0, io_callback, bus, &bus->input_io_event_source);
+        if (r < 0)
+                goto fail;
+
+        r = sd_event_source_set_priority(bus->input_io_event_source, priority);
+        if (r < 0)
+                goto fail;
+
+        if (bus->output_fd != bus->input_fd) {
+                r = sd_event_add_io(event, bus->output_fd, 0, io_callback, bus, &bus->output_io_event_source);
+                if (r < 0)
+                        goto fail;
+
+                r = sd_event_source_set_priority(bus->output_io_event_source, priority);
+                if (r < 0)
+                        goto fail;
+        }
+
+        r = sd_event_source_set_prepare(bus->input_io_event_source, prepare_callback);
+        if (r < 0)
+                goto fail;
+
+        r = sd_event_add_monotonic(event, 0, 0, time_callback, bus, &bus->time_event_source);
+        if (r < 0)
+                goto fail;
+
+        r = sd_event_source_set_priority(bus->time_event_source, priority);
+        if (r < 0)
+                goto fail;
+
+        return 0;
+
+fail:
+        sd_bus_detach_event(bus);
+        return r;
+}
+
+int sd_bus_detach_event(sd_bus *bus) {
+        assert_return(bus, -EINVAL);
+        assert_return(bus->event, -ENXIO);
+
+        if (bus->input_io_event_source)
+                bus->input_io_event_source = sd_event_source_unref(bus->input_io_event_source);
+
+        if (bus->output_io_event_source)
+                bus->output_io_event_source = sd_event_source_unref(bus->output_io_event_source);
+
+        if (bus->time_event_source)
+                bus->time_event_source = sd_event_source_unref(bus->time_event_source);
+
+        if (bus->event)
+                bus->event = sd_event_unref(bus->event);
+
+        return 0;
+}
diff --git a/src/libsystemd-bus/test-bus-chat.c b/src/libsystemd-bus/test-bus-chat.c
index aefe8f1..efc19c6 100644
--- a/src/libsystemd-bus/test-bus-chat.c
+++ b/src/libsystemd-bus/test-bus-chat.c
@@ -34,6 +34,7 @@
 #include "bus-error.h"
 #include "bus-match.h"
 #include "bus-internal.h"
+#include "bus-util.h"
 
 static int match_callback(sd_bus *bus, sd_bus_message *m, void *userdata) {
         log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m)));
@@ -243,7 +244,7 @@ static int server(sd_bus *bus) {
 
                         r = sd_bus_reply_method_error(
                                         bus, m,
-                                        &SD_BUS_ERROR_MAKE("org.freedesktop.DBus.Error.UnknownMethod", "Unknown method."));
+                                        &SD_BUS_ERROR_MAKE(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method."));
                         if (r < 0) {
                                 log_error("Failed to send reply: %s", strerror(-r));
                                 goto fail;
@@ -359,7 +360,7 @@ finish:
 static int quit_callback(sd_bus *b, sd_bus_message *m, void *userdata) {
         bool *x = userdata;
 
-        log_error("Quit callback: %s", strerror(-bus_message_to_errno(m)));
+        log_error("Quit callback: %s", strerror(sd_bus_message_get_errno(m)));
 
         *x = 1;
         return 1;
diff --git a/src/libsystemd-bus/test-bus-kernel-benchmark.c b/src/libsystemd-bus/test-bus-kernel-benchmark.c
index 2e84cd9..23e4d67 100644
--- a/src/libsystemd-bus/test-bus-kernel-benchmark.c
+++ b/src/libsystemd-bus/test-bus-kernel-benchmark.c
@@ -31,6 +31,7 @@
 #include "bus-error.h"
 #include "bus-kernel.h"
 #include "bus-internal.h"
+#include "bus-util.h"
 
 #define MAX_SIZE (4*1024*1024)
 
diff --git a/src/libsystemd-bus/test-bus-kernel-bloom.c b/src/libsystemd-bus/test-bus-kernel-bloom.c
index 5445d34..dcf0483 100644
--- a/src/libsystemd-bus/test-bus-kernel-bloom.c
+++ b/src/libsystemd-bus/test-bus-kernel-bloom.c
@@ -26,6 +26,7 @@
 #include "bus-message.h"
 #include "bus-error.h"
 #include "bus-kernel.h"
+#include "bus-util.h"
 
 static void test_one(
                 const char *path,
diff --git a/src/libsystemd-bus/test-bus-kernel.c b/src/libsystemd-bus/test-bus-kernel.c
index 680dcde..075903c 100644
--- a/src/libsystemd-bus/test-bus-kernel.c
+++ b/src/libsystemd-bus/test-bus-kernel.c
@@ -28,6 +28,7 @@
 #include "bus-message.h"
 #include "bus-error.h"
 #include "bus-kernel.h"
+#include "bus-util.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_close_ int bus_ref = -1;
diff --git a/src/libsystemd-bus/test-bus-marshal.c b/src/libsystemd-bus/test-bus-marshal.c
index ef1a77f..1e2caa0 100644
--- a/src/libsystemd-bus/test-bus-marshal.c
+++ b/src/libsystemd-bus/test-bus-marshal.c
@@ -34,6 +34,7 @@
 
 #include "sd-bus.h"
 #include "bus-message.h"
+#include "bus-util.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
diff --git a/src/libsystemd-bus/test-bus-match.c b/src/libsystemd-bus/test-bus-match.c
index db977f7..8df491a 100644
--- a/src/libsystemd-bus/test-bus-match.c
+++ b/src/libsystemd-bus/test-bus-match.c
@@ -27,6 +27,7 @@
 
 #include "bus-match.h"
 #include "bus-message.h"
+#include "bus-util.h"
 
 static bool mask[32];
 
diff --git a/src/libsystemd-bus/test-bus-objects.c b/src/libsystemd-bus/test-bus-objects.c
index 543063f..8758404 100644
--- a/src/libsystemd-bus/test-bus-objects.c
+++ b/src/libsystemd-bus/test-bus-objects.c
@@ -33,6 +33,7 @@
 #include "sd-bus.h"
 #include "bus-internal.h"
 #include "bus-message.h"
+#include "bus-util.h"
 
 struct context {
         int fds[2];
@@ -269,13 +270,13 @@ static int client(struct context *c) {
 
         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
         assert_se(r < 0);
-        assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownMethod"));
+        assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
 
         sd_bus_error_free(&error);
 
         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
         assert_se(r < 0);
-        assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.InvalidArgs"));
+        assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
 
         sd_bus_error_free(&error);
 
@@ -372,12 +373,12 @@ static int client(struct context *c) {
 
         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
         assert_se(r < 0);
-        assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownInterface"));
+        assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
         sd_bus_error_free(&error);
 
         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
         assert_se(r < 0);
-        assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownMethod"));
+        assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
         sd_bus_error_free(&error);
 
         r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
diff --git a/src/libsystemd-bus/test-bus-server.c b/src/libsystemd-bus/test-bus-server.c
index ef26a65..478a81e 100644
--- a/src/libsystemd-bus/test-bus-server.c
+++ b/src/libsystemd-bus/test-bus-server.c
@@ -32,6 +32,7 @@
 #include "sd-bus.h"
 #include "bus-internal.h"
 #include "bus-message.h"
+#include "bus-util.h"
 
 struct context {
         int fds[2];
@@ -98,7 +99,7 @@ static void *server(void *p) {
                 } else if (sd_bus_message_is_method_call(m, NULL, NULL)) {
                         r = sd_bus_message_new_method_error(
                                         bus, m,
-                                        &SD_BUS_ERROR_MAKE("org.freedesktop.DBus.Error.UnknownMethod", "Unknown method."),
+                                        &SD_BUS_ERROR_MAKE(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method."),
                                         &reply);
                         if (r < 0) {
                                 log_error("Failed to allocate return: %s", strerror(-r));
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 15e4873..ad0287d 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -61,8 +61,7 @@
 #include "fdset.h"
 #include "build.h"
 #include "fileio.h"
-#include "bus-internal.h"
-#include "bus-message.h"
+#include "bus-util.h"
 
 #ifndef TTY_GID
 #define TTY_GID 5
@@ -1187,7 +1186,7 @@ static int register_machine(void) {
                         NULL,
                         "sayssusa(sv)",
                         arg_machine,
-                        SD_BUS_APPEND_ID128(arg_uuid),
+                        SD_BUS_MESSAGE_APPEND_ID128(arg_uuid),
                         "nspawn",
                         "container",
                         (uint32_t) 0,
diff --git a/src/run/run.c b/src/run/run.c
index 18a4920..49a34fc 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -23,8 +23,7 @@
 #include <getopt.h>
 
 #include "sd-bus.h"
-#include "bus-internal.h"
-#include "bus-message.h"
+#include "bus-util.h"
 #include "strv.h"
 #include "build.h"
 #include "unit-name.h"
diff --git a/src/stdio-bridge/stdio-bridge.c b/src/stdio-bridge/stdio-bridge.c
index ab1a43a..07218e9 100644
--- a/src/stdio-bridge/stdio-bridge.c
+++ b/src/stdio-bridge/stdio-bridge.c
@@ -36,6 +36,7 @@
 #include "sd-bus.h"
 #include "bus-internal.h"
 #include "bus-message.h"
+#include "bus-util.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
diff --git a/src/systemd/sd-bus-protocol.h b/src/systemd/sd-bus-protocol.h
index 8b40386..ff2bcc9 100644
--- a/src/systemd/sd-bus-protocol.h
+++ b/src/systemd/sd-bus-protocol.h
@@ -32,10 +32,10 @@ extern "C" {
 
 enum {
         _SD_BUS_MESSAGE_TYPE_INVALID = 0,
-        SD_BUS_MESSAGE_TYPE_METHOD_CALL,
-        SD_BUS_MESSAGE_TYPE_METHOD_RETURN,
-        SD_BUS_MESSAGE_TYPE_METHOD_ERROR,
-        SD_BUS_MESSAGE_TYPE_SIGNAL,
+        SD_BUS_MESSAGE_METHOD_CALL,
+        SD_BUS_MESSAGE_METHOD_RETURN,
+        SD_BUS_MESSAGE_METHOD_ERROR,
+        SD_BUS_MESSAGE_SIGNAL,
         _SD_BUS_MESSAGE_TYPE_MAX
 };
 
diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
index 9b7ba5a..4c2c06a 100644
--- a/src/systemd/sd-bus.h
+++ b/src/systemd/sd-bus.h
@@ -25,7 +25,9 @@
 #include <inttypes.h>
 #include <sys/types.h>
 
-#include <sd-id128.h>
+#include "sd-id128.h"
+#include "sd-event.h"
+#include "sd-memfd.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -64,7 +66,6 @@ typedef int (*sd_bus_node_enumerator_t) (sd_bus *bus, const char *path, char ***
 
 #include "sd-bus-protocol.h"
 #include "sd-bus-vtable.h"
-#include "sd-memfd.h"
 
 /* Connections */
 
@@ -109,6 +110,9 @@ int sd_bus_process(sd_bus *bus, sd_bus_message **r);
 int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec);
 int sd_bus_flush(sd_bus *bus);
 
+int sd_bus_attach_event(sd_bus *bus, sd_event *e, int priority);
+int sd_bus_detach_event(sd_bus *bus);
+
 int sd_bus_add_filter(sd_bus *bus, sd_bus_message_handler_t callback, void *userdata);
 int sd_bus_remove_filter(sd_bus *bus, sd_bus_message_handler_t callback, void *userdata);
 
@@ -139,6 +143,8 @@ int sd_bus_message_new_method_call(sd_bus *bus, const char *destination, const c
 int sd_bus_message_new_method_return(sd_bus *bus, sd_bus_message *call, sd_bus_message **m);
 int sd_bus_message_new_method_error(sd_bus *bus, sd_bus_message *call, const sd_bus_error *e, sd_bus_message **m);
 int sd_bus_message_new_method_errorf(sd_bus *bus, sd_bus_message *call, sd_bus_message **m, const char *name, const char *format, ...) _sd_printf_attr_(5, 0);
+int sd_bus_message_new_method_errno(sd_bus *bus, sd_bus_message *call, int error, const sd_bus_error *e, sd_bus_message **m);
+int sd_bus_message_new_method_errnof(sd_bus *bus, sd_bus_message *call, sd_bus_message **m, int error, const char *format, ...) _sd_printf_attr_(5, 0);
 
 sd_bus_message* sd_bus_message_ref(sd_bus_message *m);
 sd_bus_message* sd_bus_message_unref(sd_bus_message *m);
@@ -147,14 +153,15 @@ int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type);
 int sd_bus_message_get_serial(sd_bus_message *m, uint64_t *serial);
 int sd_bus_message_get_reply_serial(sd_bus_message *m, uint64_t *serial);
 int sd_bus_message_get_no_reply(sd_bus_message *m);
-int sd_bus_message_get_signature(sd_bus_message *m, int complete, const char **signature);
 
+const char *sd_bus_message_get_signature(sd_bus_message *m, int complete);
 const char *sd_bus_message_get_path(sd_bus_message *m);
 const char *sd_bus_message_get_interface(sd_bus_message *m);
 const char *sd_bus_message_get_member(sd_bus_message *m);
 const char *sd_bus_message_get_destination(sd_bus_message *m);
 const char *sd_bus_message_get_sender(sd_bus_message *m);
 const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m);
+int sd_bus_message_get_errno(sd_bus_message *m);
 
 int sd_bus_message_get_monotonic_timestamp(sd_bus_message *m, uint64_t *usec);
 int sd_bus_message_get_realtime_timestamp(sd_bus_message *m, uint64_t *usec);
@@ -211,6 +218,8 @@ int sd_bus_set_property(sd_bus *bus, const char *destination, const char *path,
 int sd_bus_reply_method_return(sd_bus *bus, sd_bus_message *call, const char *types, ...);
 int sd_bus_reply_method_error(sd_bus *bus, sd_bus_message *call, const sd_bus_error *e);
 int sd_bus_reply_method_errorf(sd_bus *bus, sd_bus_message *call, const char *name, const char *format, ...) _sd_printf_attr_(4, 0);
+int sd_bus_reply_method_errno(sd_bus *bus, sd_bus_message *call, int error, const sd_bus_error *e);
+int sd_bus_reply_method_errnof(sd_bus *bus, sd_bus_message *call, int error, const char *format, ...) _sd_printf_attr_(4, 0);
 
 int sd_bus_emit_signal(sd_bus *bus, const char *path, const char *interface, const char *member, const char *types, ...);
 
@@ -239,16 +248,19 @@ int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machi
 #define SD_BUS_ERROR_NULL SD_BUS_ERROR_MAKE(NULL, NULL)
 
 void sd_bus_error_free(sd_bus_error *e);
-int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...)  _sd_printf_attr_(3, 0);
 int sd_bus_error_set(sd_bus_error *e, const char *name, const char *message);
-void sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message);
+int sd_bus_error_setf(sd_bus_error *e, const char *name, const char *format, ...)  _sd_printf_attr_(3, 0);
+int sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message);
+int sd_bus_error_set_errno(sd_bus_error *e, int error);
+int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *format, ...) _sd_printf_attr_(3, 0);
+int sd_bus_error_get_errno(const sd_bus_error *e);
 int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e);
 int sd_bus_error_is_set(const sd_bus_error *e);
 int sd_bus_error_has_name(const sd_bus_error *e, const char *name);
 
-#define SD_BUS_APPEND_ID128(x) 16,                                          \
-                (x).bytes[0],  (x).bytes[1],  (x).bytes[2],  (x).bytes[3],  \
-                (x).bytes[4],  (x).bytes[5],  (x).bytes[6],  (x).bytes[7],  \
+#define SD_BUS_MESSAGE_APPEND_ID128(x) 16,                              \
+                (x).bytes[0],  (x).bytes[1],  (x).bytes[2],  (x).bytes[3], \
+                (x).bytes[4],  (x).bytes[5],  (x).bytes[6],  (x).bytes[7], \
                 (x).bytes[8],  (x).bytes[9],  (x).bytes[10], (x).bytes[11], \
                 (x).bytes[12], (x).bytes[13], (x).bytes[14], (x).bytes[15]
 
diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h
index d160520..6ac2de8 100644
--- a/src/systemd/sd-event.h
+++ b/src/systemd/sd-event.h
@@ -81,7 +81,6 @@ int sd_event_get_quit(sd_event *e);
 int sd_event_request_quit(sd_event *e);
 int sd_event_get_now_realtime(sd_event *e, uint64_t *usec);
 int sd_event_get_now_monotonic(sd_event *e, uint64_t *usec);
-
 sd_event *sd_event_get(sd_event_source *s);
 
 sd_event_source* sd_event_source_ref(sd_event_source *s);
diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c
index 525c72e..7b22b20 100644
--- a/src/timedate/timedated.c
+++ b/src/timedate/timedated.c
@@ -19,90 +19,52 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <dbus/dbus.h>
-
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
 
-#include "systemd/sd-id128.h"
-#include "systemd/sd-messages.h"
+#include "sd-id128.h"
+#include "sd-messages.h"
+#include "sd-event.h"
+#include "sd-bus.h"
+
 #include "util.h"
 #include "strv.h"
-#include "dbus-common.h"
-#include "polkit.h"
 #include "def.h"
 #include "hwclock.h"
 #include "conf-files.h"
 #include "path-util.h"
 #include "fileio-label.h"
 #include "label.h"
+#include "bus-util.h"
+#include "event-util.h"
 
 #define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n"
 #define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
 
-#define INTERFACE                                                       \
-        " <interface name=\"org.freedesktop.timedate1\">\n"             \
-        "  <property name=\"Timezone\" type=\"s\" access=\"read\"/>\n"  \
-        "  <property name=\"LocalRTC\" type=\"b\" access=\"read\"/>\n"  \
-        "  <property name=\"CanNTP\" type=\"b\" access=\"read\"/>\n"    \
-        "  <property name=\"NTP\" type=\"b\" access=\"read\"/>\n"       \
-        "  <method name=\"SetTime\">\n"                                 \
-        "   <arg name=\"usec_utc\" type=\"x\" direction=\"in\"/>\n"     \
-        "   <arg name=\"relative\" type=\"b\" direction=\"in\"/>\n"     \
-        "   <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"SetTimezone\">\n"                             \
-        "   <arg name=\"timezone\" type=\"s\" direction=\"in\"/>\n"     \
-        "   <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"SetLocalRTC\">\n"                             \
-        "   <arg name=\"local_rtc\" type=\"b\" direction=\"in\"/>\n"    \
-        "   <arg name=\"fix_system\" type=\"b\" direction=\"in\"/>\n"   \
-        "   <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
-        "  </method>\n"                                                 \
-        "  <method name=\"SetNTP\">\n"                                  \
-        "   <arg name=\"use_ntp\" type=\"b\" direction=\"in\"/>\n"      \
-        "   <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
-        "  </method>\n"                                                 \
-        " </interface>\n"
-
-#define INTROSPECTION                                                   \
-        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
-        "<node>\n"                                                      \
-        INTERFACE                                                       \
-        BUS_PROPERTIES_INTERFACE                                        \
-        BUS_INTROSPECTABLE_INTERFACE                                    \
-        BUS_PEER_INTERFACE                                              \
-        "</node>\n"
-
-#define INTERFACES_LIST                         \
-        BUS_GENERIC_INTERFACES_LIST             \
-        "org.freedesktop.timedate1\0"
-
-const char timedate_interface[] _introspect_("timedate1") = INTERFACE;
-
-typedef struct TZ {
+typedef struct Context {
         char *zone;
         bool local_rtc;
         int can_ntp;
         int use_ntp;
-} TZ;
+        Hashmap *polkit_registry;
+} Context;
 
-static TZ tz = {
-        .zone = NULL,
-        .local_rtc = false,
-        .can_ntp = -1,
-        .use_ntp = -1,
-};
+static void context_reset(Context *c) {
+        assert(c);
 
-static usec_t remain_until;
+        free(c->zone);
+        c->zone = NULL;
 
-static void free_data(void) {
-        free(tz.zone);
-        tz.zone = NULL;
+        c->local_rtc = false;
+        c->can_ntp = c->use_ntp = -1;
+}
+
+static void context_free(Context *c, sd_bus *bus) {
+        assert(c);
 
-        tz.local_rtc = false;
+        free(c->zone);
+        bus_verify_polkit_async_registry_free(bus, c->polkit_registry);
 }
 
 static bool valid_timezone(const char *name) {
@@ -153,11 +115,13 @@ static bool valid_timezone(const char *name) {
         return true;
 }
 
-static int read_data(void) {
-        int r;
+static int context_read_data(Context *c) {
         _cleanup_free_ char *t = NULL;
+        int r;
+
+        assert(c);
 
-        free_data();
+        context_reset(c);
 
         r = readlink_malloc("/etc/localtime", &t);
         if (r < 0) {
@@ -175,8 +139,8 @@ static int read_data(void) {
                 if (!e)
                         log_warning("/etc/localtime should be a symbolic link to a timezone data file in /usr/share/zoneinfo/.");
                 else {
-                        tz.zone = strdup(e);
-                        if (!tz.zone)
+                        c->zone = strdup(e);
+                        if (!c->zone)
                                 return log_oom();
 
                         goto have_timezone;
@@ -184,28 +148,30 @@ static int read_data(void) {
         }
 
 have_timezone:
-        if (isempty(tz.zone)) {
-                free(tz.zone);
-                tz.zone = NULL;
+        if (isempty(c->zone)) {
+                free(c->zone);
+                c->zone = NULL;
         }
 
-        tz.local_rtc = hwclock_is_localtime() > 0;
+        c->local_rtc = hwclock_is_localtime() > 0;
 
         return 0;
 }
 
-static int write_data_timezone(void) {
-        int r = 0;
+static int context_write_data_timezone(Context *c) {
         _cleanup_free_ char *p = NULL;
+        int r = 0;
+
+        assert(c);
 
-        if (!tz.zone) {
+        if (isempty(c->zone)) {
                 if (unlink("/etc/localtime") < 0 && errno != ENOENT)
                         r = -errno;
 
                 return r;
         }
 
-        p = strappend("../usr/share/zoneinfo/", tz.zone);
+        p = strappend("../usr/share/zoneinfo/", c->zone);
         if (!p)
                 return log_oom();
 
@@ -216,16 +182,18 @@ static int write_data_timezone(void) {
         return 0;
 }
 
-static int write_data_local_rtc(void) {
+static int context_write_data_local_rtc(Context *c) {
         int r;
         _cleanup_free_ char *s = NULL, *w = NULL;
 
+        assert(c);
+
         r = read_full_file("/etc/adjtime", &s, NULL);
         if (r < 0) {
                 if (r != -ENOENT)
                         return r;
 
-                if (!tz.local_rtc)
+                if (!c->local_rtc)
                         return 0;
 
                 w = strdup(NULL_ADJTIME_LOCAL);
@@ -251,11 +219,11 @@ static int write_data_local_rtc(void) {
                 a = p - s;
                 b = strlen(e);
 
-                w = new(char, a + (tz.local_rtc ? 5 : 3) + b + 1);
+                w = new(char, a + (c->local_rtc ? 5 : 3) + b + 1);
                 if (!w)
                         return -ENOMEM;
 
-                *(char*) mempcpy(stpcpy(mempcpy(w, s, a), tz.local_rtc ? "LOCAL" : "UTC"), e, b) = 0;
+                *(char*) mempcpy(stpcpy(mempcpy(w, s, a), c->local_rtc ? "LOCAL" : "UTC"), e, b) = 0;
 
                 if (streq(w, NULL_ADJTIME_UTC)) {
                         if (unlink("/etc/adjtime") < 0)
@@ -265,12 +233,13 @@ static int write_data_local_rtc(void) {
                         return 0;
                 }
         }
+
         label_init("/etc");
         return write_string_file_atomic_label("/etc/adjtime", w);
 }
 
 static char** get_ntp_services(void) {
-        _cleanup_strv_free_ char **r = NULL, **files;
+        _cleanup_strv_free_ char **r = NULL, **files = NULL;
         char **i;
         int k;
 
@@ -318,709 +287,533 @@ static char** get_ntp_services(void) {
         return strv_uniq(i);
 }
 
-static int read_ntp(DBusConnection *bus) {
-        DBusMessage *m = NULL, *reply = NULL;
-        DBusError error;
+static int context_read_ntp(Context *c, sd_bus *bus) {
+        _cleanup_strv_free_ char **l;
+        char **i;
         int r;
-        char **i, **l;
 
+        assert(c);
         assert(bus);
 
-        dbus_error_init(&error);
-
         l = get_ntp_services();
         STRV_FOREACH(i, l) {
+                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+                sd_bus_message *reply = NULL;
                 const char *s;
 
-                if (m)
-                        dbus_message_unref(m);
-                m = dbus_message_new_method_call(
+                r = sd_bus_call_method(
+                                bus,
                                 "org.freedesktop.systemd1",
                                 "/org/freedesktop/systemd1",
                                 "org.freedesktop.systemd1.Manager",
-                                "GetUnitFileState");
-                if (!m) {
-                        r = log_oom();
-                        goto finish;
-                }
+                                "GetUnitFileState",
+                                &error,
+                                &reply,
+                                "s",
+                                *i);
 
-                if (!dbus_message_append_args(m,
-                                              DBUS_TYPE_STRING, i,
-                                              DBUS_TYPE_INVALID)) {
-                        r = log_oom();
-                        goto finish;
-                }
-
-                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
-                if (!reply) {
-                        if (streq(error.name, "org.freedesktop.DBus.Error.FileNotFound")) {
-                                /* This implementation does not exist, try next one */
-                                dbus_error_free(&error);
+                if (r < 0) {
+                        /* This implementation does not exist, try next one */
+                        if (sd_bus_error_has_name(&error, SD_BUS_ERROR_FILE_NOT_FOUND))
                                 continue;
-                        }
 
-                        log_error("Failed to issue method call: %s", bus_error_message(&error));
-                        r = -EIO;
-                        goto finish;
+                        return r;
                 }
 
-                if (!dbus_message_get_args(reply, &error,
-                                           DBUS_TYPE_STRING, &s,
-                                           DBUS_TYPE_INVALID)) {
-                        log_error("Failed to parse reply: %s", bus_error_message(&error));
-                        r = -EIO;
-                        goto finish;
-                }
+                r = sd_bus_message_read(reply, "s", &s);
+                if (r < 0)
+                        return r;
 
-                tz.can_ntp = 1;
-                tz.use_ntp =
+                c->can_ntp = 1;
+                c->use_ntp =
                         streq(s, "enabled") ||
                         streq(s, "enabled-runtime");
-                r = 0;
-                goto finish;
+
+                return 0;
         }
 
         /* NTP is not installed. */
-        tz.can_ntp = 0;
-        tz.use_ntp = 0;
-        r = 0;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        if (reply)
-                dbus_message_unref(reply);
+        c->can_ntp = 0;
+        c->use_ntp = 0;
 
-        strv_free(l);
-
-        dbus_error_free(&error);
-
-        return r;
+        return 0;
 }
 
-static int start_ntp(DBusConnection *bus, DBusError *error) {
-        DBusMessage *m = NULL, *reply = NULL;
-        const char *mode = "replace";
-        char **i, **l;
+static int context_start_ntp(Context *c, sd_bus *bus, sd_bus_error *error) {
+        _cleanup_strv_free_ char **l = NULL;
+        char **i;
         int r;
 
+        assert(c);
         assert(bus);
         assert(error);
 
         l = get_ntp_services();
         STRV_FOREACH(i, l) {
-                if (m)
-                        dbus_message_unref(m);
-                m = dbus_message_new_method_call(
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                tz.use_ntp ? "StartUnit" : "StopUnit");
-                if (!m) {
-                        log_error("Could not allocate message.");
-                        r = -ENOMEM;
-                        goto finish;
-                }
 
-                if (!dbus_message_append_args(m,
-                                              DBUS_TYPE_STRING, i,
-                                              DBUS_TYPE_STRING, &mode,
-                                              DBUS_TYPE_INVALID)) {
-                        log_error("Could not append arguments to message.");
-                        r = -ENOMEM;
-                        goto finish;
-                }
+                if (c->use_ntp)
+                        r = sd_bus_call_method(
+                                        bus,
+                                        "org.freedesktop.systemd1",
+                                        "/org/freedesktop/systemd1",
+                                        "org.freedesktop.systemd1.Manager",
+                                        "StartUnit",
+                                        error,
+                                        NULL,
+                                        "ss", *i, "replace");
+                else
+                        r = sd_bus_call_method(
+                                        bus,
+                                        "org.freedesktop.systemd1",
+                                        "/org/freedesktop/systemd1",
+                                        "org.freedesktop.systemd1.Manager",
+                                        "StopUnit",
+                                        error,
+                                        NULL,
+                                        "ss", *i, "replace");
 
-                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
-                if (!reply) {
-                        if (streq(error->name, "org.freedesktop.DBus.Error.FileNotFound") ||
-                            streq(error->name, "org.freedesktop.systemd1.LoadFailed") ||
-                            streq(error->name, "org.freedesktop.systemd1.NoSuchUnit")) {
+                if (r < 0) {
+                        if (sd_bus_error_has_name(error, SD_BUS_ERROR_FILE_NOT_FOUND) ||
+                            sd_bus_error_has_name(error, "org.freedesktop.systemd1.LoadFailed") ||
+                            sd_bus_error_has_name(error, "org.freedesktop.systemd1.NoSuchUnit")) {
                                 /* This implementation does not exist, try next one */
-                                dbus_error_free(error);
+                                sd_bus_error_free(error);
                                 continue;
                         }
 
-                        log_error("Failed to issue method call: %s", bus_error_message(error));
-                        r = -EIO;
-                        goto finish;
+                        return r;
                 }
 
-                r = 0;
-                goto finish;
+                return 1;
         }
 
-        /* No implementaiton available... */
-        r = -ENOENT;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        strv_free(l);
-
-        return r;
+        sd_bus_error_set_const(error, "org.freedesktop.timedate1.NoNTPSupport", "NTP not supported.");
+        return -ENOTSUP;
 }
 
-static int enable_ntp(DBusConnection *bus, DBusError *error) {
-        DBusMessage *m = NULL, *reply = NULL;
+static int context_enable_ntp(Context*c, sd_bus *bus, sd_bus_error *error) {
+        _cleanup_strv_free_ char **l = NULL;
+        char **i;
         int r;
-        DBusMessageIter iter;
-        dbus_bool_t f = FALSE, t = TRUE;
-        char **i, **l;
 
+        assert(c);
         assert(bus);
         assert(error);
 
         l = get_ntp_services();
         STRV_FOREACH(i, l) {
-                char* k[2];
-
-                if (m)
-                        dbus_message_unref(m);
-                m = dbus_message_new_method_call(
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                tz.use_ntp ? "EnableUnitFiles" : "DisableUnitFiles");
-                if (!m) {
-                        log_error("Could not allocate message.");
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                dbus_message_iter_init_append(m, &iter);
-
-                k[0] = *i;
-                k[1] = NULL;
+                if (c->use_ntp)
+                        r = sd_bus_call_method(
+                                        bus,
+                                        "org.freedesktop.systemd1",
+                                        "/org/freedesktop/systemd1",
+                                        "org.freedesktop.systemd1.Manager",
+                                        "EnableUnitFiles",
+                                        error,
+                                        NULL,
+                                        "asbb", 1, *i, false, true);
+                else
+                        r = sd_bus_call_method(
+                                        bus,
+                                        "org.freedesktop.systemd1",
+                                        "/org/freedesktop/systemd1",
+                                        "org.freedesktop.systemd1.Manager",
+                                        "DisableUnitFiles",
+                                        error,
+                                        NULL,
+                                        "asb", 1, *i, false);
 
-                r = bus_append_strv_iter(&iter, k);
                 if (r < 0) {
-                        log_error("Failed to append unit files.");
-                        goto finish;
-                }
-
-                /* send runtime bool */
-                if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &f)) {
-                        log_error("Failed to append runtime boolean.");
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                if (tz.use_ntp) {
-                        /* send force bool */
-                        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &t)) {
-                                log_error("Failed to append force boolean.");
-                                r = -ENOMEM;
-                                goto finish;
-                        }
-                }
-
-                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
-                if (!reply) {
-                        if (streq(error->name, "org.freedesktop.DBus.Error.FileNotFound")) {
+                        if (sd_bus_error_has_name(error, SD_BUS_ERROR_FILE_NOT_FOUND)) {
                                 /* This implementation does not exist, try next one */
-                                dbus_error_free(error);
+                                sd_bus_error_free(error);
                                 continue;
                         }
 
-                        log_error("Failed to issue method call: %s", bus_error_message(error));
-                        r = -EIO;
-                        goto finish;
+                        return r;
                 }
 
-                dbus_message_unref(m);
-                m = dbus_message_new_method_call(
+                r = sd_bus_call_method(
+                                bus,
                                 "org.freedesktop.systemd1",
                                 "/org/freedesktop/systemd1",
                                 "org.freedesktop.systemd1.Manager",
-                                "Reload");
-                if (!m) {
-                        log_error("Could not allocate message.");
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                dbus_message_unref(reply);
-                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
-                if (!reply) {
-                        log_error("Failed to issue method call: %s", bus_error_message(error));
-                        r = -EIO;
-                        goto finish;
-                }
+                                "Reload",
+                                error,
+                                NULL,
+                                NULL);
+                if (r < 0)
+                        return r;
 
-                r = 0;
-                goto finish;
+                return 1;
         }
 
-        r = -ENOENT;
+        sd_bus_error_set_const(error, "org.freedesktop.timedate1.NoNTPSupport", "NTP not supported.");
+        return -ENOTSUP;
+}
 
-finish:
-        if (m)
-                dbus_message_unref(m);
+static int method_set_timezone(sd_bus *bus, sd_bus_message *m, void *userdata) {
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        Context *c = userdata;
+        const char *z;
+        bool interactive;
+        char *t;
+        int r;
 
-        if (reply)
-                dbus_message_unref(reply);
+        r = sd_bus_message_read(m, "sb", &z, &interactive);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, m, r, NULL);
 
-        strv_free(l);
+        if (!valid_timezone(z))
+                return sd_bus_reply_method_errorf(bus, m, SD_BUS_ERROR_INVALID_ARGS, "Invalid time zone '%s'", z);
 
-        return r;
-}
+        if (streq_ptr(z, c->zone))
+                return sd_bus_reply_method_return(bus, m, NULL);
 
-static int property_append_can_ntp(DBusMessageIter *i, const char *property, void *data) {
-        dbus_bool_t db;
+        r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-timezone", interactive, &error, method_set_timezone, c);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, m, r, &error);
+        if (r == 0)
+                return 1;
 
-        assert(i);
-        assert(property);
+        t = strdup(z);
+        if (!t)
+                return log_oom();
 
-        db = tz.can_ntp > 0;
+        free(c->zone);
+        c->zone = t;
 
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
-                return -ENOMEM;
+        /* 1. Write new configuration file */
+        r = context_write_data_timezone(c);
+        if (r < 0) {
+                log_error("Failed to set timezone: %s", strerror(-r));
+                return sd_bus_reply_method_errnof(bus, m, r, "Failed to set timezone: %s", strerror(-r));
+        }
 
-        return 0;
-}
+        /* 2. Tell the kernel our timezone */
+        hwclock_set_timezone(NULL);
 
-static int property_append_ntp(DBusMessageIter *i, const char *property, void *data) {
-        dbus_bool_t db;
+        if (c->local_rtc) {
+                struct timespec ts;
+                struct tm *tm;
 
-        assert(i);
-        assert(property);
+                /* 3. Sync RTC from system clock, with the new delta */
+                assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
+                assert_se(tm = localtime(&ts.tv_sec));
+                hwclock_set_time(tm);
+        }
 
-        db = tz.use_ntp > 0;
+        log_struct(LOG_INFO,
+                   MESSAGE_ID(SD_MESSAGE_TIMEZONE_CHANGE),
+                   "TIMEZONE=%s", c->zone,
+                   "MESSAGE=Changed timezone to '%s'.", c->zone,
+                   NULL);
 
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db))
-                return -ENOMEM;
+        sd_bus_emit_properties_changed(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "Timezone", NULL);
 
-        return 0;
+        return sd_bus_reply_method_return(bus, m, NULL);
 }
 
-static const BusProperty bus_timedate_properties[] = {
-        { "Timezone", bus_property_append_string, "s", offsetof(TZ, zone),     true },
-        { "LocalRTC", bus_property_append_bool,   "b", offsetof(TZ, local_rtc) },
-        { "CanNTP",   property_append_can_ntp,    "b", offsetof(TZ, can_ntp)   },
-        { "NTP",      property_append_ntp,        "b", offsetof(TZ, use_ntp)   },
-        { NULL, }
-};
-
-static const BusBoundProperties bps[] = {
-        { "org.freedesktop.timedate1", bus_timedate_properties, &tz },
-        { NULL, }
-};
-
-static DBusHandlerResult timedate_message_handler(
-                DBusConnection *connection,
-                DBusMessage *message,
-                void *userdata) {
-
-        DBusMessage *reply = NULL, *changed = NULL;
-        DBusError error;
+static int method_set_local_rtc(sd_bus *bus, sd_bus_message *m, void *userdata) {
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        bool lrtc, fix_system, interactive;
+        Context *c = userdata;
+        struct timespec ts;
         int r;
 
-        assert(connection);
-        assert(message);
-
-        dbus_error_init(&error);
+        assert(bus);
+        assert(m);
+        assert(c);
 
-        if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetTimezone")) {
-                const char *z;
-                dbus_bool_t interactive;
+        r = sd_bus_message_read(m, "bbb", &lrtc, &fix_system, &interactive);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, m, r, NULL);
 
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_STRING, &z,
-                                    DBUS_TYPE_BOOLEAN, &interactive,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+        if (lrtc == c->local_rtc)
+                return sd_bus_reply_method_return(bus, m, NULL);
 
-                if (!valid_timezone(z))
-                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
+        r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-local-rtc", interactive, &error, method_set_local_rtc, c);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, m, r, &error);
+        if (r == 0)
+                return 1;
 
-                if (!streq_ptr(z, tz.zone)) {
-                        char *t;
+        c->local_rtc = lrtc;
 
-                        r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-timezone", interactive, NULL, &error);
-                        if (r < 0)
-                                return bus_send_error_reply(connection, message, &error, r);
+        /* 1. Write new configuration file */
+        r = context_write_data_local_rtc(c);
+        if (r < 0) {
+                log_error("Failed to set RTC to local/UTC: %s", strerror(-r));
+                return sd_bus_reply_method_errnof(bus, m, r, "Failed to set RTC to local/UTC: %s", strerror(-r));
+        }
 
-                        t = strdup(z);
-                        if (!t)
-                                goto oom;
+        /* 2. Tell the kernel our timezone */
+        hwclock_set_timezone(NULL);
 
-                        free(tz.zone);
-                        tz.zone = t;
+        /* 3. Synchronize clocks */
+        assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
 
-                        /* 1. Write new configuration file */
-                        r = write_data_timezone();
-                        if (r < 0) {
-                                log_error("Failed to set timezone: %s", strerror(-r));
-                                return bus_send_error_reply(connection, message, NULL, r);
-                        }
+        if (fix_system) {
+                struct tm tm;
 
-                        /* 2. Tell the kernel our timezone */
-                        hwclock_set_timezone(NULL);
+                /* Sync system clock from RTC; first,
+                 * initialize the timezone fields of
+                 * struct tm. */
+                if (c->local_rtc)
+                        tm = *localtime(&ts.tv_sec);
+                else
+                        tm = *gmtime(&ts.tv_sec);
 
-                        if (tz.local_rtc) {
-                                struct timespec ts;
-                                struct tm *tm;
+                /* Override the main fields of
+                 * struct tm, but not the timezone
+                 * fields */
+                if (hwclock_get_time(&tm) >= 0) {
 
-                                /* 3. Sync RTC from system clock, with the new delta */
-                                assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
-                                assert_se(tm = localtime(&ts.tv_sec));
-                                hwclock_set_time(tm);
-                        }
+                        /* And set the system clock
+                         * with this */
+                        if (c->local_rtc)
+                                ts.tv_sec = mktime(&tm);
+                        else
+                                ts.tv_sec = timegm(&tm);
 
-                        log_struct(LOG_INFO,
-                                   MESSAGE_ID(SD_MESSAGE_TIMEZONE_CHANGE),
-                                   "TIMEZONE=%s", tz.zone,
-                                   "MESSAGE=Changed timezone to '%s'.", tz.zone,
-                                   NULL);
-
-                        changed = bus_properties_changed_new(
-                                        "/org/freedesktop/timedate1",
-                                        "org.freedesktop.timedate1",
-                                        "Timezone\0");
-                        if (!changed)
-                                goto oom;
+                        clock_settime(CLOCK_REALTIME, &ts);
                 }
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetLocalRTC")) {
-                dbus_bool_t lrtc;
-                dbus_bool_t fix_system;
-                dbus_bool_t interactive;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_BOOLEAN, &lrtc,
-                                    DBUS_TYPE_BOOLEAN, &fix_system,
-                                    DBUS_TYPE_BOOLEAN, &interactive,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                if (lrtc != tz.local_rtc) {
-                        struct timespec ts;
-
-                        r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-local-rtc", interactive, NULL, &error);
-                        if (r < 0)
-                                return bus_send_error_reply(connection, message, &error, r);
-
-                        tz.local_rtc = lrtc;
-
-                        /* 1. Write new configuration file */
-                        r = write_data_local_rtc();
-                        if (r < 0) {
-                                log_error("Failed to set RTC to local/UTC: %s", strerror(-r));
-                                return bus_send_error_reply(connection, message, NULL, r);
-                        }
+        } else {
+                struct tm *tm;
 
-                        /* 2. Tell the kernel our timezone */
-                        hwclock_set_timezone(NULL);
+                /* Sync RTC from system clock */
+                if (c->local_rtc)
+                        tm = localtime(&ts.tv_sec);
+                else
+                        tm = gmtime(&ts.tv_sec);
 
-                        /* 3. Synchronize clocks */
-                        assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
+                hwclock_set_time(tm);
+        }
 
-                        if (fix_system) {
-                                struct tm tm;
+        log_info("RTC configured to %s time.", c->local_rtc ? "local" : "UTC");
 
-                                /* Sync system clock from RTC; first,
-                                 * initialize the timezone fields of
-                                 * struct tm. */
-                                if (tz.local_rtc)
-                                        tm = *localtime(&ts.tv_sec);
-                                else
-                                        tm = *gmtime(&ts.tv_sec);
+        sd_bus_emit_properties_changed(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "LocalRTC", NULL);
 
-                                /* Override the main fields of
-                                 * struct tm, but not the timezone
-                                 * fields */
-                                if (hwclock_get_time(&tm) >= 0) {
+        return sd_bus_reply_method_return(bus, m, NULL);
+}
 
-                                        /* And set the system clock
-                                         * with this */
-                                        if (tz.local_rtc)
-                                                ts.tv_sec = mktime(&tm);
-                                        else
-                                                ts.tv_sec = timegm(&tm);
+static int method_set_time(sd_bus *bus, sd_bus_message *m, void *userdata) {
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        bool relative, interactive;
+        Context *c = userdata;
+        int64_t utc;
+        struct timespec ts;
+        struct tm* tm;
+        int r;
 
-                                        clock_settime(CLOCK_REALTIME, &ts);
-                                }
+        assert(bus);
+        assert(m);
+        assert(c);
 
-                        } else {
-                                struct tm *tm;
+        r = sd_bus_message_read(m, "xbb", &utc, &relative, &interactive);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, m, r, NULL);
 
-                                /* Sync RTC from system clock */
-                                if (tz.local_rtc)
-                                        tm = localtime(&ts.tv_sec);
-                                else
-                                        tm = gmtime(&ts.tv_sec);
+        if (!relative && utc <= 0)
+                return sd_bus_reply_method_errorf(bus, m, SD_BUS_ERROR_INVALID_ARGS, "Invalid absolute time");
 
-                                hwclock_set_time(tm);
-                        }
+        if (relative && utc == 0)
+                return sd_bus_reply_method_return(bus, m, NULL);
 
-                        log_info("RTC configured to %s time.", tz.local_rtc ? "local" : "UTC");
+        if (relative) {
+                usec_t n, x;
 
-                        changed = bus_properties_changed_new(
-                                        "/org/freedesktop/timedate1",
-                                        "org.freedesktop.timedate1",
-                                        "LocalRTC\0");
-                        if (!changed)
-                                goto oom;
-                }
+                n = now(CLOCK_REALTIME);
+                x = n + utc;
 
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetTime")) {
-                int64_t utc;
-                dbus_bool_t relative;
-                dbus_bool_t interactive;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_INT64, &utc,
-                                    DBUS_TYPE_BOOLEAN, &relative,
-                                    DBUS_TYPE_BOOLEAN, &interactive,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                if (!relative && utc <= 0)
-                        return bus_send_error_reply(connection, message, NULL, -EINVAL);
-
-                if (!relative || utc != 0) {
-                        struct timespec ts;
-                        struct tm* tm;
-
-                        if (relative) {
-                                usec_t n, x;
-
-                                n = now(CLOCK_REALTIME);
-                                x = n + utc;
-
-                                if ((utc > 0 && x < n) ||
-                                    (utc < 0 && x > n))
-                                        return bus_send_error_reply(connection, message, NULL, -EOVERFLOW);
-
-                                timespec_store(&ts, x);
-                        } else
-                                timespec_store(&ts, (usec_t) utc);
-
-                        r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-time", interactive, NULL, &error);
-                        if (r < 0)
-                                return bus_send_error_reply(connection, message, &error, r);
-
-                        /* Set system clock */
-                        if (clock_settime(CLOCK_REALTIME, &ts) < 0) {
-                                log_error("Failed to set local time: %m");
-                                return bus_send_error_reply(connection, message, NULL, -errno);
-                        }
+                if ((utc > 0 && x < n) ||
+                    (utc < 0 && x > n))
+                        return sd_bus_reply_method_errorf(bus, m, SD_BUS_ERROR_INVALID_ARGS, "Time value overflow");
 
-                        /* Sync down to RTC */
-                        if (tz.local_rtc)
-                                tm = localtime(&ts.tv_sec);
-                        else
-                                tm = gmtime(&ts.tv_sec);
+                timespec_store(&ts, x);
+        } else
+                timespec_store(&ts, (usec_t) utc);
 
-                        hwclock_set_time(tm);
+        r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-time", interactive, &error, method_set_time, c);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, m, r, &error);
+        if (r == 0)
+                return 1;
+
+        /* Set system clock */
+        if (clock_settime(CLOCK_REALTIME, &ts) < 0) {
+                log_error("Failed to set local time: %m");
+                return sd_bus_reply_method_errnof(bus, m, errno, "Failed to set local time: %m");
+        }
 
-                        log_struct(LOG_INFO,
-                                   MESSAGE_ID(SD_MESSAGE_TIME_CHANGE),
-                                   "REALTIME=%llu", (unsigned long long) timespec_load(&ts),
-                                   "MESSAGE=Changed local time to %s", ctime(&ts.tv_sec),
-                                   NULL);
-                }
-        } else if (dbus_message_is_method_call(message, "org.freedesktop.timedate1", "SetNTP")) {
-                dbus_bool_t ntp;
-                dbus_bool_t interactive;
-
-                if (!dbus_message_get_args(
-                                    message,
-                                    &error,
-                                    DBUS_TYPE_BOOLEAN, &ntp,
-                                    DBUS_TYPE_BOOLEAN, &interactive,
-                                    DBUS_TYPE_INVALID))
-                        return bus_send_error_reply(connection, message, &error, -EINVAL);
-
-                if (ntp != !!tz.use_ntp) {
-
-                        r = verify_polkit(connection, message, "org.freedesktop.timedate1.set-ntp", interactive, NULL, &error);
-                        if (r < 0)
-                                return bus_send_error_reply(connection, message, &error, r);
-
-                        tz.use_ntp = !!ntp;
-
-                        r = enable_ntp(connection, &error);
-                        if (r < 0)
-                                return bus_send_error_reply(connection, message, &error, r);
-
-                        r = start_ntp(connection, &error);
-                        if (r < 0)
-                                return bus_send_error_reply(connection, message, &error, r);
-
-                        log_info("Set NTP to %s", tz.use_ntp ? "enabled" : "disabled");
-
-                        changed = bus_properties_changed_new(
-                                        "/org/freedesktop/timedate1",
-                                        "org.freedesktop.timedate1",
-                                        "NTP\0");
-                        if (!changed)
-                                goto oom;
-                }
+        /* Sync down to RTC */
+        if (c->local_rtc)
+                tm = localtime(&ts.tv_sec);
+        else
+                tm = gmtime(&ts.tv_sec);
 
-        } else
-                return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
+        hwclock_set_time(tm);
 
-        if (!(reply = dbus_message_new_method_return(message)))
-                goto oom;
+        log_struct(LOG_INFO,
+                   MESSAGE_ID(SD_MESSAGE_TIME_CHANGE),
+                   "REALTIME=%llu", (unsigned long long) timespec_load(&ts),
+                   "MESSAGE=Changed local time to %s", ctime(&ts.tv_sec),
+                   NULL);
 
-        if (!bus_maybe_send_reply(connection, message, reply))
-                goto oom;
+        return sd_bus_reply_method_return(bus, m, NULL);
+}
 
-        dbus_message_unref(reply);
-        reply = NULL;
+static int method_set_ntp(sd_bus *bus, sd_bus_message *m, void *userdata) {
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        bool ntp, interactive;
+        Context *c = userdata;
+        int r;
 
-        if (changed) {
+        r = sd_bus_message_read(m, "bb", &ntp, &interactive);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, m, r, NULL);
 
-                if (!dbus_connection_send(connection, changed, NULL))
-                        goto oom;
+        if (ntp == c->use_ntp)
+                return sd_bus_reply_method_return(bus, m, NULL);
 
-                dbus_message_unref(changed);
-        }
+        r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-ntp", interactive, &error, method_set_ntp, c);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, m, r, &error);
+        if (r == 0)
+                return 1;
 
-        return DBUS_HANDLER_RESULT_HANDLED;
+        c->use_ntp = ntp;
 
-oom:
-        if (reply)
-                dbus_message_unref(reply);
+        r = context_enable_ntp(c, bus, &error);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, m, r, &error);
+
+        r = context_start_ntp(c, bus, &error);
+        if (r < 0)
+                return sd_bus_reply_method_errno(bus, m, r, &error);
 
-        if (changed)
-                dbus_message_unref(changed);
+        log_info("Set NTP to %s", c->use_ntp ? "enabled" : "disabled");
 
-        dbus_error_free(&error);
+        sd_bus_emit_properties_changed(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "NTP", NULL);
 
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+        return sd_bus_reply_method_return(bus, m, NULL);
 }
 
-static int connect_bus(DBusConnection **_bus) {
-        static const DBusObjectPathVTable timedate_vtable = {
-                .message_function = timedate_message_handler
-        };
-        DBusError error;
-        DBusConnection *bus = NULL;
+static const sd_bus_vtable timedate_vtable[] = {
+        SD_BUS_VTABLE_START(0),
+        SD_BUS_PROPERTY("Timezone", "s", NULL, offsetof(Context, zone), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("LocalRTC", "b", NULL, offsetof(Context, local_rtc), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("CanNTP", "b", bus_property_get_tristate, offsetof(Context, can_ntp), 0),
+        SD_BUS_PROPERTY("NTP", "b", bus_property_get_tristate, offsetof(Context, use_ntp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_METHOD("SetTime", "xbb", NULL, method_set_time, 0),
+        SD_BUS_METHOD("SetTimezone", "sb", NULL, method_set_timezone, 0),
+        SD_BUS_METHOD("SetLocalRTC", "bbb", NULL, method_set_local_rtc, 0),
+        SD_BUS_METHOD("SetNTP", "bb", NULL, method_set_ntp, 0),
+        SD_BUS_VTABLE_END,
+};
+
+static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
+        _cleanup_bus_unref_ sd_bus *bus = NULL;
         int r;
 
+        assert(c);
+        assert(event);
         assert(_bus);
 
-        dbus_error_init(&error);
-
-        bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
-        if (!bus) {
-                log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error));
-                r = -ECONNREFUSED;
-                goto fail2;
+        r = sd_bus_open_system(&bus);
+        if (r < 0) {
+                log_error("Failed to get system bus connection: %s", strerror(-r));
+                return r;
         }
 
-        dbus_connection_set_exit_on_disconnect(bus, FALSE);
-
-        if (!dbus_connection_register_object_path(bus, "/org/freedesktop/timedate1", &timedate_vtable, NULL) ||
-            !dbus_connection_add_filter(bus, bus_exit_idle_filter, &remain_until, NULL)) {
-                r = log_oom();
-                goto fail;
+        r = sd_bus_add_object_vtable(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", timedate_vtable, c);
+        if (r < 0) {
+                log_error("Failed to register object: %s", strerror(-r));
+                return r;
         }
 
-        r = dbus_bus_request_name(bus, "org.freedesktop.timedate1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
-        if (dbus_error_is_set(&error)) {
-                log_error("Failed to register name on bus: %s", bus_error_message(&error));
-                r = -EEXIST;
-                goto fail;
+        r = sd_bus_request_name(bus, "org.freedesktop.timedate1", SD_BUS_NAME_DO_NOT_QUEUE);
+        if (r < 0) {
+                log_error("Failed to register name: %s", strerror(-r));
+                return r;
         }
 
-        if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)  {
+        if (r != SD_BUS_NAME_PRIMARY_OWNER) {
                 log_error("Failed to acquire name.");
-                r = -EEXIST;
-                goto fail;
+                return -EEXIST;
         }
 
-        if (_bus)
-                *_bus = bus;
-
-        return 0;
+        r = sd_bus_attach_event(bus, event, 0);
+        if (r < 0) {
+                log_error("Failed to attach bus to event loop: %s", strerror(-r));
+                return r;
+        }
 
-fail:
-        dbus_connection_close(bus);
-        dbus_connection_unref(bus);
-fail2:
-        dbus_error_free(&error);
+        *_bus = bus;
+        bus = NULL;
 
-        return r;
+        return 0;
 }
 
 int main(int argc, char *argv[]) {
+        Context context = {
+                .zone = NULL,
+                .local_rtc = false,
+                .can_ntp = -1,
+                .use_ntp = -1,
+        };
+
+        _cleanup_event_unref_ sd_event *event = NULL;
+        _cleanup_bus_unref_ sd_bus *bus = NULL;
         int r;
-        DBusConnection *bus = NULL;
-        bool exiting = false;
 
         log_set_target(LOG_TARGET_AUTO);
+        log_set_max_level(LOG_DEBUG);
         log_parse_environment();
         log_open();
 
         umask(0022);
 
-        if (argc == 2 && streq(argv[1], "--introspect")) {
-                fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
-                      "<node>\n", stdout);
-                fputs(timedate_interface, stdout);
-                fputs("</node>\n", stdout);
-                return 0;
-        }
-
         if (argc != 1) {
                 log_error("This program takes no arguments.");
                 r = -EINVAL;
                 goto finish;
         }
 
-        r = read_data();
+        r = sd_event_new(&event);
         if (r < 0) {
-                log_error("Failed to read timezone data: %s", strerror(-r));
+                log_error("Failed to allocate event loop: %s", strerror(-r));
                 goto finish;
         }
 
-        r = connect_bus(&bus);
+        r = connect_bus(&context, event, &bus);
         if (r < 0)
                 goto finish;
 
-        r = read_ntp(bus);
+        r = context_read_data(&context);
         if (r < 0) {
-                log_error("Failed to determine whether NTP is enabled: %s", strerror(-r));
+                log_error("Failed to read timezone data: %s", strerror(-r));
                 goto finish;
         }
 
-        remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC;
-        for (;;) {
-
-                if (!dbus_connection_read_write_dispatch(bus, exiting ? -1 : (int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC)))
-                        break;
+        r = context_read_ntp(&context, bus);
+        if (r < 0) {
+                log_error("Failed to determine whether NTP is enabled: %s", strerror(-r));
+                goto finish;
+        }
 
-                if (!exiting && remain_until < now(CLOCK_MONOTONIC)) {
-                        exiting = true;
-                        bus_async_unregister_and_exit(bus, "org.freedesktop.timedated1");
-                }
+        r = bus_event_loop_with_idle(event, bus, "org.freedesktop.timedate1", DEFAULT_EXIT_USEC);
+        if (r < 0) {
+                log_error("Failed to run event loop: %s", strerror(-r));
+                goto finish;
         }
 
+        sd_bus_flush(bus);
         r = 0;
 
 finish:
-        free_data();
-
-        if (bus) {
-                dbus_connection_flush(bus);
-                dbus_connection_close(bus);
-                dbus_connection_unref(bus);
-        }
+        context_free(&context, bus);
 
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }

commit 7a37d62501c97eb3b48a418ef764d0308e0c3fb9
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Oct 16 06:04:20 2013 +0200

    bus: return 1 on all calls that send messages
    
    This way they are nicer to use from method dispatch callbacks as last
    call, since method dispatch callbacks expect > 0 return if the message
    got handled.

diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c
index ac886e9..5d1fcd9 100644
--- a/src/libsystemd-bus/sd-bus.c
+++ b/src/libsystemd-bus/sd-bus.c
@@ -1231,7 +1231,7 @@ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial) {
         /* If this is a reply and no reply was requested, then let's
          * suppress this, if we can */
         if (m->dont_send && !serial)
-                return 0;
+                return 1;
 
         if ((bus->state == BUS_RUNNING || bus->state == BUS_HELLO) && bus->wqueue_size <= 0) {
                 size_t idx = 0;
@@ -1273,7 +1273,7 @@ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial) {
         if (serial)
                 *serial = BUS_MESSAGE_SERIAL(m);
 
-        return 0;
+        return 1;
 }
 
 static usec_t calc_elapse(uint64_t usec) {
@@ -1482,7 +1482,7 @@ int sd_bus_send_with_reply_and_block(
                                         else
                                                 sd_bus_message_unref(incoming);
 
-                                        return 0;
+                                        return 1;
                                 }
 
                                 if (incoming->header->type == SD_BUS_MESSAGE_TYPE_METHOD_ERROR) {

commit 8efd6381798d0cfcba6f98c5a81f9b296ad49733
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Oct 16 06:01:46 2013 +0200

    bus: make sure sd_bus_get_timeout() returns a 0 timeout of there are already read but not dispatched messages

diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c
index ee5f395..ac886e9 100644
--- a/src/libsystemd-bus/sd-bus.c
+++ b/src/libsystemd-bus/sd-bus.c
@@ -1589,6 +1589,11 @@ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) {
                 return 0;
         }
 
+        if (bus->rqueue_size > 0) {
+                *timeout_usec = 0;
+                return 1;
+        }
+
         c = prioq_peek(bus->reply_callbacks_prioq);
         if (!c) {
                 *timeout_usec = (uint64_t) -1;
@@ -1924,7 +1929,7 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
         struct pollfd p[2] = {};
         int r, e, n;
         struct timespec ts;
-        usec_t until, m;
+        usec_t m = (usec_t) -1;
 
         assert(bus);
         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
@@ -1934,17 +1939,23 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
                 return e;
 
         if (need_more)
+                /* The caller really needs some more data, he doesn't
+                 * care about what's already read, or any timeouts
+                 * except its own.*/
                 e |= POLLIN;
-
-        r = sd_bus_get_timeout(bus, &until);
-        if (r < 0)
-                return r;
-        if (r == 0)
-                m = (uint64_t) -1;
         else {
-                usec_t nw;
-                nw = now(CLOCK_MONOTONIC);
-                m = until > nw ? until - nw : 0;
+                usec_t until;
+                /* The caller wants to process if there's something to
+                 * process, but doesn't care otherwise */
+
+                r = sd_bus_get_timeout(bus, &until);
+                if (r < 0)
+                        return r;
+                if (r > 0) {
+                        usec_t nw;
+                        nw = now(CLOCK_MONOTONIC);
+                        m = until > nw ? until - nw : 0;
+                }
         }
 
         if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))

commit 6014597dd60a708213cf50d28278877c00843a02
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Oct 16 05:59:21 2013 +0200

    bus: fix generate introspection XML

diff --git a/src/libsystemd-bus/bus-introspect.c b/src/libsystemd-bus/bus-introspect.c
index 3178878..92deb75 100644
--- a/src/libsystemd-bus/bus-introspect.c
+++ b/src/libsystemd-bus/bus-introspect.c
@@ -103,9 +103,9 @@ static int introspect_write_arguments(struct introspect *i, const char *signatur
                 fprintf(i->f, "   <arg type=\"%.*s\"", (int) l, signature);
 
                 if (direction)
-                        fprintf(i->f, " direction=\"%s\">\n", direction);
+                        fprintf(i->f, " direction=\"%s\"/>\n", direction);
                 else
-                        fputs(">\n", i->f);
+                        fputs("/>\n", i->f);
 
                 signature += l;
         }

commit 75297aba8130cb1c1af2ae394039cbb9127161df
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Oct 16 05:58:28 2013 +0200

    bus: extend bus protocol definitions a bit

diff --git a/src/systemd/sd-bus-protocol.h b/src/systemd/sd-bus-protocol.h
index 568005b..8b40386 100644
--- a/src/systemd/sd-bus-protocol.h
+++ b/src/systemd/sd-bus-protocol.h
@@ -104,6 +104,28 @@ enum {
         _SD_BUS_MESSAGE_HEADER_MAX
 };
 
+/* RequestName parameters */
+enum  {
+        SD_BUS_NAME_ALLOW_REPLACEMENT = 1,
+        SD_BUS_NAME_REPLACE_EXISTING = 2,
+        SD_BUS_NAME_DO_NOT_QUEUE = 4
+};
+
+/* RequestName returns */
+enum  {
+        SD_BUS_NAME_PRIMARY_OWNER = 1,
+        SD_BUS_NAME_IN_QUEUE = 2,
+        SD_BUS_NAME_EXISTS = 3,
+        SD_BUS_NAME_ALREADY_OWNER = 4
+};
+
+/* ReleaseName returns */
+enum {
+        SD_BUS_NAME_RELEASED = 1,
+        SD_BUS_NAME_NON_EXISTENT = 2,
+        SD_BUS_NAME_NOT_OWNER = 3,
+};
+
 #define SD_BUS_INTROSPECT_DOCTYPE                                       \
         "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" \
         "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
@@ -161,6 +183,36 @@ enum {
         "  </signal>\n"                                                 \
         " </interface>\n"
 
+/* Well-known errors. Note that this is only a sanitized subset of the
+ * errors that the reference implementation generates. */
+#define SD_BUS_ERROR_FAILED                     "org.freedesktop.DBus.Error.Failed"
+#define SD_BUS_ERROR_NO_MEMORY                  "org.freedesktop.DBus.Error.NoMemory"
+#define SD_BUS_ERROR_SERVICE_UNKNOWN            "org.freedesktop.DBus.Error.ServiceUnknown"
+#define SD_BUS_ERROR_NAME_HAS_NO_OWNER          "org.freedesktop.DBus.Error.NameHasNoOwner"
+#define SD_BUS_ERROR_NO_REPLY                   "org.freedesktop.DBus.Error.NoReply"
+#define SD_BUS_ERROR_IO_ERROR                   "org.freedesktop.DBus.Error.IOError"
+#define SD_BUS_ERROR_BAD_ADDRESS                "org.freedesktop.DBus.Error.BadAddress"
+#define SD_BUS_ERROR_NOT_SUPPORTED              "org.freedesktop.DBus.Error.NotSupported"
+#define SD_BUS_ERROR_LIMITS_EXCEEDED            "org.freedesktop.DBus.Error.LimitsExceeded"
+#define SD_BUS_ERROR_ACCESS_DENIED              "org.freedesktop.DBus.Error.AccessDenied"
+#define SD_BUS_ERROR_AUTH_FAILED                "org.freedesktop.DBus.Error.AuthFailed"
+#define SD_BUS_ERROR_NO_SERVER                  "org.freedesktop.DBus.Error.NoServer"
+#define SD_BUS_ERROR_TIMEOUT                    "org.freedesktop.DBus.Error.Timeout"
+#define SD_BUS_ERROR_NO_NETWORK                 "org.freedesktop.DBus.Error.NoNetwork"
+#define SD_BUS_ERROR_ADDRESS_IN_USE             "org.freedesktop.DBus.Error.AddressInUse"
+#define SD_BUS_ERROR_DISCONNECTED               "org.freedesktop.DBus.Error.Disconnected"
+#define SD_BUS_ERROR_INVALID_ARGS               "org.freedesktop.DBus.Error.InvalidArgs"
+#define SD_BUS_ERROR_FILE_NOT_FOUND             "org.freedesktop.DBus.Error.FileNotFound"
+#define SD_BUS_ERROR_FILE_EXISTS                "org.freedesktop.DBus.Error.FileExists"
+#define SD_BUS_ERROR_UNKNOWN_METHOD             "org.freedesktop.DBus.Error.UnknownMethod"
+#define SD_BUS_ERROR_UNKNOWN_OBJECT             "org.freedesktop.DBus.Error.UnknownObject"
+#define SD_BUS_ERROR_UNKNOWN_INTERFACE          "org.freedesktop.DBus.Error.UnknownInterface"
+#define SD_BUS_ERROR_UNKNOWN_PROPERTY           "org.freedesktop.DBus.Error.UnknownProperty"
+#define SD_BUS_ERROR_PROPERTY_READ_ONLY         "org.freedesktop.DBus.Error.PropertyReadOnly"
+#define SD_BUS_ERROR_UNIX_PROCESS_ID_UNKNOWN    "org.freedesktop.DBus.Error.UnixProcessIdUnknown"
+#define SD_BUS_ERROR_INVALID_SIGNATURE          "org.freedesktop.DBus.Error.InvalidSignature"
+#define SD_BUS_ERROR_INCONSISTENT_MESSAGE       "org.freedesktop.DBus.Error.InconsistentMessage"
+
 #ifdef __cplusplus
 }
 #endif

commit d09d5ecda2172ba539f1b08da9f3e9787be37229
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Oct 16 05:57:41 2013 +0200

    event: handle arbitrary signals received during epoll gracefully

diff --git a/src/libsystemd-bus/sd-event.c b/src/libsystemd-bus/sd-event.c
index dd8d3ee..ace97dc 100644
--- a/src/libsystemd-bus/sd-event.c
+++ b/src/libsystemd-bus/sd-event.c
@@ -1748,7 +1748,7 @@ int sd_event_run(sd_event *e, uint64_t timeout) {
         m = epoll_wait(e->epoll_fd, ev_queue, EPOLL_QUEUE_MAX,
                        timeout == (uint64_t) -1 ? -1 : (int) ((timeout + USEC_PER_MSEC - 1) / USEC_PER_MSEC));
         if (m < 0) {
-                r = m;
+                r = errno == EAGAIN || errno == EINTR ? 0 : -errno;
                 goto finish;
         }
 

commit 72aedc1e80c7370e3413300c5d2ec04ac1713e0b
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Oct 16 05:57:05 2013 +0200

    event: properly disarm timers when we don't need them anymore

diff --git a/src/libsystemd-bus/sd-event.c b/src/libsystemd-bus/sd-event.c
index 3599d90..dd8d3ee 100644
--- a/src/libsystemd-bus/sd-event.c
+++ b/src/libsystemd-bus/sd-event.c
@@ -1384,8 +1384,20 @@ static int event_arm_timer(
         assert_se(next);
 
         a = prioq_peek(earliest);
-        if (!a || a->enabled == SD_EVENT_OFF)
+        if (!a || a->enabled == SD_EVENT_OFF) {
+
+                if (*next == (usec_t) -1)
+                        return 0;
+
+                /* disarm */
+                r = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &its, NULL);
+                if (r < 0)
+                        return r;
+
+                *next = (usec_t) -1;
+
                 return 0;
+        }
 
         b = prioq_peek(latest);
         assert_se(b && b->enabled != SD_EVENT_OFF);
@@ -1430,12 +1442,14 @@ static int process_io(sd_event *e, sd_event_source *s, uint32_t events) {
         return source_set_pending(s, true);
 }
 
-static int flush_timer(sd_event *e, int fd, uint32_t events) {
+static int flush_timer(sd_event *e, int fd, uint32_t events, usec_t *next) {
         uint64_t x;
         ssize_t ss;
 
         assert(e);
         assert(fd >= 0);
+        assert(next);
+
         assert_return(events == EPOLLIN, -EIO);
 
         ss = read(fd, &x, sizeof(x));
@@ -1449,6 +1463,8 @@ static int flush_timer(sd_event *e, int fd, uint32_t events) {
         if (ss != sizeof(x))
                 return -EIO;
 
+        *next = (usec_t) -1;
+
         return 0;
 }
 
@@ -1741,9 +1757,9 @@ int sd_event_run(sd_event *e, uint64_t timeout) {
         for (i = 0; i < m; i++) {
 
                 if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_MONOTONIC))
-                        r = flush_timer(e, e->monotonic_fd, ev_queue[i].events);
+                        r = flush_timer(e, e->monotonic_fd, ev_queue[i].events, &e->monotonic_next);
                 else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_REALTIME))
-                        r = flush_timer(e, e->realtime_fd, ev_queue[i].events);
+                        r = flush_timer(e, e->realtime_fd, ev_queue[i].events, &e->realtime_next);
                 else if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_SIGNAL))
                         r = process_signal(e, ev_queue[i].events);
                 else

commit e471512768bc0c5c3809178ff42c67e10da25f34
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Oct 16 05:56:37 2013 +0200

    event: fix sd_event_source_set_io_events()

diff --git a/src/libsystemd-bus/sd-event.c b/src/libsystemd-bus/sd-event.c
index b318fd0..3599d90 100644
--- a/src/libsystemd-bus/sd-event.c
+++ b/src/libsystemd-bus/sd-event.c
@@ -1002,7 +1002,7 @@ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) {
                 return 0;
 
         if (s->enabled != SD_EVENT_OFF) {
-                r = source_io_register(s, s->io.events, events);
+                r = source_io_register(s, s->enabled, events);
                 if (r < 0)
                         return r;
         }

commit 44b601bc79e46722bc0f0862ee0ce34a2284ef11
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Oct 16 03:17:09 2013 +0200

    macro: clean up usage of gcc attributes
    
    Always use our own macros, and name all our own macros the same style.

diff --git a/src/core/execute.c b/src/core/execute.c
index b48b1ae..8f09233 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -511,7 +511,7 @@ fail:
         return r;
 }
 
-_printf_attr_(1, 2) static int write_confirm_message(const char *format, ...) {
+_printf_(1, 2) static int write_confirm_message(const char *format, ...) {
         int fd;
         va_list ap;
 
diff --git a/src/core/manager.h b/src/core/manager.h
index a3049b5..ffcca48 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -318,7 +318,7 @@ void manager_undo_generators(Manager *m);
 void manager_recheck_journal(Manager *m);
 
 void manager_set_show_status(Manager *m, bool b);
-void manager_status_printf(Manager *m, bool ephemeral, const char *status, const char *format, ...) _printf_attr_(4,5);
+void manager_status_printf(Manager *m, bool ephemeral, const char *status, const char *format, ...) _printf_(4,5);
 
 Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path);
 
diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c
index 0a3ee18..c7e951c 100644
--- a/src/core/selinux-access.c
+++ b/src/core/selinux-access.c
@@ -174,7 +174,7 @@ static int audit_callback(
    user_avc's into the /var/log/audit/audit.log, otherwise they will be
    sent to syslog.
 */
-_printf_attr_(2, 3) static int log_callback(int type, const char *fmt, ...) {
+_printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
         va_list ap;
 
         va_start(ap, fmt);
diff --git a/src/core/unit.h b/src/core/unit.h
index 6dd750f..6971048 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -549,7 +549,7 @@ int unit_get_related_unit(Unit *u, const char *type, Unit **_found);
 
 bool unit_can_serialize(Unit *u) _pure_;
 int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs);
-void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_attr_(4,5);
+void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5);
 void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
 int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
 
@@ -557,7 +557,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants);
 
 int unit_coldplug(Unit *u);
 
-void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) _printf_attr_(3, 0);
+void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) _printf_(3, 0);
 
 bool unit_need_daemon_reload(Unit *u);
 
@@ -598,10 +598,10 @@ ExecContext *unit_get_exec_context(Unit *u) _pure_;
 CGroupContext *unit_get_cgroup_context(Unit *u) _pure_;
 
 int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data);
-int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) _printf_attr_(4,5);
+int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) _printf_(4,5);
 
 int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data);
-int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) _printf_attr_(4,5);
+int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) _printf_(4,5);
 
 int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name);
 
diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c
index d00e26f..52f9905 100644
--- a/src/journal/journal-send.c
+++ b/src/journal/journal-send.c
@@ -111,7 +111,7 @@ _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
         return sd_journal_sendv(iov, 2);
 }
 
-_printf_attr_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
+_printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int extra, struct iovec **_iov) {
         PROTECT_ERRNO;
         int r, n = 0, i = 0, j;
         struct iovec *iov = NULL;
diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h
index 10e9958..069cd17 100644
--- a/src/journal/journald-server.h
+++ b/src/journal/journald-server.h
@@ -128,7 +128,7 @@ typedef struct Server {
 #define N_IOVEC_OBJECT_FIELDS 11
 
 void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len, const char *unit_id, int priority, pid_t object_pid);
-void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) _printf_attr_(3,4);
+void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) _printf_(3,4);
 
 /* gperf lookup function */
 const struct ConfigPerfItem* journald_gperf_lookup(const char *key, unsigned length);
diff --git a/src/journal/microhttpd-util.h b/src/journal/microhttpd-util.h
index 20ad769..74d1668 100644
--- a/src/journal/microhttpd-util.h
+++ b/src/journal/microhttpd-util.h
@@ -25,4 +25,4 @@
 
 #include "macro.h"
 
-void microhttpd_logger(void *arg, const char *fmt, va_list ap) _printf_attr_(2, 0);
+void microhttpd_logger(void *arg, const char *fmt, va_list ap) _printf_(2, 0);
diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h
index 54c51ac..18bc853 100644
--- a/src/libudev/libudev-private.h
+++ b/src/libudev/libudev-private.h
@@ -48,8 +48,7 @@
 /* libudev.c */
 void udev_log(struct udev *udev,
               int priority, const char *file, int line, const char *fn,
-              const char *format, ...)
-              __attribute__((format(printf, 6, 7)));
+              const char *format, ...) _printf_(6, 7);
 int udev_get_rules_path(struct udev *udev, char **path[], usec_t *ts_usec[]);
 struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value);
 struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev);
@@ -175,5 +174,6 @@ int util_delete_path(struct udev *udev, const char *path);
 uid_t util_lookup_user(struct udev *udev, const char *user);
 gid_t util_lookup_group(struct udev *udev, const char *group);
 int util_resolve_subsys_kernel(struct udev *udev, const char *string, char *result, size_t maxsize, int read_value);
-ssize_t print_kmsg(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+ssize_t print_kmsg(const char *fmt, ...) _printf_(1, 2);
+
 #endif
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index 08428a5..9435d54 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -114,7 +114,7 @@ int config_parse_set_status(const char *unit, const char *filename, unsigned lin
 int log_syntax_internal(const char *unit, int level,
                         const char *file, unsigned line, const char *func,
                         const char *config_file, unsigned config_line,
-                        int error, const char *format, ...) _printf_attr_(9, 10);
+                        int error, const char *format, ...) _printf_(9, 10);
 
 #define log_syntax(unit, level, config_file, config_line, error, ...)   \
         log_syntax_internal(unit, level,                                \
diff --git a/src/shared/log.h b/src/shared/log.h
index 979f833..9ce99ef 100644
--- a/src/shared/log.h
+++ b/src/shared/log.h
@@ -75,7 +75,7 @@ int log_meta(
                 const char*file,
                 int line,
                 const char *func,
-                const char *format, ...) _printf_attr_(5,6);
+                const char *format, ...) _printf_(5,6);
 
 int log_metav(
                 int level,
@@ -83,7 +83,7 @@ int log_metav(
                 int line,
                 const char *func,
                 const char *format,
-                va_list ap) _printf_attr_(5,0);
+                va_list ap) _printf_(5,0);
 
 int log_meta_object(
                 int level,
@@ -92,7 +92,7 @@ int log_meta_object(
                 const char *func,
                 const char *object_name,
                 const char *object,
-                const char *format, ...) _printf_attr_(7,8);
+                const char *format, ...) _printf_(7,8);
 
 int log_metav_object(
                 int level,
@@ -102,14 +102,14 @@ int log_metav_object(
                 const char *object_name,
                 const char *object,
                 const char *format,
-                va_list ap) _printf_attr_(7,0);
+                va_list ap) _printf_(7,0);
 
 int log_struct_internal(
                 int level,
                 const char *file,
                 int line,
                 const char *func,
-                const char *format, ...) _printf_attr_(5,0) _sentinel_;
+                const char *format, ...) _printf_(5,0) _sentinel_;
 
 int log_oom_internal(
                 const char *file,
diff --git a/src/shared/macro.h b/src/shared/macro.h
index 06e16cd..3cf17bb 100644
--- a/src/shared/macro.h
+++ b/src/shared/macro.h
@@ -27,7 +27,7 @@
 #include <sys/uio.h>
 #include <inttypes.h>
 
-#define _printf_attr_(a,b) __attribute__ ((format (printf, a, b)))
+#define _printf_(a,b) __attribute__ ((format (printf, a, b)))
 #define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__)))
 #define _sentinel_ __attribute__ ((sentinel))
 #define _noreturn_ __attribute__((noreturn))
diff --git a/src/shared/strxcpyx.h b/src/shared/strxcpyx.h
index 1229a48..7be246d 100644
--- a/src/shared/strxcpyx.h
+++ b/src/shared/strxcpyx.h
@@ -24,8 +24,10 @@
 #include <stdarg.h>
 #include <stdbool.h>
 
+#include "macro.h"
+
 size_t strpcpy(char **dest, size_t size, const char *src);
-size_t strpcpyf(char **dest, size_t size, const char *src, ...) __attribute__((format(printf, 3, 4)));
-size_t strpcpyl(char **dest, size_t size, const char *src, ...) __attribute__((sentinel));
+size_t strpcpyf(char **dest, size_t size, const char *src, ...) _printf_(3, 4);
+size_t strpcpyl(char **dest, size_t size, const char *src, ...) _sentinel_;
 size_t strscpy(char *dest, size_t size, const char *src);
-size_t strscpyl(char *dest, size_t size, const char *src, ...) __attribute__((sentinel));
+size_t strscpyl(char *dest, size_t size, const char *src, ...) _sentinel_;
diff --git a/src/shared/util.h b/src/shared/util.h
index 86b2143..63cb4ac 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -320,7 +320,7 @@ bool fstype_is_network(const char *fstype);
 int chvt(int vt);
 
 int read_one_char(FILE *f, char *ret, usec_t timeout, bool *need_nl);
-int ask(char *ret, const char *replies, const char *text, ...) _printf_attr_(3, 4);
+int ask(char *ret, const char *replies, const char *text, ...) _printf_(3, 4);
 
 int reset_terminal_fd(int fd, bool switch_to_text);
 int reset_terminal(const char *name);
@@ -374,8 +374,8 @@ int pipe_eof(int fd);
 
 cpu_set_t* cpu_set_malloc(unsigned *ncpus);
 
-int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_attr_(4,0);
-int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_attr_(4,5);
+int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0);
+int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5);
 int status_welcome(void);
 
 int fd_columns(int fd);
diff --git a/src/udev/udev.h b/src/udev/udev.h
index ed8b183..29e96d6 100644
--- a/src/udev/udev.h
+++ b/src/udev/udev.h
@@ -201,7 +201,7 @@ int udev_builtin_hwdb_lookup(struct udev_device *dev, const char *prefix, const
 /* udev logging */
 void udev_main_log(struct udev *udev, int priority,
                    const char *file, int line, const char *fn,
-                   const char *format, va_list args) _printf_attr_(6, 0);
+                   const char *format, va_list args) _printf_(6, 0);
 
 /* udevadm commands */
 struct udevadm_cmd {

commit e0d856dd48d640f3d95efe7b769edec02373cc74
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Oct 16 02:51:24 2013 +0200

    rules: don't limit some of the rules to the "add" action
    
    Devices should show up in systemd regardless whether the user invoked
    "udevadm trigger" or not. Before this change some devices might have
    suddenly disappeared due issuing that command.

diff --git a/rules/99-systemd.rules.in b/rules/99-systemd.rules.in
index 74fc563..0923de5 100644
--- a/rules/99-systemd.rules.in
+++ b/rules/99-systemd.rules.in
@@ -54,17 +54,17 @@ ACTION=="add", SUBSYSTEM=="net", KERNEL!="lo", RUN+="@rootlibexecdir@/systemd-sy
 # Pull in backlight save/restore for all backlight devices and
 # keyboard backlights
 
-ACTION=="add", SUBSYSTEM=="backlight", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_WANTS}+="systemd-backlight at backlight:$name.service"
-ACTION=="add", SUBSYSTEM=="leds", KERNEL=="*kbd_backlight", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_WANTS}+="systemd-backlight at leds:$name.service"
+SUBSYSTEM=="backlight", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_WANTS}+="systemd-backlight at backlight:$name.service"
+SUBSYSTEM=="leds", KERNEL=="*kbd_backlight", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_WANTS}+="systemd-backlight at leds:$name.service"
 
 # Pull in rfkill save/restore for all rfkill devices
 
-ACTION=="add", SUBSYSTEM=="rfkill", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_WANTS}+="systemd-rfkill@$name.service"
+SUBSYSTEM=="rfkill", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_WANTS}+="systemd-rfkill@$name.service"
 
 # Asynchronously mount file systems implemented by these modules as
 # soon as they are loaded.
 
-SUBSYSTEM=="module", KERNEL=="fuse", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sys-fs-fuse-connections.mount"
-SUBSYSTEM=="module", KERNEL=="configfs", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sys-kernel-config.mount"
+SUBSYSTEM=="module", KERNEL=="fuse", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sys-fs-fuse-connections.mount"
+SUBSYSTEM=="module", KERNEL=="configfs", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sys-kernel-config.mount"
 
 LABEL="systemd_end"

commit da999068475a8c62113de45fe10103bef0b6016a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Oct 16 02:49:54 2013 +0200

    rules: expose loop block devices to systemd
    
    Since the kernel no longer exposes a large number of "dead" loop devices
    it is OK to expose them now in systemd, so let's do that. This has the
    benefit that mount dependencies on loop devices start to work.

diff --git a/rules/99-systemd.rules.in b/rules/99-systemd.rules.in
index a620354..74fc563 100644
--- a/rules/99-systemd.rules.in
+++ b/rules/99-systemd.rules.in
@@ -11,12 +11,12 @@ SUBSYSTEM=="tty", KERNEL=="tty[a-zA-Z]*|hvc*|xvc*|hvsi*", TAG+="systemd"
 
 KERNEL=="vport*", TAG+="systemd"
 
-SUBSYSTEM=="block", KERNEL!="ram*|loop*", TAG+="systemd"
-SUBSYSTEM=="block", KERNEL!="ram*|loop*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0"
+SUBSYSTEM=="block", KERNEL!="ram*", TAG+="systemd"
+SUBSYSTEM=="block", KERNEL!="ram*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0"
 
 # Ignore encrypted devices with no identified superblock on it, since
 # we are probably still calling mke2fs or mkswap on it.
-SUBSYSTEM=="block", KERNEL!="ram*|loop*", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0"
+SUBSYSTEM=="block", KERNEL!="ram*", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0"
 
 # Ignore raid devices that are not yet assembled and started
 SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", TEST!="md/array_state", ENV{SYSTEMD_READY}="0"



More information about the systemd-commits mailing list